Migration: Checkout to Orders
Guide for moving from the Encore API’s POST /api/v1/checkout flow to POST /api/v3/orders in the TTG Storefront API v3, the newer API. The two APIs number their versions separately.
For the full v1 checkout reference, see Checkout on the legacy portal.
Endpoint Comparison
What Changed
One cart, one contact, one payment
Legacy checkout took a wide BookingRequest — a shopper block, billingAddress and deliveryAddress, a delivery method and charge, a payment type, and 3DS redirect fields. v3 narrows it to what the order needs: the cart, the total you expect, a contact, and a payment method.
cartId is the UUID returned when you created the cart.
Headers
Legacy checkout needed no key. v3 needs the three headers in Authentication & Headers on every call.
Contact is one name field
To choose whether TTG emails the customer a confirmation, send sendConfirmationEmail; see Checkout.
Price is locked to the cart
Legacy trusted whatever the basket held. v3 makes you confirm the price, so the customer is never charged a price they didn’t see: read total from GET /api/v3/carts/{cartId} and send it unchanged as expectedTotal. A different amount returns 400 EXPECTED_TOTAL_MISMATCH; a different currency, 400 INVALID_FIELD_VALUE (see Currency).
The order settles in the cart’s currency. The POST /orders call can’t change it, so switch currency on the cart first with PATCH /api/v3/carts/{cartId} (see Currency).
Retries are safe
Legacy checkout had no retry protection — a network timeout could double-charge. Send an Idempotency-Key header on POST /api/v3/orders, a UUID v4 you make for each purchase attempt, so a retry after a timeout never buys twice. See Idempotency Keys.
Payment method
Legacy took a paymentType rail plus 3DS redirectUrl handling. v3 takes a payment object whose method is one of seven:
paypal, alipay, and wechatpay aren’t exposed on v3 today.
Don’t hardcode the method. Offer only the methods the cart lists. The rules for each, including when to send NONE, are in Paying. CARD, APPLE_PAY, and GOOGLE_PAY carry a payment token from the gateway (Adyen today); for the exact payment sub-object each method expects, see the Place an order endpoint in the API Reference. A card can still need the shopper to pass their bank’s check (3D Secure): the order then answers 402 PAYMENT_AUTHENTICATION_REQUIRED with the challenge in details.action, and you place it again with the result under a new Idempotency-Key (see Error Handling).
Send the billing postal code as payment.postalCode, whatever the method. It is optional, but it is the one address field the order keeps, so send it whenever you have collected one — with a wallet, KLARNA or AFTERPAY payment as much as with a card. payment.card.postalCode is still accepted on a CARD payment; when both are sent, payment.postalCode is used.
KLARNA and AFTERPAY appear only on a cart read with country, and take two calls, because the shopper approves the payment with Klarna or Afterpay. See Klarna and Afterpay.
Tickets and barcodes
On success the order carries the tickets. Each item in items[] has a tickets[] array, and each ticket has a barcode with its value, format, and an optional imageUrl. A barcode can be null for a while; see Tickets and barcodes.
Response Shape
New (v3)
Key differences:
idis the order ID — stable and safe to store (see IDs)confirmationNumberis the reference the customer quotes to supportstatussays whether the payment went through;PROCESSINGmeans it is still settling (see After Checkout)barcode.formatis a code likeQR,CODE128, orPDF417— switch on it, and treat an unknown value gracefully- Tickets live under
items[].tickets[], each with its ownbarcode receiptLines[]is the record of charges and credits — render it in order, don’t recompute
Migration Checklist
- Replace
POST /api/v1/checkoutwithPOST /api/v3/orders, and sendX-TT-API-Key,X-TT-RetailerandX-TT-Platform; dropchannelId - Send the
cartIdin place of the basketreference - Collapse
shopper.firstName/lastName/titleinto a singlecontact.name - Map
telephoneNumbertocontact.phonein E.164 format - Drop
billingAddress/deliveryAddressand the delivery fields — delivery is priced into the cart; keep the billing postal code, aspayment.postalCode - Read the cart’s
totaland pass it through asexpectedTotal, unchanged - Set
payment.methodto one the cart advertises (INVOICEfor pay-on-account); droppaymentTypeand the 3DSredirectUrl.paypal/alipay/wechatpayhave no v3 equivalent - Send an
Idempotency-Keyheader (a UUID v4) so retries are safe - Read tickets from
items[].tickets[].barcode; handle anullbarcode
Next Steps
This is the last step of the Purchase Flow. To handle failures cleanly, see Error Handling — including EXPECTED_TOTAL_MISMATCH, CART_EXPIRED, and which errors are safe to retry. Then read After Checkout to keep the cart ID, look the order up, and pick up barcodes.