ANAF e-Factura (Romania) over the API

For Romania: CIUS-RO preflight, SPV submission, normalized status, signed response and the inbound supplier inbox.

For Romania: CIUS-RO preflight, SPV submission, normalized status, signed response and the inbound supplier inbox.

← Back to the API documentation

Your first invoice in 6 steps

  1. Run POST /v1/invoices/{id}/efactura/validate. The CIUS-RO preflight (Romania) sends nothing to ANAF and tells you exactly what would be rejected.
  2. File it with POST /v1/invoices/{id}/efactura/submit, always with an Idempotency-Key. You get a submission_id and a status.
  3. Poll GET /v1/efactura/submissions/{id} until it reaches accepted or rejected.
  4. Force a fresh query to the Romanian ANAF with POST /v1/efactura/submissions/{id}/refresh — it counts against the 10-per-minute bucket.
  5. Download the archive with the signed response from the Romanian ANAF via GET /v1/efactura/submissions/{id}/download.

Every endpoint

MethodEndpointScopeIdempotency-KeyRequests / minute
GET/invoices/{invoice_id}/xml
Download the UBL / CIUS-RO XML
invoices:read—120
POST/invoices/{invoice_id}/efactura/validate
CIUS-RO preflight — validate without sending
efactura:read—120
POST/invoices/{invoice_id}/efactura/submit
Submit the invoice to ANAF (SPV, Romania)
efactura:submitrequired10
GET/efactura/submissions
List ANAF submissions (Romania)
efactura:read—120
GET/efactura/submissions/{submission_id}
Retrieve one submission
efactura:read—120
POST/efactura/submissions/{submission_id}/refresh
Ask ANAF for the current state (Romania)
efactura:read—10
GET/efactura/submissions/{submission_id}/download
Download the signed response archive
efactura:read—120
GET/efactura/inbox
Supplier invoices received via the SPV (Romania)
efactura:read—120
GET/efactura/inbox/{inbound_id}
Retrieve one inbound invoice
efactura:read—120
GET/efactura/inbox/{inbound_id}/download
Download the inbound invoice archive
efactura:read—120
POST/efactura/inbox/sync
Pull new SPV messages into the inbox (Romania)
efactura:read—10

What the 4invoices API is

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,
# so /inbox/sync counts against the 10/min submit bucket. Cron it, don't poll it.

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

The ANAF e-Factura round-trip (Romania)

not_sentvalidatingqueuedsentprocessingacceptedrejectederror

Errors

StatusTypeCode
422invalid_request_errorcius_ro_incomplete

Common mistakes

  • Normalized lifecycle: not_sent → validating → queued → sent → processing → accepted | rejected | error.
  • accepted means legally transmitted. rejected means the national system (ANAF in Romania) refused it: fix and submit again. error is a transport failure on our side and is safe to retry.
  • Submission is irreversible: a second copy of the same invoice cannot be withdrawn from the national e-invoicing system. That is why the Idempotency-Key is mandatory.
  • GET /v1/invoices/{id}/xml gives you the UBL / CIUS-RO XML (the Romanian profile) with no submission at all — for your own archive or an audit.
  • Inbox: POST /v1/efactura/inbox/sync pulls new messages, GET /v1/efactura/inbox lists them, and /download fetches each inbound invoice archive.
  • The e-Factura endpoints only work for Romanian tenants; otherwise you get a 404.

Developer questions and answers

How long does ANAF (Romania) take to accept an invoice?

It varies, from seconds to hours. Do not block the sale: submit asynchronously and treat accepted and rejected as events.

Can I get the CIUS-RO XML without sending anything to ANAF (Romania)?

Yes. GET /v1/invoices/{id}/xml generates the document with no submission, and /efactura/validate with include_xml=true returns it base64-encoded.

How often can I run inbox/sync?

At most 10 calls a minute, but in practice ANAF (Romania) allows roughly one message-list call per minute per CIF. Run it from cron, every few minutes.

What do I do if the status stays error?

error is a transport or authentication failure on our side, so it is safe to retry. If it persists, send the request_id to support.