L'API publique 4invoices envoie les données de facturation de votre système vers 4invoices et, en Roumanie, mène la facture jusqu'au bout dans le SPV de l'ANAF. Un seul hôte de production, un flux client_credentials, des écritures fiscales idempotentes et une enveloppe d'erreur identique sur toutes les routes.
https://api.4invoices.net/v1 · Spécification OpenAPI (sans clé)
Ce qu'est l'API 4invoices
- L’API publique de 4invoices est une API REST sur HTTPS, avec du JSON en entrée et en sortie.
- Un seul hôte de production : https://api.4invoices.net/v1. Il n’existe pas d’hôte de test séparé.
- La spécification OpenAPI 3.1 est publique et accessible sans clé — importez-la directement dans Postman ou dans un générateur de clients.
- Chaque réponse contient un en-tête X-Request-Id ; indiquez-le lorsque vous contactez le support.
- Chaque écriture fiscale est idempotente : une nouvelle tentative après un timeout n’émet jamais un second document.
- Pour la Roumanie, le circuit e-Factura d’ANAF complet via l’API : contrôle préalable, dépôt, suivi, réponse signée et boîte de réception entrante. Aucun concurrent roumain ne propose cela.
- SmartBill n’a aucun point de terminaison pour le dépôt dans le système national de facturation électronique (ANAF, en Roumanie) — l’envoi vers le SPV est un simple réglage de compte dans l’interface — et aucun point de terminaison de liste des factures.
- Oblio ne peut créer des clients et des produits qu’en effet secondaire de l’émission d’un document, et non comme ressources à part entière.
- Génération du XML UBL / CIUS-RO (Roumanie) sans dépôt : vous obtenez le document légal sous forme de fichier sans toucher au SPV.
- Idempotence sur les écritures fiscales : une nouvelle tentative après un timeout ne produit ni seconde facture ni second numéro consommé.
- Une boîte de réception des factures fournisseurs lisible par programme — la base d’un rapprochement automatisé.
Votre première facture en 6 étapes
- Créez des identifiants dans le panneau, sous Facturation → Paramètres → Accès API, et copiez le client_secret — il n'est affiché qu'une seule fois.
- Complétez le profil de l'entreprise et activez au moins une série de type fiscale, sinon l'émission renvoie issuer_profile_incomplete ou no_series_configured.
- Créez des identifiants dans le panneau, sous Facturation → Paramètres → Accès API, et copiez le client_secret — il n'est affiché qu'une seule fois.
- Complétez le profil de l'entreprise et activez au moins une série de type fiscale, sinon l'émission renvoie issuer_profile_incomplete ou no_series_configured.
- Échangez les identifiants contre un token : POST /v1/auth/token avec grant_type client_credentials. Le token dure une heure — mettez-le en cache, n'en demandez pas un par requête.
- Émettez la facture : POST /v1/invoices avec un en-tête Idempotency-Key et vat_rate en pourcentage (21, pas 0.21).
- Pour le marché roumain, lancez le contrôle CIUS-RO avec POST /v1/invoices/{id}/efactura/validate, puis envoyez la facture à l'ANAF avec POST /v1/invoices/{id}/efactura/submit.
- Suivez l'état avec GET /v1/efactura/submissions/{id} jusqu'à ce qu'il atteigne accepted ou rejected.
bash
# 1 — token (1 heure, à mettre en cache)
ACCESS_TOKEN=$(curl -sS -X POST https://api.4invoices.net/v1/auth/token \
-H 'Content-Type: application/json' \
-d '{"grant_type":"client_credentials","client_id":"cli_XXX","client_secret":"sec_XXX"}' \
| python3 -c 'import sys,json; print(json.load(sys.stdin)["access_token"])')
# 2 — émettre la facture (Idempotency-Key est OBLIGATOIRE)
curl -sS -X POST https://api.4invoices.net/v1/invoices \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: order-10457-invoice' \
-d '{"buyer":{"name":"Exemplu Comert SRL","tax_id":"RO12345678","county":"Cluj","city":"Cluj-Napoca","country":"RO"},
"lines":[{"description":"Abonament SaaS","quantity":1,"unit_price":400,"vat_rate":21}]}'
# 3 — preflight CIUS-RO, then send to ANAF
curl -sS -X POST https://api.4invoices.net/v1/invoices/inv_01J7ABC/efactura/validate \
-H "Authorization: Bearer $ACCESS_TOKEN"
curl -sS -X POST https://api.4invoices.net/v1/invoices/inv_01J7ABC/efactura/submit \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Idempotency-Key: efactura-inv_01J7ABC-1'javascript
const BASE = "https://api.4invoices.net/v1";
const token = await fetch(`${BASE}/auth/token`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
grant_type: "client_credentials",
client_id: process.env.FOURINVOICES_CLIENT_ID,
client_secret: process.env.FOURINVOICES_CLIENT_SECRET,
}),
}).then((r) => r.json()).then((d) => d.access_token);
const invoice = await fetch(`${BASE}/invoices`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
"Idempotency-Key": `order-${orderId}-invoice`,
},
body: JSON.stringify({
buyer: { name: "Exemplu Comert SRL", tax_id: "RO12345678", county: "Cluj", city: "Cluj-Napoca", country: "RO" },
lines: [{ description: "Abonament SaaS", quantity: 1, unit_price: 400, vat_rate: 21 }],
currency: "RON",
metadata: { order_id: String(orderId) },
}),
}).then((r) => r.json());
console.log(invoice.number, invoice.totals); // "FCT-000123" { net, vat, gross }python
import os, uuid, requests
BASE = "https://api.4invoices.net/v1"
token = requests.post(f"{BASE}/auth/token", json={
"grant_type": "client_credentials",
"client_id": os.environ["FOURINVOICES_CLIENT_ID"],
"client_secret": os.environ["FOURINVOICES_CLIENT_SECRET"],
}, timeout=30).json()["access_token"]
headers = {
"Authorization": f"Bearer {token}",
# Une clé par opération LOGIQUE — réutilisez-la au nouvel essai, ne la régénérez jamais.
"Idempotency-Key": f"order-{order_id}-invoice",
}
invoice = requests.post(f"{BASE}/invoices", headers=headers, json={
"buyer": {"name": "Exemplu Comert SRL", "tax_id": "RO12345678",
"county": "Cluj", "city": "Cluj-Napoca", "country": "RO"},
"lines": [{"description": "Abonament SaaS", "quantity": 1,
"unit_price": 400, "vat_rate": 21}], # pourcentage, pas 0.21
"currency": "RON",
}, timeout=60).json()
print(invoice["number"], invoice["totals"])Authentification
- Le flux est client_credentials : vous échangez client_id + client_secret contre un access_token de type Bearer.
- Le jeton expire au bout de 3600 secondes. Renouvelez-le avant son expiration, pas à chaque appel — POST /auth/token a sa propre limite de débit par IP.
- Le client_secret n’est stocké que sous forme de hash et ne peut pas être récupéré. Si vous le perdez, créez un nouvel identifiant et révoquez l’ancien.
- Serveur à serveur uniquement. Aucune origine navigateur n’est autorisée par CORS : depuis le JavaScript d’une page, le secret fuiterait vers le visiteur.
- Les scopes sont attribués par identifiant. Créez un identifiant distinct pour chaque système et donnez à chacun uniquement les scopes strictement nécessaires.
Facturation → Paramètres → Accès API
bash
curl -sS -X POST https://api.4invoices.net/v1/auth/token \
-H 'Content-Type: application/json' \
-d '{
"grant_type": "client_credentials",
"client_id": "cli_XXXXXXXXXXXX",
"client_secret": "sec_XXXXXXXXXXXXXXXXXXXX"
}'
# → {"access_token":"eyJ...","token_type":"Bearer","expires_in":3600,
# "scope":"invoices:read invoices:write efactura:submit"}javascript
// Mettez le token en cache ; n'en générez pas un par requête.
let cached = { token: "", expiresAt: 0 };
async function getToken() {
if (cached.token && Date.now() < cached.expiresAt - 60_000) return cached.token;
const res = await fetch("https://api.4invoices.net/v1/auth/token", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
grant_type: "client_credentials",
client_id: process.env.FOURINVOICES_CLIENT_ID,
client_secret: process.env.FOURINVOICES_CLIENT_SECRET,
}),
});
if (!res.ok) throw new Error(`token ${res.status}`);
const data = await res.json();
cached = { token: data.access_token, expiresAt: Date.now() + data.expires_in * 1000 };
return cached.token;
}Les taux de TVA sont des pourcentages
vat_rate: 21 ✓ · vat_rate: 0.19 ✗ · vat_rate: 1 ✗- vat_rate est un POURCENTAGE : 21 signifie 21 %.
- Les valeurs dans l’intervalle (0, 1] sont refusées — 0.19 est une fraction, et 1 est ambigu entre 1 % et 100 %.
- 0 est valide et signifie exonération ou autoliquidation ; placez la mention légale dans notes.
- unit_price est le prix unitaire HORS TAXES lorsque l’émetteur est assujetti à la TVA.
- Besoin des totaux avant de valider ? POST /v1/invoices/preview-totals effectue le même calcul sans consommer de numéro fiscal.
Idempotence sur les écritures fiscales
- L’en-tête Idempotency-Key est OBLIGATOIRE sur POST /invoices, POST /invoices/{id}/storno et POST /invoices/{id}/efactura/submit.
- Les clés sont conservées pendant 24 heures. Renvoyer la même clé avec le même corps retourne le résultat initial et positionne Idempotency-Replayed: true.
- La même clé avec un corps différent renvoie 409 idempotency_key_reuse — un document fiscal déjà émis n’est jamais écrasé.
- Une clé par opération LOGIQUE, pas par tentative HTTP : order-10457-invoice, et non un nouvel UUID à chaque nouvelle tentative.
- La raison est juridique, pas technique : un numéro fiscal consommé et une facture déposée dans le système national de facturation électronique ne peuvent pas être retirés.
bash
curl -sS -X POST https://api.4invoices.net/v1/invoices \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: order-10457-invoice' \
-d '{
"buyer": {
"name": "Exemplu Comert SRL",
"tax_id": "RO12345678",
"address": "Str. Fabricii 12",
"city": "Cluj-Napoca",
"county": "Cluj",
"country": "RO",
"email": "[email protected]"
},
"lines": [
{ "description": "Abonament SaaS, iulie", "quantity": 1, "unit_price": 400, "vat_rate": 21, "unit": "buc" },
{ "description": "Implementare", "quantity": 6, "unit_price": 250, "vat_rate": 21, "unit": "ora" }
],
"currency": "RON",
"document_kind": "factura",
"due_date": "2026-08-15",
"metadata": { "order_id": "10457" }
}'Tous les endpoints
| Méthode | Endpoint | Scope | Idempotency-Key | Requêtes / minute |
|---|---|---|---|---|
| POST | /auth/token Échanger les identifiants contre un token d'accès | — | — | 120 |
| GET | /me Tenant, scopes et limites actuelles | invoices:read | — | 120 |
| POST | /invoices Émettre une facture ou une proforma | invoices:write | obligatoire | 30 |
| GET | /invoices Lister les factures (pagination par curseur) | invoices:read | — | 120 |
| POST | /invoices/preview-totals Calculer les totaux sans rien créer | invoices:read | — | 120 |
| GET | /invoices/{invoice_id} Récupérer une facture | invoices:read | — | 120 |
| GET | /invoices/{invoice_id}/pdf Télécharger le PDF de la facture | invoices:read | — | 120 |
| GET | /invoices/{invoice_id}/xml Télécharger le XML UBL / CIUS-RO (Roumanie) | invoices:read | — | 120 |
| POST | /invoices/{invoice_id}/storno Émettre un avoir annulant cette facture | invoices:write | obligatoire | 30 |
| POST | /invoices/{invoice_id}/payments Marquer la facture comme payée | invoices:write | — | 30 |
| DELETE | /invoices/{invoice_id}/payments Marquer la facture comme non payée | invoices:write | — | 30 |
| GET | /clients Lister les clients | clients:read | — | 120 |
| POST | /clients Créer ou mettre à jour un client | clients:write | — | 30 |
| GET | /lookup/company/{tax_id} Valider un CUI roumain dans le registre ANAF | clients:read | — | 120 |
| GET | /series Lister les séries de numérotation | invoices:read | — | 120 |
| POST | /invoices/{invoice_id}/efactura/validate Contrôle préalable CIUS-RO (Roumanie) — valider sans envoyer | efactura:read | — | 120 |
| POST | /invoices/{invoice_id}/efactura/submit Envoyer la facture à l'ANAF (SPV, Roumanie) | efactura:submit | obligatoire | 10 |
| GET | /efactura/submissions Lister les envois à l'ANAF (Roumanie) | efactura:read | — | 120 |
| GET | /efactura/submissions/{submission_id} Récupérer un envoi | efactura:read | — | 120 |
| POST | /efactura/submissions/{submission_id}/refresh Demander à l'ANAF (Roumanie) l'état actuel | efactura:read | — | 10 |
| GET | /efactura/submissions/{submission_id}/download Télécharger l'archive signée de la réponse | efactura:read | — | 120 |
| GET | /efactura/inbox Factures fournisseurs reçues via le SPV (Roumanie) | efactura:read | — | 120 |
| GET | /efactura/inbox/{inbound_id} Récupérer une facture reçue | efactura:read | — | 120 |
| GET | /efactura/inbox/{inbound_id}/download Télécharger l'archive de la facture reçue | efactura:read | — | 120 |
| POST | /efactura/inbox/sync Récupérer les nouveaux messages SPV (ANAF, Roumanie) dans la boîte de réception | efactura:read | — | 10 |
25 endpoints · https://api.4invoices.net/v1/openapi.json
Scopes
- invoices:read
- invoices:write
- clients:read
- clients:write
- efactura:read
- efactura:submit
Le circuit ANAF e-Factura (Roumanie)
- Le vrai facteur de différenciation : pour la Roumanie, l’intégralité du circuit e-Factura d’ANAF passe par l’API, pas seulement la génération du document.
- POST /invoices/{id}/efactura/validate exécute le contrôle préalable CIUS-RO (Roumanie) et renvoie précisément les champs qu’ANAF refuserait, sans rien envoyer.
- GET /invoices/{id}/xml génère le XML UBL / CIUS-RO (le profil roumain) sans dépôt — utile pour votre propre archive ou un audit interne.
- POST /invoices/{id}/efactura/submit dépose la facture dans le SPV (ANAF, Roumanie). C’est irréversible : une seconde copie de la même facture ne peut pas être retirée du SPV roumain.
- Le cycle de vie est normalisé : not_sent → validating → queued → sent → processing → accepted | rejected | error. accepted signifie transmis légalement ; error est un échec de transport de notre côté, que l’on peut relancer sans risque.
- GET /efactura/submissions/{id}/download récupère l’archive contenant la réponse signée de l’ANAF (Roumanie).
- Le côté réception existe aussi : POST /efactura/inbox/sync récupère les nouveaux messages du SPV (ANAF, Roumanie) et GET /efactura/inbox liste les factures que vos fournisseurs vous ont envoyées.
bash
# CIUS-RO preflight. Sends NOTHING to ANAF.
curl -sS -X POST "https://api.4invoices.net/v1/invoices/inv_01J7ABC/efactura/validate?include_xml=true" \
-H "Authorization: Bearer $ACCESS_TOKEN"
# → {"invoice_id":"inv_01J7ABC","valid":false,
# "errors":["buyer.county is required for RO buyers"],
# "xml_base64":"PD94bWwg..."}bash
curl -sS -X POST https://api.4invoices.net/v1/invoices/inv_01J7ABC/efactura/submit \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Idempotency-Key: efactura-inv_01J7ABC-1'
# → {"submission_id":"sub_01J7XYZ","status":"queued"}python
import time, requests
BASE = "https://api.4invoices.net/v1"
TERMINAL = {"accepted", "rejected"}
H = {"Authorization": f"Bearer {token}"}
def wait_for_anaf(submission_id, timeout=900):
deadline = time.time() + timeout
delay = 15
while time.time() < deadline:
r = requests.get(f"{BASE}/efactura/submissions/{submission_id}", headers=H, timeout=30)
r.raise_for_status()
status = r.json()["status"]
if status in TERMINAL:
return r.json()
# /refresh asks ANAF directly and shares the 10/min submit bucket.
requests.post(f"{BASE}/efactura/submissions/{submission_id}/refresh", headers=H, timeout=30)
time.sleep(delay)
delay = min(delay * 2, 120)
raise TimeoutError(submission_id)Erreurs
- Toutes les réponses 4xx et 5xx utilisent la même enveloppe : { "error": { type, code, message, param?, doc_url, request_id, errors? } }.
- type est la catégorie générale sur laquelle vous branchez votre logique (« puis-je réessayer ? »), et code est le motif stable que vous faites correspondre dans votre propre système.
- param est le chemin pointé du champ en cause, par exemple lines.0.vat_rate.
- errors[] apparaît lorsqu’une même requête présente des problèmes sur plusieurs champs.
- request_id est journalisé de notre côté. Indiquez-le dans toute demande d'assistance — il identifie la requête exacte.
- Un 404 est également renvoyé pour un id appartenant à un autre tenant : nous ne confirmons jamais l’existence des données de quelqu’un d’autre.
json
{
"error": {
"type": "invalid_request_error",
"code": "validation_failed",
"message": "Datele trimise nu sunt valide.",
"param": "lines.0.vat_rate",
"doc_url": "https://4invoices.net/ro/api-dezvoltatori#errors",
"request_id": "req_8a893f2f33d4472da8d6e144",
"errors": [
{ "param": "lines.0.vat_rate", "message": "VAT rate must be a percent (21), not a fraction", "type": "value_error" }
]
}
}| Statut | Type | Code |
|---|---|---|
| 401 | authentication_error | missing_bearer_token |
| 401 | authentication_error | invalid_client |
| 401 | authentication_error | token_expired |
| 401 | authentication_error | invalid_token |
| 401 | authentication_error | unauthorized |
| 403 | permission_error | insufficient_scope |
| 403 | permission_error | forbidden |
| 404 | not_found_error | not_found |
| 409 | conflict_error | idempotency_key_reuse |
| 409 | conflict_error | idempotency_in_progress |
| 409 | conflict_error | no_series_configured |
| 422 | invalid_request_error | validation_failed |
| 422 | invalid_request_error | issuer_profile_incomplete |
| 422 | invalid_request_error | cius_ro_incomplete |
| 422 | invalid_request_error | cannot_storno_draft |
| 422 | invalid_request_error | nothing_to_storno |
| 422 | invalid_request_error | invalid_json_number |
| 429 | rate_limit_error | rate_limit_exceeded |
| 502 | upstream_error | upstream_error |
| 503 | service_unavailable_error | service_unavailable |
Limites de débit
| Bucket | Requêtes / minute | Signification |
|---|---|---|
| read | 120 | GET *, POST /invoices/preview-totals, POST /invoices/{id}/efactura/validate |
| write | 30 | POST /invoices, POST /invoices/{id}/storno, POST|DELETE /invoices/{id}/payments, POST /clients |
| submit | 10 | POST /invoices/{id}/efactura/submit, POST /efactura/submissions/{id}/refresh, POST /efactura/inbox/sync |
- Les limites s’appliquent par identifiant et par minute : 120 pour les lectures, 30 pour les écritures, 10 pour les opérations de facturation électronique (submit, refresh, inbox/sync).
- X-RateLimit-Limit, X-RateLimit-Remaining et X-RateLimit-Reset figurent sur CHAQUE réponse, y compris la 429.
- Une 429 contient aussi Retry-After en secondes. Respectez-le ; ne réessayez pas dans une boucle serrée.
- Le quota de 10/min existe parce qu’en Roumanie ANAF autorise elle-même environ un appel de liste de messages par minute et par CIF.
- Placez /efactura/inbox/sync dans un cron, pas dans un polling agressif.
- Besoin de plafonds plus élevés ? Faites-en la demande via le formulaire de contact en indiquant votre volume journalier prévu.
X-RateLimit-Limit · X-RateLimit-Remaining · X-RateLimit-Reset · Retry-After
http
HTTP/2 429
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1785312000
Retry-After: 17
Content-Type: application/json
{"error":{"type":"rate_limit_error","code":"rate_limit_exceeded",
"message":"...","doc_url":"https://4invoices.net/ro/api-dezvoltatori#errors",
"request_id":"req_..."}}javascript
// Respectez Retry-After ; ne retentez jamais un 4xx autre que 429.
async function call(url, init, attempt = 0) {
const res = await fetch(url, init);
if (res.status === 429 || res.status >= 500) {
if (attempt >= 5) return res;
const retryAfter = Number(res.headers.get("Retry-After")) || 2 ** attempt;
await new Promise((r) => setTimeout(r, retryAfter * 1000));
return call(url, init, attempt + 1);
}
return res;
}
// Une nouvelle tentative d'écriture DOIT réutiliser le MÊME Idempotency-Key, sinon vous émettez
// un second document fiscal.Guides par sujet
Chaque sujet a sa page, avec les endpoints, exemples et erreurs correspondants.
- Authentification à l'API 4invoicesÉchangez client_id et client_secret contre un token Bearer valable une heure, de serveur à serveur uniquement.
- Émettre des factures via l'APIPOST /invoices avec Idempotency-Key, TVA en pourcentage, plus listing, avoir et marquage payé.
- Clients et vérification au registre ANAF (Roumanie)Une insertion ou mise à jour dédoublonnée sur tax_id et une recherche au registre ANAF pour les entreprises roumaines, afin que l'e-Factura ne soit pas refusée.
- e-Factura ANAF (Roumanie) via l'APIPour la Roumanie : contrôle CIUS-RO, dépôt au SPV, statut normalisé, réponse signée et boîte de réception fournisseurs.
- Séries de numérotation dans l'APISans série active de type fiscale, l'émission renvoie 409 no_series_configured.
- Codes d'erreur et enveloppe d'erreurUn seul format sur toutes les routes : type, code, message, param, doc_url, request_id et errors.
- Limites de débit et retries120 lectures, 30 écritures et 10 opérations de facturation électronique par minute et par identifiant, avec les en-têtes X-RateLimit-*.
Erreurs fréquentes
- Envoyer la TVA sous forme de fraction (0.19) ou de 1. Les deux sont refusés ; envoyez 19 ou 21.
- Créer un jeton par requête. Le jeton est valable une heure ; mettez-le en cache, sinon vous atteindrez la limite par IP de l’endpoint de jeton.
- Générer une nouvelle clé d’idempotence à chaque nouvelle tentative — précisément le scénario qui produit des factures en double.
- Appeler l’API depuis du JavaScript dans le navigateur. CORS bloque toutes les origines, et le secret serait de toute façon exposé.
- Déposer dans le système national de facturation électronique sans contrôle préalable (CIUS-RO en Roumanie). Un dépôt erroné ne peut pas être retiré.
- Interroger /efactura/submissions/{id}/refresh plus de 10 fois par minute — ce quota est partagé avec submit.
- Émettre avant que le profil de la société soit complet et qu’une série fiscale active existe.
Questions et réponses pour développeurs
Comment obtenir des identifiants pour l'API 4invoices ?
Dans le panneau, sous Facturation → Paramètres → Accès API. Vous recevez un client_id et un client_secret ; le secret n'est affiché qu'une fois et n'est stocké que sous forme de hash.
Quelle est la durée de validité de l'access_token ?
3600 secondes, soit une heure. Mettez-le en cache et renouvelez-le avant expiration — l'endpoint de token a sa propre limite par IP.
Comment envoyer le taux de TVA ?
En pourcentage : 21 pour 21 %. Les valeurs dans (0, 1] sont refusées, donc 0.19 et 1 échouent.
Quels appels exigent un Idempotency-Key ?
POST /invoices, POST /invoices/{id}/storno et POST /invoices/{id}/efactura/submit. Les clés sont mémorisées 24 heures et un rejeu renvoie le document original avec Idempotency-Replayed: true.
Puis-je soumettre une facture à l'e-Factura ANAF (Roumanie) directement via l'API ?
Oui, pour le marché roumain : contrôle CIUS-RO avec /efactura/validate, dépôt avec /efactura/submit, suivi du statut normalisé sur /efactura/submissions/{id} et téléchargement de la réponse signée de l'ANAF.
Quelles sont les limites de débit ?
Par identifiant et par minute : 120 lectures, 30 écritures et 10 opérations de facturation électronique. Chaque réponse porte les en-têtes X-RateLimit-*, et un 429 ajoute Retry-After.
Puis-je appeler l'API depuis mon frontend ?
Non. Elle est strictement serveur à serveur : aucune origine de navigateur ne passe CORS, et un client_secret n'a rien à faire dans du code livré au visiteur.
Pourquoi ai-je issuer_profile_incomplete sur ma première facture ?
Le profil de société est incomplet ou aucune série active de type fiscale n'existe. Complétez les deux dans le panneau ; l'API refuse de produire un document fiscal invalide.