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.

Form definition

GET/v1/forms/{key}

A published form's definition — its fields, types, labels and validation — so you can render it in your own design instead of embedding a hosted page.

Artist-picker fields arrive with their options already filled in from the event's lineup.

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/forms/volunteer-signup?surface=web'

Path parameters

keystringrequired
The form's key, from the organiser's console. Example: `volunteer-signup`.

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": {
    "key": "volunteer-signup",
    "kind": "contact",
    "eventId": "6f1c8e2a-4b3d-4c9e-9f21-8a7d5e0b1c34",
    "eventSlug": "summer-fest",
    "title": "Volunteer with us",
    "version": 3,
    "surface": "web",
    "fields": [
      {
        "id": "full_name",
        "type": "text",
        "label": "Your name",
        "required": true
      },
      {
        "id": "email",
        "type": "email",
        "label": "Email address",
        "required": true,
        "role": "email"
      },
      {
        "id": "shifts",
        "type": "checkbox",
        "label": "Which shifts can you cover?",
        "help": "Pick as many as you like.",
        "required": true,
        "options": [
          {
            "value": "friday-evening",
            "label": "Friday evening"
          },
          {
            "value": "saturday-morning",
            "label": "Saturday morning"
          },
          {
            "value": "sunday-close",
            "label": "Sunday close"
          }
        ]
      },
      {
        "id": "favourite_act",
        "type": "artist_multiselect",
        "label": "Anyone you would love to work near?",
        "required": false,
        "source": "lineup",
        "options": [
          {
            "value": "9c7e5a3b-1f0d-4b2e-8a6c-4d2f0b8e6a13",
            "label": "Nala Vex"
          },
          {
            "value": "d1f3b5a7-9c2e-4d80-8b6f-5a3c1e7d9b04",
            "label": "Sonny Delrey"
          }
        ]
      }
    ]
  }
}
keystring
The form key. Post submissions back to this same key.
kind"feedback" | "mailing_list" | "contact" | "merch_enquiry"
What the form is for.
eventIduuid | null
Null for an organisation-wide form not tied to one event.
eventSlugstring | null
titlestring
versionnumber
Definition version. Send it back with the submission so the answers can be audited against it.
surface"app" | "web"
fieldsobject[]
The questions, in the organiser's order.
fields[].idstring
Key this answer under this id when you submit.
fields[].type"rating" | "radio" | "checkbox" | "select" | …
Which control to render.
fields[].labelstring
The question, as the organiser wrote it.
fields[].helpstringmay be absent
Hint text to show under the control.
fields[].requiredbooleanmay be absent
Absent means optional.
fields[].role"overall_rating" | "venue_rating" | "would_return" | "favourite_artist" | … | nullmay be absent
What the answer means to Grofomo, e.g. `email` promotes it to the contact address.
fields[].optionsobject[]may be absent
Choices for a radio, checkbox, select or artist picker. Submit the `value`, display the `label`.
fields[].options[].valuestring
fields[].options[].labelstring
fields[].minnumbermay be absent
Lower bound of a rating.
fields[].maxnumbermay be absent
Upper bound of a rating.
fields[].source"lineup" | "stages" | "merch_items"may be absent
merchCatalogobject[]may be absent
merchCatalog[].valuestring
Product id. Matches the option value on a `merch_items` form field.
merchCatalog[].namestring
merchCatalog[].garmentTypestring
What the garment is, e.g. "Heavyweight cotton t-shirt".
merchCatalog[].descriptionstring | null
merchCatalog[].pricePenniesnumber
Unit price in minor units, so 2500 is £25.00.
merchCatalog[].currencystring
ISO 4217 code, e.g. "GBP".
merchCatalog[].sizesstring[]
Available sizes, in display order.
merchCatalog[].coloursobject[]
Colourways. Each carries the PLAIN garment image; overlay the event logo yourself.
merchCatalog[].colours[].labelstring
Colourway name, e.g. "Bone".
merchCatalog[].colours[].hexstring | null
Swatch colour, for a colour picker.
merchCatalog[].colours[].frontImageUrlstring | null
Plain garment front, with no logo applied.
merchCatalog[].colours[].backImageUrlstring | null
Plain garment back, with no logo applied.
merchCatalog[].colours[].logoColorstring | nullmay be absent
How to treat the logo on this colourway: `auto`, `brand`, `white` or `black`.
merchCatalog[].colours[].outOfStockbooleanmay be absent
Show the colourway, but do not let anyone buy it.
merchCatalog[].printZonesobject[]
Where to place the logo on each side. All coordinates are 0–1 fractions, so a preview scales freely.
merchCatalog[].printZones[].side"front" | "back"
merchCatalog[].printZones[].xnumber
Centre of the logo, as a 0–1 fraction of the garment image width.
merchCatalog[].printZones[].ynumber
Centre of the logo, as a 0–1 fraction of the garment image height.
merchCatalog[].printZones[].scalenumber
Logo width, as a 0–1 fraction of the garment image width.
merchCatalog[].printZones[].recolorbooleanmay be absent
merchCatalog[].printZones[].logoUrlstring | nullmay be absent
A logo specific to this placement. Absent means use the event logo.
merchCatalog[].printZones[].logoColorstring | nullmay be absent
`auto`, `brand`, `white` or `black`.
merchCatalog[].printZones[].clipbooleanmay be absent
Mask the logo to the garment silhouette, so a wide placement does not bleed off the edge.
merchCatalog[].outlineobject[]may be absent
Traced garment silhouette (0–1 points) driving the `clip` mask. Absent means use a default tee shape.
merchCatalog[].outline[].xnumber
merchCatalog[].outline[].ynumber
Generated from PublicFormResponse

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.