# Event registration form template (with paid tickets)

Short answer: this is a complete QuizGen JSON definition for a conference or
workshop registration — attendee details, a session pick, dietary needs, a
code-of-conduct agreement, and paid ticket tiers collected with a native
`payment` question. POST it as-is and you get a hosted registration page at
a short link; nobody creates an account, and payment settles straight to
your own Stripe account.

This is the canonical example of `kind: "registration"`. Registration is a
task someone needs to finish, not a survey to work through — so the
`registration` kind hides the progress bar and keeps everything on one page
by default, instead of stepping people through screen after screen like a
quiz. You're saying "fill this in and you're done," not "here's question 1
of 9."

## The template

Replace the event name, dates, session options, ticket prices, and
`redirect_url`/webhook details before posting. This uses Stripe Connect
payment collection, which needs the Business plan and a one-time Stripe
onboarding step — see the payment section below for the fallback if you're
not there yet.

```json
{
  "schema_version": 1,
  "kind": "registration",
  "title": "Register: DevBridge Conference 2026",
  "description": "October 14–15, Grand Rapids Convention Center.",
  "settings": {
    "collect_respondent": "email_required",
    "max_responses": 300,
    "close_at": "2026-10-07T23:59:00Z",
    "completion": {
      "message": "You're registered — a confirmation and your ticket receipt are on the way."
    }
  },
  "sections": [
    {
      "key": "attendee",
      "title": "Your details",
      "questions": [
        { "id": "full_name", "type": "short_text", "prompt": "Full name",
          "required": true, "placeholder": "Jordan Smith" },
        { "id": "email", "type": "email", "prompt": "Email address",
          "required": true, "placeholder": "you@company.com" },
        { "id": "track", "type": "choice", "prompt": "Which track are you registering for?",
          "required": true,
          "options": [
            { "value": "engineering", "label": "Engineering", "detail": "Architecture, infra, and platform talks" },
            { "value": "product", "label": "Product", "detail": "Roadmapping, discovery, and launch talks" },
            { "value": "design", "label": "Design", "detail": "Systems, research, and craft talks" }
          ] },
        { "id": "dietary", "type": "choice", "prompt": "Any dietary requirements for the catered meals?",
          "required": true,
          "options": [
            { "value": "none", "label": "No restrictions" },
            { "value": "vegetarian", "label": "Vegetarian" },
            { "value": "vegan", "label": "Vegan" },
            { "value": "other", "label": "Other (tell us below)" }
          ],
          "follow_up": "What should the caterer know?" },
        { "id": "conduct", "type": "consent",
          "prompt": "I've read and agree to the event code of conduct.",
          "required": true }
      ]
    },
    {
      "key": "ticket",
      "title": "Your ticket",
      "questions": [
        { "id": "ticket_type", "type": "payment",
          "prompt": "Choose your ticket",
          "required": true,
          "price_options": [
            { "value": "early_bird", "label": "Early bird", "amount_cents": 14900,
              "detail": "Ends September 15" },
            { "value": "standard", "label": "Standard", "amount_cents": 19900,
              "detail": "September 16 onward" },
            { "value": "student", "label": "Student", "amount_cents": 7900,
              "detail": "Valid student ID required at check-in" }
          ],
          "button_label": "Pay and register" }
      ]
    }
  ]
}
```

## What each piece is doing

- `kind: "registration"` — hides the progress bar and defaults to one page
  instead of one question per screen. A conference sign-up isn't a survey
  someone browses through; it's a task with a clear end, so the layout
  should feel like a single form, not a multi-step wizard. (Advisory only —
  anything you set explicitly under `settings` still wins.)
- `track` — a plain `choice` question. Simple and sortable; if you need
  people to see room capacity or time slots, put that detail in the
  option's `detail` line.
- `dietary` + `follow_up` — picking "Other" reveals a one-line free-text
  box (saved as `dietary__followup`) instead of adding a whole extra
  question that most attendees would skip. If you'd rather branch to a full
  question, use `show_if` on a dedicated `long_text` instead — both
  patterns are valid, `follow_up` is just less to build for a one-liner.
- `conduct` — a required `consent` question. It records a timestamped
  "yes" tied to the response; there's no separate signature, just an
  attributable agreement.
- `ticket_type` — a `payment` question using `price_options` instead of a
  single `amount_cents`, so the respondent picks their tier and Stripe
  charges the right amount automatically. Each option can carry a
  `detail` line for pricing conditions (cutoff dates, ID requirements).
- `settings.max_responses: 300` — the hard capacity cap. Once registrations
  hit 300, the page stops taking new ones regardless of `close_at`.
- `settings.close_at` — the registration deadline, independent of
  capacity. Whichever limit is hit first wins.

## The payment question, in detail

`payment` is a real question type, not a redirect: the respondent enters
card details inline and the charge happens as part of submitting the form.
A few things worth knowing before you use it:

- **Business plan only** ($49/mo), and the account has to finish Stripe
  onboarding at [quizgen.dev/dashboard/payments](/dashboard/payments)
  first. If onboarding isn't done, the create call fails with 402
  `payments_not_ready`.
- **Maximum one `payment` question per quiz.** If you need multiple
  add-ons, use `price_options` to let people pick one bundle, or collect
  add-on choices with a `choice`/`multi_choice` question and total it up
  yourself before invoicing separately.
- Money settles to the creator's own Stripe account — QuizGen never holds
  the funds — and QuizGen takes a 2% platform fee on top of Stripe's own
  processing fee.
- `required: true` (as used above) blocks final submission until the
  charge succeeds, so you can't end up with a "registered but unpaid" row.
- On the response, a successful payment stores `"paid": true` and a
  `payment_intent` id you can reconcile against your Stripe dashboard.
- **No Business plan yet, or not onboarded?** Drop the `payment` question,
  collect the registration as free, and either invoice separately or send
  people to an external payment link via
  `settings.completion.redirect_url` — the same pattern used in the
  [invoice template](/blog/invoice-template).

## What respondents see at the cap or deadline

Once `max_responses` is reached or `close_at` passes, the hosted page
switches to "no longer accepting responses" — nobody gets to the payment
step on a sold-out event. Anything still hitting the API directly gets back
`410 quiz_full` (capacity) or `quiz_closed` (deadline). Responses already
collected, paid or not, stay fully readable afterward.

## Registration vs. a plain RSVP

If you just need a free headcount — "are you coming, yes or no, how many
guests" — use the simpler
[event RSVP form with a response cap](/blog/event-rsvp-form-with-response-cap)
instead. This template is for the fuller case: named attendees, session or
track selection, and paid tickets. Both use the same `max_responses` /
`close_at` capacity mechanism; the difference is what you're collecting and
whether money changes hands.

## When Eventbrite is the better tool

Be honest about the ceiling here: for a multi-track conference with printed
badges, on-site check-in scanning, seat-level session capacity, and
complex ticketing rules (group discounts, waitlists, transfers), Eventbrite
is genuinely the better tool — that's its whole product. QuizGen's
registration template is the right fit for a single-payment, single-form
sign-up: a workshop, a meetup, a small conference where "paid and on the
list" is the entire requirement. If you outgrow that, export your
responses and move to a dedicated event platform rather than bolting
check-in features onto a form.

## Customize it with an AI assistant

Because the template is plain JSON against a documented schema, an AI
assistant with [QuizGen's MCP server](/mcp)
connected can adapt it directly. For example:

> Read https://quizgen.dev/blog/event-registration-form-template.md and
> build me a registration form for a one-day photography workshop, 40 seats,
> $85 flat ticket price, registration closes October 1. Give me the live
> link.

## FAQ

**Can I skip payment and still use `kind: "registration"`?** Yes — the
`kind` only affects layout, not whether a `payment` question is present.
Drop the `ticket_type` section entirely for a free registration.

**Can different sessions have different capacity?** Not per-option —
`max_responses` caps the whole quiz, not a specific `choice` option. If a
single track needs its own cap, run it as a separate quiz.

**Does the code-of-conduct agreement need to be its own question?** It
doesn't strictly, but keeping it as a required `consent` gives you a
timestamped record independent of the ticket purchase — useful if you ever
need to show someone agreed before the charge went through.

**What if someone's payment fails?** They stay on the page and can retry;
nothing is recorded until the charge succeeds, so there's no partial or
"unpaid" response cluttering your list.
