API

Webhooks

Workflow webhook nodes send signed HTTP requests to your systems. Ingress forms also receives provider webhooks for Stripe billing and Anvil e-sign events.

Configuring an outgoing webhook

Add a webhook node to a workflow and provide a target URL. The URL is validated server-side before the request is sent: private and reserved IP ranges are blocked, responses are capped at 1 MB, and each request times out after 10 seconds.

Payload

The current webhook node sends the submission id and submitted data. The exact field keys match the form schema field ids.

json
{
  "submissionId": "sub_01H...",
  "data": {
    "__submissionId": "sub_01H...",
    "email": "alex@acme.com",
    "rating": 5
  }
}

Verifying signatures

Each request includes X-AutoForm-Signature and X-AutoForm-Timestamp. The signature is HMAC-SHA256 over timestamp + "." + rawBody using your signing secret, with a sha256= prefix in the header.

typescript
import { createHmac, timingSafeEqual } from "crypto";

export async function POST(req: Request) {
  const raw = await req.text();
  const timestamp = req.headers.get("x-autoform-timestamp") ?? "";
  const signature = req.headers.get("x-autoform-signature") ?? "";

  const expected =
    "sha256=" +
    createHmac("sha256", process.env.WEBHOOK_SIGNING_SECRET!)
      .update(timestamp + "." + raw)
      .digest("hex");

  const ok =
    signature.length === expected.length &&
    timingSafeEqual(Buffer.from(signature), Buffer.from(expected));

  if (!ok) return new Response("bad signature", { status: 401 });

  const payload = JSON.parse(raw);
  // handle payload
  return new Response("ok");
}

Delivery behavior

A 2xx response marks the webhook node as successful. Non-2xx responses and request errors are recorded on the workflow run as failures. You can inspect run logs and retry a failed workflow run from the app or with the rerun API.

Incoming provider webhooks

Ingress forms receives Stripe subscription events at /api/stripe/webhook and Anvil e-sign events at /api/esign/webhooks/anvil. Both routes verify provider signatures when the corresponding webhook secret is configured.