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.

Upload carer proof

POST/v1/events/{slug}/carer-applications/proof-uploads

Step two of the carer form. Send the file's name, type and size and you get a one-shot URL to PUT the bytes to (with Content-Type set to the file's type and the header x-upsert: true), plus a proofToken naming the upload for the application step. The bytes go straight to storage, so there is no body limit to work around and nothing is held by the API.

The upload is not trusted until the application step: the document is then locked against the upload URL, its first bytes checked against the type you declared, location and camera metadata stripped from images, and only then recorded. A file that fails is deleted and the application refused with invalid_file.

Accepted types and the size limit come from carer tickets (proof.mimeTypes, proof.maxBytes). Check them before uploading so a phone photo that is too large fails on the form, not after the wait.

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 \
  -X POST \
  -H 'X-Grofomo-Key: pk_live_YOUR_PUBLISHABLE_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"fileName":"carer-card.jpg","mimeType":"image/jpeg","sizeBytes":812345}' \
  'https://api.grofomo.com/v1/events/summer-fest/carer-applications/proof-uploads?surface=web'

Request body

fileNamestringrequired
The file's name, for its extension.
mimeTypestringrequired
The file's type. One of `proof.mimeTypes` on the programme.
sizeBytesnumberrequired
The file's size, checked against `proof.maxBytes`.
Generated from CarerProofUploadRequest

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": {
    "proofToken": "ZXZlbnQtaWR8aW1hZ2UvanBlZ3xvcmcvZXZlbnQvdXBsb2FkLmpwZzoxNzg5NjQzNjAwMDAwOmNhcmVyLXByb29m.ZXhhbXBsZS1zaWduYXR1cmU",
    "uploadUrl": "https://unfdpucpvqglrmtbbisw.supabase.co/storage/v1/object/upload/sign/carer-proofs/org/event/upload.jpg?token=example"
  }
}
proofTokenstring
An opaque token for this upload, valid for an hour. Send it as `proofToken` on the application once the PUT has finished.
uploadUrlstring
PUT the file's bytes here, with `Content-Type` set to the file's type.
Generated from CarerProofUploadResultResponse

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`.
bad_requestHTTP 400
The body did not match the schema: a file name, type and size are required.
applications_closedHTTP 409
The organiser is not taking carer applications for this event.
invalid_fileHTTP 422
The type is not accepted or the file is over the size limit.
rate_limitedHTTP 429
Too many uploads from this address, or for this event. Try again later.

Notes

  • Rate limited to roughly 10 requests per minute per caller. Guidance, not a contract — see caching and rate limits.
  • Cache-Control: no-store