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

# Quickstart

# Quickstart: receive your first webhook

## 1. Create an HTTPS webhook endpoint

Create a route in your application that can receive Brale webhook deliveries.

Example endpoint:

```
POST https://your-app.example.com/webhooks/brale
```

For local development:

```bash theme={null}
ngrok http 4000
```

Then use:

```
https://<your-ngrok-host>/webhooks/brale
```

## 2. Get an access token with webhook scopes

Your OAuth application or API credential needs webhook scopes (these are provisioned by default when you make a credential set).

| Scope | Required for |
| - | - |
| `webhooks:read` | List event types, list subscriptions, inspect delivery logs |
| `webhooks:write` | Create, update, and archive webhook subscriptions |

For subscription creation, use a credential with both `webhooks:read` and `webhooks:write`.

## 3. Discover available event types

```bash theme={null}
curl https://api.brale.xyz/accounts/{account_id}/webhooks/event_types \
  -H "Authorization: Bearer {access_token}"
```

Example response:

```json theme={null}
{
  "event_types": [
    {
      "event_type": "payment.completed",
      "summary": "Emitted when a payment reaches complete status."
    },
    {
      "event_type": "transfer.completed",
      "summary": "Emitted when a transfer (token order) reaches complete status."
    },
    {
      "event_type": "transfer.failed",
      "summary": "Emitted when a transfer (token order) reaches failed status."
    }
  ]
}
```

## 4. Create a webhook subscription

Create a subscription for your endpoint and event types.

<Note>
  **Choose your `account_id`.** The `account_id` in the path is the account that owns the subscription. If you onboard customers as managed accounts, use your managing account ID. One subscription covers events for the managing account and its managed accounts, so you don't need one per customer. Register it before onboarding customers so it is ready for asynchronous verification events. See [Choose the subscription owner](/webhooks/overview#choose-the-subscription-owner).
</Note>

```bash theme={null}
curl -X POST https://api.brale.xyz/accounts/{account_id}/webhooks \
  -H "Authorization: Bearer {access_token}" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: {uuid}" \
  -d '{
    "url": "https://your-app.example.com/webhooks/brale",
    "events": ["transfer.completed"]
  }'
```

Example response:

```json theme={null}
{
  "id": "3D3jNzs2r7Sf78qtYpRe1biscLG",
  "sharedSecret": "base64url-encoded-secret",
  "events": ["transfer.completed"],
  "url": "https://your-app.example.com/webhooks/brale",
  "status": "active"
}
```

Important:

* `sharedSecret` is returned only once.
* Store it immediately in a secrets manager or encrypted environment variable.
* Do not log it.
* Do not expose it to browsers or client-side code.
* If you lose it, archive the subscription and create a new one.

### Example: managed-account onboarding

To receive verification events for customers you onboard, create the subscription on your managing account with `account.*`:

```bash theme={null}
curl -X POST https://api.brale.xyz/accounts/{managing_account_id}/webhooks \
  -H "Authorization: Bearer {access_token}" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: {uuid}" \
  -d '{
    "url": "https://your-app.example.com/webhooks/brale",
    "events": ["account.*"]
  }'
```

Each event's `data.account_id` identifies the account the event concerns, such as the managed customer whose verification completed. Use it to route the event to the right customer record.

## 5. Verify incoming webhooks

Every webhook includes:

```
x-request-signature-sha-256: <lowercase hex HMAC-SHA256>
idempotency-key: <deterministic UUID derived from event id>
content-type: application/json
```

Notes:

* Header names may appear with different capitalization depending on your framework/server. Treat them as case-insensitive.
* The `Idempotency-Key` you send to the management API is **not** the same concept as the `idempotency-key` header Brale sends with each webhook delivery. Use the webhook event `id` and/or the webhook `idempotency-key` header for deduplication.

Verification steps:

1. Read the exact raw request body bytes.
2. Decode `sharedSecret` from Base64URL to raw bytes.
3. Compute HMAC-SHA256 over the raw request body.
4. Encode the digest as lowercase hex.
5. Compare to `x-request-signature-sha-256` using constant-time comparison.
6. Only then parse and process the JSON payload.

## 6. Return 2xx quickly

Return any `2xx` response after verification and safe receipt.

If processing takes longer, acknowledge quickly and process asynchronously.

```
Verify signature → record event id → acknowledge 200 → process async
```

## 7. Deduplicate events

Webhook deliveries are at-least-once. Your endpoint may receive the same event more than once.

Deduplicate using:

* The envelope `id`
* The `idempotency-key` header

Process each logical event once.
