Skip to main content
This guide explains how the Thanx basket lifecycle works end-to-end and how to diagnose the most common integration problems. It complements the Create & Update Basket endpoint reference with the behavioral context that most integrations need to pass certification on the first attempt. Who this is for:
  • Partners integrating the Loyalty API directly (POS, kiosk, online ordering)
  • Anyone troubleshooting missing points, $0 discounts, or unexplained basket behavior
What you’ll learn:
  • 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.
StateWhen to sendWhat Thanx doesRequired?
checkoutAny time the user modifies the basket or rewards pre-submissionValidates reward eligibility, returns updated discount amountsRequired
placedOrder has been submitted; user can no longer modifyLocks the reward; if using a points product, deducts the user’s points balanceRequired
billedPOS charged the card / payment was capturedCreates the purchase and accrues points. Reward is marked used.Required
completedOrder handed to the customerFinalizes the order recordRecommended
voidedOrder canceled between placed and billedRe-delivers locked reward; points products are not re-credited but reward stays availableRecommended
refundedOrder canceled after billedImmediately re-delivers the locked reward, and enqueues a deferred clawback of accrued loyalty points for the associated purchase. Points-product balances are not automatically re-credited.Recommended
Points are only created at billed. If your POS never transitions to billed, no purchase is created and no points accrue — even if checkout and placed succeeded.

Three Concepts Every Integration Must Get Right

1. Basket ID is partner-generated

The id 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 checkout requests 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:
payments[].amount = subtotal - tips - discounts
This means:
  • Do not send the order’s grand total (which includes tips and tax).
  • Do not send the items total (which doesn’t account for discounts).
  • Send the amount the customer actually paid toward loyalty-eligible goods.
If 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.
ScenarioCorrect price
Burger (10)+Extracheese(10) + Extra cheese (1.50)11.50
Coffee ($4) + no modifiers4.00
Combo (15)withdrinkupgrade(15) with drink upgrade (2)17.00

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.
EnvironmentBase URL
Sandboxhttps://loyalty.thanxsandbox.com/api/
Productionhttps://loyalty.thanx.com/api/
Do not use https://api.thanxsandbox.com/loyalty/* — it’s a different path that is not a supported entry point for 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) returns 401 "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 successful billed request and the purchase appearing in GET /account responses are common based on observed partner testing. Production is near real-time.
Before reporting “points not accruing” in sandbox, wait and re-check after tens of minutes. Most “missing points” sandbox tickets resolve themselves once the worker catches up.

Troubleshooting

Symptom: billed returns 201 but no purchase appears

Likely causeHow to verifyFix
Wrong Merchant-Key headerCheck the header value sent against the one your Thanx representative providedUse the hashid, not the numeric merchant ID
Missing payments[] on billedInspect the request body — is payments present and non-empty?Include payments with amount, last4, issuer
Sandbox latencyConfirm time since requestRe-check after tens of minutes; sandbox processing is slower than production
Wrong base URLCheck outgoing URLUse loyalty.thanxsandbox.com/api/, not api.thanxsandbox.com/loyalty/

Symptom: Item-level reward discount is $0

Likely causeHow to verifyFix
items[].price does not include modifier pricesCompare sent price against POS receiptSend base + modifier total
items[].id mismatches the reward template’s item IDsCompare against the reward template’s productsUse the exact IDs Thanx issued

Symptom: Points accrue for the wrong amount

Likely causeHow to verifyFix
payments[].amount includes tips or taxCompute subtotal - tips - discounts and compareSend subtotal - tips - discounts
payments[].amount reflects the grand totalSame as aboveSame

Symptom: Basket ID keeps changing between calls

Your system is generating a new UUID per request instead of reusing the one from checkout. Generate the ID once when checkout starts, persist it, and send the same value on every state transition.

Before You Certify

Use the Pre-Certification Self-Check checklist for your integration type (POS/Kiosk, Consumer UX, Pay-at-Table) to confirm your basket flow is correct before submitting for certification. The checklist mirrors the scenarios in this guide.