Errors
Errors
Every failure that surfaces out of @e-bon/sdk is an instance of one of two concrete classes — EBonApiError for HTTP-level failures, FiscalError for printer-side fiscal failures. There are no plain Error throws and no untyped unknown rejections from the SDK itself.
EBonApiError
EBonApiError wraps any non-2xx HTTP response from https://api.e-bon.ro. It is also thrown for transport-level failures — request timeouts (the SDK aborts via AbortController after timeout milliseconds, default 30000) and fetch errors — with status: 0 and a synthetic code of TIMEOUT or NETWORK_ERROR.
class EBonApiError extends Error {
status: number // HTTP status, or 0 for transport errors
code: string // matches the HTTP error catalogue (UNAUTHORIZED, VALIDATION_ERROR, …)
message: string
details: ApiErrorDetails[] // populated on VALIDATION_ERROR and a few others
retryAfter?: number // seconds — populated on 429 from the Retry-After header
}
Branch on status and code rather than parsing the message:
import { EBonApiError } from '@e-bon/sdk';
try {
await client.receipts.create(body);
} catch (err) {
if (err instanceof EBonApiError) {
if (err.code === 'VALIDATION_ERROR') {
for (const detail of err.details) {
console.warn(`${detail.field ?? '<root>'}: ${detail.message}`);
}
return;
}
if (err.status === 429 && err.retryAfter) {
await sleep(err.retryAfter * 1000);
return;
}
}
throw err;
}
The full catalogue of HTTP-level code values lives on the API overview › HTTP error code catalogue.
FiscalError
FiscalError represents a failure that originated at the printer or the fiscal driver. The SDK constructs and attaches it to every command.failed event payload, and resource methods that resolve a fiscal command synchronously (for example a wrapper that polls until completion) throw it directly.
The class has exactly four typed fields beyond the inherited message:
class FiscalError extends Error {
code: ErrorCode // one of the fiscal codes E100…E901
message: string
retryable: boolean // precomputed via isRetryable(code)
commandId?: string // the command that failed, when known
deviceId?: string // the device that emitted the failure, when known
}
The constructor accepts { code, message, commandId?, deviceId? }; retryable is derived inside the constructor from isRetryable(code), so you never need to compute it yourself.
The full ErrorCode enum and the per-code retryable mapping are documented on the API overview › Fiscal / device error codes.
Import the error helpers from @e-bon/sdk
@e-bon/sdk re-exports the three pieces you need to work with fiscal errors without pulling @e-bon/types in directly:
import { ErrorCode, RETRYABLE_ERRORS, isRetryable } from '@e-bon/sdk';
ErrorCode— the enum of fiscal error codes (E100…E901). Use it forswitchstatements and for typed comparisons againstFiscalError.code.RETRYABLE_ERRORS— the canonical set ofErrorCodevalues that are safe to retry. Mirrors theretryablecolumn in the API overview table.isRetryable(code)— the helper that backsFiscalError.retryable. Useful when you receive a code through an out-of-band channel (a webhook, a database row) and want the same answer.
Retry transient failures safely
Combine FiscalError.retryable with the Idempotency-Key header on the underlying HTTP request to retry transient fiscal failures without risking a double print:
import { EBonApiError, FiscalError } from '@e-bon/sdk';
async function sendWithRetry(
client: EBonClient,
body: SendCommandBody,
idempotencyKey: string,
maxAttempts = 3,
) {
let attempt = 0;
let delay = 1_000;
while (true) {
attempt += 1;
try {
return await client.commands.send(body);
} catch (err) {
// Fiscal failure on the printer.
if (err instanceof FiscalError && err.retryable && attempt < maxAttempts) {
await sleep(delay);
delay *= 2;
continue;
}
// HTTP-level rate limit. Honour Retry-After.
if (err instanceof EBonApiError && err.status === 429 && err.retryAfter) {
await sleep(err.retryAfter * 1000);
continue;
}
throw err;
}
}
}
Passing the same idempotencyKey on retries is what makes this safe — the server returns the cached response from the original attempt instead of executing the command twice. See API overview › Idempotency for the full rules.
err.retryable is true. Codes such as FiscalMemoryFull (E300), FiscalDailyLimitReached (E303) and FiscalHardwareError (E304) need an operator on-site, not another network round-trip.Where to next
- API overview › HTTP error code catalogue — the wire-level codes returned in
error.code. - API overview › Fiscal / device error codes — the full
ErrorCodetable. - Events — how
FiscalErroris delivered throughcommand.failedpayloads.
Events
The EventSubscriber class — connect, listen with typed payloads, auto-reconnect with exponential backoff and the full event catalogue from EventMap.
client.devices
Reference for client.devices — every method with TypeScript signatures, parameters and Node examples, mirroring the /api/v1/devices REST surface.