What’s public, what’s not
Anything visitor-facing is in the public set. Anything that mutates the event itself requires auth.
Prerequisites
The event must be:status: PUBLISHEDisPublic: true
404 for draft or non-public events. This is intentional — the public surface only exposes what the admin has chosen to share.
Step 1 — Fetch event details
attendeeCount and maxCapacity are the inputs for rendering a “87 of 200 seats taken” indicator. Everything else is straightforward — render as you like.
Step 2 — Check live availability
attendeeCount from Step 1 is correct at fetch time, but stale within seconds on busy events. For real-time availability:
Step 3 — Hold tickets while the buyer fills the form
For paid events, hold tickets the moment the buyer starts filling the form — otherwise two people could submit checkout at the same time and only one’s payment succeeds.Step 4 — Save attendee details
Once the buyer fills in the form (name, email, ticket-type selection), submit:save-attendees directly — the seat reservation happens here in one shot.
Step 5 — Take payment (paid events only)
The save-attendees response includes a Stripe checkout URL. Redirect the buyer:success_url configured on the checkout session (or Orgo’s default attendee-confirmation page). At that point the ProductPayment is SUCCESS and you can finalize:
Step 6 — Show “thanks for registering” with the QR
After completion, fetch the attendee record to render the QR code (or the email contains a deep link to a public view):Showing capacity and time-zone correctly
dateTimeBegin and dateTimeEnd are ISO 8601 timestamps in UTC. The event also includes timezone (an IANA name like America/New_York). Render the date in the event’s timezone (it’s an in-person event), not the visitor’s:
Adding to-calendar buttons
Build .ics manually from the public event data. Don’t link to a hosted Orgo .ics — there’s no public endpoint for it; visitors building their own client are expected to generate locally:Common gotchas
My public page caches event data — sold-out events show as available
My public page caches event data — sold-out events show as available
Cache the event details (Step 1) for ~5 minutes. Never cache
availability (Step 2) — call it fresh on every render. The capacity number can change second-to-second.Buyers complete the form but never reach checkout
Buyers complete the form but never reach checkout
Browser JS pop-up blockers can swallow the
window.location redirect to Stripe. Use a server-side redirect (302) instead of client-side window.location = checkoutUrl. Or use a regular <a href> link styled as a button.Attendees aren't appearing in admin even though save-attendees returned 200
Attendees aren't appearing in admin even though save-attendees returned 200
For paid events, attendance is
PENDING until payment completes via /complete. The admin UI hides pending until they pay (or filters them under “abandoned carts”). Wait for the event_attend.updated webhook with status: NEW to know the registration is confirmed.Can I let users edit their registration later?
Can I let users edit their registration later?
Each attendee gets a magic-link in their confirmation email. The link uses
X-Contact-Hash auth (see Authentication) and gives access to the attendee’s own record only. Build a public page that consumes those endpoints if you want a self-service “update my details” surface.What to do next
- Create and sell event tickets — the admin-side setup that produced this event
- Process payments — payment reconciliation after Stripe completes
- Handle webhooks — react to new registrations server-side

