Sales 101
Sales 101
Sales can be created by making a POST request to the /api/{version}/sales endpoint. This guide covers the payloads that can be used to create a sale.
The endpoint returns the created sale in the response body. To update an existing sale, use PUT /api/{version}/sales/{id}, which returns the updated sale in the same response shape.
Minimal payload
Here's a minimal payload to create a valid closed sale:
{
"source": {
"author_id": "020b2c2a-4661-11f0-e88b-1afde45e0728"
},
"state": "closed",
"line_items": [{
"product": {
"id": "5d4fcfa8-0ac1-4a6a-adc2-da1d66f4b8f7"
},
"quantity": 1,
"pricing": {
"price": "12"
},
"tax": {
"id": "b1d192bc-f019-11e3-a0f5-b8ca3a64f8f4",
"amount": "1.8"
}
}]
}Full payload with explanation
{
"source": {
"register_id": "b1e198a9-f019-11e3-a0f5-b8ca3a64f8f4",
"author_id": "020b2c2a-4661-11f0-e88b-1afde45e0728"
},
"date": "2016-05-05T23:35:34Z",
"customer_id": "06e35f89-3783-11e6-ec7e-13193f7bd2ed",
"state": "closed",
"attributes": [],
"note": "",
"short_code": "mlzs94",
"invoice_number": "MR-1484-NZ",
"line_items": [{
"product": {
"id": "5d4fcfa8-0ac1-4a6a-adc2-da1d66f4b8f7"
},
"quantity": 1,
"pricing": {
"price": "22",
"cost": "20",
"discount": "0",
"loyalty_amount": "0"
},
"tax": {
"id": "b1d192bc-f019-11e3-a0f5-b8ca3a64f8f4",
"amount": "3.3"
},
"status": "CONFIRMED"
}],
"payments": [{
"type": {
"config_id": "dd4d174f-669d-4483-972a-1484242e1227"
},
"date": "2016-05-05T23:35:34Z",
"amount": "25.3"
}]
}Definitions
The sale object
| Field | Sample Value | Req/Opt | Description |
|---|---|---|---|
source | {} | required | Source of the sale. See source object below. |
state | "closed" | required | State of the sale. One of: parked, pending, closed, voided. More about states and attributes. |
date | "2016-05-05T23:35:34Z" | optional | Sale timestamp in RFC3339 format. Defaults to the time the request is received. |
customer_id | "06e35f89-..." | optional | ID of the customer associated with this sale. |
attributes | ["delivery"] | optional | Array of sale attributes. Valid values: onaccount, layby, delivery, pickup, service. More about states and attributes. |
note | "VIP customer" | optional | A note on the sale entered by the cashier. |
short_code | "mlzs94" | optional | Short unique code used for loyalty tracking purposes. Must be unique if provided. |
invoice_number | "MR-1484-NZ" | optional | Invoice number. If omitted, one will be assigned automatically. |
pricing | {} | optional | Sale-level pricing including adjustments. |
line_items | [] | optional | Array of line items. See line item object below. When updating a sale, all existing line items must be included or they will be deleted. |
payments | [] | optional | Array of payments. See payment object below. |
fulfillment_details | [] | optional | Fulfillment details for DISPATCH or PICKUP sales. See fulfillment details below. |
_metadata | {} | optional | Additional metadata. See metadata object below. |
The source object
| Field | Sample Value | Req/Opt | Description |
|---|---|---|---|
author_id | "020b2c2a-..." | required | ID of the user (cashier) who created the sale. Retrieve from /api/{version}/users. |
register_id | "b1e198a9-..." | optional | ID of the register where the sale was created. |
id | "EXT-001" | optional | ID of the sale in an external system. |
type | "Magento" | optional | Identifier of the external system the id belongs to. |
The line item object
| Field | Sample Value | Req/Opt | Description |
|---|---|---|---|
product.id | "5d4fcfa8-..." | required | ID of the product. |
quantity | 1 | required | Quantity of the product. |
pricing.price | 22 | required | Unit price of the line item, tax exclusive. |
pricing.cost | 20 | optional | Unit cost used for margin calculations. |
pricing.discount | 0 | optional | Discount value for the line item. |
pricing.loyalty_amount | 2.0 | optional | Loyalty value to be added to the customer's balance. |
tax.id | "b1d192bc-..." | required | ID of the tax. Retrieve from /api/{version}/taxes. For tax-free items use the ID of the tax named "No Tax". |
tax.amount | 3.3 | required | Unit tax value for the line item. |
status | "CONFIRMED" | optional | Set to CONFIRMED to make the line item read-only for pending sales. |
source.author_id | "b1ed6158-..." | optional | ID of the salesperson for this line item. Only needed when different from the sale author. |
source.register_id | "b1e198a9-..." | optional | ID of the register used to add this line item. |
The payment object
| Field | Sample Value | Req/Opt | Description |
|---|---|---|---|
type.config_id | "dd4d174f-..." | required | Payment type ID. Retrieve from /api/{version}/payment_types. |
amount | 25.3 | required | Payment amount. |
date | "2016-05-05T23:35:34Z" | optional | Payment timestamp in RFC3339 format. Defaults to the time of the request. |
source.register_id | "b1e198a9-..." | optional | ID of the register where the payment was accepted. |
Fulfillment details
Required for dispatch (delivery attribute) or pickup (pickup attribute) sales.
| Field | Sample Value | Req/Opt | Description |
|---|---|---|---|
type | "DISPATCH" | optional | Fulfillment type. One of: DISPATCH, PICKUP. |
note | "Leave at door" | optional | A note for the fulfillment. |
shipping_address_id | "2031472964637822976" | optional | ID of the shipping address for DISPATCH fulfillments. |
shipping_address_token | "CB3K47K3ZZ8g..." | optional | Token of a newly created shipping address. Use instead of shipping_address_id when the address was just created. |
Metadata
| Field | Sample Value | Req/Opt | Description |
|---|---|---|---|
_metadata.xero_reference | "INV-001" | optional | Xero invoice reference ID. Only editable for onaccount sales. |
_metadata.invoice.sequence | 1484 | optional | Numeric part of the invoice number. |
_metadata.invoice.resolve_number | true | optional | Whether to resolve the invoice number automatically. |
Taxes
The tax.amount and tax.id must always be provided for each line item.
Tax IDs can be retrieved from /api/{version}/taxes. All retailers have a special tax named "No Tax" for tax-free items — use its id with "amount": 0.
Response
Create and update requests return the saved sale wrapped in a top-level data object. The response includes generated fields such as the sale id, receipt and invoice values, calculated totals, line item totals, payment details, adjustments, eCommerce custom charges, and metadata.
{
"data": {
"id": "506e5602-0a02-a9f1-11ec-d53d3e8661a6",
"date": "2026-05-28T17:27:47+00:00",
"invoice_number": "3",
"short_code": "bp2Kis",
"state": "closed",
"note": "Promotion discount of 20% applied",
"source": {
"id": null,
"type": "USER",
"register_id": "06326976-9d65-11ec-fa40-cfcea2505075",
"outlet_id": "06326976-9d65-11ec-fa40-cfcea24f09c6",
"author": {
"id": "06326976-9d65-11ec-fa40-cfcea250a465"
}
},
"customer_id": "0698ab21-5f38-11f0-e2ca-36fd67fae24d",
"attributes": ["delivery"],
"payments": [{
"id": "506e5602-0a02-a9f1-11ec-d53d81003442",
"date": "2026-05-28T17:27:47+00:00",
"amount": 48,
"type": {
"id": "1",
"name": "Cash",
"config_id": "c73614ec-a2db-4a5d-8436-9e46c4fc35ee"
},
"source": {
"id": null,
"register_id": "06326976-9d65-11ec-fa40-cfcea2505075",
"outlet_id": "06326976-9d65-11ec-fa40-cfcea24f09c6"
},
"surcharge": {
"rule": "",
"amount": 0.72
},
"external_attributes": [{
"source": "stripe",
"card_last_four_digits": "4242",
"transaction_id": "ch_3OabcXYZ",
"card_brand": "visa"
}],
"external_applications": [{
"application_id": "app_01HXYZ",
"external_id": "ext-payment-9001",
"created_at": "2026-05-28T17:27:47+00:00",
"updated_at": "2026-05-28T17:27:47+00:00"
}],
"deleted_at": null,
"billing_address_id": null,
"_metadata": {
"register_open_sequence_id": "06326976-9d38-11ec-fa40-cfcea25ec8c4"
}
}],
"line_items": [{
"id": "506e5602-0a02-a9f1-11ec-d53d576e4448",
"quantity": 1,
"product": {
"id": "1ee9b9a5-6616-4f90-a030-0ccc29d7a8e4"
},
"pricing": {
"price": 48,
"total": 48,
"discount": 12,
"discount_total": 12,
"cost": 40,
"cost_total": 40,
"loyalty_amount": 0,
"loyalty_amount_total": 0
},
"tax": {
"id": "06326976-9d65-11ec-fa40-cfcea247a383",
"amount": 0,
"total": 0
},
"status": "CONFIRMED",
"promotions": [{
"id": "1526252563421200384",
"name": "Promotion One 20%",
"amount": -12,
"promo_code": null,
"promo_code_id": null
}],
"return": {
"is_return": false,
"reason": null
},
"note": null,
"gift_card_number": null,
"salesperson_id": null,
"surcharges": [{
"value": 1.5,
"tax_components": [{
"rate_id": "a2481b6b-cfce-11ec-ba40-063269769d65",
"total_tax": 0.1
}]
}],
"customizations": [{
"id": "0242ac12-0003-11e9-e8c4-659494e99103",
"name": "Date Picker",
"field_type": "date_picker",
"value": "2026-01-31",
"files": [{
"id": "0242ac12-0003-11e9-e8c4-659494e99201",
"filename": "monogram.png",
"size": 12345,
"provider": "s3"
}]
}],
"_metadata": {
"sequence": 0,
"is_price_override": false,
"tax_components": [{
"rate_id": "a2481b6b-cfce-11ec-ba40-063269769d65",
"total_tax": 0
}]
}
}],
"return": {
"is_return": false,
"original_sale_id": null,
"return_sale_ids": []
},
"taxes": [{
"id": "a2481b6b-cfce-11ec-ba40-063269769d65",
"tax": 0
}],
"totals": {
"price": 48,
"tax": 0,
"price_incl_tax": 48,
"loyalty": 0,
"surcharge": 0
},
"adjustments": [{
"adjustment_type": "NON_CASH_FEE",
"name": "Non-cash Fee",
"total": 1.5,
"tax_components": [{
"rate_id": "00000000-0000-0000-0000-000000000005",
"total_tax": 0.1
}]
}],
"external_applications": [{
"application_id": "app_01HXYZ",
"external_id": "ext-sale-12345",
"version": "1",
"created_at": "2026-05-28T17:27:47+00:00",
"updated_at": "2026-05-28T17:27:47+00:00"
}],
"ecom_custom_charges": [{
"source_id": "abc123",
"total": 8,
"name": "my ecom custom charge",
"tax_components": [{
"rate_id": "00000000-0000-0000-0000-000000000005",
"total_tax": 2
}],
"total_tax": 2,
"total_incl": 10
}],
"receipt_number": "3",
"created_at": "2026-05-28T17:28:14+00:00",
"updated_at": "2026-05-28T17:28:14+00:00",
"deleted_at": null,
"_metadata": {
"xero_reference": null,
"version": 22446763475,
"complete_open_sequence_id": null,
"has_unsynced_on_account_payments": null
}
}
}The response does not include pagination or version wrappers. Some fields can be null or omitted depending on the sale contents, feature flags, and the authenticated user's permissions.
Updating a sale
To update an existing sale, use PUT /api/{version}/sales/{id}. The payload is identical to the POST request but without the sale id in the body — it is provided in the URL instead. The response returns the updated sale using the same data wrapper shown above.
Updating line items and payments
To update an existing line item or payment, you must include its id in the payload. Without the id, a new line item or payment will be appended to the sale instead.
To get the id values of existing line items and payments, first call GET /api/{version}/sales/{id}.
{
"source": {
"register_id": "b1e198a9-f019-11e3-a0f5-b8ca3a64f8f4",
"author_id": "020b2c2a-4661-11f0-e88b-1afde45e0728"
},
"state": "closed",
"line_items": [
{
"id": "506e5602-0a02-a9f1-11ec-d53d576e4448",
"product": { "id": "5d4fcfa8-0ac1-4a6a-adc2-da1d66f4b8f7" },
"quantity": 2,
"pricing": { "price": "22", "cost": "20", "discount": "0", "loyalty_amount": "0" },
"tax": { "id": "b1d192bc-f019-11e3-a0f5-b8ca3a64f8f4", "amount": "3.3" },
"status": "CONFIRMED"
},
{
"product": { "id": "5d4fcfa8-0ac1-4a6a-adc2-da1d66f4b8f7" },
"quantity": 1,
"pricing": { "price": "22", "cost": "20", "discount": "0", "loyalty_amount": "0" },
"tax": { "id": "b1d192bc-f019-11e3-a0f5-b8ca3a64f8f4", "amount": "3.3" },
"status": "CONFIRMED"
}
],
"payments": [
{
"id": "506e5602-0a02-a9f1-11ec-d53d81003442",
"type": { "config_id": "dd4d174f-669d-4483-972a-1484242e1227" },
"date": "2016-05-05T23:35:34Z",
"amount": "50.6"
}
]
}In the example above:
- The first line item is updated (quantity changed from
1to2) — identified by itsid. - The second line item is new — no
id, so it will be appended. - The payment is updated (amount changed from
25.3to50.6) — identified by itsid.
Updated 6 days ago
