Photo gallery
/v1/events/{slug}/galleryUp 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
{
"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"
}
}eventIduuideventSlugstringseriesIduuid | 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.
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.