docs
/
EventOxygen

Tickets and bookings

How a purchase becomes tickets, how QR codes rotate, and what transfer, comp, fulfil, cancel and refund each do to the numbers.

A booking (event_booking) is the purchase. Tickets (event_ticket) are what it contains. Four tickets bought together are one booking with four tickets, one reference, one payment and one cancellation action.

Purchase rules, in order

The server validates each line of a purchase before it creates anything. The first failing rule is the error the buyer sees.

1. The ticket type is active. isActive !== false.

2. The sale window is open. saleStartDate ≤ now ≤ saleEndDate when set.

3. Capacity remains. capacity − soldCount must cover the quantity.

4. Per-order limit. maxPerOrder, default 10.

5. Per-customer limit. maxPerCustomer, counted across the buyer's existing tickets of that type that are not cancelled or refunded. Free ticket types default to one per customer.

If everything passes, the booking is created with a 9-character upper-case bookingRef. A zero total, or a payment reference already present, marks it isPaid and tickets are issued immediately. Otherwise the booking sits pending until the order is confirmed.

Booking lifecycle

StatusMeaning
pendingCreated, payment due. No tickets yet.
paid / confirmedPayment recorded (or free); tickets issued.
cancelledBooking and all its tickets cancelled; buyer notified.
refundedPayment returned; counts adjusted.
expiredA pending booking that was never paid.

confirm-order is idempotent: confirming a booking that is already paid is rejected rather than issuing a second set of tickets. That is what protects you when a payment webhook and the app both try to confirm.

The public lookup GET /client/events/booking?email=&bookingId= returns a booking to someone who knows both the email and the reference, which is how guest buyers find their tickets without an account.

Ticket statuses

pending → confirmed → checked_in, plus transferred, cancelled and refunded. A ticket's 12-character name is its public ticket id.

QR codes

The QR is not the ticket id. It is a signed payload ticketId:timestamp:signature produced from the ticket's hidden codeSecret, and it is only valid for 60 seconds by default. The attendee app fetches a fresh code (GET /client/events/tickets/:id/qr) when the ticket is opened, and the event can additionally rotate on an interval with qrRotationEnabled.

Every fulfilment and every transfer rotates codeSecret, which is why a forwarded screenshot stops working the moment the real holder does anything with the ticket. Validation rejects a malformed payload, an expired one, a bad signature, and any ticket in cancelled or refunded.

"Ticket already used" is usually re-entry

Re-entry is off by default on a ticket type. A valid attendee stepping back in after lunch is denied unless allowReentry is on. See ticket types.

Transfers

The attendee's "Assign to someone" and "Transfer" both call POST /client/events/tickets/:id/transfer with the recipient's email and optional name and reason. The server allows it only when:

  • the ticket is confirmed or already transferred;
  • the ticket type's allowTransfer is true (default false);
  • transferDeadline, if set, has not passed.

On success the transfer is appended to transfers[], the holder changes, status becomes transferred, the QR rotates, and the recipient is emailed a new code. Claimed perks travel with the ticket when transferPreservesPerks is true (the default).

Comps, stock and activation

Comp (POST /events/tickets/comp) issues tickets with no payment — speakers, staff, sponsors' guests.

Pre-generate (POST /events/tickets/pre-generate) creates pending tickets in bulk and increments soldCount up front, so printed stock is counted against capacity before anyone has bought. Activate (POST /events/tickets/:id/activate) turns one pending ticket into a confirmed one for a named holder, creates a paid booking, adds to revenue and sends the confirmation. Only a pending ticket can be activated.

Fulfilling at an accreditation point

POST /events/tickets/fulfill is the badge desk. The point must exist and be active; a walk-in needs allowWalkIn on that point, an online pickup needs allowOnlinePickup. Cancelled and refunded tickets are refused. Fulfilment rotates the QR, stamps fulfilledAt, fulfilledBy and accreditationPoint, and promotes pending to confirmed.

Will-call is GET /events/tickets/lookup/:eventId — search by name or reference, then fulfil, for people who bought and never opened the app.

Cancel, refund, delete

ActionTicketCountsNotifies
Cancel ticketcancelledNo change to sold counts or revenueevent-ticket-cancelled
Refund ticketrefundedsoldCount −1 (floored at 0), event totalTicketsSold and totalRevenue reducedevent-ticket-refunded
Delete ticketremovedStats restored first, then the record goes—
Cancel bookingall tickets cancelledAs cancelevent-order-cancelled
Refund bookingall tickets refundedAs refundevent-ticket-refunded

Cancel when you want the seat released but the money kept; refund when the money goes back. Delete is for mistakes, not for attendees.

Credentials

Physical credentials (event_credential) are wristbands, badges, lanyards, NFC tags, cards and stickers with a code format of barcode, QR, NFC, RFID or manual.

1. Import the codes ahead of time, singly or as a range (credentials/import, credentials/import-range). They start available.

2. Assign a code to a ticket on arrival (credentials/assign). A scan point set to matchBy: credential_code then accepts the wristband instead of the phone.

3. Revoke a lost one individually (credentials/:code/revoke). The ticket is untouched; only that code dies. Other statuses: damaged, lost.

Badges and perks

A badge is generated from a template for a ticket and, once printed, marked badgePrinted so a second badge cannot be issued against the same ticket without a deliberate reset.

Perks (perks[] on the ticket, seeded from the ticket type) are two-step: the attendee claims (perks/:perkId/claim) and staff fulfil (perks/:perkId/fulfill). Each claim records who, when and at which scan point, so drink tokens and meal vouchers reconcile at the end of the day. A perk with quantity exhausted fails the eligibility scan.

Notifications along the way

MomentTemplate
Tickets issued or a pending ticket activatedevent-ticket-confirmation
Ticket cancelledevent-ticket-cancelled
Ticket refundedevent-ticket-refunded
Booking cancelledevent-order-cancelled
Check-in recordedevent-checkin-confirmation
Event updatedevent-update to every non-cancelled holder
24 h and 1 h beforeevent-reminder

Templates are edited in Studio Manager; see notifications.