init.Tasks openapi.json inittasks.com

10 routes

/attachments

10 routes.

Links, text and files. One attachment can be in SEVERAL places at once, any mix of to-dos, containers (an area, a project or a subproject) and notes: one stored file, never a copy. Its first place is its PRIMARY (parentType / parentId); places lists them all. Attachments carry tags. The API creates url and text attachments, uploads files and pictures (POST /attachments/upload: the file as the raw body up to 100 MB, or base64 in JSON up to about 3 MB), and reads the decrypted bytes of any file at GET /attachments/{id}/file. An image or file added in an app before its upload finished reads pending: true until that device uploads it. Deleting an attachment deletes its stored file.

GET /v1/attachments

List attachments

Every attachment once, in (sortKey, id) order. ?parent_id= lists the attachments IN one place (a to-do, a container or a note), whether it is their primary place or not, in that place’s own order. ?tag= keeps the ones carrying a tag (repeat it for several).

Scopes: attachments:read

Query

parameter type notes
limit integer optional min 1, max 200
cursor string optional max 4096 chars
updated_since string (RFC 3339) optional max 24 chars. An RFC 3339 instant, e.g. 2026-09-16T08:30:00.000Z.
parent_id string optional max 64 chars. Only the attachments IN this place (a to-do, container or note), primary or not, in THAT place’s order (each place keeps its own).
tag string or array of string optional max 64 chars, min 1. Only attachments carrying this tag (by name). Repeat it to require several.

Response

Errors: grant_expired * grant_revoked * unauthorized * forbidden_scope * account_too_large * validation_failed * rate_limited * internal

POST /v1/attachments

Create a url or text attachment

url and text here. A file or a picture is uploaded with POST /attachments/upload. note was an attachment kind once and is not one any more: a note is a row of its own, created with POST /notes. The new attachment goes at the end of its parent’s list. tags are names; a new name creates the tag.

Scopes: attachments:write Idempotent. Send Idempotency-Key and a retry replays the first answer instead of writing twice.

Request body

field type notes
parentType todo, container, note required What the attachment hangs off: a to-do, a container (an area, a project or a subproject), or a note (the note’s own attachments).
parentId string required max 64 chars, min 1. The to-do, container or note. It must exist and not be trashed, or the create is validation_failed at /parentId.
kind url, text required
url string (uri) optional or null, max 2048 chars, min 1. An absolute http:// or https:// URL. Other schemes (javascript:, file:, data:) are refused.
text string optional or null, max 2048 chars
title string optional or null, max 512 chars
id string (UPPERCASE UUID) optional max 64 chars. An uppercase UUID, all 36 characters, hex digits in capitals: 8E4F2A1B-7C3D-4E5F-9A0B-1C2D3E4F5A6B. Supplying one is how a create is made idempotent; a repeat is 409 duplicate_id. Lower case is refused, and so is a short id.
tags array of string optional max 64 items

Response

Errors: grant_expired * grant_revoked * unauthorized * forbidden_scope * conflict * duplicate_id * payload_too_large * unsupported_media_type * account_too_large * validation_failed * rate_limited * internal

GET /v1/attachments/{id}

One attachment

Scopes: attachments:read

Response

Errors: grant_expired * grant_revoked * unauthorized * forbidden_scope * not_found * account_too_large * rate_limited * internal

GET /v1/attachments/{id}/file

The decrypted bytes of a file attachment

The one place the server hands out plaintext bytes. The blob is decrypted server-side on your behalf, because a REST caller holds no key. A revoked grant therefore stops being able to read it, which is exactly why the wrapped file key is never returned alongside. 404 when the attachment has no stored file (a url or text row; a link’s stored site icon is not served here), when an image or file has not been uploaded yet (pending: true: its bytes are still on the device that added it), when the object is gone, or when it will not authenticate. To store a new file, use POST /attachments/upload.

Scopes: attachments:read

Response

Errors: grant_expired * grant_revoked * unauthorized * forbidden_scope * not_found * account_too_large * rate_limited * internal

PATCH /v1/attachments/{id}

Change an attachment

The content fields: title, url, text, and tags (the whole set, by name). kind is fixed at creation. Places change through /attachments/{id}/places; the stored order in one place through /attachments/{id}/reorder.

Scopes: attachments:write

Request body

field type notes
title string optional or null, which clears it, max 512 chars
url string (uri) optional max 2048 chars, min 1. An absolute http:// or https:// URL. Other schemes (javascript:, file:, data:) are refused.
text string optional or null, which clears it, max 2048 chars
tags array of string optional or null, which clears it, max 64 items

Response

Errors: grant_expired * grant_revoked * unauthorized * forbidden_scope * not_found * payload_too_large * unsupported_media_type * account_too_large * validation_failed * rate_limited * internal

DELETE /v1/attachments/{id}

Delete an attachment

Irreversible, and from EVERY place it is in. The stored file goes with the row: an image or file attachment’s encrypted bytes and thumbnail, or a link’s stored site icon, are deleted from storage too. To take it out of one place only, use DELETE /attachments/{id}/places/{parentId}.

Scopes: attachments:write

Response

Errors: grant_expired * grant_revoked * unauthorized * forbidden_scope * not_found * account_too_large * rate_limited * internal

POST /v1/attachments/{id}/places

Attach it to another place too

The apps’ attach to…: the SAME attachment (one stored file, never a copy) also shows in that to-do, container or note, at the end of its list. A place it already has changes nothing and answers 200.

Scopes: attachments:write Idempotent. Send Idempotency-Key and a retry replays the first answer instead of writing twice.

Request body

field type notes
parentType todo, container, note required What the new place is: a to-do, a container (an area, a project or a subproject) or a note.
parentId string required max 64 chars, min 1. It must exist and not be trashed.
id string (UPPERCASE UUID) optional max 64 chars. An id for the new place row (an uppercase UUID); omit it and the server issues one.

Response

Errors: grant_expired * grant_revoked * unauthorized * forbidden_scope * not_found * conflict * duplicate_id * payload_too_large * unsupported_media_type * account_too_large * validation_failed * rate_limited * internal

DELETE /v1/attachments/{id}/places/{parentId}

Take it out of one place

The apps’ detach. Another place: it leaves that place only. Its PRIMARY place while it has others: the oldest other place becomes the primary. Its LAST place: it becomes an INBOX item holding the same file, link or text (its tags stay behind), and the attachment row goes; that case needs inbox:write too. An image or file that has not been uploaded yet cannot leave its last place from here (conflict): its bytes are on the device that added it. parentId is the to-do, container or note.

Scopes: attachments:write

Response

Errors: grant_expired * grant_revoked * unauthorized * forbidden_scope * not_found * conflict * account_too_large * rate_limited * internal

POST /v1/attachments/{id}/reorder

Reorder it within one place

Each place keeps its own order, so this moves it in parentId’s list only (the apps’ move up / move down). Name a neighbour with after / before, or send step.

Scopes: attachments:write

Request body

field type notes
parentId string required max 64 chars, min 1. The place whose list to reorder (one of the attachment’s places). Each place keeps its own order.
after string optional or null, max 64 chars. Right after this attachment of the same place, or null for first.
before string optional max 64 chars. Right before this attachment of the same place.
step up, down optional One step up or down the list (the apps’ move up / move down). Not with after or before.

Response

Errors: grant_expired * grant_revoked * unauthorized * forbidden_scope * not_found * payload_too_large * unsupported_media_type * account_too_large * validation_failed * rate_limited * internal

POST /v1/attachments/upload

Upload a file or a picture

The apps’ attach… > file and picture, in two forms. Raw: the file is the body, and parent_type, parent_id and name go in the query; up to 100 MB, the apps’ own limit. JSON: the bytes base64 in content, with the filename in name; a JSON body is capped at 4 MB, so about 3 MB of file. Either way the server seals the bytes under a fresh key for this file, stores them as the user, and creates the attachment with its file in one write. An image/* type makes a picture, anything else a file. The server makes no thumbnail: the JSON form takes thumbnail (a JPEG of at most 256 px and 64 KB) for the preview the apps show in lists. A file over 100 MB is refused before it is read, and so is one that would take the account past its 10 GB (payload_too_large).

Scopes: attachments:write Idempotent. Send Idempotency-Key and a retry replays the first answer instead of writing twice.

Request body

field type notes
parentType todo, container, note required Where it goes first: a to-do, a container (an area, a project or a subproject) or a note.
parentId string required max 64 chars, min 1. It must exist and not be trashed.
name string required max 512 chars, min 1. The filename, WITH its extension (invoice.pdf): it is the attachment’s title, and the extension is how the apps name its type.
mime string optional max 128 chars. The media type (application/pdf, image/png). Omitted: taken from the extension, else application/octet-stream. An image/* type makes a picture (kind: "image"), anything else a file.
content string required pattern ^[A-Za-z0-9+/]*={0,2}$. The file’s bytes, base64. A JSON request body is capped at 4 MB, so about 3 MB is the largest file this form takes. Send a bigger one (up to 100 MB) as the raw body instead.
thumbnail string optional pattern ^[A-Za-z0-9+/]*={0,2}$. Optional: a preview the apps show in lists, a JPEG of at most 256 px on its longest side and 64 KB, base64. Without one a picture shows its name until it is opened.
tags array of string optional max 64 items
id string (UPPERCASE UUID) optional max 64 chars. An uppercase UUID, all 36 characters, hex digits in capitals: 8E4F2A1B-7C3D-4E5F-9A0B-1C2D3E4F5A6B. Supplying one is how a create is made idempotent; a repeat is 409 duplicate_id. Lower case is refused, and so is a short id.

Or a raw body: The file itself, as the whole body, with its Content-Length. Any Content-Type but application/json: the file’s own type, or application/octet-stream. Up to 100 MB. The query below says what the file is.

Query

parameter type notes
parent_type todo, container, note optional Raw body only (required there): todo, container (an area, project or subproject) or note.
parent_id string optional max 64 chars, min 1. Raw body only (required there): the place. It must exist and not be trashed.
name string optional max 512 chars, min 1. Raw body only (required there): the filename, WITH its extension.
mime string optional max 128 chars. Raw body only: the media type. Omitted: the request’s Content-Type unless that is application/octet-stream, else the extension.
tag string or array of string optional max 64 chars, min 1, max 64 items. Raw body only: a tag to put on it, by name. Repeat it for several.
id string (UPPERCASE UUID) optional max 64 chars. An uppercase UUID, all 36 characters, hex digits in capitals: 8E4F2A1B-7C3D-4E5F-9A0B-1C2D3E4F5A6B. Supplying one is how a create is made idempotent; a repeat is 409 duplicate_id. Lower case is refused, and so is a short id.

Response

Errors: grant_expired * grant_revoked * unauthorized * forbidden_scope * conflict * duplicate_id * payload_too_large * unsupported_media_type * account_too_large * validation_failed * rate_limited * internal