# Objects

The 45 objects the API returns, generated from the same `components.schemas` that [openapi.json](https://api.inittasks.com/openapi.json) publishes. Every field is listed, with its type, whether it can be `null`, its allowed values where it has a fixed set, and whether the server derives it or the encryption covers it.

## How a list is shaped

Every paged list answers with the same two fields.

```json
{ "data": [], "next_cursor": null }
```

`next_cursor` is an opaque string while more pages remain and `null` on the last one. It is present on every paged list. One list is not paged and omits the key entirely: `GET /v1/webhooks`. See [keeping a copy in sync](/sync) for what a walk does and does not guarantee.

## Two properties worth reading first

- **Server-derived** fields are written by the server. Sending one in a request body is [validation_failed](/errors/validation_failed), because request bodies reject unknown fields.
- **Encrypted** fields are ciphertext at rest. The server holds the key for the life of your request and no longer. See [encryption](/encryption).

## The objects

[AccessKey](#accesskey) * [AccessKeyCreated](#accesskeycreated) * [AccessKeyList](#accesskeylist) * [AnytimeView](#anytimeview) * [Attachment](#attachment) * [AttachmentList](#attachmentlist) * [Container](#container) * [ContainerList](#containerlist) * [DayBucket](#daybucket) * [Delivery](#delivery) * [DeliveryList](#deliverylist) * [Event](#event) * [Filter](#filter) * [FilterList](#filterlist) * [Grant](#grant) * [GrantList](#grantlist) * [InboxAttached](#inboxattached) * [InboxBecameTodo](#inboxbecametodo) * [InboxItem](#inboxitem) * [InboxList](#inboxlist) * [InboxMoved](#inboxmoved) * [LogbookView](#logbookview) * [Me](#me) * [OverviewView](#overviewview) * [PingQueued](#pingqueued) * [Problem](#problem) * [RedeliveryQueued](#redeliveryqueued) * [SearchHit](#searchhit) * [SearchResult](#searchresult) * [Session](#session) * [SessionList](#sessionlist) * [Settings](#settings) * [SomedayView](#somedayview) * [Tag](#tag) * [TagList](#taglist) * [TodayView](#todayview) * [Todo](#todo) * [TodoList](#todolist) * [TrashEmptied](#trashemptied) * [TrashList](#trashlist) * [UpcomingView](#upcomingview) * [Webhook](#webhook) * [WebhookCreated](#webhookcreated) * [WebhookList](#webhooklist) * [WebhookRotated](#webhookrotated)

## AccessKey

| field | type | | notes |
|---|---|---|---|
| `id` | string | always present |  |
| `name` | string | always present | may be null. The name the user gave this credential. end-to-end encrypted at rest; the server holds the key only for the life of this request. `null` when the caller holds no key to decrypt it; see `name_encrypted`. |
| `name_encrypted` | string | optional | Present ONLY when the server could not decrypt `name`, because a first-party app session carries no master key here, and the apps decrypt this envelope on the device. ⚠ Never rendered as text: it is `v1.<nonce>.<ciphertext>`. |
| `scopes` | array of string | always present |  |
| `createdAt` | string (RFC 3339) | always present | **server-derived** |
| `expiresAt` | string (RFC 3339) | always present | When this credential stops working. Expiry is mandatory; there is no “never”. |
| `lastUsedAt` | string (RFC 3339) | always present | may be null. **server-derived**. Server-derived, written at most once every 15 minutes per credential. `null` = never used. |
| `tokenPrefix` | string | always present | may be null. The last few characters of the token, so a user can tell two keys apart. The secret itself is returned exactly once, at creation. |

## AccessKeyCreated

| field | type | | notes |
|---|---|---|---|
| `id` | string | always present |  |
| `name` | string | always present | may be null. The name the user gave this credential. end-to-end encrypted at rest; the server holds the key only for the life of this request. `null` when the caller holds no key to decrypt it; see `name_encrypted`. |
| `name_encrypted` | string | optional | Present ONLY when the server could not decrypt `name`, because a first-party app session carries no master key here, and the apps decrypt this envelope on the device. ⚠ Never rendered as text: it is `v1.<nonce>.<ciphertext>`. |
| `scopes` | array of string | always present |  |
| `createdAt` | string (RFC 3339) | always present | **server-derived** |
| `expiresAt` | string (RFC 3339) | always present | When this credential stops working. Expiry is mandatory; there is no “never”. |
| `lastUsedAt` | string (RFC 3339) | always present | may be null. **server-derived**. Server-derived, written at most once every 15 minutes per credential. `null` = never used. |
| `tokenPrefix` | string | always present | may be null |
| `key` | string | always present | The secret, `itk_…`, returned exactly once and never again. Store it now; a lost key is re-minted, not recovered. |

## AccessKeyList

| field | type | | notes |
|---|---|---|---|
| `data` | array of [AccessKey](/objects#accesskey) | always present |  |
| `next_cursor` | string | always present | may be null. Opaque. Hand it back as `?cursor=` for the next page; `null` means this was the last page. Never construct or store one; it encodes `(orderKey, id)` of the last row and is only meaningful against the list that issued it. |

## AnytimeView

| field | type | | notes |
|---|---|---|---|
| `anytime` | array of string | always present | Open, non-trashed, undated to-dos in tree order (standalone last). A deadline alone still leaves a to-do here. |

## Attachment

| field | type | | notes |
|---|---|---|---|
| `id` | string | always present | The attachment id. Client-supplied at create, else an uppercase UUID the server issues. |
| `createdAt` | string (RFC 3339) | always present | **server-derived**. RFC 3339; the row’s creation instant as Appwrite stamped it (`$createdAt`). |
| `updatedAt` | string (RFC 3339) | always present | **server-derived**. RFC 3339; the instant the SERVER last wrote the row (`$updatedAt`). This is the field `?updated_since=` compares against. It is never the client-stamped `updatedAt` column, which the sync rules forbid. |
| `parentType` | string | always present | One of `todo`, `container`, `inbox` today. What the attachment hangs off. Clients must render an unknown value generically rather than fail, so do not generate a closed union from this field. |
| `parentId` | string | always present | The row the attachment hangs off; read `parentType` to know which table. |
| `kind` | string | always present | One of `url`, `text`, `note`, `image`, `file` today. Only `url`, `text` and `note` can be created over the API (there is no upload endpoint in v1), but `image` and `file` rows made by the apps ARE readable, and their bytes come from `GET /attachments/{id}/file`. Clients must render an unknown value generically rather than fail, so do not generate a closed union from this field. |
| `url` | string | always present | may be null. The link (`kind: "url"`). end-to-end encrypted at rest; the server holds the key only for the life of this request. |
| `text` | string | always present | may be null. The body (`kind: "text"` or `"note"`). end-to-end encrypted at rest; the server holds the key only for the life of this request. |
| `title` | string | always present | may be null. A heading, or the filename of an image/file. end-to-end encrypted at rest; the server holds the key only for the life of this request. |
| `mime` | string | always present | may be null. The media type of the stored bytes. end-to-end encrypted at rest; the server holds the key only for the life of this request. |
| `sizeBytes` | integer | always present | may be null. min -9007199254740991, max 9007199254740991. The byte size of the stored bytes. end-to-end encrypted at rest; the server holds the key only for the life of this request. |
| `sortKey` | string | always present | Server-issued fractional ordering key. The stated order of every content list is `(sortKey, id)`. Opaque: compare it, never compute one. |
| `fileId` | string | always present | may be null. **server-derived**. Non-null exactly when `GET /attachments/{id}/file` can return bytes. ⚠ The wrapped file key is NEVER returned; the server decrypts on your behalf instead, so a revoked grant stops being able to read the blob. |

## AttachmentList

| field | type | | notes |
|---|---|---|---|
| `data` | array of [Attachment](/objects#attachment) | always present |  |
| `next_cursor` | string | always present | may be null. Opaque. Hand it back as `?cursor=` for the next page; `null` means this was the last page. Never construct or store one; it encodes `(orderKey, id)` of the last row and is only meaningful against the list that issued it. |

## Container

| field | type | | notes |
|---|---|---|---|
| `id` | string | always present | The container id. Client-supplied at create, else an uppercase UUID the server issues. |
| `createdAt` | string (RFC 3339) | always present | **server-derived**. RFC 3339; the row’s creation instant as Appwrite stamped it (`$createdAt`). |
| `updatedAt` | string (RFC 3339) | always present | **server-derived**. RFC 3339; the instant the SERVER last wrote the row (`$updatedAt`). This is the field `?updated_since=` compares against. It is never the client-stamped `updatedAt` column, which the sync rules forbid. |
| `kind` | `area`, `project`, `subproject` | always present |  |
| `name` | string | always present | The container name. end-to-end encrypted at rest; the server holds the key only for the life of this request. |
| `parentId` | string | always present | may be null. The parent container, or `null` for a root area. Changed with `/move`, never with `PATCH`. |
| `subtitle` | string | always present | may be null. A one-line subtitle. end-to-end encrypted at rest; the server holds the key only for the life of this request. |
| `notes` | string | always present | may be null. Free-form notes, up to 100,000 characters. end-to-end encrypted at rest; the server holds the key only for the life of this request. |
| `symbol` | string | always present | may be null. The icon name the apps render. end-to-end encrypted at rest; the server holds the key only for the life of this request. |
| `colorHex` | string | always present | may be null. A 6-digit hex colour, with or without the leading `#`. end-to-end encrypted at rest; the server holds the key only for the life of this request. |
| `deadline` | string (yyyy-MM-dd) | always present | may be null. `yyyy-MM-dd`. A hard due date. A deadline alone does not schedule the container. |
| `priority` | `low`, `medium`, `high` | always present | may be null. Display-only; it never affects ordering or counts. |
| `status` | `active`, `archived` | always present |  |
| `sortKey` | string | always present | Server-issued fractional ordering key. The stated order of every content list is `(sortKey, id)`. Opaque: compare it, never compute one. |
| `trashedAt` | string (RFC 3339) | always present | may be null. **server-derived**. Set by `/trash`, cleared by `/restore`; `null` means the row is live. |

## ContainerList

| field | type | | notes |
|---|---|---|---|
| `data` | array of [Container](/objects#container) | always present |  |
| `next_cursor` | string | always present | may be null. Opaque. Hand it back as `?cursor=` for the next page; `null` means this was the last page. Never construct or store one; it encodes `(orderKey, id)` of the last row and is only meaningful against the list that issued it. |

## DayBucket

| field | type | | notes |
|---|---|---|---|
| `date` | string (yyyy-MM-dd) | always present | `yyyy-MM-dd`. The bucket’s local calendar day. |
| `items` | array of string | always present | To-do ids in the bucket, in display order. |

## Delivery

| field | type | | notes |
|---|---|---|---|
| `id` | string | always present | This ATTEMPT. A redelivery is a new id carrying the same `eventId`. |
| `eventId` | string | always present | The event. STABLE across redeliveries, so de-duplicate on this, never on `id`. |
| `event` | string | always present | The event type, e.g. `todo.updated`. |
| `status` | `pending`, `delivered`, `failed` | always present |  |
| `attempts` | integer | always present | min -9007199254740991, max 9007199254740991 |
| `responseStatus` | integer | always present | may be null. min -9007199254740991, max 9007199254740991. The HTTP status the subscriber answered with, or `null` if it never answered. |
| `error` | string | always present | may be null. Why the last attempt failed: a refused address, a timeout, a non-2xx. |
| `createdAt` | string (RFC 3339) | always present | **server-derived**. When the attempt was queued. |
| `deliveredAt` | string (RFC 3339) | always present | may be null. When the subscriber accepted it; `null` until then. |
| `nextAttemptAt` | string (RFC 3339) | always present | may be null. When the retry ladder will try again; `null` when there is no further attempt. |

## DeliveryList

| field | type | | notes |
|---|---|---|---|
| `data` | array of [Delivery](/objects#delivery) | always present |  |
| `next_cursor` | string | always present | may be null. Opaque. Hand it back as `?cursor=` for the next page; `null` means this was the last page. Never construct or store one; it encodes `(orderKey, id)` of the last row and is only meaningful against the list that issued it. |

## Event

| field | type | | notes |
|---|---|---|---|
| `id` | string | always present | `evt_…`. De-duplicate on this. |
| `type` | string | always present |  |
| `occurredAt` | string (RFC 3339) | always present | **server-derived** |
| `data` | object | always present | ⚠ A THIN payload: the ids only, never row content. The server would have to decrypt an account to fill one, and a webhook body is the one place the plaintext would leave our control permanently. Fetch the row over the API if you need it. |

## Filter

| field | type | | notes |
|---|---|---|---|
| `id` | string | always present | The filter id. Client-supplied at create, else an uppercase UUID the server issues. |
| `createdAt` | string (RFC 3339) | always present | **server-derived**. RFC 3339; the row’s creation instant as Appwrite stamped it (`$createdAt`). |
| `updatedAt` | string (RFC 3339) | always present | **server-derived**. RFC 3339; the instant the SERVER last wrote the row (`$updatedAt`). This is the field `?updated_since=` compares against. It is never the client-stamped `updatedAt` column, which the sync rules forbid. |
| `name` | string | always present | The filter name. end-to-end encrypted at rest; the server holds the key only for the life of this request. |
| `criteria` | string | always present | The criteria as a JSON string, with tag names (the write path seals the tag clauses to blind ids). An unparseable or unknown criterion makes the filter INERT: it matches nothing rather than erroring. end-to-end encrypted at rest; the server holds the key only for the life of this request. |
| `symbol` | string | always present | may be null. The icon name the apps render. end-to-end encrypted at rest; the server holds the key only for the life of this request. |
| `sortKey` | string | always present | Server-issued fractional ordering key. The stated order of every content list is `(sortKey, id)`. Opaque: compare it, never compute one. |

## FilterList

| field | type | | notes |
|---|---|---|---|
| `data` | array of [Filter](/objects#filter) | always present |  |
| `next_cursor` | string | always present | may be null. Opaque. Hand it back as `?cursor=` for the next page; `null` means this was the last page. Never construct or store one; it encodes `(orderKey, id)` of the last row and is only meaningful against the list that issued it. |

## Grant

| field | type | | notes |
|---|---|---|---|
| `id` | string | always present |  |
| `name` | string | always present | may be null. The name the user gave this credential. end-to-end encrypted at rest; the server holds the key only for the life of this request. `null` when the caller holds no key to decrypt it; see `name_encrypted`. |
| `name_encrypted` | string | optional | Present ONLY when the server could not decrypt `name`, because a first-party app session carries no master key here, and the apps decrypt this envelope on the device. ⚠ Never rendered as text: it is `v1.<nonce>.<ciphertext>`. |
| `scopes` | array of string | always present |  |
| `createdAt` | string (RFC 3339) | always present | **server-derived** |
| `expiresAt` | string (RFC 3339) | always present | When this credential stops working. Expiry is mandatory; there is no “never”. |
| `lastUsedAt` | string (RFC 3339) | always present | may be null. **server-derived**. Server-derived, written at most once every 15 minutes per credential. `null` = never used. |
| `clientId` | string | always present | may be null |
| `redirectHost` | string | always present | may be null. The REAL callback host: `localhost`, `127.0.0.1`, `claude.ai`. Shown so a user can tell two connections of the same app apart. |
| `known` | boolean | always present | Whether this client is one the server recognises by name rather than only by registration. |
| `localProgram` | boolean | always present | Derived from `redirectHost`: the grant belongs to a program running on the user’s own computer. |

## GrantList

| field | type | | notes |
|---|---|---|---|
| `data` | array of [Grant](/objects#grant) | always present |  |
| `next_cursor` | string | always present | may be null. Opaque. Hand it back as `?cursor=` for the next page; `null` means this was the last page. Never construct or store one; it encodes `(orderKey, id)` of the last row and is only meaningful against the list that issued it. |

## InboxAttached

| field | type | | notes |
|---|---|---|---|
| `todo` | null | always present | may be null. Always `null` here, because the capture ATTACHED to the target instead of becoming a to-do. |
| `attachmentId` | string | always present | may be null. The attachment that was created on the target. |
| `status` | string | always present | One of `moved`, `attached` today. The capture row’s new status. Clients must render an unknown value generically rather than fail, so do not generate a closed union from this field. |

## InboxBecameTodo

| field | type | | notes |
|---|---|---|---|
| `todo` | [Todo](/objects#todo) | always present |  |

## InboxItem

| field | type | | notes |
|---|---|---|---|
| `id` | string | always present | The capture-row id. Client-supplied at create, else an uppercase UUID the server issues. |
| `createdAt` | string (RFC 3339) | always present | **server-derived**. RFC 3339; the row’s creation instant as Appwrite stamped it (`$createdAt`). |
| `updatedAt` | string (RFC 3339) | always present | **server-derived**. RFC 3339; the instant the SERVER last wrote the row (`$updatedAt`). This is the field `?updated_since=` compares against. It is never the client-stamped `updatedAt` column, which the sync rules forbid. |
| `kind` | string | always present | One of `text`, `url`, `image`, `file`, `note` today. Only `text` and `url` can be created over the API; `image` and `file` rows come from the apps’ share sheet and `note` from “new note”. Clients must render an unknown value generically rather than fail, so do not generate a closed union from this field. |
| `status` | `open`, `moved`, `attached`, `archived`, `someday` | always present | **server-derived**. `moved` and `attached` are set by `/move`; `archived` by `/archive`; `someday` by `/someday`. There is no delete for a capture row; archiving is the delete. |
| `text` | string | always present | may be null. The captured text (`kind: "text"`, and the body of a note). end-to-end encrypted at rest; the server holds the key only for the life of this request. |
| `url` | string | always present | may be null. The captured URL (`kind: "url"`). end-to-end encrypted at rest; the server holds the key only for the life of this request. |
| `title` | string | always present | may be null. The page title the API fetched for a URL, or the filename/caption of an image or file. `null` until it is fetched; render the URL’s host and path meanwhile. end-to-end encrypted at rest; the server holds the key only for the life of this request. |
| `whenDate` | string (yyyy-MM-dd) | always present | may be null. `yyyy-MM-dd`. The date quick-add parsed out of the capture; it rides onto the to-do a `/move` creates. |
| `capturedAt` | string (RFC 3339) | always present | may be null. When the item was captured. This is the apps’ own stamp, which may predate `createdAt` for an offline capture. |
| `movedTodoId` | string | always present | may be null. **server-derived**. The to-do `/move` created from this item, so a client can follow or undo it. |
| `sortKey` | string | always present | Server-issued fractional ordering key. The stated order of every content list is `(sortKey, id)`. Opaque: compare it, never compute one. |
| `mime` | string | always present | may be null. The media type of an `image`/`file` capture. end-to-end encrypted at rest; the server holds the key only for the life of this request. |
| `sizeBytes` | integer | always present | may be null. min -9007199254740991, max 9007199254740991. The byte size of an `image`/`file` capture. Stored as an ENCRYPTED column so the exact size does not leak, and decoded back to a number here. end-to-end encrypted at rest; the server holds the key only for the life of this request. |

## InboxList

| field | type | | notes |
|---|---|---|---|
| `data` | array of [InboxItem](/objects#inboxitem) | always present |  |
| `next_cursor` | string | always present | may be null. Opaque. Hand it back as `?cursor=` for the next page; `null` means this was the last page. Never construct or store one; it encodes `(orderKey, id)` of the last row and is only meaningful against the list that issued it. |

## InboxMoved

No fields of its own.

## LogbookView

| field | type | | notes |
|---|---|---|---|
| `logbookDays` | array of object | always present | Newest day first. `?from=`/`?to=` narrow the range; `?today=` sets the reference day. |

## Me

| field | type | | notes |
|---|---|---|---|
| `sub` | string | always present | The pairwise pseudonymous subject id, `base64url(HMAC(serverKey, audience ‖ userId))`, different for every OAuth client and every access key, so two apps cannot correlate the same person. A first-party app session gets the raw Appwrite user id. Webhook payloads carry the same value for the same credential. |
| `scopes` | array of string | always present | The scopes this credential actually holds, after the `tasks:*` umbrellas are expanded. |
| `grant` | object | always present | may be null. `null` for a first-party app session, which has no grant row. |
| `webhooks` | object | always present | Webhook health for this account. |

## OverviewView

| field | type | | notes |
|---|---|---|---|
| `navCounts` | object | always present | The sidebar badges. A closed-world contract: `fixtures/views.json` asserts it byte-identical. |
| `navCountsV12` | object | always present | Kept out of `navCounts` so that object stays closed-world. |
| `containerOpenCounts` | object | always present | Container id → recursive open-to-do count (an area sums its projects). |
| `containerPies` | object | always present | Container id → the done/open pair the progress pie draws. |
| `overviewTreeOrder` | array of string | always present | Container ids in sidebar order, which is the order everything else in this payload refers to. |
| `overviewStandaloneBlock` | array of string | always present | To-dos with no container, in display order. |
| `unfiledTodos` | array of string | always present | Open, non-trashed to-dos with no parent AND no date. These also appear in `anytime`, and the overlap is intended. |
| `inboxPinnedBlock` | object | always present | Two arrays and not one, because they index different tables. Mixing to-do ids and capture-row ids would force every consumer to guess which one to look each id up in. |
| `topbar` | object | always present |  |
| `priorities` | object | always present | Row id → priority, for to-dos and containers alike. Display only. |
| `excludedContainerIds` | array of string | always present | Containers excluded because they are ARCHIVED (trash is `trashExcluded`, which `/trash` owns). |
| `excludedTodoIds` | array of string | always present | To-dos excluded because their container is archived. |

## PingQueued

| field | type | | notes |
|---|---|---|---|
| `delivery` | [Delivery](/objects#delivery) | always present |  |
| `event` | [Event](/objects#event) | always present |  |

## Problem

RFC 9457 `application/problem+json`. ⚠ Branch on `type`, never on `detail`. `type` is a stable URI that also resolves to the page explaining the code; `detail` is prose written for a human and may change.

| field | type | | notes |
|---|---|---|---|
| `type` | string (uri) | always present | A stable URI under https://devs.inittasks.com/errors/. This is the machine-readable code. |
| `title` | string | always present | A short, stable summary of the code. Does not vary per occurrence. |
| `status` | integer | always present | The HTTP status, repeated in the body. |
| `detail` | string | optional | What went wrong this time. Never carries row content, a token, or anything derived from a key. |
| `instance` | string | optional | The path that produced it, `/v1/…`. |
| `request_id` | string | optional | The same value as the `X-Request-Id` header. Quote it in a support request. It is the only handle that ties your call to our log, and the log carries no bodies. |
| `errors` | array of object | optional | Field-level complaints on a `validation_failed`. Every offending field is listed, not just the first. |
| `retry_after` | integer | optional | Seconds to wait, on a `rate_limited`. The same value as the `Retry-After` header. |

## RedeliveryQueued

| field | type | | notes |
|---|---|---|---|
| `delivery` | [Delivery](/objects#delivery) | always present |  |

## SearchHit

| field | type | | notes |
|---|---|---|---|
| `kind` | `todo`, `container`, `inbox`, `attachment` | always present | Which resource `id` belongs to. |
| `id` | string | always present |  |
| `label` | string | always present | The row’s primary display text: title, name, captured text, or URL. end-to-end encrypted at rest; the server holds the key only for the life of this request. |
| `field` | `title`, `name`, `subtitle`, `notes`, `tags`, `text`, `url` | always present | Which field the query matched, so a client can say “matched in notes”. |
| `crumb` | string | always present | may be null. The direct parent container’s name, or `null` for a root row. end-to-end encrypted at rest; the server holds the key only for the life of this request. |

## SearchResult

| field | type | | notes |
|---|---|---|---|
| `data` | array of [SearchHit](/objects#searchhit) | always present |  |
| `next_cursor` | string | always present | may be null. Opaque. Hand it back as `?cursor=` for the next page; `null` means this was the last page. Never construct or store one; it encodes `(orderKey, id)` of the last row and is only meaningful against the list that issued it. |

## Session

| field | type | | notes |
|---|---|---|---|
| `id` | string | always present |  |
| `createdAt` | string (RFC 3339) | always present | **server-derived**. When the session was opened. |
| `current` | boolean | always present | Whether this is the session the calling credential is using. |
| `clientName` | string | always present | may be null |
| `clientVersion` | string | always present | may be null |
| `deviceName` | string | always present | may be null |
| `osName` | string | always present | may be null |
| `provider` | string | always present | may be null. How the session was created: `email`, `apple`, `google`, `token`. |
| `grant` | [AccessKey](/objects#accesskey) or [Grant](/objects#grant) | always present | may be null. The access key or connected app that owns this session, so a screen can say which one it belongs to. `null` for a person’s own sign-in. ⚠ No IP address: the contract does not list it and the screen does not need it. |

## SessionList

| field | type | | notes |
|---|---|---|---|
| `data` | array of [Session](/objects#session) | always present |  |
| `next_cursor` | string | always present | may be null. Opaque. Hand it back as `?cursor=` for the next page; `null` means this was the last page. Never construct or store one; it encodes `(orderKey, id)` of the last row and is only meaningful against the list that issued it. |

## Settings

| field | type | | notes |
|---|---|---|---|
| `weekStart` | `monday`, `sunday` | always present | The first column of the date picker. Presentation only: no view, bucket or count depends on it. ⚠ `PATCH` accepts `null` to mean “no preference”, and the server then answers with the default, `monday`. So a read-back is never `null`. |

## SomedayView

| field | type | | notes |
|---|---|---|---|
| `somedayV2` | object | always present |  |
| `containerSomeday` | object | always present | Container id → its direct parked to-dos. Only containers that have some appear. |

## Tag

| field | type | | notes |
|---|---|---|---|
| `id` | string | always present | `tg_` + 32 hex, which is `HMAC(k_id, name)`, NOT a UUID. A tag’s identity IS its name, which is why renaming is refused. |
| `createdAt` | string (RFC 3339) | always present | **server-derived**. RFC 3339; the row’s creation instant as Appwrite stamped it (`$createdAt`). |
| `updatedAt` | string (RFC 3339) | always present | **server-derived**. RFC 3339; the instant the SERVER last wrote the row (`$updatedAt`). This is the field `?updated_since=` compares against. It is never the client-stamped `updatedAt` column, which the sync rules forbid. |
| `name` | string | always present | The tag name, normalised to lower case with runs of whitespace collapsed. end-to-end encrypted at rest; the server holds the key only for the life of this request. |
| `colorHex` | string | always present | may be null. A 6-digit hex colour, or `null` for the theme default. end-to-end encrypted at rest; the server holds the key only for the life of this request. |
| `sortKey` | string | always present | Server-issued fractional ordering key. The stated order of every content list is `(sortKey, id)`. Opaque: compare it, never compute one. |

## TagList

| field | type | | notes |
|---|---|---|---|
| `data` | array of [Tag](/objects#tag) | always present |  |
| `next_cursor` | string | always present | may be null. Opaque. Hand it back as `?cursor=` for the next page; `null` means this was the last page. Never construct or store one; it encodes `(orderKey, id)` of the last row and is only meaningful against the list that issued it. |

## TodayView

| field | type | | notes |
|---|---|---|---|
| `todayItems` | array of string | always present | To-dos scheduled for the reference day. |
| `overdue` | array of string | always present | To-dos whose day has passed and are still open. |
| `doneToday` | array of string | always present | To-dos completed on the reference day. |
| `todayContainers` | array of string | always present | Containers whose DEADLINE is the reference day. Display-only surfacing; never counted. |
| `overdueContainers` | array of string | always present | Containers whose deadline has passed. |

## Todo

| field | type | | notes |
|---|---|---|---|
| `id` | string | always present | The to-do id. Client-supplied at create, else an uppercase UUID the server issues. |
| `createdAt` | string (RFC 3339) | always present | **server-derived**. RFC 3339; the row’s creation instant as Appwrite stamped it (`$createdAt`). |
| `updatedAt` | string (RFC 3339) | always present | **server-derived**. RFC 3339; the instant the SERVER last wrote the row (`$updatedAt`). This is the field `?updated_since=` compares against. It is never the client-stamped `updatedAt` column, which the sync rules forbid. |
| `title` | string | always present | The to-do title. end-to-end encrypted at rest; the server holds the key only for the life of this request. |
| `parentId` | string | always present | may be null. The container this to-do sits in, or `null` for a standalone to-do. Changed with `/move`. |
| `subtitle` | string | always present | may be null. A one-line subtitle. end-to-end encrypted at rest; the server holds the key only for the life of this request. |
| `notes` | string | always present | may be null. Free-form notes, up to 100,000 characters. end-to-end encrypted at rest; the server holds the key only for the life of this request. |
| `tags` | array of string | always present | Tag NAMES, never ids (the store holds blind ids; the API resolves them both ways). Always present; an untagged to-do returns `[]`. |
| `whenDate` | string (yyyy-MM-dd) | always present | may be null. `yyyy-MM-dd`. The day the to-do is scheduled for. `null` = unscheduled (the anytime bucket). |
| `deadline` | string (yyyy-MM-dd) | always present | may be null. `yyyy-MM-dd`. A hard due date. A deadline alone does NOT schedule the to-do. |
| `status` | `open`, `someday`, `done` | always present | Changed only by the actions (`/complete`, `/uncomplete`, `/someday`, `/anytime`), never by `PATCH`, because each is a transition with side effects. |
| `priority` | `low`, `medium`, `high` | always present | may be null. Display-only; it never affects ordering or counts. |
| `colorHex` | string | always present | may be null. A 6-digit hex colour, with or without the leading `#`. end-to-end encrypted at rest; the server holds the key only for the life of this request. |
| `colorStyle` | `text`, `fill` | always present | may be null. How the apps apply `colorHex`: tint the text, or fill the row. `null` = the theme default. |
| `reminderTime` | string | always present | may be null. A LOCAL-NAIVE 24-hour instant, `yyyy-MM-ddTHH:mm`: no seconds, no offset, no `Z`. It means that wall-clock time on the device that fires it, so it never shifts when the user travels. end-to-end encrypted at rest; the server holds the key only for the life of this request. |
| `recurrenceRule` | string | always present | may be null. The recurrence rule. `null` = a one-off to-do. end-to-end encrypted at rest; the server holds the key only for the life of this request. |
| `recurrenceAnchor` | string (yyyy-MM-dd) | always present | may be null. `yyyy-MM-dd`. Server-derived. The date the current occurrence counts from; `/complete` advances it when the to-do recurs. |
| `completedAt` | string (RFC 3339) | always present | may be null. **server-derived**. Stamped by `/complete`, cleared by `/uncomplete`. |
| `trashedAt` | string (RFC 3339) | always present | may be null. **server-derived**. Set by `/trash`, cleared by `/restore`; `null` means the row is live. |
| `sortKey` | string | always present | Server-issued fractional ordering key. The stated order of every content list is `(sortKey, id)`. Opaque: compare it, never compute one. |

## TodoList

| field | type | | notes |
|---|---|---|---|
| `data` | array of [Todo](/objects#todo) | always present |  |
| `next_cursor` | string | always present | may be null. Opaque. Hand it back as `?cursor=` for the next page; `null` means this was the last page. Never construct or store one; it encodes `(orderKey, id)` of the last row and is only meaningful against the list that issued it. |

## TrashEmptied

| field | type | | notes |
|---|---|---|---|
| `deleted` | integer | always present | min -9007199254740991, max 9007199254740991. How many rows were permanently deleted. Not recoverable. |

## TrashList

| field | type | | notes |
|---|---|---|---|
| `data` | array of [Todo](/objects#todo) or [Container](/objects#container) | always present |  |
| `next_cursor` | string | always present | may be null. Opaque. Hand it back as `?cursor=` for the next page; `null` means this was the last page. Never construct or store one; it encodes `(orderKey, id)` of the last row and is only meaningful against the list that issued it. |

## UpcomingView

| field | type | | notes |
|---|---|---|---|
| `upcomingGroups` | array of [DayBucket](/objects#daybucket) | always present | Everything scheduled beyond the seven-day window, grouped by day. |
| `dayBuckets` | array of [DayBucket](/objects#daybucket) | always present | EXACTLY seven buckets, `today … today+6`, rolling. Empty days are present with an empty `items`. |
| `dayBucketContainers` | object | always present | Day (`yyyy-MM-dd`) → containers whose deadline falls on it, for `today+1 … today+6`. |
| `inboxWhenDates` | object | always present | Capture-row id → the date quick-add parsed for it. |

## Webhook

| field | type | | notes |
|---|---|---|---|
| `id` | string | always present | `wh_` + base64url, NOT a UUID. |
| `url` | string | always present | The https endpoint deliveries are POSTed to. Sealed at rest. |
| `events` | array of `todo.created`, `todo.updated`, `todo.deleted`, `container.created`, `container.updated`, `container.deleted`, `inbox.created`, `inbox.updated`, `inbox.deleted`, `tag.created`, `tag.updated`, `tag.deleted`, `filter.created`, `filter.updated`, `filter.deleted`, `attachment.created`, `attachment.updated`, `attachment.deleted`, `webhook.ping`, `webhook.disabled` | always present |  |
| `description` | string | always present | may be null |
| `active` | boolean | always present | The server sets this to `false` after repeated delivery failures; `GET /me` counts how many were disabled that way. `PATCH` it back to `true` once the endpoint is fixed. |
| `createdAt` | string (RFC 3339) | always present | **server-derived** |

## WebhookCreated

| field | type | | notes |
|---|---|---|---|
| `id` | string | always present | `wh_` + base64url, NOT a UUID. |
| `url` | string | always present | The https endpoint deliveries are POSTed to. Sealed at rest. |
| `events` | array of `todo.created`, `todo.updated`, `todo.deleted`, `container.created`, `container.updated`, `container.deleted`, `inbox.created`, `inbox.updated`, `inbox.deleted`, `tag.created`, `tag.updated`, `tag.deleted`, `filter.created`, `filter.updated`, `filter.deleted`, `attachment.created`, `attachment.updated`, `attachment.deleted`, `webhook.ping`, `webhook.disabled` | always present |  |
| `description` | string | always present | may be null |
| `active` | boolean | always present | The server sets this to `false` after repeated delivery failures; `GET /me` counts how many were disabled that way. `PATCH` it back to `true` once the endpoint is fixed. |
| `createdAt` | string (RFC 3339) | always present | **server-derived** |
| `secret` | string | always present | The signing secret, `whsec_…`, returned exactly once and never re-shown. Verify every delivery’s `X-InitTasks-Signature` with it; if it is lost, rotate. |

## WebhookList

| field | type | | notes |
|---|---|---|---|
| `data` | array of [Webhook](/objects#webhook) | always present |  |

## WebhookRotated

| field | type | | notes |
|---|---|---|---|
| `id` | string | always present | `wh_` + base64url, NOT a UUID. |
| `url` | string | always present | The https endpoint deliveries are POSTed to. Sealed at rest. |
| `events` | array of `todo.created`, `todo.updated`, `todo.deleted`, `container.created`, `container.updated`, `container.deleted`, `inbox.created`, `inbox.updated`, `inbox.deleted`, `tag.created`, `tag.updated`, `tag.deleted`, `filter.created`, `filter.updated`, `filter.deleted`, `attachment.created`, `attachment.updated`, `attachment.deleted`, `webhook.ping`, `webhook.disabled` | always present |  |
| `description` | string | always present | may be null |
| `active` | boolean | always present | The server sets this to `false` after repeated delivery failures; `GET /me` counts how many were disabled that way. `PATCH` it back to `true` once the endpoint is fixed. |
| `createdAt` | string (RFC 3339) | always present | **server-derived** |
| `secret` | string | always present | The signing secret, `whsec_…`, returned exactly once and never re-shown. Verify every delivery’s `X-InitTasks-Signature` with it; if it is lost, rotate. |
| `previousSecretValidUntil` | string (RFC 3339) | always present | The PREVIOUS secret keeps verifying until this instant (24 h), and both secrets sign every delivery meanwhile, so a subscriber can deploy the new one without dropping the events that arrive mid-deploy. |
