Prezentare generală API
Prezentare generală API
API-ul e-bon este un API REST bazat pe JSON peste HTTPS, dedicat sistemelor POS și integrărilor de back-office care trebuie să trimită bonuri fiscale, să administreze aparate AMEF și să citească rapoarte fiscale fără să implementeze ele însele protocolul nativ al fiecărei case de marcat. Este același API folosit intern de Portalul e-bon și de aplicația mobilă E-BON.
Arhitectură pe scurt
API-ul este orientat pe coadă de comenzi. Un POS emite o comandă fiscală (de exemplu tipărește acest bon) prin REST; serverul o pune în coadă și o trimite printr-un WebSocket către aplicația mobilă E-BON aflată lângă imprimanta fiscală; aplicația traduce comanda în protocolul nativ al imprimantei; rezultatul se întoarce pe același traseu și apoi este disponibil fie prin polling pe comandă, fie prin ascultarea pe WebSocket-ul de evenimente.
POS ──HTTPS──▶ api.e-bon.ro ──WSS──▶ aplicația mobilă E-BON ──TCP/BT/USB──▶ imprimantă AMEF
│
POS ◀────── polling / WSS evenimente ────── server e-bon ◀────── rezultat ──────────────┘
Consecința practică: majoritatea operațiunilor fiscale sunt asincrone. POST /api/v1/commands returnează imediat cu status: "pending", iar tu fie faci polling pe GET /api/v1/commands/{id}, fie te abonezi la evenimentele command.completed / command.failed.
URL de bază
| Mediu | URL de bază |
|---|---|
| Producție | https://api.e-bon.ro |
| Staging | https://api-staging.e-bon.ro |
Toate exemplele din documentație folosesc URL-ul de producție.
Versionare
API-ul se află în prezent la versiunea v1. Fiecare endpoint este prefixat cu /api/v1/:
GET /api/v1/devices HTTP/1.1
Host: api.e-bon.ro
Authorization: Bearer ebon_live_<orgId>_<32-hex>
Accept: application/json
Nu există negociere de versiuni minore — versiunea face parte din cale. Modificările cu impact se livrează sub un prefix nou (/api/v2/...); modificările aditive, compatibile retroactiv, se livrează direct sub /api/v1/.
Tipul de conținut
- Corpul cererilor:
application/json(UTF-8). TrimiteContent-Type: application/jsonla fiecarePOST/PATCH/PUT. - Răspunsuri:
application/json(UTF-8) pentru tot, cu excepția endpoint-ului de descărcare XML pentru JE, care returneazăapplication/xmlca atașament. - Toate timestamp-urile din corpul cererilor și răspunsurilor sunt șiruri ISO 8601 (de exemplu
"2026-04-09T08:10:00.000Z").
Format de eroare
Fiecare răspuns de eroare — fie că vine din validare, autentificare, logica de business sau un crash netratat — respectă aceeași formă:
{
"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 pe erorile de validare (Zod, eroare per câmp) și pe câteva alte erori care au nevoie de payload structurat. Forma depinde de codul erorii.
429 RATE_LIMIT_EXCEEDED returnat de limitatorul global este emis în prezent ca obiect plat ({ "code": "RATE_LIMIT_EXCEEDED", "message": "...", "status": 429 }), nu în formatul standard { "error": { ... } }. Tratează ambele forme ca echivalente până când API-ul este normalizat; verifică pe câmpul code, nu pe învelișul exterior.Catalogul codurilor de eroare HTTP
Acestea sunt codurile returnate în error.code de API-ul HTTP e-bon. Sunt codurile la nivelul protocolului — distincte de enumerarea ErrorCode a driver-ului fiscal (E100–E901), returnată în interiorul rezultatelor de comandă și al excepțiilor SDK, documentată în secțiunea următoare.
| Cod | HTTP | Când îl primești |
|---|---|---|
UNAUTHORIZED | 401 | Cheie API sau JWT lipsă ori invalidă, sau cheia este inactivă. |
TOKEN_EXPIRED | 401 | Token-ul JWT de acces a expirat — reîmprospătează-l. |
FORBIDDEN | 403 | Autentificat, dar permisiunile cheii nu acoperă acest endpoint. |
VALIDATION_ERROR | 400 | Corpul sau parametrii cererii au eșuat la validarea Zod. details enumeră { path, message } per câmp. |
BAD_REQUEST | 400 | Cerere incorectă, dar nu strict o încălcare a schemei. |
NOT_FOUND | 404 | Resursa adresată (dispozitiv, comandă, bon, raport, cheie) nu există pentru organizația ta. |
CONFLICT | 409 | Operațiunea intră în conflict cu starea curentă (de exemplu anularea unei comenzi deja completed). |
UNPROCESSABLE_ENTITY | 422 | Cererea a fost înțeleasă, dar nu poate fi procesată în starea de business curentă. |
RATE_LIMIT_EXCEEDED | 429 | Ai depășit fereastra de limitare. Vezi Limite de rată. |
TIER_LIMIT_EXCEEDED | 403 | Planul organizației nu permite această acțiune (de exemplu crearea unei chei API pe planul Free). |
INTERNAL_ERROR | 500 | Eroare de server netratată. Include un ID de cerere în loguri; operațiunile idempotente pot fi reluate cu backoff. |
SERVICE_UNAVAILABLE | 503 | Serverul refuză temporar cererile (deploy, indisponibilitate dependențe). Reia cu backoff exponențial. |
Coduri de eroare fiscale / pe aparat (FiscalError)
Când o comandă fiscală eșuează pe imprimantă, eșecul apare în câmpul error al comenzii la GET /api/v1/commands/{id} și — dacă folosești SDK-ul oficial @e-bon/sdk — sub forma unei excepții FiscalError cu această structură:
class FiscalError extends Error {
code: ErrorCode // unul dintre codurile de mai jos
message: string
retryable: boolean // true dacă este sigur să reiei aceeași comandă
commandId?: string
deviceId?: string
}
Enumerarea completă ErrorCode din @e-bon/types, cu marcarea celor reluabile derivată din RETRYABLE_ERROR_CODES:
| Cod | Nume | Reluabil | Semnificație |
|---|---|---|---|
E100 | ConnectionRefused | nu | Imprimanta a refuzat conexiunea TCP / Bluetooth / USB / serială. |
E101 | ConnectionTimeout | da | Tentativa de conectare a expirat înainte ca imprimanta să răspundă. |
E102 | ConnectionLost | da | Conexiunea existentă s-a întrerupt în timpul operațiunii. |
E103 | ConnectionNotFound | nu | Endpoint-ul de transport configurat nu poate fi atins deloc. |
E200 | ProtocolMismatch | nu | Imprimanta a răspuns, dar protocolul ei nu corespunde celui configurat. |
E201 | ProtocolUnsupported | nu | Comandă nesuportată de protocolul acestei imprimante. |
E202 | ProtocolChecksumError | nu | Cadru primit, dar a eșuat la validarea sumei de control. |
E203 | ProtocolFramingError | nu | Cadru malformat la nivelul protocolului. |
E300 | FiscalMemoryFull | nu | Memoria fiscală (Memorie Fiscală) a imprimantei este plină — necesită service. |
E301 | FiscalReceiptOpen | nu | Există deja un bon deschis pe imprimantă; închide-l înainte de a relua. |
E302 | FiscalNoReceiptOpen | nu | Comanda necesită un bon deschis, dar niciunul nu este deschis. |
E303 | FiscalDailyLimitReached | nu | Imprimanta a atins limita fiscală zilnică; închide ziua cu un raport Z. |
E304 | FiscalHardwareError | nu | Eroare hardware pe imprimantă (hârtie, cap, capac, sertar etc.). |
E400 | ValidationInvalidPayload | nu | Payload-ul comenzii respins de driver. |
E401 | ValidationMissingField | nu | Un câmp obligatoriu din payload lipsește. |
E402 | ValidationInvalidAmount | nu | O valoare monetară este în afara intervalului legal. |
E403 | ValidationInvalidVatRate | nu | Cota de TVA nu este una dintre cele patru cote legale din România (0, 9, 11, 21). |
E500 | TimeoutCommand | da | Comanda nu s-a încheiat în limita de timp pentru execuție. |
E501 | TimeoutResponse | da | Imprimanta a început comanda, dar nu a returnat un răspuns la timp. |
E502 | TimeoutConnection | da | Timeout la nivelul conexiunii cu imprimanta. |
E900 | Unknown | nu | Eroare driver neclasificată. |
E901 | InternalError | nu | Eroare internă neașteptată în stratul de driver. |
E902 | UnexpectedResponse | nu | Imprimanta a returnat un răspuns pe care driver-ul nu l-a putut interpreta. |
Când retryable este true, aceeași comandă poate fi retrimisă în siguranță (folosește același Idempotency-Key pentru a evita tipăriri duplicate dacă logica ta de business o cere).
Limite de rată
Limitarea ratei este aplicată la marginea API-ului de express-rate-limit și este organizată în principal după primele 20 de caractere ale cheii API (astfel toate cererile de la o integrare POS împart același bucket); când nu există cheie API, se folosește adresa IP a clientului, cu mascare corectă pe subrețele IPv6.
Valorile implicite (configurabile per mediu prin variabilele de mediu RATE_LIMIT_* și AUTH_RATE_LIMIT_* de pe server):
| Limitator | Maxim implicit | Fereastră | Cheie | Se aplică la |
|---|---|---|---|---|
| Global | 150 | 10 min | Prefix cheie API (20 caractere) sau IP | Fiecare cerere către API |
| Endpoint-uri de autentificare | 30 | 10 min | IP client | /api/v1/auth/* (register, login, refresh) |
| Trimitere de comenzi | 50 | 10 min | Prefix cheie API (20 caractere) sau IP | POST /api/v1/commands și echivalente |
Fiecare răspuns include antetele standard IETF draft-7 pentru limitarea ratei:
| Antet | Semnificație |
|---|---|
RateLimit-Limit | Numărul maxim de cereri permise în fereastra curentă. |
RateLimit-Remaining | Cereri rămase în fereastra curentă. |
RateLimit-Reset | Secunde până la resetarea ferestrei. |
Când treci de o limită, răspunsul este 429 Too Many Requests și include un antet Retry-After (secunde, întreg) care îți spune exact cât trebuie să aștepți înainte de următoarea încercare:
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
}
Implementează backoff exponențial și respectă Retry-After; nu bombarda API-ul după un 429.
Idempotență
POST /api/v1/commands și POST /api/v1/receipts acceptă antetul Idempotency-Key. Folosește-l la fiecare modificare reluabilă, ca o întrerupere de rețea să nu ducă la un bon tipărit de două ori.
- Format permis:
1–128caractere, doar[a-zA-Z0-9_-]. - Domeniu de valabilitate: per organizație. Intern, cheia de cache este
{orgId}_{idempotencyKey}. - TTL: 24 de ore. Reluările în această fereastră returnează răspunsul original memorat (același status, același corp), fără a reexecuta operațiunea.
- Eșec de validare: o cheie cu format invalid returnează
400 VALIDATION_ERROR.
POST /api/v1/commands HTTP/1.1
Host: api.e-bon.ro
Authorization: Bearer ebon_live_<orgId>_<32-hex>
Content-Type: application/json
Idempotency-Key: order-12345-attempt-1
{ "deviceId": "dev_abc123", "type": "print_receipt", "payload": { "...": "..." } }
Un șablon obișnuit este {id-operațiune-logică}-attempt-{n}, astfel încât reluările explicite să primească propria intrare în cache, iar reluările transparente (timeout-uri, erori de rețea) să refolosească răspunsul original.
Paginare
Endpoint-urile de listare folosesc paginare bazată pe cursor, cu sortare stabilă pe createdAt (cele mai noi mai întâi, implicit). Forma este:
{
"receipts": [ /* până la `limit` elemente */ ],
"hasMore": true,
"lastId": "rec_001"
}
Trimite lastId înapoi ca startAfter pentru a obține pagina următoare:
GET /api/v1/receipts?startAfter=rec_001&limit=50 HTTP/1.1
Parametri comuni pentru endpoint-urile de listare:
| Parametru | Tip | Implicit | Semnificație |
|---|---|---|---|
limit | int | 50 | Dimensiunea paginii, 1–100. |
startAfter | string | — | Cursor (lastId din pagina anterioară). |
sortBy | string | createdAt | Câmp de sortare (variază pe endpoint; bonurile acceptă și total). |
sortOrder | string | desc | asc sau desc. |
Unele endpoint-uri acceptă și filtre specifice resursei (status, type, deviceId, from, to etc.) — vezi paginile per resursă.
Restricții pe planuri
Unele operațiuni sunt limitate de planul de abonament al organizației. Serverul aplică aceste limite în middleware și returnează 403 TIER_LIMIT_EXCEEDED când sunt depășite:
| Plan | Dispozitive maxime | Creare chei API |
|---|---|---|
free | 2 | nepermisă |
pro | 10 | permisă |
enterprise | nelimitat | permisă |
Planul Free blochează POST /api/v1/devices odată ce ajungi la 2 dispozitive și blochează complet crearea de chei API. Fă upgrade din pagina de facturare a Portalului pentru a ridica limitele.
Autentificare, pe scurt
API-ul acceptă două moduri de autentificare:
- Cheie API — pentru sisteme POS și integrări de back-office. Trimite
x-api-key: ebon_live_...sauAuthorization: Bearer ebon_live_.... - JWT — pentru Portalul e-bon și aplicația mobilă. Flux standard de register / login / refresh sub
/api/v1/auth/*.
Majoritatea endpoint-urilor de resurse (/devices, /commands, /receipts, /reports) acceptă oricare dintre moduri printr-un middleware de autentificare combinată, motiv pentru care aceleași endpoint-uri deservesc atât integrările POS, cât și interfața Portalului. Detaliile complete sunt pe pagina Autentificare.
Webhook-uri
În plus față de modelul de polling și de WebSocket-ul de evenimente, e-bon livrează callback-uri webhook pentru evenimente legate de bonuri, comenzi, aparate și rapoarte. Catalogul complet de evenimente, schemele de payload și verificarea HMAC a semnăturii sunt documentate pe pagina de referință Webhook-uri; configurează abonamentele în Portal la Setări → Webhook-uri.
Pași următori
- Autentificare — formatul cheilor API, permisiuni, generarea unei chei, erori de autentificare și exemple curl.
- Endpoint-uri de autentificare — referință la nivel de protocol pentru cele cinci rute
/api/v1/auth/*(înregistrare, autentificare, parolă uitată, reîmprospătare, deconectare). - Bonuri, Rapoarte și Dispozitive — referințe de endpoint-uri pentru suprafețele fiscale principale.
- Webhook-uri, Facturare și Instanțe de aplicație — evenimente outbound, administrarea abonamentului și starea aplicației controller.
- Comenzi — pune în coadă comenzi fiscale către un AMEF, fă polling pe finalizare și anulează cele în așteptare.
- Chei API — administrare programatică a cheilor API (listare, creare, actualizare, revocare) pentru Owner și Admin.
- Referință erori — pași de recuperare per cod pentru fiecare cod HTTP și FiscalError.
- Referință idempotență — antetul
Idempotency-Keyîn detaliu: TTL, matricea de reluare, avertismente și șabloane de generare a cheilor. - Colecție Postman — importă colecția oficială (peste 77 de cereri în 12 dosare) și explorează API-ul interactiv.
- Endpoint-uri de stare, identitate și meta — sonde de liveness/readiness, introspecția identității și specificația OpenAPI publică.
Descoperă dispozitive în rețea
Folosește butonul Scanare pentru a găsi imprimante fiscale în rețeaua locală sau prin Bluetooth, apoi asociază-le cu e-bon.
Chei API
Endpoint-uri REST pentru a lista, crea, actualiza și revoca cheile API ale organizației. Secretul brut este returnat o singură dată la creare.