Webhooks
Send form responses and contact updates to your own server (or any external service that accepts HTTP requests) the moment they happen. Webhooks are the fastest, most flexible way to build a custom integration with Formsuite, no Zap or third-party automation tool required.
If you'd rather wire a webhook into a no-code automation platform like Make.com or n8n, the steps in this article apply equally. Just paste the platform's "custom webhook" URL into Formsuite. See Connect Make.com via Webhooks for a full walk-through.
What is a webhook?
A webhook is an HTTP POST request that Formsuite sends to a URL of your choice whenever a specific event happens. The payload is JSON, so any modern web server, serverless function, or automation tool can read it.
You can use webhooks to:
- Forward every form submission to your CRM, database, or analytics tool
- Trigger an automation in Make.com, Zapier, n8n, or Pipedream
- Notify a custom internal Slack/Discord bot when a high-value lead comes in
- Sync Formsuite contacts with your existing customer data
Before you start
- Webhooks are a paid plan feature. If you're still on the free plan you'll see an upgrade prompt on the webhooks page.
- You'll need an HTTPS endpoint that can accept a POST request and respond with a 2xx status within 15 seconds.
Creating a webhook
1. From your workspace sidebar, open Settings → Webhooks. (You can also reach it from any form's Connect page by clicking the "Webhooks" tile.)
2. Click + New webhook. The editor modal opens.
3. Fill in the fields:
- Name: a friendly label, e.g. "CRM sync" or "Slack alert for new leads". Only shown inside Formsuite.
- Endpoint URL: the HTTPS URL your server (or automation tool) is listening on.
- Scope: leave empty for Workspace-wide (fires on every form), or pick one or more specific forms. Contact events always run workspace-wide, so the contact event options only appear when the scope is empty.
- Events: tick the events you want to subscribe to:
- Form response completed: fires once a respondent finishes a form (after the AI summary is generated). This is the most common one to subscribe to.
- Form response started: fires exactly once per conversation, the moment a respondent submits their first answer.
- Contact created: fires when a new contact lands in your workspace.
- Contact updated: fires when a contact's name or email changes.
4. Click Create webhook. Formsuite generates a signing secret and shows it to you once. Copy it now and store it alongside your webhook URL.
Signing & verifying requests
Every request Formsuite sends includes these headers:
X-Formsuite-Event: dotted event name (e.g.form.response.completed).X-Formsuite-Event-Id: stable id for the event. Use this for idempotency on your end.X-Formsuite-Delivery-Id: unique id for this delivery attempt.X-Formsuite-Timestamp: ISO 8601 timestamp of when the request was sent.X-Formsuite-Signature:sha256=<hex>, where the hex is HMAC-SHA256 of the raw request body using your signing secret.
To verify a request came from Formsuite, re-compute the HMAC on your end and compare it against the header. Most receivers (Make.com, Zapier, n8n) don't need to verify. Only do it if you're running your own server and want to be sure no one is spoofing requests.
Custom headers
If your endpoint needs an extra header (typically Authorization: Bearer <token> or X-API-Key: <key> for self-hosted servers, or a routing header for an internal proxy) you can add up to 10 custom headers per webhook.
In the editor modal, scroll down and click Add custom headers. Each row is a name/value pair. Names must be valid HTTP token characters (letters, digits, and !#$%&'*+-.^_\|~`); duplicates and reserved names are rejected.
Reserved names you can't override (Formsuite needs to control these for the delivery to work):
Content-Type,User-Agent,Host,Content-Length,Connection,Transfer-Encoding,Accept,Accept-Encoding- Anything starting with
X-Formsuite-(those are reserved for the signing + envelope headers)
Custom header values are encrypted at rest with AES-256-GCM. The list view only shows a count. The actual values are never returned to the browser unless you explicitly open the editor for that webhook.
Payload shape
Every payload uses a consistent envelope:
{
"id": "evt_a1b2c3d4e5f6...",
"event": "form.response.completed",
"createdAt": "2026-05-28T18:42:11.123Z",
"workspaceId": "...",
"formId": "...",
"data": { ... }
}
The data block depends on the event:
- For form events:
responseId,formId(stable collectionId),formVersionId(the specific version row),formName,contact(id, name, email),answers(a structured array, described below),score,sentiment,summary,hiddenFields,referrer,startedAt+completedAttimestamps, and the raw conversationitems. - For contact events:
id,name,email,createdAt,updatedAt.
Each entry in the answers array carries everything you'd want to render or branch on without re-fetching the form:
{
"blockId": "abc123",
"questionId": "q_…",
"displayName": "Customer email",
"position": 2,
"label": "What's your email?",
"description": "We'll only use this to follow up.",
"required": true,
"type": "EMAIL",
"value": "ada@example.com",
"options": null,
"scale": null
}
A few things to note about the per-answer fields:
labelhas any recall syntax ({{blockId}},@score, hidden field references) already resolved with the respondent's prior answers, so it reads naturally (e.g. "Hi Ada, what's your email?").valueis the formatted human-readable answer. Option ids are resolved to their label, ratings include the max ("8/10"), and CONTACT_INFO / ADDRESS JSON is flattened to a comma-separated string. Same formatting the Zapier integration + CSV exports use.optionsis populated forMULTIPLE_CHOICEandDROPDOWN. It's an array of{ id, value }pairs covering every choice the respondent could have picked.scaleis populated forRATING,OPTION_SCALE, andNPS. Shape:{ min, max, minLabel, maxLabel }.displayNameis the internal name you set on a question (developer-friendly key), ornullif none was set.
startedAt is when the respondent landed on the form. completedAt is when they submitted the final answer (or when the partial event fired). For backwards compatibility there's also a submittedAt field that equals startedAt; prefer the new fields in any new integration.
Testing your webhook
Once you've saved the webhook, click the actions menu on the row and choose Send test. Formsuite will fire a synthetic payload with the same shape as a real delivery (marked "test": true) so your receiver, or your Make.com / Zapier scenario, can auto-detect the structure before any real responses arrive.
Retries
If your endpoint returns a non-2xx response or times out, Formsuite automatically retries once after 30 seconds. If that second attempt also fails, we mark the delivery as Failed. After 10 consecutive failed deliveries across the webhook, we automatically disable it so we don't keep hammering a broken endpoint. When that happens, the workspace owner gets an email and every workspace admin sees an in-app notification. Re-enable the webhook from the actions menu once you've fixed things.
There's also a soft cap of 1000 deliveries per workspace per 24 hours, designed to protect against runaway senders. If you ever bump up against it we log it server-side; reach out to support if you legitimately need a higher cap.
Recent deliveries
Click Deliveries in any webhook's actions menu to see attempts in reverse chronological order (newest first, 25 per page). Each row shows the event, the status (Delivered / Retrying / Failed), the HTTP status code your endpoint returned, and the duration. Click the chevron on a failed delivery to see the error message and the first 4KB of the response body, which is usually enough to debug what went wrong. Use Load older at the bottom of the list to page through history (kept for 30 days).
Failed deliveries also get a small replay button next to the chevron. Click it to queue the exact same payload again through the same retry pipeline. Handy when you've fixed an issue on your receiver and want to re-process a missed event without waiting for the next real submission.
Rotating the signing secret
Open the row's actions menu and choose Signing secret. The modal lets you reveal the current value, copy it, or rotate it. Rotating generates a new secret immediately. Any requests signed with the old secret will stop verifying as soon as you rotate, so plan the rotation alongside an update on the receiver side.
Next steps
If you're using Make.com, the Connect Make.com via Webhooks article walks through the Make-side setup step by step. Otherwise, point your webhook at any HTTPS endpoint and you're done.
Find the perfect template
Explore real templates crafted in Formsuite and discover how good your forms, surveys, and quizzes can look.



Build Custom Integrations
More Ways to Connect Formsuite
Pair webhooks with these features to automate your entire pipeline.