Integrations

Send form responses via webhooks

Webhooks are YeetForm's general-purpose way to send response data anywhere: your own backend, a database sync job, or another integration platform. Add an HTTPS endpoint under a form's Integrations tab and YeetForm POSTs a signed JSON payload on every new response, with a secret you can verify against using HMAC-SHA256. Failed deliveries retry automatically. This page covers the exact signature format, the payload shape, and the retry schedule so you can build a receiver with confidence.

Setup

1

Add an endpoint

In the form's Integrations tab, paste your HTTPS endpoint URL under Webhooks and click Add webhook. YeetForm generates a signing secret (whsec_...) for that endpoint.

2

Verify the signature

Every delivery carries an X-YeetForm-Signature header: t=<unix ts>,v1=<hex hmac-sha256 of `${t}.${body}`>. Verify it against the raw request body before trusting the payload.

import { createHmac, timingSafeEqual } from "crypto";

function verify(secret, signatureHeader, rawBody) {
  const [tPart, v1Part] = signatureHeader.split(",");
  const timestamp = tPart.split("=")[1];
  const signature = v1Part.split("=")[1];

  const expected = createHmac("sha256", secret)
    .update(`${timestamp}.${rawBody}`)
    .digest("hex");

  const a = Buffer.from(signature, "hex");
  const b = Buffer.from(expected, "hex");
  if (a.length !== b.length) return false;
  return timingSafeEqual(a, b);
}
3

Read the payload

POSTs fire on response.created (and webhook.test for the manual test button), with the form id, response id, response count, and answers keyed by field id, plus a fields array with each field's label.

{
  "event": "response.created",
  "form_id": "<uuid>",
  "form_title": "Customer Feedback",
  "response_id": "<uuid>",
  "response_count": 42,
  "answers": { "fld_x": "..." },
  "submitted_at": "2026-09-13T12:00:00.000Z"
}
4

Handle retries

A non-2xx response (or a timeout) triggers a retry: immediately, then after 30 seconds, then after 5 minutes - 3 attempts total before YeetForm marks the delivery failed. Redirects aren't followed, so point the URL straight at your endpoint.

Tips

  • Field labels are included in the payload's fields array (id, label, type) so you don't have to hardcode field ids downstream.
  • Every response carries a stable response_id - use it as your idempotency key, since a retried delivery reuses the same id.
  • A failed delivery retries up to 3 times total (immediately, 30s, 5 min) before it's marked failed - a 2xx response is required to count as success, and redirects aren't followed.

Build your form with AI in seconds

Start free

FAQ

What triggers a webhook?+
response.created fires on every new response; webhook.test fires when you click the test button on the integration, so you can verify your endpoint before going live.
How do I know a request really came from YeetForm?+
Verify the X-YeetForm-Signature header against your endpoint secret using HMAC-SHA256 over `${timestamp}.${rawBody}` - see the verification snippet above.
What happens if my endpoint is down?+
YeetForm retries up to 3 times total: immediately, after 30 seconds, then after 5 minutes. If all three fail, the delivery is marked failed and isn't retried further.
Can I add custom headers?+
Yes, when you configure the webhook you can set custom headers - they're merged in, but YeetForm's own Content-Type and X-YeetForm-* headers always win if there's a conflict.