Cum trimiți e-Factura prin API-ul ANAF, pas cu pas
Ghid pas cu pas pentru autentificare ANAF prin certificat eIDAS, generare UBL CIUS-RO, semnătură XAdES, upload, polling status și erori clasice.
Cuprins
- Ce ai nevoie ca să trimiți e-Factura prin API?
- Pasul 1: autentificare cu ANAF
- Pasul 2: generarea XML-ului UBL CIUS-RO
- Pasul 3: semnătura XAdES
- Pasul 4: upload-ul în e-Factura
- Pasul 5: polling pentru status și descărcarea răspunsului
- Care sunt erorile comune la trimiterea e-Facturii prin API?
- De ce crawlerra pentru integrarea e-Factura?
Ghid practic pentru dezvoltatori care vor să trimită e-Factura direct prin API-ul ANAF, fără SaaS intermediar de tipul SmartBill, Oblio sau FGO. Acoperim întregul flux: obținerea token-ului de acces prin OAuth2 bazat pe certificat eIDAS, generarea XML-ului UBL conform profilului CIUS-RO, aplicarea semnăturii XAdES, upload-ul, polling-ul răspunsului asincron și gestiunea erorilor.
Înainte să intri pe această cale, asigură-te că ai motivul potrivit. Direct prin ANAF e justificat la volume peste câteva mii de facturi pe lună, la nevoia de a servi mai mulți clienți cu același sistem, sau când vrei control total pe formatul XML și pe semnătura electronică. Pentru volume mici și un singur sistem, fluxul prin SaaS de facturare iese mai ieftin ca timp de inginerie. Decizia de fond e discutată mai pe larg în entry-ul despre e-Factura.
Ce ai nevoie ca să trimiți e-Factura prin API?
Îți trebuie patru lucruri: certificat digital eIDAS calificat, cont activ în SPV, URL-urile de mediu (sandbox și producție) și un procesor Schematron pentru validare locală. Toate sunt obligatorii înainte de prima cerere:
- Certificat digital eIDAS calificat, emis de un furnizor acreditat din România (Trans Sped, certSIGN, DigiSign etc.). Tipul potrivit pentru API este cel pentru semnătură electronică calificată (QES). Token USB sau soft, ambele funcționează.
- Cont activ în SPV (Spațiul Privat Virtual) al ANAF, asociat cu CUI-ul firmei. SPV-ul este punctul de înregistrare pentru certificat ca dispozitiv autorizat pentru API.
- URL-urile de mediu: sandbox (api.anaf.ro/test/FCTEL) și producție (api.anaf.ro/prod/FCTEL). Endpoint-urile sunt aproape identice ca structură; doar host-ul diferă.
- Procesor Schematron local, pentru validarea XML-urilor înainte de trimitere. saxon-HE (Java) este combinația standard, dar există procesoare echivalente în Node.js și Python.
Documentația tehnică oficială este publicată la efactura.anaf.ro, secțiunea „Specificații tehnice"1. Schimbările apar de obicei sub forma de noi versiuni ale schemei sau ale Schematronului; urmărește acea pagină pentru anunțuri.
Pasul 1: autentificare cu ANAF
Fluxul de autentificare folosește OAuth2 pe varianta authorization-code, dar are o particularitate: autorizarea inițială se face printr-un browser care are atașat un certificat client TLS. ANAF nu acceptă autorizare programatică pentru pasul inițial; trebuie să loghezi efectiv un utilizator având certificatul în interfața de autorizare.
- Înregistrezi o aplicație la ANAF (logout.anaf.ro) și primești
client_idșiclient_secret. - Construiești URL-ul de autorizare cu
redirect_uricătre endpoint-ul tău și deschizi browser-ul având certificatul client atașat. - După consimțământ, ANAF redirecționează către
redirect_uricucodeca parametru. - Schimbi
codepentru unaccess_tokenși unrefresh_tokenprintr-un POST către endpoint-ul de token, pe HTTPS, având certificat client atașat. - Stochezi token-urile securizat. Access-token-ul durează aproximativ 90 de zile; refresh-token-ul, mai mult, dar nu nelimitat.
Implementarea în Java cu Apache HttpClient cere configurare explicită a SSLContext cu KeyStore-ul certificatului. În Node.js, biblioteca https nativă acceptă cert și key direct. În ambele cazuri, eroarea cea mai frecventă este lipsa lanțului intermediar de certificate (CA-urile părinte) în store-ul tău.
Pasul 2: generarea XML-ului UBL CIUS-RO
XML-ul respectă profilul CIUS-RO definit prin OMFP 1366/2021. Structura de bază pentru o factură simplă, pe scheletul UBL 2.1:
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
<cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:efactura.mfinante.ro:CIUS-RO:1.0.1</cbc:CustomizationID>
<cbc:ID>FAC-2026-0001</cbc:ID>
<cbc:IssueDate>2026-06-28</cbc:IssueDate>
<cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
<cbc:DocumentCurrencyCode>RON</cbc:DocumentCurrencyCode>
<cac:AccountingSupplierParty> ... </cac:AccountingSupplierParty>
<cac:AccountingCustomerParty> ... </cac:AccountingCustomerParty>
<cac:TaxTotal> ... </cac:TaxTotal>
<cac:LegalMonetaryTotal> ... </cac:LegalMonetaryTotal>
<cac:InvoiceLine> ... </cac:InvoiceLine>
</Invoice>
Câmpurile obligatorii care sunt invalidate cel mai des de ANAF: CustomizationID trebuie să fie exact URI-ul CIUS-RO (versiunea curentă), InvoiceTypeCode trebuie să fie din lista permisă (380 factură, 381 notă de credit, 384 factură corectivă), iar DocumentCurrencyCode trebuie să fie cod ISO 4217.
Validează XML-ul local înainte de upload, în două treceri: validare XSD UBL 2.1 (prinde greșeli structurale) și validare Schematron CIUS-RO (prinde greșelile semantice). Trecerea ambele înseamnă 90% șansă să treci și de validarea ANAF de pe server.
Pasul 3: semnătura XAdES
Documentul XML trebuie semnat folosind certificatul digital calificat, în profilul XAdES-B-B (variant basic). Semnătura este aplicată după ce XML-ul UBL este complet; orice modificare ulterioară invalidează semnătura.
În Java, librăria DSS (Digital Signature Services) de la eIDAS face semnătura într-un singur apel: încarci documentul, configurezi parametrii (XAdES-B-B, hash SHA-256, semnătură detașată sau embedded), citești certificatul din KeyStore, semnezi. Output-ul este un XML cu blocul <ds:Signature> inserat conform standardului.
În Node.js, xades-js sau node-forge + manipulare manuală XML acoperă cazul, dar fluxul este mai laborios decât în Java. Pentru proiecte serioase, recomandarea practică este să apelezi un serviciu de semnare scris în Java pentru semnătură și să întorci XML-ul semnat înapoi în flux-ul tău principal.
Pasul 4: upload-ul în e-Factura
Endpoint-ul de upload pentru sandbox: POST https://api.anaf.ro/test/FCTEL/rest/upload. Pentru producție: https://api.anaf.ro/prod/FCTEL/rest/upload. Headers obligatorii: Content-Type: text/plain (nu XML, contrar așteptării; este o particularitate a API-ului), Authorization: Bearer <access_token>, plus certificatul client TLS atașat la nivel de transport.
Răspunsul imediat este un XML mic cu identificatorul încărcării (index_incarcare):
<header xmlns="mfp:anaf:dgti:efactura:transformerExeFactura:v1"
Index_incarcare="123456789"
ResponseDate="2026-06-28T10:23:45+02:00"
ExecutionStatus="0"/>
ExecutionStatus 0 înseamnă „acceptat pentru procesare". Validarea propriu-zisă este asincronă; rezultatul vine ulterior. Stochează Index_incarcare împreună cu factura comercială pentru a putea face polling.
Pasul 5: polling pentru status și descărcarea răspunsului
Endpoint-ul de status: GET /stareMesaj?id_incarcare=<Index_incarcare>. Răspunsurile posibile:
- nok: respins la validare. Răspunsul include codurile de eroare cu sensul lor.
- ok: acceptat. Documentul este disponibil pentru descărcare prin endpoint-ul
/descarcare. - in prelucrare: încă în coadă. Continuă polling-ul.
- XML cu erori: validare eșuată cu mesaje. Repară XML-ul și trimite din nou.
Cadența recomandată de polling: la 30 secunde pentru primele cinci minute, apoi la 2 minute pentru următoarele 30 de minute, apoi la 10 minute. Cele mai multe răspunsuri vin în 1-5 minute; cele lente, în 30-60 minute la încărcare mare de trafic ANAF. Folosește un job persistent (nu un setTimeout în memorie), pentru că procesul tău se poate restarta între cereri2.
Care sunt erorile comune la trimiterea e-Facturii prin API?
Cele patru respingeri clasice sunt 401 la primul request, 403 cu eroare CIUS-RO, 500 fără mesaj și validarea de semnătură eșuată:
- 401 la primul request: token expirat sau certificat client lipsă. Verifică TLS handshake-ul în log; dacă nu vezi certificatul tău trimis, configurația SSLContext este incorectă.
- 403 cu eroare CIUS-RO: XML-ul a trecut sintactic, dar a căzut la validarea Schematron pe server. Rulează Schematronul local pe același XML pentru a obține codul de eroare exact.
- 500 fără mesaj: indisponibilitate ANAF. Retransmite cu backoff exponențial; documentul nu este creat de două ori dacă păstrezi idempotența pe numărul facturii.
- Validare semnătură eșuată: XML-ul a fost modificat după semnare (de exemplu, pretty-print) sau certificatul nu este în lanțul de încredere ANAF. Verifică hash-ul XML-ului trimis vs cel semnat.
De ce crawlerra pentru integrarea e-Factura?
Direct prin ANAF este un proiect cu o curbă serioasă de învățare, dar cu un ROI clar la volume potrivite. Pe crawlerra am implementat acest flux ca pipeline modular: generator UBL configurabil pe profil (CIUS-RO și PEPPOL BIS pentru clienți EU), serviciu de semnare în Java cu DSS, job de polling persistent cu retry exponențial, monitoring complet pe rata de respingere. Pentru contextul de format UBL, vezi entry-ul dedicat; pentru autentificare, semantica JWT ajută. Pentru alternativa prin SaaS, urmează ghidul de integrare SmartBill plus Stripe.
- Documentația tehnică oficială pentru API-ul e-Factura: efactura.anaf.ro/specificatii-tehnice. Conține schema XSD CIUS-RO curentă, regulile Schematron, codurile de eroare standardizate și diagramele de flux pentru autentificare, upload și download.
[seo.efactura_api_docs] - Caracteristicile observate ale polling-ului ANAF în clientul crawlerra de producție: răspunsurile vin cel mai des în interval 1-5 minute, dar la încărcare mare pot ajunge până la 30-60 minute. Job-ul de polling trebuie să fie persistent (nu rezident în memorie), cu reluare după restart al procesului, ca să nu pierzi tracking-ul facturilor în curs.
[crawlerra.efactura_polling]
Întrebări frecvente
Pot trimite e-Factura prin API fără certificat digital?
Nu. ANAF cere autentificare bazată pe certificat eIDAS calificat, fie pe persoană fizică (administrator/împuternicit), fie pe persoană juridică prin token-uri specifice ANAF. Certificatul nu este doar pentru semnătură; este și fundamentul flow-ului OAuth2 prin care obții token-ul de acces pentru API. Fără certificat valid, nu poți autentifica niciun request către e-Factura.
Cât de des trebuie să reînnoiesc token-ul de acces?
Token-ul de acces are durată de viață scurtă (de regulă 90 de zile), dar fluxul refresh-token este disponibil pentru reînnoire fără reintervenție umană. Implementarea defensivă: stochezi refresh-token-ul securizat, planifici un job care reînnoiește access-token-ul în avans, înainte de expirare, și prinzi codul de eroare 401 pentru fallback la refresh la cerere. Refresh-token-ul însuși are o durată mai mare, dar nu nelimitată, deci păstrează un alert dacă fluxul de refresh începe să eșueze.
Cum diferă sandbox-ul ANAF de producție?
Sandbox-ul (mediul de test) acceptă XML-uri și răspunde cu validare, dar nu emite documente fiscale reale și nu publică în SPV. Endpoint-urile au URL-uri diferite, certificatele acceptate sunt aceleași, iar regulile de validare sunt aliniate cu producția. Folosește sandbox-ul pentru a testa fluxul complet (auth, upload, polling, retry) fără să riști să generezi documente fiscale neintenționate. Trecerea la producție înseamnă schimbarea URL-urilor și nimic mai mult.
Ce fac dacă ANAF respinge un XML pentru o eroare neclară?
Începe cu validarea locală prin Schematron CIUS-RO înainte de orice retrimitere. ANAF returnează coduri de eroare standardizate (BR-04, BR-12 etc.) care corespund regulilor din EN 16931 plus CIUS-RO. Documentația publică listează semantica fiecărui cod. Dacă rulezi Schematron local pe XML-ul tău, prinzi 90% din erori înainte să trimiți, iar restul de 10% sunt validări semantice pe care doar serverul ANAF le poate face (de exemplu, CUI inactiv în baza de date ANAF).