Invoices
Une Invoice représente une facture électronique en cours de traitement. C'est l'objet central de l'API EFact.
Cycle de vie d'une facture
1
Pending
Créé
2
Signing
Signature
3
Transmitted
DGI
Accepted
Validé
Rejected
| Statut | Description |
|---|---|
pending | Facture créée, en attente de normalisation XML |
signing | XML UBL généré, signature XAdES en cours |
transmitted | Facture signée envoyée à la DGI |
accepted | DGI a accepté la facture - dgi_id disponible |
rejected | DGI a rejeté la facture - rejection_reason disponible |
POST/v1/invoices
Crée une nouvelle Invoice et lance le pipeline de traitement de manière asynchrone.
Request
Request
POST /v1/invoices
Authorization: Bearer sk_live_xxx
Content-Type: application/json
Idempotency-Key: INV-2026-042 (optionnel)Body
{
"amount": 14400,
"currency": "MAD",
"customer": {
"ice": "002345678901234",
"name": "Société Exemple SARL",
"address": "12 Rue Hassan II, Casablanca 20000",
"email": "comptabilite@exemple.ma"
},
"lines": [
{
"description": "Développement application web",
"quantity": 1,
"unit_price": 12000,
"tax_rate": 20
},
{
"description": "Hébergement mensuel",
"quantity": 1,
"unit_price": 2000,
"tax_rate": 20
}
],
"metadata": {
"internal_id": "INV-2026-042",
"project_ref": "PROJ-007"
}
}Champs de la requête
Racine
| Champ | Type | Requis | Description |
|---|---|---|---|
amount | integer | Oui | Montant total TTC en centimes DH |
currency | string | Oui | Devise - seul MAD est supporté en V0.1 |
customer | object | Oui | Informations sur le client destinataire |
lines | array | Oui | Lignes de facturation (minimum 1) |
metadata | object | Non | Données libres du client (clés/valeurs string) |
customer
| Champ | Type | Requis | Description |
|---|---|---|---|
ice | string | Oui | Identifiant Commun Entreprise (15 chiffres) |
name | string | Oui | Raison sociale |
address | string | Non | Adresse complète |
email | string | Non | Email pour envoi automatique du PDF signé |
lines[]
| Champ | Type | Requis | Description |
|---|---|---|---|
description | string | Oui | Désignation de la prestation ou du produit |
quantity | integer | Oui | Quantité (entier positif) |
unit_price | integer | Oui | Prix unitaire HT en centimes DH |
tax_rate | integer | Non | Taux de TVA en % (0, 7, 10, 14, 20) - défaut : 20 |
Response 201 Created
Response
{
"id": "inv_01H8XYZABC",
"object": "invoice",
"client_secret": "inv_01H8XYZABC_secret_b7e3f2a1c9d4",
"status": "pending",
"amount": 14400,
"currency": "MAD",
"customer": {
"ice": "002345678901234",
"name": "Société Exemple SARL"
},
"lines": [
{
"description": "Développement application web",
"quantity": 1,
"unit_price": 12000,
"tax_rate": 20,
"amount": 12000
},
{
"description": "Hébergement mensuel",
"quantity": 1,
"unit_price": 2000,
"tax_rate": 20,
"amount": 2000
}
],
"metadata": {
"internal_id": "INV-2026-042",
"project_ref": "PROJ-007"
},
"xml_url": null,
"pdf_url": null,
"dgi_id": null,
"rejection_reason": null,
"created_at": "2026-04-07T10:00:00Z",
"updated_at": "2026-04-07T10:00:00Z"
}Erreurs spécifiques
| Code HTTP | Code erreur | Cause |
|---|---|---|
400 | invalid_request | Champ ice absent ou mal formaté |
400 | invalid_request | lines vide |
422 | amount_too_small | amount inférieur à 100 centimes |
422 | invalid_ice | ice ne correspond pas à un format valide (15 chiffres numériques) |
409 | idempotency_conflict | Idempotency-Key déjà utilisée avec un payload différent |
GET/v1/invoices/:id
Récupère le statut et les détails d'une facture.
Request
Request
GET /v1/invoices/inv_01H8XYZABC
Authorization: Bearer sk_live_xxxAlternative côté frontend - utiliser le client_secret :
Alternative Request
GET /v1/invoices/inv_01H8XYZABC
Authorization: Bearer inv_01H8XYZABC_secret_b7e3f2a1c9d4Le client_secretdonne accès en lecture seule à cette unique facture - aucune donnée d'autres factures n'est accessible.
Response 200 OK
Une fois la facture acceptée :
Accepted Response
{
"id": "inv_01H8XYZABC",
"object": "invoice",
"status": "accepted",
"amount": 14400,
"currency": "MAD",
"customer": {
"ice": "002345678901234",
"name": "Société Exemple SARL"
},
"xml_url": "https://storage.googleapis.com/efact-invoices/tenant_id/2026/04/inv_01H8XYZABC.xml",
"pdf_url": "https://storage.googleapis.com/efact-invoices/tenant_id/2026/04/inv_01H8XYZABC.pdf",
"dgi_id": "DGI-2026-0042-XYZABC",
"rejection_reason": null,
"created_at": "2026-04-07T10:00:00Z",
"updated_at": "2026-04-07T10:04:23Z"
}Si la facture est rejected :
Rejected Response
{
"status": "rejected",
"dgi_id": null,
"rejection_reason": "ICE client inconnu dans le registre DGI"
}GET/v1/invoices
Liste les factures du tenant courant, avec pagination par curseur.
Request
Request
GET /v1/invoices?limit=20&status=accepted
Authorization: Bearer sk_live_xxxParamètres de filtre
| Paramètre | Type | Description |
|---|---|---|
status | string | Filtrer par statut : pending, signing, transmitted, accepted, rejected |
limit | integer | Nombre de résultats (1-100, défaut : 20) |
starting_after | string | Curseur de pagination (ID du dernier objet) |
created_after | string | ISO 8601 - factures créées après cette date |
created_before | string | ISO 8601 - factures créées avant cette date |
Response 200 OK
Response
{
"object": "list",
"data": [
{ "id": "inv_01H...", "status": "accepted", ... },
{ "id": "inv_01G...", "status": "accepted", ... }
],
"has_more": true,
"next_cursor": "inv_01G..."
}Accès temps réel via SSE
Pour suivre les transitions de statut sans polling, EFact expose un endpoint Server-Sent Events scopé au client_secret :
TypeScript
const eventSource = new EventSource(
`https://api.efact.itzenata.com/v1/invoices/${invoiceId}/stream`,
{
headers: { Authorization: `Bearer ${clientSecret}` }
}
)
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data)
console.log('Nouveau statut :', data.status) // "signing", "transmitted", "accepted"
}Le composant <InvoiceStatus /> gère cette connexion automatiquement.