Connect Zapier, Make or n8n
The other app gives you an address, and OG Forms sends each answer to it. You do not need an API key for this.
- Zapier: make a Zap and choose Webhooks by Zapier as the trigger, with the event Catch Hook. Copy the address it shows. Make: add a Webhooks module, Custom webhook, and copy its address. n8n: add a Webhook node set to POST and copy its production URL.
- In OG Forms, open the form, go to Integrate, and press Add webhook. Paste the address and keep New response ticked.
- Press Send test. It sends a sample with every question on the form, so the other app learns each field.
- Back in the other app, test the trigger, map the fields you want, and turn it on.
A webhook on a form hears only that form. An admin can also add one in Settings, API and webhooks that hears every form in the workspace.
Events
- form.response.created: someone submitted a form. Carries the form and the response.
- form.published: a form went live.
- form.closed: a form was closed by hand or reached its response limit. Carries the reason.
- member.joined: someone joined the workspace. Workspace webhooks only.
What is sent
A POST with a JSON body. Each response has its answers twice: answers, in form order with each question's id, type and raw value, for code; and fields, a flat map of question to readable answer, for Zapier and Make, whose mapping screens cannot reach into lists.
{
"id": "dlv_...",
"event": "form.response.created",
"createdAt": "2026-10-05T09:12:44.000Z",
"workspaceId": "ws_...",
"data": {
"form": { "id": "frm_...", "title": "Contact", "status": "published", "url": "https://ogforms.app/f/contact", ... },
"response": {
"id": "rsp_...",
"submittedAt": "2026-10-05T09:12:43.000Z",
"email": "ada@example.com",
"fields": { "Name": "Ada Lovelace", "Message": "Hello" },
"answers": [{ "fieldId": "fld_...", "label": "Name", "type": "short_text", "value": "Ada Lovelace", "text": "Ada Lovelace" }]
}
}
}Passwords are never sent. A file answer is its name, size and a link that opens only for members allowed to see the form's responses.
Check the signature
Every request carries these headers. OG-Delivery stays the same on every retry of one delivery, so you can drop repeats.
- OG-Event: the event name.
- OG-Delivery: the delivery id, also the body's id.
- OG-Webhook: which webhook sent it.
- OG-Signature: t=TIME,v1=HMAC.
The HMAC is SHA-256, keyed with the webhook's signing secret (shown once, when you add it), over the time, a full stop, and the raw body. Compare it in constant time and refuse a time more than five minutes old.
import { createHmac, timingSafeEqual } from 'node:crypto';
function verify(rawBody, header, secret) {
const { t, v1 } = Object.fromEntries(header.split(',').map((p) => p.split('=')));
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
return v1.length === expected.length && timingSafeEqual(Buffer.from(v1), Buffer.from(expected));
}Custom headers
If your receiver wants a token, add up to ten headers of your own when you add the webhook, or later from its Deliveries panel. They go out with every request. Saved values are shown masked, never in full.
You cannot set Content-Type, User-Agent, Host or the other headers that describe the request, nor any header starting with OG-, so a custom header can never forge a signature.
Retries, failures and pausing
- A delivery succeeds when your server answers 2xx within 10 seconds. Redirects are not followed.
- A failure is tried again after 1 minute, 5 minutes, 30 minutes, 2 hours and 6 hours, so for about 9 hours in all.
- If the last try fails, whoever set the webhook up gets one email saying what went wrong. There is no second email until it has worked again.
- A webhook that has failed every try for a day is turned off. An answer of 410 Gone turns it off at once, which is how Zapier says a Zap was turned off.
- Pause a webhook to stop it for a while. Answers that arrive while it is paused are not sent later.
- Each webhook keeps a log of its last 20 deliveries, for 30 days, with what was sent and what came back. Any delivery can be sent again from there.
