The Revenue API returns every fiscal transaction in a date range — with its positions, payments and tax breakdown — in a single call. Use it for accounting exports, revenue reconciliation, BI warehouses or ad-hoc reports.
Tip: Revenue API or SQL Views?
The Revenue API and the SQL Views expose the
same underlying data, but in different shapes for different runtimes:
- Revenue API — served over the public cloud endpoint
(my.apro.at). Returns a hierarchical JSON document per receipt
with positions, payments, tax, staff and table already nested. Ideal
for off-premise systems, SaaS integrations, mobile clients and any
consumer that wants a ready-to-use object tree.
- SQL Views — read-only views on the on-premise cash register
database. Flat, relational, queryable with any tool that speaks
SQL Server. Ideal for on-premise integrations, ETL pipelines and
existing BI workflows (Power BI, Tableau, Qlik, Metabase).
Pick the cloud API for real-time system-to-system integration, pick
the SQL views for bulk analytics and dashboards.
- Host:
my.apro.at - Auth: API key in
x-api-key - Content type:
application/json
Endpoints
Variant | Endpoint | Location derived from |
|---|---|---|
Path + key |
|
|
Key only |
| The API key itself. |
Both variants require a location-scoped API key. The key itself determines which location's data is returned — there is no tenant-wide variant. Pick whichever feels more explicit in your client code — both return the same data and require the same key.
Request body
Field | Type | Required | Description |
|---|---|---|---|
| ISO 8601 timestamp | ✅ | Return receipts after this point in time. |
| ISO 8601 timestamp | ✅ | Return receipts before this point in time. |
| integer | — | Cap the number of results returned. |
| GUID | — | Cursor — return transactions after this ID. Combine with |
Example request
POST /api/v1/reports/receipts
{
"after": "2026-01-01T00:00:00Z",
"before": "2026-02-01T00:00:00Z",
"limit": 100,
"afterTransactionID": "f03e11de-6330-4a03-a8a8-b6e5fd4e32a5"
}Download: revenue-request.json
Response
An array of receipts. Each element is one transaction with its positions, payments and metadata.
Top-level fields
Field | Type | Description |
|---|---|---|
| GUID | Unique transaction ID. |
| string | See Transaction types. |
| string |
|
| decimal | Gross total of the receipt. |
| decimal | Tip included in |
| decimal | Discount applied to the receipt. |
| ISO 8601 | When the transaction happened. |
| Tenant / operator record. | |
| The APRO location the data was queried for. | |
| Operator / waiter. | |
| Table or delivery spot (e.g. "Bar 1", "Room 301"). | |
| Room / zone the table belongs to (e.g. Garden, Bar). | |
| Customer · nullable | Invoice recipient. Always |
| Grouping the payment types roll up into. | |
| [Payment] | Payments settling the receipt. |
| [Item] | Line items. |
| integer | Number of guests, summed over the receipt's line items. |
Item
Field | Type | Description |
|---|---|---|
| string | Unique item ID. |
| integer | Product number (as used in APRO). |
| string | Product name. |
| string · nullable | Stable per-line identifier. Use it to deduplicate or reconcile lines across repeated queries. |
| string · nullable | Reference assigned by an external system. |
| ISO 8601 | Time the line was booked. |
| decimal | Gross price. |
| decimal | Net price. |
| decimal | Cost price of the line, for margin reporting. |
| decimal | Units sold. |
| integer · nullable | Course number in a multi-course service (Gang). |
| Applied tax rate. | |
| Product category (a.k.a. "Sparte"). | |
| [Side dish] · nullable | Side dishes / modifiers booked on this line. |
Side dish
Side dishes (Unterartikel) are the modifiers booked underneath a line item — the Pommes under a schnitzel, the ohne Zwiebel on a burger. They are returned nested inside their parent item, never as items of their own.
A side dish reuses the Item shape, but only the following fields are populated. Every other field — bookDate, externalId, purchasePrice, course, tax, category, sideDishes — is null or its zero value, and side dishes do not nest recursively.
Field | Type | Description |
|---|---|---|
| string | Unique side dish ID. |
| integer | Product number of the side dish. |
| string | Side dish name. |
| string | Stable per-side-dish identifier. Also the key the API deduplicates on. |
| decimal | Gross price of the side dish. |
| decimal | Net price of the side dish. |
| decimal | Units of the side dish. |
Caution: Do not add side dishes to your totals
A side dish that carries a surcharge is **already included in its
parent item'sgrossAmount/netAmount** and in the receipt'stotalAmount. SummingsideDishes[].grossAmounton top of the parent
line double-counts revenue. Treat the amounts as a breakdown for
display, not as separate positions.
sideDishes is null — not [] — when a line has none, and also on older query configurations that predate the feature. Test for null-or-empty rather than assuming an array is present.
Tax
Field | Type | Description |
|---|---|---|
| string | Unique tax rate ID. |
| decimal | Rate, e.g. |
| string | Display name, e.g. |
Category
Field | Type | Description |
|---|---|---|
| string | Unique category ID. |
| integer | Category number. |
| string | Display name. |
Payment
Field | Type | Description |
|---|---|---|
| string | Unique payment ID. Payments are deduplicated on this value. |
| decimal | Amount paid. |
| Method used. | |
| string · nullable | Financial-accounting account number the payment posts to. Use it to map payments onto ledger accounts in an export. |
Payment type
Field | Type | Description |
|---|---|---|
| integer · nullable | Unique payment method ID. |
| integer · nullable | Payment method number. Note the key is |
| string | Display name, e.g. |
Business
Field | Type | Description |
|---|---|---|
| string | Tenant ID from the POS database. |
| string | Legal name. |
Staff
Field | Type | Description |
|---|---|---|
| string | Unique staff ID. |
| integer | Personnel number. |
| string | Staff name. |
Table
Field | Type | Description |
|---|---|---|
| string | Unique table ID. |
| integer | Table number. |
| string | Table label, e.g. |
Location
Field | Type | Description |
|---|---|---|
| string | APRO location ID — the |
| string · nullable | Location name. |
Area
The room or zone a table sits in.
Field | Type | Description |
|---|---|---|
| string | Unique area ID. |
| integer | Area number. |
| string | Area label, e.g. |
Payment group
The grouping payment types roll up into — used for cash-book and settlement reporting.
Field | Type | Description |
|---|---|---|
| integer | Payment group ID. |
| string | Group label. |
Customer
Field | Type | Description |
|---|---|---|
| string | Unique customer ID. |
| integer | Customer number. |
| string | Customer name. |
Note: Always null today
The receipts endpoint never populatescustomer— it is reserved in the
response contract but not filled by the query. Do not build invoice-
recipient logic on it; resolve customers through their own endpoints
instead.
Example response
Response · two receipts settled back-to-back
[
{
"transactionId": "f03e11de-6330-4a03-a8a8-b6e5fd4e32a5",
"transactionType": "Abrechnen",
"receiptType": "Beleg",
"totalAmount": 3.2,
"tip": 0.0,
"discount": 0.0,
"dateTime": "03.10.2021 21:59:57",
"business": { "id": "1", "name": "APRO Kassensysteme" },
"location": { "id": "7236", "name": "Wien Haupthaus" },
"staff": { "id": "8", "number": 9500, "name": "Onlinekellner" },
"table": { "id": "76", "number": 76, "name": "Daniel Z" },
"area": { "id": "3", "number": 3, "name": "Garten" },
"customer": null,
"paymentGroup": { "id": 2, "name": "Kartenzahlung" },
"payments": [
{
"id": "04b2d2f5-8765-41b5-ad5c-aed802dc23bc",
"amount": 3.2,
"paymentType": { "id": 26, "nr": 200, "name": "Smorder Kreditkarte" },
"fibuAccountNr": "2751"
}
],
"items": [
{
"id": "38",
"number": 216,
"name": "Wiener Schnitzel",
"uniqueId": "0f6c2c14-3f8a-4f0b-9a1e-2b7d5c8e4411",
"externalId": null,
"bookDate": "03.10.2021 21:59:55",
"grossAmount": 3.2,
"netAmount": 3.2,
"purchasePrice": 1.1,
"quantity": 1.0,
"course": 2,
"tax": { "id": "5", "value": 5.0, "name": "Mwst 5 %" },
"category": { "id": "12", "number": 12, "name": "Hauptspeisen" },
"sideDishes": [
{
"id": "512",
"number": 9001,
"name": "Pommes",
"uniqueId": "b41d9a77-55c2-4e3d-8f10-6cc0a2b93d88",
"grossAmount": 1.5,
"netAmount": 1.36,
"quantity": 1.0
},
{
"id": "518",
"number": 9007,
"name": "ohne Zwiebel",
"uniqueId": "c9a70e31-1d44-4a92-b7e5-30f8c1d6a204",
"grossAmount": 0.0,
"netAmount": 0.0,
"quantity": 1.0
}
]
}
],
"guestCount": 2
},
{
"transactionId": "db2b90d1-ab37-4557-b169-2289c3004a0a",
"transactionType": "Abrechnen",
"receiptType": "Beleg",
"totalAmount": 3.2,
"tip": 0.0,
"discount": 0.0,
"dateTime": "03.10.2021 22:00:12",
"business": { "id": "1", "name": "APRO Kassensysteme" },
"location": { "id": "7236", "name": "Wien Haupthaus" },
"staff": { "id": "8", "number": 9500, "name": "Onlinekellner" },
"table": { "id": "76", "number": 76, "name": "Daniel Z" },
"area": { "id": "3", "number": 3, "name": "Garten" },
"customer": null,
"paymentGroup": { "id": 2, "name": "Kartenzahlung" },
"payments": [
{
"id": "bb3e6300-0cc3-4922-80c4-a8a4c3530d3c",
"amount": 3.2,
"paymentType": { "id": 26, "nr": 200, "name": "Smorder Kreditkarte" },
"fibuAccountNr": "2751"
}
],
"items": [
{
"id": "38",
"number": 216,
"name": "Cola 0,5",
"uniqueId": "7d2f3b90-6c11-4c8e-93aa-5e4419c7f0d3",
"externalId": null,
"bookDate": "03.10.2021 22:00:11",
"grossAmount": 3.2,
"netAmount": 3.2,
"purchasePrice": 0.7,
"quantity": 1.0,
"course": null,
"tax": { "id": "5", "value": 5.0, "name": "Mwst 5 %" },
"category": { "id": "20", "number": 20, "name": "Alkoholfreie Getränke" },
"sideDishes": null
}
],
"guestCount": 1
}
]Download the same payload as a standalone file: revenue-response.json
Transaction types
The transactionType discriminates what the row represents. For revenue-effective reports, filter on Abrechnen (and RechnungZurückholen for reversals).
Type | Meaning |
|---|---|
| Item booked on an open table. |
| Table change. |
| Settlement — a paid receipt. |
| Reversal of a booking. |
| Reversal of a settlement. |
| Debit booking. |
| Outgoing invoice lifecycle. |
| Day-end close / preview. |
| Waiter hand-over / settlement. |
| Legal fiscal receipts (RKSV). |
| Table lifecycle. |
| Order-manager events. |
| Cart lifecycle. |
| Data export markers. |
| Other operational events. |
Calculating revenue
To compute revenue-effective turnover over a response, keep only paid settlements and their reversals, and sum the net line totals:
response
.filter(x =>
x.paymentGroup.name === "Umsatzwirksam" &&
["Abrechnen", "RechnungZurückholen"].includes(x.transactionType)
)
.map(x =>
x.items.reduce((sum, item) => sum + item.netAmount * item.quantity, 0)
)
.reduce((sum, val) => sum + val, 0);Paging
There is no cursor-in-response — use the deterministic transactionId of the last row you saw as afterTransactionID on the next request, keeping after/before unchanged. Continue until the response contains fewer rows than your limit.
