01Documentație tehnică · API v2

Documentație API e-Factura — 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 sau XML-ul UBL trimis la ANAF. Iar când ANAF răspunde, afli printr-un webhook semnat — fără interogare periodică.

Format JSON  ·  URL de bază https://efactura.docuhelp.ro/api/v2/  ·  Autentificare cu cheie API  ·  Versiune document 2.0  ·  English version (PDF)

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.

Nou în versiunea 2.0 a documentației

Webhook-uri pentru statusul SPV — nu mai e nevoie de interogare periodică. Plus POST /invoices/{id}/send-spv pentru retrimiterea unei facturi existente, GET /invoices cu filtre pentru reconciliere și GET /invoices/{id}/xml pentru XML-ul UBL trimis la ANAF. Câmpurile vechi rămân neschimbate — integrările existente nu trebuie modificate.

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 începând cu următoarea cerere.

03Convenții generale
AspectDetalii
FormatRequest și response: JSON (Content-Type: application/json), cu excepția /pdf (răspuns application/pdf) și /xml (răspuns application/xml).
URL de bazăhttps://efactura.docuhelp.ro/api/v2/
ID-uriToate ID-urile (client, proformă, factură, webhook) 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-24).
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ă/webhook) nu există sau nu aparține firmei cheii folosite.
409Conflict — ex: număr de factură/proformă deja folosit (cerere concurentă); proformă deja convertită în factură; factură deja acceptată în SPV.
413Corpul cererii depășește 1 MB.
422Date invalide (câmp obligatoriu lipsă, valoare greșită).
429Prea multe cereri — încetinește (limitare pe firmă, pe endpoint).
500Eroare internă server.

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

04Referință endpointuri

Sistem, clienți, proforme, facturi, webhook-uri.

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-24", "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-24", "total": 266.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?exp=...&sig=..." }
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).

Linkul pdf_url din răspunsuri e semnat și valabil 30 de zile — îl poți pune direct într-un email sau în contul clientului, fără header de autentificare. PDF-urile nu pot fi afișate în <iframe> de pe alt domeniu (X-Frame-Options: SAMEORIGIN) — deschide-le în tab nou.

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. Răspunsul are aceeași structură ca POST /api/v2/invoices, plus converted_from_proforma_id.

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-24", "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-24", "total": 242.00, "currency": "RON", "paid": false, "client": {"id": "kL9mN2pQ7rS1", "name": "Client Exemplu SRL"}, "spv": {"status": "not_sent", "sent": false, "accepted": false, "index_incarcare": null, "document_id": null, "message": null, "error": null, "sent_at": null, "note": "SPV upload queued - subscribe to the invoice.spv.* webhooks, or poll GET /api/v2/invoices/{id}"}, "pdf_url": "https://efactura.docuhelp.ro/api/v2/invoices/fG2hJ4kL6mN8/pdf?exp=...&sig=..." }
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.

GET/api/v2/invoices

Listează facturile emise, pentru reconciliere din magazin — util dacă sistemul tău a pierdut ID-urile. Fiecare element din items are exact aceeași structură ca GET /api/v2/invoices/{id}.

ParametruDescriere
from, toInterval de date (YYYY-MM-DD), inclusiv.
seriesDoar o anumită serie.
spvpending, accepted, rejected sau not_sent — filtrează după statusul SPV curent.
limit, offsetPaginare. limit implicit 50, maxim 100.
curl "https://efactura.docuhelp.ro/api/v2/invoices?from=2026-08-01&spv=rejected" \ -H "Authorization: Bearer dh_xxxxx" {"items":[ ... ],"total":3,"limit":50,"offset":0}
GET/api/v2/invoices/{id}/xml

XML-ul UBL 2.1 exact așa cum a fost (sau ar fi) trimis la ANAF — pentru contabilitățile care arhivează documentul original, nu PDF-ul randat. Dacă XML-ul nu a fost încă generat, se generează la cerere.

POST/api/v2/invoices/{id}/send-spv

Trimite în SPV o factură deja creată: fie ca reîncercare după o urcare eșuată (token ANAF expirat, ANAF indisponibil), fie ca trimitere ulterioară a unei facturi create fără send_spv.

curl -X POST https://efactura.docuhelp.ro/api/v2/invoices/fG2hJ4kL6mN8/send-spv \ -H "Authorization: Bearer dh_xxxxx" 202 Accepted

Răspunsul 202 vine imediat și înseamnă „pus la trimis”, nu „acceptat de ANAF” — rezultatul real ajunge prin webhook sau la următorul GET /api/v2/invoices/{id}. Endpointul refuză cu 409 dacă factura e deja acceptată de ANAF sau dacă există deja o încărcare în curs. Dacă a fost respinsă, reîncercarea se face explicit, cu ?force=1, după corectarea datelor.

Webhook-uri

POST/api/v2/webhooks GET/api/v2/webhooks

Înregistrează o adresă la care îți trimitem un POST semnat la fiecare schimbare, respectiv listează webhook-urile existente cu starea ultimei livrări (last_status, last_error, fail_count) și lista completă de evenimente disponibile.

DELETE/api/v2/webhooks/{id} POST/api/v2/webhooks/{id}/test

Șterge webhook-ul și livrările lui aflate în coadă, respectiv trimite o livrare de probă sincron și returnează codul HTTP primit de la tine — așa depanezi o integrare fără să aștepți un eveniment real.

Detalii complete — evenimente, structura livrării, verificarea semnăturii, reîncercări — în secțiunea 07.

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). Un cod nerecunoscut nu dă eroare — se afișează ca atare pe document.
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.
cpvtextnuCod CPV, dacă e relevant.

Categorii TVA: S = cotă standard/redusă, Z = cotă zero, E = scutit, AE = taxare inversă, K = livrare intracomunitară, G = export, O = în afara sferei TVA. Maximum 500 de linii pe document.

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, subdivision, countryAdresa, orașul, județul (format RO-XX) și codul ISO de țară (implicit RO). Recomandate dacă factura va fi trimisă în SPV.
email, phone, contact_person, reg_comOpționale.
currencyValuta implicită a clientului, implicit RON.

Un cif care există deja la clienții firmei tale reutilizează clientul existent — nu creează duplicate. Fără cif (persoane fizice), fiecare cerere poate crea un client nou — nu există deduplicare după nume sau CNP.

06Trimiterea în SPV

Adaugi "send_spv": true, restul e asincron — în două etape.

Răspunsul 201 ajunge imediat, cu spv.status = "not_sent" („pus la trimis”). Apoi, în câteva secunde, factura ajunge la ANAF și primește un index de încărcare — statusul devine pending. ANAF o validează și răspunde accepted sau rejected abia după minute sau ore.

Nu aștepta rezultatul final în câteva secunde: nu depinde de noi, ci de ANAF. Recomandat: înregistrează un webhook și primești ambele schimbări automat, în loc să interoghezi periodic.

Necesită ca firma să aibă deja conectat contul ANAF (OAuth) din interfața web. Fără conectare, trimiterea eșuează — factura în sine nu e afectată, iar cu POST /invoices/{id}/send-spv se poate reîncerca după configurare.

status
not_sent, pending, accepted sau rejected. Cel mai simplu câmp de folosit — câmpurile sent și accepted de mai jos rămân pentru compatibilitate.
sent
true dacă există o încercare de trimitere înregistrată.
accepted
true dacă ANAF a acceptat factura.
index_incarcare
Numărul de încărcare SPV — numărul pe care îl comunici ANAF-ului când întrebi de o factură.
document_id
ID-ul documentului ANAF, după ce există un răspuns.
message
Mesajul de eroare, dacă ANAF a respins factura.
error
Vechiul câmp de eroare, păstrat pentru compatibilitate, cu aceeași valoare ca message.
sent_at
Momentul trimiterii.
07Webhook-uri

Nu mai întrebi periodic — te anunțăm noi.

În loc să interoghezi GET /api/v2/invoices/{id} până când ANAF răspunde, înregistrezi o adresă la care îți trimitem un POST semnat de fiecare dată când se schimbă ceva. O singură cerere, o singură dată, la instalare.

Evenimente disponibile

EvenimentCând se emite
invoice.spv.sentFactura a ajuns la ANAF și are index de încărcare. Încă „în prelucrare”.
invoice.spv.acceptedOK-ul final: ANAF a validat factura.
invoice.spv.rejectedANAF a respins factura; erorile sunt în spv.message.
invoice.spv.failedUrcarea în sine a eșuat (nu există index de încărcare) — ex: token ANAF expirat.
invoice.createdFactură creată prin API v2 (direct sau din proformă).
proforma.createdProformă creată prin API v2.

Înregistrarea unui webhook

POST/api/v2/webhooks
curl -X POST https://efactura.docuhelp.ro/api/v2/webhooks \ -H "Authorization: Bearer dh_xxxxx" -H "Content-Type: application/json" \ -d '{ "url": "https://magazinul-meu.ro/wp-json/efactura-docuhelp/v1/webhook", "label": "Magazin WooCommerce", "events": ["invoice.spv.sent", "invoice.spv.accepted", "invoice.spv.rejected", "invoice.spv.failed"] }' 201 Created {"id":"wH1jK3lM5nP7","url":"https://magazinul-meu.ro/...","label":"Magazin WooCommerce", "events":[...],"active":true,"secret":"a3f1...<64 caractere hex>"}

secret e afișat o singură dată, ca și cheia API — cu el verifici semnătura fiecărei livrări, deci salvează-l în configurarea integrării. Dacă îl pierzi, reînregistrezi același URL: secretul se rotește și primești unul nou. Câmpul events e opțional; dacă lipsește, primești toate evenimentele.

Cerințe pentru adresă

  • Obligatoriu https://, cu certificat valid.
  • Trebuie să fie o adresă publică. Adresele locale sau private (localhost, 127.0.0.1, 10.x, 192.168.x, 169.254.x) sunt respinse la înregistrare — serverul nostru face cererea, deci o adresă internă ar fi o breșă de securitate.
  • Nu se urmăresc redirectări: răspunde direct cu 2xx.
  • Un site local sau de test nu poate primi webhook-uri — folosește interogarea periodică pentru mediile de dezvoltare.

Structura unei livrări

POST /adresa-ta HTTP/1.1 Content-Type: application/json X-Docuhelp-Event: invoice.spv.accepted X-Docuhelp-Delivery: 4821 X-Docuhelp-Timestamp: 1787560982 X-Docuhelp-Signature: sha256=14582d25c33212dbe05c1376739eff9ff6c956ac3cba4865cdd08967e2fe3815 { "event": "invoice.spv.accepted", "event_id": "9f2c1a7b3e4d5f6a7b8c9d0e", "created_at": "2026-08-24T09:15:00+00:00", "data": { "business_id": "a1B2c3D4e5F6", "invoice": { "id": "fG2hJ4kL6mN8", "series": "EFA", "nr": "00123", "date": "2026-08-24", "total": 242.00, "currency": "RON", "paid": false, "client": {"id": "kL9mN2pQ7rS1", "name": "Client Exemplu SRL", "cif": "42979940"}, "pdf_url": "https://efactura.docuhelp.ro/api/v2/invoices/fG2hJ4kL6mN8/pdf?exp=...&sig=..." }, "spv": { "status": "accepted", "sent": true, "accepted": true, "index_incarcare": "5005559549", "document_id": "3007979966", "message": null, "sent_at": "2026-08-24 09:10:00" } } }

Verificarea semnăturii — obligatoriu

Adresa ta e publică, deci oricine ar putea trimite un POST acolo. Verifică întotdeauna semnătura înainte de a modifica ceva.

Semnătura se calculează peste șirul "{timestamp}.{corpul brut}", cu secret-ul primit la înregistrare. Folosește corpul brut, exact cum a venit — nu îl re-serializa din JSON, pentru că ordinea cheilor s-ar putea schimba și semnătura nu ar mai corespunde. Compară cu hash_equals(), nu cu ==.

$raw = file_get_contents('php://input'); $ts = $_SERVER['HTTP_X_DOCUHELP_TIMESTAMP'] ?? 0; $sig = $_SERVER['HTTP_X_DOCUHELP_SIGNATURE'] ?? ''; // respinge livrările vechi (fereastră anti-replay de 5 minute) if (abs(time() - (int)$ts) > 300) { http_response_code(400); exit; } $expected = 'sha256=' . hash_hmac('sha256', $ts . '.' . $raw, $secret); if (!hash_equals($expected, $sig)) { http_response_code(401); exit; } // abia acum ai voie să folosești conținutul $event = json_decode($raw, true);

Reîncercări și deduplicare

  • Răspunde cu 2xx dacă ai primit livrarea. Orice altceva (sau un timeout de 15 secunde) înseamnă eșec.
  • La eșec reîncercăm de 6 ori, cu intervale crescătoare: 1 min, 5 min, 30 min, 2 ore, 6 ore, 24 ore. După aceea livrarea se abandonează.
  • După 25 de eșecuri consecutive, webhook-ul se dezactivează automat — un magazin șters nu e solicitat la nesfârșit. Se reactivează reînregistrând același URL.
  • Reîncercările păstrează același event_id — folosește-l pentru deduplicare, ca să nu procesezi de două ori același eveniment.
  • Răspunde 2xx și atunci când nu recunoști factura — poate fi emisă din aplicație, nu din magazin. Un răspuns de eroare ar declanșa reîncercări inutile timp de 32 de ore.
  • Livrările de probă au "test": true în corp și o factură fictivă — confirmă-le, dar nu modifica nicio comandă pe baza lor.
08Exemplu de flux complet

De la comandă WooCommerce/OpenCart la factură.

O singură dată, la instalare: POST /webhooks. După aceea statusul SPV al fiecărei facturi ajunge singur la tine.

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. Statusul SPV vine singur, prin webhook — invoice.spv.sent, apoi accepted sau rejected. Fără webhook, îl citești cu 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.

09Bune 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.
  • Verifică întotdeauna semnătura webhook-urilor înainte de a modifica o comandă — vezi secțiunea 07.
  • 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 la creare (foarte rar — cereri simultane pe aceeași serie), reîncearcă cererea, căci numerele se alocă atomic pe server. 409 la convert sau send-spv înseamnă stare deja finalizată și nu se rezolvă prin reîncercare.
  • Păstrează ID-urile primite (client/proformă/factură) în comanda ta locală, pentru referințe ulterioare.
  • Nu trata 202 de la send-spv ca pe o confirmare ANAF — înseamnă doar că trimiterea a fost pusă la rând.
10Î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ă, în două etape. Răspunsul 201 la crearea facturii ajunge imediat, cu spv.status = not_sent. În câteva secunde factura ajunge la ANAF și primește un index de încărcare (status pending), iar validarea ANAF — acceptată sau respinsă — vine după minute sau ore, nu secunde. Recomandat: înregistrează un webhook și primești ambele schimbări automat, în loc să interoghezi periodic GET /api/v2/invoices/{id}.
Există webhook-uri pentru statusul e-Factura?
Da. Înregistrezi o adresă https publică printr-un singur POST /api/v2/webhooks și primești un POST semnat la fiecare schimbare: invoice.spv.sent, invoice.spv.accepted, invoice.spv.rejected, invoice.spv.failed, plus invoice.created și proforma.created. Fiecare livrare e semnată HMAC-SHA256 și are o fereastră anti-replay de 5 minute; livrările eșuate se reîncearcă de 6 ori, eșalonat pe circa 32 de ore.
Trebuie să îmi modific integrarea existentă pe API v2?
Nu. Toate câmpurile vechi rămân neschimbate — inclusiv spv.sent, spv.accepted și spv.error. Câmpurile noi (spv.status, document_id, message, sent_at) se adaugă lângă ele, iar webhook-urile sunt opționale: dacă nu înregistrezi niciunul, nu se schimbă nimic.
Cum retrimit în SPV o factură la care urcarea a eșuat?
Cu POST /api/v2/invoices/{id}/send-spv. Același endpoint trimite în SPV și o factură creată fără send_spv. Răspunde 202 imediat, ceea ce înseamnă „pus la trimis”, nu „acceptat de ANAF”. Pentru o factură respinsă de ANAF, reîncercarea se face explicit, cu ?force=1, după corectarea datelor.
Pot primi webhook-uri pe un site local sau de test?
Nu. Adresa trebuie să fie publică și pe https — adresele locale sau private (localhost, 127.0.0.1, 10.x, 192.168.x) sunt respinse la înregistrare, pentru că serverul nostru face cererea. Pentru mediile de dezvoltare folosește interogarea periodică: GET /api/v2/invoices/{id}.
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?
La creare apare foarte rar, doar la cereri simultane pentru aceeași serie — reîncearcă cererea, căci numerele se alocă atomic pe server. 409 mai apare și la convert pe o proformă deja convertită sau la send-spv pe o factură deja acceptată în SPV; acolo nu se rezolvă prin reîncercare.

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. Pentru un conector construit complet la cerere, vezi dezvoltarea personalizată.

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