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.

Photo gallery

GET/v1/events/{slug}/gallery

Up to 25 photos an organiser hand-picked in Grofomo, in the order they arranged them. Render them in that order: the first few carry most of the weight on a page.

The gallery belongs to the event series, not to one edition, so every year of a festival answers with the same set. That is deliberate: it is "the best shots across the years", not "this year's shots".

An event that is not part of a series answers with seriesId: null and an empty photos array. So does one whose organiser has not picked any yet. Empty is a normal answer, not an error - design a page that reads well without it.

Photos can disappear between requests, without the array shrinking for any reason you can see. A photo whose consent was withdrawn, or which the organiser deleted, stops being served immediately. Do not cache image URLs beyond your own page build, and do not treat a shrinking gallery as a fault.

focalX and focalY are where the subject is, as fractions of width and height. Crop around that point rather than the centre and a wide shot keeps its subject on a narrow screen. Null means centre.

credit is a request, not decoration: where it is set, show it wherever you show the photo.

Request

curl -sS \
  -H 'X-Grofomo-Key: pk_live_YOUR_PUBLISHABLE_KEY' \
  'https://api.grofomo.com/v1/events/summer-fest/gallery'

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

Response

200 OK
{
  "apiVersion": 1,
  "data": {
    "eventId": "6f1c8e2a-4b3d-4c9e-9f21-8a7d5e0b1c34",
    "eventSlug": "summer-fest",
    "seriesId": "8f2c1a6e-5d3b-4c7a-9e10-2b4d6f8a0c31",
    "photos": [
      {
        "id": "c1a9f0d2-3e4b-45a6-8b7c-9d0e1f2a3b4c",
        "url": "https://cdn.grofomo.com/summer-fest/gallery/main-stage-sunset.jpg",
        "thumbnailUrl": "https://cdn.grofomo.com/summer-fest/gallery/main-stage-sunset-thumb.jpg",
        "width": 2400,
        "height": 1600,
        "caption": "Main Stage, Sunday golden hour",
        "credit": "Ellis Vaughan",
        "focalX": 0.5,
        "focalY": 0.38
      },
      {
        "id": "d2b0a1e3-4f5c-46b7-9c8d-0e1f2a3b4c5d",
        "url": "https://cdn.grofomo.com/summer-fest/gallery/crowd-friday.jpg",
        "thumbnailUrl": null,
        "width": 1800,
        "height": 1800,
        "caption": null,
        "credit": null,
        "focalX": null,
        "focalY": null
      }
    ],
    "lastUpdatedAt": "2026-06-02T11:20:00.000Z"
  }
}
eventIduuid
eventSlugstring
seriesIduuid | null
The series these photos belong to. Null when the event is not part of one, in which case `photos` is always empty.
photosobject[]
In the order the organiser arranged them. At most 25, and often none: an empty array is a normal answer, not an error.
photos[].iduuid
Stable id for this gallery entry. Use it as a render key.
photos[].urlstring
The full-size image.
photos[].thumbnailUrlstring | null
A smaller version where one exists. Null means use `url` and size it yourself.
photos[].widthnumber | null
Pixel width of `url`, when known. Use it to reserve space and avoid layout shift.
photos[].heightnumber | null
Pixel height of `url`, when known.
photos[].captionstring | null
Organiser-written caption. Null when they did not write one; do not invent alt text from the filename.
photos[].creditstring | null
Photographer or source credit the organiser asked to be shown. Display it wherever you display the photo.
photos[].focalXnumber | null
Horizontal focal point as a fraction of width, 0 = left, 1 = right. Crop around it so a wide shot does not lose its subject on a narrow screen. Null means centre.
photos[].focalYnumber | null
Vertical focal point as a fraction of height, 0 = top, 1 = bottom. Null means centre.
lastUpdatedAtstring | null
When the gallery last changed, for your own cache checks. Null when it is empty.
Generated from EventGalleryResponse

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.
  • Always served from the web surface, whatever `?surface=` says.
  • At most 25 photos. The cap is enforced when the organiser curates, not here.
  • Only photos appear. Organisers place video on their sites themselves.