e-bon
e-bon.ro
API reference

Devices

REST endpoints for managing fiscal devices (AMEFs) — CRUD, claim/release, live status, alerts, and the full set of device commands (cash balance, datetime, logos, VAT rates, header/footer, operators, void, reversal, etc.).

Devices

The Devices API is the largest surface in e-bon. It splits into two layers, both mounted under /api/v1/devices:

  • CRUD & introspection — register, update and delete devices, list them, fetch status and alerts. These endpoints read and write the Firestore device record and the in-memory WebSocket gateway.
  • Commands & live operations — claim/release control of a device, dispatch fiscal commands (set_datetime, print_duplicate, non_fiscal_receipt, set_logo, VAT/header/footer/operator configuration, voiding, reversals…), and fetch live data from the device. For most command routes, the platform forwards the request to the device over WebSocket and waits for the device's reply before responding.

Each endpoint declares its own scope below. The four scopes used in this group are devices:read, devices:write, commands and receipts — see Authentication › Choose scopes for the full catalogue. The error envelope, rate limits and authentication rules are documented once on API overview.

Live-command endpoints (cash balance, set datetime, print duplicate, non-fiscal, logo, VAT rates, header/footer, operator, info, last-receipt, void, reversal) require the device to be online over WebSocket and to have an assigned controller. If either condition is not met, the request fails with 503 SERVICE_UNAVAILABLE.

CRUD

POST /api/v1/devices

Registers a new fiscal device on the organization.

  • Auth scope: devices:write
  • Tier check: the request is checked against your plan's device limit before the body is validated; if your organization is already at its device limit, the request is rejected with 403.

Request body

FieldTypeRequiredNotes
namestringyes1–255 chars.
protocolstringyesOne of datecs_compact, datecs_professional, datecs_extended, daisy, daisy_ro, eltrade, incotex, tremol, tremol_v2, custom, mfje.
transportstringyesOne of tcp, bluetooth, serial, usb.
locationIdstringyesThe location the device belongs to (≥ 1 char).
connectionParamsobjectyesEither { host: string, port: number (1–65535) } (TCP) or { address: string } (bluetooth/serial/usb).

Response (201 Created)

{
  "id": "dev_pos_01",
  "name": "Tejghea POS 1",
  "protocol": "datecs_compact",
  "transport": "tcp",
  "locationId": "loc_main",
  "connectionParams": { "host": "192.168.1.50", "port": 9100 },
  "orgId": "acme_corp",
  "status": "offline",
  "controllerId": null,
  "controllerName": null,
  "createdAt": "2026-04-09T08:10:00.000Z",
  "updatedAt": "2026-04-09T08:10:00.000Z"
}

Example

curl -X POST https://api.e-bon.ro/api/v1/devices \
  -H "x-api-key: ebon_live_acme_corp_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Tejghea POS 1",
    "protocol": "datecs_compact",
    "transport": "tcp",
    "locationId": "loc_main",
    "connectionParams": { "host": "192.168.1.50", "port": 9100 }
  }'

Error codes

  • VALIDATION_ERROR (400) — body failed schema validation.
  • FORBIDDEN (403) — device limit reached for the organization's tier.
  • UNAUTHORIZED / FORBIDDEN — see Authentication › Handle auth errors.

GET /api/v1/devices

Lists devices for the organization, optionally filtered by status or locationId.

  • Auth scope: devices:read

Query parameters

ParameterTypeNotes
statusstringOne of online, offline, busy, error.
locationIdstringFilter by location.

Response (200 OK)

[
  {
    "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"
  }
]

Example

curl "https://api.e-bon.ro/api/v1/devices?status=online" \
  -H "x-api-key: ebon_live_acme_corp_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"

GET /api/v1/devices/statuses

Returns the WebSocket connectivity (wsConnected) and Firestore status for every device in the organization, in a single call.

  • Auth scope: devices:read

Response (200 OK)

{
  "statuses": {
    "dev_pos_01": {
      "wsConnected": true,
      "firestoreStatus": "online",
      "lastSeen": "2026-04-09T08:09:55.000Z"
    },
    "dev_pos_02": { "wsConnected": false, "firestoreStatus": "offline", "lastSeen": null }
  }
}

Example

curl https://api.e-bon.ro/api/v1/devices/statuses \
  -H "x-api-key: ebon_live_acme_corp_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"

GET /api/v1/devices/alerts

Returns derived alerts for all devices in the organization, keyed by deviceId.

  • Auth scope: devices:read

Query parameters

ParameterTypeNotes
severitystringFilter by alert severity: warning, error, info.

Response (200 OK)

{
  "alerts": {
    "dev_pos_01": [
      {
        "type": "paper_low",
        "severity": "warning",
        "message": "Paper roll is below 10%",
        "deviceId": "dev_pos_01",
        "deviceName": "Tejghea POS 1",
        "detectedAt": "2026-04-09T08:00:00.000Z"
      }
    ]
  }
}

Example

curl "https://api.e-bon.ro/api/v1/devices/alerts?severity=error" \
  -H "x-api-key: ebon_live_acme_corp_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"

GET /api/v1/devices/{deviceId}

Returns a single device by ID.

  • Auth scope: devices:read

Example

curl https://api.e-bon.ro/api/v1/devices/dev_pos_01 \
  -H "x-api-key: ebon_live_acme_corp_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"

Error codes

  • NOT_FOUND (404) — device does not exist in your organization.

PATCH /api/v1/devices/{deviceId}

Updates name, connectionParams and/or locationId. At least one field must be provided.

  • Auth scope: devices:write

Request body

FieldTypeNotes
namestring1–255 chars.
connectionParamsobjectSame shape as on create.
locationIdstringMove the device to a different location.

Example

curl -X PATCH https://api.e-bon.ro/api/v1/devices/dev_pos_01 \
  -H "x-api-key: ebon_live_acme_corp_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Tejghea POS 1 (renumită)" }'

Error codes

  • VALIDATION_ERROR (400) — body failed schema validation (e.g. empty body).
  • NOT_FOUND (404) — device does not exist in your organization.

DELETE /api/v1/devices/{deviceId}

Permanently removes a device.

  • Auth scope: devices:write
  • Response: 204 No Content on success.

Example

curl -X DELETE https://api.e-bon.ro/api/v1/devices/dev_pos_01 \
  -H "x-api-key: ebon_live_acme_corp_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"

Error codes

  • NOT_FOUND (404) — device does not exist in your organization.

Control & status

POST /api/v1/devices/{deviceId}/claim

Sets controllerId and controllerName on a device, indicating which app instance is currently driving it. Broadcasts a device.claimed event on the org events WebSocket.

  • Auth scope: devices:write

Request body

FieldTypeRequiredNotes
controllerIdstringyes1–255 chars. Stable per instance.
controllerNamestringyes1–255 chars. Human-readable label.

Example

curl -X POST https://api.e-bon.ro/api/v1/devices/dev_pos_01/claim \
  -H "x-api-key: ebon_live_acme_corp_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6" \
  -H "Content-Type: application/json" \
  -d '{ "controllerId": "instance_a", "controllerName": "Counter A" }'

Error codes

  • VALIDATION_ERROR (400) — body failed schema validation.
  • NOT_FOUND (404) — device does not exist.
  • CONFLICT (409) — device is already controlled by a different controllerId.

POST /api/v1/devices/{deviceId}/release

Removes controllerId / controllerName. Only the current controller may release the device.

  • Auth scope: devices:write

Request body

FieldTypeRequiredNotes
controllerIdstringyesThe controllerId of the instance releasing control.

Error codes

  • FORBIDDEN (403) — controllerId does not match the current controller.
  • NOT_FOUND (404) — device does not exist.

GET /api/v1/devices/{deviceId}/status

Returns WebSocket connectivity and Firestore status for one device.

  • Auth scope: devices:read

Response (200 OK)

{
  "deviceId": "dev_pos_01",
  "wsConnected": true,
  "firestoreStatus": "online",
  "lastSeen": "2026-04-09T08:09:55.000Z"
}

Error codes

  • NOT_FOUND (404) — device does not exist.

GET /api/v1/devices/{deviceId}/connection-history

Returns the last 20 connection / disconnection events for a device, newest-first.

  • Auth scope: devices:read

Response (200 OK)

{
  "events": [
    {
      "type": "connected",
      "timestamp": "2026-04-09T08:00:00.000Z",
      "deviceModel": "Datecs DP-25",
      "appVersion": "2.4.1",
      "osVersion": "Android 14",
      "code": null,
      "reason": null
    },
    {
      "type": "disconnected",
      "timestamp": "2026-04-08T22:15:00.000Z",
      "deviceModel": "Datecs DP-25",
      "appVersion": "2.4.1",
      "osVersion": "Android 14",
      "code": 1006,
      "reason": "network unreachable"
    }
  ]
}

Error codes

  • NOT_FOUND (404) — device does not exist.

GET /api/v1/devices/{deviceId}/alerts

Returns derived alerts for one device.

  • Auth scope: devices:read

Query parameters

ParameterTypeNotes
severitystringFilter by alert severity: warning, error, info.

Error codes

  • NOT_FOUND (404) — device does not exist.

Commands

POST /api/v1/devices/{deviceId}/commands

Generic shortcut to enqueue a fiscal command targeting a specific device. The body is pre-validated against the command-payload schema for the given type before dispatch.

  • Auth scope: commands
  • Rate limit: this route is subject to a stricter command-specific rate limit, in addition to the global API rate limit.

Request body

FieldTypeRequiredNotes
typestringyesOne of: 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 (and the more specific types listed in the dedicated routes below).
payloadobjectyesCommand-specific payload. Pre-validated server-side.

Response (201 Created)

{
  "id": "cmd_abc123",
  "deviceId": "dev_pos_01",
  "type": "print_receipt",
  "payload": { "items": [], "payments": [] },
  "orgId": "acme_corp",
  "status": "pending",
  "apiKeyId": "apikey_abc",
  "createdAt": "2026-04-09T08:10:00.000Z",
  "updatedAt": "2026-04-09T08:10:00.000Z"
}

Error codes

  • VALIDATION_ERROR (400) — invalid command payload.
  • NOT_FOUND (404) — device does not exist.
  • RATE_LIMIT_EXCEEDED (429) — command rate limit hit.

GET /api/v1/devices/{deviceId}/cash-balance

Dispatches a get_cash_amount command and returns the device's current cash balance.

  • Auth scope: devices:read

Response (200 OK)

{
  "cashBalance": 1234.5,
  "currency": "RON",
  "deviceId": "dev_pos_01",
  "timestamp": "2026-04-09T08:10:00.000Z"
}

Error codes

  • NOT_FOUND (404) — device does not exist.
  • INTERNAL_ERROR (500) — device responded but did not return cash data.
  • SERVICE_UNAVAILABLE (503) — device offline or no controller assigned.

POST /api/v1/devices/{deviceId}/set-datetime

Dispatches a set_datetime command. If datetime is omitted, the server's current time is used.

  • Auth scope: devices:write

Request body

FieldTypeRequiredNotes
datetimestringnoISO 8601 string. Defaults to server time.

Response (200 OK)

{
  "success": true,
  "datetime": "2026-04-09T08:10:00.000Z",
  "deviceId": "dev_pos_01",
  "timestamp": "2026-04-09T08:10:00.000Z"
}

Error codes

  • NOT_FOUND (404) — device does not exist.
  • SERVICE_UNAVAILABLE (503) — device offline or no controller assigned.

POST /api/v1/devices/{deviceId}/print-duplicate

Dispatches a print_duplicate command to reprint the last receipt. No request body.

  • Auth scope: devices:write

Error codes

  • NOT_FOUND (404) — device does not exist.
  • SERVICE_UNAVAILABLE (503) — device offline or no controller assigned.

POST /api/v1/devices/{deviceId}/non-fiscal

Prints a non-fiscal text receipt (free-text, bypasses fiscal logic). Useful for internal notes, training, vouchers etc.

  • Auth scope: devices:write

Request body

FieldTypeRequiredNotes
linesstringyesAt least one line. Each line ≤ 48 chars.
headerstringnoOptional header text printed bold/centered at the top. ≤ 48 chars.

Example

curl -X POST https://api.e-bon.ro/api/v1/devices/dev_pos_01/non-fiscal \
  -H "x-api-key: ebon_live_acme_corp_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6" \
  -H "Content-Type: application/json" \
  -d '{
    "header": "MULȚUMIM",
    "lines": ["Cod cupon: ABC-123", "Valabil până la 30.06.2026"]
  }'

Error codes

  • VALIDATION_ERROR (400) — body failed schema validation.
  • NOT_FOUND (404) — device does not exist.
  • SERVICE_UNAVAILABLE (503) — device offline or no controller assigned.

Uploads a base64-encoded receipt logo (BMP/PNG/JPEG depending on the device).

  • Auth scope: devices:write

Request body

FieldTypeRequiredNotes
logostringyesBase64-encoded image data, ≥ 1 char.

Error codes

  • VALIDATION_ERROR (400) — body failed schema validation.
  • NOT_FOUND (404) — device does not exist.
  • SERVICE_UNAVAILABLE (503) — device offline or no controller assigned.

Removes the currently stored receipt logo on the device. No request body.

  • Auth scope: devices:write

Error codes

  • NOT_FOUND (404) — device does not exist.
  • SERVICE_UNAVAILABLE (503) — device offline or no controller assigned.

VAT configuration

GET /api/v1/devices/{deviceId}/vat-rates

Queries the VAT rates currently programmed on the device.

  • Auth scope: devices:read

Response (200 OK)

{
  "rates": [
    { "name": "Standard", "percentage": 21 },
    { "name": "Redusă alimente", "percentage": 9 }
  ],
  "deviceId": "dev_pos_01",
  "timestamp": "2026-04-09T08:10:00.000Z"
}

Error codes

  • NOT_FOUND (404) — device does not exist.
  • INTERNAL_ERROR (500) — device responded but did not return rates data.
  • SERVICE_UNAVAILABLE (503) — device offline or no controller assigned.

GET /api/v1/devices/{deviceId}/vat-capabilities

Queries the device's VAT-rate capabilities (max number of rates, whether names are programmable, etc.).

  • Auth scope: devices:read

Error codes

  • NOT_FOUND (404) — device does not exist.
  • INTERNAL_ERROR (500) — device did not return capabilities data.
  • SERVICE_UNAVAILABLE (503) — device offline or no controller assigned.

POST /api/v1/devices/{deviceId}/vat-rates

Reprograms the VAT rates on the device.

  • Auth scope: devices:write

Request body

FieldTypeRequiredNotes
ratesarrayyesAt least one entry. Each { name: string (≥ 1 char), percentage: number (≥ 0) }.

Error codes

  • VALIDATION_ERROR (400) — body failed schema validation.
  • NOT_FOUND (404) — device does not exist.
  • SERVICE_UNAVAILABLE (503) — device offline or no controller assigned.

Queries the device's header/footer capabilities (max lines, line length, etc.).

  • Auth scope: devices:read

Error codes

  • NOT_FOUND (404) — device does not exist.
  • INTERNAL_ERROR (500) — device did not return capabilities data.
  • SERVICE_UNAVAILABLE (503) — device offline or no controller assigned.

Returns the current header and footer programmed on the device.

  • Auth scope: devices:read

Response (200 OK)

{
  "header": ["ACME SRL", "Strada Exemplu 1, Bucuresti"],
  "footer": ["www.acme.ro", "Vă mulțumim!"],
  "deviceId": "dev_pos_01",
  "timestamp": "2026-04-09T08:10:00.000Z"
}

Error codes

  • NOT_FOUND (404) — device does not exist.
  • INTERNAL_ERROR (500) — device did not return header/footer data.
  • SERVICE_UNAVAILABLE (503) — device offline or no controller assigned.

POST /api/v1/devices/{deviceId}/header-footer

Reprograms the header and footer printed on every receipt.

  • Auth scope: devices:write

Request body

FieldTypeRequiredNotes
headerstringyesUp to 10 lines, each ≤ 48 chars.
footerstringyesUp to 10 lines, each ≤ 48 chars.

Error codes

  • VALIDATION_ERROR (400) — body failed schema validation.
  • NOT_FOUND (404) — device does not exist.
  • SERVICE_UNAVAILABLE (503) — device offline or no controller assigned.

GET /api/v1/devices/{deviceId}/operator-capabilities

Queries the device's operator capabilities (max number of operators, whether names/passwords are programmable, etc.).

  • Auth scope: devices:read

Error codes

  • NOT_FOUND (404) — device does not exist.
  • INTERNAL_ERROR (500) — device did not return capabilities data.
  • SERVICE_UNAVAILABLE (503) — device offline or no controller assigned.

POST /api/v1/devices/{deviceId}/operator

Programs an operator (cashier) slot on the device.

  • Auth scope: devices:write

Request body

FieldTypeRequiredNotes
operatorIdintegeryesOperator slot, ≥ 1.
namestringyes1–32 chars.
passwordstringno≤ 8 chars.

Error codes

  • VALIDATION_ERROR (400) — body failed schema validation.
  • NOT_FOUND (404) — device does not exist.
  • SERVICE_UNAVAILABLE (503) — device offline or no controller assigned.

Live data & corrective actions

GET /api/v1/devices/{deviceId}/info

Dispatches a get_info command and returns the device's identifying information (model, firmware, fiscal series, etc., as exposed by the protocol).

  • Auth scope: devices:read

Error codes

  • NOT_FOUND (404) — device does not exist.
  • INTERNAL_ERROR (500) — device did not return info data.
  • SERVICE_UNAVAILABLE (503) — device offline or no controller assigned.

GET /api/v1/devices/{deviceId}/last-receipt

Dispatches a get_last_receipt_info command and returns the device's last receipt summary.

  • Auth scope: devices:read

Error codes

  • NOT_FOUND (404) — device does not exist.
  • INTERNAL_ERROR (500) — device did not return last-receipt data.
  • SERVICE_UNAVAILABLE (503) — device offline or no controller assigned.

POST /api/v1/devices/{deviceId}/void-open

Dispatches a void_open_receipt command to discard a receipt that is open on the AMEF (e.g. after an aborted sale). No request body.

  • Auth scope: devices:write

Response (200 OK)

{
  "success": true,
  "message": "Open receipt voided successfully",
  "deviceId": "dev_pos_01",
  "timestamp": "2026-04-09T08:10:00.000Z"
}

Error codes

  • NOT_FOUND (404) — device does not exist.
  • SERVICE_UNAVAILABLE (503) — device offline or no controller assigned.

POST /api/v1/devices/{deviceId}/reversal

Dispatches a print_reversal_receipt command. The body is forwarded as the command payload after server-side validation against the reversal payload schema. Returns the printed reversal's receiptNumber when the device reports it.

  • Auth scope: devices:write

Response (201 Created)

{
  "success": true,
  "message": "Reversal receipt printed successfully",
  "receiptNumber": "0000123",
  "deviceId": "dev_pos_01",
  "timestamp": "2026-04-09T08:10:00.000Z"
}

Error codes

  • VALIDATION_ERROR (400) — payload failed reversal-receipt validation.
  • NOT_FOUND (404) — device does not exist.
  • SERVICE_UNAVAILABLE (503) — device offline or no controller assigned.

GET /api/v1/devices/{deviceId}/receipts

Shortcut to list receipts filtered by device, newest-first. This is a convenience wrapper around GET /receipts.

  • Auth scope: receipts

Query parameters

ParameterTypeDefaultNotes
typestringFilter by receipt type (sale / refund / storno).
limitinteger501100.

Example

curl "https://api.e-bon.ro/api/v1/devices/dev_pos_01/receipts?type=sale&limit=20" \
  -H "x-api-key: ebon_live_acme_corp_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"

Error codes

  • VALIDATION_ERROR (400) — bad query.
  • NOT_FOUND (404) — device does not exist.

See also

  • Receipts — store and search the receipts produced by these devices.
  • Reports — X / Z / JE / MF reports built on top of the receipt journal.
  • Authentication — scope catalogue used by every endpoint above.
  • API overview — base URL, error envelope, rate limits, idempotency, pagination.