e-Factura ANAF (Roumanie) via l'API

Pour la Roumanie : contrôle CIUS-RO, dépôt au SPV, statut normalisé, réponse signée et boîte de réception fournisseurs.

Pour la Roumanie : contrôle CIUS-RO, dépôt au SPV, statut normalisé, réponse signée et boîte de réception fournisseurs.

← Retour à la documentation API

Votre première facture en 6 étapes

  1. Lancez POST /v1/invoices/{id}/efactura/validate. Le contrôle préalable CIUS-RO (Roumanie) n’envoie rien à ANAF et vous indique précisément ce qui serait refusé.
  2. Déposez la facture avec POST /v1/invoices/{id}/efactura/submit, toujours avec une Idempotency-Key. Vous obtenez un submission_id et un status.
  3. Interrogez GET /v1/efactura/submissions/{id} jusqu’à ce qu’il atteigne accepted ou rejected.
  4. Forcez une nouvelle interrogation de l’ANAF (Roumanie) avec POST /v1/efactura/submissions/{id}/refresh — elle est décomptée du quota de 10 par minute.
  5. Téléchargez l’archive contenant la réponse signée de l’ANAF (Roumanie) via GET /v1/efactura/submissions/{id}/download.

Tous les endpoints

MéthodeEndpointScopeIdempotency-KeyRequêtes / minute
GET/invoices/{invoice_id}/xml
Télécharger le XML UBL / CIUS-RO (Roumanie)
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:submitobligatoire10
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

Ce qu'est l'API 4invoices

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)
bash
# Pull new SPV messages, then read the inbound supplier invoices.
curl -sS -X POST https://api.4invoices.net/v1/efactura/inbox/sync \
  -H "Authorization: Bearer $ACCESS_TOKEN"

curl -sS "https://api.4invoices.net/v1/efactura/inbox?limit=50" \
  -H "Authorization: Bearer $ACCESS_TOKEN"

# ANAF allows roughly ONE message-list call per minute per CIF,
# donc /inbox/sync compte dans le quota d'envoi de 10/min. Planifiez-le par cron, ne l'interrogez pas.

https://api.4invoices.net/v1 · https://api.4invoices.net/v1/openapi.json

Le circuit ANAF e-Factura (Roumanie)

not_sentvalidatingqueuedsentprocessingacceptedrejectederror

Erreurs

StatutTypeCode
422invalid_request_errorcius_ro_incomplete

Erreurs fréquentes

  • Cycle de vie normalisé : not_sent → validating → queued → sent → processing → accepted | rejected | error.
  • accepted signifie transmis légalement. rejected signifie que le système national (l’ANAF en Roumanie) l’a refusée : corrigez et déposez à nouveau. error est un échec de transport de notre côté, que l’on peut relancer sans risque.
  • Le dépôt est irréversible : une seconde copie de la même facture ne peut pas être retirée du système national de facturation électronique. C’est pourquoi l’Idempotency-Key est obligatoire.
  • GET /v1/invoices/{id}/xml vous fournit le XML UBL / CIUS-RO (le profil roumain) sans aucun dépôt — pour votre propre archive ou un audit.
  • Boîte de réception : POST /v1/efactura/inbox/sync récupère les nouveaux messages, GET /v1/efactura/inbox les liste, et /download récupère l’archive de chaque facture reçue.
  • Les endpoints e-Factura ne fonctionnent que pour les tenants roumains ; sinon, vous recevez une 404.

Questions et réponses pour développeurs

Combien de temps ANAF (Roumanie) met-elle pour accepter une facture ?

Cela varie, de quelques secondes à plusieurs heures. Ne bloquez pas la vente : déposez de manière asynchrone et traitez accepted et rejected comme des événements.

Puis-je obtenir le XML CIUS-RO sans rien envoyer à l’ANAF (Roumanie) ?

Oui. GET /v1/invoices/{id}/xml génère le document sans dépôt, et /efactura/validate avec include_xml=true le renvoie encodé en base64.

À quelle fréquence puis-je lancer inbox/sync ?

Au maximum 10 appels par minute, mais en pratique, en Roumanie, ANAF autorise environ un appel de liste de messages par minute et par CIF. Lancez-le depuis un cron, toutes les quelques minutes.

Que faire si le statut reste à error ?

error est un échec de transport ou d’authentification de notre côté, il est donc sans risque de réessayer. Si cela persiste, envoyez le request_id au support.