Developer quickstart
Developer quickstart
This page is for developers integrating a POS, ERP or back-office tool with e-bon. By the end of it you will have an API key, a successful GET /api/v1/devices call, your first queued print_receipt command and a minimal subscriber listening for the matching command.completed / command.failed event. Plan on roughly ten minutes once you have a verified e-bon organization.
If you are a business owner who just wants to connect a fiscal printer to a phone, the Integration walkthrough is the page for you — this one assumes you can run curl or node from a terminal and read JSON.
Sign up and copy your first API key
Create an organization in the Cloud Portal (app.e-bon.ro) using your business email. Your CUI is fetched automatically from ANAF — confirm it, set a password, and the organization is provisioned on the free plan with no card required.
Once you land on the dashboard, open Settings → API Keys (path: /portal/api-keys), click Create key, give it a label like Local dev — quickstart, pick at least the devices:read and commands scopes, and copy the key. The full key is shown only once — store it in a password manager or in a .env file you do not commit.
API keys have the shape:
ebon_live_<orgId>_<32-hex>
For the rest of this page, export it once and reuse it:
export EBON_API_KEY="ebon_live_acme_corp_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"
The portal walkthrough — including rotation, deactivation and last-used tracking — lives at Portal › API keys.
Make your first call — list devices
The smallest end-to-end call you can make is GET /api/v1/devices. It validates your key, returns the devices registered against your organization, and works against an empty organization too (you get back []).
curl
curl https://api.e-bon.ro/api/v1/devices \
-H "Authorization: Bearer $EBON_API_KEY"
Node — @e-bon/sdk
First install the SDK in your project:
pnpm add @e-bon/sdk
Then:
import { EBonClient } from '@e-bon/sdk';
const client = new EBonClient({
baseUrl: 'https://api.e-bon.ro',
apiKey: process.env.EBON_API_KEY!,
});
const devices = await client.devices.list();
console.log(devices);
A successful response is a flat JSON array (no envelope):
[
{
"id": "dev_pos_01",
"name": "Tejghea POS 1",
"protocol": "datecs_compact",
"transport": "tcp",
"locationId": "loc_main",
"connectionParams": { "host": "192.168.1.50", "port": 9100 },
"status": "online",
"orgId": "acme_corp",
"controllerId": "instance_a",
"controllerName": "Counter A",
"createdAt": "2026-04-09T08:10:00.000Z",
"updatedAt": "2026-04-09T08:10:00.000Z"
}
]
If you have not paired a fiscal device yet, the array will be empty — that is fine for the next step, but you will need at least one online device (a live AMEF, or a development device pointed at a printer simulator) before your print_receipt command can actually complete. The Integration walkthrough covers the pairing flow in the portal and the E-BON Android app.
Pick a deviceId from the response (or register one first) and export it for the next step:
export EBON_DEVICE_ID="dev_pos_01"
Send your first fiscal command
The fiscal-command API is asynchronous: POST /api/v1/commands queues the command, returns 201 with status: "pending" and dispatches it to the device over WebSocket in the background. You then either poll GET /api/v1/commands/{commandId} or — better — subscribe to command.* events (next step).
The smallest valid print_receipt payload is one item paid in cash:
curl
curl -X POST https://api.e-bon.ro/api/v1/commands \
-H "Authorization: Bearer $EBON_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: quickstart-$(date +%s)" \
-d '{
"deviceId": "'"$EBON_DEVICE_ID"'",
"type": "print_receipt",
"payload": {
"items": [
{ "name": "Item A", "price": 10, "quantity": 1, "vatRate": 21 }
],
"payments": [
{ "type": "cash", "amount": 10 }
]
}
}'
Node — @e-bon/sdk
const command = await client.commands.send({
deviceId: process.env.EBON_DEVICE_ID!,
type: 'print_receipt',
payload: {
items: [{ name: 'Item A', price: 10, quantity: 1, vatRate: 21 }],
payments: [{ type: 'cash', amount: 10 }],
},
});
console.log(command.id, command.status); // → "cmd_…", "pending"
You get back a 201 Created with the queued record:
{
"id": "cmd_abc123",
"deviceId": "dev_pos_01",
"type": "print_receipt",
"payload": {
"items": [{ "name": "Item A", "price": 10, "quantity": 1, "vatRate": 21 }],
"payments": [{ "type": "cash", "amount": 10 }]
},
"orgId": "acme_corp",
"status": "pending",
"apiKeyId": "apikey_abc",
"deviceOnline": true,
"createdAt": "2026-04-09T08:10:00.000Z",
"updatedAt": "2026-04-09T08:10:00.000Z"
}
201 only confirms that the command was persisted and queued — the AMEF can still reject it (failed) or never reply (timeout). Always check the final status, either by polling GET /api/v1/commands/{commandId} or by listening for the command.completed / command.failed events in the next step.The full per-type payload schemas, the commandRateLimit (50 / 10 min) and the Idempotency-Key header semantics are documented on Commands.
Subscribe to your first event
Polling works, but the real-time path is simpler: open one WebSocket subscriber, listen for command.completed and command.failed, and resolve every command from a single handler.
curl — there is no curl path for the events stream; the channel is a WebSocket. Either jump to the Node snippet below or, while you wait, poll the command record:
curl https://api.e-bon.ro/api/v1/commands/cmd_abc123 \
-H "Authorization: Bearer $EBON_API_KEY"
Node — @e-bon/sdk
import { EBonClient } from '@e-bon/sdk';
const client = new EBonClient({
baseUrl: 'https://api.e-bon.ro',
apiKey: process.env.EBON_API_KEY!,
});
const events = client.events.subscribe();
events.on('command.completed', (data) => {
// data: { commandId, deviceId, type, result, timestamp }
console.log(`✓ ${data.type} ${data.commandId} on ${data.deviceId} ok`);
});
events.on('command.failed', (data) => {
// data: { commandId, deviceId, type, error, errorCode, retryable, timestamp, fiscalError }
console.error(
`✗ ${data.type} ${data.commandId} failed: ${data.errorCode} — ${data.error} (retryable=${data.retryable})`,
);
});
// On shutdown:
// events.close();
errorCode is one of the ErrorCode constants — common values include E300 (fiscal memory full), E304 (fiscal hardware error), E400 (validation — invalid payload), E500 (timeout — command), E900 (unknown). The full catalogue and the retryable semantics are documented on API › Webhooks and SDK › Events.
The subscriber reconnects automatically with exponential backoff, so you can leave it running for the lifetime of your worker.
Continue your integration
You have the loop end-to-end: key → list → command → event. Everything else in the e-bon API is a variation on the same shape.
Full API reference
SDK overview
@e-bon/sdk surface — EBonClient, the ten resource accessors, EBonApiError, FiscalError and the typed EventSubscriber.Integration walkthrough
Postman collection
Authorization: Bearer {{EBON_API_KEY}}. See API › Postman collection for the import walkthrough.