API Reference
Flint Task exposes two APIs over the same data: a GraphQL endpoint (the richer one, and the one most clients should use) and a REST API. The REST endpoints live under https://flinttask.com/api and exchange JSON.
Authentication
Use a personal API key (create one under API keys) or a token from /auth/login, then send it on each request:
curl https://flinttask.com/api/issues?limit=20 \ -H "Authorization: Bearer <token>"
Authentication
Email + password authentication. Login or registration returns a JWT (valid 7 days). Send it as `Authorization: Bearer <token>` on every authenticated request.
/auth/register PublicCreate an account (role: member) and return a JWT.
/auth/login PublicExchange email + password for a JWT.
/auth/me Bearer tokenReturn the authenticated user.
/auth/change-password Bearer tokenChange your own password.
Workspace config
Public, read-only workspace configuration — enabled features and branding.
/config PublicEnabled feature flags + workspace branding.
Issues
The core work items. List supports filtering (teamId, stateId, assigneeId, projectId, cycleId, priority), full-text search (q) and pagination (limit ≤ 250, offset).
/issues Bearer tokenList issues. Returns { issues, pageInfo: { total, limit, offset } }.
Response
200 OK
{
"issues": [ { "id", "identifier", "title", "stateId", "priority", … } ],
"pageInfo": { "total": 142, "limit": 50, "offset": 0 }
}/issues Bearer tokenCreate an issue (auto-assigns identifier, e.g. CLA-42).
Request
{
"title": "Fix flaky cycle filter",
"teamId": "t_cla", // optional, defaults to first team
"priority": 1, // 0 none … 1 urgent … 4 low
"assigneeId": "<user id>",
"projectId": "<project id>",
"labelIds": ["l_bug"]
}Response
201 Created
{ "issue": { "id", "identifier": "CLA-42", "title", "stateId",
"priority", "labelIds": [...], "createdAt", … } }/issues/:id Bearer tokenGet an issue by id or identifier (e.g. CLA-42).
/issues/:id Bearer tokenUpdate title, state, priority, assignee, project, cycle, labels, …
/issues/:id Bearer tokenDelete an issue and its comments.
/issues/:id/comments Bearer tokenList comments on an issue.
/issues/:id/comments Bearer tokenAdd a comment to an issue.
Projects
Organizational containers for work, with status, health, lead and target date.
/projects Bearer tokenList projects.
/projects Bearer tokenCreate a project.
/projects/:id Bearer tokenGet a project.
/projects/:id Bearer tokenUpdate a project.
/projects/:id Bearer tokenDelete a project.
Cycles
Time-boxed iterations belonging to a team. Filter the list by teamId.
/cycles Bearer tokenList cycles (optionally ?teamId=).
/cycles Bearer tokenCreate a cycle (auto-numbers within the team).
/cycles/:id Bearer tokenUpdate a cycle.
/cycles/:id Bearer tokenDelete a cycle.
Reference data
Read-only collections used to resolve ids on issues and projects.
/teams Bearer tokenList teams.
/workflow-states Bearer tokenList workflow states (optionally ?teamId=).
/labels Bearer tokenList labels.
/users Bearer tokenList workspace members.
GraphQL
The full domain is also served as a GraphQL API at https://flinttask.com/graphql. It is the richer of the two — one round trip can fetch an issue with its state, assignee, labels and comments — and it is schema-compatible with Linear's, so a client written against their reference works here by changing only the host.
Authentication
Send a personal API key as the bare Authorization value, or a login token with a Bearer prefix.
curl https://flinttask.com/graphql \
-H "Content-Type: application/json" \
-H "Authorization: <your API key>" \
--data '{"query":"{ viewer { id name email } }"}'Pagination
Every list is a connection. Read it as nodes for the common case, or as edges when you need cursors. Connections accept first, last, after, before, orderBy (createdAt · updatedAt), includeArchived and filter. The first 50 results come back when no arguments are given.
query {
issues(first: 50, orderBy: updatedAt) {
edges { node { id identifier title } cursor }
pageInfo { hasNextPage endCursor }
}
}Filtering
Filters are comparator objects. Every field takes eq · neq · in · nin; numbers and dates add lt · lte · gt · gte; strings add contains · containsIgnoreCase · startsWith · endsWith and their negations; optional fields add null. Fields combine with AND; use or for alternatives. Relations nest, and many-to-many relations take every / some.
query {
issues(filter: {
state: { type: { eq: "started" } }
assignee: { email: { eq: "[email protected]" } }
labels: { name: { eq: "Bug" } }
or: [{ priority: { eq: 1 } }, { dueDate: { lt: "2026-09-01" } }]
}) {
nodes { identifier title priorityLabel state { name } }
}
}Mutations
Each mutation returns a payload carrying success, lastSyncId and the affected record. Deletes return entityId.
mutation IssueCreate($input: IssueCreateInput!) {
issueCreate(input: $input) {
lastSyncId
success
issue { id identifier title url branchName }
}
}
# variables
{ "input": { "title": "Rate-limit the public API", "teamId": "<team id or key>", "priority": 2 } }Available: issueCreate · issueUpdate · issueDelete · issueArchive · issueUnarchive · commentCreate · commentUpdate · commentDelete · projectCreate · projectUpdate · projectDelete · cycleCreate · cycleUpdate · issueLabelCreate · issueLabelUpdate · issueLabelDelete · attachmentCreate · attachmentUpdate · attachmentDelete · fileUpload. Introspection is enabled, so codegen and GraphQL IDEs work against the endpoint directly.
Uploading files
Uploads are two steps: ask for a URL, then PUT the bytes to it. The returned assetUrl is what you reference from a description, a comment or an attachment. Files are capped at 25 MB.
mutation FileUpload($contentType: String!, $filename: String!, $size: Int!) {
fileUpload(contentType: $contentType, filename: $filename, size: $size) {
success
uploadFile { assetUrl uploadUrl headers { key value } }
}
}
# then, with the headers the payload asked for:
curl -X PUT "<uploadUrl>" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: image/png" \
--data-binary @screenshot.png
# and attach it to an issue:
mutation { attachmentCreate(input: {
issueId: "<id>", title: "screenshot.png", url: "<assetUrl>"
}) { success attachment { id url } } }A one-shot REST form exists for clients that would rather not round-trip: POST /api/files with the file as the raw body, its name in an x-filename header (percent-encoded) and its type in Content-Type.
Webhooks
A workspace admin can register endpoints (System administration → Webhooks). When an issue or comment changes, Flint Task POSTs a JSON payload to each endpoint.
POST <your endpoint>
X-Flint-Event: issue.create
X-Flint-Signature: sha256=<hex>
{ "type": "issue", "action": "create",
"data": { "id", "identifier", "title", … },
"createdAt": "2026-…Z" }Verify authenticity with HMAC-SHA256(secret, rawBody) and compare to the X-Flint-Signature header.