Linear
Elixir client for the Linear GraphQL API.
Provides a clean, functional interface for querying and mutating Linear data -- issues, comments, projects, workflow states, teams, and more. Includes cursor-based auto-pagination and supports both API key and OAuth authentication.
Installation
def deps do
[
{:linear_client, "~> 0.1.0"}
]
endQuick Start
client = Linear.client(api_key: "lin_api_...")
# Fetch the authenticated user
{:ok, viewer} = Linear.viewer(client)
IO.puts(viewer["name"])
# List issues for a team
{:ok, issues} = Linear.list_issues(client, team_id: "TEAM-UUID")
Enum.each(issues, &IO.puts(&1["title"]))
# Create an issue
{:ok, issue} = Linear.create_issue(client, %{
"teamId" => "TEAM-UUID",
"title" => "Fix login bug",
"description" => "Users can't log in with SSO"
})
# Transition an issue by state name
{:ok, _} = Linear.transition_issue(client, "ABC-123", "In Progress")Authentication
Two modes are supported:
# Personal API key (Authorization: <key>)
client = Linear.client(api_key: "lin_api_...")
# OAuth bearer token (Authorization: Bearer <token>)
client = Linear.client(access_token: "oauth_access_token")Create API keys at Linear Settings > Security & Access.
API Reference
Queries
# Current user
{:ok, viewer} = Linear.viewer(client)
# Teams
{:ok, teams} = Linear.list_teams(client)
# Issues (auto-paginated)
{:ok, issues} = Linear.list_issues(client,
team_id: "...",
state_names: ["In Progress", "Todo"],
assignee_id: "...",
project_id: "...",
first: 50,
include_archived: false
)
# Single issue (UUID or shorthand like "ABC-123")
{:ok, issue} = Linear.get_issue(client, "ABC-123")
# Workflow states
{:ok, states} = Linear.list_workflow_states(client, team_id: "...")
# Projects (auto-paginated)
{:ok, projects} = Linear.list_projects(client)Mutations
# Create issue
{:ok, issue} = Linear.create_issue(client, %{
"teamId" => "...",
"title" => "New feature",
"description" => "Markdown description",
"assigneeId" => "...",
"priority" => 2,
"labelIds" => ["label-uuid"]
})
# Update issue
{:ok, issue} = Linear.update_issue(client, "ABC-123", %{
"title" => "Updated title",
"priority" => 1
})
# Create comment
{:ok, comment} = Linear.create_comment(client, "issue-uuid", "This is fixed in PR #42")
# Transition issue state (resolves state name to ID automatically)
{:ok, issue} = Linear.transition_issue(client, "ABC-123", "Done")Raw GraphQL
For queries not covered by the built-in helpers:
{:ok, data} = Linear.query(client,
"query($id: String!) { issue(id: $id) { title state { name } } }",
variables: %{"id" => "ABC-123"}
)
{:ok, data} = Linear.mutate(client,
"mutation($id: String!, $input: IssueUpdateInput!) { issueUpdate(id: $id, input: $input) { success } }",
variables: %{"id" => "ABC-123", "input" => %{"title" => "New title"}}
)Auto-Pagination
list_issues/2 and list_projects/2 automatically follow cursors. You can also use pagination directly:
{:ok, all_nodes} = Linear.paginate(fn cursor ->
Linear.query(client, my_query, variables: %{"after" => cursor, "first" => 50})
|> case do
{:ok, %{"myConnection" => connection}} -> {:ok, connection}
error -> error
end
end)Error Handling
All functions return {:ok, result} or {:error, reason}:
case Linear.get_issue(client, "ABC-999") do
{:ok, issue} ->
IO.puts(issue["title"])
{:error, {:graphql_errors, errors, _data}} ->
IO.puts("GraphQL error: #{hd(errors)["message"]}")
{:error, {:http_status, 401}} ->
IO.puts("Authentication failed")
{:error, {:request_failed, reason}} ->
IO.puts("Network error: #{inspect(reason)}")
{:error, {:state_not_found, name}} ->
IO.puts("No workflow state named #{name}")
endConfiguration Options
| Option | Default | Description |
|---|---|---|
:api_key | nil | Linear personal API key |
:access_token | nil | OAuth2 bearer token |
:endpoint | "https://api.linear.app/graphql" | GraphQL API endpoint |
:timeout | 30_000 | HTTP timeout in milliseconds |
Architecture
Linear (public API facade)
├── Linear.Client — HTTP transport, auth, request/response handling
├── Linear.Queries — Pre-built read queries (viewer, teams, issues, etc.)
├── Linear.Mutations — Pre-built write mutations (create, update, transition)
└── Linear.Pagination — Cursor-based auto-pagination for connectionsDevelopment
mix deps.get
mix test
mix credo --strictLicense
MIT — see LICENSE.