> ## 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.

# Connecting banks and destinations

> Link sessions for bank consent, connection lifecycle, institutions, destination links and destinations

## Link sessions (connect a bank)

Bank consent has to happen on a hosted page (CDR). The API mints a **link session** and you send the user to its `url`; they sign in to Redbark with the same account the key belongs to, finish the bank's consent, and land on your `return_url` with `?link_session=completed` (or `failed&reason=…`).

```bash theme={null}
curl https://api.redbark.com/v2/link_sessions \
  -H "Authorization: Bearer rbk_live_..." -H "Redbark-Version: 2026-10-01.wattle" \
  -H "Content-Type: application/json" \
  -d '{ "provider": "fiskil", "institution": "inst_fk_anz", "return_url": "https://example.com/connected" }'
```

```json theme={null}
{
  "id": "ls_7Kp3Lm5nQr7sTu9vWx1yZa",
  "object": "link_session",
  "provider": "fiskil",
  "institution": "inst_fk_anz",
  "status": "pending",
  "url": "https://app.redbark.com/link/ls_7Kp3Lm5nQr7sTu9vWx1yZa",
  "connection": null,
  "return_url": "https://example.com/connected",
  "failure_reason": null,
  "expires_at": "2026-08-21T02:30:00.000Z",
  "completed_at": null,
  "metadata": null,
  "livemode": true,
  "created": "2026-08-21T02:00:00.000Z",
  "updated": "2026-08-21T02:00:00.000Z"
}
```

`institution` (Fiskil only) must be an id from `GET /v2/institutions`. Poll `GET /v2/link_sessions/{id}` until `status` is `completed` (then `connection` is set) or subscribe to `connection.created`. Sessions expire after 30 minutes. Scope `connections:write`.

## Connection lifecycle

| Method and path                         | Notes                                                                                                         |
| --------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| `POST /v2/connections/{id}/reauthorize` | Returns a link session bound to the connection; completing it renews consent in place                         |
| `POST /v2/connections/{id}/refresh`     | Queues a run for every enabled sync reading this connection; returns the runs (202)                           |
| `DELETE /v2/connections/{id}`           | Withdraws consent at the provider, disables dependent syncs, queues data deletion; emits `connection.revoked` |

`GET /v2/institutions?provider=fiskil&q=anz` lists banks with current availability (scope `connections:read`):

```json theme={null}
{ "id": "inst_fk_anz", "object": "institution", "provider": "fiskil", "name": "ANZ", "short_name": "ANZ", "logo": "https://…", "available": true, "status": "ONLINE" }
```

`available` and `status` answer different questions and can disagree. `available` is whether we offer the bank for linking at all; `status` is what the provider reports about it right now (`ONLINE`, `OUTAGE`, or `null` when unknown). `available: true` with `status: "OUTAGE"` is the normal way a supported bank looks during an outage: the link session will be created, but the consent may not complete until the bank is back.

## Destination links (Sheets, Notion, Airtable, YNAB)

OAuth destinations go through a **destination link**: `POST /v2/destination_links { type, return_url }` → send the user to `url`. On completion a draft destination exists (`status: incomplete`, `destination` set on the link). Then:

1. `GET /v2/destinations/{id}/resources?type=spreadsheet` (or `sheet&parent=<spreadsheet id>`, `database`, `base`, `table&parent=app…`, `budget`, `account&parent=…`, `category&parent=…`) to see what the grant can reach. A child type with no `parent` falls back to the destination's current target, so `type=sheet` alone lists the tabs of the spreadsheet the destination already points at.
2. `POST /v2/destinations/{id} { "target": { "spreadsheet_id": "1AbC…", "sheet_id": 0 } }` to aim it. The destination becomes `active`.

Targets by type: Sheets `spreadsheet_id` (+ `sheet_id`, names), Notion `database_id`, Airtable `base_id` + `table_id`, YNAB `budget_id`, Webhook `url`.

## Webhook destinations

Created directly: `POST /v2/destinations { "type": "webhook", "name": "My endpoint", "target": { "url": "https://example.com/redbark" } }`. The signing secret (`config.signing_secret`) is returned on create and `POST /v2/destinations/{id}/rotate_secret` only; store it then. Payloads and headers are documented under [Webhooks](/api-reference/webhooks).

## The destination object

```json theme={null}
{
  "id": "dest_3Fg5Hj7kLm9nPq1rSt3uVw",
  "object": "destination",
  "type": "sheets",
  "name": "Budget 2026",
  "status": "active",
  "target": { "spreadsheet_id": "1AbC…", "spreadsheet_name": "Budget 2026", "sheet_id": 0, "sheet_name": "Transactions" },
  "config": null,
  "sync_count": 1,
  "metadata": null,
  "livemode": true,
  "created": "2026-03-01T10:05:00.000Z",
  "updated": "2026-08-21T02:00:00.000Z"
}
```

`status`: `active`, `incomplete` (no target yet), `reauth_required` (the grant failed on a sync; use a new destination link or the dashboard), `disabled` (auto-disabled webhook; `POST …/enable`).

| Method and path                                                                                 | Scope                                                |
| ----------------------------------------------------------------------------------------------- | ---------------------------------------------------- |
| `GET /v2/destinations`, `GET /v2/destinations/{id}`                                             | destinations:read                                    |
| `POST /v2/destinations` (webhook), `POST /v2/destinations/{id}`, `DELETE /v2/destinations/{id}` | destinations:write                                   |
| `POST /v2/destinations/{id}/rotate_secret`, `POST /v2/destinations/{id}/enable`                 | destinations:write                                   |
| `GET /v2/destinations/{id}/resources`                                                           | destinations:read (mid tier; live from the provider) |

Deleting a destination also deletes syncs that only wrote to it; `409 destination_in_use` while a run is writing.
