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

FieldSample ValueReq/OptDescription
source{}requiredSource of the sale. See source object below.
state"closed"requiredState of the sale. One of: parked, pending, closed, voided. More about states and attributes.
date"2016-05-05T23:35:34Z"optionalSale timestamp in RFC3339 format. Defaults to the time the request is received.
customer_id"06e35f89-..."optionalID of the customer associated with this sale.
attributes["delivery"]optionalArray of sale attributes. Valid values: onaccount, layby, delivery, pickup, service. More about states and attributes.
note"VIP customer"optionalA note on the sale entered by the cashier.
short_code"mlzs94"optionalShort unique code used for loyalty tracking purposes. Must be unique if provided.
invoice_number"MR-1484-NZ"optionalInvoice number. If omitted, one will be assigned automatically.
pricing{}optionalSale-level pricing including adjustments.
line_items[]optionalArray 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[]optionalArray of payments. See payment object below.
fulfillment_details[]optionalFulfillment details for DISPATCH or PICKUP sales. See fulfillment details below.
_metadata{}optionalAdditional metadata. See metadata object below.

The source object

FieldSample ValueReq/OptDescription
author_id"020b2c2a-..."requiredID of the user (cashier) who created the sale. Retrieve from /api/{version}/users.
register_id"b1e198a9-..."optionalID of the register where the sale was created.
id"EXT-001"optionalID of the sale in an external system.
type"Magento"optionalIdentifier of the external system the id belongs to.

The line item object

FieldSample ValueReq/OptDescription
product.id"5d4fcfa8-..."requiredID of the product.
quantity1requiredQuantity of the product.
pricing.price22requiredUnit price of the line item, tax exclusive.
pricing.cost20optionalUnit cost used for margin calculations.
pricing.discount0optionalDiscount value for the line item.
pricing.loyalty_amount2.0optionalLoyalty value to be added to the customer's balance.
tax.id"b1d192bc-..."requiredID of the tax. Retrieve from /api/{version}/taxes. For tax-free items use the ID of the tax named "No Tax".
tax.amount3.3requiredUnit tax value for the line item.
status"CONFIRMED"optionalSet to CONFIRMED to make the line item read-only for pending sales.
source.author_id"b1ed6158-..."optionalID of the salesperson for this line item. Only needed when different from the sale author.
source.register_id"b1e198a9-..."optionalID of the register used to add this line item.

The payment object

FieldSample ValueReq/OptDescription
type.config_id"dd4d174f-..."requiredPayment type ID. Retrieve from /api/{version}/payment_types.
amount25.3requiredPayment amount.
date"2016-05-05T23:35:34Z"optionalPayment timestamp in RFC3339 format. Defaults to the time of the request.
source.register_id"b1e198a9-..."optionalID of the register where the payment was accepted.

Fulfillment details

Required for dispatch (delivery attribute) or pickup (pickup attribute) sales.

FieldSample ValueReq/OptDescription
type"DISPATCH"optionalFulfillment type. One of: DISPATCH, PICKUP.
note"Leave at door"optionalA note for the fulfillment.
shipping_address_id"2031472964637822976"optionalID of the shipping address for DISPATCH fulfillments.
shipping_address_token"CB3K47K3ZZ8g..."optionalToken of a newly created shipping address. Use instead of shipping_address_id when the address was just created.

Metadata

FieldSample ValueReq/OptDescription
_metadata.xero_reference"INV-001"optionalXero invoice reference ID. Only editable for onaccount sales.
_metadata.invoice.sequence1484optionalNumeric part of the invoice number.
_metadata.invoice.resolve_numbertrueoptionalWhether 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 1 to 2) — identified by its id.
  • The second line item is new — no id, so it will be appended.
  • The payment is updated (amount changed from 25.3 to 50.6) — identified by its id.