Receipts
Receipts
The Receipts API is the journal layer of e-bon: once a fiscal command has been executed by the AMEF and the printer has returned a fiscal ID, the integration stores a copy of that receipt on the e-bon side so it can be searched, exported and audited later. The endpoints under /api/v1/receipts do not print anything themselves — printing goes through the Devices commands layer; the receipts collection is a write-once journal of what was printed.
All endpoints in this group accept either an API key (x-api-key / Authorization: Bearer …) or a Portal JWT and are governed by a single scope: receipts. There is no separate read-only access for these particular routes — receipts:read and receipts:admin cover other operations (history exports, storno) documented elsewhere. See Authentication › Choose scopes for the full scope catalogue.
The error envelope, idempotency rules and pagination conventions used below are documented once on API overview; only the per-endpoint error codes are listed in full on this page.
POST /api/v1/receipts
Stores a receipt after a successful fiscal print. Use this immediately after a print_receipt command on the device returns a fiscal ID, to keep the e-bon journal in sync.
- Auth scope:
receipts - Idempotency: supports
Idempotency-Keyheader (replays return the original 201 response). - Side effect: broadcasts a
receipt.createdevent on the org events WebSocket and dispatches areceipt.createdwebhook to subscribers.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
deviceId | string | yes | Must be a device that exists in your organization. |
type | string | yes | One of sale, refund, storno. |
items | array | yes | At least one item. Each { name, quantity, price, vatRate, department, discount? }. |
payments | array | yes | At least one payment. Each { method, amount }. method ∈ cash, card, voucher, credit, other. |
total | number | yes | Receipt grand total (sum of payments). |
vatBreakdown | array | yes | At least one entry. Each { rate, base, amount }. rate ∈ 0, 9, 11, 21. |
operatorId | string | yes | Operator / cashier identifier. |
fiscalId | string | no | Fiscal ID returned by the AMEF. |
fiscalDate | string | no | Fiscal date string returned by the AMEF. |
customerCif | string | no | Customer CIF, 2–20 chars, trimmed. |
qrCode | string | no | QR code data, ≤ 2048 chars. |
source | string | no | One of api, local, portal. Defaults to api. |
Response (201 Created)
{
"receipt": {
"id": "rec_abc123",
"deviceId": "dev_pos_01",
"type": "sale",
"items": [
{ "name": "Paine alba 500g", "quantity": 2, "price": 5.49, "vatRate": 9, "department": 1 }
],
"payments": [{ "method": "cash", "amount": 10.98 }],
"total": 10.98,
"vatBreakdown": [{ "rate": 9, "base": 10.07, "amount": 0.91 }],
"operatorId": "casier_01",
"orgId": "acme_corp",
"fiscalId": "AMEF-000123",
"fiscalDate": "2026-04-09",
"source": "api",
"createdAt": "2026-04-09T08:10:00.000Z"
}
}
Example
curl -X POST https://api.e-bon.ro/api/v1/receipts \
-H "x-api-key: ebon_live_acme_corp_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-12345-attempt-1" \
-d '{
"deviceId": "dev_pos_01",
"type": "sale",
"items": [
{ "name": "Paine alba 500g", "quantity": 2, "price": 5.49, "vatRate": 9, "department": 1 }
],
"payments": [{ "method": "cash", "amount": 10.98 }],
"total": 10.98,
"vatBreakdown": [{ "rate": 9, "base": 10.07, "amount": 0.91 }],
"operatorId": "casier_01",
"fiscalId": "AMEF-000123",
"fiscalDate": "2026-04-09"
}'
Error codes
VALIDATION_ERROR(400) — the request body is invalid (missing fields, wrong VAT rate, etc.).NOT_FOUND(404) —deviceIddoes not exist in your organization.UNAUTHORIZED/FORBIDDEN— see Authentication › Handle auth errors.
The full HTTP catalogue is on API overview › HTTP error code catalogue.
GET /api/v1/receipts
Lists receipts for the organization with cursor pagination and a set of optional filters. Receipts are returned newest-first by default.
- Auth scope:
receipts
Query parameters
| Parameter | Type | Default | Notes |
|---|---|---|---|
deviceId | string | — | Filter by device. |
type | string | — | One of sale, refund, storno. |
operatorId | string | — | Filter by operator. |
minTotal | number | — | Inclusive lower bound on total. |
maxTotal | number | — | Inclusive upper bound on total. Must be ≥ minTotal. |
startDate | string | — | ISO 8601 timestamp; receipts with createdAt >= startDate. |
endDate | string | — | ISO 8601 timestamp; receipts with createdAt <= endDate. |
sortBy | string | createdAt | createdAt or total. Ignored when startDate/endDate is set (orders by createdAt instead). |
sortOrder | string | desc | asc or desc. |
limit | integer | 50 | Page size, 1–100. |
startAfter | string | — | Cursor — pass the previous response's lastId. |
total range filter (minTotal / maxTotal) with sorting, the server orders by total first to satisfy Firestore's range-query rule, then by createdAt desc as a tiebreaker.Response (200 OK)
{
"receipts": [
{
"id": "rec_abc123",
"deviceId": "dev_pos_01",
"type": "sale",
"total": 10.98,
"operatorId": "casier_01",
"orgId": "acme_corp",
"createdAt": "2026-04-09T08:10:00.000Z"
}
],
"hasMore": true,
"lastId": "rec_abc123"
}
Example
curl "https://api.e-bon.ro/api/v1/receipts?deviceId=dev_pos_01&limit=20" \
-H "x-api-key: ebon_live_acme_corp_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"
Then, to fetch the next page:
curl "https://api.e-bon.ro/api/v1/receipts?deviceId=dev_pos_01&limit=20&startAfter=rec_abc123" \
-H "x-api-key: ebon_live_acme_corp_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"
Error codes
VALIDATION_ERROR(400) — bad query (e.g.minTotal > maxTotal,limit > 100).UNAUTHORIZED/FORBIDDEN— see Authentication › Handle auth errors.
GET /api/v1/receipts/{receiptId}
Returns a single receipt by ID.
- Auth scope:
receipts
Path parameters
| Parameter | Type | Notes |
|---|---|---|
receiptId | string | Receipt document ID. |
Response (200 OK)
{
"receipt": {
"id": "rec_abc123",
"deviceId": "dev_pos_01",
"type": "sale",
"items": [
{ "name": "Paine alba 500g", "quantity": 2, "price": 5.49, "vatRate": 9, "department": 1 }
],
"payments": [{ "method": "cash", "amount": 10.98 }],
"total": 10.98,
"vatBreakdown": [{ "rate": 9, "base": 10.07, "amount": 0.91 }],
"operatorId": "casier_01",
"orgId": "acme_corp",
"fiscalId": "AMEF-000123",
"fiscalDate": "2026-04-09",
"createdAt": "2026-04-09T08:10:00.000Z"
}
}
Example
curl https://api.e-bon.ro/api/v1/receipts/rec_abc123 \
-H "x-api-key: ebon_live_acme_corp_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"
Error codes
NOT_FOUND(404) — no receipt with that ID in your organization.UNAUTHORIZED/FORBIDDEN— see Authentication › Handle auth errors.
See also
- Devices commands — issue a
print_receiptcommand before storing the receipt here. - Reports — X / Z / JE / MF reports built on top of the receipt journal.
- API overview — base URL, error envelope, rate limits, idempotency, pagination.
- Troubleshooting — symptom-driven recipes when receipts fail to print, time out, or trigger ANAF rejections.
Request tracing & logging
How to trace a single HTTP call from your client to e-bon — the X-Request-Id round-trip, the error envelope shape, ready-made client recipes, and a bug-report checklist that turns minute-long investigations into seconds.
Reports
REST endpoints for fiscal reports — X (running totals), Z (end-of-day), JE (ANAF Electronic Journal XML) and MF (Fiscal Memory archive) — with request/response schemas, curl examples and per-endpoint error codes.