Capture GTD exposes a RESTful API built on CQRS principles. Write operations (commands) and read operations (queries) use distinct endpoint patterns. The API is auto-generated from the domain model using OpenAPI 3.1.
Base URL
https://app.capture-gtd.com/api
All endpoints are scoped to an organization:
/api/organizations/{organizationId}/...
The organizationId is a UUID assigned to each user account.
Authentication
Capture GTD uses OAuth 2.0 with Keycloak as the identity provider. The server publishes standard discovery endpoints:
| Endpoint | Purpose |
|---|---|
GET /.well-known/oauth-authorization-server | OAuth 2.0 Authorization Server Metadata (RFC 8414) |
GET /.well-known/oauth-protected-resource | Protected Resource Metadata (RFC 9728) |
Supported grant types: authorization_code, refresh_token
Required scopes: profile, email, organization, offline_access
PKCE: Required. The server supports S256 code challenge method.
Include the access token in the Authorization header:
Authorization: Bearer <access_token>
Request and Response Conventions
- All request and response bodies use
application/json. - UUIDs are formatted as strings (e.g.,
"550e8400-e29b-41d4-a716-446655440000"). - Timestamps use ISO 8601 format (e.g.,
"2026-01-15T10:30:00Z"). - The
Accept-Languageheader (en,de) controls error message localization. - Enum values use PascalCase (e.g.,
"Medium","XSmall","Critical").
Write operation responses
| HTTP Method | Success Code | Description |
|---|---|---|
POST (create) | 201 Created | Returns a Location header with the new resource URL |
POST (action) | 202 Accepted | Command accepted for processing |
PATCH | 202 Accepted | Partial update accepted |
DELETE | 204 No Content | Resource deleted |
Error response format
All errors return a JSON body:
{
"message": "Task name cannot be blank",
"details": {}
}
Common error codes
| Code | Meaning |
|---|---|
400 | Validation error — the request body is invalid or a business rule was violated |
401 | Authentication required or token expired |
403 | Insufficient permissions for the requested organization |
404 | Resource not found |
500 | Internal server error |
Tasks
Tasks are the core resource. Each task has a kind that determines its GTD classification: Stuff, Todo, Project, Scheduled, SomedayMaybe, ReferenceFile, or WaitingFor.
Create a task (capture)
POST /api/organizations/{organizationId}/tasks
Creates a new inbox item (Stuff kind). Returns 201 with Location header.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | Task title |
description | string | no | Additional details (defaults to "") |
project | string (UUID) | no | Parent project ID |
importance | string | yes | ExtraLow, Low, Medium, High, or Critical |
Clarify a task
POST /api/organizations/{organizationId}/tasks/{taskId}/clarify
Transitions a task from inbox to a clarified state. Returns 202.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
nextState | object | yes | Target kind (see ClarifyKind below) |
name | string | no | Updated name |
description | string | no | Updated description |
importance | string | no | Updated importance |
projectId | string (UUID) | no | Parent project to assign |
contexts | array of strings (UUIDs) | no | Context IDs to assign |
areasOfFocus | array of strings (UUIDs) | no | Area of focus IDs to assign |
Move a task
POST /api/organizations/{organizationId}/tasks/{taskId}/move
Re-classifies an already-clarified task to a different kind. Returns 202.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
nextState | object | yes | Target kind (see ClarifyKind below) |
Complete a task
POST /api/organizations/{organizationId}/tasks/{taskId}/complete
Marks a task as complete. For recurring tasks, pass occurrenceDate to complete a specific occurrence. Returns 202.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
occurrenceDate | string (ISO 8601) | no | Specific recurrence occurrence to complete |
Reopen a task
POST /api/organizations/{organizationId}/tasks/{taskId}/reopen
Reopens a previously completed task. No request body. Returns 202.
Trash and restore
POST /api/organizations/{organizationId}/tasks/{taskId}/trash
POST /api/organizations/{organizationId}/tasks/{taskId}/restore
Soft-deletes or restores a task. No request body. Returns 202.
Delegate a task
POST /api/organizations/{organizationId}/tasks/{taskId}/delegate
Delegates a task to a person, converting it to WaitingFor state. Returns 202.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
personId | string (UUID) | yes | Person to delegate to |
Delete a task
DELETE /api/organizations/{organizationId}/tasks/{taskId}
Permanently deletes a task. Returns 204.
Uncomplete a recurrence
POST /api/organizations/{organizationId}/tasks/{taskId}/uncomplete-recurrence
Reverses a specific recurrence completion. Returns 202.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
occurrenceDate | string (ISO 8601) | yes | The occurrence to uncomplete |
Update task properties (PATCH)
PATCH /api/organizations/{organizationId}/tasks/{taskId}
Applies a partial update using RFC 6902 JSON Patch format. Returns 202.
Each patch operation specifies op, path, and value:
{ "op": "replace", "path": "/name", "value": "Updated task name" }
Supported patch operations:
| Path | Value Type | Description |
|---|---|---|
/name | string | Task title |
/description | string | Task description |
/importance | string | ExtraLow through Critical |
/effort | string | XSmall, Small, Medium, Large, XLarge |
/deadline | object | Deadline change (see below) |
/schedule | object | Schedule for scheduled tasks |
/outcome | string | Project outcome statement |
/project | string (UUID) or null | Parent project |
/waitingForPerson | string (UUID) | Delegated person |
/contexts | uses add/remove ops | Add or remove a context by ID |
/areasOfFocus | uses add/remove ops | Add or remove an area of focus by ID |
/dependencies | uses add/remove ops | Add or remove a dependency by ID |
/projectToGoal | uses add/remove ops | Link or unlink project from a goal |
Query tasks
GET /api/organizations/{organizationId}/tasks?query={queryName}
Returns an array of TaskView objects. The query parameter selects the list.
Available queries:
| Query | Parameters | Description |
|---|---|---|
inbox | — | All unclarified stuff |
nextTasks | — | Actionable next actions sorted by impact score |
engagedTasks | context?, project? | Filtered next actions for the engage view |
projects | — | Active (incomplete, non-trashed) projects |
allProjects | — | All projects including completed |
scheduled | — | All scheduled items |
scheduledBefore | date | Scheduled items before a given date |
somedayMaybe | — | Someday/maybe items |
referenceFiles | — | Reference material |
waitingFor | — | Delegated items |
completedTasks | — | All completed tasks |
trashed | — | Trashed tasks |
inProject | projectId | Tasks belonging to a project |
subProjects | projectId | Sub-projects of a project |
blockedTasksInProject | projectId | Tasks blocked by unresolved dependencies |
projectsWithoutNextActions | — | Projects that have no actionable next steps |
staleProjects | activityThreshold | Projects with no activity since threshold |
tasksDueOnOrBefore | date | Tasks with deadlines on or before a date |
tasksScheduledBetween | startInclusive, endExclusive | Scheduled in a date range |
tasksCompletedBetween | startInclusive, endExclusive | Completed in a date range |
doneOnDate | date | Tasks completed on a specific date |
allTasks | — | Every task regardless of state |
getRecurringTasks | — | All recurring tasks |
Get a single task
GET /api/organizations/{organizationId}/tasks/{taskId}
Returns a single TaskView object or 404.
Get dependency graph
GET /api/organizations/{organizationId}/tasks/{taskId}/dependency-graph
Returns a DependencyGraphView containing all tasks in the dependency chain, their edges, and the root task ID.
Contexts
Contexts represent where or with whom you can act (e.g., @computer, @errands, @office).
| Endpoint | Method | Description |
|---|---|---|
/api/organizations/{organizationId}/contexts | POST | Create a context (name required) |
/api/organizations/{organizationId}/contexts/{contextId} | DELETE | Delete a context |
/api/organizations/{organizationId}/contexts/{contextId} | PATCH | Update context name (RFC 6902) |
/api/organizations/{organizationId}/contexts | GET | List all contexts |
/api/organizations/{organizationId}/contexts/{contextId} | GET | Get a single context |
Areas of Focus
Areas of focus represent life domains to maintain (e.g., Health, Career, Finances).
| Endpoint | Method | Description |
|---|---|---|
/api/organizations/{organizationId}/area-of-focuses | POST | Create an area of focus (name required) |
/api/organizations/{organizationId}/area-of-focuses/{areaOfFocusId} | DELETE | Delete an area of focus |
/api/organizations/{organizationId}/area-of-focuses/{areaOfFocusId} | PATCH | Update name (RFC 6902) |
/api/organizations/{organizationId}/area-of-focuses | GET | List all areas of focus |
/api/organizations/{organizationId}/area-of-focuses/{areaOfFocusId} | GET | Get a single area of focus |
People
People represent contacts for task delegation (WaitingFor).
| Endpoint | Method | Description |
|---|---|---|
/api/organizations/{organizationId}/persons | POST | Create a person (name required, email optional) |
/api/organizations/{organizationId}/persons/{personId} | DELETE | Delete a person |
/api/organizations/{organizationId}/persons/{personId} | PATCH | Update name/email (RFC 6902) |
/api/organizations/{organizationId}/persons | GET | List all people |
/api/organizations/{organizationId}/persons/{personId} | GET | Get a single person |
Goals (Horizon 3)
Goals represent 1-2 year objectives. Projects can be linked to goals.
| Endpoint | Method | Description |
|---|---|---|
/api/organizations/{organizationId}/goals | POST | Create a goal (name required, description optional) |
/api/organizations/{organizationId}/goals/{goalId} | DELETE | Delete a goal |
/api/organizations/{organizationId}/goals/{goalId} | PATCH | Update name/description (RFC 6902) |
/api/organizations/{organizationId}/goals/{goalId}/complete | POST | Mark goal complete |
/api/organizations/{organizationId}/goals/{goalId}/reopen | POST | Reopen a completed goal |
/api/organizations/{organizationId}/goals | GET | List all goals |
/api/organizations/{organizationId}/goals/{goalId} | GET | Get a single goal |
Visions (Horizon 4)
Visions represent 3-5 year life direction.
| Endpoint | Method | Description |
|---|---|---|
/api/organizations/{organizationId}/visions | POST | Create a vision (name required, description optional) |
/api/organizations/{organizationId}/visions/{visionId} | DELETE | Delete a vision |
/api/organizations/{organizationId}/visions/{visionId} | PATCH | Update name/description (RFC 6902) |
/api/organizations/{organizationId}/visions/{visionId}/complete | POST | Mark vision complete |
/api/organizations/{organizationId}/visions/{visionId}/reopen | POST | Reopen a completed vision |
/api/organizations/{organizationId}/visions | GET | List all visions |
/api/organizations/{organizationId}/visions/{visionId} | GET | Get a single vision |
Purpose and Principles (Horizon 5)
The purpose statement and core principles that guide all decisions.
| Endpoint | Method | Body | Description |
|---|---|---|---|
/api/organizations/{organizationId}/purpose-and-principleses/{id} | PATCH | {"op":"replace","path":"/purposeStatement","value":"..."} | Set or clear the purpose statement |
/api/organizations/{organizationId}/purpose-and-principleses/{id} | PATCH | {"op":"add","path":"/principles","value":"..."} | Add a principle |
/api/organizations/{organizationId}/purpose-and-principleses/{id} | PATCH | {"op":"remove","path":"/principles","value":"..."} | Remove a principle |
/api/organizations/{organizationId}/purpose-and-principleses | GET | — | Get purpose and principles |
Review Analytics
Specialized read-only endpoints for review screens.
| Endpoint | Parameters | Returns |
|---|---|---|
GET .../reviews/has-stuck-projects | — | { "hasStuckProjects": boolean } |
GET .../reviews/project-progress/{projectId} | — | ProjectProgressDto with completed/incomplete counts |
GET .../reviews/analytics/completed-by-context | startInclusive, endExclusive | Counts of completed tasks by context |
GET .../reviews/analytics/completed-by-area | startInclusive, endExclusive | Counts of completed tasks by area of focus |
GET .../reviews/analytics/incomplete-by-context | — | Counts of incomplete tasks by context |
GET .../reviews/analytics/incomplete-by-area | — | Counts of incomplete tasks by area of focus |
GET .../reviews/analytics/all-completed-by-context | — | All-time completed counts by context |
GET .../reviews/analytics/all-completed-by-area | — | All-time completed counts by area of focus |
All review endpoints are prefixed with /api/organizations/{organizationId}/reviews.
Habits and Recurring Task Analytics
| Endpoint | Returns |
|---|---|
GET .../habits-overviews | Overall completion rate, streaks, and per-task analytics |
GET .../heatmap-days | Daily completion heatmap data |
GET .../trend-data-points | Completion rate trends over time |
GET .../recurring-task-analyticses | Detailed analytics per recurring task |
ClarifyKind Object
The nextState field in clarify and move operations uses a discriminated union with a type field:
| Type | Additional Fields |
|---|---|
Stuff | (none) |
ReferenceFile | (none) |
SomedayMaybe | effort, dependsOn (array of UUIDs) |
Scheduled | effort, schedule ({ "type": "Once", "scheduleDate": "..." } or { "type": "RecurrenceRule", "rrule": "..." }) |
Project | outcome, effort, dependsOn, deadline?, goalId? |
Todo | effort, dependsOn, deadline? |
WaitingFor | personId, effort, dependsOn, deadline? |
Deadline variants: { "type": "Once", "due": "2026-03-01T00:00:00Z" } or { "type": "RecurrenceRule", "rrule": "FREQ=WEEKLY;BYDAY=MO" }.
Effort values: XSmall, Small, Medium, Large, XLarge.