AI-agent operating guide

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

  1. 1Call GET /me to verify the token and inspect scopes.
  2. 2Call GET /today and GET /next-task before recommending work.
  3. 3Capture work with POST /tasks; omit status to place it in Inbox.
  4. 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.
  5. 5Use PATCH /tasks/bulk instead of looping single-task requests when the same change applies to many tasks at once.
  6. 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.
  7. 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.
  8. 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.
  9. 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.
  10. 10Record follow-ups as comments on the task (POST /tasks/{taskId}/comments) instead of appending to description, which would destroy the original intent.
  11. 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).
  12. 12Use GET /daily-summary to report what the user accomplished.

Endpoint map

Base URL: https://task.infinitatech.com/api/v1

MethodPathPurposeScope
GET/tasksSearch and filter taskstasks:read
POST/tasksCreate a tasktasks:write
GET/tasks/{taskId}Read one tasktasks:read
PATCH/tasks/{taskId}Update task fieldstasks:write
DELETE/tasks/{taskId}Soft-delete a tasktasks:write
PATCH/tasks/bulkApply one patch to up to 100 taskstasks:write
POST/tasks/{taskId}/completeComplete idempotentlytasks:write
POST/tasks/{taskId}/reopenReopen idempotentlytasks:write
GET/tasks/{taskId}/subtasksList a task's subtaskstasks:read
GET / POST/tasks/{taskId}/commentsRead or append timestamped notestasks:read / tasks:write
DELETE/tasks/{taskId}/comments/{commentId}Delete a notetasks:write
GET/tagsEvery tag in use, with countstasks:read
GET/todayDue, overdue, scheduled, and active taskstasks:read
GET/upcomingFuture worktasks:read
GET/next-taskRecommended next tasktasks:read
GET/inboxUntriaged taskstasks:read
GET / POST/projectsList or create projectsprojects:*
GET / PATCH / DELETE/projects/{projectId}Read, update, or archiveprojects:*
GET/activityImmutable historyactivity:read
GET/daily-summarySummarize a local daytasks:read + activity:read
GET/meInspect token identity and scopesvalid 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-01

Create 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": []
  }
}
400Invalid JSON
401Missing, invalid, expired, or revoked token
403Token lacks the required scope
404Resource absent or owned by another user
422Validation or ownership-reference failure
500Unexpected server failure

Machine-readable schema

OpenAPI 3.1 is the source for operation IDs, parameters, request bodies, response schemas, and authentication.