Skip to content

Orders & Checkout

Understand the order lifecycle, hosted checkout, refunds, and how to verify completed purchases.

Orders are the core transaction model in Session Services. An order reserves inventory, collects payment through our hosted checkout, and generates tickets on completion.

Order Lifecycle

PENDING → PROCESSING → SUCCESSFUL
   │                        │
   └→ ABANDONED             └→ (refundable)

        └→ PENDING (re-reserve)
StatusMeaning
PENDINGInventory reserved, awaiting checkout completion
PROCESSINGPayment is being processed (immediate for free orders)
SUCCESSFULPayment confirmed, tickets generated
ABANDONEDReservation expired (10-minute window)
DISPUTEDChargeback filed by payment provider

Creating an Order

1. Get a Quote (Optional)

Preview pricing before committing. Quotes do not reserve inventory.

const { quote } = await client.order.quote({
  eventId: 'evt_01jps5cgsenjrazw6wswmyspa3',
  items: [
    {
      admissionId: 'adm_01jps5cgsee0xvapbk92e8eb4g',
      sectionId: 'sct_01jps5cgse0g3qj16kpq8t221r',
      quantity: 2,
    },
  ],
});

console.log(quote.price.total); // Total in cents
console.log(quote.price.currency); // "AUD"
curl -X POST https://api.session.services/orders/quote \
  -H "x-tenant-id: tnt_01jqpj2t2kfvmstt6f6tzkbaf2" \
  -H "Content-Type: application/json" \
  -d '{
    "eventId": "evt_01jps5cgsenjrazw6wswmyspa3",
    "items": [
      { "admissionId": "adm_01jps5cgsee0xvapbk92e8eb4g", "sectionId": "sct_01jps5cgse0g3qj16kpq8t221r", "quantity": 2 }
	    ]
	  }'

Price Breakdown

All values are in the smallest currency unit (e.g. cents).

FieldDescription
totalAmount the customer pays
grossTotal before discounts and refunds
baseTicket face value
bookingNon-refundable booking fee
shippingShipping costs (if applicable)
smsSMS delivery fee (if selected)
discountCoupon discount applied (negative value)
refundedRefunded amount (negative value)
gatewayAbsorbed gateway fees (negative value)
disputeDispute fees (negative value)
netAmount payable to the promoter
currencyISO 4217 currency code (e.g. AUD)

Negative amounts are represented as negative integers.

2. Create the Order

Creating an order reserves inventory for 10 minutes and returns a checkoutUrl for the hosted checkout page.

const { order } = await client.order.create({
  eventId: 'evt_01jps5cgsenjrazw6wswmyspa3',
  items: [
    {
      admissionId: 'adm_01jps5cgsee0xvapbk92e8eb4g',
      sectionId: 'sct_01jps5cgse0g3qj16kpq8t221r',
      quantity: 2,
    },
  ],
  returnUrl: 'https://yoursite.com/order/complete',
});

// Redirect the customer to checkout
window.location.href = order.checkoutUrl;
curl -X POST https://api.session.services/orders \
  -H "x-tenant-id: tnt_01jqpj2t2kfvmstt6f6tzkbaf2" \
  -H "Content-Type: application/json" \
  -d '{
    "eventId": "evt_01jps5cgsenjrazw6wswmyspa3",
    "items": [
      { "admissionId": "adm_01jps5cgsee0xvapbk92e8eb4g", "sectionId": "sct_01jps5cgse0g3qj16kpq8t221r", "quantity": 2 }
    ],
	    "returnUrl": "https://yoursite.com/order/complete"
	  }'

Applying a Coupon

Pass a couponCode to apply a discount:

const { order } = await client.order.create({
  eventId: 'evt_01jps5cgsenjrazw6wswmyspa3',
  items: [
    {
      admissionId: 'adm_01jps5cgsee0xvapbk92e8eb4g',
      sectionId: 'sct_01jps5cgse0g3qj16kpq8t221r',
      quantity: 2,
    },
  ],
  couponCode: 'TEST50',
  returnUrl: 'https://yoursite.com/order/complete',
});

Hosted Checkout

After creating an order, redirect the customer to the checkoutUrl. The hosted checkout page handles:

  • Customer details collection (name, email, phone)
  • Payment method selection (card, Apple Pay, Google Pay)
  • Payment processing
  • Order confirmation

You do not need to build any checkout UI — the hosted page handles the entire payment flow.

After Payment

When checkout completes, the customer is redirected to your returnUrl with the order ID and a signature appended:

https://yoursite.com/order/complete/{orderId}?sig={signature}

Use the order ID to fetch the completed order and display a confirmation:

const { order } = await client.order.get({ id: orderId });

if (order.status === 'SUCCESSFUL') {
  // Show confirmation with ticket details
}

Updating Customer Details

Hosted checkout collects customer details automatically. If you need to update customer info in a customer-facing flow, use order.update with the checkout signature (sig) returned to your returnUrl:

await client.order.update({
  id: orderId,
  signature: sig,
  customer: {
    firstName: 'Jane',
    lastName: 'Doe',
    email: 'test@session.services',
    phone: '+61412345678',
  },
});

SMS Ticket Delivery

If SMS delivery is enabled for the event, the order may include an offers entry with kind: "SMS_DELIVERY". To request SMS delivery, set a phone number and delivery method on the order:

await client.order.update({
  id: orderId,
  signature: sig,
  customer: {
    phone: '+61412345678',
    deliveryMethod: 'SMS',
  },
});

When SMS delivery is selected, the order price includes the sms fee.

Reservation Expiry

If the customer doesn’t complete checkout within 10 minutes, the order moves to ABANDONED and inventory is released.


Ticketing Element Checkout

If you use the Ticketing Element instead of creating orders via the API, the element handles the full flow automatically:

  1. Customer selects ticket quantities in the element
  2. Element creates the order and redirects to hosted checkout
  3. After payment, customer returns to your returnUrl

Listen for the checkoutInit event if you need to run logic before the redirect:

el.addEventListener('checkoutInit', (e) => {
  const { orderId, checkoutUrl } = e.detail;
  // Track analytics, save state, etc.
});

Refunds

Refunds can be full or partial. Refunded tickets are cancelled and inventory is restored.

Full Refund

const { refund } = await client.order.refund({
  id: 'ord_01jps5cgsfgve5b5g2666kyryh',
  fullRefund: true,
  reason: 'CUSTOMER_REQUEST',
});

Partial Refund

Specify individual items and quantities:

const { refund } = await client.order.refund({
  id: 'ord_01jps5cgsfgve5b5g2666kyryh',
  items: [{ orderItemId: 'itm_01jps5cgsfwyxj0516571eaf17', quantity: 1 }],
  reason: 'CUSTOMER_REQUEST',
  note: 'Customer requested single ticket refund',
});

Refund Options

FieldTypeDefaultDescription
fullRefundbooleanfalseRefund all remaining items
itemsarraySpecific items and quantities to refund
shippingAmountnumberShipping amount to refund in cents
cancelTicketsbooleantrueCancel associated tickets
notifybooleantrueSend refund notification email
reasonstringCUSTOMER_REQUEST, DUPLICATE, EVENT_CANCELLED, or OTHER
notestringFree-form explanation
idempotencyKeystringPrevent duplicate refund processing
metadataobjectKey-value pairs passed to the gateway

Refund Statuses

StatusMeaning
PENDINGCreated, awaiting payment gateway response
PROCESSINGGateway acknowledged, finalising
SUCCEEDEDRefund complete
FAILEDGateway rejected the refund

Booking fees are non-refundable. Only the base ticket price is refunded.


Resending Tickets

Resend the order confirmation and tickets to the customer (or to a different email):

await client.order.resend({
  id: 'ord_01jps5cgsfgve5b5g2666kyryh',
  email: 'test@session.services', // optional — defaults to the order email
});

The order must be in SUCCESSFUL status.


Re-reserving an Expired Order

If a customer’s reservation expires, you can attempt to re-reserve inventory:

const { order } = await client.order.reserve({
  id: 'ord_01jps5cgsfgve5b5g2666kyryh',
  signature: 'abc123def456',
});

This returns the order to PENDING status with a fresh 10-minute window. If inventory is no longer available, the API returns a 409 Conflict error.