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.
{
"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.
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.