Documentation développeur

API EloCRM
REST · oRPC · Webhooks

Connectez EloCRM à vos outils internes, déclenchez des automatisations sur n'importe quel événement, et construisez vos propres tableaux de bord en consommant les données scopées par organisation.

Étape 1

Démarrage rapide

  1. Connectez-vous à EloCRM, ouvrez Paramètres → Clés API (plan Business requis).
  2. Créez une clé : nommez-la (ex. Production · Zapier) et sélectionnez les permissions nécessaires.
  3. Copiez la clé immédiatement — elle commence par thia_sk_ et ne sera plus jamais affichée.
  4. Effectuez votre premier appel — par défaut sur /api/rpc/<procedure>.
bash
curl -X POST https://app.elocrm.io/api/rpc/clients/list \
  -H "Authorization: Bearer thia_sk_..." \
  -H "Content-Type: application/json" \
  -d '{}'
Étape 2

Authentification

Toutes les requêtes API doivent porter un header Authorization: Bearer <clé>. Le serveur résout l'organisation associée et applique automatiquement l'isolation multi-tenant — aucune donnée d'autres agences n'est jamais accessible.

  • Format : thia_sk_ + 32 caractères aléatoires.
  • Stocké en SHA-256 côté serveur — la clé en clair est perdue dès qu'elle quitte la dialog de création.
  • Permissions au format module:action (par ex. clients:read, invoices:write). Le scope * donne accès à tout.
  • Une clé peut être révoquée à tout instant ; les intégrations cessent immédiatement.
Sécurité

Catalogue de permissions

Chaque clé API porte un ensemble de permissions au format module:action. Le scope * donne accès à tout — réservez-le aux scripts internes critiques. Pour les intégrations tierces, suivez le principe du moindre privilège.

ScopeDescription
*Tout (lecture + écriture)
clients:readLire les clients et notes
clients:writeCréer / modifier / supprimer des clients
projects:readLire les projets
projects:writeCréer / modifier des projets
tasks:readLire les tâches
tasks:writeCréer / modifier / clôturer des tâches
quotes:readLire les devis
quotes:writeCréer / envoyer des devis
invoices:readLire les factures
invoices:writeCréer / envoyer / payer des factures
appointments:readLire l'agenda
appointments:writeCréer / modifier des RDV
time:readLire les saisies de temps
time:writeDémarrer / modifier des timers
Étape 3

Endpoints

L'API EloCRM est exposée via oRPC sur POST /api/rpc/<procedure>. La référence OpenAPI complète est générée automatiquement et navigable dans Scalar — vous pouvez y exécuter des requêtes directement en collant votre clé.

Ouvrir la référence /api/reference →

Familles d'endpoints : clients, projects, tasks, quotes, invoices, appointments, time, analytics, webhooks, apiKeys.

Référence

Codes d'erreur

Chaque erreur renvoie un statut HTTP standard ainsi qu'un objet { code, message } dans le body. Inspectez le message pour des détails utilisateur.

HTTPCodeCauseSolution
401UNAUTHORIZEDClé invalide, révoquée, expirée, ou organisation désactivée.Vérifier la clé dans Paramètres → Clés API.
403FORBIDDENPermission insuffisante OU plan trop bas pour la fonctionnalité.Ajouter la permission OU upgrader le plan.
404NOT_FOUNDRessource introuvable ou hors de votre organisation.Vérifier l'ID.
400BAD_REQUESTValidation Zod échouée — champ manquant ou type incorrect.Lire le champ message de la réponse.
409CONFLICTDoublon (email, numéro de facture déjà pris).Récupérer l'enregistrement existant.
Étape 4

Webhooks sortants

Configurez vos endpoints depuis Paramètres → Webhooks (plan Pro requis). EloCRM envoie un POST signé HMAC-SHA256 à chaque événement souscrit. 3 tentatives avec backoff (1 s, 10 s, 60 s) ; timeout réseau 10 s par tentative.

  • Header x-webhook-signature : HMAC-SHA256 du body brut en hexadécimal.
  • Header x-webhook-event: type d'événement (routage rapide).
  • Réponse 2xx = succès, stoppe la boucle. Tout le reste déclenche un retry.
  • Idempotence recommandée côté receveur (un même événement peut arriver deux fois en cas de timeout).

Forme du payload

json
{
  "event": "invoice.paid",
  "timestamp": "2026-04-26T10:32:11.412Z",
  "data": {
    "type": "invoice.paid",
    "orgId": "org_acme_xyz",
    "invoiceId": "ckxyz...",
    "clientId": "ckabc...",
    "actorId": "usr_..."
  }
}
Référence

Événements disponibles

13 événements sont exposés aux webhooks. Les événements internes (mentions de notes, alertes) restent privés à l'application.

ÉvénementDescription
client.createdClient créé
client.updatedClient mis à jour
project.createdProjet créé
task.createdTâche créée
task.completedTâche terminée
task.reopenedTâche réouverte
appointment.createdRDV créé
quote.sentDevis envoyé
quote.signedDevis signé
invoice.createdFacture créée
invoice.sentFacture envoyée
invoice.paidFacture payée
document.sharedDocument partagé
Sécurité

Vérifier la signature HMAC

La signature prouve que le webhook vient bien d'EloCRM. Calculez HMAC-SHA256 sur le body brut avec votre secret et comparez en temps constant (jamais avec ===).

Node.js (Express)

javascript
import { createHmac, timingSafeEqual } from "node:crypto";
import express from "express";

const app = express();

function verifyEloSignature(rawBody, signature, secret) {
  const expected = createHmac("sha256", secret).update(rawBody).digest("hex");
  const a = Buffer.from(expected);
  const b = Buffer.from(signature);
  return a.length === b.length && timingSafeEqual(a, b);
}

app.post(
  "/webhooks/elocrm",
  express.raw({ type: "application/json" }),
  (req, res) => {
    const ok = verifyEloSignature(
      req.body,
      req.headers["x-webhook-signature"],
      process.env.ELO_WEBHOOK_SECRET,
    );
    if (!ok) return res.status(401).send("Invalid signature");
    const payload = JSON.parse(req.body.toString());
    // ... traiter en async, répondre tout de suite
    res.status(200).end();
  },
);

Python (Flask)

python
import hmac, hashlib, os
from flask import Flask, request, abort

app = Flask(__name__)

def verify_elo_signature(raw_body: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature)

@app.post("/webhooks/elocrm")
def receive_elo():
    if not verify_elo_signature(
        request.get_data(),
        request.headers.get("X-Webhook-Signature", ""),
        os.environ["ELO_WEBHOOK_SECRET"],
    ):
        abort(401)
    # ... traiter en async, répondre tout de suite
    return "", 200

PHP

php
<?php
$rawBody   = file_get_contents("php://input");
$signature = $_SERVER["HTTP_X_WEBHOOK_SIGNATURE"] ?? "";
$secret    = getenv("ELO_WEBHOOK_SECRET");

$expected = hash_hmac("sha256", $rawBody, $secret);
if (!hash_equals($expected, $signature)) {
    http_response_code(401);
    exit("Invalid signature");
}
http_response_code(200);
// ... traiter en async (queue, job worker, etc.)
Étape 5

Exemples — appels API

curl — lister les clients

bash
curl -X POST https://crm.thiagency.be/api/rpc/clients/list \
  -H "Authorization: Bearer thia_sk_abc123..." \
  -H "Content-Type: application/json" \
  -d '{}'

curl — créer un client

bash
curl -X POST https://crm.thiagency.be/api/rpc/clients/create \
  -H "Authorization: Bearer thia_sk_abc123..." \
  -H "Content-Type: application/json" \
  -d '{
    "firstName": "Jean",
    "lastName": "Dupont",
    "email": "jean@dupont.be",
    "companyName": "Dupont SA"
  }'

Node.js (fetch) — gestion des erreurs

javascript
const ELO_API = "https://crm.thiagency.be/api/rpc";
const ELO_KEY = process.env.ELO_API_KEY; // jamais hardcodé

async function listClients() {
  const res = await fetch(`${ELO_API}/clients/list`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${ELO_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({}),
  });
  if (!res.ok) {
    throw new Error(`ELO API ${res.status}: ${await res.text()}`);
  }
  const { json } = await res.json();
  return json;
}

const clients = await listClients();
console.log(`${clients.length} clients chez THIA'gency`);

Python (requests) — lister les factures

python
import os, requests

ELO_API = "https://crm.thiagency.be/api/rpc"
ELO_KEY = os.environ["ELO_API_KEY"]

def list_invoices():
    r = requests.post(
        f"{ELO_API}/invoices/list",
        headers={
            "Authorization": f"Bearer {ELO_KEY}",
            "Content-Type": "application/json",
        },
        json={},
        timeout=10,
    )
    r.raise_for_status()
    return r.json()

invoices = list_invoices()
print(f"{len(invoices)} factures")
Bonus

Rate limits

L'API EloCRM applique une politique souple : pour l'instant, aucun quota strict n'est en place — un système de rate-limit par clé est prévu pour la prochaine itération. Les abus manifestes (bursts répétés au-dessus de 200 req/sec) peuvent entraîner une révocation manuelle.

Pour les intégrations à fort volume, contactez-nous sur dev@elocrm.io — nous pouvons fournir des clés dédiées avec quotas relevés.