Skip to content

article

Sending Submissions to Other Tools with Webhooks

Push each new submission to any external system with HMAC-signed, timestamped payloads, automatic retries, a delivery log, and a one-click test.

Overview

Webhooks let StretchForms notify an external system the moment a submission arrives — a Slack channel, a spreadsheet automation, your data warehouse, or any endpoint that accepts a POST. Deliveries are signed so your receiver can trust them, retried automatically on failure, and logged so you can see exactly what happened. This guide covers configuring, verifying, and testing webhooks.

How delivery works

When a submission is created for a form that has webhooks configured, StretchForms:

  1. Builds a JSON payload describing the event, the form, the submission, and its routing.
  2. Signs it with your signing secret using HMAC-SHA256 over a timestamp and the payload body.
  3. POSTs it to your endpoint with the signature in a header.
  4. Retries on failure — up to the configured number of attempts (default 3, max 5), with an 8-second timeout per attempt.
  5. Records the outcome in the delivery log: queued, succeeded, retrying, failed, or test.

The payload

A submission webhook body looks like this:

{
  "event": "submission.created",
  "created_at": "2026-07-10T15:04:05.000Z",
  "form": {
    "id": "…",
    "form_key": "client-intake",
    "title": "Client Intake",
    "form_type": "intake",
    "target_app_key": null
  },
  "submission": { "…": "the submitted fields" },
  "routing": {
    "surface": "forms.intake",
    "note": "Contact and quote submissions route to Messaging > Submissions."
  }
}

The signature

Each delivery includes an x-stretchforms-signature header formatted:

x-stretchforms-signature: t=<timestamp>,v1=<hmac_sha256("<timestamp>.<payload>", secret)>

To verify on your side:

  1. Read t and v1 from the header.
  2. Compute HMAC_SHA256(secret, t + "." + rawBody) as hex.
  3. Compare it to v1 using a constant-time comparison.
  4. Optionally reject deliveries whose timestamp is too old to prevent replay.

StretchForms also records a SHA-256 of the payload for your reference.

Configure a webhook

  1. Open the form's advanced/automation settings and add a webhook endpoint.
  2. Enter the URL that will receive the POST.
  3. Set a signing secret (a long random string) so deliveries are verifiable.
  4. Optionally set max attempts (1–5) and give the endpoint a key to identify it in the log.
  5. Enable the endpoint and save.

Test before you rely on it

  1. Use Test webhook: provide the URL, signing secret, and max attempts.
  2. StretchForms sends a webhook.test payload and records the result as a test delivery.
  3. Confirm your endpoint received it, verified the signature, and returned a 2xx.

Read the delivery log

The webhook log shows each delivery with its form, endpoint key, URL, status, attempt count, last status code, and last error. Watch the needs-attention count on the dashboard — it counts deliveries that are queued, retrying, or failed.

Example

An agency wants every new project-brief submission in a Slack channel. They point a webhook at their Slack workflow URL, set a signing secret, and send a test. Slack posts the test message, they verify the signature in their middleware, enable the endpoint, and from then on every brief appears in Slack within seconds — with a full log they can audit.

Tips

  • Always set a signing secret and verify it — an unsigned endpoint can't tell real deliveries from spoofed ones.
  • Return 2xx quickly. Do heavy work asynchronously so you don't hit the 8-second timeout and trigger retries.
  • Make your receiver idempotent. Retries mean the same submission could arrive more than once.
  • Test first, enable second. The test path proves the whole round trip before real data flows.

Troubleshooting

Deliveries are failing. Check the log's last status code and error. A non-2xx response or a timeout will retry up to your max attempts and then mark the delivery failed.

Signature verification fails on my side. Sign over "<t>.<rawBody>" — the exact timestamp from the header joined to the raw request body — not a re-serialized version, and use the same secret you configured.

Nothing arrives at all. Confirm the endpoint is enabled, the URL is reachable from the internet, and the form is Active. Run the test to isolate the endpoint from the form.

FAQ

How many times will StretchForms retry? Up to the endpoint's max attempts (default 3, max 5). After that the delivery is marked failed and appears in the needs-attention count.

Can one form have multiple webhooks? Yes — configure multiple endpoints; each gets its own delivery record.

What event types are sent? New submissions send submission.created; the test path sends webhook.test.

Was this helpful?

Help us improve this article

Use these controls to share whether this answer solved the issue. Feedback helps prioritize updates to StretchSuite Support.