Integrations
Send HTML form submissions to a webhook
Add a Generic JSON webhook to your form in Formward and each processed submission is POSTed to your URL as JSON: form id and name, submission id, timestamp, the fields, and AI results when your plan has them. With a signing secret set, every request carries an HMAC signature your server can check.
Failed deliveries are retried, logged and can be replayed by hand. Webhooks need the Professional plan, and a form can have several, each with its own secret. This page covers setup; the webhooks reference documents the schema and verification code in full.
Set it up
- In Formward, open the form, go to its Settings tab and scroll to the Connections panel. Choose Webhooks.
- Keep the type on Generic JSON and paste your endpoint's https URL. Add a label if the form will have more than one webhook.
- Enter a signing secret: a long random string that your server also knows. It is optional, but without it your endpoint cannot tell a real delivery from a forged one.
- Click Add webhook, then Test. Formward sends a sample submission with the message "This is a test delivery from Formward".
- In your endpoint, verify the X-Formward-Signature header against the raw body before trusting the JSON, and answer with a 2xx status.
- Send a real submission and check the delivery log on the form's Webhooks settings tab.
A delivery, headers and body
What your endpoint receives for a contact form submission on a plan with AI:
http
POST /hooks/formward HTTP/1.1
Content-Type: application/json
X-Formward-Signature: t=1791366600,v1=9b1f0c...e4
X-Formward-Signature-Legacy: 3a7d...c1
{
"formId": "<formId>",
"formName": "Contact form",
"submissionId": "<submissionId>",
"createdAt": "2026-10-07T09:30:00.000Z",
"status": "processed",
"fields": {
"name": "Ada Lovelace",
"email": "ada@example.com",
"message": "Do you ship to Norway?"
},
"ai": {
"spamScore": 3,
"summary": "Shipping question about Norway",
"leadScore": 64,
"routingCategory": "sales"
}
}v1 is HMAC-SHA256 over v1:<t>:<raw body>. Compare it in constant time and reject old timestamps; the webhooks reference has Node.js and Python versions. The Legacy header is a bare HMAC of the body, kept for older verifiers during a rollover.
Field values are sent exactly as submitted. Unlike the chat formats, nothing is shortened or escaped, so treat them as untrusted input.
Plan and limits
- Available on the Professional plan and above.
- https only, public addresses only, no redirects followed. The check runs when you save and again on every delivery.
- A 2xx answer within 10 seconds is a success. Anything else is retried up to three more times with increasing delays, so the same submissionId can arrive twice: deduplicate on it.
- Owners and admins can replay a failed delivery from the log. Formward will not replay a step that already succeeded.
Where the data goes
The submission goes wherever you point the webhook. Point it at EU infrastructure and that copy stays in the EU; point it at a US service and you have made a transfer.
Your data-flow page lists every destination each of your forms uses right now.
Troubleshooting
- Deliveries fail with a 301 or 302
- Formward does not follow redirects. Use the final URL, including https and any trailing slash your server insists on.
- Deliveries time out although the endpoint works
- Your handler is doing its work before answering. Return 2xx as soon as the signature checks out and process the submission in the background.
- The signature never matches
- Hash the raw request body exactly as received. Most frameworks parse JSON first; reading the parsed object and serialising it again changes the bytes.
- localhost or a private IP is rejected
- That is the SSRF guard. Test against a public https URL, for example a staging server or a tunnel to your machine.
Other integrations
Connect Outbound webhooks to your first form
Create a form, point your HTML at it and set up Outbound webhooks in a few minutes. Submissions are stored and processed in the EU.