Facturi, proforme și stornări
De la ciornă la factura emisă, într-o cerere sau pas cu pas, cu regulile aplicației.
Creare și emitere
POST /companies/{company_id}/documents face o ciornă. Cu "issue": true o și emite (îi dă numărul următor din serie), iar cu "submit": true o și trimite în RO e-Factura, toate în aceeași cerere:
{
"client_id": 55,
"lines": [
{ "product_id": 31, "quantity": 2 },
{ "name": "Transport", "quantity": 1, "unit_price": 40, "vat_percent": 21 }
],
"due_date": "2026-10-30",
"order_ref": "PO-7781",
"issue": true,
"submit": true
}- Dacă emiterea nu reușește (lipsește județul clientului, seria e dezactivată), cererea întoarce eroarea și nu lasă nicio ciornă în urmă.
- Dacă emiterea reușește, dar ANAF nu primește factura chiar atunci, factura rămâne emisă și programată pentru trimitere; reîncercăm noi.
- Fără
issue, documentul rămâne ciornă: îl vezi în aplicație și îl emiți mai târziu, din aplicație sau cu/issue.
Data emiterii este implicit ziua de azi în România, scadența vine din setările firmei, iar totalurile, TVA-ul și cursul valutar le calculăm noi.
Clientul
Dai fie client_id, un client din agendă, fie client, scris direct pe document. Cu "save_client": true, clientul scris direct intră și în agendă (dacă există deja cu același CUI, CNP sau ref, se folosește acela).
- Pentru RO e-Factura, o firmă din România are nevoie de CUI, localitate și județ. În București, localitatea este sectorul:
"city": "Sector 3","county": "București". - O persoană fizică:
"kind": "pf", cu sau fără CNP. Fără CNP, sau cu"send_cnp": false, în e-Factura pleacă 13 zerouri, cum cere ANAF. - O firmă din alt stat:
"country": "DE"și codul ei de TVA încui.
Liniile și TVA-ul
quantityșiunit_price(în moneda documentului); cu"price_includes_vat": true, prețul conține TVA.discount_percentreduce linia.- TVA-ul:
vat_rate_id(o cotă a firmei, dinGET /companies/{company_id}), sauvat_percentcuvat_category, sau nimic, pentru cota implicită a firmei. La o firmă neplătitoare de TVA nu se aplică TVA. - Unitatea este un cod UN/ECE:
H87bucată (implicit),HURoră,KGMkilogram,MTRmetru,C62unitate. - Cu
product_id, linia ia din catalog denumirea, prețul, unitatea și cota; ce trimiți în plus are prioritate.
Valuta
Cu "currency": "EUR" și fără exchange_rate, punem cursul BNR pentru data emiterii (ultimul comunicat înaintea ei) și îl arătăm în exchange_rate și exchange_rate_date. Dacă dai tu cursul, rămâne cel dat. Un produs cu prețul în euro pe o factură în lei se convertește la același curs (src_price, src_currency).
Încasată la emitere
Cu "collected": true și payment_method, factura iese încasată integral, cu încasarea înregistrată la emitere. Cu "payment_method": "numerar" se emite și chitanța. "payment_method": "bon_fiscal" face factura de tip 751 (emisă pe baza unui bon fiscal).
Numerotarea
La emitere, numărul este următorul din seria principală a firmei. Altă serie: series_id (seriile sunt în GET /companies/{company_id}); alt număr: number. Un număr deja folosit în serie primește 409 conflict.
Modificare și ștergere
PATCH schimbă doar câmpurile trimise; lines, dacă îl trimiți, înlocuiește toate liniile. Se poate modifica o ciornă și o factură emisă care nu a ajuns la ANAF (de exemplu una respinsă). După ce ANAF a primit-o, factura nu se mai modifică și nu se mai șterge: se stornează. Ștergerea (DELETE) merge pentru ciorne și pentru documentele emise netrimise, fără chitanțe și fără stornări; ea rămâne în jurnalul firmei.
Stornarea
POST …/storno emite factura de stornare: cantități negative, cu trimitere la factura inițială, totală sau doar pe unele linii ({"line_id", "quantity"}, cu id-urile liniilor din document). O factură trimisă în RO e-Factura se stornează după ce ANAF a validat-o. Stornarea se trimite apoi ca orice factură.
Proforme
"type": "proforma" face o proformă, cu seria ei. O proformă nu ajunge în RO e-Factura și nu se stornează. Când clientul plătește, POST …/convert face din ea o ciornă de factură cu aceleași linii, pe care o emiți cu /issue.
PDF și email
GET …/pdf dă PDF-ul, cu sigla firmei și contul bancar. POST …/email îl trimite clientului (sau adreselor din to), de la adresa Chappa, cu suma, scadența și IBAN-ul în mesaj; merge pentru firmele verificate, conectate la ANAF.
Găsirea documentelor
GET …/documents are filtre pentru tip, stare, starea în e-Factura, plată, perioadă și client. Cel mai sigur mod de a regăsi o factură a ta este external_ref: pune la creare id-ul comenzii și caută după el cu ?external_ref=comanda-1042. Lista cuprinde și facturile trimise din alte programe prin SPV ("source": "spv"); pe acestea doar le citești.
Referința
Lista documentelor
GET /api/v1/companies/{company_id}/documents
Permisiune: documents:read.
Facturile, proformele și stornările firmei, cele mai noi primele, fără linii și încasări. Include facturile trimise din alte programe prin SPV (source: "spv").
| Parametru | Tip | Ce este |
|---|---|---|
company_id în adresă | integer | Id-ul firmei. |
type | invoice | proforma | storno | Tipul. |
status | draft | issued | Ciorne sau emise. |
efactura | not_sent | scheduled | queued | processing | accepted | rejected | Starea în RO e-Factura. |
payment | unpaid | paid | overdue | Încasare (doar facturi emise). |
issued_from | date | Emise de la data. |
issued_to | date | Emise până la data (inclusiv). |
client_id | integer | Ale unui client din agendă. |
external_ref | string | Cu id-ul tău. |
q | string | Caută în număr, client și CUI. |
limit | integer | Câte pe pagină, 1–100. Implicit 25. |
starting_after | string | next_cursor din pagina anterioară. |
Răspuns 200: o List de Document.
{
"object": "list",
"data": [
{ "id": 812, "object": "document", "type": "invoice", "status": "issued", "number": "FCT 42",
"issue_date": "2026-10-09", "currency": "RON", "client": { "kind": "pj", "name": "Beta Construct SRL", "cui": "RO18547290", "country": "RO" },
"totals": { "net": 610, "vat": 128.1, "total": 738.1 },
"efactura": { "applies": true, "status": "accepted", "upload_index": "5012345678", "errors": null, "scheduled_at": null, "anaf_id": null },
"payment": { "status": "unpaid", "paid": 0, "outstanding": 738.1, "overdue": false }, "…": "…" }
],
"has_more": true,
"next_cursor": 812
}Creează o factură sau o proformă
POST /api/v1/companies/{company_id}/documents
Permisiune: documents:write.
Creează o ciornă; cu issue: true o și emite (număr din serie), cu submit: true o și trimite în RO e-Factura, toate într-o cerere. Răspunsul este documentul întreg. Totalurile, TVA-ul, cursul BNR și scadența le calculăm noi, cu regulile aplicației.
| Parametru | Tip | Ce este |
|---|---|---|
company_id în adresă | integer | Id-ul firmei. |
Corp: DocumentCreate, de exemplu.
{
"type": "invoice",
"client": {
"name": "Beta Construct SRL",
"cui": "RO18547290",
"address": "Str. Fabricii 12",
"city": "Sector 3",
"county": "București",
"email": "contabilitate@beta.ro"
},
"save_client": true,
"lines": [
{ "name": "Abonament lunar", "unit": "H87", "quantity": 1, "unit_price": 250, "vat_percent": 21 },
{ "name": "Ore suport", "unit": "HUR", "quantity": 3, "unit_price": 120, "vat_percent": 21 }
],
"payment_method": "ordin_plata",
"external_ref": "comanda-1042",
"issue": true,
"submit": true
}Răspuns 201: Document.
{
"id": 812,
"object": "document",
"company_id": 7,
"type": "invoice",
"status": "issued",
"source": "chappa",
"number": "FCT 42",
"series": "FCT",
"sequence": 42,
"issue_date": "2026-10-09",
"due_date": "2026-10-23",
"currency": "RON",
"exchange_rate": null,
"exchange_rate_date": null,
"client_id": 55,
"client": {
"kind": "pj", "name": "Beta Construct SRL", "cui": "RO18547290", "cnp": null, "send_cnp": false,
"reg_com": null, "address": "Str. Fabricii 12", "city": "Sector 3", "county": "București",
"country": "RO", "email": "contabilitate@beta.ro", "phone": null
},
"lines": [
{ "id": 3301, "position": 1, "product_id": null, "code": null, "name": "Abonament lunar", "description": null,
"unit": "H87", "quantity": 1, "unit_price": 250, "price_includes_vat": false, "discount_percent": 0,
"vat_rate_id": 14, "vat_percent": 21, "vat_category": "S", "exemption_code": null, "exemption_text": null,
"net": 250, "vat": 52.5, "gross": 302.5, "storno_of_line_id": null, "src_price": null, "src_currency": null },
{ "id": 3302, "position": 2, "product_id": null, "code": null, "name": "Ore suport", "description": null,
"unit": "HUR", "quantity": 3, "unit_price": 120, "price_includes_vat": false, "discount_percent": 0,
"vat_rate_id": 14, "vat_percent": 21, "vat_category": "S", "exemption_code": null, "exemption_text": null,
"net": 360, "vat": 75.6, "gross": 435.6, "storno_of_line_id": null, "src_price": null, "src_currency": null }
],
"totals": { "net": 610, "vat": 128.1, "total": 738.1 },
"notes": null,
"internal_note": null,
"order_ref": null,
"contract_ref": null,
"external_ref": "comanda-1042",
"payment_method": "ordin_plata",
"bank_account_id": 3,
"vat_on_collection": false,
"storno_of": null,
"stornos": [],
"converted_from_id": null,
"converted_to_id": null,
"efactura": {
"applies": true,
"status": "processing",
"upload_index": "5012345678",
"errors": null,
"scheduled_at": null,
"deadline": "2026-10-16",
"anaf_id": null,
"history": [{ "status": "processing", "upload_index": "5012345678", "errors": null, "at": "2026-10-09 14:02" }]
},
"payment": { "status": "unpaid", "paid": 0, "outstanding": 738.1, "overdue": false, "collected_at_issue": false },
"payments": [],
"created_at": "2026-10-09T14:02:11+03:00",
"issued_at": "2026-10-09T14:02:11+03:00"
}Un document
GET /api/v1/companies/{company_id}/documents/{document_id}
Permisiune: documents:read.
Documentul întreg: linii, totaluri, starea în RO e-Factura cu istoricul trimiterilor, încasările.
| Parametru | Tip | Ce este |
|---|---|---|
company_id în adresă | integer | Id-ul firmei. |
document_id în adresă | integer | Id-ul documentului. |
Răspuns 200: Document.
Modifică un document
PATCH /api/v1/companies/{company_id}/documents/{document_id}
Permisiune: documents:write.
O ciornă, sau o factură emisă care nu a ajuns la ANAF (după o respingere, de exemplu). Doar câmpurile trimise se schimbă. După ce ANAF a primit-o, factura nu se mai modifică: se stornează.
| Parametru | Tip | Ce este |
|---|---|---|
company_id în adresă | integer | Id-ul firmei. |
document_id în adresă | integer | Id-ul documentului. |
Corp: DocumentInput, de exemplu.
{ "due_date": "2026-10-30", "notes": "Plata în două tranșe." }Răspuns 200: Document.
Șterge un document
DELETE /api/v1/companies/{company_id}/documents/{document_id}
Permisiune: documents:delete.
Ciornele și documentele emise care nu au ajuns la ANAF, fără chitanțe și fără stornări. Ștergerea rămâne în jurnalul firmei.
| Parametru | Tip | Ce este |
|---|---|---|
company_id în adresă | integer | Id-ul firmei. |
document_id în adresă | integer | Id-ul documentului. |
Răspuns 200: Deleted.
Emite o ciornă
POST /api/v1/companies/{company_id}/documents/{document_id}/issue
Permisiune: documents:issue.
Îi dă număr din serie și îngheață datele firmei pe document. Dacă firma trimite automat, intră în programul de trimitere.
| Parametru | Tip | Ce este |
|---|---|---|
company_id în adresă | integer | Id-ul firmei. |
document_id în adresă | integer | Id-ul documentului. |
Corp: IssueInput, de exemplu.
{ "series_id": 2 }Răspuns 200: Document.
Stornează o factură
POST /api/v1/companies/{company_id}/documents/{document_id}/storno
Permisiune: documents:issue.
Emite factura de stornare (cantități negative, cu trimitere la factura inițială), totală sau pe linii. O factură trimisă se stornează abia după validarea ANAF. Răspunsul este stornarea.
| Parametru | Tip | Ce este |
|---|---|---|
company_id în adresă | integer | Id-ul firmei. |
document_id în adresă | integer | Id-ul documentului. |
Corp: StornoInput, de exemplu.
{ "lines": [{ "line_id": 3302, "quantity": 1 }], "reason": "O oră facturată în plus" }Răspuns 201: Document.
Transformă o proformă în factură
POST /api/v1/companies/{company_id}/documents/{document_id}/convert
Permisiune: documents:write.
Face din proforma emisă o ciornă de factură cu aceleași linii; o emiți apoi cu /issue.
| Parametru | Tip | Ce este |
|---|---|---|
company_id în adresă | integer | Id-ul firmei. |
document_id în adresă | integer | Id-ul documentului. |
Răspuns 201: Document.
Trimite documentul pe email
POST /api/v1/companies/{company_id}/documents/{document_id}/email
Permisiune: documents:write.
PDF-ul, atașat, de la adresa Chappa, cu IBAN-ul pentru plată. Doar pentru o firmă verificată, conectată la ANAF.
| Parametru | Tip | Ce este |
|---|---|---|
company_id în adresă | integer | Id-ul firmei. |
document_id în adresă | integer | Id-ul documentului. |
Corp: EmailInput, de exemplu.
{ "to": "contabilitate@beta.ro", "message": "Vă mulțumim pentru comandă." }Răspuns 200: Email.
PDF-ul documentului
GET /api/v1/companies/{company_id}/documents/{document_id}/pdf
Permisiune: documents:read.
Documentul în PDF, cu sigla firmei. Și pentru facturile trimise din alte programe.
| Parametru | Tip | Ce este |
|---|---|---|
company_id în adresă | integer | Id-ul firmei. |
document_id în adresă | integer | Id-ul documentului. |
Răspuns 200: un fișier PDF (application/pdf).
Obiectul DocumentInput
Ce trimiți la creare și la modificare. La modificare, câmpurile lipsă rămân cum erau; lines trimis înlocuiește toate liniile.
| Câmp | Tip | Ce este |
|---|---|---|
type | invoice | proforma | Doar la creare. Implicit invoice. |
issue_date | date | Data emiterii. Implicit azi (ora României). |
due_date | date sau null | Scadența. Implicit data emiterii plus zilele implicite ale firmei; "" o șterge. |
currency | string | Moneda, cod ISO 4217. Implicit moneda firmei. |
exchange_rate | number sau null | Cursul. Lipsă: cursul BNR pentru data emiterii, completat de noi. |
client_id | integer sau null | Un client din agendă… |
client | ClientInput | …sau clientul scris direct pe document. |
save_client | boolean | Salvează clientul scris direct în agendă (după CUI, CNP sau ref îl găsește dacă există). |
lines | listă de LineInput | Liniile documentului. |
notes | string sau null | Mențiuni tipărite pe document. |
internal_note | string sau null | Notă internă, netipărită. |
order_ref | string sau null | Numărul comenzii (BT-13 în e-Factura). |
contract_ref | string sau null | Numărul contractului (BT-12). |
external_ref | string sau null | Id-ul tău pentru document. Îl cauți apoi cu ?external_ref=. |
payment_method | ordin_plata | numerar | card | cec | bon_fiscal | altul | Modul de plată; bon_fiscal face factura de tip 751. |
collected | boolean | Încasată integral la emitere, prin payment_method (numerar: cu chitanță). |
bank_account_id | integer sau null | Contul tipărit pe factură. Implicit cel principal. |
Obiectul DocumentCreate
DocumentInput, plus ce poate face aceeași cerere:
| Câmp | Tip | Ce este |
|---|---|---|
issue | boolean | Emite documentul (îi dă număr). Dacă emiterea nu reușește, nu rămâne nicio ciornă. Cere documents:issue. |
submit | boolean | Trimite factura emisă în RO e-Factura. Cere issue: true și documents:submit. Dacă ANAF nu o ia acum, rămâne programată și reîncercăm. |
series_id | integer | Seria, la emitere. Implicit seria principală. |
number | integer | Numărul, la emitere. Implicit următorul din serie. |
Obiectul LineInput
O linie, cum o trimiți.
| Câmp | Tip | Ce este |
|---|---|---|
product_id | integer sau null | Un produs din catalog (completează restul câmpurilor lipsă). |
code | string sau null | Codul articolului. |
name | string | Denumirea. |
description | string sau null | Descriere. |
unit | string | Unitatea, cod UN/ECE: H87 bucată, HUR oră, KGM kilogram, C62 unitate. Implicit H87. |
quantity | number | Cantitatea. |
unit_price | number | Prețul unitar, în moneda documentului. |
price_includes_vat | boolean | Prețul conține TVA. |
discount_percent | number sau null | Reducere pe linie, în procente. |
vat_rate_id | integer sau null | O cotă a firmei (vat_rates)… |
vat_percent | number sau null | …sau procentul, cu vat_category. Lipsă: cota implicită a firmei. |
vat_category | string sau null | Categoria de TVA: S, Z, E, AE, K, G, O. |
src_price | number sau null | Prețul în altă monedă, convertit de noi la cursul BNR dacă lipsește unit_price. |
src_currency | string sau null | Moneda lui src_price. |
Obiectul Document
O factură, o proformă sau o stornare.
| Câmp | Tip | Ce este |
|---|---|---|
id | integer | Id-ul documentului. |
object | document | Mereu document. |
company_id | integer | Firma. |
type | invoice | proforma | storno | Factură, proformă sau factură de stornare. |
status | draft | issued | Ciornă sau emis (cu număr). |
source | chappa | spv | spv: trimisă din alt program prin SPV și preluată de noi (nu se modifică). |
number | string sau null | Numărul tipărit (seria și numărul). null la ciornă. |
series | string sau null | Seria. |
sequence | integer sau null | Numărul din serie. |
issue_date | date | Data emiterii. |
due_date | date sau null | Scadența. |
currency | string | Moneda. |
exchange_rate | number sau null | Cursul folosit. |
exchange_rate_date | date sau null | Data cursului BNR (lipsă când cursul a fost scris de mână). |
client_id | integer sau null | Clientul din agendă. |
client | ClientSnapshot | Clientul de pe document. |
lines | listă de Line | Liniile (lipsesc din liste). |
totals | object | net, vat, total. |
notes | string sau null | Mențiunile. |
internal_note | string sau null | Nota internă. |
order_ref | string sau null | Comanda. |
contract_ref | string sau null | Contractul. |
external_ref | string sau null | Id-ul tău. |
payment_method | string sau null | Modul de plată. |
bank_account_id | integer sau null | Contul tipărit. |
vat_on_collection | boolean | Emisă cu TVA la încasare. |
storno_of | object sau null | Pe o stornare: factura stornată (id, number, date). |
stornos | listă de object | Pe o factură: stornările ei (id, number, date, total). |
converted_from_id | integer sau null | Proforma din care vine factura. |
converted_to_id | integer sau null | Factura în care s-a transformat proforma. |
efactura | EfacturaState | Starea în RO e-Factura. |
payment | PaymentState | Cât s-a încasat. |
payments | listă de object | Încasările (lipsesc din liste): id, amount, paid_on, method, reference, note, receipt_id, receipt_number. |
created_at | date-time | Creat. |
issued_at | date-time sau null | Emis. |
Obiectul Line
O linie, cum o citești: câmpurile din LineInput, plus:
| Câmp | Tip | Ce este |
|---|---|---|
id | integer | Id-ul liniei (îl folosești la stornare). |
position | integer | Ordinea. |
exemption_code | string sau null | Codul motivului de scutire (VATEX). |
exemption_text | string sau null | Temeiul scutirii. |
net | number | Valoarea fără TVA. |
vat | number | TVA-ul liniei. |
gross | number | Valoarea cu TVA. |
storno_of_line_id | integer sau null | Linia stornată, pe o stornare. |
Obiectul ClientSnapshot
Clientul cum a rămas pe document.
| Câmp | Tip | Ce este |
|---|---|---|
kind | pj | pf | Firmă sau persoană fizică. |
name | string | Denumirea sau numele. |
cui | string sau null | CUI-ul firmei. |
cnp | string sau null | CNP-ul persoanei (mascat pentru rolul de vizualizare). |
send_cnp | boolean | CNP-ul se transmite în e-Factura (altfel 13 zerouri). |
reg_com | string sau null | Registrul Comerțului. |
address | string sau null | Adresa. |
city | string sau null | Localitatea (în București: Sector 1…6). |
county | string sau null | Județul. |
country | string | Țara, ISO 3166-1. |
email | string sau null | Emailul. |
phone | string sau null | Telefonul. |
Obiectul IssueInput
Emiterea unei ciorne. Toate opționale.
| Câmp | Tip | Ce este |
|---|---|---|
series_id | integer | Seria. Implicit cea principală. |
number | integer | Numărul. Implicit următorul liber. |
issue_date | date | Data emiterii. Implicit cea din ciornă. |
Obiectul StornoInput
O stornare (factură cu cantități negative care face trimitere la cea inițială).
| Câmp | Tip | Ce este |
|---|---|---|
lines | listă de object | {line_id, quantity}: cât stornezi din fiecare linie. Lipsă: tot ce se mai poate storna. |
series_id | integer | Seria stornării. Implicit seria facturii. |
issue_date | date | Data. Implicit azi. |
reason | string | Motivul, tipărit în mențiuni. |
Obiectul EmailInput
Trimiterea PDF-ului pe email, de la adresa Chappa, în numele firmei. Doar pentru o firmă verificată, conectată la ANAF.
| Câmp | Tip | Ce este |
|---|---|---|
to | string | Adrese separate prin virgulă. Implicit emailul clientului. |
message | string | Mesajul tău, deasupra facturii. |
Obiectul Email
Emailul trimis.
| Câmp | Tip | Ce este |
|---|---|---|
object | email | Mereu email. |
document_id | integer | Documentul (sau receipt_id, chitanța). |
sent_to | listă de string | Adresele. |