Till sales
Called with shop (retail) account keys. A key only sees its own account's data. Every example uses the same sample brand, order and item, so you can follow one item from call to call.
http://62.169.23.239:8001/api/v1Auth Bearer token3 endpointsEndpoints
Record a till sale#
Requires scope pos:write
Record an in-store checkout and issue the buyer's digital passport.
A line carrying a unit_token is a serialised item, so the sale transfers real ownership: it requires buyer_email (an existing consumer account), writes the consumer_items row, and queues the custody, activate and certificate legs on chain. Sale and passport share one transaction — neither commits without the other.
409 if a referenced unit is not in stock at this shop (already sold, removed, or belonging to another shop).
Request body
- source_terminalstring | null
- destinationstring | null
- line_itemsarray of objectsRequired
What was sold.
+Show 6 child attributesHide child attributes
- unit_tokenstring | null
The item's own token. It is what the item's QR code carries, and the id every item event uses.
- product_namestringRequired
- variant_labelstring | null
- skustring | null
Stock-keeping unit of the variant.
- unit_price_eurnumberRequired
Price of one unit in euro, including VAT.
- quantityinteger
Number of units.
Defaults to
1
- discount_kindstring | nullOne of
percentamount - discount_valuenumber | null
The rate/amount the worker entered — 0-100 when discount_kind is 'percent', a euro amount when 'amount'. Applied to the subtotal before VAT.
- buyer_emailstring | null
Buyer's account email — what the consumer reads out at the till. Resolved server-side to their internal user_id (stored as buyer_consumer_id on the transfer). Required when any line carries a unit_token — a serialised item cannot be sold into no account, or it leaves the shop as a passport orphan.
Returns
HTTP 201- transfer_idstringRequired
- source_terminalstring | null
- processed_attimestampRequired
- statusstringRequired
Current state of the object. See the allowed values.
One ofcompletedprocessingcancelled - line_itemsarray of objects
What was sold.
+Show 8 child attributesHide child attributes
- product_namestringRequired
- variant_labelstring | null
- skustring | null
Stock-keeping unit of the variant.
- unit_price_eurnumber
Price of one unit in euro, including VAT.
Defaults to
0 - quantityinteger
Number of units.
Defaults to
1 - subtotal_eurnumber
Defaults to
0 - unit_tokenstring | null
The item's own token. It is what the item's QR code carries, and the id every item event uses.
- consumer_item_idinteger | null
The consumer_items row this sale produced — present only for serialised lines. Its absence on a line that carries a unit_token means the item left the shop without a digital passport.
- subtotal_eurnumber
Defaults to
0 - discount_kindstring | nullOne of
percentamount - discount_valuenumber | null
- discount_eurnumber
Defaults to
0 - vat_rate_pctnumber
Defaults to
0 - vat_countrystring | null
- vat_eurnumber
Defaults to
0 - total_eurnumber
Total paid in euro, including VAT.
Defaults to
0 - buyer_consumer_idstring | null
- storeobject | null
Shop identity for receipts — sourced from retail_profiles + owner user.
+Show 5 child attributesHide child attributes
- store_namestring | null
- citystring | null
- countrystring | null
- glnstring | null
- emailstring | null
- buyerobject | null
Buyer identity when a consumer account was linked to the sale. No phone_number: consumers (users.role='Consumer') have no phone column anywhere in the schema — only email identifies them. Do not add a phone_number field here without first adding the column and a real collection point for it.
+Show 3 child attributesHide child attributes
- consumer_idstring | null
- namestring | null
- emailstring | null
curl -X POST http://62.169.23.239:8001/api/v1/retail/pos-transfers \
-H "Authorization: Bearer $SKANNIT_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"buyer_email": "customer@example.com",
"source_terminal": "till-1",
"line_items": [
{
"unit_token": "Qm7xK2pL9vR4tY8wZ1nB3c",
"sku": "TT-100-WHT-M",
"product_name": "Trail Tee",
"variant_label": "White / M",
"quantity": 1,
"unit_price_eur": 29.0
}
]
}'{
"transfer_id": "2bc6a10e-b83d-56a1-b614-53e022ba4c86",
"source_terminal": "till-1",
"processed_at": "2026-10-09T09:30:00Z",
"status": "completed",
"line_items": [
{
"product_name": "Trail Tee",
"variant_label": "White / M",
"sku": "TT-100-WHT-M",
"unit_price_eur": 29,
"quantity": 1,
"subtotal_eur": 29,
"unit_token": "Qm7xK2pL9vR4tY8wZ1nB3c",
"consumer_item_id": "7bf9462f-3324-593d-9012-c800e102b014"
}
],
"subtotal_eur": 29,
"discount_kind": "percent",
"discount_value": 24,
"discount_eur": 0,
"vat_rate_pct": 21,
"vat_country": "NL",
"vat_eur": 5.03,
"total_eur": 29,
"buyer_consumer_id": "b3a40984-b53d-50bf-b3de-f096ab2c40a8",
"store": {
"store_name": "Northwind Amsterdam",
"city": "Rotterdam",
"country": "NL",
"gln": "8712345000004",
"email": "ops@northwind.example"
},
"buyer": {
"consumer_id": "f4811030-eecf-579d-a105-e02ee601e044",
"name": "Northwind Apparel",
"email": "ops@northwind.example"
}
}List till sales#
Requires scope pos:read
Recent POS transfers / in-store checkout receipts for this shop.
Returns
HTTP 200- itemsarray of objects
The objects on this page.
+Show 6 child attributesHide child attributes
- transfer_idstringRequired
- transfer_typestringRequired
- source_terminalstring | null
- destinationstring | null
- processed_attimestampRequired
- statusstringRequired
Current state of the object. See the allowed values.
One ofcompletedprocessingcancelled
- totalinteger
Total count.
Defaults to
0
curl http://62.169.23.239:8001/api/v1/retail/pos-transfers \
-H "Authorization: Bearer $SKANNIT_TOKEN"{
"items": [
{
"transfer_id": "2bc6a10e-b83d-56a1-b614-53e022ba4c86",
"transfer_type": "sale",
"source_terminal": "till-1",
"destination": "in_store",
"processed_at": "2026-10-09T09:30:00Z",
"status": "completed"
}
],
"total": 1
}Retrieve a till sale#
Requires scope pos:read
Single POS transfer detail — line items, VAT, totals.
Parameters
- transfer_idstringpathRequired
Returns
HTTP 200- transfer_idstringRequired
- source_terminalstring | null
- processed_attimestampRequired
- statusstringRequired
Current state of the object. See the allowed values.
One ofcompletedprocessingcancelled - line_itemsarray of objects
What was sold.
+Show 8 child attributesHide child attributes
- product_namestringRequired
- variant_labelstring | null
- skustring | null
Stock-keeping unit of the variant.
- unit_price_eurnumber
Price of one unit in euro, including VAT.
Defaults to
0 - quantityinteger
Number of units.
Defaults to
1 - subtotal_eurnumber
Defaults to
0 - unit_tokenstring | null
The item's own token. It is what the item's QR code carries, and the id every item event uses.
- consumer_item_idinteger | null
The consumer_items row this sale produced — present only for serialised lines. Its absence on a line that carries a unit_token means the item left the shop without a digital passport.
- subtotal_eurnumber
Defaults to
0 - discount_kindstring | nullOne of
percentamount - discount_valuenumber | null
- discount_eurnumber
Defaults to
0 - vat_rate_pctnumber
Defaults to
0 - vat_countrystring | null
- vat_eurnumber
Defaults to
0 - total_eurnumber
Total paid in euro, including VAT.
Defaults to
0 - buyer_consumer_idstring | null
- storeobject | null
Shop identity for receipts — sourced from retail_profiles + owner user.
+Show 5 child attributesHide child attributes
- store_namestring | null
- citystring | null
- countrystring | null
- glnstring | null
- emailstring | null
- buyerobject | null
Buyer identity when a consumer account was linked to the sale. No phone_number: consumers (users.role='Consumer') have no phone column anywhere in the schema — only email identifies them. Do not add a phone_number field here without first adding the column and a real collection point for it.
+Show 3 child attributesHide child attributes
- consumer_idstring | null
- namestring | null
- emailstring | null
curl http://62.169.23.239:8001/api/v1/retail/pos-transfers/2bc6a10e-b83d-56a1-b614-53e022ba4c86 \
-H "Authorization: Bearer $SKANNIT_TOKEN"{
"transfer_id": "2bc6a10e-b83d-56a1-b614-53e022ba4c86",
"source_terminal": "till-1",
"processed_at": "2026-10-09T09:30:00Z",
"status": "completed",
"line_items": [
{
"product_name": "Trail Tee",
"variant_label": "White / M",
"sku": "TT-100-WHT-M",
"unit_price_eur": 29,
"quantity": 1,
"subtotal_eur": 29,
"unit_token": "Qm7xK2pL9vR4tY8wZ1nB3c",
"consumer_item_id": "7bf9462f-3324-593d-9012-c800e102b014"
}
],
"subtotal_eur": 29,
"discount_kind": "percent",
"discount_value": 24,
"discount_eur": 0,
"vat_rate_pct": 21,
"vat_country": "NL",
"vat_eur": 5.03,
"total_eur": 29,
"buyer_consumer_id": "b3a40984-b53d-50bf-b3de-f096ab2c40a8",
"store": {
"store_name": "Northwind Amsterdam",
"city": "Rotterdam",
"country": "NL",
"gln": "8712345000004",
"email": "ops@northwind.example"
},
"buyer": {
"consumer_id": "f4811030-eecf-579d-a105-e02ee601e044",
"name": "Northwind Apparel",
"email": "ops@northwind.example"
}
}