AnimationFunnel

Webhooks

Receive a signed HTTP POST on every submission — the fastest way to stream form data into your own backend.

Create a webhook

Open Integrations → Webhooks in your workspace. Click New webhook, give it a URL, and pick which events you want to receive.

Payload structure

Every webhook POST body follows this shape:

json
{
  "id": "sub_01H9Q...",
  "event": "submission.created",
  "form_id": "frm_01H9P...",
  "created_at": "2026-04-12T10:15:30Z",
  "data": {
    "name": "Ada Lovelace",
    "email": "[email protected]",
    "message": "Interested in the Pro plan."
  },
  "meta": {
    "ip_country": "TR",
    "referrer": "https://example.com/pricing",
    "utm": { "source": "google", "campaign": "q2-pricing" }
  }
}

Verifying signatures

Every webhook request includes a X-AnimationFunnel-Signature header with an HMAC-SHA256 of the raw body, signed with your workspace's webhook secret. Always verify this before trusting the payload.

typescript
import crypto from "node:crypto";

export function verify(body: string, signature: string, secret: string) {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(body)
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signature)
  );
}

Retries & delivery

We retry failed webhooks up to 5 times with exponential backoff (1m, 5m, 30m, 2h, 12h). Your endpoint must respond with a 2xx status code within 10 seconds.

Was this page helpful?