Prelaunch form
/v1/events/{slug}/prelaunchThe prelaunch form an organiser has published for the event in the path (the event being registered for): the copy, which fields to ask, and the exact consent wording to print beside them. The hosted page at events.grofomo.com/prelaunch/{slug} renders the same thing; use this to render it in your own design instead.
Print the consent wording verbatim. Registering is the email consent, so consent.email goes beside the submit button; consent.post labels the postal checkbox. The register endpoint snapshots this wording as the proof of consent, so a paraphrase makes the record wrong.
consent.messaging is rendered two ways, and fields.phone.consentMode says which. Under checkbox it is the label for a tick box beside the number, and you send the result as consentSms. Under implied there is no tick: print it as a NOTICE immediately beside the number field and send no consentSms at all, because submitting an optional number and confirming the texted code is itself the consent. Put an implied notice anywhere else, in a footer or behind a link, and you have broken the thing that makes it valid, which is that one deliberate act covers one channel.
Never make the number required. fields.phone.required is always false and is a promise rather than a formality. A mandatory number would make the messaging consent a condition of registering when it is not needed to register, and a consent that is not freely given is not consent, so the list you build on it is not usable.
404 not_found when the organiser has no published prelaunch form for the event. closed turns true once closesAt has passed, after which registrations are refused with 410 closed.
404 not_found for no visible reason.Request
curl -sS \
-H 'X-Grofomo-Key: pk_live_YOUR_PUBLISHABLE_KEY' \
'https://api.grofomo.com/v1/events/summer-fest/prelaunch?surface=web'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`.
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": {
"eventSlug": "twisted-roots-2027",
"eventName": "Twisted Roots 2027",
"hostEventName": "Twisted Roots 2026",
"organiserName": "EVA Events",
"headline": "Be first for 2027",
"bodyText": "Register now for tickets, presales and news.",
"bodyDoc": null,
"imageUrl": null,
"ctaLabel": "Email me about tickets",
"successMessage": "You're on the list. We'll email you with tickets, presales and news.",
"closesAt": null,
"closed": false,
"privacyPolicyUrl": "https://www.evaevents.co.uk/privacy",
"formVersion": "prelaunch_form_v5",
"fields": {
"firstName": {
"required": true
},
"email": {
"required": true
},
"phone": {
"enabled": true,
"channels": [
"sms",
"whatsapp"
],
"required": false,
"consentMode": "checkbox"
},
"post": {
"enabled": false
}
},
"consent": {
"email": "Registering signs you up for email updates about Twisted Roots 2027, plus other events from EVA Events. Unsubscribe anytime.",
"messaging": "Be first in line: updates about Twisted Roots 2027, plus other events from EVA Events, by SMS or WhatsApp. Reply STOP anytime to opt out.",
"post": null
}
}
}eventSlugstring- The event being registered for. Post registrations to the same slug.
eventNamestringhostEventNamestring | nullorganiserNamestring | nullheadlinestring | nullbodyTextstring | nullbodyDocobject | nullimageUrlstring | nullctaLabelstring- Submit button text.
successMessagestring- What to show once the registration is confirmed; the register response repeats it.
closesAtstring | null- ISO instant after which registrations are refused (410 `closed`).
closedbooleanprivacyPolicyUrlstring | null- The ORGANISER's own privacy notice, which they set in their Grofomo legal settings and attest to. Link it beside the consent wording: they are the controller for what this form collects, so Grofomo's policy does not cover it. Null only where they have not set one, which the console blocks for a published form.
formVersionstringfieldsobjectfields.firstNameobjectfields.firstName.requiredtruefields.emailobjectfields.email.requiredtruefields.phoneobjectfields.phone.enabledbooleanfields.phone.channels"sms" | "whatsapp"[]fields.phone.requiredfalsefields.phone.consentMode"checkbox" | "implied"fields.postobjectfields.post.enabledbooleanconsentobjectconsent.emailstringconsent.messagingstring | nullconsent.poststring | null
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 event with that slug is published on this surface. Check the slug, and check you sent `?surface=web`.
Notes
- Rate limited to roughly 60 requests per minute per caller. Guidance, not a contract — see caching and rate limits.