---
title: "Webhooks: tell other tools what happened | Briks"
url: https://briks.dev/docs/webhooks
description: "Send a signed message to another tool when your site is published, a form is sent or a record changes. Payloads, signatures, retries and deliveries explained."
last_updated: 2026-10-08
---

# Webhooks: tell other tools what happened

A webhook sends a short message to another tool the moment something happens in your project: a publish, a form entry, a changed record. This page covers adding one, what the message looks like, how the other end can check it's genuine, and what happens when that end is down.

7 minute read Checked against the studio on 8 October 2026

## What a webhook is

Think of it as your project ringing another service to say what just happened. You give Briks an address (a URL the other tool gave you), choose the events it should hear about, and each time one happens Briks sends a message there. Many automation tools, client list tools and spreadsheet add ons can give you such an address.

Technically, each message is a POST request: a call that carries a body, here written in JSON, a plain text format programs read. The receiving tool reads the body and does what you set it up to do.

| Event, as the studio shows it | Code | Sent when |
| --- | --- | --- |
| **Published** | `site.published` | A new version of the site went live. |
| **Form received** | `form.received` | A visitor sent a message through one of the site's forms. |
| **Record changed** | `record.changed` | A record in the project's database was added, changed or deleted. |

`record.changed` follows changes made in the studio: a record added, edited or deleted in the Database tab, a collection cleared, or the database restored. Records the live site saves by itself, such as a booking request a visitor sends, don't trigger it.

`form.received` is sent for entries from the preview as well as from production. Each message says which, so the other tool can skip preview entries.

Where

1. Projects
2. Your project
3. Settings
4. Webhooks

## Limits on each plan

| Plan | Webhooks per project | Calls a day per project |
| --- | --- | --- |
| Free | 1 | 2,000 |
| Starter | 5 | 5,000 |
| Pro | 10 | 10,000 |
| Studio | 25 | 50,000 |
| Agency | 50 | 100,000 |

Calls a day are shared with scheduled tasks. Every delivery attempt counts as one, including retries, and the day starts at midnight UTC.

When the day's calls are used up, a delivery isn't sent and is marked **Failed** with: Today's calls for this project are used up, so this delivery was not sent. Send it again tomorrow.

Once a project has as many webhooks as its plan allows, **Add webhook** is greyed out and a **Get more** link beside the count opens the upgrade window, which names the smallest plan with room for another.

## Add a webhook

1. Press Add webhook

   Where: Settings, Webhooks

   The page shows how many you have against your plan, such as 1 of 5 on your plan. Editors, Admins and Owners can add webhooks.

2. Enter the address

   Where: Add a webhook

   Paste the address the other tool gave you into **Address**. It must be a public https address, with the name written out rather than a number.

3. Add a note

   Where: Add a webhook

   **Note** is optional, up to 120 characters, and helps you tell webhooks apart later: `Enquiries sheet`, say.

4. Choose the events

   Where: Add a webhook

   Tick the events it should hear about. **Published** and **Form received** start ticked; change them to suit.

5. Save and copy the secret

   Where: Your signing secret

   Press **Add webhook**. A dialog shows the signing secret, which starts with `whsec_`. Press **Copy** and keep it: it is shown once. Then press **Done**.

6. Send a test

   Where: Settings, Webhooks

   Open the webhook's three dots and choose **Send a test event**. You see: A test event is on its way. See how it went under Deliveries.

Each webhook in the list shows its address, note and events, which secret it is signed with (the first few characters), and how the last delivery went. Its switch turns it **On** or **Off**, and its three dots hold **Send a test event** (up to ten an hour, only while it is on), **Change**, **New signing secret** and **Delete**.

## What a delivery looks like

Every delivery has the same three parts: `type` (the event's code), `timestamp` (when it happened, in UTC) and `data` (the details). Here is a form entry:

A form.received delivery

> `{"type":"form.received","timestamp":"2026-10-08T09:41:07.000Z","data":{"form":{"id":"…","subject":"Wedding enquiry","page":"/contact","fields":[{"label":"Name","value":"Ellie Marsh"},{"label":"Wedding date","value":"14 June 2027"}],"replyTo":"ellie@example.com"},"production":true}}`

| Event | What `data` holds |
| --- | --- |
| `form.received` | `form`: its `id`, `subject`, the `page` it was sent from, `fields` (each a `label` and a `value`, in the form's order) and `replyTo`, the visitor's email when the form asks for one. Then `production`: `true` for the live site, `false` for the preview. |
| `site.published` | `url`: the address it went live at. `production`: whether the site is in production. `abTest`: whether an A/B test is running. `served`: whether Briks saw the new version answering at that address when it sent the message. |
| `record.changed` | `action`: `created`, `updated`, `deleted`, `cleared` or `restored`. `collection`: which collection. `record`: the record's id. The record's values aren't included. |
| `test` | A `message` and the `project`, with its `id` and `name`. Sent only when you press **Send a test event**. |

Each delivery also carries three headers: `webhook-id` (the message's id), `webhook-timestamp` (when it was sent, in seconds) and `webhook-signature`. They follow the open Standard Webhooks format, so tools that understand it can check deliveries for you.

## Check that a delivery is genuine

Anyone can send a message to an address, so the receiving end should check the signature before trusting one. The signature is made with the signing secret that only you and Briks have. Once a project has a webhook, the Webhooks page shows a short code example under **Checking a delivery is genuine**. In words, the check goes like this:

1. Take the body exactly as it arrived, as text, before reading it as JSON.
2. Join the `webhook-id`, the `webhook-timestamp` and the body with full stops between them.
3. Take your secret, drop the `whsec_` at the start and decode the rest from base64. That is the key.
4. Sign the joined text with HMAC SHA-256 and that key, write the result in base64, and put `v1,` in front.
5. The delivery is genuine if that matches one of the space separated values in `webhook-signature`, and the timestamp is within five minutes of now.

A delivery that is tried again keeps its `webhook-id`, so the receiver can keep the ids it has handled and skip repeats.

Keep the secret safe

The signing secret is shown once and can't be shown again. If you lose it, or it leaks, choose **New signing secret** from the webhook's three dots. The old one stops signing new deliveries at once, so put the new one into the receiving tool straight away.

## Deliveries and retries

Where

1. Projects
2. Your project
3. Settings
4. Webhooks
5. Deliveries

**Deliveries** lists every delivery of the last thirty days, newest first. Narrow it with **Status** and press **Show**. Click one to see the full message, any error and what the address answered.

| Status | Meaning |
| --- | --- |
| **Sending** | Waiting for its first try. |
| **Retrying** | A try failed and another is coming. The line shows when, after next try. |
| **Delivered** | The address answered with a 2xx status, the web's code for success. |
| **Failed** | Every try failed, or the delivery couldn't be sent at all. |

Each try waits up to 15 seconds for an answer. If the answer isn't a 2xx, Briks tries again: five tries in all, the first at once and then after about 30 seconds, 2 minutes, 8 minutes and 32 minutes, so roughly 45 minutes from first to last. An answer of 410 (gone) stops the retries at once. Redirects aren't followed, so give the final address.

Once a delivery is **Failed** or **Delivered**, **Send again** sends the same message with the same id, signed afresh. The webhook has to be on.

## Insights and settings

**Insights** sums up the last thirty days: **Deliveries**, the share **Delivered**, **Failed after every try** (with the number of retries it took), and the **Average answer** time. Below, **By event** and **By address** show where failures gather.

**Settings** has **Download JSON** under **Download the webhooks**, with every webhook's address, events and note. Signing secrets are never included. Its danger zone holds **Clear log**, which deletes the delivery log and stops any retries, and **Delete all**, which removes every webhook after you type the project's name. Both are for Owners and Admins.

## Worked example: form entries into another tool

Form entries can't be exported from the studio, so a webhook is the way to keep them in another tool as they arrive. The studio keeps them too: the latest 100 show under **Settings**, **Forms**.

A wedding photographer in York sends enquiries to her client list

1. Get an address from the other tool

   Where: Her client list tool

   She creates an incoming webhook there and copies the address it gives her.

2. Add the webhook

   Where: Settings, Webhooks

   She pastes the address, writes the note `Client list`, unticks **Published** and leaves only **Form received** ticked.

3. Give the tool the secret

   Where: Her client list tool

   Her tool checks signatures, so she pastes the signing secret into its settings before closing the dialog.

4. Test it

   Where: Settings, Webhooks, Deliveries

   She sends a test event and sees it **Delivered** under **Deliveries**.

5. Match the fields

   Where: Her client list tool

   She maps the `fields` labels Name, Wedding date and Venue to her tool's columns, and tells it to ignore messages where `production` is `false`.

The next enquiry

> A couple fills in the contact form on her live site.

The enquiry reaches her inbox, since the site is in production, and appears in her client list a moment later.

## Read next

- [Your site's features **Forms** Add a form to your Briks site, test it in preview, find every entry in the studio, get each one by email in production and pass them on with a webhook.](https://briks.dev/docs/forms)
- [Data and automation **Scheduled tasks** Run a scheduled task on your site at set times: a morning summary, a weekly tidy up. Write a schedule, read each run, fix one that fails, and see plan limits.](https://briks.dev/docs/crons)
- [Data and automation **Database** Find what your site stores, edit and add records by hand, and download collections as JSON or CSV, with who can do what and the limits that apply.](https://briks.dev/docs/database)
- [Data and automation **Logs** Read the build log and the last day of your site's requests, filter by level or status, and track down a failing form, a failing job or a slow page.](https://briks.dev/docs/logs)

Still stuck?

Write to [hello@briks.dev](mailto:hello@briks.dev) with your project's name and what you expected to see. A screenshot helps.
