Keys
An admin makes keys in Settings, API and webhooks. A key belongs to one workspace and is shown once. A read key lists forms and responses; a write key can also make forms.
curl https://ogforms.app/api/v1/me \ -H "Authorization: Bearer og_live_..."
Each key may make 120 requests a minute. Past that the answer is 429 with a Retry-After header. To hear about new answers, use a webhook rather than asking every minute.
Endpoints
All under https://ogforms.app/api/v1.
- GET /me: the key's workspace and access. Good for testing a connection.
- GET /forms: every form in the workspace.
- POST /forms (write keys): a new draft form, from { title, description?, fields?: [{ type, label, required?, choices? }] }.
- GET /forms/{id}: one form with its questions.
- GET /forms/{id}/responses: its responses, newest first. Takes limit (up to 100), cursor and since.
- GET /forms/{id}/responses/{responseId}: one response.
- GET /webhooks, POST /webhooks and DELETE /webhooks/{id}: subscriptions made through the API, the REST-hook way Zapier and Make use. POST takes { url, events?, formId?, headers? } and returns the signing secret once.
Pages
A list of responses comes back as { data, nextCursor, hasMore }. While hasMore is true, pass nextCursor back as cursor for the next page. Use since, a date and time such as 2026-01-31T09:00:00Z, to get only what arrived after it.
curl "https://ogforms.app/api/v1/forms/FORM_ID/responses?limit=100&cursor=NEXT_CURSOR" \ -H "Authorization: Bearer og_live_..."
A response has the same shape as in a webhook: answers for code and fields for spreadsheets and no-code tools.
Errors
Every error is JSON, { "error": { "code", "message" } }, with a code you can branch on and a message you can show.
- unauthorized (401): no key, or a key that is not valid or was revoked.
- forbidden (403): a read key asked to change something, or the key's workspace cannot do it.
- not_found (404): nothing with that id in this key's workspace.
- invalid_request (400): the message says what to fix.
- rate_limited (429): wait for Retry-After seconds.
- server_error (500): try again.
