e-bon
e-bon.ro
TypeScript SDK

Configure the HTTP transport

Set up authentication, timeouts, error handling, idempotency keys and credential rotation when using the @e-bon/sdk HTTP client.

Configure the HTTP transport

Every SDK call — client.receipts, client.devices, client.commands, and the rest — sends requests through a single shared HTTP transport. This page shows you how to configure it: pick an authentication method, set timeouts, handle errors, retry safely with idempotency keys, and rotate credentials at runtime.

Choose an authentication method

The SDK supports two auth methods. Pass either an API key or a bearer token when you construct the client.

Use an API key

API keys are the simplest option for server-to-server integrations.

import { EBonClient } from '@e-bon/sdk';

const client = new EBonClient({
  baseUrl: 'https://api.e-bon.ro',
  apiKey: process.env.EBON_API_KEY,
});

The SDK sends the key in the X-API-Key header on every request.

Use a bearer token

Use a JWT bearer token when you need short-lived credentials or per-user authentication.

import { EBonClient } from '@e-bon/sdk';

const client = new EBonClient({
  baseUrl: 'https://api.e-bon.ro',
  token: accessToken,
});

The SDK sends the token in Authorization: Bearer <token> on every request.

If you pass both apiKey and token, the token wins — the API key is ignored. This matters when you migrate a long-lived client from API-key auth to JWT auth.

Set timeouts

Requests fall back to a 30-second default. Override the client-wide timeout when you construct the client:

const client = new EBonClient({
  baseUrl: 'https://api.e-bon.ro',
  apiKey: process.env.EBON_API_KEY,
  timeout: 10_000, // 10 seconds for every request
});

When a request exceeds the timeout, the SDK aborts the underlying fetch and throws EBonApiError with code === 'TIMEOUT' and status === 0.

Handle errors

Every error the SDK throws is an instance of EBonApiError. Branch on err.status (HTTP status code) to decide what to do — it's the most reliable field across all error types.

import { EBonApiError } from '@e-bon/sdk';

try {
  const receipt = await client.receipts.create(body);
} catch (err) {
  if (err instanceof EBonApiError) {
    switch (err.status) {
      case 0:
        // Network error or timeout — safe to retry
        console.error('Network problem:', err.message);
        break;
      case 401:
        // Missing or expired credentials — refresh and retry
        await refreshCredentials();
        break;
      case 422:
        // Validation failed — inspect err.details
        console.error('Validation errors:', err.details);
        break;
      case 429:
        // Rate limited — wait err.retryAfter seconds
        await sleep((err.retryAfter ?? 1) * 1000);
        break;
      default:
        throw err;
    }
  }
}

Common status codes

StatusMeaningRecommended action
0Network error or timeoutRetry with backoff
401UnauthorizedRefresh credentials
404Resource not foundSurface to the user
422Validation failedInspect err.details
429Rate limit hitWait err.retryAfter seconds
500599Server errorRetry with backoff
For rate-limit errors the SDK populates err.retryAfter from the Retry-After response header (in seconds). For all other errors retryAfter is undefined.

Retry safely with idempotency keys

POST and PATCH calls can produce duplicates if you retry them after a network failure. Send the same Idempotency-Key header on every retry attempt and the API returns the cached response within a 24-hour window — see the Idempotency reference for the full contract.

Wrap your write calls in a small helper that injects the header and retries on transient errors:

import { EBonClient, EBonApiError, type CreateReceiptBody, type Receipt } from '@e-bon/sdk';
import { randomUUID } from 'node:crypto';

async function createReceiptIdempotent(
  client: EBonClient,
  body: CreateReceiptBody,
): Promise<Receipt> {
  const idempotencyKey = randomUUID();
  let attempt = 0;

  while (true) {
    try {
      return await client.receipts.create(body, {
        headers: { 'Idempotency-Key': idempotencyKey },
      });
    } catch (err) {
      attempt++;
      const transient =
        err instanceof EBonApiError &&
        (err.status === 0 || err.status >= 500);

      if (transient && attempt < 3) {
        await sleep(2 ** attempt * 250);
        continue;
      }
      throw err;
    }
  }
}
Always generate a fresh idempotency key per logical operation (one receipt = one key) and reuse the same key across retries of that operation. Never reuse a key for a different request body — the API returns the original cached response regardless of what you send.

Rotate credentials at runtime

For long-lived clients, refresh the bearer token without rebuilding the client:

client.setToken(newAccessToken);

The next request picks up the new value. Requests already in flight keep the credentials they captured when they started — setToken does not abort or re-stamp them.

A typical refresh-on-401 pattern:

import { EBonApiError } from '@e-bon/sdk';

async function withRefresh<T>(call: () => Promise<T>): Promise<T> {
  try {
    return await call();
  } catch (err) {
    if (err instanceof EBonApiError && err.status === 401) {
      const fresh = await refreshAccessToken();
      client.setToken(fresh);
      return await call();
    }
    throw err;
  }
}

const receipt = await withRefresh(() => client.receipts.get(id));
Use this pattern in a single shared wrapper around every SDK call so a token refresh from one resource benefits the next call to any other resource — they all share the same transport.

Where to next

  • SDK overview — the high-level shape of EBonClient and the resource accessors.
  • Errors — the full EBonApiError shape and the recommended retry pattern.
  • Events — real-time event delivery over WebSocket.
  • Idempotency — wire-level rules for Idempotency-Key reuse and the 24-hour cache.
  • Rate limits — the Retry-After semantics on 429 responses.
  • API errors — the full HTTP code catalogue.