Grofomo API
Browse the docs

Examples use a fictional festival, summer-fest. Sign in at events.grofomo.com and they switch to your own events.

Prelaunch form

GET/v1/events/{slug}/prelaunch

The 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.

Send ?surface=webOmit it and the request is treated as coming from the mobile app, which is gated on a different visibility setting — so a perfectly live event can return 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

200 OK
{
  "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.
eventNamestring
hostEventNamestring | null
organiserNamestring | null
headlinestring | null
bodyTextstring | null
bodyDocobject | null
imageUrlstring | null
ctaLabelstring
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`).
closedboolean
privacyPolicyUrlstring | 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.
formVersionstring
fieldsobject
fields.firstNameobject
fields.firstName.requiredtrue
fields.emailobject
fields.email.requiredtrue
fields.phoneobject
fields.phone.enabledboolean
fields.phone.channels"sms" | "whatsapp"[]
fields.phone.requiredfalse
fields.phone.consentMode"checkbox" | "implied"
fields.postobject
fields.post.enabledboolean
consentobject
consent.emailstring
consent.messagingstring | null
consent.poststring | null
Generated from PrelaunchFormResponse

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.