# Link Sessions API

Create link tokens and exchange public tokens. These are the server-side operations you call with an API key. Link-management operations remain withheld until their ownership failures are uniform. The in-flow operations the hosted page and the Elements SDK drive inside the iframe are not part of this reference — see [/docs/concepts/connection-flow.md](/docs/concepts/connection-flow.md).

> **Scope of this file.** It is the OPERATION reference for THIS resource, generated from the BillerAPI OpenAPI document served at [/docs/openapi.json](/docs/openapi.json): each API-key endpoint the resource owns, with its parameters, request body, responses and schemas. Narrative and catalog sections the rendered page also carries (walkthroughs, event taxonomies, payload catalogs) are NOT reproduced here — read [/docs/api/link-sessions](/docs/api/link-sessions) for those. Endpoints the hosted flow drives from inside the iframe, and dashboard-session endpoints, are absent by design: they are not API-key operations. [/docs/api.md](/docs/api.md) enumerates the full API-key surface, including the endpoints that have no reference page yet.

All request and response field names are snake_case. Errors use the coded envelope described in [/docs/concepts/errors.md](/docs/concepts/errors.md).

## Endpoints

- [`POST /v1/link-tokens`](#post-v1link-tokens)
- [`POST /v1/link-tokens/{linkTokenId}/exchange`](#post-v1link-tokenslinktokenidexchange)
- [`GET /v1/links/{id}`](#get-v1linksid)

## POST /v1/link-tokens

Create link token

Create a new link token for initiating account linking flow. Server-to-server: requires client credentials.

Operation ID: `createLinkToken`

Auth: `client-api-key`

**Request body** (required)

Schema: `CreateLinkTokenBodyDto`

| Field | Required | Type | Notes | Description |
| --- | --- | --- | --- | --- |
| `client_user_id` | yes | string | — | Your stable identifier for the end user this link belongs to. |
| `consents` | no | array<string> | — | Consent scopes the user is granting. |
| `client_id` | no | string | — | Explicit client id. Validated against the credential; 403 on mismatch. |
| `biller_id` | no | string | — | Pin the flow to a specific biller. |
| `connectivity_type` | no | string | — | Preferred connectivity type for the link. |
| `redirect_uri` | no | string | — | Where to send the user after a hosted flow. |
| `request_to_link_id` | no | string | — | Associate the token with an existing request-to-link. |
| `metadata_json` | no | string | — | Opaque JSON metadata string echoed back on the token. |
| `update` | no | CreateLinkTokenUpdateDto | — | Update-mode mint: repair an EXISTING Link (#4831). |
| `hosted` | no | object | — | Request a hosted connect flow: `true` or an options object. |
| `language` | no | string | — | BCP-47 UI language for the connect flow (#4937). Defaults to `en`. |
| `webhook_url` | no | string | **deprecated** | Ignored. Webhook delivery is governed by your registered webhook config. |

**Responses**

| Status | Description | Body |
| --- | --- | --- |
| 201 | Link token created successfully | — |
| 400 | Invalid request | — |
| 401 | Missing or invalid client credentials | — |
| 403 | Body client_id does not match the authenticated client, or update.link_id names a Link owned by another client/user | — |
| 404 | update.link_id names a Link that does not exist | — |

## POST /v1/link-tokens/{linkTokenId}/exchange

Exchange public token

Exchange a public token for an access token. Server-to-server: requires client credentials.

Operation ID: `exchangePublicToken`

Auth: `client-api-key`

**Parameters**

| Parameter | In | Required | Type | Notes | Description |
| --- | --- | --- | --- | --- | --- |
| `linkTokenId` | path | yes | string | — | — |

**Request body** (required)

Schema: `ExchangePublicTokenBodyDto`

| Field | Required | Type | Notes | Description |
| --- | --- | --- | --- | --- |
| `client_id` | no | string | — | Explicit client id. Validated against the credential; 403 on mismatch. |
| `public_token` | no | string | — | Public token, when not supplied in the path. |

**Responses**

| Status | Description | Body |
| --- | --- | --- |
| 200 | Token exchanged successfully | — |
| 400 | Invalid public token | — |
| 401 | Missing or invalid client credentials | — |
| 403 | Body client_id does not match the authenticated client | — |

## GET /v1/links/{id}

Get link by id for the authenticated client

Returns the full link entity (biller, status, scopes, dates, accounts) scoped to the session client_id. 404 if the link is unknown; 403 CLIENT_ID_MISMATCH if it belongs to a different client. The `:id` accepts BOTH the Stripe-style prefixed form `link_<uuid>` and a bare UUID (bare UUIDs remain accepted for backwards compatibility); responses return the prefixed `link_<uuid>` form.

Operation ID: `getById`

Auth: `client-api-key`

**Parameters**

| Parameter | In | Required | Type | Notes | Description |
| --- | --- | --- | --- | --- | --- |
| `id` | path | yes | string | — | — |

**Responses**

| Status | Description | Body |
| --- | --- | --- |
| 200 | Link entity. | — |
| 401 | No portal session (NEEDS_RESIGNIN). | — |
| 403 | Link belongs to a different client (CLIENT_ID_MISMATCH). | — |
| 404 | Link not found (LINK_NOT_FOUND). | — |

## Schemas

### CreateLinkTokenBodyDto

| Field | Always present | Type | Notes | Description |
| --- | --- | --- | --- | --- |
| `client_user_id` | yes | string | — | Your stable identifier for the end user this link belongs to. |
| `consents` | no | array<string> | — | Consent scopes the user is granting. |
| `client_id` | no | string | — | Explicit client id. Validated against the credential; 403 on mismatch. |
| `biller_id` | no | string | — | Pin the flow to a specific biller. |
| `connectivity_type` | no | string | — | Preferred connectivity type for the link. |
| `redirect_uri` | no | string | — | Where to send the user after a hosted flow. |
| `request_to_link_id` | no | string | — | Associate the token with an existing request-to-link. |
| `metadata_json` | no | string | — | Opaque JSON metadata string echoed back on the token. |
| `update` | no | CreateLinkTokenUpdateDto | — | Update-mode mint: repair an EXISTING Link (#4831). |
| `hosted` | no | object | — | Request a hosted connect flow: `true` or an options object. |
| `language` | no | string | — | BCP-47 UI language for the connect flow (#4937). Defaults to `en`. |
| `webhook_url` | no | string | **deprecated** | Ignored. Webhook delivery is governed by your registered webhook config. |

### CreateLinkTokenUpdateDto

| Field | Always present | Type | Notes | Description |
| --- | --- | --- | --- | --- |
| `link_id` | yes | string | — | The id of the Link to repair. |
| `reason` | no | string | — | Normalized reason echoed from the link.disconnected webhook: credentials_invalid \| mfa_required \| session_expired \| consent_expired. |

### ExchangePublicTokenBodyDto

| Field | Always present | Type | Notes | Description |
| --- | --- | --- | --- | --- |
| `client_id` | no | string | — | Explicit client id. Validated against the credential; 403 on mismatch. |
| `public_token` | no | string | — | Public token, when not supplied in the path. |


## See also

- [API reference index](/docs/api.md)
- [Authentication](/docs/guides/authentication.md)
- [Pagination](/docs/concepts/pagination.md)
- [Error handling](/docs/concepts/errors.md)
