Webhook Processing
Webhooks let you run server-side logic whenever a form submission arrives: save to a database, send a Slack notification, trigger an email sequence, or anything else.
Formtorch sends a POST request to your endpoint with a JSON body and an HMAC-SHA256 signature header.
Next.js
Add your webhook endpoint in the dashboard
Go to Form Settings → Webhooks → Add endpoint. Enter your URL, for example https://yourapp.com/api/webhooks/formtorch. Copy the webhook secret.
Store the secret
FORMTORCH_WEBHOOK_SECRET=whsec_your_secret_hereCreate the route handler
import { createHmac } from "crypto";
export async function POST(req: Request) {
const body = await req.text();
const signature = req.headers.get("x-formtorch-signature") ?? "";
// Verify the signature
const expected = `sha256=${createHmac(
"sha256",
process.env.FORMTORCH_WEBHOOK_SECRET!
)
.update(body)
.digest("hex")}`;
if (signature !== expected) {
return new Response("Unauthorized", { status: 401 });
}
// Parse the payload
const event = JSON.parse(body) as FormtorchEvent;
// Handle by event type (currently only submission.created)
if (event.type === "submission.created") {
const { formId, submissionId, fields, submittedAt, isSpam } = event.data;
// Skip spam
if (isSpam) {
return new Response("OK");
}
console.log(`New submission for form ${formId}:`, fields);
// Your logic here: save to DB, send notification, etc.
}
return new Response("OK");
}
type FormtorchEvent = {
type: "submission.created";
data: {
formId: string;
submissionId: string;
fields: Record<string, string>;
submittedAt: string;
isSpam: boolean;
spamScore: number;
};
};Webhook payload shape
{
"type": "submission.created",
"data": {
"formId": "a1b2c3d4e5",
"submissionId": "x9y8z7w6v5",
"fields": {
"name": "Alex",
"email": "alex@example.com",
"message": "Hello"
},
"submittedAt": "2025-03-15T14:30:00.000Z",
"isSpam": false,
"spamScore": 0
}
}Reserved _* fields (like _redirect, _honeypot) are stripped from fields before delivery.
Always verify the signature
Skipping signature verification means anyone can send fake events to your endpoint.
Always verify x-formtorch-signature before processing. Read the raw request
body as a string before parsing it. If you parse JSON first, the string
representation may differ and the signature check will fail.
Retry behavior
If your endpoint returns a non-2xx response or times out, Formtorch retries with exponential backoff: 30 seconds, 5 minutes, 30 minutes. After 3 retries, the delivery is marked failed.
Return 200 OK quickly, then process asynchronously if your logic takes time.
Testing locally
Use a tunnel tool like ngrok or Cloudflare Tunnel to expose your local server to the internet during development. Then add the tunnel URL as a webhook endpoint in the dashboard.
Learn more
- Webhooks feature overview — payload shape, retry behavior, plan availability
- Webhook Events — full event type reference
- Signature Verification — security implementation details
- Webhooks as an integration layer — connecting to Slack, Make, n8n, and other tools