POST every new submission to the URL you choose, the moment it arrives.
- Integrations. Point it at Zapier, Make, n8n, or your own backend to push responses into a CRM, spreadsheet, or internal tool.
- Slack out of the box. Paste a Slack incoming-webhook URL and responses show up as a formatted message in your channel, with no extra setup.
- Signed and secure. Optionally sign every payload so your server can verify it genuinely came from Formo.
Setup
1
Open form settings
Open your form in the builder and go to Settings → Webhooks.
2
Add the endpoint
Click Add webhook and paste your endpoint URL. Give it an optional name so it’s easy to recognize later.
3
Keep the signing secret
A signing secret is generated for you. Copy it now; it’s stored encrypted and never shown again. Use it to verify incoming requests (see Verifying signatures).
4
Test it
Click Test to send a sample response to your endpoint and confirm it’s wired up, then toggle the webhook on.
Slack
To post responses into a Slack channel, create a Slack incoming webhook and paste its URL (it looks likehttps://hooks.slack.com/services/...). Formo detects Slack automatically and sends a formatted Block Kit message. No signing secret is needed; keep the URL private, since anyone who has it can post to your channel.
Sample Payload
Non-Slack endpoints receive a JSON envelope:answers keeps the order and human labels the respondent saw; fields is a flat id to value map that’s easy to bind in automation tools. Field ids are stable across label edits, so key on id, not label.
Headers
Security
When a signing secret is set, Formo signs each request so your server can prove it genuinely came from Formo and wasn’t tampered with. A valid signature can only be produced with the secret (authenticity), it covers the exact body (integrity), and it includes a timestamp your server can use to reject old requests (replay protection). Secrets are encrypted at rest and never returned by the API. Only publichttp(s) endpoints are allowed; URLs that resolve to private or internal addresses are rejected.
The signature is different on every request because it covers both the timestamp and the body, which carries a fresh event id. Don’t compare it to a stored value: recompute it per request from that request’s timestamp, body, and your secret, then compare to the X-Webhook-Signature header.
Verifying signatures
X-Webhook-Signature and X-Webhook-Timestamp headers appear in the request’s Headers section.
Delivery
Delivery happens after the response is saved and never blocks the submitter, so a slow or dead endpoint can’t fail or delay a submission. Failed deliveries are retried a few times on transient errors (network issues, timeouts,5xx). Deduplicate on data.response_id if a retry could double-process on your side.