01Documentație tehnică · API v2

API v2 — proforme și facturi din sistemul tău, printr-un apel.

Ghid de integrare pentru sisteme externe — WordPress/WooCommerce, OpenCart, ERP-uri proprii. Caută sau creează clienți, creează proforme și facturi cu TVA calculat automat, transformă o proformă în factură, descarcă PDF-ul și trimite-l opțional în SPV.

Format JSON  ·  URL de bază https://efactura.docuhelp.ro/api/v2/  ·  Autentificare cu cheie API

API v2 e separat de API v1

API v1 (/api/v1/invoice/add) e deja folosit de alte integrări și rămâne neschimbat — cele două nu se afectează reciproc și pot fi folosite în paralel. Pentru integrarea de bază, cu chei de acces și jurnal de trafic, vezi pagina API și integrări.

02Autentificare

O cheie API, trimisă în header la fiecare cerere.

Fiecare cerere către /api/v2/ trebuie să conțină Authorization: Bearer <cheia_dvs_api>.

Autentifică-te în aplicație

Cu contul firmei tale, pe efactura.docuhelp.ro.

Mergi la Setări → tab „API”

Introdu o denumire pentru cheie (ex: „Magazin WordPress”) și apasă Generează cheie nouă.

Copiază cheia — o singură dată

Cheia completă e afișată o singură dată, imediat după generare. Serverul reține doar un hash SHA-256, nu valoarea în clar — dacă ai pierdut-o, generezi una nouă și o revoci pe cea veche.

Revocare, oricând

Fiecare cheie are un buton Revocă. Revocarea e imediată și ireversibilă: orice integrare care mai folosește acea cheie primește 403 Forbidden de la următoarea cerere.

03Convenții generale
AspectDetalii
FormatRequest și response: JSON (Content-Type: application/json), excepție /pdf (răspuns application/pdf).
URL de bazăhttps://efactura.docuhelp.ro/api/v2/
ID-uriToate ID-urile (client, proformă, factură) sunt șiruri scurte (ex: a1B2c3D4e5F6), nu numere — folosite exact cum sunt returnate.
SumePrețurile din linii sunt fără TVA (nete). TVA-ul și totalul se calculează automat pe server. Orice total trimis de client e ignorat.
DateFormat YYYY-MM-DD (ex: 2026-08-13).
ValuteRON, EUR, USD, HUF.

Coduri de eroare

Cod HTTPSemnificație
400Corp cerere JSON invalid/lipsă.
401Lipsește header-ul Authorization.
403Cheie API invalidă, revocată sau expirată.
404Resursa (client/proformă/factură) nu există sau nu aparține firmei cheii folosite.
409Conflict — ex: număr de factură/proformă deja folosit (cerere concurentă); proformă deja convertită.
422Date invalide (câmp obligatoriu lipsă, valoare greșită).
500Eroare internă server.

Corpul răspunsului de eroare are mereu forma: {"error": "mesaj explicativ"}.

04Referință endpointuri

Sistem, clienți, proforme, facturi.

Sistem

GET/api/v2/ping

Verifică dacă cheia API e validă.

curl https://efactura.docuhelp.ro/api/v2/ping \ -H "Authorization: Bearer dh_xxxxx" {"ok":true,"business_id":"a1B2c3D4e5F6","business_name":"Firma Mea SRL","vat_payer":true}
GET/api/v2/series

Seriile de facturare configurate pentru firmă, pentru a alege una la creare (sau lași serverul să aleagă prima serie configurată).

{"invoice":["EFA"],"proforma":["PRO"],"currencies":["RON","EUR","USD","HUF"]}
GET/api/v2/nextnr?type=invoice&series=EFA

Următorul număr disponibil pentru o serie (informativ — numărul real se alocă automat, atomic, la creare).

{"type":"invoice","series":"EFA","nr":"00123"}

Clienți

GET/api/v2/clients?q=...

Caută clienți după nume sau CIF. Se poate folosi și ?cif=.

curl "https://efactura.docuhelp.ro/api/v2/clients?q=42979940" \ -H "Authorization: Bearer dh_xxxxx" {"items":[{"id":"kL9mN2pQ7rS1","name":"Client Exemplu SRL","cif":"42979940","email":"contact@exemplu.ro","city":"Bucuresti","country":"RO","currency":"RON"}]}
POST/api/v2/clients

Creează un client nou, sau — dacă există deja un client cu același CIF la firma ta — returnează clientul existent (fără duplicat). Singurul câmp obligatoriu pentru un client nou e name.

curl -X POST https://efactura.docuhelp.ro/api/v2/clients \ -H "Authorization: Bearer dh_xxxxx" -H "Content-Type: application/json" \ -d '{ "name": "Client Exemplu SRL", "cif": "42979940", "address": "Str. Exemplu nr. 1", "city": "Bucuresti", "subdivision": "RO-B", "country": "RO", "email": "contact@exemplu.ro", "currency": "RON" }' 201 Created {"id":"kL9mN2pQ7rS1","name":"Client Exemplu SRL","cif":"42979940","email":"contact@exemplu.ro","currency":"RON","country":"RO"}

Dacă ai deja client.id dintr-un apel anterior, îl poți trimite direct: {"client":{"id":"kL9mN2pQ7rS1"}}.

Proforme

POST/api/v2/proformas

Creează o proformă nouă.

curl -X POST https://efactura.docuhelp.ro/api/v2/proformas \ -H "Authorization: Bearer dh_xxxxx" -H "Content-Type: application/json" \ -d '{ "client": {"id": "kL9mN2pQ7rS1"}, "date": "2026-08-13", "currency": "RON", "obs": "Comanda #10452 din magazinul online", "items": [ {"name": "Produs A", "unit": "H87", "qty": 2, "price": 100, "vat_rate": 21}, {"name": "Transport", "unit": "H87", "qty": 1, "price": 20, "vat_rate": 21} ] }' 201 Created { "id": "pR3sT5uV7wX9", "series": "PRO", "nr": "00045", "date": "2026-08-13", "total": 261.20, "currency": "RON", "converted_to_invoice": false, "client": {"id": "kL9mN2pQ7rS1", "name": "Client Exemplu SRL"}, "pdf_url": "https://efactura.docuhelp.ro/api/v2/proformas/pR3sT5uV7wX9/pdf" }
GET/api/v2/proformas/{id} GET/api/v2/proformas/{id}/pdf

Datele proformei, respectiv PDF-ul ei (generat la prima cerere, apoi servit din cache).

POST/api/v2/proformas/{id}/convert

Transformă o proformă existentă în factură (de exemplu după confirmarea plății comenzii). O proformă poate fi convertită o singură dată.

curl -X POST https://efactura.docuhelp.ro/api/v2/proformas/pR3sT5uV7wX9/convert \ -H "Authorization: Bearer dh_xxxxx" -H "Content-Type: application/json" \ -d '{"send_spv": false}'

Corpul cererii e opțional ({} e valid); câmpuri acceptate: date, series, payby, send_spv.

Facturi

POST/api/v2/invoices

Creează direct o factură (fără să treacă prin proformă).

curl -X POST https://efactura.docuhelp.ro/api/v2/invoices \ -H "Authorization: Bearer dh_xxxxx" -H "Content-Type: application/json" \ -d '{ "client": {"id": "kL9mN2pQ7rS1"}, "date": "2026-08-13", "currency": "RON", "send_spv": true, "items": [ {"name": "Produs A", "unit": "H87", "qty": 2, "price": 100, "vat_rate": 21} ] }' 201 Created { "id": "fG2hJ4kL6mN8", "series": "EFA", "nr": "00123", "date": "2026-08-13", "total": 238.00, "currency": "RON", "paid": false, "client": {"id": "kL9mN2pQ7rS1", "name": "Client Exemplu SRL"}, "spv": {"sent": false, "accepted": false, "index_incarcare": null, "error": null, "note": "SPV upload queued - poll GET /api/v2/invoices/{id} for status"}, "pdf_url": "https://efactura.docuhelp.ro/api/v2/invoices/fG2hJ4kL6mN8/pdf" }
GET/api/v2/invoices/{id} GET/api/v2/invoices/{id}/pdf

Starea curentă a facturii, inclusiv statusul real al trimiterii în SPV, respectiv PDF-ul ei.

05Modele de date

Linii factură/proformă

CâmpTipOblig.Descriere
nametextdaDenumire produs/serviciu.
descriptiontextnuDescriere suplimentară (linia a 2-a pe factură).
unittextnuUnitate de măsură, cod UN/CEFACT (implicit H87 = bucată, dacă lipsește).
qtynumărdaCantitate. Poate fi negativă (linie de corecție/storno).
pricenumărdaPreț unitar fără TVA.
vat_ratenumărnuCotă TVA în procente. Ignorată dacă firma nu e plătitoare de TVA.
vat_categorytextnuS, Z, E, AE, K, G sau O. Dacă lipsește, se deduce din vat_rate.

Client

CâmpDescriere
idID-ul unui client existent. Dacă e trimis, celelalte câmpuri sunt ignorate.
nameSingurul câmp obligatoriu pentru un client nou.
cifCIF/CUI firmă, fără prefixul RO. Lipsa lui înseamnă persoană fizică.
cnpCNP persoană fizică, 13 cifre — opțional.
address, city, subdivisionRecomandate dacă factura va fi trimisă în SPV.
currencyValuta implicită a clientului, implicit RON.

Un cif care există deja la clienții firmei tale reutilizează clientul existent — nu creează duplicate.

06Trimiterea în SPV

Adaugi "send_spv": true, restul e asincron.

Răspunsul 201 ajunge imediat, cu spv.sent = false. Rezultatul real (acceptat/respins de ANAF) apare câteva secunde mai târziu, la un apel ulterior GET. Verifică statusul după 5–15 secunde — webhook-uri nu sunt disponibile încă, se folosește polling.

Necesită ca firma să aibă deja conectat contul ANAF (OAuth) din interfața web. Fără conectare, trimiterea eșuează silențios — factura în sine nu e afectată.

sent
true dacă există o încercare de trimitere înregistrată.
accepted
true dacă ANAF a acceptat factura.
index_incarcare
Numărul de încărcare SPV, dacă a fost trimisă.
error
Mesajul de eroare, dacă ANAF a respins factura.
07Exemplu de flux complet

De la comandă WooCommerce/OpenCart la factură.

Plată online, confirmată imediat

Pași

1. Caută clientul după CIF: GET /clients?cif=...
2. Dacă nu există, creează-l: POST /clients
3. Creează factura direct: POST /invoices, cu "send_spv": true dacă vrei trimitere automată

Rezultat

4. Descarci PDF-ul din pdf_url și îl atașezi la emailul de confirmare.
5. (opțional) După câteva secunde, verifici statusul SPV: GET /invoices/{id}.

Plată offline (OP), confirmată ulterior

Pași

1. La plasarea comenzii: POST /proformas.
2. Trimiți clientului PDF-ul proformei (pdf_url) ca instrucțiuni de plată.

Rezultat

3. La confirmarea plății (manual sau prin webhook propriu): POST /proformas/{id}/convert — proforma devine factură, fără să retastezi nimic.

08Bune practici și securitate
  • Nu expune cheia API în cod client (JavaScript din browser) — apelurile se fac din server, nu din browserul cumpărătorului.
  • O cheie separată per integrare (magazin, mediu de test etc.) — ușor de revocat individual, fără să afectezi celelalte.
  • Tratează orice răspuns 4xx/5xx — nu presupune că factura a fost creată dacă nu primești 201 cu un id valid.
  • La 409 Conflict (foarte rar, doar la cereri simultane), reîncearcă cererea — numerele se alocă atomic pe server.
  • Păstrează ID-urile primite (client/proformă/factură) în comanda ta locală, pentru referințe ulterioare.
09Întrebări frecvente

Despre API v2, pe scurt

Există un API pentru facturare electronică compatibil cu ANAF SPV?
Da. API v2 este o interfață REST în format JSON prin care creezi clienți, proforme și facturi direct din sistemul tău extern — WordPress/WooCommerce, OpenCart sau un ERP propriu — cu TVA calculat automat, PDF generat la cerere și trimitere opțională a facturii în ANAF SPV.
Cum mă autentific la API-ul de facturare?
Fiecare cerere către /api/v2/ trebuie să conțină header-ul Authorization: Bearer urmat de cheia API. Cheia se generează din aplicație, la Setări → tab API, este afișată o singură dată la generare, iar serverul reține doar un hash SHA-256 al ei, nu valoarea în clar.
Ce cod de eroare primesc dacă cheia API e invalidă sau revocată?
403 Forbidden — același cod pentru o cheie invalidă, revocată sau expirată. Dacă lipsește complet header-ul Authorization, răspunsul este 401.
Care e diferența dintre API v1 și v2?
API v1 (/api/v1/invoice/add) e deja folosit de alte integrări și rămâne neschimbat. API v2 este separat, cu endpointuri proprii pentru clienți, proforme și facturi. Cele două nu se afectează reciproc și pot fi folosite în paralel.
Trimiterea facturii în SPV e sincronă sau asincronă?
Este asincronă. Răspunsul 201 la crearea facturii ajunge imediat, cu spv.sent = false, iar rezultatul real — acceptată sau respinsă de ANAF — apare câteva secunde mai târziu, la un apel GET ulterior. Se verifică prin polling, la 5–15 secunde după creare; webhook-uri nu sunt disponibile încă.
Ce se întâmplă dacă trimit de două ori același CIF la crearea unui client?
Nu se creează un duplicat. Un CIF care există deja la clienții firmei tale reutilizează clientul existent, în loc să creeze unul nou.
De ce primesc 409 Conflict la crearea unei facturi prin API?
E foarte rar și apare doar la cereri simultane pentru aceeași serie. Reîncearcă cererea — numerele se alocă atomic pe server, deci nu riști o factură duplicată sau un număr sărit.

Ai nevoie de ajutor la integrare?

Adu-ne un exemplu de comandă din sistemul tău — ne uităm împreună la ce trimiți și cât de aproape ești de un apel funcțional.

Fără obligații · Răspundem în aceeași zi lucrătoare