Referință erori
Referință erori
Această pagină este indexul canonic al fiecărei erori pe care platforma e-bon o poate expune unui integrator. Folosește-o ca singura sursă de adevăr când implementezi tratarea erorilor în POS-ul tău, în back-office sau în propriile unelte construite peste @e-bon/sdk.
Există două familii distincte de erori, care trăiesc la straturi diferite:
- Erorile HTTP sunt eșecuri la nivelul protocolului, returnate direct de API-ul REST e-bon. Le vezi chiar pe răspuns — un status non-2xx cu un corp JSON — pentru eșecuri de transport, autentificare, autorizare, validare și limitare de rată. Nu implică deloc imprimanta.
- Codurile FiscalError sunt eșecuri pe partea de aparat. Cererea HTTP care a trimis comanda poate să fi reușit cu un
202 Accepted; eșecul s-a întâmplat ulterior, pe AMEF sau în driver-ul fiscal. Vezi codurile fiscale în interiorul rezultatului comenzii returnat deGET /api/v1/commands/{id}(în câmpulerror), în payload-urile evenimentelorcommand.failedși — când folosești@e-bon/sdk— sub forma unei excepții tipateFiscalError.
Ambele familii respectă aceeași regulă: ramifică pe șirul code, nu pe mesajul lizibil. Mesajele se pot reformula; codurile sunt stabile.
Plicul de eroare
Fiecare răspuns HTTP de eroare — fie că vine din validare, autentificare, logica de business sau un crash netratat — respectă același plic JSON încapsulat:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Request validation failed",
"details": [
{ "path": "items[0].vatRate", "message": "vatRate must be one of: 0, 9, 11, 21" }
]
}
}
error.code— un identificator stabil de tip text din catalogul de mai jos. Mereu prezent.error.message— un mesaj lizibil în limba engleză. Util pentru loguri; nu îl analiza programatic.error.details— opțional. Apare laVALIDATION_ERROR(erori per câmp de la Zod, sub formă de{ path, message }[]) și la câteva alte coduri care au nevoie de payload structurat.
Un răspuns tipic 400 VALIDATION_ERROR complet:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Request validation failed",
"details": [
{ "path": "items.0.vatRate", "message": "vatRate must be one of: 0, 9, 11, 21" },
{ "path": "items.0.unitPrice", "message": "Number must be greater than 0" }
]
}
}
429 RATE_LIMIT_EXCEEDED returnat de limitatorul global este emis în prezent ca obiect plat — { "code": "RATE_LIMIT_EXCEEDED", "message": "...", "status": 429 } — în loc de plicul standard. Verifică pe câmpul code; tratează ambele forme ca echivalente până când API-ul este normalizat.Coduri de eroare HTTP
Douăsprezece coduri stabile. Fiecare răspuns non-2xx de la https://api.e-bon.ro poartă unul dintre ele în error.code (sau în code pentru excepția 429 de mai sus).
UNAUTHORIZED
HTTP 401. Cererea a ajuns la API, dar nu s-a putut rezolva nicio credențială validă — antet x-api-key / Authorization lipsă, cheie malformată, cheie necunoscută sau cheia a fost revocată ori marcată inactivă.
{
"error": {
"code": "UNAUTHORIZED",
"message": "Missing or invalid API key"
}
}
Ce ai de făcut
- Confirmă că cererea poartă fie
x-api-key: ebon_live_..., fieAuthorization: Bearer ebon_live_.... - Verifică în Portal că cheia nu a fost revocată sau dezactivată (Setări → Chei API).
- Asigură-te că lovești mediul corect — cheile de producție nu funcționează pe staging și invers.
- Rotește cheia dacă suspectezi o scurgere și actualizează depozitul de secrete.
TOKEN_EXPIRED
HTTP 401. Token-ul JWT de acces prezentat unui endpoint de tip Portal a expirat. Se aplică doar la autentificarea JWT, nu la cheile API (care nu expiră).
{
"error": {
"code": "TOKEN_EXPIRED",
"message": "Access token expired"
}
}
Ce ai de făcut
- Apelează
POST /api/v1/auth/refreshcu token-ul de refresh pentru a obține un token de acces nou. - Reia cererea originală cu antetul
Authorization: Bearer <accessToken>actualizat. - Dacă și endpoint-ul de refresh returnează 401, forțează utilizatorul să se autentifice din nou.
- Pentru integrările neinteractive, preferă o cheie API — aceasta nu expiră.
FORBIDDEN
HTTP 403. Autentificarea a reușit, dar entitatea autentificată nu are permisiunea sau rolul necesar pentru acest endpoint sau această resursă.
{
"error": {
"code": "FORBIDDEN",
"message": "Insufficient permissions for this operation"
}
}
Ce ai de făcut
- Verifică permisiunile configurate ale cheii API față de referința Autentificare.
- La autentificare JWT, confirmă că rolul utilizatorului în organizație (Owner / Admin / Member) acoperă acțiunea.
- Reemite cheia API cu permisiunile corecte dacă a fost creată cu un set prea restrâns.
- Asigură-te că resursa (aparat, bon, comandă) chiar aparține organizației pe care credențiala o acoperă.
VALIDATION_ERROR
HTTP 400. Corpul cererii sau parametrii din URL au eșuat la validarea schemei Zod. details este o listă de intrări { path, message }, una per câmp eșuat.
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Request validation failed",
"details": [
{ "path": "items.0.vatRate", "message": "vatRate must be one of: 0, 9, 11, 21" }
]
}
}
Ce ai de făcut
- Iterează prin
error.detailsși prezintă fiecare perechepath/messageoperatorului sau dezvoltatorului. - Corectează câmpul greșit local; nu relua orbește — cererea va eșua la fel.
- Verifică pagina resursei relevante (Bonuri, Comenzi, Dispozitive) pentru forma exactă acceptată.
- Pentru eșecuri de validare ale
Idempotency-Key, regenerează o cheie care respectă[a-zA-Z0-9_-]{1,128}.
BAD_REQUEST
HTTP 400. Cererea este malformată într-un mod care nu este strict o încălcare de schemă — JSON invalid, Content-Type nesuportat, corp prea mare sau o precondiție de endpoint pe care schema nu o poate exprima.
{
"error": {
"code": "BAD_REQUEST",
"message": "Request body is not valid JSON"
}
}
Ce ai de făcut
- Confirmă că corpul este JSON valid în UTF-8 și că
Content-Type: application/jsoneste trimis la fiecarePOST/PATCH/PUT. - Verifică dimensiunea payload-ului față de limitele documentate per endpoint.
- Citește atent
error.message— de obicei numește precondiția specifică ce a eșuat. - Nu relua fără să schimbi cererea; acest cod nu este tranzitoriu.
NOT_FOUND
HTTP 404. Resursa adresată nu există pentru organizația credențialei. Fie ID-ul este greșit, fie resursa a fost ștearsă, fie aparține altei organizații decât cea pe care o acoperă credențiala.
{
"error": {
"code": "NOT_FOUND",
"message": "Device not found"
}
}
Ce ai de făcut
- Confirmă că ID-ul este bine format și se potrivește cu prefixul așteptat al resursei (
dev_,cmd_,rec_,rep_,key_). - Listează colecția părinte (
GET /api/v1/devices,GET /api/v1/commands) ca să verifici că resursa încă există. - Asigură-te că nu interoghezi cu o credențială delimitată la altă organizație.
- Dacă resursa a fost ștearsă, recreează-o sau elimină referința expirată din cache-ul tău local.
CONFLICT
HTTP 409. Operațiunea este incompatibilă cu starea curentă a resursei — de exemplu anularea unei comenzi deja completed sau failed, sau actualizarea unui webhook care a fost dezactivat.
{
"error": {
"code": "CONFLICT",
"message": "Command is already completed and cannot be cancelled"
}
}
Ce ai de făcut
- Reia resursa (
GET /api/v1/commands/{id},GET /api/v1/devices/{id}) și inspecteazăstatusînainte de a relua acțiunea. - Decide dacă conflictul este acceptabil (operațiunea s-a întâmplat deja) sau dacă trebuie să iei o altă acțiune.
- Nu relua orbește — vei primi același
409. Starea trebuie să se schimbe mai întâi. - Pentru operațiuni idempotente, preferă fluxul cu
Idempotency-Key, ca o întrerupere de rețea să nu apară caCONFLICT.
UNPROCESSABLE_ENTITY
HTTP 422. Cererea a fost validă sintactic și a trecut validarea de schemă, dar starea de business a sistemului o respinge — de exemplu încercarea de a tipări un storno mai mare decât bonul original.
{
"error": {
"code": "UNPROCESSABLE_ENTITY",
"message": "Refund amount exceeds the original receipt total"
}
}
Ce ai de făcut
- Citește
error.messagepentru regula de business specifică ce a eșuat. - Reinterogă resursele asociate (bonul original, starea curentă a aparatului) și ajustează cererea.
- Nu relua fără să schimbi payload-ul.
- Dacă regula nu se potrivește cu așteptările tale, verifică pagina de referință a resursei pentru ultimele constrângeri.
RATE_LIMIT_EXCEEDED
HTTP 429. Ai depășit o fereastră de limitare a ratei. Răspunsul include un antet Retry-After (secunde, întreg) care îți spune exact cât trebuie să aștepți. Atenție: acest cod ajunge în prezent ca obiect plat, nu sub formă de plic încapsulat.
HTTP/1.1 429 Too Many Requests
Retry-After: 47
RateLimit-Limit: 150
RateLimit-Remaining: 0
RateLimit-Reset: 47
Content-Type: application/json
{
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests, please try again later.",
"status": 429
}
Ce ai de făcut
- Așteaptă valoarea din
Retry-After(secunde) înainte de următoarea încercare — niciodată mai devreme. - Adaugă deasupra un backoff exponențial, plafonat la un maxim rezonabil, în caz că 429 se repetă.
- Distribuie traficul în rafale pe lățimea ferestrei de limitare în loc să-l tragi tot dintr-o dată.
- Dacă atingi des limitele, discută cu echipa e-bon sau grupează operațiunile în mai puține cereri; vezi Limite de rată.
TIER_LIMIT_EXCEEDED
HTTP 403. Planul de abonament al organizației nu permite această acțiune — de exemplu încercarea de a crea mai mult de două aparate pe planul Free, sau crearea unei chei API pe planul Free în general.
{
"error": {
"code": "TIER_LIMIT_EXCEEDED",
"message": "Free plan is limited to 2 devices"
}
}
Ce ai de făcut
- Verifică tabelul de restricții pe planuri pentru limitele aplicate planului tău.
- Fă upgrade planul organizației din pagina de facturare a Portalului ca să ridici limita.
- Șterge aparatele sau cheile nefolosite înainte să creezi altele noi, dacă nu vrei să faci upgrade.
- Acest cod este permanent pentru planul curent; nu relua fără să schimbi starea.
INTERNAL_ERROR
HTTP 500. O eroare netratată pe server. Cererea nu a produs rezultatul dorit, iar serverul a logat eșecul cu un ID de cerere pentru investigare.
{
"error": {
"code": "INTERNAL_ERROR",
"message": "An internal error occurred"
}
}
Ce ai de făcut
- Pentru operațiuni idempotente (și pentru toate
POST-urile care poartă unIdempotency-Key), reia o singură dată după un backoff scurt. - Capturează ID-ul cererii din propriile loguri (și din antetele răspunsului dacă e prezent), ca echipa de suport să poată corela.
- Nu presupune că operațiunea s-a întâmplat sau nu — reia resursa pentru a afla.
- Dacă eroarea persistă, deschide un tichet de suport cu ID-ul cererii, ID-ul comenzii și pașii de reproducere.
SERVICE_UNAVAILABLE
HTTP 503. Serverul refuză temporar cererile — de obicei un deploy în desfășurare, indisponibilitatea unei dependențe sau o fereastră de mentenanță forțată.
{
"error": {
"code": "SERVICE_UNAVAILABLE",
"message": "Service temporarily unavailable, please try again shortly"
}
}
Ce ai de făcut
- Reia cu backoff exponențial — pornește de la 1s și dublează până la un plafon rezonabil.
- Refolosește același
Idempotency-Key, ca duplicatele să fie absorbite de cache odată ce serviciul revine. - Verifică pagina de status e-bon sau canalul tău de suport înainte de a ridica o alertă.
- Nu transforma asta în alertă la prima apariție; indisponibilitatea tranzitorie este așteptată în timpul deploy-urilor.
Coduri de eroare fiscale / de aparat (FiscalError)
Douăzeci și cinci de coduri grupate în șase familii după prima cifră. Apar în interiorul rezultatelor de comandă (error.code la GET /api/v1/commands/{id}), în payload-urile evenimentelor command.failed și sub forma câmpului code de pe excepția tipată FiscalError aruncată de @e-bon/sdk.
Forma FiscalError din SDK:
class FiscalError extends Error {
code: ErrorCode // unul din codurile de mai jos
message: string
retryable: boolean // precalculat prin isRetryable(code)
commandId?: string
deviceId?: string
}
Doar cinci coduri sunt reluabile: E101 ConnectionTimeout, E102 ConnectionLost, E500 TimeoutCommand, E501 TimeoutResponse, E502 TimeoutConnection. Restul sunt netranzitorii și cer o acțiune — pe payload-ul cererii, pe imprimantă sau de la un tehnician de service.
E1xx Erori de conexiune
Eșecuri la deschiderea sau menținerea unei conexiuni la nivel de transport între aplicația mobilă E-BON și imprimanta AMEF. Verifică întotdeauna endpoint-ul de transport configurat (host și port TCP, împerechere Bluetooth, cablu USB, port serial) înainte de orice altceva.
E100 ConnectionRefused
- Reluabil: nu.
- Semnificație: imprimanta a refuzat activ conexiunea TCP / Bluetooth / USB / serială.
- Recuperare: verifică transportul — host-ul și portul TCP, împerecherea Bluetooth, cablul USB sau portul serial — și confirmă că imprimanta este pornită și nu este deja folosită de un alt controller.
E101 ConnectionTimeout
- Reluabil: da.
- Semnificație: tentativa de conectare a expirat înainte ca imprimanta să răspundă.
- Recuperare: reia cu backoff exponențial (flag-ul
retryabledin SDK este dejatruepentru acest cod); dacă continuă să eșueze, verifică transportul — accesibilitatea host-ului TCP, împerecherea Bluetooth, cablul USB, portul serial — pentru o legătură picată.
E102 ConnectionLost
- Reluabil: da.
- Semnificație: o conexiune deja stabilită s-a întrerupt în timpul operațiunii.
- Recuperare: reia cu același
Idempotency-Key; dacă pierderea se repetă, verifică transportul (TCP, Bluetooth, USB, port serial) pentru o legătură fizică instabilă.
E103 ConnectionNotFound
- Reluabil: nu.
- Semnificație: endpoint-ul de transport configurat nu poate fi atins deloc.
- Recuperare: verifică configurația de transport pe aparat — host-ul și portul TCP, împerecherea Bluetooth, calea dispozitivului USB, numele portului serial — și confirmă că imprimanta este pe aceeași rețea sau magistrală.
E2xx Erori de protocol
Eșecuri la nivelul protocolului — imprimanta a răspuns, dar octeții nu se aliniază cu protocolul configurat. Verifică dacă protocolul selectat pentru AMEF în Portal corespunde firmware-ului și modelului real al imprimantei.
E200 ProtocolMismatch
- Reluabil: nu.
- Semnificație: imprimanta a răspuns, dar protocolul ei nu corespunde celui configurat pentru aparat.
- Recuperare: verifică potrivirea de protocol/firmware între AMEF-ul configurat și imprimanta reală; reconfigurează aparatul cu protocolul corect în Portal.
E201 ProtocolUnsupported
- Reluabil: nu.
- Semnificație: comanda nu este suportată de protocolul acestei imprimante.
- Recuperare: verifică potrivirea de protocol/firmware între AMEF-ul configurat și imprimantă; alege o variantă de comandă pe care protocolul imprimantei o suportă sau actualizează firmware-ul imprimantei.
E202 ProtocolChecksumError
- Reluabil: nu.
- Semnificație: un cadru a fost primit, dar a eșuat la validarea sumei de control.
- Recuperare: verifică potrivirea de protocol/firmware între AMEF-ul configurat și imprimantă; asigură-te că niciun alt program nu vorbește cu imprimanta pe același transport în același timp.
E203 ProtocolFramingError
- Reluabil: nu.
- Semnificație: un cadru malformat a ajuns la nivelul protocolului.
- Recuperare: verifică potrivirea de protocol/firmware între AMEF-ul configurat și imprimantă; verifică dacă cablajul sau legătura radio este suficient de stabilă pentru a livra cadre complete.
E3xx Erori fiscale
Eșecuri venite din logica fiscală a imprimantei — hârtie, limită zilnică, bonuri deschise, memorie fiscală. Acestea cer un operator pe loc sau o intervenție de service, nu încă un tur prin rețea.
E300 FiscalMemoryFull
- Reluabil: nu.
- Semnificație: memoria fiscală (Memorie Fiscală) a imprimantei este plină.
- Recuperare: contactează service-ul pentru memorie fiscală plină — necesită intervenție de service autorizat; aparatul nu mai poate tipări bonuri fiscale până când nu este înlocuită.
E301 FiscalReceiptOpen
- Reluabil: nu.
- Semnificație: există deja un bon deschis pe imprimantă.
- Recuperare: roagă operatorul să închidă bonul deschis (finalizare sau anulare) pe imprimantă, apoi retrimite comanda.
E302 FiscalNoReceiptOpen
- Reluabil: nu.
- Semnificație: comanda necesită un bon deschis, dar niciunul nu este deschis.
- Recuperare: deschide întâi un bon (SDK-ul / API-ul expune comanda dedicată), apoi reia comanda de linie.
E303 FiscalDailyLimitReached
- Reluabil: nu.
- Semnificație: imprimanta a atins limita fiscală zilnică și nu mai poate tipări bonuri astăzi.
- Recuperare: roagă operatorul să ruleze un raport Z (închidere de zi) pe imprimantă, apoi reia — contoarele zilnice se resetează.
E304 FiscalHardwareError
- Reluabil: nu.
- Semnificație: o eroare hardware pe imprimantă — hârtie, cap, capac, sertar sau similar.
- Recuperare: roagă operatorul să schimbe rola de hârtie, să închidă capacul sau să elimine blocajul; dacă defectul persistă, contactează service-ul.
E4xx Erori de validare
Driver-ul a respins payload-ul comenzii înainte de a trimite ceva spre imprimantă. Sunt deterministe — același payload va eșua la fel până când îl schimbi.
E400 ValidationInvalidPayload
- Reluabil: nu.
- Semnificație: payload-ul comenzii a fost respins de driver.
- Recuperare: corectează payload-ul cererii — recitește referința comenzii și ajustează corpul, apoi retrimite.
E401 ValidationMissingField
- Reluabil: nu.
- Semnificație: un câmp obligatoriu din payload lipsește.
- Recuperare: corectează payload-ul cererii adăugând câmpul obligatoriu; verifică referința comenzii pentru lista completă a câmpurilor obligatorii.
E402 ValidationInvalidAmount
- Reluabil: nu.
- Semnificație: o valoare monetară este în afara intervalului legal.
- Recuperare: corectează payload-ul cererii — limitează sumele la intervalul documentat și verifică unitățile (lei, bani, întreg vs. zecimal).
E403 ValidationInvalidVatRate
- Reluabil: nu.
- Semnificație: cota de TVA nu este una dintre cele patru cote legale din România (
0,9,11,21). - Recuperare: corectează payload-ul cererii — alege una dintre
0,9,11,21; respinge orice altă valoare la nivelul POS-ului tău înainte de trimitere.
E5xx Erori de timeout
Comanda a fost trimisă, dar nu s-a încheiat în fereastra așteptată. Toate codurile E5xx sunt reluabile.
E500 TimeoutCommand
- Reluabil: da.
- Semnificație: comanda nu s-a încheiat în limita de timp pentru execuție.
- Recuperare: reia cu backoff exponențial; respectă același
Idempotency-Key, ca o primă încercare reușită memorată pe server să nu fie reexecutată.
E501 TimeoutResponse
- Reluabil: da.
- Semnificație: imprimanta a început comanda, dar nu a returnat un răspuns la timp.
- Recuperare: reia cu backoff exponențial; respectă același
Idempotency-Keyși verifică hârtia tipărită ca să confirmi dacă comanda chiar s-a executat.
E502 TimeoutConnection
- Reluabil: da.
- Semnificație: s-a produs un timeout la nivelul conexiunii cu imprimanta.
- Recuperare: reia cu backoff exponențial; respectă același
Idempotency-Keyși, dacă timeout-ul se repetă, verifică și transportul (TCP, Bluetooth, USB, serial).
E9xx Erori necunoscute
Eșecuri neclasificate sau neașteptate la nivelul driver-ului. Scapă din categoriile de mai sus și au nevoie de investigare.
E900 Unknown
- Reluabil: nu.
- Semnificație: o eroare driver neclasificată.
- Recuperare: deschide un tichet de suport cu ID-ul cererii și ID-ul comenzii eșuate, ca echipa e-bon să poată investiga.
E901 InternalError
- Reluabil: nu.
- Semnificație: o eroare internă neașteptată în stratul de driver.
- Recuperare: deschide un tichet de suport cu ID-ul cererii și ID-ul comenzii eșuate; capturează modelul aparatului și versiunea de firmware dacă le ai.
E902 UnexpectedResponse
- Reluabil: nu.
- Semnificație: imprimanta a returnat un răspuns pe care driver-ul nu l-a putut interpreta.
- Recuperare: deschide un tichet de suport cu ID-ul cererii și ID-ul comenzii eșuate; include modelul AMEF, ca driver-ul să fie învățat noua formă de răspuns.
Model universal pentru SDK
Fiecare loc de catch din codul tău poate folosi aceeași formă: prinde ambele familii de erori, reia doar când err.retryable este true (pentru eșecurile fiscale) sau când Retry-After este setat (pentru limitele HTTP), refolosește același Idempotency-Key la reîncercare.
import { EBonApiError, FiscalError, isRetryable } from '@e-bon/sdk';
try {
await client.commands.send(body);
} catch (err) {
if (err instanceof FiscalError && err.retryable) {
// E101, E102, E500, E501, E502 — reia cu același Idempotency-Key.
return await client.commands.send(body);
}
if (err instanceof EBonApiError && err.status === 429 && err.retryAfter) {
await sleep(err.retryAfter * 1000);
return await client.commands.send(body);
}
throw err;
}
isRetryable(code) este re-exportat din @e-bon/sdk dacă primești un cod printr-un canal exterior (un webhook, o coloană de bază de date) și ai nevoie de același răspuns fără să construiești un FiscalError.Vezi și
- Prezentare generală API — tabelele de sinteză pentru ambele familii de erori, plus limite de rată, idempotență și restricții pe planuri.
- Erori SDK — formele claselor
FiscalErrorșiEBonApiError, re-exporturile și modelul recomandat de reîncercare în detaliu. - Depanare — diagnostic ghidat pe simptome pentru cele mai comune probleme de integrare.
Colecție Postman
Importă colecția oficială Postman pentru e-bon — peste 77 de cereri preconfigurate, organizate în 12 dosare, care acoperă fiecare endpoint REST public al API-ului e-bon.
API Organizații și Locații
Endpoint-uri REST pentru gestionarea profilului organizației (nume, adresă de facturare), a locațiilor sale și a listei de abonați la notificări.