> ## Documentation Index
> Fetch the complete documentation index at: https://paper.brimble.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks

> Brimble emits webhooks for deployment, project, domain, environment, DNS, autoscaling, subscription, and payment events.

Brimble emits webhooks for deployment, project, domain, environment, DNS, autoscaling, subscription, and payment events. Wire them into your own endpoint, a Discord channel, or a Slack channel.

## Prerequisites

* A subscription on a plan that includes webhooks (Hacker and above).
* An HTTPS endpoint to receive POSTs, or a Discord/Slack incoming-webhook URL.

## How webhooks are configured

Webhooks are configured **per subscription**, not per project. Three URLs can be configured, independently:

| URL field    | Format expected                                                            | Receives                            |
| ------------ | -------------------------------------------------------------------------- | ----------------------------------- |
| `webhookUrl` | An HTTPS endpoint you control                                              | JSON POSTs (one event per request). |
| `discordUrl` | A Discord channel webhook URL (`https://discord.com/api/webhooks/.../...`) | Discord-formatted messages.         |
| `slackUrl`   | A Slack incoming webhook URL (`https://hooks.slack.com/services/...`)      | Slack-formatted messages.           |

A single events list applies to all three destinations, whichever ones are set.

## Set up a webhook

1. Open the dashboard.
2. Open your account settings, then **Webhooks** (or your team's webhook settings, if you're configuring a team subscription).
3. Paste an endpoint URL into one or more of **Webhook URL**, **Discord URL**, or **Slack URL**.
4. Pick the events you want to receive. Use **Select all** to subscribe to every event.
5. Save.

<Info>
  **Image needed:** screenshot of the Webhooks settings page showing the three URL input fields (Webhook, Discord, Slack), the events checklist grouped by category (Deployment, Project, Domain, Environment, DNS, Autoscaling, Subscription, Payment), and a Save button
</Info>

The next matching event delivers to every configured destination.

Subscribe to specific events by listing them, or use `["*"]` to subscribe to everything. Use `[]` to disable delivery without removing the URL.

## What an HTTP webhook delivery looks like

```http theme={null}
POST /brimble HTTP/1.1
Host: your-endpoint.example.com
Content-Type: application/json

{
  "event": "deployment.success",
  "data": {
    "name": "main",
    "status": "ACTIVE",
    "user_id": "65a1...",
    "project_id": "65a2...",
    "team_id": null,
    "type": "web-service",
    "git": {
      "name": "acme-api",
      "full_name": "acme/acme-api",
      "id": 12345,
      "branch": "main",
      "installationId": 67890,
      "git": "github"
    },
    "compute": { "cpu": 1, "memory": 2, "storage": 0 },
    "message": "Add /healthz endpoint"
  }
}
```

Full payload schema for every event is in [Webhook events reference](/webhooks/events).

## Verifying the source

Webhooks reach your endpoint through Brimble's webhook delivery layer. The body is JSON with `{event, data}`; nothing else changes between deliveries.

Treat the **endpoint URL itself as a shared secret**. Don't post your webhook URL publicly, in client-side code, in logs, or in screenshots. Anyone with the URL can post to it.

For high-trust workflows (sending notifications you'll act on, mutating state in response to webhook events), require an additional secret on top of the URL. The simplest pattern is appending a token to the path:

```
https://your-endpoint.example.com/brimble?token=<long-random-string>
```

Reject any request that doesn't include the matching token. The token is private to you and Brimble; only requests originating from your configured webhook will carry it.

## Discord and Slack delivery

Discord and Slack URLs are pre-authenticated by URL secrecy. Each event is rendered as a channel message:

* **Discord** gets an embed-style message with project name, event, and a short summary.
* **Slack** gets a block-formatted message with the same fields.

You can configure all three URLs at once. The same event delivers to each independently. If your HTTP endpoint times out, the Discord and Slack messages still post.

## Delivery semantics

* **At-least-once.** A delivery may be retried if your endpoint fails or times out. Make your handler idempotent. Keying on `data.project_id` (or `data.domain_id`, etc.) plus `event` plus the relevant timestamp works for most resources.
* **Order is not guaranteed.** Two events from the same project can arrive out of order. Use `created_at` / `updated_at` from `data` to reconcile.
* **Best-effort delivery.** After repeated failures, a delivery is dropped. Your webhook stays enabled and continues to receive future events.
* **No automatic disable.** If your endpoint has been broken for hours, deliveries are dropped, but new events keep being attempted.

<Warning>
  **Always return `200` quickly, then process asynchronously.** Returning a non-2xx status, or taking too long to respond, triggers retries and surfaces as duplicate deliveries. Acknowledge first, queue the work, then run downstream calls outside the request handler.
</Warning>

## Test a webhook

Click **Send test event** on the webhook in the dashboard. The dashboard fires a synthetic event of the type you pick at the URL you've configured. Test events use the same envelope as real events.

## Troubleshooting

**No deliveries at all.** The webhook URL may not be saved. Check the webhook settings page in the dashboard. Also confirm the events list isn't empty.

**Some events arrive, others don't.** The events you're missing aren't in your subscription list. Add them, or pass `["*"]` to subscribe to everything.

**Discord/Slack worked once, now silent.** The incoming-webhook URL was regenerated or removed at Discord/Slack (someone with admin on the channel did it, or the integration was reinstalled). Generate a new URL there and paste it back into Brimble's webhook settings.

**Endpoint times out under load.** Acknowledge fast (return 200 immediately), then process asynchronously. Don't run downstream calls inside the request handler.

**Rapid duplicate deliveries.** Most likely your endpoint returned a non-2xx status, triggering a retry. Confirm you return 200 even when the body is malformed; never error inside the handler before sending the response.

## Next steps

* [Webhook events reference](/webhooks/events), every event with full payload schema.
* [Deployments](../projects/deployments), what triggers each `deployment.*` event.
