API-ul v6 WeBill permite unei aplicații externe (magazin online, ERP, CRM, aplicație de pontaj) să emită și să gestioneze facturi fiscale, proforme, încasări, stornări, clienți și pontaje în contul unei companii WeBill și să citească datele companiei.
În WeBill, la Setări companie > API: copiază Client ID (login-ul contului care deține compania) și ID companie, apoi generează Secretul API (se afișează o singură dată; fiecare companie are secretul ei).
În Postman, importă colecția și fișierul de mediu webident-crm-api-v6.postman_environment.json (sau creează un Environment cu variabilele de mai jos) și completează base_url, api_user, api_secret și, dacă ai mai multe companii, company_id.
Rulează Autentificare > Obținere token: tokenul se salvează automat în api_token și este folosit de toate celelalte cereri (autentificarea Bearer e setată la nivel de colecție).
Rulează Nomenclatoare > Facturi: completează automat serie_id, receipt_serie_id, delegate_id și bank_id cu valorile marcate „Implicit” în Setări, altfel primele active.
Cererile din fiecare folder pot fi rulate de sus în jos (Collection Runner): fiecare cerere care creează ceva salvează ID-ul în Environment pentru cererile următoare.
⚠️ Cererile emit documente fiscale reale în compania tokenului (numere consumate din serie). Testează pe o companie / serie de test.
Autentificare
POST /api/v6/auth/token cu login-ul utilizatorului și secretul API al companiei → access_token.
Toate celelalte cereri trimit Authorization: Bearer {access_token} (alternativ headerul X-API-Token: {access_token}). Tokenul în query string nu este acceptat.
Tokenul este valabil 12 ore (expires_in: 43200); nu există refresh — la 401 cere un token nou și reia cererea.
Un utilizator are un singur token activ pe companie: un token nou îl invalidează imediat pe cel vechi. Dacă două integrări folosesc același utilizator și aceeași companie, ele se deconectează reciproc; folosește câte un utilizator pentru fiecare integrare sau partajează tokenul.
Toate datele sunt limitate la compania tokenului: ID-urile altor companii răspund 404.
Răspuns 401
Cauză
(401.0) Acces refuzat: lipseste tokenul de acces
Lipsește tokenul.
(401.1) Acces refuzat: token de acces invalid
Token necunoscut sau înlocuit de un token mai nou.
(401.2) Tokenul de acces a expirat
Tokenul a expirat (după 12 ore). Cererile următoare cu același token primesc 401.1.
(401.3) Compania tokenului nu mai exista
Compania tokenului nu mai există.
(401.4) Acces refuzat: compania este inchisa
Compania a fost închisă; nu se mai emit tokenuri, iar cele emise sunt refuzate.
Format cereri
Trimite JSON cu Content-Type: application/json și Accept: application/json. Sunt acceptate și cererile form-data; un corp JSON trimis cu alt Content-Type este decodat oricum.
Date: AAAA-LL-ZZ. Sume: numere (121.5); se acceptă și virgula zecimală în string ("121,5"). Boolean: true / false (se acceptă și 1, "da", "yes", "on").
Multe câmpuri au și denumiri alternative (camelCase, ex. clientId, serieId); în documentație apar denumirile principale, recomandate.
În Postman, o cerere care folosește o variabilă încă goală (ex. product_id când compania nu are produse, project_id fără proiecte) este sărită, cu motivul în Console. Restul colecției rulează mai departe.
O rută sau o metodă inexistentă sub /api/v6/ răspunde tot în formatul de mai jos: 404 Ruta nu exista, 405 Metoda nu este permisa pe aceasta ruta.
Toate mesajele (statusMessage și textele din errors) sunt în limba română, fără diacritice. În mesajele de validare numele câmpului apare cu spații în loc de _ (ex. Campul serie id este obligatoriu.); cheile din errors rămân numele câmpurilor. Codul HTTP și errors.code sunt cele de urmărit în integrare, nu textul.
{ "status": 422, "statusMessage": "Cota TVA selectata nu este disponibila.", "errors": { "code": "INVALID_TAX" }, "data": null }
statusMessage este textul de afișat / logat; data este null la erori.
errors este [] sau un obiect: erori pe câmpuri ({"items": ["..."]}) sau {"code": "..."} pentru refuzurile de business pe documente și încasări. Integrează-te pe status + errors.code, nu pe textul mesajului.
Descărcările (/download) răspund direct cu fișierul PDF (Content-Type: application/pdf, Content-Disposition: attachment; filename=...); erorile lor sunt JSON.
HTTP
Când
200 / 201
Succes (201 doar la un pontaj nou).
400
JSON invalid, parametri lipsă la nomenclatoare, alte erori neașteptate ale operației.
401
Autentificare (vezi mai sus).
403
Resursa există, dar nu aparține companiei (proiecte).
404
Resursa nu există în compania tokenului.
409
Starea documentului nu permite operația (factură trimisă în SPV, cu încasări, deja stornată etc.).
422
Date invalide (validare).
429
Limita de cereri depășită. Corpul nu are formatul de mai sus; respectă headerul Retry-After.
Coduri errors.code
Cod
HTTP
Semnificație
INVALID_CLIENT
422
Clientul nu este disponibil.
INVALID_INVOICE_SERIE / INVALID_PROFORMA_SERIE
422
Seria nu există, nu e activă sau nu e a companiei.
INVALID_RECEIPT_SERIE
422
Seria de chitanțe nu este disponibilă.
INVALID_DELEGATE
422
Delegatul nu este disponibil.
INVALID_BANK_ACCOUNT
422
Contul bancar nu este disponibil.
INVALID_TAX
422
Cota TVA nu este disponibilă.
INVALID_TAX_CLIENT
422
Cota TVA aleasă (ex. taxare inversă) nu se aplică acestui client.
INVALID_PRODUCT
422
Produsul nu există în nomenclatorul companiei.
INVALID_ITEMS
422
Documentul nu are nicio linie validă.
INVOICE_PAYMENT_AMOUNT_INVALID
422
Suma încasării trebuie să fie mai mare decât zero.
INVOICE_PAYMENT_TYPE_INVALID
422
Tipul de încasare nu este disponibil.
INVOICE_PAYMENT_NOT_ALLOWED
409
Documentul nu mai acceptă încasări (anulat, stornat, proformă convertită etc.).
INVOICE_CANCEL_HAS_PAYMENTS
409
Factura are încasări și nu poate fi anulată (șterge încasările sau storneaz-o).
INVOICE_CANCEL_NOT_ALLOWED
409
Factura nu poate fi anulată în starea curentă.
INVOICE_STORNO_HAS_PAYMENTS
409
Factura are încasări: trimite payments_action (credit sau refund).
INVOICE_STORNO_PAYMENTS_ACTION_INVALID
422
payments_action invalid.
INVOICE_STORNO_NOT_ALLOWED
409
Factura nu poate fi stornată în starea curentă.
AMBIGUOUS_DOCUMENT
409
Caută după serie și număr: mai multe documente se potrivesc; errors.candidates[].
CLIENT_MISMATCH
404
Caută după serie și număr: documentul există, dar clientul nu corespunde.
COMPANY_MISMATCH
404
Caută după serie și număr: documentul există, dar emitentul are alt cod fiscal.
DATE_MISMATCH
404
Caută după serie și număr: documentul există, dar are altă dată decât date.
DOCUMENT_NOT_FOUND
404
Caută după serie și număr: niciun document cu seria și numărul acestea.
Limite
120 de cereri pe minut pentru toate rutele /api/v6 (inclusiv obținerea tokenului). Peste limită: 429 cu headerele Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining.
GET /clients este paginat (max. 100 pe pagină); celelalte liste nu sunt paginate.
Cache (ETag)
GET /company și toate GET /nomenclature/* răspund cu ETag și Cache-Control: no-cache, private. Păstrează răspunsul împreună cu ETag-ul și la cererea următoare trimite headerul If-None-Match: <ETag>: dacă datele nu s-au schimbat primești 304 Not Modified, fără corp, și folosești copia ta; altfel 200 cu datele noi și un ETag nou. ETag-ul se schimbă la orice modificare a datelor (o serie, un cont, un produs nou). Cererea 304 se numără în limita de 120 pe minut, dar nu mai transferă datele.
Recomandare: citește Nomenclatoare > Facturi o dată la pornirea integrării (sau înaintea unei serii de facturi) și revalidează-l, în loc să-l ceri înaintea fiecărei facturi.
Răspunsurile sunt private (depind de token): un proxy partajat nu le păstrează.
Ciclul unei facturi
Emitere — POST /invoices creează direct o factură emisă, numerotată în serie (API-ul nu creează ciorne). Transmiterea în SPV (e-Factura) se face din WeBill, după setările companiei.
Modificare — PATCH /invoices/{id} cât timp factura nu a fost trimisă în SPV.
Încasare — POST /invoices/{id}/receipts (sau direct la emitere cu POST /invoices/with-receipt); o plată pentru mai multe facturi: POST /invoices/receipts/bulk.
Corectare — înainte de SPV și fără încasări: POST /invoices/{id}/cancel (anulare). După SPV: stornare totală sau parțială, POST /invoices/{id}/storno.
Stare
Modificare
Încasări
Anulare
Stornare
emisa, netrimisă în SPV
da
da
da, fără încasări
da
emisa, trimisă în SPV
nu (409)
da
devine stornare
da
anulata
nu
nu
idempotent
nu
storno (factura inversă)
—
doar restituiri (sume negative)
dacă nu e trimisă în SPV
nu
Scenarii frecvente
Factura după numărul tipărit: GET /invoices/find?serie=WB&number=12&company_vat=... (opțional și date, client_vat, client_name) întoarce factura ca GET /invoices/{id} doar dacă seria, numărul, codul fiscal al emitentului și fiecare parametru opțional trimis corespund exact; altfel o eroare cu errors.code, niciodată un document apropiat. La fel GET /proforme/find.
Datele emitentului: GET /company — identitatea fiscală, adresa, conturile bancare, punctele de lucru, modulele pornite și dacă e-Factura e conectată.
Comandă plătită online (magazin): POST /invoices/with-receipt cu clientul inline, order_id = ID-ul comenzii și receipt.type = card. Factura și încasarea se creează în aceeași tranzacție; reîncercarea cu același order_id în 2 minute nu dublează factura. Apoi POST /invoices/{id}/email.
Comandă cu plata ulterior (OP / ramburs): POST /invoices, iar la confirmarea plății POST /invoices/{id}/receipts cu type = op sau ramburs.
Extras bancar cu o plată pentru mai multe facturi: citește restul de plată (GET /invoices/{id} → totals.stats.rest) și trimite POST /invoices/receipts/bulk cu expected_balances.
Retur parțial: GET /invoices/{id}/storno (liniile și ce a rămas de stornat), apoi POST /invoices/{id}/storno cu lines.
Ofertă / avans: POST /proforme, încasare pe proformă; proforma se convertește în factură din WeBill.
Variabile de mediu
Variabilă
Setată de
Descriere
base_url
tine
https://webill.ro
api_user
tine
Login-ul utilizatorului WeBill.
api_secret
tine
Secretul API al companiei.
company_id
tine
ID-ul companiei; obligatoriu doar dacă utilizatorul are mai multe companii cu același secret.
Un token nou pentru același utilizator și aceeași companie îl invalidează imediat pe cel anterior. Cere un token nou la expirare (401.2) sau la 401.1, nu la fiecare cerere.
Erori
401 (401) Date de autentificare invalide — lipsește login-ul sau secretul.
401 (401) Utilizator inexistent.
401 (401) Secret sau companie invalida — secretul nu se potrivește cu nicio companie a utilizatorului (sau cu company_id).
422 (422) Selectati compania (company_id) cand exista mai mult de o companie activa (errors.company_id).
{
"status":401,
"statusMessage":"(401) Secret sau companie invalida",
"errors": [],
"data":null
}
Nomenclatoare
Listele de valori ale companiei: serii, delegați, conturi bancare, cote TVA, țări, județe, curs valutar și produse. ID-urile de aici sunt cele pe care le primesc documentele. Nomenclatoarele se schimbă rar: păstrează-le în cache și revalidează-le cu If-None-Match (304 fără corp când nu s-a schimbat nimic). Nomenclatoare > Facturi aduce într-o singură cerere tot ce trebuie pentru o factură.
Tot ce trebuie pentru a construi o factură sau o proformă. Doar elementele active ale companiei, în ordinea din WeBill (Setări, săgețile sus / jos). Un document creat fără serie_id, delegate_id sau bank_accounts ia ce e marcat „Implicit” în Setări (is_default: true: seria, delegatul, contul monedei documentului), altfel prima serie, primul delegat, toate conturile active.
Cheie
Conținut
currencies[]
code, name — monedele acceptate în currency.
languages[]
code (ro, en), name.
invoice_series[]
id, serie, current_number (următorul număr), receipt_serie / receipt_current_number (chitanțierul seriei, folosit la încasările cash), currency, is_default, is_active. rec_serie / rec_current_index sunt aliasuri vechi.
id, bank, iban, currency, label, is_default (cel mult unul pe monedă), is_active — pentru bank_accounts.
taxes[]
id, name, percent, categorie (categoria e-Factura: S, Z, E, AE, K, O ...), is_default, is_active — pentru tax_id / tax_value.
units[]
id, code (codul UN/ECE, ex. H87, HUR), name (denumirea dată de companie, altfel cea standard), default_name, is_default — unitățile de măsură ale companiei (Setări > Unități de măsură), în ordinea din editorul de documente. Pe o linie, um primește code sau name.
Tipurile de client (client_types: pf persoană fizică, pj persoană juridică — la clienți se trimit ca is_pf: true/false) și țările active (countries[]: code, name), cu cele fixate primele.
Județele / regiunile unei țări: country (code, name) și states[] (code, name), ordonate după nume. Codul (B, CJ, IF ...) se trimite în câmpul state al clientului.
Query: country (obligatoriu) — codul țării (RO), sau o parte din numele ei.
Erori: 400 Parametrul country este obligatoriu; 404 Tara nu a fost gasita.
Cursul BNR pe care WeBill îl folosește pentru un document cu data cerută: ultimul curs publicat înaintea datei (cursul zilei bancare anterioare).
Query
currency (obligatoriu): codul monedei, 3 litere (EUR, USD ...). Pentru RON se întoarce cursul EUR.
date (opțional): AAAA-LL-ZZ; implicit azi. Alternativ year, month, day.
Răspuns: requested_currency, currency, rate, multiplier (1 pentru majoritatea monedelor; 100 pentru HUF / JPY: cursul este pentru 100 de unități), requested_date, rate_date, source (BNR).
Erori: 400 Parametrul currency este obligatoriu. / ... trebuie sa aiba 3 caractere. / Parametrul date trebuie sa fie in format YYYY-MM-DD.; 404 Cursul valutar nu a fost gasit pentru moneda solicitata.
Cu modulul Gestiune pornit, stock are câte un rând pe gestiune activă care a avut articolul: warehouse_id, warehouse_name, quantity, reserved, lots[] (lot, expiry_date, quantity). Fără urmărire de stoc (sau cu modulul oprit), tracks_stock / tracks_lots sunt false și stock este null.
Pe o linie de factură / proformă poți trimite doar product_id și qty: restul câmpurilor se completează din produs (le poți suprascrie trimițându-le).
Datele companiei tokenului (emitentul documentelor), doar de citit. Utile pentru afișarea emitentului, verificarea plătitorului de TVA sau a modulelor pornite înainte de a emite.
Datele companiei tokenului, doar de citit: identitatea fiscală și adresa așa cum apar pe documente, punctele de lucru, modulele pornite, starea la ANAF, conectarea e-Factura (SPV) și preferințele documentelor. Tot ce trebuie pentru o factură (serii, conturi bancare, cote TVA, delegați, unități de măsură) este într-o singură cerere, Nomenclatoare > Facturi.
Răspunde cu ETag: retrimite-l în If-None-Match și primești 304 fără corp cât timp datele nu s-au schimbat (vezi Cache în descrierea colecției).
company
Câmp
Detalii
id, name, alias, code
ID-ul (același cu company_id de la token), denumirea legală, numele scurt și codul intern din Setări.
vat, vat_label
Codul fiscal fără / cu prefixul RO (prefixul doar la plătitorii de TVA).
has_vat, vat_on_collection
Plătitor de TVA; TVA la încasare (doar împreună cu has_vat).
vat_vies, reg, capital_social, bt_29
Codul VIES, nr. de înregistrare la Registrul Comerțului, capitalul social, identificatorul vânzătorului din e-Factura (BT-29). null când nu sunt completate.
label, value — informațiile suplimentare tipărite pe documente (ex. cont Trezorerie).
conta_cont_analitic_client
Contul analitic al companiei folosit la exportul contabil.
logo_url
URL-ul public al logo-ului sau null.
is_branch, cui_branch, parent_company
Punct de lucru: CUI-ul punctului și compania-mamă (id, name, vat). Un punct de lucru are identitatea fiscală a companiei-mamă (vat, reg, has_vat etc.).
subscription_until
Ultima zi plătită a abonamentului WeBill (AAAA-LL-ZZ) sau null.
created_at
Data creării companiei în WeBill.
Celelalte chei
Cheie
Conținut
anaf
state (active, inactive, suspended, deregistered), state_text, state_date, synced_at — ultima verificare a companiei la ANAF; null dacă nu a fost verificată.
efactura
connected (există un token SPV valabil), expires_at, autoupload (facturile se trimit automat în SPV), autodownload.
branches[]
id, name, code, cui_branch, city — punctele de lucru active ale companiei (gol pentru un punct de lucru). Fiecare are propriul company_id și propriul token.
Clienții companiei: căutare, creare și actualizare. Nu există ștergere prin API. Documentele pot primi fie client_id, fie clientul inline (client), cu aceleași câmpuri ca aici.
Dacă există deja un client PJ cu același CUI, nu se creează un duplicat: răspunsul conține clientul existent, nemodificat (folosește PATCH pentru a-l actualiza). Poți apela deci acest endpoint ca „găsește sau creează”.
Pentru un CUI nou, datele lipsă (denumire, Reg. Com., adresă, plătitor de TVA) se completează din ANAF; valorile trimise de tine au prioritate.
Body
Câmp
Tip
Obligatoriu
Detalii
is_pf
bool
recomandat
false persoană juridică, true persoană fizică. Implicit true la creare.
company
string
nu
Denumirea firmei sau numele persoanei.
vat
string
da la PJ
CUI (cu sau fără RO; se păstrează doar cifrele) sau CNP la persoana fizică. În România CUI-ul și CNP-ul sunt validate. PF fără CNP → CNP anonim 0000000000000.
has_vat
bool
nu
Plătitor de TVA. La PJ se completează din ANAF dacă nu e trimis.
Codul județului (B, CJ ...), din Nomenclatoare > Județe.
city
string
nu
Localitatea. Pentru București (state: B) este obligatoriu și trebuie să fie Sector 1 ... Sector 6.
address_line_1
string
nu
Adresa (stradă, număr).
address_line_2
string
nu
Completare adresă.
zip
string
nu
Cod poștal.
phone
string
nu
Telefon.
email
string
nu
Emailul folosit implicit la trimiterea documentelor (mai multe adrese separate prin virgulă).
bank
string
nu
Banca.
iban
string
nu
IBAN.
Răspuns: statusMessageClient creat cu succes pentru un client nou. Dacă firma are deja un client PJ cu același CUI, răspunsul este tot HTTP 200, cu aceeași structură data, clientul existent rămâne nemodificat, iar statusMessage este Clientul exista deja cu acest cod fiscal si nu a fost modificat.
data (client): id, company, is_pf, has_vat, vat (doar cifre), country (code, name) / null, state (code, name) / null, city, email, address_1, phone, bank, iban.
Erori — 422 Eroare validare client: <motiv>, de exemplu:
Denumirea tarii este obligatorie pentru tipul de client selectat.
Campul vat este obligatoriu. (PJ fără CUI) / Codul fiscal (vat) nu este valid (CUI românesc invalid) / CNP-ul introdus este invalid
Pentru Bucuresti, campul city este obligatoriu si trebuie sa fie Sector 1, Sector 2, ... sau Sector 6.
{
"status":200,
"statusMessage":"Client creat cu succes",
"data": {
"id":2,
"company":"EXEMPLU DISTRIBUTIE SRL",
"is_pf":false,
"has_vat":true,
"vat":"10000008",
"country": {
"code":"RO",
"name":"Romania"
},
"state": {
"code":"B",
"name":"Bucuresti"
},
"city":"Sector 1",
"email":"[email protected]",
"address_1":"Str. Exemplu nr. 1",
"phone":"0722000000",
"bank":"Banca Exemplu",
"iban":"RO49AAAA1B31007593840000"
}
}
{
"status":422,
"statusMessage":"Eroare validare client: Codul fiscal (vat) nu este valid",
"errors": [],
"data":null
}
{
"status":422,
"statusMessage":"Eroare validare client: Pentru Bucuresti, campul city trebuie sa fie Sector 1, Sector 2, Sector 3, Sector 4, Sector 5 sau Sector 6.",
"errors": [],
"data":null
}
Creează un client persoană fizică (is_pf: true). CNP-ul (vat) este opțional: fără el se folosește CNP-ul anonim 0000000000000, acceptat de e-Factura. Persoanele fizice nu sunt deduplicate: fiecare cerere creează un client nou — caută-l întâi după CNP dacă ai unul.
Câmpurile și erorile sunt cele de la persoana juridică.
data (client): id, company, is_pf, has_vat, vat (doar cifre), country (code, name) / null, state (code, name) / null, city, email, address_1, phone, bank, iban.
Caută clientul după cod fiscal sau CNP. Prefixul RO și orice alt caracter în afara cifrelor sunt ignorate. Răspunsul are același format ca lista: items cu cel mult un client (total: 0 și items: [] dacă nu există).
Tipic pentru integrare: caută după CUI → dacă nu există, creează-l (sau trimite direct clientul inline pe factură).
Un client după ID. data este direct obiectul client.
data (client): id, company, is_pf, has_vat, vat (doar cifre), country (code, name) / null, state (code, name) / null, city, email, address_1, phone, bank, iban.
Actualizează doar câmpurile trimise (aceleași câmpuri ca la creare); restul rămân neschimbate. Validarea se face pe clientul rezultat (de ex. un client din București trebuie să aibă în continuare city = Sector N). Nu se face completare din ANAF.
Răspuns: statusMessageClient actualizat, data = clientul.
Erori: 404 Clientul nu a fost gasit; 422 Eroare validare client: ....
Înregistrează timpul lucrat într-o zi pe un proiect. Există un singur pontaj pe proiect și zi: a doua cerere pentru aceeași zi îl suprascrie (200), prima îl creează (201).
Body
Câmp
Tip
Obligatoriu
Detalii
job_date
AAAA-LL-ZZ
da
Ziua lucrată.
job_time
H:MM / HH:MM / HH:MM:SS
da
Durata lucrată (nu ora din zi), ex. 2:30 = 2 ore și 30 de minute.
job_notes
string
da
Ce s-a lucrat.
billable
bool
nu
Se facturează. Implicit true (și la suprascriere, dacă lipsește).
status
int
nu
0 To Do, 2 In Progress, 5 In review (implicit), 1 Done, 3 On Hold, 4 Canceled.
created_by
int
nu
ID-ul utilizatorului WeBill care a lucrat.
Tariful orar este întotdeauna default_price_per_hour al proiectului.
{
"status":422,
"statusMessage":"Date invalide la pontaj",
"errors": {
"job_date": [
"Campul job date este obligatoriu."
],
"job_time": [
"Formatul campului job time nu este valid."
],
"job_notes": [
"Campul job notes este obligatoriu."
]
},
"data":null
}
Facturi fiscale
Facturi fiscale: emitere, modificare, PDF, email, încasări, anulare și stornare. Cererile sunt în ordinea în care pot fi rulate cap-coadă (Collection Runner); fiecare creare salvează ID-ul în Environment.
Emite o factură fiscală emisă, numerotată în seria aleasă (API-ul nu creează ciorne). Transmiterea în SPV (e-Factura) se face din WeBill, după setările companiei.
Cu modulul Gestiune pornit, liniile cu produse urmărite pe stoc descarcă stocul din gestiunea implicită, din loturile cele mai vechi (API-ul nu primește gestiunea sau lotul). Stoc insuficient → 422 Stoc insuficient pentru "..." in gestiunea "...", la AAAA-LL-ZZ: disponibil X, necesar Y., iar factura nu se creează.
Body
Câmp
Tip
Obligatoriu
Detalii
client_id
int
unul din client_id / client
Client existent al companiei (vezi Clienți).
client
obiect
unul din client_id / client
Client inline, cu aceleași câmpuri și reguli ca POST /clients (persoana juridică existentă cu același CUI este refolosită). Eroare → 422 Client invalid: ....
items
array
da
Cel puțin o linie (vezi mai jos).
serie_id
int
nu
Seria (Nomenclatoare > Facturi: invoice_series / proforma_series). Implicit seria marcată „Implicită” în Setări, altfel prima serie activă. Serie străină / inactivă → 422 INVALID_INVOICE_SERIE / INVALID_PROFORMA_SERIE.
delegate_id
int
nu
Delegatul (delegates). Implicit delegatul marcat „Implicit” în Setări, altfel primul delegat activ. → 422 INVALID_DELEGATE.
bank_accounts
int[]
nu
Conturile bancare tipărite pe document (banks). Implicit contul marcat „Implicit” în moneda documentului, altfel toate conturile active. → 422 INVALID_BANK_ACCOUNT.
issue_date
AAAA-LL-ZZ
nu
Data documentului; implicit azi. O factură nu poate fi datată înaintea ultimei facturi emise din aceeași serie (422).
due_days / due_date
int ≥ 0 sau dată
nu
Termenul de plată: numărul de zile (implicit 15) sau direct data scadenței, AAAA-LL-ZZ (sau ZZ.LL.AAAA), care nu poate fi înaintea datei documentului.
Implicit cursul BNR al datei documentului (1 pentru RON).
language
ro / en
nu
Limba documentului (PDF, email). Implicit ro.
comments
string
nu
Observații tipărite pe document.
document_type
int
nu
Tipul e-Factura: 380 factură (implicit), 751 factură în scop de informare contabilă, 389 autofactură (emisă în numele furnizorului: clientul documentului e furnizorul, compania e cumpărătorul).
order_id
string
nu
ID-ul comenzii din sistemul tău. Idempotență: o factură pentru același client și același order_id creată în ultimele 2 minute este întoarsă în loc să se creeze un duplicat (sigur la reîncercări după timeout). Două cereri simultane cu același order_id → a doua primește 409 Comanda este deja in curs de facturare. Reincearca.
curier, awb
string
nu
Date de livrare.
generate_payment_link
bool
nu
true generează un link de plată cu cardul (Netopia) inclus în email și PDF. Cere un cont Netopia activ în companie, altfel 400.
Linii (items[])
Câmp
Tip
Obligatoriu
Detalii
description
string ≤ 255
da*
Denumirea produsului / serviciului.
details
string
nu
Text suplimentar pe linie.
um
string ≤ 50
da*
Unitatea de măsură: denumirea folosită de companie (ex. BUC, ORA) sau codul UN/ECE (H87, HUR). Lista: Nomenclatoare > Facturi (units).
qty
număr > 0
da
Cantitatea. Zecimale cu punct sau virgulă.
unit_price
număr ≥ 0
da*
Prețul unitar, în moneda liniei.
tax_included
bool
nu
Implicit true: prețul include TVA. false = preț fără TVA.
tax_value
număr 0–100
nu
Cota TVA în procente (ex. 21, 11, 0). Se potrivește cu o cotă activă a companiei cu exact acest procent; vezi taxes din Nomenclatoare > Facturi.
tax_id
int
nu
ID-ul cotei TVA din Nomenclatoare > Facturi. Are prioritate față de tax_value. Cotă inexistentă / inactivă → 422 INVALID_TAX.
discount
număr
nu
Reducere pe linie, ca valoare (în moneda liniei).
discount_type
string
nu
Doar valoric (implicit). Reducerea procentuală nu este disponibilă prin API.
currency
string (3)
nu
Moneda liniei; implicit moneda documentului. Conversia se face la cursul BNR al datei documentului.
product_id
int
nu
Produs din Nomenclatoare > Produse și servicii: câmpurile netrimise (description, details, um, unit_price, currency, tax_id, tax_included, cpv_code) se completează din produs. Produs inexistent → 422 INVALID_PRODUCT.
cpv_code
string
nu
Cod CPV (achiziții publice).
* nu sunt obligatorii când linia are product_id. O cantitate, un preț sau o reducere negativă marchează linia ca linie de stornare.
Exemplu de calcul (body-ul de mai jos): linia 1 are prețul cu TVA inclus (1000 = 826,45 + 173,55 TVA); linia 2 are prețul fără TVA: 2 × 150 − 30 reducere = 270 + 56,70 TVA. Totalurile sunt în totals.
totals.items[]: liniile — id (folosit la stornare), denumire, nota, um, um_code, qty, cota_tva, pret_cu_tva, pret_fara_tva, valoare (fără TVA), tva, discount, discount_net, discount_tva, cpv_code.
totals.subtotal: pe cota TVA ("21": {"total_fara_tva", "total_tva"}); totals.total: valoare (fără TVA) și tva sunt înainte de reduceri, total (de plată) este după reduceri: total = valoare + tva - discount.total; totals.discount: reducerile; totals.stats: incasat, rest (rest de plată).
items_count, payment_link_requested, payment_link (linkul de plată Netopia activ sau null).
Erori
400 Payload JSON invalid: ... — corpul nu este JSON valid.
422 Date invalide la linii, cu erorile în errors pe cheia liniei (ex. {"items.0.description": ["Campul description este obligatoriu."]}); la fel pentru items: [].
422 Data din campul issue_date nu este valida (format AAAA-LL-ZZ). (sau date, după câmpul trimis) — o dată pe care serverul nu o poate citi nu mai devine data de azi.
422 pentru un due_date care nu e nici număr de zile, nici dată, sau care e înaintea datei documentului.
422 Clientul nu a fost identificat — lipsește client_id / client sau clientul nu este al companiei.
422 Date invalide la document + errors pe câmpuri (ex. errors.items).
422 cu errors.code: INVALID_INVOICE_SERIE, INVALID_PROFORMA_SERIE, INVALID_DELEGATE, INVALID_BANK_ACCOUNT, INVALID_TAX, INVALID_TAX_CLIENT (cotă de taxare inversă / intracomunitară nepotrivită clientului), INVALID_PRODUCT, INVALID_CLIENT, INVALID_ITEMS.
422 Data facturii (...) nu poate fi inaintea ultimei facturi emise din seria ... (errors.issue_date).
409 Comanda este deja in curs de facturare. Reincearca. — altă cerere cu același order_id este în curs.
400 Compania nu are un cont Netopia activ pentru generarea linkului de plata.
{
"status":422,
"statusMessage":"Cota TVA selectata nu este disponibila.",
"errors": {
"code":"INVALID_TAX"
},
"data":null
}
{
"status":422,
"statusMessage":"Clientul nu a fost identificat",
"errors": [],
"data":null
}
{
"status":422,
"statusMessage":"Date invalide la linii",
"errors": {
"items.0.description": [
"Campul description este obligatoriu."
],
"items.0.qty": [
"Campul qty trebuie sa fie cel putin 0.0001."
],
"items.0.tax_id": [
"Cota de TVA a liniei este obligatorie."
]
},
"data":null
}
{
"status":422,
"statusMessage":"Data scadentei (due_date) nu poate fi inaintea datei documentului.",
"errors": {
"due_date": [
"Data scadentei (due_date) nu poate fi inaintea datei documentului."
]
},
"data":null
}
Cea mai scurtă factură validă: clientul și liniile. Seria, delegatul, conturile bancare, data (azi), termenul (15 zile), moneda (RON) și limba (ro) iau valorile implicite ale companiei; o linie fără tax_value / tax_id primește cota implicită.
Factură cu clientul trimis direct în client (fără să-l creezi întâi): clientul PJ existent cu același CUI este refolosit, altfel se creează. Util pentru magazinele online. Câmpurile clientului sunt cele de la Clienți > Creează; pentru o persoană fizică fără CNP trimite is_pf: true fără vat.
Folosește product_id (din Nomenclatoare > Produse): linia se completează din nomenclator.
Erori în plus față de Creează: 422 Client invalid: <motiv>.
Emite factura și o încasează în aceeași cerere, într-o singură tranzacție: dacă încasarea e invalidă, factura nu se creează. Potrivit pentru comenzile deja plătite online.
Body: câmpurile de la Creează plus receipt (obligatoriu), cu câmpurile de la Încasări - Creează (type, amount, date, identifier, serie_id, notes).
Răspuns: statusMessageDocument si incasare create; data = factura (ca la Creează) plus cheia receipt (încasarea).
Erori în plus: 422 Date invalide la incasare (errors.receipt: Obiectul receipt este obligatoriu., sau erori pe câmpurile încasării); 422 INVOICE_PAYMENT_AMOUNT_INVALID.
Modifică o factură emisă care nu a fost trimisă în SPV. Se schimbă doar câmpurile trimise (cele de la Creează, plus status).
client_id (sau client) e opțional: fără el factura își păstrează clientul; trimis, schimbă clientul.
items, dacă e trimis, înlocuiește toate liniile facturii.
status: emisa, anulata, storno, doar prin tranzițiile permise; pentru anulare și stornare folosește endpointurile dedicate.
Răspuns: statusMessageDocument actualizat, data = factura.
Erori
404 Documentul nu a fost gasit.
409 Factura nu mai poate fi modificata. (errors.invoice) — factura a fost trimisă în SPV sau este blocată de o stornare parțială / factură de corecție / reducere. Corecția se face prin stornare.
422 Clientul nu a fost identificat — client_id trimis nu este un client al companiei.
totals.items[]: liniile — id (folosit la stornare), denumire, nota, um, um_code, qty, cota_tva, pret_cu_tva, pret_fara_tva, valoare (fără TVA), tva, discount, discount_net, discount_tva, cpv_code.
totals.subtotal: pe cota TVA ("21": {"total_fara_tva", "total_tva"}); totals.total: valoare (fără TVA) și tva sunt înainte de reduceri, total (de plată) este după reduceri: total = valoare + tva - discount.total; totals.discount: reducerile; totals.stats: incasat, rest (rest de plată).
items_count, payment_link_requested, payment_link (linkul de plată Netopia activ sau null).
Factura fiscală cu seria și numărul date, confirmată de codul fiscal al emitentului și, opțional, de dată și de client, în compania tokenului: același răspuns ca la Detaliu (GET /invoices/{id}). Util când sistemul tău a păstrat numărul tipărit, nu ID-ul WeBill.
Exact sau nimic. Căutarea nu ghicește: dacă ceva nu corespunde întocmai sau mai multe documente se potrivesc, primești o eroare, niciodată documentul „cel mai probabil”. O automatizare care acționează pe răspuns (încasare, stornare) nu poate atinge astfel o factură greșită.
Query (serie, number și company_vat obligatorii; restul opționale, fiecare trimis se compară)
Parametru
Detalii
serie
Seria, ex. WB.
number
Numărul: doar cifre (12, 0012) sau numărul tipărit cu seria în față (WB0012). Orice altceva (12a, WB-12, altă serie) → 400.
company_vat
CUI-ul emitentului, cum apare pe document (pentru un punct de lucru, al companiei-mamă). Se acceptă cu sau fără RO, cu spații.
date
Opțional. Data documentului, AAAA-LL-ZZ. Deosebește documentele vechi cu aceeași serie și același număr.
client_vat
Opțional. CUI-ul / CNP-ul clientului cum a fost tipărit la emitere (o schimbare ulterioară a clientului nu contează). Cu sau fără RO; un cod străin își păstrează prefixul țării (DE123...). La persoanele fizice fără CNP (0000000000000) codul nu identifică pe nimeni: lasă-l gol sau folosește date.
client_name
Opțional. Numele clientului de pe document, comparat fără majuscule, diacritice și spații în plus.
Răspuns
errors.code
Când
200
—
Exact un document se potrivește.
400
—
Lipsește un parametru obligatoriu, number nu este exact numărul documentului sau date nu e o dată AAAA-LL-ZZ.
404
DOCUMENT_NOT_FOUND
Nu există niciun document cu seria și numărul acestea (Factura nu a fost gasita).
404
COMPANY_MISMATCH
Documentul există, dar emitentul are alt cod fiscal (ex. tokenul altei companii).
404
DATE_MISMATCH
Documentul există, dar are altă dată.
404
CLIENT_MISMATCH
Documentul există, dar clientul are alt cod fiscal sau alt nume.
409
AMBIGUOUS_DOCUMENT
Mai multe documente se potrivesc (aceeași serie și același număr, fără date sau client care să le deosebească) (ex. o factură veche și stornarea ei cu același număr). errors.candidates[] are id, date, status: alege documentul și cere-l cu GET /invoices/{id}.
Proformele nu sunt căutate aici (au proforme/find). Ciornele nu au număr, deci nu se găsesc.
Trimite documentul pe email, cu PDF-ul atașat. Trimiterea se face asincron (în coadă), deci răspunsul confirmă programarea, nu livrarea. Fiecare trimitere apare în istoricul de emailuri al documentului din WeBill (sursa API), la facturi și la proforme.
Body (toate opționale)
Câmp
Tip
Obligatoriu
Detalii
to
string
nu
Destinatarul. Implicit emailul clientului (prima adresă validă; celelalte trec în CC).
Înregistrează o încasare pe document. Starea de încasare a documentului (status_incasare) se actualizează: pending → partial → incasata. O sumă mai mare decât restul este acceptată; diferența intră în creditul clientului.
Body
Câmp
Tip
Obligatoriu
Detalii
type
string
da
Tipul încasării (tabelul de mai jos).
amount
număr > 0
da
Suma, în moneda documentului.
date
AAAA-LL-ZZ
da
Data încasării.
identifier
string ≤ 255
la op / bf / card / ramburs
Referința plății (nr. OP, ID tranzacție, AWB, nr. bon).
serie_id
int
la cash
Seria cu chitanțier (invoice_series[].id din Nomenclatoare > Facturi). Chitanța se numerotează automat.
notes
string
nu
Observații.
type
Ce este
Câmpuri cerute în plus
op
Ordin de plată / transfer bancar
identifier (ex. numărul OP)
bf
Bon fiscal
identifier (numărul bonului)
card
Plată cu cardul / POS / online
identifier (ex. ID-ul tranzacției)
ramburs
Ramburs prin curier
identifier (ex. AWB)
cash
Numerar, cu chitanță numerotată automat
serie_id = ID-ul seriei de facturi care are chitanțierul (invoice_series[].id, câmpul receipt_serie)
avans
Avans
—
credit
Din creditul clientului (sume plătite în plus, stornări)
— ; suma nu poate depăși creditul disponibil
Răspuns: statusMessageIncasare creata.
data (încasare): id, invoice_id (ID-ul documentului), type, identifier, serie_id, serie, number, receipt_number (ex. CH.1, doar la numerar), date, amount, notes, created_at, updated_at.
Erori
404 Documentul nu a fost gasit.
422 Date invalide la incasare + errors pe câmpuri (ex. identifier, serie_id).
Modifică doar câmpurile trimise: amount, date, identifier, notes. Tipul și seria încasării nu se pot schimba (422 Tipul incasarii nu poate fi modificat.): pentru alt tip, șterge încasarea și creeaz-o din nou.
Răspuns: statusMessageIncasare actualizata, data = încasarea.
Erori: 404 Incasarea nu a fost gasita; 422 Date invalide la incasare; 422 Eroare validare incasare: ... (sumă ≤ 0, încasare creată automat din credit / stornare, factură stornată).
PDF-ul chitanței (încasări cash) sau al dovezii de încasare. Răspunsul este fișierul (Content-Type: application/pdf, Content-Disposition: attachment; filename="Chitanta-CH.1.pdf").
Erori (JSON): 404 Documentul nu a fost gasit / Incasarea nu a fost gasita.
O singură plată (ex. un OP din extras) împărțită pe mai multe facturi ale aceluiași client, de la cea mai veche: fiecare factură se achită integral înainte de următoarea; ultima poate rămâne parțial achitată. Se creează câte o încasare pe fiecare factură atinsă.
Body
Câmp
Tip
Obligatoriu
Detalii
invoice_ids
int[]
da
Facturile: același client, aceeași monedă, status emisa, cu rest de plată.
expected_balances
obiect
da
{"<invoice_id>": <rest>} pentru fiecare factură: restul de plată pe care l-ai văzut (totals.stats.rest). Dacă între timp s-a schimbat, cererea e refuzată, ca să nu aloci pe date vechi.
amount
număr > 0
da
Suma totală; cel mult suma resturilor.
date
AAAA-LL-ZZ
da
Data încasării.
type
string
da
op, bf, cash, card sau ramburs.
identifier
string
da, în afară de cash
Referința plății, aceeași pe toate încasările.
serie_id
int
la cash
Seria cu chitanțier; fiecare factură primește chitanța ei.
notes
string
nu
Observații.
Scriptul pre-request citește resturile celor două facturi (invoice_id, invoice_id_2), le pune în expected_balances și alege amount = restul primei facturi plus jumătate din restul celei de-a doua (prima se achită integral, a doua parțial).
Erori — 422 Date invalide la incasare (câmpuri lipsă) sau 422 Eroare validare incasare: <motiv>:
Facturile selectate trebuie sa apartina aceluiasi client. / ... aceeasi moneda.
Doar pe facturile cu status Emisa se pot efectua incasari multiple. / Facturile selectate trebuie sa aiba rest de incasat.
Restul de incasat al unei facturi s-a schimbat intre timp. Reciteste facturile si incearca din nou. — expected_balances nu mai corespunde; recitește facturile.
Lipseste restul de incasat (expected_balances) pentru una dintre facturi. Reciteste facturile si incearca din nou. — lipsește o factură din expected_balances.
Valoarea incasarii nu poate depasi totalul facturilor selectate.
{
"status":422,
"statusMessage":"Eroare validare incasare: Restul de incasat al unei facturi s-a schimbat intre timp. Reciteste facturile si incearca din nou.",
"errors": {
"invoices": [
"Restul de incasat al unei facturi s-a schimbat intre timp. Reciteste facturile si incearca din nou."
]
},
"data":null
}
Ce se poate storna pe factură, înainte de POST .../storno.
Răspuns (data)
storno_allowed / storno_blocker — stornarea totală e posibilă / motivul pentru care nu e.
partial_storno_allowed / partial_storno_blocker — idem pentru stornarea parțială.
has_payments — factura are încasări (stornarea totală cere atunci payments_action).
default_date, default_serie_id — data și seria propuse.
reasons — motivele acceptate (cheie → text).
lines[] — liniile facturii: id (se trimite în lines[].id), description, um, qty, price, vat_rate, tax_included, qty_left / price_left / amount_left (ce a rămas de stornat), done (linie stornată complet). Listă goală când stornarea parțială nu e permisă.
Stornare parțială: emite o factură storno doar pentru liniile / cantitățile alese (retur parțial, reducere de preț). Suma stornată trece în creditul clientului și se aplică pe restul de plată al facturii.
Body
Câmp
Tip
Obligatoriu
Detalii
lines
array (≤ 500)
da, sau all
Liniile de stornat: id (din Variante de stornare), mode, și qty sau price.
lines[].mode
qty / price
da
qty: stornează qty bucăți. price: scade prețul unitar cu price pe cantitatea rămasă.
all
bool
nu
true stornează tot ce a rămas. După o stornare parțială, este singurul mod de a storna restul.
date
AAAA-LL-ZZ
nu
Data stornării; implicit azi, cel mai devreme data facturii.
serie_id
int
nu
Seria facturii storno; implicit seria stornărilor din Preferințe, altfel seria facturii.
reason
string
nu
retur, eroare, anulare_comanda, serviciu_neprestat, altul. Apare în observații și în e-Factura.
reason_note
string ≤ 500
la altul
Motivul, în text liber.
Răspuns: statusMessageStornarea partiala a fost emisa, data: action (partial_storno), invoice (factura actualizată), storno_invoice (factura storno, cu totaluri negative).
Erori
404 Factura nu a fost gasita.
422 Eroare validare stornare: <motiv> + errors pe câmpuri, de ex. Alege cel putin o linie si cantitatea sau valoarea de stornat., Linia nu mai exista pe factura., Cantitatea de pe linia ... depaseste ce a ramas (N)., Stornarea nu poate fi datata inaintea facturii pe care o storneaza (...).
409 — factura nu poate fi stornată parțial (motivul în statusMessage).
Stornare totală: emite factura storno pentru întreaga factură (fără lines / all). Se folosește pentru facturile trimise în SPV; o factură netrimisă se poate și anula (Anulează).
Body (toate opționale): date, serie_id, reason, reason_note (ca la stornarea parțială) și:
Câmp
Tip
Obligatoriu
Detalii
payments_action
credit / refund
dacă factura are încasări
credit: suma încasată trece în creditul clientului (se poate folosi la încasări cu type: credit). refund: suma se restituie clientului.
Răspuns: statusMessageFactura a fost stornata, data: action (storno), invoice, storno_invoice (status storno).
Erori
409 INVOICE_STORNO_HAS_PAYMENTS — factura are încasări și lipsește payments_action.
409 INVOICE_STORNO_NOT_ALLOWED / 409 cu motivul (ex. Factura are stornari partiale; restul se storneaza cu "all"., Factura a fost deja stornata.).
{
"status":409,
"statusMessage":"Factura are incasari. Alege ce se intampla cu banii incasati: credit client sau restituire.",
"errors": {
"code":"INVOICE_STORNO_HAS_PAYMENTS"
},
"data":null
}
{
"status":409,
"statusMessage":"Factura are incasari si nu poate fi anulata.",
"errors": {
"code":"INVOICE_CANCEL_HAS_PAYMENTS"
},
"data":null
}
Proforme
Facturi proforme: emitere, modificare, PDF, email și încasări (avansuri). Proforma se convertește în factură fiscală din WeBill; o proformă convertită nu mai acceptă modificări sau încasări. Proformele nu au anulare / stornare prin endpoint dedicat: anularea se face cu PATCH status: anulata.
Emite o proformă în seria aleasă (proforma_series din Nomenclatoare > Facturi). Câmpurile sunt cele ale facturii (fără order_id, curier, awb, generate_payment_link); document_type este întotdeauna 100.
Body
Câmp
Tip
Obligatoriu
Detalii
client_id
int
unul din client_id / client
Client existent al companiei (vezi Clienți).
client
obiect
unul din client_id / client
Client inline, cu aceleași câmpuri și reguli ca POST /clients (persoana juridică existentă cu același CUI este refolosită). Eroare → 422 Client invalid: ....
items
array
da
Cel puțin o linie (vezi mai jos).
serie_id
int
nu
Seria (Nomenclatoare > Facturi: invoice_series / proforma_series). Implicit seria marcată „Implicită” în Setări, altfel prima serie activă. Serie străină / inactivă → 422 INVALID_INVOICE_SERIE / INVALID_PROFORMA_SERIE.
delegate_id
int
nu
Delegatul (delegates). Implicit delegatul marcat „Implicit” în Setări, altfel primul delegat activ. → 422 INVALID_DELEGATE.
bank_accounts
int[]
nu
Conturile bancare tipărite pe document (banks). Implicit contul marcat „Implicit” în moneda documentului, altfel toate conturile active. → 422 INVALID_BANK_ACCOUNT.
issue_date
AAAA-LL-ZZ
nu
Data documentului; implicit azi. O factură nu poate fi datată înaintea ultimei facturi emise din aceeași serie (422).
due_days / due_date
int ≥ 0 sau dată
nu
Termenul de plată: numărul de zile (implicit 15) sau direct data scadenței, AAAA-LL-ZZ (sau ZZ.LL.AAAA), care nu poate fi înaintea datei documentului.
Implicit cursul BNR al datei documentului (1 pentru RON).
language
ro / en
nu
Limba documentului (PDF, email). Implicit ro.
comments
string
nu
Observații tipărite pe document.
Linii (items[])
Câmp
Tip
Obligatoriu
Detalii
description
string ≤ 255
da*
Denumirea produsului / serviciului.
details
string
nu
Text suplimentar pe linie.
um
string ≤ 50
da*
Unitatea de măsură: denumirea folosită de companie (ex. BUC, ORA) sau codul UN/ECE (H87, HUR).
qty
număr > 0
da
Cantitatea. Zecimale cu punct sau virgulă.
unit_price
număr ≥ 0
da*
Prețul unitar, în moneda liniei.
tax_included
bool
nu
Implicit true: prețul include TVA. false = preț fără TVA.
tax_value
număr 0–100
nu
Cota TVA în procente (ex. 21, 11, 0). Se potrivește cu o cotă activă a companiei cu exact acest procent; vezi taxes din Nomenclatoare > Facturi.
tax_id
int
nu
ID-ul cotei TVA din Nomenclatoare > Facturi. Are prioritate față de tax_value. Cotă inexistentă / inactivă → 422 INVALID_TAX.
discount
număr
nu
Reducere pe linie, ca valoare (în moneda liniei).
discount_type
string
nu
Doar valoric (implicit). Reducerea procentuală nu este disponibilă prin API.
currency
string (3)
nu
Moneda liniei; implicit moneda documentului. Conversia se face la cursul BNR al datei documentului.
product_id
int
nu
Produs din Nomenclatoare > Produse și servicii: câmpurile netrimise (description, details, um, unit_price, currency, tax_id, tax_included, cpv_code) se completează din produs. Produs inexistent → 422 INVALID_PRODUCT.
cpv_code
string
nu
Cod CPV (achiziții publice).
* nu sunt obligatorii când linia are product_id. O cantitate, un preț sau o reducere negativă marchează linia ca linie de stornare.
totals.items[]: liniile — id (folosit la stornare), denumire, nota, um, um_code, qty, cota_tva, pret_cu_tva, pret_fara_tva, valoare (fără TVA), tva, discount, discount_net, discount_tva, cpv_code.
totals.subtotal: pe cota TVA ("21": {"total_fara_tva", "total_tva"}); totals.total: valoare (fără TVA) și tva sunt înainte de reduceri, total (de plată) este după reduceri: total = valoare + tva - discount.total; totals.discount: reducerile; totals.stats: incasat, rest (rest de plată).
items_count, payment_link_requested, payment_link (linkul de plată Netopia activ sau null).
Erori
400 Payload JSON invalid: ... — corpul nu este JSON valid.
422 Date invalide la linii, cu erorile în errors pe cheia liniei (ex. {"items.0.description": ["Campul description este obligatoriu."]}); la fel pentru items: [].
422 Data din campul issue_date nu este valida (format AAAA-LL-ZZ). (sau date, după câmpul trimis) — o dată pe care serverul nu o poate citi nu mai devine data de azi.
422 pentru un due_date care nu e nici număr de zile, nici dată, sau care e înaintea datei documentului.
422 Clientul nu a fost identificat — lipsește client_id / client sau clientul nu este al companiei.
422 Date invalide la document + errors pe câmpuri (ex. errors.items).
422 cu errors.code: INVALID_INVOICE_SERIE, INVALID_PROFORMA_SERIE, INVALID_DELEGATE, INVALID_BANK_ACCOUNT, INVALID_TAX, INVALID_TAX_CLIENT (cotă de taxare inversă / intracomunitară nepotrivită clientului), INVALID_PRODUCT, INVALID_CLIENT, INVALID_ITEMS.
422 Data facturii (...) nu poate fi inaintea ultimei facturi emise din seria ... (errors.issue_date).
Modifică proforma; doar câmpurile trimise se schimbă. Ca la facturi, fără client_id (sau client) proforma își păstrează clientul, iar items înlocuiește toate liniile. status: emisa sau anulata.
Răspuns: statusMessageDocument actualizat.
Erori: 404 Documentul nu a fost gasit; 422 Clientul nu a fost identificat; celelalte de la Creează.
totals.items[]: liniile — id (folosit la stornare), denumire, nota, um, um_code, qty, cota_tva, pret_cu_tva, pret_fara_tva, valoare (fără TVA), tva, discount, discount_net, discount_tva, cpv_code.
totals.subtotal: pe cota TVA ("21": {"total_fara_tva", "total_tva"}); totals.total: valoare (fără TVA) și tva sunt înainte de reduceri, total (de plată) este după reduceri: total = valoare + tva - discount.total; totals.discount: reducerile; totals.stats: incasat, rest (rest de plată).
items_count, payment_link_requested, payment_link (linkul de plată Netopia activ sau null).
Proforma cu seria și numărul date, confirmată de codul fiscal al emitentului și, opțional, de dată și de client, în compania tokenului: același răspuns ca la Detaliu (GET /proforme/{id}). Util când sistemul tău a păstrat numărul tipărit, nu ID-ul WeBill.
Exact sau nimic. Căutarea nu ghicește: dacă ceva nu corespunde întocmai sau mai multe documente se potrivesc, primești o eroare, niciodată documentul „cel mai probabil”. O automatizare care acționează pe răspuns (încasare, stornare) nu poate atinge astfel o factură greșită.
Query (serie, number și company_vat obligatorii; restul opționale, fiecare trimis se compară)
Parametru
Detalii
serie
Seria, ex. WB.
number
Numărul: doar cifre (12, 0012) sau numărul tipărit cu seria în față (WB0012). Orice altceva (12a, WB-12, altă serie) → 400.
company_vat
CUI-ul emitentului, cum apare pe document (pentru un punct de lucru, al companiei-mamă). Se acceptă cu sau fără RO, cu spații.
date
Opțional. Data documentului, AAAA-LL-ZZ. Deosebește documentele vechi cu aceeași serie și același număr.
client_vat
Opțional. CUI-ul / CNP-ul clientului cum a fost tipărit la emitere (o schimbare ulterioară a clientului nu contează). Cu sau fără RO; un cod străin își păstrează prefixul țării (DE123...). La persoanele fizice fără CNP (0000000000000) codul nu identifică pe nimeni: lasă-l gol sau folosește date.
client_name
Opțional. Numele clientului de pe document, comparat fără majuscule, diacritice și spații în plus.
Răspuns
errors.code
Când
200
—
Exact un document se potrivește.
400
—
Lipsește un parametru obligatoriu, number nu este exact numărul documentului sau date nu e o dată AAAA-LL-ZZ.
404
DOCUMENT_NOT_FOUND
Nu există niciun document cu seria și numărul acestea (Proforma nu a fost gasita).
404
COMPANY_MISMATCH
Documentul există, dar emitentul are alt cod fiscal (ex. tokenul altei companii).
404
DATE_MISMATCH
Documentul există, dar are altă dată.
404
CLIENT_MISMATCH
Documentul există, dar clientul are alt cod fiscal sau alt nume.
409
AMBIGUOUS_DOCUMENT
Mai multe documente se potrivesc (aceeași serie și același număr, fără date sau client care să le deosebească) (ex. o factură veche și stornarea ei cu același număr). errors.candidates[] are id, date, status: alege documentul și cere-l cu GET /proforme/{id}.
Facturile fiscale nu sunt căutate aici (au invoices/find). Ciornele nu au număr, deci nu se găsesc.
Trimite documentul pe email, cu PDF-ul atașat. Trimiterea se face asincron (în coadă), deci răspunsul confirmă programarea, nu livrarea. Fiecare trimitere apare în istoricul de emailuri al documentului din WeBill (sursa API), la facturi și la proforme.
Body (toate opționale)
Câmp
Tip
Obligatoriu
Detalii
to
string
nu
Destinatarul. Implicit emailul clientului (prima adresă validă; celelalte trec în CC).
Înregistrează o încasare pe document. Starea de încasare a documentului (status_incasare) se actualizează: pending → partial → incasata. O sumă mai mare decât restul este acceptată; diferența intră în creditul clientului.
Body
Câmp
Tip
Obligatoriu
Detalii
type
string
da
Tipul încasării (tabelul de mai jos).
amount
număr > 0
da
Suma, în moneda documentului.
date
AAAA-LL-ZZ
da
Data încasării.
identifier
string ≤ 255
la op / bf / card / ramburs
Referința plății (nr. OP, ID tranzacție, AWB, nr. bon).
serie_id
int
la cash
Seria cu chitanțier (invoice_series[].id din Nomenclatoare > Facturi). Chitanța se numerotează automat.
notes
string
nu
Observații.
type
Ce este
Câmpuri cerute în plus
op
Ordin de plată / transfer bancar
identifier (ex. numărul OP)
bf
Bon fiscal
identifier (numărul bonului)
card
Plată cu cardul / POS / online
identifier (ex. ID-ul tranzacției)
ramburs
Ramburs prin curier
identifier (ex. AWB)
cash
Numerar, cu chitanță numerotată automat
serie_id = ID-ul seriei de facturi care are chitanțierul (invoice_series[].id, câmpul receipt_serie)
avans
Avans
—
credit
Din creditul clientului (sume plătite în plus, stornări)
— ; suma nu poate depăși creditul disponibil
Răspuns: statusMessageIncasare creata.
data (încasare): id, invoice_id (ID-ul documentului), type, identifier, serie_id, serie, number, receipt_number (ex. CH.1, doar la numerar), date, amount, notes, created_at, updated_at.
Erori
404 Documentul nu a fost gasit.
422 Date invalide la incasare + errors pe câmpuri (ex. identifier, serie_id).
Modifică doar câmpurile trimise: amount, date, identifier, notes. Tipul și seria încasării nu se pot schimba (422 Tipul incasarii nu poate fi modificat.): pentru alt tip, șterge încasarea și creeaz-o din nou.
Răspuns: statusMessageIncasare actualizata, data = încasarea.
Erori: 404 Incasarea nu a fost gasita; 422 Date invalide la incasare; 422 Eroare validare incasare: ... (sumă ≤ 0, încasare creată automat din credit / stornare, factură stornată).
PDF-ul chitanței (încasări cash) sau al dovezii de încasare. Răspunsul este fișierul (Content-Type: application/pdf, Content-Disposition: attachment; filename="Chitanta-CH.1.pdf").
Erori (JSON): 404 Documentul nu a fost gasit / Incasarea nu a fost gasita.