Operate TaskOS through REST
The API is the complete machine interface to a user's account. An agent can capture, organize, prioritize, complete, and analyze work without interacting with the frontend.
Owner derived from token
Versioned JSON API
Scoped, revocable access
Authentication
The user creates a token under API Access after Google sign-in and gives it to the agent. Raw tokens are shown once and retained by TaskOS only as SHA-256 hashes.
Authorization: Bearer taskos_<prefix>_<secret>Never send user_id. TaskOS derives the owner exclusively from the token. Revoked or expired tokens immediately return 401.
Recommended agent workflow
- 1Call GET /me to verify the token and inspect scopes.
- 2Call GET /today and GET /next-task before recommending work.
- 3Capture work with POST /tasks; omit status to place it in Inbox.
- 4Use PATCH /tasks/{taskId} to schedule, prioritize, value, or assign work. Set recurrence to { freq, interval } to make a task repeat — it needs a due_date or scheduled_date to shift from.
- 5Use PATCH /tasks/bulk instead of looping single-task requests when the same change applies to many tasks at once.
- 6Break a large task down with parent_task_id instead of writing steps into the description; nesting is exactly one level deep. GET /tasks/{taskId}/subtasks reads the children back.
- 7Set blocked_by_task_id when one task genuinely cannot start until another finishes. Blocked tasks report is_blocked, are excluded from GET /today, and are never recommended by GET /next-task — so never advise the user to start one.
- 8Put durations in estimated_minutes and time_spent_minutes rather than in prose, so the workload rollups in GET /today and GET /daily-summary stay accurate.
- 9Label work with tags for anything that cuts across projects, and read GET /tags first so you reuse the account's existing vocabulary rather than inventing near-duplicates.
- 10Record follow-ups as comments on the task (POST /tasks/{taskId}/comments) instead of appending to description, which would destroy the original intent.
- 11Use complete and reopen actions instead of managing completion timestamps. Completing a recurring task returns its next occurrence in meta.spawned_task (meta.spawned_tasks for bulk).
- 12Use GET /daily-summary to report what the user accomplished.
Endpoint map
Base URL: https://task.infinitatech.com/api/v1
| Method | Path | Purpose | Scope |
|---|---|---|---|
| GET | /tasks | Search and filter tasks | tasks:read |
| POST | /tasks | Create a task | tasks:write |
| GET | /tasks/{taskId} | Read one task | tasks:read |
| PATCH | /tasks/{taskId} | Update task fields | tasks:write |
| DELETE | /tasks/{taskId} | Soft-delete a task | tasks:write |
| PATCH | /tasks/bulk | Apply one patch to up to 100 tasks | tasks:write |
| POST | /tasks/{taskId}/complete | Complete idempotently | tasks:write |
| POST | /tasks/{taskId}/reopen | Reopen idempotently | tasks:write |
| GET | /tasks/{taskId}/subtasks | List a task's subtasks | tasks:read |
| GET / POST | /tasks/{taskId}/comments | Read or append timestamped notes | tasks:read / tasks:write |
| DELETE | /tasks/{taskId}/comments/{commentId} | Delete a note | tasks:write |
| GET | /tags | Every tag in use, with counts | tasks:read |
| GET | /today | Due, overdue, scheduled, and active tasks | tasks:read |
| GET | /upcoming | Future work | tasks:read |
| GET | /next-task | Recommended next task | tasks:read |
| GET | /inbox | Untriaged tasks | tasks:read |
| GET / POST | /projects | List or create projects | projects:* |
| GET / PATCH / DELETE | /projects/{projectId} | Read, update, or archive | projects:* |
| GET | /activity | Immutable history | activity:read |
| GET | /daily-summary | Summarize a local day | tasks:read + activity:read |
| GET | /me | Inspect token identity and scopes | valid token |
Requests and responses
Create a high-value task
curl -X POST https://task.infinitatech.com/api/v1/tasks \
-H "Authorization: Bearer $TASKOS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"title": "Send the launch brief",
"status": "todo",
"priority": "high",
"value_score": 5,
"scheduled_date": "2026-09-01"
}'Success envelope
{
"data": {
"id": "6ad28d2e-...",
"title": "Send the launch brief",
"status": "todo",
"priority": "high",
"value_score": 5,
"priority_score": 65
}
}Complete and summarize
POST /api/v1/tasks/{taskId}/complete
GET /api/v1/daily-summary?date=2026-09-01Create a repeating task
curl -X POST https://task.infinitatech.com/api/v1/tasks \
-H "Authorization: Bearer $TASKOS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"title": "Water the plants",
"status": "todo",
"scheduled_date": "2026-09-01",
"recurrence": { "freq": "weekly", "interval": 1 }
}'
# Completing it returns the next occurrence in meta.spawned_task:
# POST /api/v1/tasks/{taskId}/complete
# { "data": { ...completed task... }, "meta": { "spawned_task": { ...next occurrence... } } }Bulk-update many tasks at once
curl -X PATCH https://task.infinitatech.com/api/v1/tasks/bulk \
-H "Authorization: Bearer $TASKOS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"ids": ["6ad28d2e-7c47-4e06-ae72-29469d812ef1", "0f6f2d81-9a3e-4c2b-9c19-2f1a0b7d5e44"],
"patch": { "status": "todo", "project_id": null }
}'
# Ownership is checked before the write: an unknown, deleted, or foreign id
# rejects the whole batch with 422 and changes nothing. Bulk-completing
# recurring tasks returns their new occurrences in meta.spawned_tasks.Subtasks and blockers
# Break a large task into subtasks (nesting is one level deep):
curl -X POST https://task.infinitatech.com/api/v1/tasks \
-H "Authorization: Bearer $TASKOS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"title": "Analyse requirements",
"parent_task_id": "6ad28d2e-7c47-4e06-ae72-29469d812ef1",
"estimated_minutes": 45,
"tags": ["research"]
}'
# Declare that one task cannot start until another finishes:
curl -X PATCH https://task.infinitatech.com/api/v1/tasks/0f6f2d81-... \
-H "Authorization: Bearer $TASKOS_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "blocked_by_task_id": "6ad28d2e-7c47-4e06-ae72-29469d812ef1" }'
# While the blocker is open the task reports "is_blocked": true, is left out
# of GET /today, and is never returned by GET /next-task. Cycles are rejected.
# GET /api/v1/tasks/{taskId}/subtasks lists the children of one task.
# GET /api/v1/tasks?parent_task_id=none lists only top-level tasks.Estimates and time tracking
# Estimates and logged time are first-class integer fields, in minutes —
# never write them into the description.
curl -X PATCH https://task.infinitatech.com/api/v1/tasks/6ad28d2e-... \
-H "Authorization: Bearer $TASKOS_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "estimated_minutes": 30, "time_spent_minutes": 45 }'
# GET /today returns meta.estimated_minutes (today's workload) alongside
# meta.blocked_count. GET /daily-summary adds estimated_minutes_remaining
# and time_spent_minutes_logged for the day.Tags
# Tags are a flat, cross-project vocabulary. Sending "tags" replaces the
# task's whole set; send [] or null to clear it.
curl -X PATCH https://task.infinitatech.com/api/v1/tasks/6ad28d2e-... \
-H "Authorization: Bearer $TASKOS_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "tags": ["sales", "quick win"] }'
# Filter by tag (AND semantics — a task must carry every tag listed):
curl "https://task.infinitatech.com/api/v1/tasks?tags=sales,quick%20win" \
-H "Authorization: Bearer $TASKOS_TOKEN"
# Discover the vocabulary first, with per-tag counts:
curl https://task.infinitatech.com/api/v1/tags -H "Authorization: Bearer $TASKOS_TOKEN"Comments on a task
# Log a follow-up without overwriting the task description:
curl -X POST https://task.infinitatech.com/api/v1/tasks/6ad28d2e-.../comments \
-H "Authorization: Bearer $TASKOS_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "body": "Client asked to call back tomorrow." }'
# Read the log back, oldest first:
curl https://task.infinitatech.com/api/v1/tasks/6ad28d2e-.../comments \
-H "Authorization: Bearer $TASKOS_TOKEN"Errors
Errors use one stable envelope. Do not retry validation, permission, or not-found errors without changing the request.
{
"error": {
"code": "validation_error",
"message": "Request validation failed",
"details": []
}
}Machine-readable schema
OpenAPI 3.1 is the source for operation IDs, parameters, request bodies, response schemas, and authentication.