Guides/How to send form submissions to a webhook

How to send form submissions to a webhook

Every submission goes to Slack, Discord, or your server. HMAC-signed.

Updated March 2026

Someone submits a form. You want to know about it. Webhooks send the data to a URL you pick -- Slack, Discord, your own server, wherever. Sutrena signs every webhook payload with HMAC-SHA256 so you can verify it is real. There are built-in templates for Slack and Discord formatting, or you can receive raw JSON for custom wiring.

1. Create a form

You need a form before you can attach a webhook. Use a template or create one with custom fields.

curl -X POST https://sutrena.com/api/forms \
  -H "Authorization: Bearer st_trial_abc123" \
  -H "Content-Type: application/json" \
  -d '{"templateId": "contact"}'

2. Create a webhook

Attach a webhook to the form. Pick the target URL, the events to listen for, and an optional formatting template. The response includes a signing secret for verifying payloads.

curl -X POST https://sutrena.com/api/webhooks \
  -H "Authorization: Bearer st_trial_abc123" \
  -H "Content-Type: application/json" \
  -d '{
    "formId": "frm_xyz789",
    "url": "https://your-server.com/webhooks/sutrena",
    "events": ["form.submission"],
    "template": null
  }'

# Response:
# {
#   "id": "wh_abc123",
#   "signingSecret": "whsec_...",
#   "url": "https://your-server.com/webhooks/sutrena"
# }

3. Verify the HMAC signature

Every request has an X-Sutrena-Signature header. Compute HMAC-SHA256 of the raw body with your signing secret. If it does not match, reject it.

import crypto from "node:crypto";

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

// In your Express/Hono/Next.js handler:
app.post("/webhooks/sutrena", (req, res) => {
  const rawBody = req.body; // must be raw string, not parsed JSON
  const sig = req.headers["x-sutrena-signature"];

  if (!verifyWebhook(rawBody, sig, "whsec_your_secret")) {
    return res.status(401).send("Invalid signature");
  }

  const payload = JSON.parse(rawBody);
  console.log("New submission:", payload.data);
  res.status(200).send("OK");
});

4. Use Slack or Discord templates

Set template to "slack" or "discord" when creating the webhook. Sutrena formats the payload as a Slack Block Kit message or Discord embed. Point the URL straight at an incoming webhook.

# Slack webhook:
curl -X POST https://sutrena.com/api/webhooks \
  -H "Authorization: Bearer st_trial_abc123" \
  -H "Content-Type: application/json" \
  -d '{
    "formId": "frm_xyz789",
    "url": "https://hooks.slack.com/services/T00/B00/xxx",
    "template": "slack",
    "events": ["form.submission"]
  }'

# Discord webhook:
curl -X POST https://sutrena.com/api/webhooks \
  -H "Authorization: Bearer st_trial_abc123" \
  -H "Content-Type: application/json" \
  -d '{
    "formId": "frm_xyz789",
    "url": "https://discord.com/api/webhooks/123/token",
    "template": "discord",
    "events": ["form.submission"]
  }'

FAQ

How many webhooks can I create?

Free: 1. Builder: 5. Pro: 10. Scale: unlimited.

What happens if my endpoint is down?

Sutrena retries with exponential backoff. After enough failures, the webhook gets marked as failing. You can see the status in your dashboard.

Can I send webhooks to Zapier?

Yes. Use a Zapier catch webhook URL with no template. Zapier gets the raw JSON, you map fields to whatever downstream action you want.

Is the signing secret rotatable?

Delete the webhook and create a new one with the same URL. Fresh secret. There is no in-place rotation -- avoids race conditions during verification.

What does the webhook payload look like?

Raw webhooks (no template): event type, form ID, submission ID, submitted data as key-value pairs, and a timestamp. Slack/Discord templates format it according to those platforms' message specs.

What is Sutrena?

Sutrena is the web runtime for AI agents. Three primitives — pages, forms, and dashboards — accessible through one API. Your agent creates web artifacts, humans interact with them, and your agent gets the data back. Framework-agnostic. Works from any MCP client or HTTP client.

Get started in two API calls

1. Get a trial key (no auth, no signup)

curl -X POST https://sutrena.com/api/trial

2. Create a form + dashboard from a template

curl -X POST https://sutrena.com/api/forms \
  -H "Authorization: Bearer st_trial_xxx" \
  -H "Content-Type: application/json" \
  -d '{"templateId": "waitlist", "createDashboard": true}'

Ready to build?

Get a trial API key instantly with no signup, or create an account for the full experience.

How to send form submissions to a webhook — Sutrena | Sutrena