Receipt Format
Receipts are the primary transaction records produced by POS terminals. Each receipt is stored as a JSON document in the
receipt field of the sales model. This page documents the structure of that JSON.
Common Fields
Section titled “Common Fields”Every receipt has these top-level fields regardless of type.
Receipt Types
Section titled “Receipt Types”| Value | Description |
|---|---|
SALES | Standard sales transaction |
CASH_DROP | Cash drop from the register |
CLOSE_DAY | End-of-day closing |
OPEN_DAY | Start-of-day opening |
PAID_OUT | Paid out from the register |
RECEIVED_ON_ACCOUNT | Received on account |
CASHIER_LOGIN | Cashier login event |
CASHIER_LOGOUT | Cashier logout event |
NO_SALE | No-sale drawer open |
SETTLEMENT | EFT settlement |
PURCHASE_ORDER | Purchase order |
DELIVERY | Stock receiving |
WASTAGE | Stock wastage |
This overview assumes that the receipt is a standard sales receipt.
Top-Level Fields
Section titled “Top-Level Fields”{ "id": "561c9e0c-6ea5-356f-cd84-9adaba192f49", "type": "SALES", "void": false, "timestamp": "2026-02-05T09:53:15.987Z", "company": "fad11441-f7b6-47f2-bff1-66c52c7bad1a", "pos": "09d6a809-5a96-40fc-b148-89576bff513a", "businessDay": "cfcfc579-c02c-4116-8b68-ca446026f916", "pricingData": "9fa7b9bf-134a-4896-9cc4-5da67b2c3068", "receiptNumber": 161, "orderNumber": 4, "totalSales": 2150}| Field | Type | Description |
|---|---|---|
id | guid | Unique receipt identifier |
type | enum | Receipt type (see table above) |
status | enum? | voided or voiding if the receipt has been voided |
void | boolean | true if the receipt is voided |
timestamp | datetime | Time of the transaction |
company | guid | Company the receipt belongs to |
pos | guid | POS terminal that created the receipt |
businessDay | guid? | Business day the receipt belongs to |
pricingData | guid? | Pricing data used for this receipt |
receiptNumber | int? | Sequential receipt number within the POS |
orderNumber | int? | Order number within the POS and business day |
totalSales | amount? | Total sales amount in cents |
comment | string? | Comment entered at the POS |
topComment | string? | Top comment printed on the receipt |
delivery | string? | Delivery method |
salesOrder | guid? | Linked sales order |
age_verified | boolean? | Whether customer age was verified |
originalReceiptNumber | int? | Original receipt number for returns |
Cashier
Section titled “Cashier”Present on most receipt types. Contains the cashier who processed the transaction.
{ "cashier": { "id": "5720375c-6f98-4149-a46c-d827631ab95b", "name": "Myyjä-1", "cashier_num": 1, "active": true, "data": { "pos_layout": "2d781f99-f932-4861-82ec-d4f623de2ff1" } }}| Field | Type | Description |
|---|---|---|
id | guid | Cashier identifier |
name | string | Cashier name |
cashier_num | int | Cashier number |
active | boolean | Whether the cashier is active |
data | object | Cashier configuration (layout overrides, etc.) |
Customer
Section titled “Customer”Optional. Present when a customer is attached to the receipt.
| Field | Type | Description |
|---|---|---|
id | guid | Customer identifier |
name | string | Customer name |
number | string? | Customer number |
ident | string? | Customer identifier (business ID, etc.) |
identified_by | string? | How the customer was identified |
Tax Lines
Section titled “Tax Lines”The taxes array summarizes tax by tax group for the entire receipt.
{ "taxes": [ { "taxGuid": "ccb26d59-c76c-4126-a7e9-af9fcd3156a9", "taxName": "ALV 13.5%", "taxPercent": 13.5, "taxAmount": 256, "taxlessAmount": 1894, "totalAmount": 2150 } ]}| Field | Type | Description |
|---|---|---|
taxGuid | guid | Tax group identifier |
taxName | string | Tax group name |
taxPercent | number | Tax percentage |
taxAmount | amount | Tax amount in cents |
taxlessAmount | amount | Amount without tax in cents |
totalAmount | amount | Total amount including tax in cents |
Table and Restaurant Fields
Section titled “Table and Restaurant Fields”These fields are present when the receipt is associated with table service.
| Field | Type | Description |
|---|---|---|
table | guid? | Table identifier |
seats | number? | Number of seats |
tableSession | guid? | Table session identifier |
seat | number? | Seat number (for split-by-seat receipts) |
tableState | string? | Table state at the time of the receipt |
tableOps | array? | Table state change history with timestamps |
Origin
Section titled “Origin”Present when the receipt was created from another receipt (e.g. split table).
| Field | Type | Description |
|---|---|---|
origin.id | string | Original receipt ID |
origin.receiptNumber | number? | Original receipt number |
origin.table | guid? | Original table |
origin.type | enum? | Origin type (e.g. split) |
POS Actions
Section titled “POS Actions”The posActions array lists actions the POS should perform after the receipt is completed (open drawer, print, send to
kitchen, etc.).
{ "posActions": [ { "id": "9df7907c-...", "name": "OPEN_DRAWER", "data": 0 }, { "id": "3bedd2de-...", "name": "PRINT_RECEIPT", "data": "CUSTOMER_RECEIPT" }, { "id": "a3f1d7dc-...", "name": "KITCHEN_PRINT", "data": "KITCHEN_PRINT1" } ]}| Action | Description |
|---|---|
OPEN_DRAWER | Open cash drawer |
PRINT_RECEIPT | Print receipt (data specifies which template) |
EMAIL_RECEIPT | Email receipt to customer |
SMS_RECEIPT | SMS receipt to customer |
KITCHEN_PRINT | Send order to kitchen printer |
Sales Lines
Section titled “Sales Lines”The salesLines array contains all product lines in the receipt. Each line represents one product sold (or voided).
Sales Line Fields
Section titled “Sales Line Fields”{ "id": "0", "qty": 1, "price": 950, "tax": "ccb26d59-c76c-4126-a7e9-af9fcd3156a9", "amountTax": 113, "amountWithoutTax": 837, "productId": "020003", "productGuid": "9ab590d0-f322-4574-8234-bbf3781479db", "productName": "K3. Kebab salaatilla", "delivery": "TAKE_OUT", "sentToKitchen": true, "no_group": true, "no_discount": false}| Field | Type | Description |
|---|---|---|
id | string | Line identifier within the receipt |
productId | string | Product number (PLU code) |
productGuid | guid | Product GUID |
productName | string | Product name |
qty | number | Quantity sold |
price | number | Unit price in cents |
tax | guid | Tax group identifier |
amountTax | amount? | Tax amount for this line in cents |
amountWithoutTax | amount? | Tax-exclusive amount in cents |
delivery | enum? | TAKE_OUT or EAT_IN |
voided | boolean? | Line has been voided |
comment | string? | Line comment |
description | string? | Line description |
seat | int? | Seat number (table service) |
course | string? | Course name (table service) |
sentToKitchen | boolean? | Whether the line was sent to kitchen |
priceOverride | boolean? | Price was manually overridden |
priceKeyedIn | boolean? | Price was keyed in manually |
quantityKeyedIn | boolean? | Quantity was keyed in manually |
no_group | boolean? | Exclude from product grouping |
no_discount | boolean? | Exclude from automatic discounts |
pricing | guid? | Pricing rule used |
startTime | datetime? | Service start time (timed items) |
endTime | datetime? | Service end time (timed items) |
Modifiers and Linked Items
Section titled “Modifiers and Linked Items”Products sold as part of a combo meal or with modifiers use the modifiers array and linked item fields. The parent
item lists modifier line IDs in modifiers, and each modifier line references back via menuItem.
[ { "id": "1", "productName": "B1. MANDO Burger", "price": 950, "modifiers": [ "2", "3" ] }, { "id": "2", "productName": "-TOMAATTI", "price": 0, "menuItem": "b1efac6e-a87e-707e-d727-d931b4dd66bf", "forceModifier": true, "topLevelPrice": false }, { "id": "3", "productName": "+ LISÄPIHVI", "price": 250, "menuItem": "35cd4f0a-ca30-271a-2590-f98b36d4b93c", "forceModifier": true, "topLevelPrice": false }]| Field | Type | Description |
|---|---|---|
modifiers | string[]? | IDs of modifier/linked sales lines |
menuItem | guid? | Menu item definition that caused this modifier |
isLinkedItem | boolean? | This line is a linked/modifier item |
forceModifier | boolean? | This line is a forced modifier (always added) |
topLevelPrice | boolean? | Modifier price is included in the parent price |
Line Discounts
Section titled “Line Discounts”Each sales line can have its own discounts array with line-level discounts.
| Field | Type | Description |
|---|---|---|
id | string? | Discount identifier |
name | string? | Discount name |
type | string? | Discount type |
amount | amount? | Discount amount in cents |
originalAmount | amount? | Original amount before discount |
manual | boolean? | Manually applied discount |
qty | number? | Quantity affected |
bundlable | boolean? | Part of a bundle discount |
productsPerDiscount | int? | Products per discount application |
Line Infocodes
Section titled “Line Infocodes”Each sales line can have an infocodes array with information collected during the sale.
| Field | Type | Description |
|---|---|---|
id | guid | Infocode definition identifier |
type | string | Infocode type |
target | string? | Target value |
value | string? | Collected value |
Per-Line Tax Breakdown (Split VAT)
Section titled “Per-Line Tax Breakdown (Split VAT)”The optional taxSales array provides a per-tax-group breakdown for a single sales line. This is used when a product
contains components taxed at different rates — for example, an Irish Coffee where the alcohol portion is taxed at 25.5%
and the non-alcoholic portion at 13.5%.
{ "id": "3", "qty": 2, "price": 1500, "productId": "130002", "productName": "Irish Coffee", "tax": "3bbb3660-5b9e-11ef-a550-0800200c9a66", "amountTax": 433, "amountWithoutTax": 2567, "taxSales": [ { "tax": "ccb26d59-c76c-4126-a7e9-af9fcd3156a9", "taxAmount": 250, "totalAmount": 2100, "taxlessAmount": 1850 }, { "tax": "3bbb3660-5b9e-11ef-a550-0800200c9a66", "taxAmount": 183, "totalAmount": 900, "taxlessAmount": 717 } ]}| Field | Type | Description |
|---|---|---|
tax | guid | Tax group identifier |
taxAmount | amount | Tax amount in cents |
taxlessAmount | amount | Tax-exclusive amount in cents |
totalAmount | amount | Total amount including tax in cents |
Key observations:
taxon the sales line: The line’s primary tax group (25.5% in this case). This is the default tax used for simple products.taxSalesarray: When present, overrides the simple tax calculation. Each entry represents one tax component of the product.- Sum of
taxSales: The individualtaxAmountvalues (250 + 183 = 433) sum to the line’samountTax. Similarly,totalAmountvalues (2100 + 900 = 3000) sum toqty × price(2 × 1500 = 3000). - Receipt-level
taxes: The receipt’s top-leveltaxesarray aggregates all tax groups across all lines, including both components of split-VAT products.
Discounts
Section titled “Discounts”Discounts appear in the receipt at two levels: receipt-level in the top-level discounts array, and line-level
in each sales line’s discounts array. The discount engine splits products across lines when bundle discounts apply —
one line gets the discounted (or free) price, and other lines keep the original price with a reference to the discount.
How Bundle Discounts Appear
Section titled “How Bundle Discounts Appear”In a “buy 5 pay for 5, get 6th free” (mix-and-match) scenario, the customer buys 8 items at €3.50 each. The discount engine identifies that 6 items qualify for the bundle: 5 at full price and 1 free. The remaining 2 items are at full price without any discount.
The receipt splits quantities across lines so each line carries its own discount reference. The free item getsprice: 0
with the originalAmount showing its regular price:
{ "salesLines": [ { "id": "0", "qty": 1, "price": 0, "productId": "1001", "productName": "Cake, White Chocolate", "amountTax": 0, "amountWithoutTax": 0, "discounts": [ { "id": "6FOR5", "name": "Buy 6 Pay 5", "qty": 1, "manual": false, "bundlable": true, "originalAmount": 350, "productsPerDiscount": 6 } ] }, { "id": "1", "qty": 1, "price": 350, "productId": "1001", "productName": "Cake, White Chocolate", "amountTax": 42, "amountWithoutTax": 308, "discounts": [ { "id": "6FOR5", "qty": 1, "manual": false, "bundlable": true, "originalAmount": 350, "productsPerDiscount": 6 } ] }, { "id": "2", "qty": 3, "price": 350, "productId": "1002", "productName": "Cake, Milk Chocolate", "amountTax": 42, "amountWithoutTax": 308, "discounts": [ { "id": "6FOR5", "qty": 3, "manual": false, "bundlable": true, "originalAmount": 350, "productsPerDiscount": 6 } ] }, { "id": "5", "qty": 2, "price": 350, "productId": "1003", "productName": "Cake, Pomada", "amountTax": 42, "amountWithoutTax": 308, "discounts": [ { "id": "6FOR5", "qty": 1, "manual": false, "bundlable": true, "originalAmount": 350, "productsPerDiscount": 6 } ] }, { "id": "7", "qty": 1, "price": 350, "productId": "1004", "productName": "Cake, Caramel", "amountTax": 42, "amountWithoutTax": 308 } ]}Key observations:
- Line splitting: The original 2x White Chocolate is split into two lines — one free (
price: 0) and one at full price. Both carry the discount reference. bundlable: true: Marks lines that participate in the bundle discount calculation.productsPerDiscount: The total number of products required to trigger the discount (6 in this case).originalAmount: The regular unit price before the discount was applied. On the free line this shows what the item would have cost.qtyin discount: The number of units on this line that count toward the discount. Note line"id": "5"hasqty: 2on the sales line but onlyqty: 1in the discount — one unit participates in the bundle, the other is at regular price.- No discount on remaining items: Line
"id": "7"has nodiscountsarray — it is outside the bundle.
App Coupon Discounts with Customer Identification
Section titled “App Coupon Discounts with Customer Identification”When a customer is identified (e.g. via QR code scan from a loyalty app), the receipt includes a customer object and
the discount’s infocodes array links the discount back to the external coupon. The manual: true flag indicates the
discount was triggered by the customer identification rather than applied automatically.
{ "customer": { "id": "00a22e55-7cfe-4291-94e6-445b7ab19120", "name": "Customer identified", "ident": "6a2c759f-bf8b-4074-b4e1-1164765498cd" }, "salesLines": [ { "id": "0", "qty": 1, "price": 518, "productId": "2518", "productName": "Toast, Aura & Salami", "amountTax": 62, "amountWithoutTax": 456, "discounts": [ { "id": "_APP_CP_TOAST_26", "name": "APP Toast -25%", "qty": 1, "manual": true, "bundlable": true, "originalAmount": 690, "productsPerDiscount": 1, "infocodes": [ { "id": "eaf86284-42d0-46c4-add6-506e650128ac", "type": "EXTERNAL_DISCOUNT", "value": "coupon_dabfcd64-acc9-4b18-8bac-ec79d0781275", "target": "a245b5dc-9066-4a43-8429-bc3dfee54362" } ] } ] } ], "externalActions": { "60453285": { "customerId": "6a2c759f-bf8b-4074-b4e1-1164765498cd", "discountList": [ { "discountId": "coupon_dabfcd64-acc9-4b18-8bac-ec79d0781275", "posDiscountId": "a245b5dc-9066-4a43-8429-bc3dfee54362" } ] } }}Key observations:
customer.ident: The external customer identifier from the loyalty system, matched via QR code scan.manual: true: The discount was applied through customer identification, not automatically by the pricing engine.originalAmount: The regular price (€6.90) before the 25% discount. The sales linepricereflects the discounted price (€5.18).- Discount
infocodes: Links the discount to its external source. Thetype: "EXTERNAL_DISCOUNT"indicates it came from an external system,valueholds the coupon identifier, andtargetreferences the POS discount definition. externalActions: Top-level object that maps external action IDs to customer and discount information, providing the full chain from customer identification to applied discounts.
Receipt-Level Discounts
Section titled “Receipt-Level Discounts”The top-level discounts array holds receipt-wide discounts (e.g. total percentage discount). It uses the same
discount_line structure as line-level discounts. In the bundle and coupon examples above, discounts is empty because
the discounts are applied at the line level.
Tender Lines
Section titled “Tender Lines”The tenderLines array contains all payment lines in the receipt. A receipt can have multiple tender lines when paid
with multiple payment methods.
Tender Line Fields
Section titled “Tender Line Fields”{ "tenderLines": [ { "id": "1", "tenderId": "d45c30d4-e6c6-45b3-95a6-5fe92e41c534", "tenderGuid": "d45c30d4-e6c6-45b3-95a6-5fe92e41c534", "tenderName": "KÄTEINEN", "tenderType": "TENDER", "qty": 1, "amount": 2150, "total": 2150, "overTender": 0 } ]}| Field | Type | Description |
|---|---|---|
id | string | Line identifier within the receipt |
tenderId | string | Tender type identifier |
tenderGuid | guid | Tender GUID |
tenderName | string | Payment method name |
tenderType | enum | TENDER (payment), CHANGE (change given), or VOID (voided tender) |
qty | number | Quantity (usually 1) |
amount | amount | Payment amount in cents |
total | amount | Total amount in cents |
overTender | amount | Overpayment amount in cents (change due) |
voided | boolean? | Tender line has been voided |
Card Payment
Section titled “Card Payment”When the tender is a card or mobile payment, the cardPayment object contains terminal transaction details.
| Field | Type | Description |
|---|---|---|
type | enum? | eft, mobilepay, or mobilepay_refund |
batchId | string? | Terminal batch identifier |
terminalTransId | string? | Terminal transaction identifier |
authNumber | string? | Authorization number |
cardNumber | string? | Masked card number |
cardName | string? | Card type name (e.g. “Visa”, “Mastercard”) |
archiveId | string? | Archive/reference identifier |
entryMethod | string? | How the card was read (chip, contactless, etc.) |
verification | string? | Verification method (PIN, signature, etc.) |
customerReceipt | string | Customer copy of the card receipt |
controlReceipt | string? | Merchant copy of the card receipt |
aid | string? | EMV Application Identifier |
tvr | string? | EMV Terminal Verification Results |
tsi | string? | EMV Transaction Status Information |
terminalName | string? | Payment terminal name |
terminalBatch | string? | Current terminal batch number |
attributes | object? | Additional terminal-specific attributes |
Tender Line Infocodes
Section titled “Tender Line Infocodes”Like sales lines, tender lines can have an infocodes array with information collected during payment (e.g. reference
number for invoice payments).
Returns and Refunds
Section titled “Returns and Refunds”A return receipt reverses a previous sale. It uses type: "SALES" with status: "voided", negative quantities on sales
lines, and negative amounts on tender lines. The originalReceiptNumber field links the return to the original receipt.
{ "id": "8c551a50-5ab6-ca47-7b48-799bb6f6e5e7", "type": "SALES", "void": false, "status": "voided", "timestamp": "2026-02-07T10:01:48.975Z", "receiptNumber": 577, "originalReceiptNumber": 575, "totalSales": -1780, "taxes": [ { "taxGuid": "ccb26d59-c76c-4126-a7e9-af9fcd3156a9", "taxName": "ALV 13.5%", "taxAmount": -212, "taxPercent": 14, "totalAmount": -1780, "taxlessAmount": -1568 } ], "salesLines": [ { "id": "0", "qty": -2, "price": 890, "productId": "2227", "productName": "Filling, Chicken Caesar", "amountTax": 106, "amountWithoutTax": 784 }, { "id": "2", "qty": -2, "price": 0, "productId": "2124", "productName": "Bagel, Cheese-Oregano", "amountTax": 0, "amountWithoutTax": 0 } ], "tenderLines": [ { "id": "1", "qty": 1, "amount": -1780, "total": -1780, "tenderId": "7bec3395-aeea-40a5-940d-027aa96cad17", "tenderGuid": "7bec3395-aeea-40a5-940d-027aa96cad17", "tenderName": "Wolt", "tenderType": "VOID", "overTender": 0 } ]}Key observations:
status: "voided": Marks this receipt as a return/refund. Note thatvoid: false— the receipt itself is valid, it is the original receipt that is being voided.originalReceiptNumber: References the receipt being returned (575 in this case).- Negative
qty: Sales lines have negative quantities (e.g.-2) indicating items being returned. - Positive
price: Unit prices remain positive — the negative total comes from the negative quantity. - Negative
totalSalesandtaxes: The receipt totals and tax amounts are all negative, reversing the original transaction. tenderType: "VOID": The tender line type isVOIDinstead ofTENDER, and the amount is negative, indicating money returned to the customer.- Tender is the refund method: The tender name indicates how the refund was processed (in this case back through the original delivery platform).