Order form template that takes payment
Short answer: this is a complete QuizGen JSON definition for a small-business order form — customer details, product picks, a pickup or delivery date — with a native Stripe payment question at the end so the order and the payment happen in the same step. POST it as-is (with your own products and prices) and you get a hosted order page at a short link. If you haven't connected Stripe yet, skip to the fallback section below — the rest of the template still works.
This is what an order form template is for: not a full storefront, but a single link you can text or post that takes someone from "I want one" to "paid" for a fixed, simple catalog — pre-orders, custom orders, small runs, event merch. For the wider case — what a hosted order form does that a printable one can't, and where it stops — see https://quizgen.dev/online-order-form.
The template
A print shop taking custom t-shirt orders, priced by quantity:
{
"schema_version": 1,
"kind": "form",
"title": "Riverside Print Co. — order form",
"description": "Custom screen-printed shirts. Payment is collected when you submit.",
"settings": {
"collect_respondent": "email_required",
"completion": {
"message": "Thanks! We'll confirm your order and pickup or delivery time by email."
}
},
"sections": [
{
"key": "order",
"title": "Your order",
"questions": [
{ "id": "customer_name", "type": "short_text", "prompt": "Your name",
"required": true },
{ "id": "phone", "type": "phone", "prompt": "Phone number",
"required": true, "help": "In case we need to reach you about your order." },
{ "id": "style", "type": "choice", "prompt": "Which shirt are you ordering?",
"required": true,
"options": [
{ "value": "crew_tee", "label": "Crew neck tee" },
{ "value": "hoodie", "label": "Hoodie" },
{ "value": "tank", "label": "Tank top" },
{ "value": "long_sleeve", "label": "Long sleeve" }
] },
{ "id": "fulfillment", "type": "choice", "prompt": "Pickup or delivery?",
"required": true,
"options": [
{ "value": "pickup", "label": "Pickup at the shop" },
{ "value": "delivery", "label": "Local delivery" }
] },
{ "id": "delivery_address", "type": "short_text", "prompt": "Delivery address",
"required": true,
"show_if": { "question": "fulfillment", "op": "eq", "value": "delivery" } },
{ "id": "needed_by", "type": "date", "prompt": "Date you need it by",
"required": true },
{ "id": "notes", "type": "long_text", "prompt": "Design details, logo placement, colors",
"help": "Attach nothing here — just describe it. We'll follow up by email if we need a file.",
"rows": 4 }
]
},
{
"key": "payment",
"title": "Payment",
"questions": [
{ "id": "package", "type": "payment",
"prompt": "Choose your quantity and pay now", "required": true,
"price_options": [
{ "value": "single", "label": "1 shirt", "amount_cents": 2500 },
{ "value": "five_pack", "label": "5-pack", "amount_cents": 11000,
"detail": "$22 each" },
{ "value": "ten_pack", "label": "10-pack", "amount_cents": 20000,
"detail": "$20 each" },
{ "value": "twenty_pack", "label": "20-pack (event size)", "amount_cents": 38000,
"detail": "$19 each" }
],
"button_label": "Pay & confirm order" }
]
}
]
}
What each piece is doing
kind: "form"— the order shows on one page (not one question per screen), which matches how people expect to fill in an order.collect_respondent: "email_required"— this is the "customer contact" field. You don't need a separateemailquestion; the address is captured automatically and attached to the response.styleis achoicequestion. Note that every style costs the same here — see the rule below about why it has to.fulfillmentis achoice, anddelivery_addressonly appears when they pick delivery, viashow_if.needed_byis adatequestion — always prefer it over a text field for dates; the answer comes back as"YYYY-MM-DD".packageis the onepaymentquestion this quiz is allowed to have.price_options(2–10 of them) is the right choice here instead of a singleamount_cents, because the respondent is picking their quantity and paying the exact amount for it — one dropdown, one charge, no separate invoice step.
The one rule to keep: price_options is the only place quantity lives
There is deliberately no separate "How many shirts?" question in this
template, and that is the most important thing to copy. A form takes one
payment question, and that question charges exactly the amount_cents of
the option the customer picked — nothing else on the form can change the
total. So the moment you add a free-entry field that also implies a price,
the two can disagree and the charge always wins:
A
numberquestion asking "How many shirts?" alongside aprice_optionslist is a trap. The customer types 20, picks the 1 shirt — $25 option, and the form accepts it. The order arrives withpaid: trueagainst $25 for twenty shirts, and the only way to catch it is for a human to read every row.
The same trap catches per-option surcharges. If style had a "Hoodie
+$15" label, picking the hoodie would still charge the plain bundle price,
because price_options is the entire pricing model — labels are text, not
arithmetic. Either fold the surcharge into the price list (a "5-pack
hoodies" option at its real price) or charge one price across styles, as
this template does.
The rule that follows: anything that changes what someone owes belongs in
price_options, and nowhere else. Questions outside the payment question
are for things you need in order to fulfil the order — style, colour,
address, deadline, notes — not for things that determine the total. If your
combinations won't fit in ten price options, that is the signal to reach for
a real store rather than to add a quantity box.
Payment needs Stripe — here's the fallback
The payment question type is live on every plan, including free, but
only after the creator finishes Stripe onboarding at quizgen.dev/dashboard/payments. Until
that's done, creating a quiz with a payment question returns a 402
payments_not_ready error. Money always goes to the creator's own Stripe
account — QuizGen takes a 2% platform fee on top, nothing more.
If you haven't connected Stripe yet, the rest of this template still works —
just drop the payment section and pick one of two fallbacks:
- Collect now, invoice after. Take the order with everything above, then send an invoice with the total and a payment link once you've confirmed details (custom sizing, design proofs, whatever needs a human look first).
- Redirect to an external payment link. Add
"completion": { "redirect_url": "https://buy.stripe.com/YOUR_LINK" }tosettingsand the respondent lands on your existing Stripe Payment Link or PayPal.me page right after submitting. You lose the "pick your size, pay the right amount" convenience ofprice_options, but the order and the payment still happen in one flow.
Either fallback is a completely normal way to run this template — plenty of small shops will use redirect links even after they're eligible for native payment, especially if they already have Stripe Payment Links set up.
Reading orders back
GET /api/v1/quizzes/:id/responses returns each order's answers (style,
package, fulfillment, notes) plus, for a paid order, paid: true and the
Stripe payment_intent id — that's what you reconcile against your Stripe
dashboard if a number ever looks off. Filter with ?complete=true to skip
abandoned carts.
For same-day routing, don't poll — set a webhook on the quiz. Every completed order POSTs itself to your endpoint the moment it's paid, so you can push it straight into your fulfillment queue, a Slack channel, or a spreadsheet instead of checking the dashboard.
When a real store is the better tool
Be honest with yourself about the size of the catalog before reaching for this. QuizGen's order form is for a fixed, simple catalog — a handful of products or package sizes, no per-item options exploding into hundreds of SKUs. It has no inventory tracking, no variant matrix (size × color × style all at once), and no shipping-rate calculator. If you need any of those — real inventory counts, a cart with multiple line items, calculated shipping — use Shopify or Square; they're built for exactly that and it would be a mistake to fight this template into doing their job. Reach for this template instead for pre-orders, custom one-off orders, small production runs, and event merch — the cases where "one page, one payment, done" is the whole requirement.
Let an AI assistant fill it in
Connect QuizGen's MCP server and say:
Read https://quizgen.dev/blog/order-form-template.md and make me an order form for my candle shop: 3 scents, one size, $18 each, pickup only, needed-by date, and a notes field for gift messages. I'm already connected to Stripe.
The assistant adapts the products and prices, POSTs the definition, and hands back the live link.
FAQ
Can I sell more than one product in the same order? Change style to
multi_choice so people can select several items, but keep the payment
question's price_options as fixed bundles or package sizes — there's no
per-line-item cart math, so price each option as a complete order. If
selecting a second item is supposed to cost more, that difference has to
appear as its own price option; a multi_choice selection can't add to the
total on its own.
How do I let someone order a quantity I didn't list? You don't — not in
the same submission. Add a "More than 20 / custom quantity" choice option
with no price attached and show_if a notes field off it, then quote them
separately with an invoice. A form charges one
listed amount; anything negotiated needs a second step.
What happens if someone abandons before paying? The response is saved
with complete: false and no paid field. Nothing is charged, and nothing
ships — you can safely ignore incomplete responses when you tally orders.
Can I cap how many orders I take? Yes — "max_responses": 50 in
settings closes the form automatically once you hit it, which is exactly
what a limited production run needs.
Does the order form need to be a quiz? No — kind: "form" renders
everything on one page, which is what people expect from an order form.
kind is advisory only; anything you set in settings overrides it.
$ curl quizgen.dev/blog/order-form-template.md
This guide as raw markdown — no HTML for your agent to parse.
Keep reading
- Quote template your client can approve in one clickNot a document to email — a hosted quote with a recorded approval.
- Event registration form template (with paid tickets)Ticket tiers, a capacity cap, and card payment on the registration page.
- Customer satisfaction survey template (with NPS)The NPS question is a 0–10 scale — here's the whole survey around it.