Linear
Preview
Create and update Linear issues and read what your team shipped.
- Status: Preview
- Shelf: Developer
- How you connect: API key
- Regions: global (not available to Kazakhstan-only workspaces)
- The service’s own API reference: https://linear.app/developers/graphql
Apps create and update Linear issues and read what a team finished, with a personal API key.
Linear is reached through the HTTP API connector with a preset: the gate calls only
api.linear.app/graphql, with POST. The key is sealed to the gate and apps never see it.
Connect it#
- In Linear: Settings → Account → Security & access → Personal API keys → New API key (linear.app/settings/account/security).
- Give it only the permissions the apps need: Read, and Create issues if apps open issues. Leave out Admin.
- Copy the key (it starts with
lin_api_; Linear shows it once). - Qaldy → Connectors → Linear → Connect Linear → paste the key → Seal and connect.
A personal key acts as you, with your access to teams. Create it from a shared or machine account if the apps should not be tied to one person.
Test connection only checks that the sealed key opens. Linear has no GET to test with and
the preset allows only POST, so the gate sends nothing; the first real call proves the key.
What the gate allows#
| Host | api.linear.app (pinned, every resolved address public) |
| Method | POST only |
| Path | /graphql |
| Key | Authorization: <key>, added by the gate (Linear takes a personal key without Bearer) |
GraphQL means one path carries every operation, so the fence is the host, the method and the key's own permissions; the typed helper below sends only the documented operations.
Use it from an app#
{ "id": "http", "actions": ["request"], "scope": "conn_k3v9…" }import { linear } from '@qaldy/sdk'
const ln = linear(ctx.connectors.http('conn_k3v9…'))
const { teams } = await ln.listTeams()
const { issues } = await ln.listIssues({ teamId: teams[0]?.id, completedSince: '2026-10-12T00:00:00Z' })
await ln.createIssue({ teamId: teams[0]?.id ?? '', title: 'Checkout shows the wrong total', priority: 2 })
await ln.updateIssue({ id: issues[0]?.id ?? '', description: 'Seen on mobile only.' })The helper checks the input before anything is sent and decodes the reply; a GraphQL errors
array becomes an error with Linear's own words.
When it breaks#
| You see | Why | Do |
|---|---|---|
401 / "Authentication required" | The key was revoked or mistyped | Replace the key |
RATELIMITED | Linear's request or complexity limit | Read fewer issues per call, run less often |
| "Entity not found" for a team or state | The id is from another workspace, or deleted | List teams again and pick one |
"Forbidden" on createIssue | The key lacks Create issues | Make a new key with it |
Gaps#
- Not run against a live workspace (hence Preview).
- No webhooks from Linear, no comments, projects or cycles; only issues and teams.
- Test connection sends nothing (see above).