Taskaid API reference The Taskaid API reads and changes the same tasks, lists and daily plans you see in the app, over HTTPS and JSON. Base URL: https://taskaid.ai/api/v1 Description: /openapi.json, in OpenAPI 3.1, also listed in the API catalog. Import it into an API client, such as Postman, Bruno or others, to get every request ready to send. The endpoints below are generated from that description, so they say exactly what the server accepts. Signing in Every request carries a key in the Authorization header: Authorization: Bearer <key> There are two kinds of key. The API treats them the same way. API keys, for your own scripts Create one in Settings, under API keys. Give it a name you'll recognise, and choose its access: Read only: view tasks, lists and daily plans. Read and write: also create, change and delete them. The key is shown once, so copy it then; only a hash of it is kept. It works until you revoke it in the same place, which takes effect immediately. Keys start with taid_api_, so a leaked one is easy to recognise. Treat one like a password and keep it out of code you share. OAuth, for apps other people use An app that acts for other people signs each of them in through Taskaid's OAuth 2.1 authorization server, the same one assistants connect through: the authorization code flow with PKCE, the person approving access in their browser, and a refresh token to renew it without asking again. A client identifies itself with a client ID metadata document, or registers on first use. Everything a client needs to start is in the authorization server metadata. Scopes Two scopes cover the API: read: view tasks, lists and daily plans. write: create and update them, and delete tasks and lists. A read-only API key holds read; a read-and-write key holds both. Each endpoint names the scope it needs. A request without a valid key gets 401. A key without the scope gets 403, with a WWW-Authenticate header naming the scope. Requests Bodies are JSON, sent as Content-Type: application/json. Anything else gets 415. Unknown fields and query parameters are refused with 400, so a misspelt name fails instead of being quietly ignored. A task is named by its reference, such as TASKAID-45 or 45. A list is named by its id. Dates are calendar days, YYYY-MM-DD, in your own time zone. Until you've opened the web app once, that's UTC. Task filters also take a day counted from today, as an ISO 8601 duration: P0D is today, P1D tomorrow, -P1D yesterday. A reminder is a time of day, HH:MM in 24-hour time, on the task's when day in your time zone. Setting one needs a when, a time zone, and a time that hasn't passed; otherwise it gets 400. Responses Creating a task or a list answers 201 Created, with the new one's address in Location. Saving a day's plan with PUT answers 201 when the plan is new and 200 when it replaces one. PUT writes the whole plan, so a title left out is cleared. Deleting answers 204, with no body. Tasks come a page at a time. When there are more, the response has nextCursor. Send it back as cursor, with the same filters, for the next page. No nextCursor means the last page. Errors Every error is a problem details object (RFC 9457), sent as application/problem+json: { "type": "https://taskaid.ai/problems/task-not-found", "title": "Task not found", "status": 404, "detail": "Task TASKAID-999 not found" } Branch on type. title is fixed for each type and detail is written for people, so don't parse either. Handle the types below, fall back to the status for any other, and ignore members you don't recognise. An error the status already explains, such as a malformed request, a missing scope or an unknown endpoint, has "type": "about:blank". task-not-found 404. The task doesn't exist, or isn't yours. list-not-found 404. The list doesn't exist, or isn't yours. A task write that names such a list gets it too. plan-not-found 404. The day has no plan. Saving one with PUT creates it. note-too-long 400. The note is longer than one write may send. The limit is on the note field below. note-changed 412. The note changed after you read it, so nothing was written. The current note is in the note member. See Changing a note safely, below. Changing a note safely A note can change from more than one place: the app, an assistant, your own script. To update a task without overwriting a change you haven't seen, send If-Match with the note as you last read it: Hash the note with SHA-256, as lowercase hex. Treat a null note as an empty string before hashing. Send it in quotes, If-Match: "<hash>", with your PATCH. If the note has changed since, nothing is written, and the 412 carries the current note to merge and try again. Without If-Match, the write goes through as sent. Versioning The version is in the path. Within v1, changes only add: new endpoints, optional parameters, response fields and error types. Ignore fields you don't recognise. A change that would break a client comes as v2, served alongside v1 for a stated period, announced in the changelog and marked with Deprecation and Sunset headers on v1. Tasks The to-dos in your account: each has a name, and can have a day, a reminder, a note and a list. List tasks Method: GET Path: /api/v1/tasks Operation ID: listTasks Tags: Tasks Effective servers / Authentication oauth2: OAuth 2.0: authorization code, authorize /oauth/authorize, token /oauth/token, refresh /oauth/token, scopes: read Or: apiKey: HTTP bearer, scopes: read An API key from Settings. Query parameters completed: boolean Narrow to finished (true) or open (false) tasks. Omit for both. listId: string Narrow to a single list. Omit to span every list. limit: integer, default: 50, minimum: 1, maximum: 100 Max results. Defaults to 50, up to 100. cursor: string Continue from a previous response's nextCursor, with the same filters. Omit for the first page. query: string Narrow to tasks matching this text. Every whitespace-separated word must appear in the task's name or note (case-insensitive, any order), so extra words narrow the results rather than widening them — pass distinctive keywords, not a full sentence. when[gte]: string Narrow by scheduled day. Each bound is a day, "2026-09-19", or an ISO 8601 duration from today in the user's timezone: "P0D" is today, "P1D" tomorrow, "-P1D" yesterday, "P2W" two weeks out. Inbox tasks have no day and never match. Inclusive lower bound. Omit it to include every earlier day. when[lte]: string Narrow by scheduled day. Each bound is a day, "2026-09-19", or an ISO 8601 duration from today in the user's timezone: "P0D" is today, "P1D" tomorrow, "-P1D" yesterday, "P2W" two weeks out. Inbox tasks have no day and never match. Inclusive upper bound. With completed: false, "P0D" alone reads today and everything overdue. Responses 200 A page of tasks. Content type: application/json tasks (required): array of Task nextCursor: string Pass as cursor, with the same filters, to read the next page. Absent on the last page. 400, 401, 403 400 The request is malformed or breaks a rule. 401 No valid credential. 403 The credential lacks the scope. Content type: application/problem+json schema: Problem Problem details (RFC 9457). detail (required): string What went wrong this time, for people. Don't parse it. status (required): integer title (required): string Fixed for each type. Don't branch on it. type (required): string Names the problem: a type under https://taskaid.ai/problems/, or about:blank when the status says it all. Handle the types you recognise and fall back to the status for any other; ignore members you don't recognise. Create a task Method: POST Path: /api/v1/tasks Operation ID: createTask Tags: Tasks Effective servers / Authentication oauth2: OAuth 2.0: authorization code, authorize /oauth/authorize, token /oauth/token, refresh /oauth/token, scopes: write Or: apiKey: HTTP bearer, scopes: write An API key from Settings. Request body Required: true Content type: application/json no additional properties name (required): string, minLength: 1, maxLength: 500 Required when creating. On update, omit to keep the current name. A few words naming the action; the day goes in when, the detail in note. completed: boolean Marks the task done. True stamps completedAt with the time of the call, never the time the work finished. duration: integer | null, minimum: 1, maximum: 1440 Estimated duration in minutes, up to a day. Null clears the estimate. listId: string | null Pass null to unlink the task from its list. note: string | null Task notes, as Markdown, up to 15,000 characters — rendered as rich text in the app. Headings, lists, bold, and inline code are supported. Send literal newlines and characters, not escape sequences. reminder: string | null, format: time A time of day for a reminder, "HH:MM" in 24-hour time (e.g. "15:00"), on the task's when day in the user's time zone. Moving the task moves it; null removes it. At that time Taskaid sends the task.reminded event to subscribed assistants. starred: boolean when: string | null The day the task is scheduled for, as "YYYY-MM-DD" (e.g. "2026-05-21"). Omit or pass null when creating to leave the task in Inbox; pass null when updating to move it back there. Responses 201 The created task. Headers: Location (required) Where the new resource can be read. string Where the new resource can be read. Content type: application/json schema: Task completed (required): boolean completedAt (required): string | null duration (required): number | null id (required): string list (required): object | null emoji (required): string id (required): string name (required): string name (required): string note (required): string | null reminder (required): string | null Time of day on the when day, "HH:MM", or null for none. source (required): string | null starred (required): boolean updatedAt (required): string url (required): string when (required): string | null Calendar date, "YYYY-MM-DD", or null for Inbox. 400, 401, 403, 404, 415 400 The request is malformed or breaks a rule. 401 No valid credential. 403 The credential lacks the scope. 404 The list it names does not exist. 415 The body is not JSON. Content type: application/problem+json schema: Problem Problem details (RFC 9457). detail (required): string What went wrong this time, for people. Don't parse it. status (required): integer title (required): string Fixed for each type. Don't branch on it. type (required): string Names the problem: a type under https://taskaid.ai/problems/, or about:blank when the status says it all. Handle the types you recognise and fall back to the status for any other; ignore members you don't recognise. Get a task Method: GET Path: /api/v1/tasks/{id} Operation ID: getTask Tags: Tasks Effective servers / Authentication oauth2: OAuth 2.0: authorization code, authorize /oauth/authorize, token /oauth/token, refresh /oauth/token, scopes: read Or: apiKey: HTTP bearer, scopes: read An API key from Settings. Path parameters id (required): string Task reference, such as TASKAID-45 or 45. Responses 200 The task. Content type: application/json schema: Task completed (required): boolean completedAt (required): string | null duration (required): number | null id (required): string list (required): object | null emoji (required): string id (required): string name (required): string name (required): string note (required): string | null reminder (required): string | null Time of day on the when day, "HH:MM", or null for none. source (required): string | null starred (required): boolean updatedAt (required): string url (required): string when (required): string | null Calendar date, "YYYY-MM-DD", or null for Inbox. 400, 401, 403, 404 400 The request is malformed or breaks a rule. 401 No valid credential. 403 The credential lacks the scope. 404 The task does not exist. Content type: application/problem+json schema: Problem Problem details (RFC 9457). detail (required): string What went wrong this time, for people. Don't parse it. status (required): integer title (required): string Fixed for each type. Don't branch on it. type (required): string Names the problem: a type under https://taskaid.ai/problems/, or about:blank when the status says it all. Handle the types you recognise and fall back to the status for any other; ignore members you don't recognise. Update a task Method: PATCH Path: /api/v1/tasks/{id} Operation ID: updateTask Tags: Tasks Effective servers / Authentication oauth2: OAuth 2.0: authorization code, authorize /oauth/authorize, token /oauth/token, refresh /oauth/token, scopes: write Or: apiKey: HTTP bearer, scopes: write An API key from Settings. Path parameters id (required): string Task reference, such as TASKAID-45 or 45. Header parameters if-match: string The note as you last read it, as an entity tag: the SHA-256 of the note in hex, quoted ("…"). The write fails with 412 if the note has changed since. Request body Required: true Content type: application/json no additional properties completed: boolean Marks the task done. True stamps completedAt with the time of the call, never the time the work finished. duration: integer | null, minimum: 1, maximum: 1440 Estimated duration in minutes, up to a day. Null clears the estimate. listId: string | null Pass null to unlink the task from its list. name: string, minLength: 1, maxLength: 500 Required when creating. On update, omit to keep the current name. A few words naming the action; the day goes in when, the detail in note. note: string | null Task notes, as Markdown, up to 15,000 characters — rendered as rich text in the app. Headings, lists, bold, and inline code are supported. Send literal newlines and characters, not escape sequences. reminder: string | null, format: time A time of day for a reminder, "HH:MM" in 24-hour time (e.g. "15:00"), on the task's when day in the user's time zone. Moving the task moves it; null removes it. At that time Taskaid sends the task.reminded event to subscribed assistants. starred: boolean when: string | null The day the task is scheduled for, as "YYYY-MM-DD" (e.g. "2026-05-21"). Omit or pass null when creating to leave the task in Inbox; pass null when updating to move it back there. Responses 200 The updated task. Content type: application/json schema: Task completed (required): boolean completedAt (required): string | null duration (required): number | null id (required): string list (required): object | null emoji (required): string id (required): string name (required): string name (required): string note (required): string | null reminder (required): string | null Time of day on the when day, "HH:MM", or null for none. source (required): string | null starred (required): boolean updatedAt (required): string url (required): string when (required): string | null Calendar date, "YYYY-MM-DD", or null for Inbox. 400, 401, 403, 404, 415 400 The request is malformed or breaks a rule. 401 No valid credential. 403 The credential lacks the scope. 404 The task, or the list it moves to, does not exist. 415 The body is not JSON. Content type: application/problem+json schema: Problem Problem details (RFC 9457). detail (required): string What went wrong this time, for people. Don't parse it. status (required): integer title (required): string Fixed for each type. Don't branch on it. type (required): string Names the problem: a type under https://taskaid.ai/problems/, or about:blank when the status says it all. Handle the types you recognise and fall back to the status for any other; ignore members you don't recognise. 412 The note changed since it was read; nothing was written. Content type: application/problem+json schema: NoteChangedProblem The note changed since it was read. detail (required): string What went wrong this time, for people. Don't parse it. note (required): string | null The note as stored now. Nothing was written. status (required): integer title (required): string Fixed for each type. Don't branch on it. type (required): string, possible values: "https://taskaid.ai/problems/note-changed" Delete a task Method: DELETE Path: /api/v1/tasks/{id} Operation ID: deleteTask Tags: Tasks Effective servers / Authentication oauth2: OAuth 2.0: authorization code, authorize /oauth/authorize, token /oauth/token, refresh /oauth/token, scopes: write Or: apiKey: HTTP bearer, scopes: write An API key from Settings. Path parameters id (required): string Task reference, such as TASKAID-45 or 45. Responses 204 The task is deleted. 400, 401, 403, 404 400 The request is malformed or breaks a rule. 401 No valid credential. 403 The credential lacks the scope. 404 The task does not exist. Content type: application/problem+json schema: Problem Problem details (RFC 9457). detail (required): string What went wrong this time, for people. Don't parse it. status (required): integer title (required): string Fixed for each type. Don't branch on it. type (required): string Names the problem: a type under https://taskaid.ai/problems/, or about:blank when the status says it all. Handle the types you recognise and fall back to the status for any other; ignore members you don't recognise. Lists Lists group related tasks. A task is in one list, or none. List lists Method: GET Path: /api/v1/lists Operation ID: listLists Tags: Lists Every list, oldest first. Effective servers / Authentication oauth2: OAuth 2.0: authorization code, authorize /oauth/authorize, token /oauth/token, refresh /oauth/token, scopes: read Or: apiKey: HTTP bearer, scopes: read An API key from Settings. Responses 200 The lists. Content type: application/json lists (required): array of List 400, 401, 403 400 The request is malformed or breaks a rule. 401 No valid credential. 403 The credential lacks the scope. Content type: application/problem+json schema: Problem Problem details (RFC 9457). detail (required): string What went wrong this time, for people. Don't parse it. status (required): integer title (required): string Fixed for each type. Don't branch on it. type (required): string Names the problem: a type under https://taskaid.ai/problems/, or about:blank when the status says it all. Handle the types you recognise and fall back to the status for any other; ignore members you don't recognise. Create a list Method: POST Path: /api/v1/lists Operation ID: createList Tags: Lists Effective servers / Authentication oauth2: OAuth 2.0: authorization code, authorize /oauth/authorize, token /oauth/token, refresh /oauth/token, scopes: write Or: apiKey: HTTP bearer, scopes: write An API key from Settings. Request body Required: true Content type: application/json no additional properties name (required): string, minLength: 1, maxLength: 120 Required when creating. On update, omit to keep the current name. emoji: string, minLength: 1, maxLength: 8 A single emoji shown before the list name. Defaults to 📋 when creating; omit on update to keep the current one. note: string | null A note about the list, as Markdown, up to 500 characters: what it is for and how its tasks are handled. Replaces the whole note; null clears it. Responses 201 The created list. Headers: Location (required) Where the new resource can be read. string Where the new resource can be read. Content type: application/json schema: List emoji (required): string id (required): string name (required): string note (required): string | null 400, 401, 403, 415 400 The request is malformed or breaks a rule. 401 No valid credential. 403 The credential lacks the scope. 415 The body is not JSON. Content type: application/problem+json schema: Problem Problem details (RFC 9457). detail (required): string What went wrong this time, for people. Don't parse it. status (required): integer title (required): string Fixed for each type. Don't branch on it. type (required): string Names the problem: a type under https://taskaid.ai/problems/, or about:blank when the status says it all. Handle the types you recognise and fall back to the status for any other; ignore members you don't recognise. Get a list Method: GET Path: /api/v1/lists/{id} Operation ID: getList Tags: Lists Effective servers / Authentication oauth2: OAuth 2.0: authorization code, authorize /oauth/authorize, token /oauth/token, refresh /oauth/token, scopes: read Or: apiKey: HTTP bearer, scopes: read An API key from Settings. Path parameters id (required): string The list's id. Responses 200 The list. Content type: application/json schema: List emoji (required): string id (required): string name (required): string note (required): string | null 400, 401, 403, 404 400 The request is malformed or breaks a rule. 401 No valid credential. 403 The credential lacks the scope. 404 The list does not exist. Content type: application/problem+json schema: Problem Problem details (RFC 9457). detail (required): string What went wrong this time, for people. Don't parse it. status (required): integer title (required): string Fixed for each type. Don't branch on it. type (required): string Names the problem: a type under https://taskaid.ai/problems/, or about:blank when the status says it all. Handle the types you recognise and fall back to the status for any other; ignore members you don't recognise. Update a list Method: PATCH Path: /api/v1/lists/{id} Operation ID: updateList Tags: Lists Effective servers / Authentication oauth2: OAuth 2.0: authorization code, authorize /oauth/authorize, token /oauth/token, refresh /oauth/token, scopes: write Or: apiKey: HTTP bearer, scopes: write An API key from Settings. Path parameters id (required): string The list's id. Request body Required: true Content type: application/json no additional properties emoji: string, minLength: 1, maxLength: 8 A single emoji shown before the list name. Defaults to 📋 when creating; omit on update to keep the current one. name: string, minLength: 1, maxLength: 120 Required when creating. On update, omit to keep the current name. note: string | null A note about the list, as Markdown, up to 500 characters: what it is for and how its tasks are handled. Replaces the whole note; null clears it. Responses 200 The updated list. Content type: application/json schema: List emoji (required): string id (required): string name (required): string note (required): string | null 400, 401, 403, 404, 415 400 The request is malformed or breaks a rule. 401 No valid credential. 403 The credential lacks the scope. 404 The list does not exist. 415 The body is not JSON. Content type: application/problem+json schema: Problem Problem details (RFC 9457). detail (required): string What went wrong this time, for people. Don't parse it. status (required): integer title (required): string Fixed for each type. Don't branch on it. type (required): string Names the problem: a type under https://taskaid.ai/problems/, or about:blank when the status says it all. Handle the types you recognise and fall back to the status for any other; ignore members you don't recognise. Delete a list Method: DELETE Path: /api/v1/lists/{id} Operation ID: deleteList Tags: Lists Its tasks stay, no longer in any list. Effective servers / Authentication oauth2: OAuth 2.0: authorization code, authorize /oauth/authorize, token /oauth/token, refresh /oauth/token, scopes: write Or: apiKey: HTTP bearer, scopes: write An API key from Settings. Path parameters id (required): string The list's id. Responses 204 The list is deleted. 400, 401, 403, 404 400 The request is malformed or breaks a rule. 401 No valid credential. 403 The credential lacks the scope. 404 The list does not exist. Content type: application/problem+json schema: Problem Problem details (RFC 9457). detail (required): string What went wrong this time, for people. Don't parse it. status (required): integer title (required): string Fixed for each type. Don't branch on it. type (required): string Names the problem: a type under https://taskaid.ai/problems/, or about:blank when the status says it all. Handle the types you recognise and fall back to the status for any other; ignore members you don't recognise. Plans One short plan per day: what to tackle, in what order, and where to start. Get a day's plan Method: GET Path: /api/v1/plans/{date} Operation ID: getPlan Tags: Plans Effective servers / Authentication oauth2: OAuth 2.0: authorization code, authorize /oauth/authorize, token /oauth/token, refresh /oauth/token, scopes: read Or: apiKey: HTTP bearer, scopes: read An API key from Settings. Path parameters date (required): string, format: date The plan's day, as "YYYY-MM-DD". Responses 200 The day's plan. Content type: application/json schema: Plan content (required): string date (required): string Calendar date, "YYYY-MM-DD". id (required): string title (required): string | null url (required): string 400, 401, 403, 404 400 The request is malformed or breaks a rule. 401 No valid credential. 403 The credential lacks the scope. 404 The day has no plan. Content type: application/problem+json schema: Problem Problem details (RFC 9457). detail (required): string What went wrong this time, for people. Don't parse it. status (required): integer title (required): string Fixed for each type. Don't branch on it. type (required): string Names the problem: a type under https://taskaid.ai/problems/, or about:blank when the status says it all. Handle the types you recognise and fall back to the status for any other; ignore members you don't recognise. Create or replace a day's plan Method: PUT Path: /api/v1/plans/{date} Operation ID: savePlan Tags: Plans Writes the day's whole plan. A title left out is cleared, as with any field PUT replaces. Effective servers / Authentication oauth2: OAuth 2.0: authorization code, authorize /oauth/authorize, token /oauth/token, refresh /oauth/token, scopes: write Or: apiKey: HTTP bearer, scopes: write An API key from Settings. Path parameters date (required): string, format: date The plan's day, as "YYYY-MM-DD". Request body Required: true Content type: application/json no additional properties content (required): string, minLength: 1, maxLength: 5000 The whole day's plan, as Markdown. title: string | null, minLength: 1, maxLength: 120 A few words naming what the day is for. Left out or null, the plan has no title. Responses 200 The plan, replaced. Content type: application/json schema: Plan content (required): string date (required): string Calendar date, "YYYY-MM-DD". id (required): string title (required): string | null url (required): string 201 The plan, created. Headers: Location (required) Where the new resource can be read. string Where the new resource can be read. Content type: application/json Schema Plan is shown above. 400, 401, 403, 415 400 The request is malformed or breaks a rule. 401 No valid credential. 403 The credential lacks the scope. 415 The body is not JSON. Content type: application/problem+json schema: Problem Problem details (RFC 9457). detail (required): string What went wrong this time, for people. Don't parse it. status (required): integer title (required): string Fixed for each type. Don't branch on it. type (required): string Names the problem: a type under https://taskaid.ai/problems/, or about:blank when the status says it all. Handle the types you recognise and fall back to the status for any other; ignore members you don't recognise.