Buyer details and consent
/v1/events/{slug}/tickets/orders/{checkoutToken}Attach the buyer to the order: where the tickets go, and what they agreed to hear about. Required before pay or complete-free.
Print the wording we give you. The checkout block on ticket availability carries three consent labels. Show organiserEmail beside a box that is ticked by default (the buyer is becoming the organiser's customer, so this is a soft opt-in) and send the result as orgConsent.email with orgEmailBasis: "soft_opt_in". Show organiserMessaging beside an unticked box that needs a phone number, and send the one result as both orgConsent.sms and orgConsent.whatsapp. Show platformEmail beside its own box, ticked or not as platformEmailDefaultTicked says, and send the result as platformConsent.email with platformEmailBasis copied across. Then send the three strings back, verbatim, as consentTextSnapshot under the keys organiser, messaging and platform, with formVersion copied from the same block: that snapshot is the record of what was agreed to.
A channel you did not ask about is omitted, not sent as false. Omitted leaves a returning buyer's standing choice alone; false withdraws it.
Calling again replaces the details; it is safe to retry.
404 not_found for no visible reason.Request
curl -sS \
-X PATCH \
-H 'X-Grofomo-Key: pk_live_YOUR_PUBLISHABLE_KEY' \
-H 'Content-Type: application/json' \
-d '{"customer":{"email":"alex@example.com","firstName":"Alex","lastName":"Doe","phoneE164":"+447700900123"},"orgConsent":{"email":true,"sms":true,"whatsapp":true},"platformConsent":{"email":false},"orgEmailBasis":"soft_opt_in","platformEmailBasis":"consent","consentTextSnapshot":{"organiser":"We'll email you about future Riot Promotions shows, presales and lineup drops. Untick if you'd rather not - unsubscribe anytime.","messaging":"Be first in line: on-sale alerts, presale codes and last-minute ticket drops from Riot Promotions by SMS or WhatsApp. Reply STOP anytime to opt out.","platform":"Grofomo runs this checkout and delivers your tickets. Tick to get occasional email picks of similar events on Grofomo. Unsubscribe anytime."},"formVersion":"storefront-web-3"}' \
'https://api.grofomo.com/v1/events/summer-fest/tickets/orders/YzNhMWU1ZDctOWIyZi00ZTZhLThjMGQtMmY0YjZhOGMwZTEyOjE3ODk2NDM2MDAwMDA6dGt0LWNoZWNrb3V0.ZXhhbXBsZS1zaWduYXR1cmU?surface=web'Request body
customerobjectrequired- The buyer.
customer.emailemailrequiredcustomer.firstNamestringcustomer.lastNamestringcustomer.phoneE164stringorgConsentobjectrequired- What the buyer agreed to from the ORGANISER. Print `checkout.consent.organiserEmail` from the ticket feed beside a pre-ticked box (soft opt-in) and `organiserMessaging` beside an unticked one; send `sms` and `whatsapp` together from the messaging box.
orgConsent.emailbooleanorgConsent.smsbooleanorgConsent.pushbooleanorgConsent.postbooleanorgConsent.whatsappbooleanplatformConsentobjectrequired- What the buyer agreed to from GROFOMO, asked separately. Print `checkout.consent.platformEmail` from the ticket feed beside its own box and send only `email`.
platformConsent.emailbooleanplatformConsent.smsbooleanplatformConsent.pushbooleanplatformConsent.postbooleanplatformConsent.whatsappbooleanorgEmailBasis"consent" | "soft_opt_in"- How the organiser email box was shown: `soft_opt_in` when it was pre-ticked (the wording we give you assumes this), `consent` when the buyer had to tick it.
platformEmailBasis"consent" | "soft_opt_in"- How the Grofomo email box was shown. Send `checkout.platformEmailBasis` from the ticket feed.
consentTextSnapshotobject- The exact wording the buyer saw, keyed `organiser`, `messaging` and `platform`. Send the strings you printed, verbatim: they are stored as the proof of consent.
formVersionstring- Send `checkout.formVersion` from the ticket feed, so the stored consent names the wording it was given under.
answersobject[]- Answers to the organiser's registration questions. The questions are not published on this API yet, so leave this out; the hosted ticket page collects them.
answers[].questionIduuidrequiredanswers[].ticketIduuidanswers[].valuestring | number | boolean | string[]requiredlocalestring- The buyer's BCP 47 locale, e.g. `en-GB`, for the confirmation email. Optional.
Path parameters
slugstringrequired- The event's URL slug. Globally unique. It can change if the organiser renames the event, but an old slug keeps reaching the same event, so a stored one never breaks. Example: `summer-fest`.
checkoutTokenstringrequired- The order's `checkoutToken` from the reserve response. It authorises this checkout only and expires a day after the reserve; keep it out of logs and analytics. Example: `YzNhMWU1ZDctOWIyZi00ZTZhLThjMGQtMmY0YjZhOGMwZTEyOjE3ODk2NDM2MDAwMDA6dGt0LWNoZWNrb3V0.ZXhhbXBsZS1zaWduYXR1cmU`.
Query parameters
surface'web'required- Must be `web` for a website. Omit it and you get the mobile-app surface, which is gated on a different visibility setting — so a perfectly live event can return 404. Example: `web`.
Response
{
"apiVersion": 1,
"data": {
"ok": true
}
}okboolean- Always `true` on success.
Errors
unauthorizedHTTP 401- No key was sent and the organiser requires one — or the key is invalid, revoked, belongs to another organisation, or is scoped to a different event.
origin_not_allowedHTTP 403- Your site's domain is not on the organiser's allowed list. Browser calls only: a server sends no Origin header and is unaffected.
not_foundHTTP 404- No order for that `checkoutToken` on this event (or the token has expired), or no event with that slug on this surface.
bad_requestHTTP 400- The body did not match the schema, or messaging consent was sent without a phone number.
expiredHTTP 409- The 15-minute hold has ended. Start again from reserve.
order_not_openHTTP 409- The order is no longer `reserved`: it has been paid, completed or cancelled.
promo_not_yoursHTTP 409- The order's promo code was issued to a different email address.
consent_text_mismatchHTTP 400- The `consentTextSnapshot` differs from the wording the ticket feed publishes for this `formVersion`. Print the feed's text verbatim.
promo_customer_limitHTTP 409- This email address has used the promo code as many times as it may.
Notes
- Rate limited to roughly 30 requests per minute per caller. Guidance, not a contract — see caching and rate limits.
Cache-Control: no-store