Documentation Index
Fetch the complete documentation index at: https://docs.moda.app/llms.txt
Use this file to discover all available pages before exploring further.
Pagination
Every list endpoint on2026-05-01 uses opaque cursor pagination. No offsets, no total count.
Response shape
data— the page of items.next_cursor— opaque signed string. Pass back as?cursor=<value>to get the next page.nullmeans you’ve reached the end.
Iteration pattern
TypeScript:Limits
| Parameter | Default | Max |
|---|---|---|
limit | 20 | 100 |
Sort order
List endpoints sort by(created_at DESC, id DESC) on immutable columns. This guarantees pagination correctness when rows are added or modified mid-scan — no skips, no duplicates — at the cost of “sort by updated_at” being unavailable.
Client-side sort if you need a different order.
No total
Canonical responses do not include a total count. Computing it on every list call would pressure the DB. If you need an approximate count for a dashboard, cache it separately (e.g. run a count query daily). For a progress bar on a long iteration, the common pattern is “processed 127 so far…” without a denominator.
Opaque cursors
Cursors are HMAC-signed + base64url-encoded. Don’t:- Parse or mutate the cursor value.
- Attempt to construct one by hand.
- Reuse a cursor from a different list endpoint.
400 invalid_request.
Cursors are valid across sessions but have a bounded TTL — don’t store one for a week and expect it to resume correctly. For long-running iterations (> a few hours), consider re-starting from the beginning.
Endpoints that paginate
All of these return{data, next_cursor}:
GET /v1/canvasesGET /v1/canvases/searchGET /v1/tasksGET /v1/brand-kitsGET /v1/organizationsGET /v1/events
GET /v1/canvases/{id}, GET /v1/tasks/{id}, GET /v1/credits, etc.) don’t paginate.
Concurrency
Don’t parallelize pagination. Each page depends on the previous one’s cursor. Parallelize the work done per item inside a page instead.Migration from offset pagination
If you’re carrying code from the legacy2026-04-12 shape:
Common wrong guesses
- Expecting
totalin the response. Not there. Compute separately if you need it. - Parsing / mutating cursors. Opaque; server rejects tampered values.
- Passing
offset=as a fallback. Ignored (or rejected, depending on endpoint) on2026-05-01. Use cursor. - Holding a cursor for days. Cursors expire; restart the iteration.
- Parallel page fetches. Each page depends on the prior cursor.
- Reading
response.canvases/response.tasks/response.brand_kits. Canonical always puts items underdata.
Upstream
docs.moda.app/api/versioning— migration map- Per-endpoint docs at
docs.moda.app/api/{canvases,tasks,brand-kits,organizations}/*