
Documentation de l'API — v1
Facturation électronique • Espace développeur
Objectif
Cette API centralise la réception des factures au format canonique (JSON) pour plusieurs applications et plusieurs clients (multi-tenant). Elle permet ensuite l'envoi vers une plateforme de facturation électronique (ex : B2Brouter), avec traçabilité, idempotence et suivi des statuts.
Cycle de vie d’une facture
- DRAFT : facture créée, modifiable
- SENDING : envoi en cours vers la plateforme
- SENT : transmise à la plateforme
- ACCEPTED : acceptée par la plateforme / destinataire
- REJECTED : rejetée (erreur métier ou technique)
- ERROR : erreur lors de l’envoi (ou validation plateforme)
Chaque transition est historisée dans un journal d’événements (audit).
Base URL
https://facturation.sipco.fr
En production, remplacer par l'URL de l'API (ex : https://facturation.sipco.fr).
Authentification
Toutes les routes sous /api/v1 nécessitent une clé API interne transmise dans l’en-tête :
Authorization: Bearer VOTRE_CLE_API
Sans cet en-tête, l’API renvoie 401 Unauthorized.
Exemple rapide
curl -X GET "https://facturation.sipco.fr/api/v1/secure/ping" \ -H "Authorization: Bearer <VOTRE_CLE_API>"
GET /api/health/db
Endpoint de santé (non protégé) validant la connexion à la base.
curl -X GET "https://facturation.sipco.fr/api/health/db"
GET /api/v1/secure/ping
Endpoint protégé de test (valide l’auth API Key).
curl -X GET "https://facturation.sipco.fr/api/v1/secure/ping" \ -H "Authorization: Bearer <VOTRE_CLE_API>"
GET /api/v1/b2brouter/accounts
Liste les comptes B2Brouter accessibles (utile pour récupérer l’accountId à associer au tenant).
curl -X GET "https://facturation.sipco.fr/api/v1/b2brouter/accounts" \ -H "Authorization: Bearer <VOTRE_CLE_API>"
POST /api/v1/tenants
Création complète d’un tenant local. Cette route administrative utilise SUPERADMIN_API_KEY et n’appelle pas B2Brouter. Le body JSON n’est pas enveloppé dans account.
Body JSON (recommandé)
{
"name": "ENTREPRISE EXEMPLE",
"slug": "entreprise-exemple",
"companyName": "ENTREPRISE EXEMPLE",
"siren": "123456789",
"siret": "12345678900010",
"vatNumber": "FRXX123456789",
"rcsCity": "VILLE EXEMPLE",
"rcsNumber": "123456789",
"legalRepresentativeName": "NOM EXEMPLE",
"legalRepresentativeTitle": "Gérant",
"street": "1 RUE EXEMPLE",
"city": "VILLE EXEMPLE",
"zipCode": "35000",
"province": "Ille-et-Vilaine",
"country": "FR",
"phone": "+33 2 99 00 00 00",
"electronicInvoicingEmail": "facturation@example.fr",
"dgfipTypeOperation": "services",
"dgfipEnterpriseSize": "pme",
"dgfipNafCodePrefix": "62",
"dgfipAnnuaireOnly": true,
"dgfipStartDate": "2026-09-01"
}Les champs métier facultatifs acceptent null ou une chaîne vide, normalisée en null. Le SIRET doit commencer par le SIREN. Avec dgfipAnnuaireOnly=false, la taille et le préfixe NAF sont obligatoires. isActive, b2brouterAccountId, les statuts et l’erreur d’onboarding ne sont pas librement modifiables par ces routes.
La province est obligatoire avant la création du compte B2Brouter. Le téléphone reste facultatif et nullable. La taille et le préfixe NAF à deux chiffres sont à collecter dès l’onboarding ; en mode Annuaire uniquement, ils restent stockés sans être envoyés au réglage DGFiP.
Les valeurs DGFiP officielles sont services, goods, mixed et ge, eti, pme, micro. Les anciennes formes en majuscules restent temporairement acceptées, puis sont normalisées et stockées en minuscules.
curl -X POST "https://facturation.sipco.fr/api/v1/tenants" \
-H "Authorization: Bearer <SUPERADMIN_API_KEY>" \
-H "Content-Type: application/json" \
-d @tenant.jsonGET /api/v1/tenants/:slug
Retourne la vue administrative complète du tenant local, ses données légales, DGFiP et son état d’onboarding, sans clé ni relation sensible.
curl -X GET "https://facturation.sipco.fr/api/v1/tenants/<TENANT_SLUG>" \ -H "Authorization: Bearer <SUPERADMIN_API_KEY>"
PATCH /api/v1/tenants/:slug
Modifie partiellement les champs métier du tenant. Le slug, isActive, b2brouterAccountId et les statuts techniques restent immuables via cette route.
curl -X PATCH "https://facturation.sipco.fr/api/v1/tenants/<TENANT_SLUG>" \
-H "Authorization: Bearer <SUPERADMIN_API_KEY>" \
-H "Content-Type: application/json" \
-d '{
"rcsCity": "VILLE EXEMPLE",
"rcsNumber": "123456789",
"legalRepresentativeName": "NOM EXEMPLE",
"legalRepresentativeTitle": "Gérant"
}'Le PATCH fusionne les champs fournis avec l’état existant avant de contrôler SIREN/SIRET et les exigences DGFiP. Le tenant local est distinct du compte B2Brouter : l’association et l’onboarding externe utilisent les routes dédiées ci-dessous. Aucune route d’import batch n’est exposée à ce stade.
POST /api/v1/tenants/:slug/b2brouter/account
Crée ou rattache le compte parent français B2Brouter d’un tenant existant. Route protégée par SUPERADMIN_API_KEY. Le tenant doit disposer d’une raison sociale, d’un SIREN, d’un numéro de TVA français et d’une adresse complète, sans compte B2Brouter déjà associé.
Le Hub recherche d’abord un compte compatible par SIREN (cin_scheme=0002). Un résultat unique est rattaché ; sinon le compte parent est créé au niveau SIREN. L’adresse e-mail provient exclusivement de electronicInvoicingEmail, enregistrée au préalable dans le tenant.
curl -X POST "https://facturation.sipco.fr/api/v1/tenants/<TENANT_SLUG>/b2brouter/account" \
-H "Authorization: Bearer <SUPERADMIN_API_KEY>" \
-H "Content-Type: application/json" \
-d '{}'MVP strict : aucune unité organisationnelle SIRET, aucun transport, aucun utilisateur B2Brouter, aucune activation DGFiP et aucune TenantApiKey ne sont créés. Erreurs principales : 400 validation, 401 authentification, 404 tenant absent, 409 compte lié, ambigu, incompatible ou en conflit, 502 erreur B2Brouter, 503 configuration absente ou résultat de création incertain.
POST /api/v1/tenants/:slug/b2brouter/dgfip
Crée ou retrouve le DgfipTaxReportSetting du compte déjà lié. Cette étape distincte permet de reprendre un onboarding dont le compte existe mais dont l’inscription Annuaire manque. Route protégée par SUPERADMIN_API_KEY.
curl -X POST "https://facturation.sipco.fr/api/v1/tenants/<TENANT_SLUG>/b2brouter/dgfip" \
-H "Authorization: Bearer <SUPERADMIN_API_KEY>" \
-H "Content-Type: application/json" \
-d '{}'Le réglage est créé avec code=dgfip, enabled=true et annuaire_only=true par défaut. En mode Annuaire uniquement, la taille d’entreprise et le préfixe NAF ne sont pas obligatoires. L’e-mail, le type d’opération et la date de début viennent du tenant.
Aucun transport Peppol n’est créé manuellement. Un 422 DGFIP_DIRECTORY_ALREADY_LINKED_TO_ANOTHER_PA signale une entreprise déjà rattachée à une autre PA ; les autres erreurs 422 sont retournées sous B2BROUTER_VALIDATION_ERROR. Un compte créé ne signifie pas que l’onboarding est actif : le statut devient ACTIVE après création ou détection d’un réglage DGFiP compatible.
Emission de factures
POST /api/v1/tenants/:slug/invoices
Création d’une facture au format canonique (JSON). Statut initial : DRAFT. Un événement INVOICE_CREATED est enregistré.
Déclenche automatiquement le service sendInvoice pour vérifier la conformité des champs et déclenche l'envoie si OK.
Body JSON (exemple “prêt à envoyer”)
{
"type": "INVOICE",
"externalRef": "SIPCO-INV-2026-0003",
"issueDate": "2026-02-06",
"currency": "EUR",
"seller": {
"companyName": "SIPCO",
"siret": "32409458000051",
"vatNumber": "FR81324094580",
"address": { "street": "12 rue des artisans", "city": "Vitré", "zipCode": "35500", "country": "FR" }
},
"buyer": {
"companyName": "CLIENT TEST SARL",
"siret": "98765432100033",
"vatNumber": "FR98765432100",
"email": "contact@client.fr",
"address": { "street": "10 Avenue du Client", "city": "Paris", "zipCode": "75001", "country": "FR" }
},
"lines": [
{ "id": "1", "description": "Abonnement maintenance – Février 2026", "quantity": 1, "unitPriceExclTax": "45.00", "vatRate": 20 }
]
}curl -X POST "https://facturation.sipco.fr/api/v1/tenants/sipco/invoices" \ -H "Authorization: Bearer <VOTRE_CLE_API>" \ -H "Content-Type: application/json" \ -d @invoice.json
GET /api/v1/tenants/:slug/invoices
Liste paginée des factures d’un tenant.
Paramètres (query)
limit | number | Nombre d’éléments (défaut 50, max 200) |
offset | number | Décalage de pagination |
status | string | Filtrer par statut (DRAFT, SENT, ERROR…) |
search | string | Recherche sur externalRef (contains) |
curl -X GET "https://facturation.sipco.fr/api/v1/tenants/sipco/invoices?limit=50&offset=0" \
-H "Authorization: Bearer <VOTRE_CLE_API>"GET /api/v1/tenants/:slug/invoices/:id
Détail complet d’une facture (canonique + événements + fichiers).
curl -X GET "https://facturation.sipco.fr/api/v1/tenants/sipco/invoices/{invoiceId}" \
-H "Authorization: Bearer <VOTRE_CLE_API>"PATCH /api/v1/tenants/:slug/invoices/:id
Mise à jour d’une facture uniquement si DRAFT. Ajoute un événement INVOICE_VALIDATED.
curl -X PATCH "https://facturation.sipco.fr/api/v1/tenants/sipco/invoices/{invoiceId}" \
-H "Authorization: Bearer <VOTRE_CLE_API>" \
-H "Content-Type: application/json" \
-d '{ "buyer": { "email": "contact@client.fr" } }'POST /api/v1/tenants/:slug/invoices/:id/send
Déclenche l’envoi vers B2Brouter. L’API assure l’idempotence pour éviter un double envoi. Si la facture est incomplète, l’API bloque avant B2Brouter.
Headers optionnels
Authorization: Bearer <VOTRE_CLE_API>
Idempotency-Key: <clé_unique_côté_client>curl -X POST "https://facturation.sipco.fr/api/v1/tenants/sipco/invoices/{invoiceId}/send" \
-H "Authorization: Bearer <VOTRE_CLE_API>" \
-H "Idempotency-Key: <clé_unique>"Si déjà envoyé : 409 INVOICE_ALREADY_SENT. Si déjà en cours : 200 avec already: true.
Champs requis
1) Création / mise à jour (DRAFT)
À la création (POST) ou modification (PATCH), la facture doit respecter le schéma canonique.
externalRef(référence externe)issueDate(YYYY-MM-DD) etcurrency(ISO3, ex: EUR)seller.companyName+seller.addressbuyer.companyName+buyer.addresslines[](≥ 1) avecdescription,quantity,unitPriceExclTax
Note : certains identifiants (SIRET/TVA/email) peuvent être absents en DRAFT, mais requis à l’envoi.
2) Pré-requis à l’envoi (SEND)
Avant /send, validation renforcée pour éviter un appel fournisseur inutile.
buyer.email(email valide) → requis par B2Brouterbuyer.siretoubuyer.sirenbuyer.vatNumber(TVA intracom)
- Tenant lié à B2Brouter :
tenant.b2brouterAccountId - Sinon :
TENANT_B2BROUTER_ACCOUNT_MISSING
En cas d’échec : 400 INVOICE_NOT_READY_TO_SEND + liste des champs manquants.
Réception des factures (Incoming)
Centralise les factures reçues depuis une PDP (ex : B2Brouter) pour un tenant donné. Les factures sont synchronisées, stockées et exposées aux applications clientes.
POST /api/v1/tenants/:slug/received-invoices/sync
Synchronise les factures reçues : liste + détail JSON + document original + ACK.
POST /api/v1/tenants/:slug/received-invoices/sync Authorization: Bearer <VOTRE_CLE_API>
GET /api/v1/tenants/:slug/received-invoices
Liste des factures reçues (paginée). Filtres : status, search.
GET /api/v1/tenants/:slug/received-invoices?limit=50&offset=0
GET /api/v1/tenants/:slug/received-invoices/:id
Détail d’une facture reçue (inclut events).
GET /api/v1/tenants/:slug/received-invoices/:id
GET /api/v1/tenants/:slug/received-invoices/:id/original
Proxy sécurisé vers la PDP : renvoie le binaire original sans exposer la clé PDP.
GET /api/v1/tenants/:slug/received-invoices/:id/original
POST /api/v1/tenants/:slug/received-invoices/:id/lifecycle
Met à jour le cycle de vie. Aucun e-mail B2Brouter n'est envoyé par défaut ; commit: "with_mail" doit être fourni explicitement pour le demander.
POST /api/v1/tenants/:slug/received-invoices/:id/lifecycle
Content-Type: application/json
{"action":"accept"}
Notification e-mail explicite uniquement :
{"action":"accept","commit":"with_mail"}Codes de réponse
| Code | Signification | Description |
|---|---|---|
| 200 | OK | Requête réussie |
| 201 | Created | Ressource créée |
| 400 | Bad Request | Validation / JSON invalide |
| 401 | Unauthorized | Clé API absente ou incorrecte |
| 404 | Not Found | Tenant ou facture introuvable |
| 409 | Conflict | Conflit |
| 502 | Bad Gateway | Erreur fournisseur (B2Brouter) |
| 500 | Server Error | Erreur interne |