# Link tracking

3 endpoints.

## Read a workspace's link-tracking settings and channel overrides

```http
GET https://orbitwrite.com/api/v1/link-tracking
```

Requires `linkTracking:read`. Returns the workspace settings plus every channel that overrides them — read this to know how a link in a post you schedule will be tagged when it publishes.

**Authentication:** bearer token or session cookie.

### Query parameters

- `organizationId` (string, optional) — Session callers only — an API key already determines the workspace.

### Responses

#### 200

The workspace settings and its channel overrides

- `workspace` (LinkTrackingSettings | any | null, required) — Null when the workspace has never configured link tracking — distinct from configured-and-disabled.
- `accounts` (object[], required) — Only channels carrying an override; every other channel inherits the workspace settings.
  - `accountId` (string, required)
  - `platform` (string, required)
  - `override` (LinkTrackingOverride, required)
    - `enabled` (boolean | null, required)
    - `params` (LinkTrackingParam[] | null, required)
      - `key` (string, required) — utm_source / pk_source style key.
      - `value` (string, required) — May reference {{platform}} and {{campaign}}, resolved per post at publish time.

#### 400

Invalid request

- `error` (string, required)
- `issues` (any[], optional)

#### 401

Not signed in

- `error` (string, required)
- `issues` (any[], optional)

#### 403

Not a member of the organization

- `error` (string, required)
- `issues` (any[], optional)

## Save a workspace's link-tracking settings

```http
PUT https://orbitwrite.com/api/v1/link-tracking
```

Requires `linkTracking:update`. A full save of the three fields — the settings form always sends them whole, and a partial write would make an empty domain list indistinguishable from an untouched one.

**Authentication:** bearer token or session cookie.

### Request body (`application/json`)

- `enabled` (boolean, required)
- `params` (LinkTrackingParam[], required) — Appended in order. Parameter names must be unique — a repeated name is a 400, not a silently dropped entry.
  - `key` (string, required) — utm_source / pk_source style key.
  - `value` (string, required) — May reference {{platform}} and {{campaign}}, resolved per post at publish time.
- `domains` (string[], required) — Hostnames to tag, subdomains included. Empty tags every link. Normalized on save (a pasted URL collapses to its host), so the response is what was stored.
- `organizationId` (string, optional) — Session callers only — an API key already determines the workspace.

### Responses

#### 200

The saved settings, with domains as normalized

- `workspace` (LinkTrackingSettings, required)
  - `enabled` (boolean, required)
  - `params` (LinkTrackingParam[], required) — Appended in order. Parameter names must be unique — a repeated name is a 400, not a silently dropped entry.
    - `key` (string, required) — utm_source / pk_source style key.
    - `value` (string, required) — May reference {{platform}} and {{campaign}}, resolved per post at publish time.
  - `domains` (string[], required) — Hostnames to tag, subdomains included. Empty tags every link. Normalized on save (a pasted URL collapses to its host), so the response is what was stored.

#### 400

Invalid request

- `error` (string, required)
- `issues` (any[], optional)

#### 401

Not signed in

- `error` (string, required)
- `issues` (any[], optional)

#### 403

Not a member of the organization

- `error` (string, required)
- `issues` (any[], optional)

#### 404

The resource does not exist

- `error` (string, required)
- `issues` (any[], optional)

## Set or clear one channel's link-tracking override

```http
PUT https://orbitwrite.com/api/v1/link-tracking/account
```

Requires `linkTracking:update`. A null field inherits the workspace value; `params`, when set, replaces the workspace list rather than merging. A null override — or one whose every field is null — clears the row back to full inheritance.

**Authentication:** bearer token or session cookie.

### Request body (`application/json`)

- `organizationId` (string, optional) — Session callers only — an API key already determines the workspace.
- `accountId` (string, required)
- `override` (LinkTrackingOverride | any | null, required)

### Responses

#### 200

The override as stored, or null when cleared

- `override` (LinkTrackingOverride | any | null, required) — Null when the override was cleared — including when every field of the submitted override was null, which is inheritance spelled longhand.

#### 400

Invalid request

- `error` (string, required)
- `issues` (any[], optional)

#### 401

Not signed in

- `error` (string, required)
- `issues` (any[], optional)

#### 403

Not a member of the organization

- `error` (string, required)
- `issues` (any[], optional)

#### 404

The resource does not exist

- `error` (string, required)
- `issues` (any[], optional)
