Webhooks
A Pro feature. Upgrading a single form doesn't include it. See Plans & pricing.
Setting it up
- Open Settings, then API, and choose Add webhook under Webhooks.
- Enter your endpoint's address. It needs to be public and start with
https://. - Choose all your forms, or just some.
- Copy the signing secret. You can see it again later from the webhook's Signing secret button.
- Choose Send test to check it works. You'll see what your endpoint answered straight away.
You can have up to 5 webhooks.
What gets sent
A POST with a JSON body. data is the response, the same as the API gives it. Tests have the type webhook.test and a made-up response.
{
"type": "response.created",
"timestamp": "2026-10-18T09:30:00.000Z",
"data": {
"id": "b1c7…",
"form_id": "4f2a…",
"link_id": "9d0e…",
"sequence": 1042,
"submitted_at": "2026-10-18T09:30:00.000Z",
"answers": { "q_name": "Ada" },
"display": { "q_name": "Ada" },
"encryption": null
}
}Answer with any 2xx status within 10 seconds. Anything else, a redirect, or no answer counts as a failure.
Checking it's from us
Every request is signed the Standard Webhooks way, with three headers: webhook-id, webhook-timestamp and webhook-signature. Their libraries check it for you, in most languages:
import { Webhook } from "standardwebhooks";
const wh = new Webhook(process.env.WEBHOOK_SECRET); // whsec_…
// In your handler, with the raw request body: the exact text we sent,
// before any JSON parsing (parsed and re-saved JSON won't match the signature):
const event = wh.verify(rawBody, {
"webhook-id": request.headers["webhook-id"],
"webhook-timestamp": request.headers["webhook-timestamp"],
"webhook-signature": request.headers["webhook-signature"],
});
// Throws if the signature is wrong or the timestamp is more than 5 minutes off.To check it yourself: the signature is v1, followed by the base64 HMAC-SHA256 of id.timestamp.body. The key is the part of the secret after whsec_, base64 decoded.
Retries and turning off
- If a delivery fails, we try again after 1 minute, 5 minutes, 30 minutes, 2 hours, 6 hours, then 12 hours twice. That's 8 tries over about a day and a half.
- If the last try fails too, the webhook is turned off. We'll tell you with an alert and an email.
- Once your endpoint is fixed, choose Turn back on, then Resend anything it missed from Recent deliveries.
- The log keeps each delivery's result for 30 days.
- To see what was sent for one response, open that response from the link's Responses tab. Under Webhook deliveries it lists each endpoint and whether it was delivered.
webhook-id to skip ones you've already handled, and sequence to put them in order. To catch up on anything missed, ask the API for responses since the last submitted_at you saw, or carry on from your saved cursor.Managing them with the API
An API key can add, list and delete webhooks too, which is how tools like Zapier set them up: POST /webhooks with {"url": "https://…"}, then DELETE /webhooks/{id} when done. The reply to adding one has its id, its secret (the whsec_… key for checking signatures) and form_ids. Add "form_ids": [...] to send just some forms. You can't send a test or read the delivery log through the API: those are on the API settings page. See the API reference. A key for some forms only can only add webhooks for those forms.
If your Pro ends
Nothing more is sent, and your webhooks are kept. Sending starts again when you have Pro.