| description | Production-ready REST reference for the Public API v2. Top-10 most-used endpoints with cURL, TypeScript, and Python examples. |
|---|
The Public API v2 launched in 2026 with cleaner response formats, improved pagination, and better error messages. This page documents the endpoints most integrators reach for first.
{% hint style="info" %} v1 still works. v2 runs side-by-side with v1 so existing integrations continue to function. New integrations should target v2. {% endhint %}
- Base URL & Authentication
- OAuth 2.0 Flow
- Endpoints
- Rate Limits
- Pagination
- Error Handling
- Security Best Practices
All v2 endpoints 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 production apps.
Authorization: Bearer YOUR_TOKENFor production applications that act on behalf of other users, use OAuth 2.0 instead of a personal token.
sequenceDiagram
participant App as Your App
participant Taskade as www.taskade.com
participant User as End User
App->>Taskade: GET /oauth/authorize?client_id&redirect_uri&scope
Taskade->>User: Show consent screen
User->>Taskade: Approve
Taskade->>App: Redirect with authorization code
App->>Taskade: POST /oauth/token (code + client_secret)
Taskade->>App: access_token + refresh_token
App->>Taskade: GET /api/v2/workspaces (Bearer access_token)
Taskade->>App: 200 OK [workspaces]
Refresh an expired access token by calling POST /oauth/token with grant_type=refresh_token and the stored refresh token.
GET /workspaces — Every integration's entry point.
{% tabs %} {% tab title="cURL" %}
curl https://www.taskade.com/api/v2/workspaces \
-H "Authorization: Bearer YOUR_TOKEN"{% endtab %}
{% tab title="TypeScript" %}
import { Taskade } from "@taskade/sdk";
const taskade = new Taskade({ token: process.env.TASKADE_TOKEN! });
const workspaces = await taskade.workspaces.list();
console.log(workspaces.items);{% endtab %}
{% tab title="Python" %}
import requests
response = requests.get(
"https://www.taskade.com/api/v2/workspaces",
headers={"Authorization": "Bearer YOUR_TOKEN"},
)
print(response.json()["items"]){% endtab %} {% endtabs %}
GET /workspaces/{workspaceId}/folders
curl https://www.taskade.com/api/v2/workspaces/WORKSPACE_ID/folders \
-H "Authorization: Bearer YOUR_TOKEN"GET /folders/{folderId}/projects — Supports cursor pagination.
curl "https://www.taskade.com/api/v2/folders/FOLDER_ID/projects?limit=50" \
-H "Authorization: Bearer YOUR_TOKEN"GET /projects/{projectId} — Returns project structure with blocks.
{% tabs %} {% tab title="cURL" %}
curl https://www.taskade.com/api/v2/projects/PROJECT_ID \
-H "Authorization: Bearer YOUR_TOKEN"{% endtab %}
{% tab title="TypeScript" %}
const project = await taskade.projects.get("PROJECT_ID");
console.log(`Project: ${project.name}, ${project.blocks.length} blocks`);{% endtab %} {% endtabs %}
POST /folders/{folderId}/projects
curl -X POST https://www.taskade.com/api/v2/folders/FOLDER_ID/projects \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Q2 Planning",
"template": "list"
}'POST /projects/{projectId}/tasks/
{% tabs %} {% tab title="cURL" %}
curl -X POST https://www.taskade.com/api/v2/projects/PROJECT_ID/tasks/ \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"tasks": [
{ "contentType": "text/markdown", "content": "Review Q2 roadmap" }
],
"placement": "afterbegin"
}'{% endtab %}
{% tab title="TypeScript" %}
await taskade.tasks.create("PROJECT_ID", {
tasks: [{ contentType: "text/markdown", content: "Review Q2 roadmap" }],
placement: "afterbegin",
});{% endtab %} {% endtabs %}
Placement values: afterbegin (top), beforeend (bottom).
POST /agents/{agentId}/prompt — Send a prompt to any workspace agent and receive a synchronous response.
{% tabs %} {% tab title="cURL" %}
curl -X POST https://www.taskade.com/api/v2/agents/AGENT_ID/prompt \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"message": "Summarize yesterday'\''s standup notes",
"conversationId": "optional-convo-id"
}'{% endtab %}
{% tab title="TypeScript" %}
const response = await taskade.agents.prompt("AGENT_ID", {
message: "Summarize yesterday's standup notes",
});
console.log(response.message);{% endtab %} {% endtabs %}
Response:
{
"ok": true,
"conversationId": "convo_abc123",
"message": "Here's a summary of the standup..."
}Pass conversationId from a previous response to continue the same conversation. Conversations persist automatically.
POST /agents/{agentId}/knowledge/project
curl -X POST https://www.taskade.com/api/v2/agents/AGENT_ID/knowledge/project \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "projectId": "PROJECT_ID" }'Now the agent has the project as a grounded knowledge source.
POST /webhooks — Subscribe to workspace events.
curl -X POST https://www.taskade.com/api/v2/webhooks \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.com/taskade-webhook",
"events": ["task.created", "task.completed"]
}'See the Webhooks guide for event types and signature verification.
PUT /projects/{projectId}/tasks/{taskId} — Edit task content, completion, or placement.
curl -X PUT https://www.taskade.com/api/v2/projects/PROJECT_ID/tasks/TASK_ID \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "content": "Updated task text", "completed": true }'API requests are rate-limited per token.
| Response | Meaning | Action |
|---|---|---|
429 Too Many Requests |
You exceeded the rate limit | Respect the Retry-After header |
Retry-After: 30 |
Wait 30 seconds before retrying | Use exponential backoff |
Recommended retry strategy:
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 wait = 2 ** i * 1000;
await new Promise(r => setTimeout(r, wait));
continue;
}
throw err;
}
}
throw new Error("Retry exhausted");
}List endpoints use cursor-based pagination:
{
"items": [ /* ... */ ],
"nextCursor": "eyJpZCI6InByb2pfMTIzIn0="
}Pass ?cursor=<nextCursor> to get the next page. No nextCursor in the response means you're on the last page.
let cursor: string | undefined;
do {
const page = await taskade.projects.list({ folderId, cursor, limit: 50 });
for (const project of page.items) {
console.log(project.name);
}
cursor = page.nextCursor;
} while (cursor);All error responses follow this shape:
{
"ok": false,
"message": "Project not found",
"code": "not_found",
"statusMessage": "Not Found"
}| Status | Meaning | Retry? | Fix |
|---|---|---|---|
| 400 | Bad request | No | Check request body |
| 401 | Invalid / missing token | No | Regenerate or refresh token |
| 403 | Insufficient scope | No | Regenerate token with needed scope |
| 404 | Resource not found | No | Verify ID and workspace access |
| 429 | Rate limited | Yes | Exponential backoff |
| 402 | Out of credits | No | Top up or switch to cheaper model |
| 5xx | Server error | Yes | Retry up to 3 times with backoff |
{% hint style="warning" %}
Never retry on 400, 401, 403, or 404. Fix the request first.
{% endhint %}
- Never commit tokens. Use environment variables (
process.env.TASKADE_TOKEN) or a secret manager. - Rotate personal tokens every 90 days.
- Use OAuth, not personal tokens, for multi-user applications.
- Scope tokens to the minimum required permissions.
- Encrypt refresh tokens at rest — they're long-lived.
- Verify webhook signatures on incoming events (see Webhooks).
{% content-ref url="sdk-quickstart.md" %} sdk-quickstart.md {% endcontent-ref %}
{% content-ref url="sdk-cookbook.md" %} sdk-cookbook.md {% endcontent-ref %}
{% content-ref url="developers/authentication.md" %} authentication.md {% endcontent-ref %}
{% content-ref url="webhooks.md" %} webhooks.md {% endcontent-ref %}

