Skip to content

Notifications & integrations ​

Add one or more notification destinations to a form (dashboard Workflow tab) and every accepted submission gets delivered to all of them. Availability by plan is on the pricing page; this page covers how each destination type works.

Destination types ​

TypeWhat it does
emailSends to a verified sender address on your account
discordPosts to a Discord channel via an incoming webhook URL
slackPosts to a Slack channel via an incoming webhook URL
telegramSends a message via a Telegram bot token + chat ID
webhookPOSTs the submission as JSON to your own endpoint, signed. See Webhook setup
zapier / makeThe same delivery, created for you when you connect a Zap or a Make scenario. See Zapier and Make

Toggle any destination on/off from the dashboard without deleting it, or remove it outright.

A new form starts with an email to you. A form you claim, or create in the dashboard, gets an email destination to the address you log in with, as long as that address is a verified email of the account the form is in. If the address isn't verified yet when you make the form, the destination is added when you verify it, to each such form that still has no destinations at all. Remove it or change the address whenever you like. A form created over MCP or with an API key starts with no destinations, and verifying an address later doesn't change that: the agent or program that made it adds the recipients it wants.

Need more than one recipient? Add multiple destinations of the same type - e.g. two email destinations with different addresses, or two discord destinations for two different channels. Every enabled destination gets its own delivery attempt for each submission, so this is the supported way to notify several people or channels; there's no separate CC/multi-address field. Adding the same address/URL/chat twice as two destinations of the same type is rejected (DUPLICATE_DESTINATION) since it would just deliver the same submission there twice.

Discord setup ​

  1. Open the Discord channel you want submissions posted to.
  2. Click the gear icon next to the channel name (Edit Channel), then go to Integrations → Webhooks.
  3. Click New Webhook (or Create Webhook), optionally rename it and pick the channel.
  4. Click Copy Webhook URL.
  5. In BootForm, add a Discord destination and paste the URL into Webhook URL. The optional Bot name overrides the name Discord shows on each posted message.

Each new submission is posted as a message in that channel. Removing the webhook on Discord's side (rather than in BootForm) will cause deliveries to that destination to start failing - check the destination's Delivery log in the dashboard if messages stop showing up.

Slack setup ​

  1. Go to api.slack.com/apps and click Create New App → From scratch.
  2. Name the app (e.g. "BootForm") and select the workspace to install it into.
  3. In the app's settings sidebar, open Incoming Webhooks and toggle it On.
  4. Click Add New Webhook to Workspace, pick the channel to post to, and authorize.
  5. Copy the generated webhook URL (starts with https://hooks.slack.com/services/...).
  6. In BootForm, add a Slack destination and paste the URL into Webhook URL.

A Slack incoming webhook is tied to one specific channel - to post to a different channel, create another webhook (repeat step 4) and add it as a separate BootForm destination.

Telegram setup ​

  1. Open a chat with @BotFather in Telegram and send /newbot, following its prompts to name your bot. BotFather replies with a bot token (looks like 123456:ABC-DEF...) - copy it.
  2. Add the bot to the chat, group, or channel you want notified. For a channel, add it as an administrator (Telegram requires this for a bot to post there).
  3. Find the numeric chat ID: the simplest way is to message @getidsbot from the same chat/group/channel and read the ID it returns, or send any message to your bot and check https://api.telegram.org/bot<token>/getUpdates for the chat.id field.
  4. In BootForm, add a Telegram destination with the bot token and chat ID from steps 1 and 3.

Delivery log ​

Each destination's Delivery log (in the dashboard's Workflow tab) shows its most recent 50 delivery attempts, newest first, 8 per page with Previous/Next to page through the rest, with status code, response time, and whether it ultimately succeeded. Older entries are removed automatically after 90 days, so this is a recent-activity view for troubleshooting - not a permanent record. Need a longer history? Export or archive delivery outcomes on your own end by watching the destination's own receiving endpoint.

Webhook setup ​

A webhook destination sends every accepted submission to a URL you choose, as a JSON POST. Use it when the submission should reach your own code or a service BootForm has no direct integration for:

  • Your own backend: a route such as https://example.com/api/bootform that saves the submission to your database, creates a lead in your CRM, or sends your own reply.
  • A serverless function: Cloudflare Workers, Netlify or Vercel functions, AWS Lambda function URLs, Azure Functions.
  • An automation tool's webhook trigger: n8n, Pipedream, or a Make "Custom webhook". For Zapier and Make, the dedicated integrations are easier (see Zapier and Make).
  • Trying it out: paste a temporary URL from a request inspector such as webhook.site and watch the payload arrive.

To add one: open the form, Workflow tab, Add destination → Webhook, paste the URL, Add. Copy the signing secret it shows you; it's displayed only once (you can rotate it later).

What the URL must be

  • A public https:// (or http://) address. Addresses on private or local networks (localhost, 127.0.0.1, 10.x, 192.168.x and similar) are rejected. To receive on your own machine while developing, expose it with a tunnel such as ngrok or Cloudflare Tunnel.
  • It must answer within 10 seconds with a 2xx status. Anything else counts as a failed attempt: BootForm retries after about 1 second, 10 seconds and 60 seconds, then gives up, records the failure in the destination's Delivery log and emails you about it.

Receiving it

Read the raw body, check the signature (see Outgoing webhook signature verification), then use the JSON. A minimal Node.js (Express) receiver:

js
import crypto from 'node:crypto'
import express from 'express'

const app = express()
const secret = process.env.BOOTFORM_WEBHOOK_SECRET

app.post('/api/bootform', express.raw({ type: 'application/json' }), (req, res) => {
  const header = req.get('BootForm-Signature') ?? ''
  const { t, v1 } = Object.fromEntries(header.split(',').map((part) => part.split('=')))
  const expected = crypto.createHmac('sha256', secret).update(`${t}.${req.body}`).digest('hex')
  const valid = v1 && v1.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected))
  if (!valid) return res.sendStatus(401)

  const submission = JSON.parse(req.body)
  console.log(submission.fields)
  res.sendStatus(200)
})

app.listen(3000)

Webhook payload ​

A webhook destination receives each submission as a JSON POST. The body is the submission itself, with no wrapper. Zapier and Make receive exactly the same body:

json
{
  "id": "9a2b3c4d-5e6f-7081-92a3-b4c5d6e7f809",
  "form_id": "11111111-1111-4111-8111-111111111111",
  "created_at": "2026-08-15T11:30:00Z",
  "fields": { "name": "Alice", "email": "alice@example.com", "message": "Hello there" },
  "files": [
    { "name": "resume.pdf", "url": "https://...", "size": 208452, "mime": "application/pdf" }
  ]
}

created_at is when BootForm accepted the submission. files is always present ([] when there are none), and each file url is a fresh download link valid for 1 hour.

Outgoing webhook signature verification ​

Every delivery to a webhook destination carries a BootForm-Signature header so you can confirm it genuinely came from BootForm:

BootForm-Signature: t=1700000000,v1=5257a869e7bfa9...

v1 is an HMAC-SHA256 of "{t}.{raw_request_body}", keyed with your destination's signing secret (shown once, in plaintext, when the destination is created - rotate it any time from the dashboard if it leaks). To verify: recompute the same HMAC with your stored secret and compare it to v1 using a constant-time comparison (e.g. Node's crypto.timingSafeEqual, Python's hmac.compare_digest) - a plain ==/=== string comparison leaks timing information an attacker can use to guess the signature byte-by-byte.

Zapier ​

Search for BootForm in Zapier and use the New Submission trigger: connect it with an API key (Settings → API Keys, Pro plan or higher), pick the form, and Zapier adds a zapier destination to that form. Each submission then reaches your Zap with the same fields as the webhook payload. Turning the Zap off removes the destination again.

If Zapier refuses three submissions in a row with 410 Gone (nothing is listening on the hook), BootForm pauses the zapier destination and emails you once. Choose Enable in the destination's menu in the form's Workflow tab once the Zap is on again.

Make ​

Make has a dedicated BootForm app with an instant trigger, a polling trigger and a Make an API call module that lets a scenario star, archive, moderate or delete the submission afterwards. See the Make guide.

Google Sheets, Airtable, and Notion ​

Not available yet - there's no real delivery mechanism for any of these three, so they're not offered as a destination type in the dashboard. If you want submissions flowing into a sheet or database today, connect through Zapier or Make instead (both have a direct Google Sheets/Airtable/Notion action on their own side), or pull with the submissions API / a CSV/JSON export.