Commands
Commands
The Commands API is the public surface of e-bon's command-queue model. A POS or back-office integration submits a fiscal command (print_receipt, x_report, cash_in, set_datetime, …) to e-bon over REST; the server persists the command, dispatches it to the matching device over WebSocket in the background, and returns a pending record immediately so the HTTP caller is never blocked by the device round-trip. The integration then polls GET /api/v1/commands/{commandId} until the command reaches a terminal status (completed, failed, timeout) or subscribes to the command.completed / command.failed / command.timeout events on the Webhooks channel.
All endpoints in this group live under /api/v1/commands and are governed by a single API-key scope: commands. They also accept a Portal JWT through the combined-auth middleware. See Authentication › Choose scopes for the full scope catalogue.
POST /api/v1/commands returns 201 with status: "pending"before the command has actually run on the AMEF. The HTTP 201 only confirms that the command has been persisted and queued — the device may 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 command.* webhook events.The error envelope, idempotency rules and rate limits used below are documented once on API overview; only the per-endpoint error codes are listed in full on this page.
POST /api/v1/commands
Queues a fiscal command targeting a device in your organization. The command is dispatched to the device over WebSocket asynchronously; the response is returned immediately with status: "pending".
- Auth scope:
commands - Idempotency: supports the
Idempotency-Keyheader (replays return the original201response without re-dispatching). - Rate limit: the route goes through the dedicated
commandRateLimitmiddleware (50 / 10 min by default) on top of the global limit. See Rate limits.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
deviceId | string | yes | A device that exists in your organization (≥ 1 char). |
type | string | yes | One of the CommandType values: print_receipt, void_receipt, x_report, z_report, cash_in, cash_out, get_status, get_cash_amount, set_datetime, print_duplicate, non_fiscal_receipt, set_logo, delete_logo, raw_command, open_drawer, get_vat_rates, set_vat_rates, get_vat_capabilities, get_header_footer_capabilities, get_header_footer, set_header_footer, get_operator_capabilities, set_operator, get_info, get_last_receipt_info, void_open_receipt, print_reversal_receipt. |
payload | object | yes | Command-specific payload. Validated server-side against the per-type payload schema before dispatch. |
Response (201 Created)
{
"id": "cmd_abc123",
"deviceId": "dev_pos_01",
"type": "print_receipt",
"payload": { "items": [], "payments": [] },
"orgId": "acme_corp",
"status": "pending",
"apiKeyId": "apikey_abc",
"deviceOnline": true,
"createdAt": "2026-04-09T08:10:00.000Z",
"updatedAt": "2026-04-09T08:10:00.000Z"
}
deviceOnline is a snapshot of the WebSocket connectivity at the moment the command was queued — false does not block the command (it stays pending and is dispatched as soon as the device reconnects), but it's a useful early-warning signal in your logs.
Example
curl -X POST https://api.e-bon.ro/api/v1/commands \
-H "Authorization: Bearer ebon_live_acme_corp_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-12345-attempt-1" \
-d '{
"deviceId": "dev_pos_01",
"type": "x_report",
"payload": {}
}'
Error codes
VALIDATION_ERROR(400) — body failed Zod validation, or thepayloadfailed the per-typepayload-schema check (detailslists{ path, message }per field).NOT_FOUND(404) —deviceIddoes not exist in your organization.RATE_LIMIT_EXCEEDED(429) — command rate limit hit.UNAUTHORIZED/FORBIDDEN— see Authentication › Handle auth errors.
The full HTTP catalogue is on API overview › HTTP error code catalogue.
GET /api/v1/commands
Lists commands for the organization, newest-first by createdAt. Optional filters narrow the result set; the response is a flat JSON array (no envelope).
- Auth scope:
commands
Query parameters
| Parameter | Type | Default | Notes |
|---|---|---|---|
deviceId | string | — | Filter by target device. |
status | string | — | One of the CommandStatus values: pending, sent, processing, completed, failed, timeout. |
type | string | — | Filter by CommandType value (see the enum on POST /api/v1/commands). |
limit | integer | 50 | 1–100. |
Response (200 OK)
[
{
"id": "cmd_abc123",
"deviceId": "dev_pos_01",
"type": "print_receipt",
"status": "completed",
"payload": { "items": [], "payments": [] },
"result": { "success": true, "fiscalId": "AMEF-000123" },
"orgId": "acme_corp",
"apiKeyId": "apikey_abc",
"createdAt": "2026-04-09T08:10:00.000Z",
"updatedAt": "2026-04-09T08:10:02.500Z"
}
]
Example
curl "https://api.e-bon.ro/api/v1/commands?deviceId=dev_pos_01&status=failed&limit=20" \
-H "Authorization: Bearer ebon_live_acme_corp_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"
Error codes
VALIDATION_ERROR(400) — bad query (e.g.limit > 100).UNAUTHORIZED/FORBIDDEN— see Authentication › Handle auth errors.
GET /api/v1/commands/{commandId}
Returns a single command by ID. Use this to poll for completion after POST /api/v1/commands.
- Auth scope:
commands
Path parameters
| Parameter | Type | Notes |
|---|---|---|
commandId | string | Command document ID. |
Response (200 OK)
{
"id": "cmd_abc123",
"deviceId": "dev_pos_01",
"type": "print_receipt",
"status": "completed",
"payload": { "items": [], "payments": [] },
"result": {
"success": true,
"fiscalId": "AMEF-000123",
"data": { "receiptNumber": "0000123" }
},
"orgId": "acme_corp",
"apiKeyId": "apikey_abc",
"createdAt": "2026-04-09T08:10:00.000Z",
"updatedAt": "2026-04-09T08:10:02.500Z"
}
When the command is in a terminal failed state, result.success is false and error / errorCode / errorMessage are populated. The errorCode value is one of the Fiscal / device error codes.
Example
curl https://api.e-bon.ro/api/v1/commands/cmd_abc123 \
-H "Authorization: Bearer ebon_live_acme_corp_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"
Error codes
NOT_FOUND(404) — no command with that ID in your organization.UNAUTHORIZED/FORBIDDEN— see Authentication › Handle auth errors.
POST /api/v1/commands/{commandId}/cancel
Cancels a command that is still in pending or sent status. The command's status is moved to failed with error: "Cancelled by API" and errorCode: "Unknown". Commands already in processing, completed, failed or timeout cannot be cancelled — once the device picks the command up, only the device decides the outcome.
- Auth scope:
commands - Side effect: updates the command record. Does not push a cancellation message to the device — if the device has already received the command over WebSocket, it may still finish it; the cancelled status is purely a server-side bookkeeping flag for the API caller.
Path parameters
| Parameter | Type | Notes |
|---|---|---|
commandId | string | Command document ID. |
Response (200 OK)
{
"id": "cmd_abc123",
"deviceId": "dev_pos_01",
"type": "print_receipt",
"status": "failed",
"payload": { "items": [], "payments": [] },
"error": "Cancelled by API",
"errorCode": "Unknown",
"errorMessage": "Cancelled by API",
"orgId": "acme_corp",
"apiKeyId": "apikey_abc",
"createdAt": "2026-04-09T08:10:00.000Z",
"updatedAt": "2026-04-09T08:10:01.000Z"
}
Example
curl -X POST https://api.e-bon.ro/api/v1/commands/cmd_abc123/cancel \
-H "Authorization: Bearer ebon_live_acme_corp_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"
Error codes
NOT_FOUND(404) — no command with that ID in your organization.CONFLICT(409) — the command is no longer cancellable (current status is one ofprocessing,completed,failed,timeout). The error message includes the current status.UNAUTHORIZED/FORBIDDEN— see Authentication › Handle auth errors.
See also
- Devices — device-scoped command shortcuts (
POST /api/v1/devices/{deviceId}/commandsand the typed wrappers for cash balance, header/footer, VAT rates, reversals, etc.). - Webhooks — subscribe to
command.completed,command.failedandcommand.timeoutevents instead of polling. - Authentication — API-key format, scopes and JWT login flow.
- API overview — base URL, error envelope, rate limits, idempotency, pagination.
- Troubleshooting › Command timeouts and the 180s sweep — what
command.timeoutactually means and how to retry idempotently.
App instances
REST endpoint for inspecting which E-BON mobile app instances are currently connected over WebSocket and bridging fiscal devices for the organization.
SDK overview
What the @e-bon/sdk TypeScript client is, how to install it, instantiate it with an API key or JWT, and the ten resource accessors it exposes.