Integrations
Linear
Create and manage Linear issues, cycles, and projects through Conductor. Covers personal API keys, OAuth apps, finding workspace and team IDs, state UUID lookup, priority values, and webhook configuration.
Authentication
Personal API Key
The quickest way to get started. Acts with the same permissions as your Linear user account. Goes to Settings → API → Personal API keys. Ideal for individual automation. Tokens start with lin_api_.
OAuth App
For team tools or products that multiple Linear users connect to. Create an OAuth app under Settings → API → OAuth applications. Users authorize via Linear's consent screen. More setup, but doesn't rely on one person's account.
Creating a personal API key
- 01Open Linear and click your workspace name in the top-left corner → Settings.
- 02In the left sidebar, scroll to My Account → API.
- 03Under Personal API keys, click Create key. Give it a descriptive label (e.g., "Conductor").
- 04Copy the key immediately — Linear only shows it once. It starts with lin_api_.
- 05Add it to your Conductor config (see below).
Finding workspace and team IDs
// Your workspace slug is in the Linear URL:
// https://linear.app/YOUR-SLUG/settings
// ^^^^^^^^^^^
// Example: https://linear.app/acme/settings → slug is "acme"
// Team IDs: linear.team.list({}) returns id, name, key, slug
// Project IDs: linear.project.list({}) returns id, name, slugId
// Member IDs: linear.member.list({}) returns id, name, email, displayNameConductor config
Personal API key (most common)
{
"plugins": {
"linear": {
"api_key": "lin_api_your-personal-api-key"
}
}
}OAuth app
{
"plugins": {
"linear": {
"client_id": "your-oauth-client-id",
"client_secret": "your-oauth-client-secret",
"redirect_uri": "https://yourapp.com/linear/callback",
"access_token": "lin_oauth_access_token"
}
}
}Available tools
| Tool | Description |
|---|---|
| linear.issue.create | Create a new issue in a team. Returns the created issue ID and identifier (e.g., ENG-123). |
| linear.issue.list | List issues with optional filters for team, state, assignee, cycle, project, and priority. |
| linear.issue.update | Update any field on an existing issue: title, description, state, priority, assignee, labels. |
| linear.issue.comment | Add a comment to an issue. Supports Markdown in the body. |
| linear.issue.assign | Assign an issue to a team member by their user UUID. |
| linear.cycle.list | List all cycles (sprints) for a team, including active, upcoming, and completed ones. |
| linear.project.list | List all projects in the workspace. Projects span across teams. |
| linear.team.list | List all teams in the workspace with their IDs, keys, and slugs. |
| linear.member.list | List all members of the workspace with their user IDs, names, and emails. |
| linear.label.list | List all labels available in the workspace or for a specific team. |
Priority values
Linear uses numeric priority values. Lower numbers are higher priority. Priority 0 means no priority has been assigned.
| Value | Label | Notes |
|---|---|---|
| 0 | No priority | Issue has not been prioritized yet |
| 1 | Urgent | Needs immediate attention, blocks others |
| 2 | High | Important, should be addressed soon |
| 3 | Medium | Normal priority work |
| 4 | Low | Nice to have, address when time permits |
Issue state IDs
State names like "In Progress" or "Done" are human labels — the API uses UUIDs. Each team has its own set of workflow states. You must look up the UUID for the state you want before creating or updating issues.
// State IDs are UUIDs — you can't use names like "In Progress" directly.
// To find state IDs for a team:
linear.team.list({})
// Then use the team ID to list workflow states via the API:
// GET https://api.linear.app/graphql with query:
// { team(id: "TEAM-UUID") { states { nodes { id name type } } } }
//
// State types: "triage", "backlog", "unstarted", "started", "completed", "cancelled"
// Note: within each type there can be multiple custom states with their own UUIDs.State types (backlog, started, completed, etc.) are consistent across teams, but the specific states within each type are team-specific with unique UUIDs.
Usage examples
Creating an issue
// Create a new issue
linear.issue.create({
teamId: "TEAM-UUID-HERE", // required: UUID, not the slug
title: "Fix login redirect bug",
description: "Users are being redirected to /404 after login.",
priority: 2, // 0=None, 1=Urgent, 2=High, 3=Medium, 4=Low
stateId: "STATE-UUID-HERE", // optional: UUID of the workflow state
assigneeId: "USER-UUID-HERE", // optional
labelIds: ["LABEL-UUID-1"], // optional: array of label UUIDs
projectId: "PROJECT-UUID-HERE" // optional
})Listing and filtering issues
// List issues with filters
linear.issue.list({
teamId: "TEAM-UUID-HERE",
filter: {
state: { name: { eq: "In Progress" } },
assignee: { id: { eq: "USER-UUID-HERE" } },
priority: { gte: 2 } // 2 = High priority or higher (lower number = higher priority)
},
orderBy: "updatedAt",
first: 25
})
// Filter by cycle
linear.issue.list({
cycleId: "CYCLE-UUID-HERE",
filter: { state: { type: { neq: "completed" } } }
})
// Filter by project
linear.issue.list({
projectId: "PROJECT-UUID-HERE"
})Updating an issue
// Update an issue
linear.issue.update({
issueId: "ISSUE-UUID-HERE", // UUID, not the identifier like ENG-123
title: "Updated title",
stateId: "NEW-STATE-UUID",
priority: 1, // escalate to Urgent
assigneeId: null // unassign
})Commenting on an issue
// Add a comment to an issue
linear.issue.comment({
issueId: "ISSUE-UUID-HERE",
body: "Investigated this — it's caused by the session token expiry. Fix in progress."
})Working with cycles (sprints)
// List cycles (sprints) for a team
linear.cycle.list({
teamId: "TEAM-UUID-HERE"
})
// Returns: id, name, number, startsAt, endsAt, completedAt, progress
// Get active cycle issues
linear.issue.list({
filter: {
cycle: { isActive: { eq: true } },
team: { id: { eq: "TEAM-UUID-HERE" } }
}
})Working with projects
// List projects
linear.project.list({
first: 50
})
// List issues in a project
linear.issue.list({
projectId: "PROJECT-UUID-HERE",
filter: {
state: { type: { neq: "cancelled" } }
}
})Webhooks from Linear
// Linear can send webhooks to Conductor when issues change.
// Configure at: linear.app/YOUR-SLUG/settings/api → Webhooks
//
// Supported events:
// Issue — created, updated, removed
// Comment — created, updated, removed
// Cycle — created, updated, removed
// Project — created, updated, removed
// IssueLabel — created, updated, removed
//
// The webhook payload includes the resource type, action, and full object data.
// Conductor receives these and can trigger automations based on the event.Rate limits
Linear uses a GraphQL API with complexity-based rate limiting. Each query is assigned a complexity cost based on how many resources it fetches. The limit is 1,500 complexity points per minute. Simple mutations (create, update) cost around 5–10 points. Paginated list queries cost more depending on the first argument. The API response includes X-RateLimit-Requests-Remaining and X-RateLimit-Complexity-Remaining headers so you can track usage. HTTP 429 is returned when you exceed the limit; retry after 60 seconds.
Common errors
Authentication required
API key is missing or malformed in the request
Fix: Verify the token starts with lin_api_. Check there are no extra spaces or newlines in the config.
Entity not found
The UUID you passed doesn't correspond to any object in the workspace
Fix: Re-fetch the ID. UUIDs are case-sensitive. Make sure you're not mixing up team IDs, issue IDs, and user IDs.
You don't have permission
The API key belongs to a user who lacks access to the resource
Fix: Use an API key from a user with admin or member access. Guest users have restricted API access.
Argument validation error
A field value is wrong type, out of range, or refers to a non-existent enum value
Fix: Check priority is 0–4. Check stateId, assigneeId, and labelIds are valid UUIDs. Check dates are ISO 8601.