FGO API Ghiduri Referință API

Erori, limite și reluări

O eroare are altă formă decât un răspuns reușit. Nu vine în data; vine ca application/problem+json, după RFC 9457, cu un type stabil pe care poți ramifica.

{
  "type": "urn:fgo:api:v2:problem:validation",
  "title": "Cererea nu a trecut validarea.",
  "status": 400,
  "detail": "Corectati campurile indicate in validation_errors si retrimiteti cererea.",
  "instance": "urn:trace:00-8f3a1c2e6b7d4e219c0a2f1d3e4b5a6c-5f2a9c1d3e4b6a7c-01",
  "meta": { "timestamp": "2026-09-03T12:00:00+03:00" },
  "validation_errors": [
    {
      "location": "body",
      "pointer": "/articole",
      "issues": [
        { "code": "invalid_value", "message": "Campul 'articole' trebuie sa contina cel putin un articol." }
      ]
    }
  ]
}

Ramifică pe type și pe status. title și detail sunt pentru oameni și se pot schimba fără o versiune nouă.

Categoriile

type (sufixul) Status Înseamnă
validation 400 cererea e greșită: câmp lipsă, format, valoare din afara nomenclatorului, parametru necunoscut
invalid-state 400 cererea e corectă, dar starea resursei nu permite operația — o factură încasată nu se șterge
invalid-cursor 400 cursorul de paginare nu e al nostru sau nu mai e valabil
unauthenticated 401 cheia lipsește, e expirată sau revocată
forbidden 403 cheia n-are dreptul, abonamentul nu include operația, sau Fgo-Cod-Unic nu e firma cheii
resource-not-found 404 factura, clientul, arhiva nu există — sau sunt ale altei firme, ceea ce arată identic
url-not-found 404 adresa nu există
unsupported-media-type 415 corpul nu e application/json
rate-limited 429 prea multe apeluri; vezi Retry-After
internal 500 eroare internă; trimite-ne valorile headerelor Server-Timing și x-fapi-interaction-id
maintenance 503 mentenanță planificată; API-ul e închis temporar, vezi Retry-After

validation_errors

Apare numai pe validation și spune exact ce e greșit, câmp cu câmp. Fiecare element are location — body, query, path, header — și, după caz, pointer (JSON Pointer în corp, ca /articole/0/cota_tva) sau name (numele parametrului sau al headerului). issues are codul stabil al problemei și un mesaj.

Codurile din issues[].code sunt extensibile: pot apărea coduri noi. Pentru un cod necunoscut, tratează răspunsul ca eroare de validare și folosește mesajul pentru diagnosticare. Codurile existente sunt:

code Înseamnă
required elementul obligatoriu lipsește sau e gol
invalid_format valoarea nu se poate citi în tipul sau forma așteptată: dată, număr, identificator, JSON stricat, tipar nerespectat
out_of_range număr sau lungime în afara limitelor; limitele vin în args: min, max, exclusive, value pentru numere, min_length, max_length, length pentru texte și liste
subfields_required un câmp compus a fost cerut în fields fără subcâmpuri, de exemplu incasari în loc de incasari(suma_incasata)
invalid_value orice altă regulă: valoare din afara nomenclatorului, parametru sau câmp necunoscut

De exemplu, o serie de storno prea lungă:

{ "code": "out_of_range", "message": "Dimensiunea valorii transmise pentru 'serie_storno' nu trebuie sa depaseasca 50 caractere.", "args": { "max_length": 50, "length": 60 } }

O cerere cu trei câmpuri greșite primește un singur 400 cu trei elemente, nu trei runde de încercări.

Validarea e strictă în amândouă direcțiile: un parametru de query sau o proprietate JSON pe care nu o documentăm e 400, nu e ignorată. Așa afli de o greșeală de tastare din prima, nu după ce filtrul „n-a mers".

motiv

Pe 403 și pe invalid-state, motiv.cod spune de ce:

{
  "type": "urn:fgo:api:v2:problem:forbidden",
  "status": 403,
  "detail": "Nu ai suficiente drepturi, vezi motiv.",
  "motiv": { "cod": "drept_lipsa", "mesaj": "Cheia API nu are dreptul de a face aceasta operatie." }
}
motiv.cod Răspuns Înseamnă
drept_lipsa 403 forbidden cheia nu are dreptul cerut sau abonamentul nu include operația
cod_unic_neasociat 403 forbidden Fgo-Cod-Unic nu corespunde firmei asociate cheii API
factura_duplicata 400 invalid-state cu verificare_duplicat=true, a fost găsită o factură după id_extern sau, dacă acesta lipsește, după serie și număr; nu se emite o factură nouă
stare_nepermisa 400 invalid-state regulile de business sau starea resursei nu permit operația; explicația este în motiv.mesaj

De exemplu, o emitere oprită de verificarea duplicatelor:

{
  "type": "urn:fgo:api:v2:problem:invalid-state",
  "title": "Starea curenta nu permite operatia",
  "status": 400,
  "detail": "Factura FGO 1201 exista deja salvata.",
  "instance": "urn:trace:00-8f3a1c2e6b7d4e219c0a2f1d3e4b5a6c-5f2a9c1d3e4b6a7c-01",
  "meta": { "timestamp": "2026-09-03T12:00:00+03:00" },
  "motiv": {
    "cod": "factura_duplicata",
    "mesaj": "Factura FGO 1201 exista deja salvata."
  }
}

Criteriile verificării sunt descrise în Emiterea unei facturi.

Codurile din motiv.cod sunt extensibile. Pentru un cod necunoscut, tratează refuzul folosind status și type, fără să presupui că operația a reușit.

Limitele de apeluri

Fiecare operație acceptă un apel la un interval fix, pe firmă. A doua cerere pe aceeași operație, înainte să treacă intervalul, primește 429. Operațiile diferite nu se influențează: poți citi articolele și gestiunile în aceeași secundă. Intervalele, pe fiecare operație:

Operație Interval
GET /v2/identitate 1 s
POST /v2/facturi 1 s
GET /v2/facturi 1 s
GET /v2/facturi/{serie}/{numar} 1 s, împărțit cu trimite-in-spv
GET /v2/facturi/{serie}/{numar}/efactura 1 s
POST /v2/facturi/{serie}/{numar}/genereaza-link-de-descarcare 1 s
POST /v2/facturi/{serie}/{numar}/genereaza-link-de-plata 1 s
PUT /v2/facturi/{serie}/{numar}/awb 1 s
POST /v2/facturi/{serie}/{numar}/anuleaza 1 s
POST /v2/facturi/{serie}/{numar}/storneaza 1 s
POST /v2/facturi/{serie}/{numar}/repune-in-vigoare-factura-stornata 1 s
DELETE /v2/facturi/{serie}/{numar} 1 s
POST /v2/facturi/{serie}/{numar}/incasari 1 s
DELETE /v2/facturi/{serie}/{numar}/incasari 1 s, împărțit cu ștergerea unei singure încasări
DELETE /v2/facturi/{serie}/{numar}/incasari/{serie_incasare}/{numar_incasare} 1 s, împărțit cu ștergerea tuturor încasărilor
POST /v2/facturi/{serie}/{numar}/trimite-in-spv 1 s, împărțit cu citirea facturii
POST /v2/facturi/{serie}/{numar}/trimite-pe-email 1 s
GET /v2/facturi/{serie}/{numar}/asociate 1 s
GET /v2/facturi/facturi-restante 1 s
GET /v2/facturi-furnizori 1 s
GET /v2/clienti 1 s
GET /v2/clienti/{id_client}/sold 1 s
GET /v2/clienti/clienti-cu-restante 1 s
GET /v2/furnizori 1 s
GET /v2/furnizori/{id_furnizor}/sold 1 s
POST /v2/fise-partener 10 s
GET /v2/articole 1 s
GET /v2/gestiuni 1 s
GET /v2/stocuri/stoc-gestiune-articol 1 s
GET /v2/stocuri/stoc-gestiune 1 s
GET /v2/stocuri/stoc-articol 1 s
GET /v2/rapoarte/totaluri-vanzari 10 s
GET /v2/rapoarte/vanzari-lunare 10 s
GET /v2/rapoarte/vanzari-achizitii-articole 10 s
GET /v2/solduri-conturi-bancare 1 s
GET /v2/balante/balanta-indicatori-financiari 10 s
GET /v2/balante/balanta-contabila 10 s
GET /v2/firme/pozitie-anaf 10 s
POST /v2/arhive-pdf 30 s
POST /v2/arhive-pdf/verifica-limite 5 s
GET /v2/arhive-pdf/{id_arhiva} 5 s
POST /v2/arhive-pdf/{id_arhiva}/genereaza-link-de-descarcare 1 s
nomenclatoarele, de exemplu GET /v2/nomenclatoare/judete 1 s

Aceleași intervale sunt scrise și în referință, la răspunsul 429 al fiecărei operații. Listele paginate nu au un interval separat pentru pagini: fiecare pagină e un apel, la o secundă de precedenta.

Limitele se pot modifica. La depășirea limitei, răspunsul indică timpul de așteptare:

HTTP/1.1 429 Too Many Requests
Retry-After: 1

Așteaptă cel puțin numărul de secunde din Retry-After înainte de a reîncerca. Pentru apeluri în lot, respectă intervalul operației și ajustează pauza după acest header.

Ce reîncerci și ce nu

Citirile (GET) se reîncearcă în siguranță. La 5xx, reîncearcă de câteva ori cu pauză crescătoare — o secundă, două, patru — apoi oprește-te.

Scrierile nu se reîncearcă automat, decât acolo unde documentația operației spune că e sigur. Atașarea AWB-ului e idempotentă: același AWB de două ori lasă factura în aceeași stare. Emiterea nu e: fiecare apel reușit produce o factură. Ce faci când nu primești răspuns la emitere e descris în Emiterea unei facturi.

La 429 sau 503 maintenance returnat de FGO API, reîncearcă după intervalul indicat de Retry-After: cererea nu a fost procesată. 503 maintenance înseamnă mentenanță planificată: documentația rămâne disponibilă, API-ul nu. Pentru un alt răspuns 503, inclusiv unul generat de un proxy, nu presupune că cererea nu a fost procesată; aplică regulile de reluare ale operației.

Identificarea unei cereri

Fiecare răspuns conține headerul x-fapi-interaction-id, identificatorul cererii:

x-fapi-interaction-id: 7b0f11d5-6e52-4b57-beca-15f47bf3f808

UUID (numit și GUID) este un identificator de 128 de biți, definit de RFC 9562. Folosește forma cu cratime din exemplu. Poți trimite tu un UUID în acest header; dacă lipsește sau nu este valid, îl generăm noi și îl întoarcem în răspuns. Păstrează-l în logurile tale.

Când semnalezi o problemă suportului, trimite valorile headerelor Server-Timing și x-fapi-interaction-id din răspunsul primit. Dacă nu ai primit niciun răspuns, trimite UUID-ul generat de tine.