Recording Rules¶
How to represent common POS situations in POST /trade-records.
Amount identities¶
| Case | Identity |
|---|---|
Tax added on top (prices_include_tax = false) |
total = subtotal − discount + tax + service_charge + tip + rounding |
Tax included (prices_include_tax = true) |
total = subtotal − discount + service_charge + tip + rounding |
Records that do not satisfy the identity are still accepted and reported in the response warnings.
Combos and modifiers¶
| Situation | How to record it |
|---|---|
| Combo | One line for the combo itself (product_type = COMBO, combo price). One child line for every item in combo_components (including the main item), with parent_line_no pointing to the combo line and unit_price = "0.00". |
| Modifier with extra charge | Put the charge in the line's modifiers[].price_delta and include it in unit_price. Example: Fries 4.49 + Cheese Powder 0.75 → unit_price = "5.24". |
| Combo drink upgrade | The combo line's unit_price includes the upgrade, and its modifiers record the choice. The drink child line carries the drink actually served, with unit_price = "0.00". |
Item quantities
Combo child lines count toward item quantities but not toward item revenue — the revenue sits on the combo line.
Example: combo with drink upgrade¶
Master Jimbo Combo (14.49), upgraded to Taiwan Boba Tea (+3.50) → combo line unit_price = "17.99".
[
{ "line_no": 1, "parent_line_no": null, "product_id": "COMBO-02", "product_name": "Master Jimbo Combo", "product_type": "COMBO",
"quantity": "1", "unit_price": "17.99", "discount_amount": "0.00", "line_amount": "17.99", "tax_category": "STANDARD",
"modifiers": [
{ "group_id": "FLAVOR_JIMBO", "option_id": "SALT_PEPPER", "option_name": "Taiwanese Salt & Pepper", "quantity": "1", "price_delta": "0.00" },
{ "group_id": "COMBO_DRINK", "option_id": "DRK-BOBA", "option_name": "Taiwan Boba Tea", "quantity": "1", "price_delta": "3.50" }
], "is_voided": false },
{ "line_no": 2, "parent_line_no": 1, "product_id": "SGL-JIMBO", "product_name": "Master Jimbo", "product_type": "SINGLE",
"quantity": "1", "unit_price": "0.00", "discount_amount": "0.00", "line_amount": "0.00", "tax_category": "STANDARD", "modifiers": [], "is_voided": false },
{ "line_no": 3, "parent_line_no": 1, "product_id": "SIDE-FRIES", "product_name": "Fries", "product_type": "SIDE",
"quantity": "1", "unit_price": "0.00", "discount_amount": "0.00", "line_amount": "0.00", "tax_category": "STANDARD", "modifiers": [], "is_voided": false },
{ "line_no": 4, "parent_line_no": 1, "product_id": "DRK-BOBA", "product_name": "Taiwan Boba Tea", "product_type": "DRINK",
"quantity": "1", "unit_price": "0.00", "discount_amount": "0.00", "line_amount": "0.00", "tax_category": "STANDARD", "modifiers": [], "is_voided": false }
]
Exchanges (EXCHANGE)¶
The customer brings back a purchased item and swaps it for another in a single transaction, paying or receiving only the difference. Because one transaction contains both returned (negative) and new (positive) lines, the transaction type's amount_sign is null.
- Returned item: negative
quantityandline_amount. - New item: positive
quantityandline_amount. original_trade_record_idpoints to the original transaction.- Difference: collect it with
payment_type = SALEif the new item costs more; give it back withREFUNDif it costs less; leavepaymentsempty if equal.
Example: Fries (4.49) exchanged for Cheese Corn (5.49), collecting 1.00 before tax.
"items": [
{ "line_no": 1, "parent_line_no": null, "product_id": "SIDE-FRIES", "product_name": "Fries", "product_type": "SIDE",
"quantity": "-1", "unit_price": "4.49", "discount_amount": "0.00", "line_amount": "-4.49", "tax_category": "STANDARD", "modifiers": [], "is_voided": false },
{ "line_no": 2, "parent_line_no": null, "product_id": "SIDE-CHEESE-CORN", "product_name": "Cheese Corn", "product_type": "SIDE",
"quantity": "1", "unit_price": "5.49", "discount_amount": "0.00", "line_amount": "5.49", "tax_category": "STANDARD", "modifiers": [], "is_voided": false }
]
Tip
If your POS has no exchange function, send one RETURN transaction and one SALE transaction instead. HQ reports come out the same.
Refunds and changes to closed days¶
- Refunds keep the
business_dateof the original transaction. Record them withpayments[].payment_type = REFUNDandoriginal_trade_record_id. - Signs — in
RETURNandREFUNDtransactions, itemquantityandline_amountand the transaction amounts (subtotal_amount,discount_amount,tax_amount,total_amount, …) are negative. In anEXCHANGE, only the returned lines are negative. Paymentamountstays positive;payment_type = REFUNDgives the direction. This way the daily totals are simple sums. - Changing a transaction — resend the whole transaction with
version + 1. The highest version wins; with equal versions, the laterlast_modified_atwins. - Changing a business date that is already closed — resend the changed transaction (
version + 1) and resend that day's daily close with updated control totals and a newbatch_id.
order_type vs order_source¶
order_type describes how the order is fulfilled (dine-in, to go, pick-up, delivery). order_source describes where the order was placed. Record both:
| Situation | order_type | order_source | order_source_detail |
|---|---|---|---|
| Ordered at the counter, eaten in | DINE_IN | POS | — |
| Ordered at a kiosk, taken away | TO_GO | KIOSK | — |
| Uber Eats delivery | DELIVERY | DELIVERY_PLATFORM | UBER_EATS |
| Ordered on the website, picked up in store | PICK_UP | WEB | — |
order_source is a suggested list: values outside it are accepted. Send null (or omit it) when unknown — it is not assumed to be POS.
payment_type vs payment_method¶
payment_type describes what the money is for (sale, refund, deposit…). payment_method describes what was used to pay (cash, card, points…).
| Situation | payment_type | payment_method | payment_method_detail |
|---|---|---|---|
| Pay by VISA | SALE | CREDIT_CARD | VISA |
| Pay with loyalty points | SALE | LOYALTY_POINTS | e.g. POINTS:500 |
| Pay with a gift card | SALE | GIFT_CARD | — |
| Cash deposit for a cake order | DEPOSIT | CASH | — |
| Deposit applied at pick-up | DEPOSIT_APPLIED | CASH (same instrument as the deposit) | — |
| Return refunded to credit card | REFUND | CREDIT_CARD | VISA |
- Payment
amountis always positive; the direction comes frompayment_type(onlyADJUSTMENTmay be negative). payment_typevalues outside the suggested list are accepted, but HQ cannot tell their direction automatically and will review them manually. Tell HQ the meaning and direction of any custom value in advance.
Members¶
member_idis optional. Leave itnullor omit it for non-members.- It must be your loyalty system's internal ID — never a phone number, email address or national ID. If your system is keyed by phone number, send an internal sequence number or a salted hash.