# Connecting Linear

> Import Linear issues as ProductOS features with a personal API key, keep them fresh with syncs, and mark the Linear issue done when the feature ships.

Source: https://productos.ca/documentation/guides/integrations/linear (last reviewed 2026-09-22)

Linear connects with a personal API key. Issues import as ProductOS features (one-way, Linear → ProductOS) and re-sync on demand; the one write-back is that shipping a feature marks its Linear issue done.

## What it does

- **Issue → Feature import.** Pick a team key (or leave it empty for every team the key can read). Each issue becomes a feature with title (`ENG-123: …`), description, status, priority, effort (from the estimate), start and target dates, team, labels as tags, and the Linear URL and identifier under `metadata.linear`.
- **Status sync (Linear → ProductOS).** Every sync re-maps the issue's workflow state onto the feature's status. Existing features are matched by Linear issue ID, so nothing duplicates.
- **Shipped write-back.** When a feature imported from Linear is set to `shipped` in ProductOS, the Linear issue is moved to the team's first *completed*-type state. No other field is pushed back.
- **Import wizard.** **Import from Linear** previews issues page by page, flags the ones already imported, and only writes the ones you tick.

There is no comment mirroring and no ProductOS widget inside Linear.

## Connecting

1. In Linear, create a personal API key under **Settings → API** (read access to issues and projects is enough).
2. **Settings → Integrations → Linear → Connect.** Paste the key (`lin_api_…`), optionally set **Team key filter** (e.g. `ENG`) and **Max pages per sync** (default 4; 50 issues per page, so 200 issues per run, hard cap 10 pages), then **Connect & test**. The test runs Linear's `viewer` query and shows who the key belongs to.
3. Run **Sync now** or **Import from Linear** for the first pull.

## Status mapping

Linear workflow states are mapped by their *type*, so custom state names work without configuration; there is no in-app override:

| Linear state type (typical names) | ProductOS `status` |
| :--- | :--- |
| Triage | `discovery` |
| Backlog | `planned` |
| Unstarted (Todo) | `planned` |
| Started (In Progress, In Review) | `in-progress` |
| Completed (Done) | `shipped` |
| Canceled | `wont-do` |

Estimates map to effort: 1 → `xs`, 2 → `s`, 3 → `m`, 5 → `l`, 8 and up → `xl`.

## Priority mapping

| Linear priority | ProductOS `priority` |
| :--- | :--- |
| Urgent | `critical` |
| High | `high` |
| Medium | `medium` |
| Low | `low` |
| No priority | (unset) |

## Conflict resolution

Linear is the authority for the fields it imports. Each sync overwrites title, description, status, priority, effort, dates, team and `metadata` with Linear's values, so edits you make to those fields in ProductOS are replaced on the next sync. Keep ProductOS-only context in the links along the Golden Thread (themes, feedback, initiatives, releases), which the sync never touches.

## Webhook events

An inbound endpoint exists at `POST /api/webhooks/linear/{workspaceId}`: Linear `Issue` events (create and update upsert the feature, `remove` deletes it) are accepted after the `Linear-Signature` header verifies as HMAC-SHA256 of the raw body with the webhook secret, and anything else is ignored. Registering the webhook and its secret isn't exposed in Settings, so Linear sync is poll-based: changes land on the next **Sync now**.

## Disconnecting

**Settings → Integrations → Linear → Disconnect.** No-op on the Linear side; in ProductOS, the imported features stay (with the Linear URL and identifier preserved under `metadata.linear`) but stop receiving updates. There is no bulk unlink; delete the imported features or leave them.

## Next

- [Golden Thread](https://productos.ca/documentation/guides/concepts/golden-thread): how Linear issues fit into the upstream/downstream graph.
- [Webhooks reference](https://productos.ca/documentation/api/v1/webhooks): signature verification details.
