1) Éligibilité et quotas
Abonnements éligibles à l'API publique
L’API publique REST et les Webhooks sortants sont inclus
sans surcoût dans les forfaits Avocat Indépendant
et Petit Cabinet, uniquement en mode cabinet normal. Ils ne sont pas
disponibles pour le forfait Avocat Stagiaire ni pour les Workspaces
inter-cabinets (renvoi d'un code
HTTP 403 Forbidden).
- Avocat Indépendant (39,99 € HT / mois)
- Petit Cabinet (69,99 € HT / mois)
Quotas autorisés par utilisateur
- Maximum 5 clés d'API simultanées par utilisateur.
- Maximum 5 endpoints Webhook simultanés par utilisateur.
Vous pouvez générer, gérer et révoquer vos clés d'API et vos abonnements Webhook directement depuis votre application Lexlo dans : Paramètres > API & Webhooks.
2) Authentification par Clé d'API
Chaque requête transmise à l'API Lexlo doit inclure une clé d'API
secrète valide débutant obligatoirement par le préfixe
lx_live_.
Deux méthodes d'authentification sont acceptées :
| Méthode | En-tête HTTP | Format de la valeur | Statut |
|---|---|---|---|
| En-tête X-API-Key | X-API-Key |
lx_live_votreCleSecreteLexlo
|
⭐ Recommandé |
| Bearer Token | Authorization |
Bearer lx_live_votreCleSecreteLexlo
|
Standard HTTP |
Recommandation de sécurité
Vos clés d'API possèdent un niveau d'accès complet équivalent à votre compte utilisateur. Ne les exposez jamais dans du code source public (GitHub, GitLab) ou côté client (navigateur, application mobile décompilable). Utilisez-les exclusivement sur vos serveurs ou plateformes d'automatisation sécurisées.
3) URL de base et Limitation de débit (Rate Limits)
Toutes les requêtes en production doivent être émises en HTTPS :
https://api.lexlo.be/api/v1
En environnement de développement local :
http://localhost:8000/api/v1
| Portée | Limite | En-tête HTTP | Comportement si dépassé |
|---|---|---|---|
| Par clé d'API | 60 requêtes / minute | X-RateLimit-Remaining |
Code HTTP 429 Too Many Requests
|
| Par cabinet (global) | 120 requêtes / minute | — |
Code HTTP 429 Too Many Requests
|
4) Format standard des réponses JSON
Toutes les réponses de l'API sont enveloppées dans une structure JSON standardisée :
{
"success": true,
"data": { ... },
"meta": {
"count": 10,
"limit": 50,
"offset": 0
}
}
En cas d'erreur, le format de réponse inclut un message explicite et
un identifiant unique de requête (request_id) pour faciliter le support :
{
"detail": "Le numéro de dossier '2026-001' est déjà utilisé dans votre cabinet.",
"request_id": "b72b2302-6196-4cf9-b7ba-c7428b33ccea"
}
5) Fuseau horaire et Timestamps (Belgique)
Fuseau horaire officiel : Europe/Brussels
Tous les timestamps renvoyés par l'API REST et expédiés dans les
payloads de Webhooks sont strictement convertis et exprimés sur le
fuseau horaire de la Belgique (Europe/Brussels) au format standard
ISO 8601 avec offset explicite :
-
Heure d'été (CEST) : offset
+02:00(ex:2026-09-28T15:30:00+02:00) -
Heure d'hiver (CET) : offset
+01:00(ex:2026-12-15T10:00:00+01:00)
Pour les dates sans heure (ex:
due_date,
expense_date,
issue_date), le format standard
YYYY-MM-DD est utilisé (ex:
2026-10-15).
6) Codes d'erreur HTTP
| Code | Intitulé | Description & Résolution |
|---|---|---|
400 Bad Request |
Requête invalide | Paramètre obligatoire manquant ou corps JSON malformé. |
401 Unauthorized |
Non authentifié |
Clé d'API absente, invalide, révoquée ou ne débutant pas par
lx_live_.
|
403 Forbidden |
Accès refusé | Abonnement non éligible (mode Workspace ou forfait Stagiaire). |
404 Not Found |
Ressource introuvable | Identifiant inexistant ou n'appartenant pas à votre cabinet (isolation stricte multi-tenant). |
409 Conflict |
Conflit de données | Numéro de dossier déjà utilisé, ou suppression refusée en raison d'éléments liés (factures, débours). |
422 Unprocessable |
Validation échouée | Type de donnée non conforme ou contrainte de champ non respectée. |
429 Too Many Requests |
Rate limit dépassé | Nombre maximal de requêtes par minute atteint (60 req/min). |
500 Internal Error |
Erreur serveur |
Erreur inattendue — contactez le support en fournissant le
request_id.
|
7) Référence complète des Endpoints REST
7.1 Compte & Cabinet (/me)
| Méthode | Route | Description |
|---|---|---|
| GET | /api/v1/me |
Informations sur l'utilisateur connecté, son cabinet et son forfait actif. |
{
"success": true,
"data": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"email": "marie.dupont@avocat-barreau.be",
"first_name": "Marie",
"last_name": "Dupont",
"cabinet_id": "384939e9-cec8-41fc-bd91-7b53e831cb75",
"plan": "Avocat indépendant",
"created_at": "2026-01-15T09:00:00+01:00"
},
"meta": {
"key_name": "Clé CRM Make",
"key_prefix": "lx_live_gHT7"
}
}
7.2 Dossiers (/cases)
| Méthode | Route | Description |
|---|---|---|
| GET | /api/v1/cases |
Lister les dossiers (filtres :
status,
client_id,
limit,
offset).
|
| GET | /api/v1/cases/{case_id} |
Consulter le détail complet d'un dossier. |
| POST | /api/v1/cases |
Créer un dossier (titre obligatoire, numéro auto-généré au
format AAAA-NNN si omis).
|
| PATCH | /api/v1/cases/{case_id} |
Mettre à jour un dossier (title, status:
ACTIF,
TERMINE,
SUSPENDU,
ARCHIVU, etc.).
|
| DELETE | /api/v1/cases/{case_id} |
Supprimer un dossier (bloqué si des factures ou débours y sont rattachés). |
{
"title": "Affaire Dupont c/ SA Immo",
"description": "Litige commercial bail commercial",
"client_id": "6fc4d5b9-6461-450a-af4c-d5bb93104a90",
"case_number": "2026-001",
"jurisdiction": "Tribunal de l'entreprise de Bruxelles",
"is_baj": false
}
7.3 Clients & Contacts (/clients)
| Méthode | Route | Description |
|---|---|---|
| GET | /api/v1/clients |
Lister les clients avec recherche textuelle (search) sur nom, prénom, société, e-mail.
|
| GET |
/api/v1/clients/{client_id}
|
Consulter la fiche détaillée d'un client. |
| POST | /api/v1/clients |
Créer un client (au moins un parmi
first_name,
last_name ou
company_name requis).
|
| PATCH |
/api/v1/clients/{client_id}
|
Mettre à jour les coordonnées d'un client. |
| DELETE |
/api/v1/clients/{client_id}
|
Supprimer un client (protégé si des dossiers ou factures y sont liés). |
7.4 Tâches & Échéances (/tasks)
| Méthode | Route | Description |
|---|---|---|
| GET | /api/v1/tasks |
Lister les tâches (filtres :
case_id,
status:
todo,
en_cours,
terminee).
|
| GET | /api/v1/tasks/{task_id} |
Consulter une tâche. |
| POST | /api/v1/tasks |
Créer une tâche (title,
due_date,
priority:
haute,
normale,
basse ou 1-5).
|
| PATCH | /api/v1/tasks/{task_id} |
Modifier une tâche ou marquer terminée (status: "terminee").
|
| DELETE | /api/v1/tasks/{task_id} |
Supprimer une tâche. |
7.5 Rendez-vous & Audiences (/appointments)
| Méthode | Route | Description |
|---|---|---|
| GET | /api/v1/appointments |
Lister les rendez-vous et audiences planifiés (filtre :
case_id).
|
| GET |
/api/v1/appointments/{appointment_id}
|
Consulter le détail d'un rendez-vous. |
| POST | /api/v1/appointments |
Créer un rendez-vous (title,
start_time ISO 8601,
duration_minutes ou
end_time,
location).
|
| PATCH |
/api/v1/appointments/{appointment_id}
|
Modifier un rendez-vous ou reporter son horaire. |
| DELETE |
/api/v1/appointments/{appointment_id}
|
Supprimer un rendez-vous de l'agenda. |
7.6 Facturation (/invoices)
Gestion des factures
Pour garantir la conformité comptable, les factures sont créées
depuis l'interface Lexlo. L'API permet la
consultation des factures (total_ht, total_ttc,
paid_amount) et la
mise à jour de leur statut.
| Méthode | Route | Description |
|---|---|---|
| GET | /api/v1/invoices |
Lister les factures (filtres :
status,
case_id).
|
| GET |
/api/v1/invoices/{invoice_id}
|
Consulter le détail d'une facture. |
| PATCH |
/api/v1/invoices/{invoice_id}/status
|
Mettre à jour le statut (brouillon, envoyee,
payee,
en_retard,
annulee).
|
7.7 Frais & Débours (/expenses)
| Méthode | Route | Description |
|---|---|---|
| GET | /api/v1/expenses |
Lister les frais et débours enregistrés par dossier. |
| GET |
/api/v1/expenses/{expense_id}
|
Consulter le détail d'une dépense. |
| POST | /api/v1/expenses |
Enregistrer une dépense (case_id, amount,
description,
expense_type).
|
| PATCH |
/api/v1/expenses/{expense_id}
|
Modifier une dépense ou son montant. |
| DELETE |
/api/v1/expenses/{expense_id}
|
Supprimer un débours (bloqué si déjà rattaché à une facture). |
8) Webhooks sortants en temps réel
Les Webhooks Lexlo notifient vos serveurs ou plateformes d'automatisation (Make, Zapier, n8n, serveurs internes) instantanément dès qu'une action intervient dans votre cabinet.
8.1 Catalogue des événements disponibles
| Ressource | Événements déclenchés |
|---|---|
| Dossiers |
case.created,
case.updated,
case.deleted
|
| Clients |
client.created,
client.updated,
client.deleted
|
| Tâches |
task.created,
task.updated,
task.completed,
task.deleted
|
| Rendez-vous |
appointment.created,
appointment.updated,
appointment.deleted
|
| Factures |
invoice.status_changed,
invoice.paid
|
| Frais / Débours |
expense.created,
expense.updated,
expense.deleted
|
| Tous événements | * (Abonnement universel) |
8.2 Format du payload et en-têtes HTTP
Chaque notification webhook est transmise en HTTP POST avec les en-têtes suivants :
-
X-Lexlo-Delivery-ID: Identifiant unique de l'envoi (UUID v4) -
X-Lexlo-Event: Nom de l'événement (ex:case.created) -
X-Lexlo-Timestamp: Horodatage ISO 8601 (heure belge) -
X-Lexlo-Signature: Signature cryptographiquesha256=<hmac_hex>
{
"id": "8a93ef01-47bb-4e32-9c3f-91772184ad22",
"event": "case.created",
"created_at": "2026-09-28T23:09:18.234152+02:00",
"data": {
"id": "dff099e7-0091-40bd-8548-b6ae7be64315",
"title": "Affaire Dupont c/ SA Immo",
"case_number": "2026-001",
"status": "ACTIF",
"client_id": "6fc4d5b9-6461-450a-af4c-d5bb93104a90",
"created_at": "2026-09-28T23:09:18+02:00"
}
}
Règles de livraison et désactivation automatique
Votre endpoint doit répondre en moins de 5 secondes avec un code HTTP 2xx. Après 10 échecs consécutifs, le webhook est automatiquement désactivé pour protéger votre infrastructure.
8.3 Vérification de signature HMAC-SHA256
import hmac
import hashlib
from fastapi import FastAPI, Request, Header, HTTPException
app = FastAPI()
WEBHOOK_SECRET = "whsec_7b8e348d4c5217c3b0373b6bfc89d62a08fa24a071f346bc"
def verify_signature(raw_body: bytes, signature_header: str, secret: str) -> bool:
expected = "sha256=" + hmac.new(
secret.encode("utf-8"),
raw_body,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature_header)
@app.post("/webhooks/lexlo")
async def receive_webhook(
request: Request,
x_lexlo_signature: str = Header(...),
x_lexlo_event: str = Header(...)
):
raw_body = await request.body()
if not verify_signature(raw_body, x_lexlo_signature, WEBHOOK_SECRET):
raise HTTPException(status_code=401, detail="Signature HMAC invalide")
payload = await request.json()
print(f"Événement Lexlo validé : {x_lexlo_event}", payload.get("data"))
return {"received": True}
const express = require('express');
const crypto = require('crypto');
const app = express();
const WEBHOOK_SECRET = 'whsec_7b8e348d4c5217c3b0373b6bfc89d62a08fa24a071f346bc';
app.post('/webhooks/lexlo', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-lexlo-signature'];
const event = req.headers['x-lexlo-event'];
const hmac = crypto.createHmac('sha256', WEBHOOK_SECRET);
hmac.update(req.body);
const expectedSignature = `sha256=${hmac.digest('hex')}`;
if (!signature || !crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSignature))) {
return res.status(401).json({ error: 'Signature HMAC invalide' });
}
const payload = JSON.parse(req.body.toString('utf-8'));
console.log(`Événement reçu : ${event}`, payload.data);
res.json({ received: true });
});
app.listen(3000);
<?php
$secret = "whsec_7b8e348d4c5217c3b0373b6bfc89d62a08fa24a071f346bc";
$signatureHeader = $_SERVER['HTTP_X_LEXLO_SIGNATURE'] ?? '';
$rawPayload = file_get_contents('php://input');
$expectedSignature = 'sha256=' . hash_hmac('sha256', $rawPayload, $secret);
if (!hash_equals($expectedSignature, $signatureHeader)) {
http_response_code(401);
echo json_encode(['error' => 'Signature invalide']);
exit;
}
$data = json_decode($rawPayload, true);
http_response_code(200);
echo json_encode(['received' => true]);
9) Exemples d'intégration complets
# En-têtes d'authentification
$headers = @{ "X-API-Key" = "lx_live_votreCleSecreteLexlo" }
$baseUrl = "https://api.lexlo.be/api/v1"
# 1. Vérifier votre profil et le cabinet
$me = Invoke-RestMethod -Uri "$baseUrl/me" -Headers $headers
Write-Host "Cabinet: $($me.data.cabinet_id) (Plan: $($me.data.plan))"
# 2. Créer un client
$clientBody = @{
first_name = "Jean"
last_name = "Dupont"
company_name = "Dupont SPRL"
email = "jean.dupont@example.com"
phone = "+32 470 12 34 56"
} | ConvertTo-Json
$client = Invoke-RestMethod -Uri "$baseUrl/clients" -Method Post -Headers $headers `
-ContentType "application/json; charset=utf-8" `
-Body ([System.Text.Encoding]::UTF8.GetBytes($clientBody))
# 3. Créer un dossier lié (numéro auto-généré au format AAAA-NNN)
$caseBody = @{
title = "Affaire Dupont c/ SA Immo"
client_id = $client.data.id
jurisdiction = "Tribunal de l'entreprise de Bruxelles"
} | ConvertTo-Json
$case = Invoke-RestMethod -Uri "$baseUrl/cases" -Method Post -Headers $headers `
-ContentType "application/json; charset=utf-8" `
-Body ([System.Text.Encoding]::UTF8.GetBytes($caseBody))
Write-Host "Dossier créé avec succès : $($case.data.case_number)"
import requests
API_KEY = "lx_live_votreCleSecreteLexlo"
BASE_URL = "https://api.lexlo.be/api/v1"
headers = {
"X-API-Key": API_KEY,
"Content-Type": "application/json; charset=utf-8",
"Accept": "application/json",
}
# 1. Profil
me = requests.get(f"{BASE_URL}/me", headers=headers).json()
print(f"Cabinet: {me['data']['cabinet_id']} | Plan: {me['data']['plan']}")
# 2. Créer un client
client = requests.post(f"{BASE_URL}/clients", headers=headers, json={
"first_name": "Sophie",
"last_name": "Dubois",
"email": "sophie.dubois@example.be",
}).json()
# 3. Créer un dossier
case = requests.post(f"{BASE_URL}/cases", headers=headers, json={
"title": "Règlement succession Dubois",
"client_id": client["data"]["id"],
}).json()
print(f"Numéro de dossier attribué : {case['data']['case_number']}")
const API_KEY = "lx_live_votreCleSecreteLexlo";
const BASE_URL = "https://api.lexlo.be/api/v1";
const headers = {
"X-API-Key": API_KEY,
"Content-Type": "application/json",
"Accept": "application/json",
};
async function main() {
const me = await fetch(`${BASE_URL}/me`, { headers }).then(r => r.json());
console.log("Cabinet:", me.data.cabinet_id);
const client = await fetch(`${BASE_URL}/clients`, {
method: "POST", headers,
body: JSON.stringify({ first_name: "Jean", last_name: "Dupont", email: "jean.dupont@example.com" }),
}).then(r => r.json());
const caseRes = await fetch(`${BASE_URL}/cases`, {
method: "POST", headers,
body: JSON.stringify({ title: "Affaire Dupont", client_id: client.data.id }),
}).then(r => r.json());
console.log("Dossier créé:", caseRes.data.case_number);
}
main();
# Vérifier le compte
curl -X GET "https://api.lexlo.be/api/v1/me" \
-H "X-API-Key: lx_live_votreCleSecreteLexlo" \
-H "Accept: application/json"
# Créer un client
curl -X POST "https://api.lexlo.be/api/v1/clients" \
-H "X-API-Key: lx_live_votreCleSecreteLexlo" \
-H "Content-Type: application/json" \
-d '{"first_name":"Jean","last_name":"Dupont","email":"jean.dupont@example.com"}'
# Créer un dossier
curl -X POST "https://api.lexlo.be/api/v1/cases" \
-H "X-API-Key: lx_live_votreCleSecreteLexlo" \
-H "Content-Type: application/json" \
-d '{"title":"Affaire Dupont c/ SA Immo"}'
10) Support et assistance aux développeurs
Besoin d'aide pour connecter vos outils ou concevoir une automatisation personnalisée pour votre cabinet ? Notre équipe technique vous accompagne : contact@lexlo.be
Lors de vos échanges, veillez à indiquer le
request_id fourni en cas d'erreur
ainsi que le nom ou préfixe de la clé d'API utilisée.