REST API

Build on AllScrum.
From scripts to AI agents.

The AllScrum REST API gives your code the same projects, tasks, sprints and notes you work with in the app, with the same permissions. Create an API key, send one request, and you are in.

Updated 12 min read

Quickstart

  1. Sign in and open Account settings → API keys.
  2. Choose Create an API key, give it a name, pick Read only or Read and write and when it expires. Copy the key: it is shown once.
  3. Send your first request:
curl https://allscrum.com/api/v1/me \
  -H "Authorization: Bearer allscrum_your_key_here"

You get your account back:

{
  "data": {
    "id": "Xk29fQ7a",
    "name": "Ann Owner",
    "email": "[email protected]",
    "timezone": "Europe/Amsterdam",
    "api_key": {"id": "pL3m9QzR", "name": "My script", "scope": "write", "expires_at": "2026-11-19T10:00:00Z", "allowed_ips": []}
  }
}

From here, GET /projects lists your projects and GET /tasks?assignee_id=me your tasks.

Authentication

Every request (except GET / and GET /openapi.json) needs an API key in the Authorization header:

Authorization: Bearer allscrum_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Tools that can't set that header can send X-API-Key: allscrum_… instead. Keys always start with allscrum_, which makes them easy to spot if one ends up somewhere it shouldn't, like a public repository.

Keys in the URL (not recommended)

For tools that can't send headers at all, like a spreadsheet formula, a read-only key also works in the URL of GET requests:

curl "https://allscrum.com/api/v1/tasks?assignee_id=me&api_key=allscrum_your_read_only_key"

We advise against this. URLs are stored in server and proxy logs, browser history and bookmarks, and travel along when a link is shared or a page links elsewhere. Anyone who sees such a URL can read everything you can. Use the Authorization header whenever you can. If you must use the URL, give it a separate read-only key with a short expiry and allowed IP addresses. Responses then carry an X-API-Key-Warning header, and keys that can make changes are always refused in the URL (403 api_key_in_url_not_allowed).

A key acts as you

A key belongs to the person who created it and has exactly their access. When you lose access to a project, so do your keys. Everything a key changes shows up in the history under your name, marked via API.

Access

  • Read only keys can call GET endpoints. Anything else returns 403 insufficient_scope.
  • Read and write keys can call every endpoint, including deleting things you are allowed to delete.

Give each integration its own key with the least access it needs. That way you can revoke one without touching the others.

Expiry

When you create a key, choose when it expires: after 1 hour, 3 hours, 1 day, 1 week, 1 month, 3 months, 6 months, 1 year, 2 years, or never. After that, requests with it return 401 api_key_expired. A key's expiry can't be extended: create a new key and revoke the old one.

Allowed IP addresses

You can limit a key to IP addresses and CIDR ranges, IPv4 or IPv6, for example 203.0.113.7 or 198.51.100.0/24. Requests from anywhere else return 403 ip_not_allowed. You can change the list at any time without replacing the key.

Keep keys secret. Store them in environment variables or a secrets manager, never in code or in a web page. You get an email whenever a key is created on your account. If a key may have leaked, revoke it in your settings: it stops working immediately.

Requests

The base URL is https://allscrum.com/api/v1. Use HTTPS. Send request bodies as JSON with Content-Type: application/json.

curl -X POST https://allscrum.com/api/v1/tasks \
  -H "Authorization: Bearer $ALLSCRUM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"project_id": "AbC1234", "title": "Fix the login page", "type": "bug", "priority": "high"}'

Only GET and POST?

Some clients, proxies and firewalls only let GET and POST through. Send a POST with an X-HTTP-Method-Override header instead, and it is handled exactly like a PATCH or DELETE, permissions and idempotency keys included:

curl -X POST https://allscrum.com/api/v1/tasks/CAR-12 \
  -H "Authorization: Bearer $ALLSCRUM_API_KEY" \
  -H "X-HTTP-Method-Override: PATCH" \
  -H "Content-Type: application/json" \
  -d '{"priority": "high"}'

IDs

Every object has an 8-character id, like a1B2c3D4. A few objects can also be addressed the way you see them in the app:

  • Projects by the code in their URL: allscrum.com/p/AbC1234 → GET /projects/AbC1234.
  • Tasks by their key: GET /tasks/CAR-12. If two of your projects use the same key, you get 409 ambiguous_task_key with both candidates; use the ID then.
  • Teams by the code in their URL.

Fields

  • PATCH changes only the fields you send. Send null to clear a field, like "assignee_id": null.
  • Unknown fields and query parameters are refused (422 unknown_field, 400 invalid_parameter). A typo never silently changes what a request does.
  • Types are strict: "points": 5 works, "points": "5" doesn't.
  • Times are ISO 8601 in UTC, like 2026-10-18T09:30:00Z. Dates are YYYY-MM-DD.
  • Task descriptions and notes are HTML with simple formatting (paragraphs, lists, bold, links, code). Plain text works too; line breaks are kept. Responses include a plain-text version as well.

Responses and errors

Successful responses put the result in data. Creating something returns 201 Created with a Location header; deleting returns 204 No Content.

{"data": {"id": "a1B2c3D4", "key": "CAR-12", "title": "Fix the login page", "status": "open", "...": "..."}}

Errors have a status code, a stable code for your program, and a message for people. details.field names the field at fault when there is one.

HTTP/1.1 422 Unprocessable Content

{"error": {"code": "validation_failed", "message": "Pick a priority from the list.", "details": {"field": "priority"}, "request_id": "5f2c9a1be04d7c31"}}
StatusCodesWhat to do
400invalid_parameter, invalid_json, invalid_idempotency_key, invalid_method_overrideFix the request.
401unauthorized, invalid_api_key, api_key_expiredSend a valid key, or create a new one.
403insufficient_scope, ip_not_allowed, account_disabled, api_key_in_url_not_allowed, forbiddenThe key or its owner may not do this, for example a member changing project settings.
404not_found, route_not_foundIt doesn't exist, or you don't have access to it.
405method_not_allowedUse a method from the Allow header.
409conflict, ambiguous_task_key, version_conflict, backlog_disabled, idempotency_conflictThe current state doesn't allow it, like starting a sprint while another runs. Fetch fresh data and decide.
413, 415payload_too_large, unsupported_media_typeSend JSON, up to 1 MB.
422validation_failed, missing_field, unknown_field, idempotency_key_reusedFix the field named in details.field.
429rate_limitedWait Retry-After seconds.
500internal_errorRetry with an idempotency key. If it keeps happening, contact us with the request_id.
503project_busy, service_unavailableRetry after Retry-After seconds.

Every response has an X-Request-Id header. Mention it when you contact us about a request.

Pagination

Task lists (GET /tasks and GET /projects/{project}/tasks) come in pages. Use page (from 1) and per_page (default 50, at most 100):

GET /tasks?assignee_id=me&status=open&per_page=100&page=2

{"data": [ ... ], "meta": {"page": 2, "per_page": 100, "total": 243, "total_pages": 3}}

The Link header holds ready-made URLs for the first, prev, next and last pages. Other lists (projects, lanes, comments, sprints…) come complete.

History endpoints return 50 entries at a time, newest first. For older entries, pass meta.next_before as before until meta.has_more is false.

Keeping a copy in sync

Every task has updated_at, which changes when any of its fields, its lane or its place changes. Ask for what changed since your last sync with GET /tasks?updated_after=2026-10-18T09:30:00Z&archived=all.

Rate limits

Each key can make 120 requests per minute. Every response tells you where you stand:

X-RateLimit-Limit: 120
X-RateLimit-Remaining: 117
X-RateLimit-Reset: 1792367400

Over the limit you get 429 rate_limited with a Retry-After header in seconds. Repeated requests with invalid keys from one address are limited as well.

Safe retries

Networks fail. If a POST times out, did the task get created or not? Send an Idempotency-Key header with any unique value, a UUID for example, and retry with the same key:

curl -X POST https://allscrum.com/api/v1/tasks \
  -H "Authorization: Bearer $ALLSCRUM_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 6f1c8e52-3f0b-4d1e-9a4b-2f6b7c1d0e9a" \
  -d '{"project_id": "AbC1234", "title": "Invoice March"}'

The first request does the work. Repeats with the same key and the same request, for 24 hours, return the stored response with Idempotent-Replayed: true, without creating anything twice. The same key with a different request returns 422 idempotency_key_reused. Idempotency keys work for POST, PATCH and DELETE.

Permissions

The API follows the same rules as the app:

  • Any project member can work with tasks, comments, checklists, blockers, epics, notes, planned sprints and the backlog.
  • Project admins and the owner can also change settings, lanes and members, and start or complete sprints.
  • Only the owner can delete a project or change its team. Deleting a project needs ?confirm= with its exact name.
  • Comments can be edited by their author, and deleted by their author or an admin.

Something you can't open returns 404, never 403, so the API never reveals what exists in other people's projects.

Examples

Your open tasks, most urgent first

curl "https://allscrum.com/api/v1/tasks?assignee_id=me&status=open&sort=-priority" \
  -H "Authorization: Bearer $ALLSCRUM_API_KEY"

Move a task to Done

Find the lane with GET /projects/{project}/lanes (the done lane has "is_done": true), then:

curl -X PATCH https://allscrum.com/api/v1/tasks/CAR-12 \
  -H "Authorization: Bearer $ALLSCRUM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"lane_id": "Lp9x2KqA"}'

Plan and start a sprint

# 1. Plan a sprint
curl -X POST https://allscrum.com/api/v1/projects/AbC1234/sprints -H "Authorization: Bearer $ALLSCRUM_API_KEY" \
  -H "Content-Type: application/json" -d '{"name": "Sprint 8", "goal": "Checkout flow"}'
# 2. Put backlog items in it
curl -X POST https://allscrum.com/api/v1/projects/AbC1234/backlog/plan -H "Authorization: Bearer $ALLSCRUM_API_KEY" \
  -H "Content-Type: application/json" -d '{"task_ids": ["a1B2c3D4", "e5F6g7H8"], "sprint_id": "S8x9y0Zq"}'
# 3. Start it (project admins)
curl -X POST https://allscrum.com/api/v1/sprints/S8x9y0Zq/start -H "Authorization: Bearer $ALLSCRUM_API_KEY" \
  -H "Content-Type: application/json" -d '{"end_date": "2026-11-02"}'

JavaScript

const response = await fetch('https://allscrum.com/api/v1/tasks', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.ALLSCRUM_API_KEY}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': crypto.randomUUID(),
  },
  body: JSON.stringify({project_id: 'AbC1234', title: 'Deploy failed on main', type: 'bug', priority: 'highest'}),
});
const body = await response.json();
if (!response.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
console.log(`Created ${body.data.key}: ${body.data.url}`);

Python

import os, requests

api = requests.Session()
api.headers["Authorization"] = f"Bearer {os.environ['ALLSCRUM_API_KEY']}"

page = 1
while True:
    r = api.get("https://allscrum.com/api/v1/tasks", params={"assignee_id": "me", "status": "open", "per_page": 100, "page": page})
    r.raise_for_status()
    body = r.json()
    for task in body["data"]:
        print(task["key"], task["title"])
    if page >= body["meta"]["total_pages"]:
        break
    page += 1

AI agents (MCP)

AllScrum has an MCP server, so AI assistants and agents like Claude, ChatGPT, Claude Code, Cursor and GitHub Copilot can work with your board directly: "what's on my plate today?", "create a bug for this stack trace", "move CAR-12 to Done". There is nothing to install. The server is at:

https://allscrum.com/mcp

There are two ways to connect:

  • Sign in (OAuth): add the URL and the app opens an AllScrum page where you sign in and click Allow. That's how Claude, ChatGPT, Claude Code and most current tools connect. Step by step for everyone: Use AllScrum in Claude and ChatGPT.
  • An API key, for tools that can only send a header, or for agents running unattended: send it as Authorization: Bearer allscrum_….

Claude Code

# Sign in: add the server, then type /mcp in Claude Code and choose Authenticate
claude mcp add --transport http allscrum https://allscrum.com/mcp

# Or with an API key
claude mcp add --transport http allscrum https://allscrum.com/mcp \
  --header "Authorization: Bearer allscrum_your_key_here"

Cursor

In ~/.cursor/mcp.json (all projects) or .cursor/mcp.json (one project). Leave out headers to sign in instead:

{
  "mcpServers": {
    "allscrum": {
      "url": "https://allscrum.com/mcp",
      "headers": {"Authorization": "Bearer allscrum_your_key_here"}
    }
  }
}

VS Code (GitHub Copilot)

In .vscode/mcp.json. Without headers, VS Code asks you to sign in; with them, it asks for the key once and stores it securely:

{
  "inputs": [{"type": "promptString", "id": "allscrum-key", "description": "AllScrum API key", "password": true}],
  "servers": {
    "allscrum": {
      "type": "http",
      "url": "https://allscrum.com/mcp",
      "headers": {"Authorization": "Bearer ${input:allscrum-key}"}
    }
  }
}

Claude and ChatGPT

Add AllScrum as a custom connector with the URL above; they sign in with OAuth. See the step-by-step guide. A read-only key in the URL (/mcp?api_key=…) also works there, but isn't recommended: the URL, key included, is stored by the app and ends up in logs.

What agents can do

The server offers 47 tools: search, read projects, boards, tasks, comments, sprints, the backlog, notes and history, and create and change tasks, comments, checklists, blockers, lanes, epics, sprints and notes. Each tool is an API endpoint, with the same permissions, limits and validation. Deleting projects and inviting people are left out on purpose.

  • Read-only access (a read-only key, or "Read only" when signing in) only gets the tools that read. Start there, with a short expiry while you try things out.
  • Agents can use the task keys people mention, like CAR-12, directly.
  • Mistakes come back as clear messages the agent can correct, not silent surprises.
  • Everything an agent changes shows in the project history, marked via API with the key's or app's name, and most changes can be undone there.

Building your own agent instead? Give it the OpenAPI document, or call the API directly.

OAuth for MCP clients

For developers of MCP clients: AllScrum follows the MCP authorization specification (OAuth 2.1). Clients that implement it, like the official MCP SDKs, need no AllScrum-specific code.

  1. A request to /mcp without a token returns 401 with WWW-Authenticate: Bearer resource_metadata="https://allscrum.com/.well-known/oauth-protected-resource/mcp".
  2. That document (RFC 9728) names https://allscrum.com as the authorization server, whose metadata is at /.well-known/oauth-authorization-server (RFC 8414).
  3. Register with POST /oauth/register (Dynamic Client Registration, RFC 7591). No account or approval needed.
  4. Send the person to /oauth/authorize with PKCE and resource=https://allscrum.com/mcp (RFC 8707), and exchange the code at POST /oauth/token.
  5. Call /mcp with Authorization: Bearer <access token>; refresh with the refresh token when it expires.
RuleDetails
Grant typesauthorization_code with refresh_token. No implicit, password or client credentials grants.
PKCERequired on every request, S256 only.
ClientsPublic (token_endpoint_auth_method: none) or with a secret (client_secret_basic or client_secret_post). Registration is limited per IP address; apps that never connect anyone are removed after 7 days.
Redirect URIsMatched exactly. https, http only for localhost / 127.0.0.1 / [::1], or an app's own scheme. Never fragments.
Scopesread or write (includes read). Without a scope, the person chooses. The granted scope is in the token response.
Access tokensOpaque, valid for 1 hour, accepted only by /mcp (the REST API takes API keys).
Refresh tokensValid for 90 days, renewed with each use. Each works once: you get a new one with every refresh. Using one twice ends the connection.
CodesValid for 10 minutes, once. Using one twice ends the connection.
Signing outPOST /oauth/revoke (RFC 7009) with either token ends the connection.
ErrorsAs in RFC 6749: {"error": "invalid_grant", "error_description": "…"}. The authorization response includes iss (RFC 9207).

Versioning

This is version 1 of the API, under /api/v1. Within version 1 we only make changes that don't break working code:

  • New endpoints, new optional parameters and fields, and new fields in responses can be added at any time. Ignore fields you don't know.
  • New values can be added to lists like task types and error codes. Handle unknown values gracefully.
  • Anything that would break working code (removing or renaming fields, changing types or meaning) gets a new version, with time to move.

Reference

The API reference lists every endpoint with its parameters, request and response fields and errors. It is generated from the OpenAPI 3.1 document, which you can import into Postman, Insomnia or a client generator.

Endpoints by area:

AreaEndpoints
AccountGET /me, GET /search
Workspaces/workspaces, /workspaces/{workspace}
Projects/projects, /projects/{project}, …/members, …/activity
BoardGET /projects/{project}/board, /projects/{project}/lanes, /lanes/{lane}
Tasks/tasks, /tasks/{task}, …/move, …/archive, …/comments, …/checklist, …/blockers, …/activity
Planning…/epics, …/sprints, /sprints/{sprint}/start, …/complete, …/backlog
Notes/projects|workspaces|teams/{id}/notes, /notes/{note}
Teams/teams, /teams/{team}, …/members

FAQ

Questions

Does the API cost extra?

No. Every AllScrum account can create API keys and use the API, within the rate limit of 120 requests per minute per key.

What can I do with the API?

Everything you do daily: workspaces, projects and their members, lanes and the board, tasks with comments, checklists and blockers, epics, sprints, the backlog, notes, teams, search and the history. Account settings, sign-in methods and imports stay in the app.

Can a key do more than I can?

No. A key acts as you and never has more access than you have in the app. A read-only key can only read.

What happens when a key expires or is revoked?

Requests with it are refused straight away with 401: api_key_expired after expiry, invalid_api_key after revoking. Expired keys stay listed in your settings for 90 days, so you can see why an integration stopped.

Is there an SDK?

You can generate a client in almost any language from the OpenAPI document with a tool like OpenAPI Generator. For most scripts plain HTTP is enough: see the examples.

Does the API support OAuth or webhooks?

Not yet. Today the API uses personal API keys; OAuth sign-in for apps and webhooks are on our list.

Less talk. More done.

Create an account, name a project and drag the first card.