Integrare ANAF SPV — Cum sa conectezi aplicatia de facturare la ANAF

Ghid tehnic pentru integrarea cu ANAF prin SPV: autorizare OAuth2, trimitere facturi si verificare status.

Avansat10 min lectura

Arhitectura API-ului e-Factura ANAF

ANAF expune un API REST pentru sistemul e-Factura, documentat oficial pe pagina de developer a institutiei. Autentificarea se face prin protocolul OAuth 2.0, cu fluxul de autorizare prin redirectare (Authorization Code Flow) — similar cu „Conectare cu Google/Facebook" din aplicatii web.

Exista doua medii disponibile:

  • Mediul de test (sandbox): https://api.anaf.ro/test/ — pentru dezvoltare si testare, fara efecte fiscale reale
  • Mediul de productie: https://api.anaf.ro/prod/ — pentru tranzactii reale, cu efecte legale

Principalele endpoint-uri utilizate in fluxul e-Factura sunt:

  • POST /upload — incarcarea unui fisier XML (factura sau nota de creditare)
  • GET /stareMesaj?id_incarcare={id} — verificarea statusului unui upload
  • GET /descarcare?id={id} — descarcarea raspunsului semnat de ANAF
  • GET /listaMesajeFactura — lista mesajelor (facturi primite si trimise) din inbox-ul SPV

Pasul 1: Inregistrarea aplicatiei in SPV

Pentru a obtine acces la API-ul ANAF, trebuie mai intai sa inregistrezi aplicatia de facturare in Spatiul Privat Virtual (SPV) al firmei tale. Iata cum:

  1. Autentifica-te in SPV la adresa spv.anaf.ro cu semnatura digitala sau prin intermediul serviciului de autentificare cu date ANAF
  2. Navigheaza la sectiunea „Servicii disponibile" > „e-Factura" > „Obtine token acces"
  3. Sistemul iti va prezenta o interfata de autorizare OAuth2: copiaza Client ID si, daca aplicatia ta necesita, genereaza un Client Secret
  4. Completeaza Redirect URI — aceasta este adresa la care ANAF va trimite codul de autorizare dupa ce utilizatorul aproba accesul (de ex: https://app.storno.ro/callback/anaf)

Retine ca token-ul OAuth2 este asociat cu CUI-ul firmei, nu cu contul de utilizator al persoanei care l-a generat. Daca firma are mai multi utilizatori SPV, oricare dintre ei poate autoriza aplicatia.

Pasul 2: Fluxul de autorizare OAuth2

Odata inregistrata aplicatia, fluxul de autorizare functioneaza astfel:

  1. Redirectare la ANAF: Aplicatia redirecxtioneaza utilizatorul catre endpoint-ul de autorizare ANAF:
    GET https://logincert.anaf.ro/anaf-oauth2/v1/authorize
      ?response_type=code
      &client_id={CLIENT_ID}
      &redirect_uri={REDIRECT_URI}
      &scope=efactura
      &state={RANDOM_STATE}
    
  2. Autentificarea utilizatorului: Utilizatorul se autentifica in SPV (cu semnatura digitala sau token hardware)
  3. Codul de autorizare: ANAF redirecxtioneaza inapoi la redirect_uri cu un parametru code in URL
  4. Schimbul codului pentru token: Aplicatia face o cerere POST catre endpoint-ul de token:
    POST https://logincert.anaf.ro/anaf-oauth2/v1/token
    Content-Type: application/x-www-form-urlencoded
    
    grant_type=authorization_code
    &code={CODE}
    &client_id={CLIENT_ID}
    &client_secret={CLIENT_SECRET}
    &redirect_uri={REDIRECT_URI}
    

    Raspunsul contine access_token (valabil 1 ora) si refresh_token (valabil 30 zile)
  5. Reimprospatarea token-ului: Inainte de expirarea access_token-ului, aplicatia il poate reinnoi automat folosind refresh_token, fara a solicita reautorizarea utilizatorului

Pasul 3: Incarcarea unei facturi XML

Cu token-ul de acces obtinut, trimiterea unei facturi se face printr-un POST multipart:

POST /prod/FCTEL/rest/upload?standard=UBL&cif={CIF_EMITENT}
Authorization: Bearer {ACCESS_TOKEN}
Content-Type: multipart/form-data

[fisier XML al facturii]

Parametrii importanti:

  • standard: UBL pentru formatul UBL 2.1 sau CII pentru Cross Industry Invoice
  • cif: CUI-ul firmei emitente (fara prefix RO pentru firmele romane)

Raspunsul de la ANAF este un JSON care contine index_incarcare — acesta este ID-ul unic al upload-ului, necesar pentru verificarea statusului:

{
  "ExecutionStatus": 0,
  "index_incarcare": 12345678
}

Un ExecutionStatus de 0 inseamna ca fisierul a fost primit cu succes. Atentie: acesta nu inseamna ca factura a fost acceptata — doar ca a fost incarcata in coada de procesare.

Pasul 4: Verificarea statusului procesarii

Procesarea de catre ANAF dureaza de la cateva secunde la cateva minute. Poti verifica statusul astfel:

GET /prod/FCTEL/rest/stareMesaj?id_incarcare={INDEX_INCARCARE}
Authorization: Bearer {ACCESS_TOKEN}

Raspunsul posibil:

{
  "stare": "ok",
  "id_descarcare": 87654321
}

Stari posibile:

  • "ok" — factura a fost acceptata; id_descarcare contine ID-ul pentru descarcarea raspunsului semnat
  • "nok" — factura a fost respinsa; apeleaza endpoint-ul de descarcare pentru a obtine lista de erori
  • "in prelucrare" — inca in procesare; reincearca peste cateva secunde
  • "eroare prelucrare" — eroare tehnica pe serverele ANAF; retrimite dupa un interval

Pasul 5: Descarcarea dovezii de transmitere

Odata ce statusul este ok sau nok, descarca fisierul de raspuns:

GET /prod/FCTEL/rest/descarcare?id={ID_DESCARCARE}
Authorization: Bearer {ACCESS_TOKEN}

Raspunsul este un fisier ZIP care contine:

  • {index_incarcare}.xml — fisierul XML original pe care l-ai trimis
  • {index_incarcare}_semnatura.xml — semnatura digitala aplicata de ANAF (XMLDSig)
  • In caz de eroare: {index_incarcare}_Errors.xml — lista detaliata a erorilor de validare

Arhiveaza acest fisier ZIP pentru fiecare factura — reprezinta dovada legala ca factura a fost inregistrata in sistemul e-Factura.

Erorile frecvente si cum le rezolvi

CIF invalid (Cif-ul beneficiarului nu este valid): Verifica ca CUI-ul clientului este activ in baza de date ANAF. Poti verifica prin API-ul public ANAF verificare.anaf.ro sau prin SPV.

Schema XML invalida: Fisierul XML nu respecta schema UBL 2.1. Valideaza fisierul local cu un validator XML schema inainte de a-l trimite (schema oficiala este publicata de ANAF).

Token expirat: access_token-ul a expirat. Implementeaza logica de reimprospatare automata folosind refresh_token inainte de fiecare cerere API.

Duplicate: ANAF poate respinge un fisier daca detecteaza ca o factura cu acelasi numar si CUI emitent a mai fost trimisa. Verifica in baza ta de date daca factura a mai fost trimisa inainte de a retrimite.

Sfaturi de implementare pentru robustete

Implementeaza retry logic cu backoff exponential. ANAF poate fi indisponibil sau lent intermitent. O strategie de reincercare cu intervale crescatoare (1s, 5s, 30s, 5min) previne supraincarcarea serverelor si asigura ca facturile ajung in final la destinatie.

Stocheaza intotdeauna index_incarcare in baza de date imediat dupa upload, inainte de a verifica statusul. Daca aplicatia ta cade sau serverul reporneste intre upload si verificarea statusului, vei putea relua verificarea din index_incarcare stocat.

Monitorizeaza expirarea refresh_token-ului. Tokenul de refresh expira dupa 30 de zile de neutilizare. Daca nu ai trimis facturi o luna, tokenul poate expira si va trebui reautorizat manual prin SPV. Trimite o alerta utilizatorului cu 7 zile inainte de expirare.

Gata sa incepi facturarea electronica?

Creaza un cont gratuit si emite prima factura in mai putin de 5 minute.