init.Tasks openapi.json inittasks.com

7 routes

/tags

7 routes.

Free-form labels on to-dos, attachments and notes. A tag is identified by its NAME, and the row id is derived from it, so creating one twice is not an error, and a RENAME moves the tag to the new name’s id: every to-do, filter, attachment and note that used it is rewritten and the old id forwards (GET /tags/{oldId} answers 308).

GET /v1/tags

List tags

The live tags. A tag in the trash is left out unless include_trashed=true (then it carries its trashedAt). A forwarding id a rename left behind is never listed.

Scopes: tags: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.
include_trashed true, false optional

Response

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

POST /v1/tags

Create a tag, or return the existing one

A tag is identified by its NAME, and its row id is a hash of it, so creating one twice is not a conflict. The name is normalised to lower case with runs of whitespace collapsed before the comparison. A tag of that name in the TRASH is that row: it comes back out of the trash (its colour and place kept, a colorHex sent now wins), and every to-do still carrying the name shows it again.

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

Request body

field type notes
name string required max 64 chars, min 1
colorHex string optional or null, 6-digit hex, with or without the #, max 16 chars. A 6-digit hex colour, with or without the leading #: #3A7BD5 or 3A7BD5. Three-digit shorthand is refused.

Response

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

GET /v1/tags/{id}

Get a tag (a renamed tag’s old id redirects to it)

A live tag answers 200. A tag id that a RENAME left behind answers 308 Permanent Redirect with Location: /v1/tags/{newId} and the tag it now resolves to as the body, so a client that does not follow redirects still gets the current tag. An old id whose chain cannot be resolved answers 404.

Scopes: tags:read

Response

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

PATCH /v1/tags/{id}

Rename, merge or recolour a tag

name RENAMES the tag. A tag’s id is derived from its name, so a rename MOVES the tag to the new name’s id: every to-do, filter, attachment and note that used it is rewritten, the response is the tag at its NEW id, and the old id keeps working as a forwarding pointer (GET /tags/{oldId} answers 308). A change of case only (Bug → bug) is the same tag and changes nothing. Renaming onto a name another tag already has is a MERGE: it answers 409 tag_exists unless the body says "merge": true; a merge keeps the existing tag’s colour, and to-dos that carried both keep one. colorHex alone recolours. after (a tag id, or null for first) or before reorders the tag list. An id that a rename left behind answers 404 here; only GET follows it.

Scopes: tags:write

Request body

field type notes
name string optional max 64 chars, min 1
merge boolean optional
colorHex string optional or null, which clears it, 6-digit hex, with or without the #, max 16 chars. A 6-digit hex colour, with or without the leading #: #3A7BD5 or 3A7BD5. Three-digit shorthand is refused.
after string optional or null, which clears it, max 64 chars. Reorder the tag list: right after this tag, or null for first.
before string optional max 64 chars. Reorder the tag list: right before this tag.

Response

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

POST /v1/tags/{id}/trash

Move a tag to the trash

One write: the tag is stamped trashedAt. Nothing else changes: its to-dos, notes and attachments KEEP its name and filters keep their criteria, so /restore brings everything back. While it is in the trash the apps hide it from every list, picker and pill, GET /tags leaves it out, and a filter criterion naming it matches nothing. The trash deletes it for good after 30 days (or DELETE /trash). Already in the trash: no change.

Scopes: tags:write

Response

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

POST /v1/tags/{id}/restore

Restore a tag from the trash

Scopes: tags:write

Response

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

DELETE /v1/tags/{id}

Delete a tag and remove it from every to-do, attachment and note

Irreversible, live or in the trash (the apps’ delete moves a tag to the trash: POST /tags/{id}/trash). Removes the tag from every to-do, attachment and note, and retires every old id that forwarded to it. A filter never changes what it matches because of a delete: a criterion that names the tag is removed only where that is exactly equivalent, and otherwise stays, reading back as the deleted tag’s raw tg_ id (a filter that required the tag now matches nothing). An id that a rename left behind answers 404.

Scopes: tags:write

Response

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