# REST API

> Taskhold REST API reference: authentication, tasks, steps, progress, notes, events and the live snapshot, with curl examples and real responses.

Source: https://taskhold.com/docs/rest-api
Last updated: 2026-10-26

Base URL https://taskhold.com/api. Every request sends Authorization: Bearer atd_sk_... and JSON bodies. Writes made with an API key are recorded as agent changes. The full machine-readable description is /openapi.json (OpenAPI 3.1).

## Name the caller

Send X-Taskhold-Agent with a label, for example "GitHub Actions (deploy)", and the board shows it on the card and in the activity feed. Without it Taskhold uses a known client from the User-Agent, then the API key's name.

## Endpoints

| Method and path | What it does |
| --- | --- |
| GET /api/tasks | List tasks. Filters: status, priority, project_id, created_by, parent_id, include_subtasks, limit, offset |
| POST /api/tasks | Create a task: title, description, priority, status, labels, parent_task_id, code_file_path, code_line_number |
| GET /api/tasks/current | The task in progress, with steps and rollups, or task: null |
| GET /api/tasks/{id} | One task with steps, notes, labels and project |
| PATCH /api/tasks/{id} | Update: status, blocked_reason, completed_summary, title, description, priority, project_id, agent_name |
| DELETE /api/tasks/{id} | Delete a task |
| GET /api/tasks/{id}/subtasks | Steps in order, with counts and overall progress |
| POST /api/tasks/{id}/subtasks | Add steps: {steps: [...], replace?} or one {title} |
| PUT /api/tasks/{id}/subtasks | Reorder steps: {order: [step ids]} |
| POST /api/tasks/{id}/progress | Report progress: percent, or current and total, and message. Reports on one task within 5 seconds merge into one event; an account can send 120 a minute (then 429 with Retry-After) |
| GET /api/tasks/{id}/notes | Notes on a task |
| POST /api/tasks/{id}/notes | Add a note: {content} |
| GET /api/events | Changes after a cursor (see /docs/events) |
| GET /api/events/stream | The same changes as Server-Sent Events |
| GET /api/live | What the live board shows, in one call |
| GET /api/projects, GET /api/labels, GET /api/summary | Projects, labels, counts |

## Create a task and plan steps

```bash
curl -s https://taskhold.com/api/tasks -H "Authorization: Bearer API_KEY" -H "Content-Type: application/json" \
  -H "X-Taskhold-Agent: deploy script" -d '{"title": "Deploy v2.4 to staging", "priority": "high"}'

curl -s -X PATCH https://taskhold.com/api/tasks/TASK_ID -H "Authorization: Bearer API_KEY" \
  -H "Content-Type: application/json" -d '{"status": "in_progress"}'

curl -s https://taskhold.com/api/tasks/TASK_ID/subtasks -H "Authorization: Bearer API_KEY" \
  -H "Content-Type: application/json" -d '{"steps": ["Build images", "Run migrations", "Smoke tests"]}'
```

```json
{"subtasks": [{"id": "0a017133-...", "title": "Build images", "status": "todo", ...}, ...],
 "task": {"id": "fd11278a-...", "status": "in_progress", "subtask_counts": {"total": 3, "done": 0, "in_progress": 0, "blocked": 0, "todo": 3}, "overall_progress": 0, ...}}
```

Response to the last call (201), shortened.

## Report progress

```bash
curl -s https://taskhold.com/api/tasks/STEP_ID/progress -H "Authorization: Bearer API_KEY" \
  -H "Content-Type: application/json" -d '{"current": 3, "total": 5, "message": "Building api image"}'
```

```json
{"task": {"id": "0a017133-...", "progress": 60, "progress_current": 3, "progress_total": 5,
          "progress_message": "Building api image", "last_activity_at": "2026-10-26T05:09:47.401Z", ...}}
```

The parent task's overall_progress is now 20: one of three steps at 60%.

## Finish or block

```bash
curl -s -X PATCH https://taskhold.com/api/tasks/TASK_ID -H "Authorization: Bearer API_KEY" -H "Content-Type: application/json" \
  -d '{"status": "done", "completed_summary": "Deployed 2.4 to staging; smoke tests pass."}'

curl -s -X PATCH https://taskhold.com/api/tasks/TASK_ID -H "Authorization: Bearer API_KEY" -H "Content-Type: application/json" \
  -d '{"status": "blocked", "blocked_reason": "Decide: run the migration now or after hours?"}'
```

## Status codes

| Code | Meaning |
| --- | --- |
| 200, 201 | OK; the body holds the task (or list) after the change |
| 400 | Validation failed; details lists each field problem. Also: adding steps to a step (steps don't nest), more than 200 steps |
| 401 | Key missing, malformed, not a Taskhold key, or revoked. reason and message say which |
| 402 | The key is valid but the account has no active subscription |
| 403 | Fair-use ceiling reached (100,000 tasks) |
| 404 | Task or project not found in this account |

## Related

- [Taskhold events API and Server-Sent Events stream](https://taskhold.com/docs/events.md)
- [Taskhold MCP tools reference (taskhold_*)](https://taskhold.com/docs/mcp-tools.md)
- [Troubleshooting Taskhold: errors, missing tools, no progress](https://taskhold.com/docs/troubleshooting.md)
