Checkout walkthrough
Build the full reserve → checkout → redirect flow with the SDK.
This walks through a complete white-label checkout with the SDK. See the checkout flow concept for how the pieces fit together server-side.
Show the event and its tickets
const { data: event } = await client.getEvent('my-event')
const { data: gallery } = await client.getEventGallery('my-event')
const { data: tickets } = await client.listTickets('my-event')
renderHeadliners(event?.headliners ?? [])
renderGallery(gallery?.items ?? [])
// Only offer purchasable tickets
const purchasable = tickets.filter((t) => t.status === 'AVAILABLE')The event's headliners identify its public guests and performers. Gallery
items contain an imageURL and optional altText in stable creation order.
Each ticket carries live quantityLeft, formatted prices, and per-order limits
(maximumPurchasableTicketCount) to enforce in your UI.
Reserve the cart
Use one stable UUID per attendee as the deviceId (persist it in the browser)
so repeat calls refresh the same hold:
const deviceId = getOrCreateDeviceId() // e.g. crypto.randomUUID() in localStorage
const promoCode = form.promoCode.trim() || undefined
const { data: reservation } = await client.createReservation(
'my-event',
{
items: [{ sku: purchasable[0].id, quantity: 2 }],
promoCode,
},
{ deviceId },
)Drive the countdown
clientExpiresAt is the client-facing deadline for the hold:
const msLeft = new Date(reservation.clientExpiresAt).getTime() - Date.now()
startCountdown(msLeft, {
onExpired: () => promptToReserveAgain(),
})Display the priced cart from reservation.items, reservation.total, and
reservation.totalFees. When a promo code was accepted, use
reservation.promoCode and reservation.discount in the order summary.
Amounts are integers in the smallest currency unit
(Money). Do not calculate the discount locally; see
Promo codes.
Create the order
const { data: order } = await client.createOrder(
'my-event',
{
quoteReference: reservation.quoteReference,
email: form.email,
firstName: form.firstName,
lastName: form.lastName,
phone: form.phone,
callbackUrl: 'https://your-site/checkout/callback',
metadata: { seatPreference: 'front' }, // optional, echoed in the TICKET_PURCHASED webhook
},
{ deviceId: reservation.reservationToken },
)Handle the result
if (order.status === 'confirmed') {
// Free order: fulfilled immediately, order.reference is set
showConfirmation(order.reference)
} else {
// Paid order: send the attendee to the hosted payment page
window.location.href = order.checkoutUrl
}After payment, the attendee is sent to your callbackUrl with a reference
query parameter. Verify it on your callback page and show the confirmation.
Abandoned carts
Release the hold if the attendee bails out, so the stock frees up immediately:
await client.releaseReservation('my-event', { deviceId })Duplicate orders
Creating a second order for the same reservation returns a 409. Catch the
ApiError and treat it as "payment already in
progress".

