- Partners integrating the Loyalty API directly (POS, kiosk, online ordering)
- Anyone troubleshooting missing points, $0 discounts, or unexplained basket behavior
- How a basket moves through its states and what the API does at each transition
- Which fields drive points accrual, and when they must be sent
- The three most common integration mistakes and how to fix them
- How to debug a basket that returned 201 but produced no purchase
The Basket State Machine
A basket is an object partners manage across several API calls. Each call updates the basket’s state, and points are only accrued at a specific transition. For the full state diagram, see the Create & Update Basket endpoint reference.Three Concepts Every Integration Must Get Right
1. Basket ID is partner-generated
Theid field in the basket payload is an identifier your system creates. Thanx does not return a new ID — you reuse the same value across every state transition so the API can correlate the updates to a single basket.
- Generate once when the user starts checkout.
- Reuse for every subsequent request (
placed,billed,completed, etc.). - Only
checkoutrequests may omit the ID; every other state requires it.
A common mistake is interpreting the endpoint reference (“Basket ID is not required when submitting a basket with ‘checkout’ state”) to mean the API assigns the ID. It does not. If you generate a new ID for each request, each basket is treated as a separate order and points will not accrue correctly.
2. payments[].amount drives points accrual — not items[] or the grand total
Points are calculated from the sum of payments[].amount values on the billed request. The formula is:
- Include tax; exclude tips.
- Do not send the order’s grand total (which includes tips).
- Do not send the items total (which doesn’t account for discounts or tax).
- A gift-card load/reload is not a purchase — exclude it, so a load-only transaction is correctly $0 loyalty-eligible. Paying with a gift card is a normal purchase and stays eligible.
payments is missing or empty on the billed request, no purchase is created. The API will return 201 but nothing lands downstream.
3. items[].price must include modifier prices
When you send items, the price for each item must be the final item price including any modifiers (base price + modifier prices). Sending price: 0 or the base-only price causes item-level discount rewards to calculate a $0 discount.
Endpoint URLs: Sandbox vs. Production
The Loyalty API lives on a dedicated subdomain. Using the wrong base URL returns 404s or routes to an unrelated service that will not accept basket requests.Required Headers
See Loyalty API Headers for the full list. Two headers cause the majority of “why are my baskets silently lost” tickets:Merchant-Key— the merchant hashid (e.g.,example-hashid-from-your-rep), not the numeric merchant ID. Sending a numeric ID (or any value that isn’t a valid hashid) returns401 "The Merchant-Key header is missing or invalid"— no basket or purchase is created. Your Thanx representative provides the correct key during onboarding.User-Agent— must identify your integration; some auth paths reject generic values.
Sandbox Testing: Expected Latency
Sandbox purchase processing is noticeably slower than production. Delays of several minutes up to tens of minutes between a successfulbilled request and the purchase appearing in GET /account responses are common based on observed partner testing. Production is near real-time.
Troubleshooting
Symptom: billed returns 201 but no purchase appears
Symptom: Item-level reward discount is $0
Symptom: Points accrue for the wrong amount
Symptom: Basket ID keeps changing between calls
Your system is generating a new UUID per request instead of reusing the one fromcheckout. Generate the ID once when checkout starts, persist it, and send the same value on every state transition.