The Public API v2 is an action-based API: every operation is a POST to a named endpoint (/listSpaces, /promptAgent, /createProject), with a JSON body. It is not RESTful — there are no GET /workspaces or PUT /tasks/{id} style routes. (The only REST-style exceptions: media/bundle downloads and the webhook registration routes.)
v2 is in beta (2.0.0-beta) and runs alongside v1. v2 is simpler and adds capabilities v1 lacks — most notablypromptAgentand signed webhook registration. Tasks are fully writable in v2 as of August 2026:createTask,updateTask,deleteTask,moveTask, complete/uncomplete, assignees, dates, notes, and custom fields all ship. v1 remains the surface with the longest track record and the only one with single-task read endpoints (GET /tasks/{taskId}and friends). Neither version can rename a project. See Which API should I use? below.
The live OpenAPI spec is published at taskade.com/api/documentation/v2.
Table of Contents
- Which API should I use?
- Base URL & Authentication
- Calling convention
- Endpoints
- Pagination
- Rate Limits
- Error Handling
- Security Best Practices
Which API should I use?
Taskade ships two public HTTP APIs. They share the same authentication.
| REST API v1 | Action API v2 | |
|---|---|---|
| Base URL | https://www.taskade.com/api/v1 |
https://www.taskade.com/api/v2 |
| Style | RESTful (GET/POST/PUT/DELETE) |
Action / RPC (POST /{operation}) |
| Status | Stable (GA) | Beta (2.0.0-beta) |
| Live spec | /api/documentation/v1 | /api/documentation/v2 |
| Task create / update / delete | ✅ Full CRUD | ✅ Full CRUD (createTask, updateTask, deleteTask, moveTask) |
| Task assignees / dates / notes / fields | ✅ | ✅ (assignTask, setTaskDate, setTaskNote, setTaskFieldValue, …) |
| Read a single task, date, note or field | ✅ GET /tasks/{taskId} etc. |
❌ list-only (listTasks, listBlocks, listFields) |
| Project update / rename | ❌ | ❌ (create / complete / restore / copy only) |
| Prompt an agent | ❌ | ✅ promptAgent |
| Agent lifecycle (create/update/delete) | ✅ | ✅ |
| Bundles (export/import Taskade Genesis apps) | ✅ | ✅ |
| Signed webhook registration | ❌ | ✅ POST /webhooks |
| Reference | Comprehensive API Guide | This page |
Rule of thumb: reach for v2 when you are wiring operations into an LLM as tools, prompting agents, or registering webhooks — one verb per endpoint maps straight onto a tool definition. Reach for v1 when you want the surface with the longest stability track record, or need to read one task (or its date, note, or field) without listing the project.
Every row above is checkable: it is derived from the two live OpenAPI documents, and the generated Action API reference and REST API reference are built from those same specs.
Base URL & Authentication
All v2 operations live under:
https://www.taskade.com/api/v2
Authenticate with a Personal Access Token from taskade.com/settings/api, or an OAuth 2.0 access token for apps that act on behalf of other users:
Authorization: Bearer YOUR_TOKEN
See the Authentication guide for personal tokens vs. OAuth 2.0 (PKCE) details.
Calling convention
Every v2 call is a POST to an operation name, with a JSON body and a JSON response. Successful responses are wrapped in { "ok": true, ... }.
Here is a single Action API v2 call, from authentication to JSON response.
curl -X POST https://www.taskade.com/api/v2/OPERATION \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "param": "value" }'
A typical response:
{ "ok": true, "items": [ /* ... */ ] }
Receiving events: register a signed outbound webhook withPOST /api/v2/webhooks(Pro and above) — Taskade signs every delivery with an HMAC secret you can verify. See the Webhook Registration API. The oldersubscribeWebhook/unsubscribeWebhookoperations are deprecated.
Endpoints
List spaces (workspaces)
POST /listSpaces — every integration's entry point. Body is optional.
cURL
curl -X POST https://www.taskade.com/api/v2/listSpaces \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'
Python
import requests
res = requests.post(
"https://www.taskade.com/api/v2/listSpaces",
headers={"Authorization": "Bearer YOUR_TOKEN"},
json={},
)
print(res.json()["items"])
TypeScript
const res = await fetch("https://www.taskade.com/api/v2/listSpaces", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TASKADE_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({}),
});
const { items } = await res.json();
Filter with { "filterBy": { "name": { "operator": "contains", "value": "Marketing" } } }.
List folders in a space
POST /listFolders
curl -X POST https://www.taskade.com/api/v2/listFolders \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "spaceId": "SPACE_ID" }'
List projects in a space
POST /listProjects
curl -X POST https://www.taskade.com/api/v2/listProjects \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "spaceId": "SPACE_ID" }'
Get a project
POST /getProject — returns { ok, item: { id, name } }.
curl -X POST https://www.taskade.com/api/v2/getProject \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "projectId": "PROJECT_ID" }'
Create a project
POST /createProject — seed a project from Markdown.
cURL
curl -X POST https://www.taskade.com/api/v2/createProject \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"spaceId": "SPACE_ID",
"contentType": "text/markdown",
"content": "# Q2 Planning\n\n- Review roadmap\n- Draft OKRs"
}'
Python
import requests
res = requests.post(
"https://www.taskade.com/api/v2/createProject",
headers={"Authorization": "Bearer YOUR_TOKEN"},
json={
"spaceId": "SPACE_ID",
"contentType": "text/markdown",
"content": "# Q2 Planning\n\n- Review roadmap\n- Draft OKRs",
},
)
print(res.json()["item"]["id"])
List tasks
POST /listTasks — paginated with after / before cursors. Each task is { id, text, parentId?, completed }.
curl -X POST https://www.taskade.com/api/v2/listTasks \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "projectId": "PROJECT_ID", "limit": 100 }'
To create, update, complete, or delete tasks — or set assignees, dates, notes, and custom fields — v2 has you covered: seecreateTask,updateTask,moveTask,assignTask,setTaskDate,setTaskNote, andsetTaskFieldValue. To read one task rather than listing a project, use the REST API v1 Tasks endpoints.
Prompt an agent
POST /promptAgent — send a single prompt to a workspace agent and get a synchronous text response. This capability is v2-only.
cURL
curl -X POST https://www.taskade.com/api/v2/promptAgent \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"spaceId": "SPACE_ID",
"agentId": "AGENT_ID",
"prompt": "Summarize yesterday'\''s standup notes"
}'
Python
import requests
res = requests.post(
"https://www.taskade.com/api/v2/promptAgent",
headers={"Authorization": "Bearer YOUR_TOKEN"},
json={
"spaceId": "SPACE_ID",
"agentId": "AGENT_ID",
"prompt": "Summarize yesterday's standup notes",
},
)
print(res.json()["summary"])
TypeScript
const res = await fetch("https://www.taskade.com/api/v2/promptAgent", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TASKADE_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ spaceId, agentId, prompt: "Summarize standup notes" }),
});
const { summary } = await res.json();
Response:
{ "ok": true, "summary": "Here's a summary of the standup..." }
To review past conversations, use POST /listConversations ({ agentId, limit?, page? }) and POST /getConversation ({ agentId, convoId, includeTranscript? }). Pass "includeTranscript": true to get a Markdown transcript of the conversation in the response.
Manage agents
| Operation | Body |
|---|---|
POST /listAgents |
{ spaceId, filterBy? } |
POST /getAgent |
{ agentId } |
POST /createAgent |
{ folderId, name, data } |
POST /updateAgent |
{ agentId, name?, data? } |
POST /deleteAgent |
{ agentId } |
POST /generateAgent |
{ folderId, text } — generate an agent from a description |
POST /enablePublicAgentAccess |
{ agentId } → { ok, publicUrl } |
Attach knowledge to an agent
POST /addKnowledgeProject grounds an agent in a project. (removeKnowledgeProject, addKnowledgeMedia, removeKnowledgeMedia mirror it.)
curl -X POST https://www.taskade.com/api/v2/addKnowledgeProject \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "agentId": "AGENT_ID", "projectId": "PROJECT_ID" }'
Export / import a bundle
POST /exportBundle returns a portable Genesis app bundle; POST /importBundle installs one. See Bundles & App Kits for the full schema and the binary .tsk variants.
curl -X POST https://www.taskade.com/api/v2/exportBundle \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "spaceId": "SPACE_ID" }'
Full operation list
- Workspaces & structure:
listSpaces,listFolders,listMyProjects,listTemplates,listMedia. - Projects:
listProjects,getProject,createProject,createProjectFromTemplate,copyProject,completeProject,restoreProject,listTasks,listBlocks,listFields,listProjectMembers,getShareLink,enableShareLink. - Agents:
listAgents,getAgent,createAgent,updateAgent,deleteAgent,promptAgent,generateAgent,listConversations,getConversation,addKnowledgeProject,removeKnowledgeProject,addKnowledgeMedia,removeKnowledgeMedia,enablePublicAgentAccess,getPublicAgent,updatePublicAgent. - Media:
uploadMedia,getMedia,deleteMedia, plusGET /media/{mediaId}/contentandGET /media/spaces/{spaceId}/contentfor downloads. - Bundles:
exportBundle,importBundle,importBundleZip, plusGET /bundles/{spaceId}/export/zip. - Webhooks:
POST /webhooks,GET /webhooks,GET /webhooks/{id},DELETE /webhooks/{id}(signed — see Webhooks);subscribeWebhookandunsubscribeWebhookare deprecated.
The authoritative, always-current list is the live v2 spec.
Pagination
List operations that can return many rows use cursor pagination with after / before (tasks, blocks) or page / limit (members, conversations).
# next page of tasks
curl -X POST https://www.taskade.com/api/v2/listTasks \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "projectId": "PROJECT_ID", "limit": 100, "after": "LAST_TASK_ID" }'
Rate Limits
Requests are rate-limited per endpoint. Exact ceilings aren't published and can change without notice — when you hit one, the 429 response itself tells you everything you need:
| Header | Meaning |
|---|---|
x-rate-limit-limit |
Your total budget for the current window |
x-rate-limit-remaining |
Requests left in the window (0 when you're blocked) |
x-rate-limit-reset |
Seconds until the window reopens — schedule your retry from this |
Retry-After is not sent, so don't wait for it. Wait out x-rate-limit-reset before retrying — earlier retries will also be rejected:
async function withRetry<T>(fn: () => Promise<T>, retries = 3): Promise<T> {
for (let i = 0; i < retries; i++) {
try {
return await fn();
} catch (err: any) {
if (err.status === 429 && i < retries - 1) {
const resetSec = Number(err.headers?.["x-rate-limit-reset"]);
const waitMs = resetSec > 0 ? resetSec * 1000 : 2 ** i * 1000;
await new Promise(r => setTimeout(r, waitMs));
continue;
}
throw err;
}
}
throw new Error("Retry exhausted");
}
If you need sustained throughput, prefer batching — operations like /createTask accept arrays — over tightening polling loops, and spread scheduled jobs so they don't all fire at the same instant.
Error Handling
All error responses share this shape:
{
"ok": false,
"message": "Project not found",
"code": "not_found",
"statusMessage": "Not Found"
}
| Status | Meaning | Retry? | Fix |
|---|---|---|---|
| 400 | Bad request | No | Check the request body |
| 401 | Invalid / missing token | No | Regenerate or refresh the token |
| 402 | Out of credits, or the operation needs a higher plan (e.g. webhook registration requires Pro) | No | Top up credits or upgrade your plan |
| 403 | Insufficient permission | No | Use a token with access to the resource |
| 404 | Not found | No | Verify the ID and your workspace access |
| 429 | Rate limited | Yes | Exponential backoff |
| 5xx | Server error | Yes | Retry up to 3 times with backoff |
Never retry on400,401,403, or404. Fix the request first.
Security Best Practices
- Never commit tokens. Use environment variables or a secret manager.
- Use OAuth, not personal tokens, for multi-user applications.
- Rotate personal tokens periodically; you can hold up to 5 at a time.
- Encrypt refresh tokens at rest — they're long-lived.
Related
→ Webhooks