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

# Events and event destinations

> Thin, signed events delivered to your endpoint, with a 30 day log and redelivery

Subscribe an HTTPS endpoint to the events you care about and stop polling. Every delivery is a **thin event**: what happened and to which object, never the object itself. Fetch the current state from `related_object.url`, or the full event (with `data` and `changes`) from `GET /v2/events/{id}`.

## Event destinations

`POST /v2/event_destinations` (scope `events:write`):

```bash theme={null}
curl https://api.redbark.com/v2/event_destinations \
  -H "Authorization: Bearer rbk_live_..." \
  -H "Redbark-Version: 2026-10-01.wattle" \
  -H "Content-Type: application/json" \
  -d '{ "name": "CI", "webhook_endpoint": { "url": "https://example.com/redbark" }, "enabled_events": ["sync_run.*", "connection.*"] }'
```

```json theme={null}
{
  "id": "ed_5Rt7Uv9wXy1zAb3cDe5fGh",
  "object": "event_destination",
  "name": "CI",
  "type": "webhook_endpoint",
  "webhook_endpoint": { "url": "https://example.com/redbark", "signing_secret": "rbk_whsec_…" },
  "enabled_events": ["sync_run.*", "connection.*"],
  "event_payload": "thin",
  "status": "enabled",
  "status_details": null,
  "metadata": null,
  "livemode": true,
  "created": "2026-08-21T02:00:00.000Z",
  "updated": "2026-08-21T02:00:00.000Z"
}
```

The signing secret is returned on create and on rotate only; store it then (it is `null` on every other read). `event_payload` is `thin` today; `snapshot` is reserved and currently rejected with `400 parameter_invalid` (full transaction payloads stay on [webhook destinations](/api-reference/webhooks)). `enabled_events` accepts exact types, families (`sync_run.*`) or `*`. Up to 10 destinations per account.

| Method and path                                                 | Notes                                                                      |
| --------------------------------------------------------------- | -------------------------------------------------------------------------- |
| `GET /v2/event_destinations`, `GET /v2/event_destinations/{id}` |                                                                            |
| `POST /v2/event_destinations/{id}`                              | `name`, `webhook_endpoint.url`, `enabled_events`, `metadata`               |
| `DELETE /v2/event_destinations/{id}`                            |                                                                            |
| `POST /v2/event_destinations/{id}/enable` / `disable`           |                                                                            |
| `POST /v2/event_destinations/{id}/ping`                         | Sends `event_destination.ping` to this destination only; returns the event |
| `POST /v2/event_destinations/{id}/rotate_secret`                | New secret; the old one verifies for 24 more hours                         |

## The delivered payload

```json theme={null}
{
  "id": "evt_2Hj4Kl6mNp8qRs0tUv2wXy",
  "object": "event",
  "type": "sync_run.succeeded",
  "created": "2026-08-21T02:00:09.000Z",
  "livemode": true,
  "reason": { "type": "request", "request": { "id": "req_6xB3V3zmWkNGSCARJFA1UE", "idempotency_key": "run-1" } },
  "related_object": { "id": "run_4Kt7Lm2nPq9rSv1wXy3zAb", "type": "sync_run", "url": "https://api.redbark.com/v2/sync_runs/run_4Kt7Lm2nPq9rSv1wXy3zAb" }
}
```

Headers: `Redbark-Signature`, `Redbark-Delivery-Id`, `Redbark-Event-Id`, `User-Agent: Redbark-Events/1.0`. Payloads are unversioned. Respond with any 2xx within 30 seconds.

## Verifying signatures

`Redbark-Signature: t=1755741609,v1=5257a869e7…` where each `v1` is HMAC-SHA256 of `"{t}.{raw_body}"` with a signing secret. During the 24 hours after a rotate there are two `v1` values; accept the delivery if any matches. Reject deliveries whose `t` is more than 5 minutes old.

```ts theme={null}
import { createHmac, timingSafeEqual } from 'node:crypto'

export function verifyRedbarkSignature(header: string, rawBody: string, secret: string, toleranceSeconds = 300): boolean {
  const parts = Object.fromEntries(header.split(',').map((kv) => kv.split('=') as [string, string]))
  const t = Number(parts.t)
  if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSeconds) return false
  const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex')
  return header
    .split(',')
    .filter((kv) => kv.startsWith('v1='))
    .some((kv) => {
      const sig = kv.slice(3)
      return sig.length === expected.length && timingSafeEqual(Buffer.from(sig), Buffer.from(expected))
    })
}
```

## Delivery and retries

Deliveries are at-least-once and unordered; deduplicate on `id`. A non-2xx or a timeout is retried with exponential backoff (1 minute, 5, 30, 2 hours, 6, 12, then daily) for up to 3 days, after which the delivery is abandoned. A destination that has failed continuously for 3 days is disabled (`status_details.reason = "delivery_failures"`) and `event_destination.disabled` is emitted; fix the endpoint and `POST …/enable`.

## The event log

`GET /v2/events?type[]=sync_run.*` (scope `events:read`) lists the last 30 days of events for resources your key can read. `GET /v2/events/{id}` returns the full event with `data`, `changes` and every delivery attempt. `POST /v2/events/{id}/redeliver` (`events:write`) queues a fresh delivery to every subscribed destination, or one with `{ "event_destination": "ed_…" }`.

## Event types

| Type                                                                                        | When                                                                                                                                                                                                                           |
| ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `connection.created`, `connection.refreshed`                                                | A bank or brokerage connection landed or re-materialised                                                                                                                                                                       |
| `connection.expiring`, `connection.expired`, `connection.invalidated`, `connection.revoked` | Consent lifecycle                                                                                                                                                                                                              |
| `sync.created`, `sync.updated`, `sync.deleted`, `sync.attention`                            | Sync configuration; `attention` carries `data.code`                                                                                                                                                                            |
| `sync_run.queued`, `sync_run.succeeded`, `sync_run.failed`, `sync_run.cancelled`            | Run lifecycle; `succeeded` and `failed` carry counts or the failure message in `data`                                                                                                                                          |
| `destination.reauth_required`, `destination.disabled`                                       | A destination needs attention                                                                                                                                                                                                  |
| `category.created`, `category.updated`, `category.deleted`                                  | Taxonomy changes                                                                                                                                                                                                               |
| `event_destination.disabled`, `event_destination.ping`                                      | About the destination itself                                                                                                                                                                                                   |
| `transactions.synced`, `trades.synced`                                                      | A run wrote new rows; `data` carries counts only. Full payloads stay on [webhook destinations](/api-reference/webhooks), which keep their `X-Redbark-Signature` / `X-Redbark-Timestamp` headers until they are next versioned. |
