Submit a form
POST
/v1/forms/{key}/submissionsSubmit answers for a published form. Answers are validated against the form's own definition, so fetch the definition first and post back matching field ids.
Requires a Turnstile token.
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.Bot check requiredThis write needs a Cloudflare Turnstile token, so it cannot be driven from a script. Render the widget in your form and post the token it produces.
Request
curl -sS \
-X POST \
-H 'X-Grofomo-Key: pk_live_YOUR_PUBLISHABLE_KEY' \
-H 'Content-Type: application/json' \
-d '{"answers":{"full_name":"Alex Doe","email":"alex@example.com","shifts":["friday-evening","saturday-morning"]},"turnstileToken":"<token from the Turnstile widget>"}' \
'https://api.grofomo.com/v1/forms/volunteer-signup/submissions?surface=web'Path parameters
keystringrequired- The form's key. 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": {
"ok": true
}
}oktrue
Generated from FormSubmissionResponse
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`.
turnstile_failedHTTP 400- The bot-check token was missing or invalid.
bad_requestHTTP 400- An answer did not match the form definition.
Notes
- Rate limited to roughly 30 requests per minute per caller. Guidance, not a contract — see caching and rate limits.
Cache-Control: no-store