Jetron TicketFluid

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".

On this page