# Webhooks

> POST every submission as JSON to your own endpoint, Zapier, Make or n8n.

Source: https://docs.formclick.io/html-forms/webhooks

A webhook sends each new submission to a URL you choose. Use it to trigger automations in Zapier, Make or n8n, or to save submissions in your own backend.

> **Starter, Pro and Business plans:** Webhooks are available on all paid plans.

## Setup

1. Open your form → **Integrations** → **Webhooks**.
2. Enter your endpoint URL and a name, and choose the HTTP method.
3. Optionally add custom headers, e.g. an `Authorization` token your endpoint checks.
4. Send a test submission and check your endpoint receives it.

You can add several webhooks to one form; each one receives every new submission. AI assistants can also add and remove webhooks with the [MCP](https://docs.formclick.io/mcp/mcp-tools) `add_webhook` and `remove_webhook` tools.

## Options

| Option | Values |
| --- | --- |
| URL | Any public `https://` or `http://` address. Private and internal addresses are rejected. |
| Method | `POST` (default), `PUT`, `PATCH` or `GET`. `GET` sends no body. |
| Headers | Any custom headers, e.g. `Authorization: Bearer …` or an API key your endpoint expects. |
| Events | `submission.created`: sent once for each new, non-spam submission. |

## Payload

```json
{
  "submissionId": "7f6c2b8e-…",
  "formId": "0d1a4f3c-…",
  "data": {
    "name": "Jane Smith",
    "email": "jane@example.com",
    "message": "Hi! Could we book a demo next week?"
  },
  "fromName": "Jane Smith",
  "fromEmail": "jane@example.com",
  "submittedAt": "2026-11-08T10:24:31.000Z"
}
```

Requests are sent with `Content-Type: application/json` and `User-Agent: Formclick-Webhook/1.0`, plus any custom headers you set.

## Receiving it

**Node.js (Express)**

```js
app.post('/formclick', express.json(), (req, res) => {
  if (req.get('Authorization') !== 'Bearer ' + process.env.WEBHOOK_TOKEN) {
    return res.sendStatus(401);
  }
  const { submissionId, data } = req.body;
  console.log('New submission', submissionId, data.email);
  res.sendStatus(200);
});
```

**Next.js route**

```js title="app/api/formclick/route.ts"
export async function POST(req) {
  const { submissionId, data } = await req.json();
  await db.leads.insert({ id: submissionId, ...data });
  return Response.json({ ok: true });
}
```

> **Tip:** Respond with any `2xx` status quickly. Failed deliveries are retried automatically.
