# Grofomo API > Build an event website on live festival data. Read-only JSON feeds for an event's published lineup, FAQs, news, announcements, ticket availability and merch, plus light writes for mailing-list signups and forms. Three things to get right before writing any code: - Send `?surface=web` on every request. It defaults to the mobile-app surface, which is gated on a different visibility setting, so omitting it can return `404` for a live event. - Authenticate with an `X-Grofomo-Key` header. Publishable keys (`pk_live_…`) are safe in browser code; secret keys (`sk_live_…`) are server-only. Choose by where the code runs. - Every response is `{ "apiVersion": 1, "data": … }`, or `{ "apiVersion": 1, "error": { "code", "message" } }` on failure. Branch on `code`, never on `message`. Every page below is also available as HTML at the same path without `.md`. ## Start here - [Overview](https://developers.grofomo.com/index.md): What this API is, and what you can build with it. - [Quickstart](https://developers.grofomo.com/quickstart.md): Your first request, and a working lineup page in about ten minutes. - [For organisers](https://developers.grofomo.com/organisers.md): Give your web developer a key, and choose which domains may use it. ## Concepts - [Authentication](https://developers.grofomo.com/concepts/authentication.md): Publishable and secret keys, where each one belongs, and the two failure codes. - [Surfaces](https://developers.grofomo.com/concepts/surfaces.md): Why every website request needs `?surface=web`, and what happens without it. - [Responses and errors](https://developers.grofomo.com/concepts/responses.md): The response envelope, the error shape, and how to tell them apart. - [Caching and rate limits](https://developers.grofomo.com/concepts/caching.md): How long each feed is cached, and how to poll cheaply. - [CORS and allowed domains](https://developers.grofomo.com/concepts/cors.md): What the domain allowlist does, and the thing it deliberately does not do. ## API reference - [All endpoints](https://developers.grofomo.com/reference.md): Index of every documented endpoint. ## Event - [Event detail](https://developers.grofomo.com/reference/events/detail.md): Core event info: dates, venue, stages and brand. - [Content version](https://developers.grofomo.com/reference/events/version.md): A cheap probe for "has anything changed?". - [Organiser profile](https://developers.grofomo.com/reference/organisers/detail.md): Organiser bio, branding and their upcoming events. ## Lineup - [Event lineup](https://developers.grofomo.com/reference/events/lineup.md): Published lineup: artists, stages and set times. - [Artist detail](https://developers.grofomo.com/reference/events/artist.md): Full artist profile, plus their sets at this event. ## Content - [Event FAQs](https://developers.grofomo.com/reference/events/faq.md): Categorised FAQs, with answers pre-rendered to HTML. - [News index](https://developers.grofomo.com/reference/events/news.md): Published news articles, newest first. - [News article](https://developers.grofomo.com/reference/events/news-article.md): A single published article, with its full body. - [Announcements](https://developers.grofomo.com/reference/events/broadcasts.md): Announcements the organiser has sent, newest first. ## Tickets & merch - [Ticket availability](https://developers.grofomo.com/reference/events/tickets.md): Visible ticket types and release tiers, with live availability. - [Merch catalogue](https://developers.grofomo.com/reference/events/merch.md): Garments, colours, sizes, print zones and prices. ## Forms & signups - [Mailing-list signup](https://developers.grofomo.com/reference/events/subscribe.md): Add an email to the organiser's mailing list from your own form. - [Form definition](https://developers.grofomo.com/reference/forms/definition.md): The fields of a published form, so you can render it yourself. - [Submit a form](https://developers.grofomo.com/reference/forms/submit.md): Send answers back for a published form. ## Discovery - [Event search](https://developers.grofomo.com/reference/events/search.md): Search public events across all organisers. ## More - [Webhooks](https://developers.grofomo.com/webhooks.md): Receive ticket sales and signups on your own endpoint, with signature verification. - [Selling tickets](https://developers.grofomo.com/checkout.md): How to sell from your own site today, and the embed that is coming. - [For AI agents](https://developers.grofomo.com/ai.md): Machine-readable entry points: llms.txt, markdown twins and an OpenAPI document. - [Changelog](https://developers.grofomo.com/changelog.md): What changed, and how versioning works. ## Optional - [https://developers.grofomo.com/llms-full.txt](https://developers.grofomo.com/llms-full.txt): every page above, concatenated into one file. - [https://developers.grofomo.com/openapi.json](https://developers.grofomo.com/openapi.json): OpenAPI 3.1 for every documented endpoint. --- # Grofomo API Build an event website on live festival data. Organisers run their festival in Grofomo — lineup, stages, set times, FAQs, news, tickets, merch. This API hands you that same data as JSON, already published and already public, so the site you build stays right without anyone re-typing a running order into a CMS. ## One request ```bash curl -sS \ -H 'X-Grofomo-Key: pk_live_YOUR_PUBLISHABLE_KEY' \ 'https://api.grofomo.com/v1/events/summer-fest/lineup?surface=web' ``` ## Where to go next - [Quickstart](/quickstart.md): Your first request, and a working lineup page in about ten minutes. - [For organisers](/organisers.md): Give your web developer a key, and choose which domains may use it. - [Authentication](/concepts/authentication.md): Publishable and secret keys, where each one belongs, and the two failure codes. - [Surfaces](/concepts/surfaces.md): Why every website request needs `?surface=web`, and what happens without it. - [Responses and errors](/concepts/responses.md): The response envelope, the error shape, and how to tell them apart. - [Caching and rate limits](/concepts/caching.md): How long each feed is cached, and how to poll cheaply. - [CORS and allowed domains](/concepts/cors.md): What the domain allowlist does, and the thing it deliberately does not do. - [Webhooks](/webhooks.md): Receive ticket sales and signups on your own endpoint, with signature verification. - [Selling tickets](/checkout.md): How to sell from your own site today, and the embed that is coming. - [For AI agents](/ai.md): Machine-readable entry points: llms.txt, markdown twins and an OpenAPI document. - [Changelog](/changelog.md): What changed, and how versioning works. - [API reference](/reference.md): every documented endpoint, grouped. --- # Quickstart Your first request, and a working lineup page in about ten minutes. You need two things before you start: an **event slug** and a **publishable key**. Both come from the organiser — if you are the organiser, see [For organisers](/organisers). The slug is the last part of the event's Grofomo link. For `grfm.to/e/summer-fest` the slug is `summer-fest`. ## Your first request ```bash curl -sS \ -H 'X-Grofomo-Key: pk_live_YOUR_PUBLISHABLE_KEY' \ 'https://api.grofomo.com/v1/events/summer-fest/lineup?surface=web' ``` Two details in that command do real work: - **`X-Grofomo-Key`** identifies the organisation. Most organisers now require it; some older ones do not yet. Send it either way — see [Authentication](/concepts/authentication). - **`?surface=web`** tells the API you are a website. Leave it off and you get the mobile-app surface, which is gated on a *different* visibility setting, so a perfectly live event can answer `404`. This trips up nearly everyone once. See [Surfaces](/concepts/surfaces). ## What comes back Every response is wrapped in the same envelope: ```json { "apiVersion": 1, "data": { "eventSlug": "summer-fest", "slots": [] } } ``` Errors use the same envelope with `error` instead of `data`: ```json { "apiVersion": 1, "error": { "code": "unauthorized", "message": "A valid API key is required" } } ``` So the check is always: look at `res.ok`, then read `body.data` or `body.error`. Nothing else varies. ## A lineup page This is a complete Next.js server component. It runs on your server, so it uses the **secret** key and lets the framework cache the result — a busy festival page then costs you one API call a minute, not one per visitor. ```javascript async function getLineup() { const res = await fetch( 'https://api.grofomo.com/v1/events/summer-fest/lineup?surface=web', { headers: { 'X-Grofomo-Key': process.env.GROFOMO_SECRET_KEY }, next: { revalidate: 60 }, }, ); const body = await res.json(); if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`); return body.data; } export default async function LineupPage() { const lineup = await getLineup(); return (
    {lineup.slots.map((slot) => (
  1. {slot.artist?.name ?? slot.placeholderLabel} {' — '} {slot.stage} · {slot.day} · {slot.startTime}
  2. ))}
); } ``` Note `slot.artist?.name ?? slot.placeholderLabel`. An unannounced set has no artist yet, and rendering "undefined" on a public festival page is a bad afternoon. ## Free SEO On the web surface the lineup, FAQ and news responses each carry a ready-made schema.org block in `schemaOrg`. Drop it into the page and search engines can read your running order without you modelling any of it: ```javascript