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)
| Status | Meaning |
|---|---|
PENDING | Inventory reserved, awaiting checkout completion |
PROCESSING | Payment is being processed (immediate for free orders) |
SUCCESSFUL | Payment confirmed, tickets generated |
ABANDONED | Reservation expired (10-minute window) |
DISPUTED | Chargeback 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).
| Field | Description |
|---|---|
total | Amount the customer pays |
gross | Total before discounts and refunds |
base | Ticket face value |
booking | Non-refundable booking fee |
shipping | Shipping costs (if applicable) |
sms | SMS delivery fee (if selected) |
discount | Coupon discount applied (negative value) |
refunded | Refunded amount (negative value) |
gateway | Absorbed gateway fees (negative value) |
dispute | Dispute fees (negative value) |
net | Amount payable to the promoter |
currency | ISO 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:
- Customer selects ticket quantities in the element
- Element creates the order and redirects to hosted checkout
- 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
| Field | Type | Default | Description |
|---|---|---|---|
fullRefund | boolean | false | Refund all remaining items |
items | array | — | Specific items and quantities to refund |
shippingAmount | number | — | Shipping amount to refund in cents |
cancelTickets | boolean | true | Cancel associated tickets |
notify | boolean | true | Send refund notification email |
reason | string | — | CUSTOMER_REQUEST, DUPLICATE, EVENT_CANCELLED, or OTHER |
note | string | — | Free-form explanation |
idempotencyKey | string | — | Prevent duplicate refund processing |
metadata | object | — | Key-value pairs passed to the gateway |
Refund Statuses
| Status | Meaning |
|---|---|
PENDING | Created, awaiting payment gateway response |
PROCESSING | Gateway acknowledged, finalising |
SUCCEEDED | Refund complete |
FAILED | Gateway 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.