Linear
Linear API integration with managed OAuth. Query and manage issues, projects, teams, cycles, and labels using GraphQL. Use this skill when users want to create, update, or query Linear issues, search
Linear API integration with managed OAuth. Query and manage issues, projects, teams, cycles, and labels using GraphQL. Use this skill when users want to create, update, or query Linear issues, search
Real data. Real impact.
Emerging
Developers
Per week
Open source
Skills give you superpowers. Install in 30 seconds.
Access the Linear API with managed OAuth authentication. Query and manage issues, projects, teams, cycles, labels, and comments using GraphQL.
# Get current user python <<'EOF' import urllib.request, os, json data = json.dumps({'query': '{ viewer { id name email } }'}).encode() req = urllib.request.Request('https://gateway.maton.ai/linear/graphql', data=data, method='POST') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') req.add_header('Content-Type', 'application/json') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
https://gateway.maton.ai/linear/graphql
All requests use POST to the GraphQL endpoint. The gateway proxies requests to
api.linear.app and automatically injects your OAuth token.
All requests require the Maton API key in the Authorization header:
Authorization: Bearer $MATON_API_KEY
Environment Variable: Set your API key as
MATON_API_KEY:
export MATON_API_KEY="YOUR_API_KEY"
Manage your Linear OAuth connections at
https://ctrl.maton.ai.
python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://ctrl.maton.ai/connections?app=linear&status=ACTIVE') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
python <<'EOF' import urllib.request, os, json data = json.dumps({'app': 'linear'}).encode() req = urllib.request.Request('https://ctrl.maton.ai/connections', data=data, method='POST') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') req.add_header('Content-Type', 'application/json') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
Response:
{ "connection": { "connection_id": "fda4dabb-9d62-47e3-9503-a2f29d0995df", "status": "ACTIVE", "creation_time": "2026-02-04T23:03:22.676001Z", "last_updated_time": "2026-02-04T23:03:51.239577Z", "url": "https://connect.maton.ai/?session_token=...", "app": "linear", "metadata": {} } }
Open the returned
url in a browser to complete OAuth authorization.
python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}', method='DELETE') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
If you have multiple Linear connections, specify which one to use with the
Maton-Connection header:
python <<'EOF' import urllib.request, os, json data = json.dumps({'query': '{ viewer { id name } }'}).encode() req = urllib.request.Request('https://gateway.maton.ai/linear/graphql', data=data, method='POST') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') req.add_header('Content-Type', 'application/json') req.add_header('Maton-Connection', 'fda4dabb-9d62-47e3-9503-a2f29d0995df') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
If omitted, the gateway uses the default (oldest) active connection.
Linear uses a GraphQL API. All operations are sent as POST requests with a JSON body containing the
query field.
POST /linear/graphql Content-Type: application/json{"query": "{ viewer { id name email } }"}
Response:
{ "data": { "viewer": { "id": "4933b394-c42f-4623-904f-355fc40a4858", "name": "Byungkyu Park", "email": "byungkyujpark@gmail.com" } } }
POST /linear/graphql Content-Type: application/json{"query": "{ organization { id name urlKey } }"}
POST /linear/graphql Content-Type: application/json{"query": "{ teams { nodes { id name key } } }"}
Response:
{ "data": { "teams": { "nodes": [ { "id": "70c49a0d-6973-4563-a743-8504f1a5171b", "name": "Maton", "key": "MTN" } ] } } }
POST /linear/graphql Content-Type: application/json{"query": "{ team(id: "TEAM_ID") { id name key issues { nodes { id identifier title } } } }"}
POST /linear/graphql Content-Type: application/json{"query": "{ issues(first: 10) { nodes { id identifier title state { name } priority createdAt } pageInfo { hasNextPage endCursor } } }"}
Response:
{ "data": { "issues": { "nodes": [ { "id": "565e2ee9-2552-48d8-bbf9-a8b79ca1baec", "identifier": "MTN-527", "title": "Shopify app verification", "state": { "name": "In Progress" }, "priority": 0, "createdAt": "2026-02-03T07:49:31.675Z" } ], "pageInfo": { "hasNextPage": true, "endCursor": "4c7b33c8-dabf-47ce-9d30-7f286f9463be" } } } }
POST /linear/graphql Content-Type: application/json{"query": "{ issue(id: "MTN-527") { id identifier title description state { name } priority assignee { name } team { key name } createdAt updatedAt } }"}
Filter by state type:
POST /linear/graphql Content-Type: application/json{"query": "{ issues(first: 10, filter: { state: { type: { eq: "started" } } }) { nodes { id identifier title state { name type } } } }"}
Filter by title:
POST /linear/graphql Content-Type: application/json{"query": "{ issues(first: 10, filter: { title: { containsIgnoreCase: "bug" } }) { nodes { id identifier title } } }"}
POST /linear/graphql Content-Type: application/json{"query": "{ searchIssues(first: 10, term: "shopify") { nodes { id identifier title } } }"}
POST /linear/graphql Content-Type: application/json{"query": "mutation { issueCreate(input: { teamId: "TEAM_ID", title: "New issue title", description: "Issue description" }) { success issue { id identifier title state { name } } } }"}
Response:
{ "data": { "issueCreate": { "success": true, "issue": { "id": "9dff693f-27d2-4656-9b2d-baa4a828dc83", "identifier": "MTN-528", "title": "New issue title", "state": { "name": "Backlog" } } } } }
POST /linear/graphql Content-Type: application/json{"query": "mutation { issueUpdate(id: "ISSUE_ID", input: { title: "Updated title", priority: 2 }) { success issue { id identifier title priority } } }"}
POST /linear/graphql Content-Type: application/json{"query": "{ projects(first: 10) { nodes { id name state createdAt } } }"}
POST /linear/graphql Content-Type: application/json{"query": "{ cycles(first: 10) { nodes { id name number startsAt endsAt } } }"}
POST /linear/graphql Content-Type: application/json{"query": "{ issueLabels(first: 20) { nodes { id name color } } }"}
Response:
{ "data": { "issueLabels": { "nodes": [ { "id": "510edbdf-9f6e-43a0-80e5-c3b3bd82e26f", "name": "Blocked", "color": "#eb5757" }, { "id": "cb7a7ef2-d2d3-4da2-ad4e-7cea0f8a72c7", "name": "Feature", "color": "#BB87FC" }, { "id": "c795d04c-24d2-4d20-b3c1-9f9f1ce7b017", "name": "Improvement", "color": "#4EA7FC" }, { "id": "40ff69f9-4a93-40a2-b143-f3b94aa594b7", "name": "Bug", "color": "#EB5757" } ] } } }
POST /linear/graphql Content-Type: application/json{"query": "{ workflowStates(first: 20) { nodes { id name type team { key } } } }"}
Response:
{ "data": { "workflowStates": { "nodes": [ { "id": "f21dfa65-7951-4742-a202-00ceb0ff6e9f", "name": "Backlog", "type": "backlog", "team": { "key": "MTN" } }, { "id": "1ab9475f-eb91-4207-a5a3-1176e38b85be", "name": "Todo", "type": "unstarted", "team": { "key": "MTN" } }, { "id": "ee724a62-0212-4b53-af67-08297a5ae132", "name": "In Progress", "type": "started", "team": { "key": "MTN" } }, { "id": "427a9916-3849-4303-b982-f00f1d79c5ee", "name": "Done", "type": "completed", "team": { "key": "MTN" } }, { "id": "363df32a-f22d-4083-8efb-b3615c019925", "name": "Canceled", "type": "canceled", "team": { "key": "MTN" } } ] } } }
POST /linear/graphql Content-Type: application/json{"query": "{ users(first: 20) { nodes { id name email active } } }"}
POST /linear/graphql Content-Type: application/json{"query": "{ comments(first: 10) { nodes { id body createdAt issue { identifier } user { name } } } }"}
POST /linear/graphql Content-Type: application/json{"query": "mutation { commentCreate(input: { issueId: "ISSUE_ID", body: "Comment text here" }) { success comment { id body } } }"}
Linear uses Relay-style cursor-based pagination with
first/after and last/before arguments.
# First page POST /linear/graphql {"query": "{ issues(first: 10) { nodes { id identifier title } pageInfo { hasNextPage endCursor } } }"}Next page using endCursor
POST /linear/graphql {"query": "{ issues(first: 10, after: "CURSOR_VALUE") { nodes { id identifier title } pageInfo { hasNextPage endCursor } } }"}
Response includes
pageInfo:
{ "data": { "issues": { "nodes": [...], "pageInfo": { "hasNextPage": true, "endCursor": "4c7b33c8-dabf-47ce-9d30-7f286f9463be" } } } }
const response = await fetch('https://gateway.maton.ai/linear/graphql', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.MATON_API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ query: `{ issues(first: 10) { nodes { id identifier title state { name } } } }` }) }); const data = await response.json();
import os import requestsresponse = requests.post( 'https://gateway.maton.ai/linear/graphql', headers={ 'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}', 'Content-Type': 'application/json' }, json={ 'query': '{ issues(first: 10) { nodes { id identifier title state { name } } } }' } ) data = response.json()
MTN-527 can be used in place of UUIDs for the id parameterbacklog, unstarted, started, completed, canceledhttps://api.linear.app/graphqlsearchIssues(term: "...") for full-text search across issues| Status | Meaning |
|---|---|
| 400 | Missing Linear connection or GraphQL validation error |
| 401 | Invalid or missing Maton API key |
| 403 | Insufficient OAuth scope for the operation |
| 429 | Rate limited |
| 4xx/5xx | Passthrough error from Linear API |
GraphQL errors are returned in the
errors array:
{ "errors": [ { "message": "Invalid scope: `write` required", "extensions": { "type": "forbidden", "code": "FORBIDDEN", "statusCode": 403 } } ] }
MATON_API_KEY environment variable is set:echo $MATON_API_KEY
python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://ctrl.maton.ai/connections') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
linear. For example:https://gateway.maton.ai/linear/graphqlhttps://gateway.maton.ai/graphqlNo automatic installation available. Please visit the source repository for installation instructions.
View Installation Instructions1,500+ AI skills, agents & workflows. Install in 30 seconds. Part of the Torly.ai family.
© 2026 Torly.ai. All rights reserved.