Skip to navigation

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

Legacy (v1)New (v3)
MethodPOSTPOST
Path/api/v1/checkout/api/v3/orders
AuthNone — channelId in the body only picks the retailerX-TT-API-Key, X-TT-Retailer and X-TT-Platform headers
Referencereference (basket)cartId
Price safetyNoneexpectedTotal must match the cart
Safe retryNot built inIdempotency-Key header
PaymentpaymentType rail + 3DS redirectUrlpayment.method from the set the cart advertises; a card challenge or a Klarna or Afterpay approval comes back as 402

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": "6aac14d3-5826-4da8-98b6-9e68c28629d6",
"expectedTotal": { "amount": 18500, "currency": "USD" },
"contact": {
"name": "John Smith",
"email": "john.smith@example.com",
"phone": "+12125550123"
},
"payment": { "method": "INVOICE" }
}

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

Legacy (v1)New (v3)Notes
shopper.firstName + lastName + titlecontact.nameOne field — send the full name
shopper.emailcontact.emailSame
shopper.telephoneNumbercontact.phoneE.164 format (+12125550123)
billingAddress / deliveryAddress(not sent)v3 doesn’t collect addresses at order time
deliveryMethod / deliveryCharge(on the cart)Delivery is priced into the cart’s total

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:

methodWhat it isLegacy paymentType
INVOICESettle on account, billed later — the usual path for B2B and reseller partners. Offered only to your secret key, on a retailer set up for it; see Payingaccount
CARDA card, freshly entered or saved on filecard, amex
APPLE_PAYApple Pay wallet token—
GOOGLE_PAYGoogle Pay wallet token—
KLARNABuy now, pay later — the shopper approves the purchase in Klarna’s widget—
AFTERPAYBuy now, pay later — the shopper approves the purchase on Afterpay’s own page (Clearpay in the UK, Cash App Afterpay in the US)—
NONENothing to pay — the cart total is zero—

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)

{
"data": {
"id": "1000123",
"confirmationNumber": "T123456789012",
"status": "COMPLETED",
"total": { "amount": 18500, "currency": "USD" },
"contact": { "name": "John Smith", "email": "john.smith@example.com" },
"items": [
{
"tickets": [
{ "barcode": { "value": "123456789", "format": "QR", "imageUrl": null } }
]
}
],
"receiptLines": [ ... ]
}
}

Key differences:

  • id is the order ID — stable and safe to store (see IDs)
  • confirmationNumber is the reference the customer quotes to support
  • status says whether the payment went through; PROCESSING means it is still settling (see After Checkout)
  • barcode.format is a code like QR, CODE128, or PDF417 — switch on it, and treat an unknown value gracefully
  • Tickets live under items[].tickets[], each with its own barcode
  • receiptLines[] is the record of charges and credits — render it in order, don’t recompute

Migration Checklist

  1. Replace POST /api/v1/checkout with POST /api/v3/orders, and send X-TT-API-Key, X-TT-Retailer and X-TT-Platform; drop channelId
  2. Send the cartId in place of the basket reference
  3. Collapse shopper.firstName / lastName / title into a single contact.name
  4. Map telephoneNumber to contact.phone in E.164 format
  5. Drop billingAddress / deliveryAddress and the delivery fields — delivery is priced into the cart; keep the billing postal code, as payment.postalCode
  6. Read the cart’s total and pass it through as expectedTotal, unchanged
  7. Set payment.method to one the cart advertises (INVOICE for pay-on-account); drop paymentType and the 3DS redirectUrl. paypal / alipay / wechatpay have no v3 equivalent
  8. Send an Idempotency-Key header (a UUID v4) so retries are safe
  9. Read tickets from items[].tickets[].barcode; handle a null barcode

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.