REST API v1
Drive your TallyWeek workspace from scripts, Zapier or Make, or any other platform. Same permission model as the app.
Two ways to drive a workspace from outside the app, both backed by the same server-side core and the same permission model the app uses:
| URL | Auth | For | |
|---|---|---|---|
| MCP server | https://tallyweek.com/api/mcp | Authorization: Bearer jk_… or /api/mcp/<key> | Claude, ChatGPT, Claude Code, Cursor, any MCP client |
| REST API v1 | https://tallyweek.com/api/v1/... | Authorization: Bearer jk_… | Your own scripts, Zapier/Make, other platforms |
API keys
Keys are created in Workspace home, API & MCP by anyone whose workspace role has the Change workspace settings permission (owners by default). API keys are part of the Pro plan.
A key acts as one workspace member and carries scopes:
- Every call is first authorised as that member. Their workspace role, the permissions matrix and their board role (owner / editor / contributor / viewer) apply exactly as in the app. Private boards they cannot open do not exist to the key.
- The key's scopes then clamp what is left. A read-only key held by an owner cannot write; an
items:deletekey held by a viewer still cannot delete.
| Scope | Allows |
|---|---|
read | List/read workspace, folders, boards, groups, columns, items, updates, activity, members |
items:write | Create/edit items and subitems, values, assignees, move between groups |
items:delete | Trash, restore, permanently delete items |
updates:write | Post updates and replies (with @mentions) |
structure:write | Create/rename/reorder/configure groups and columns; hide/restore built-in columns |
structure:delete | Delete groups (and their items) and columns |
boards:write | Create boards and folders, rename, move into folders, settings, visibility |
boards:delete | Archive, trash, restore, permanently delete boards; delete folders |
members:manage | Share boards, change board roles/general access, send invites |
The full key is shown once at creation; only its SHA-256 hash is stored. Revoke a key from the same tab; it stops working immediately. See Permissions and sharing for the roles and matrix a key inherits.
Basics
Base URL https://tallyweek.com/api/v1. JSON in, JSON out. Every response is { "ok": true, "data": … } or { "ok": false, "error": "…" } with a matching HTTP status (400 bad input, 401 bad key, 403 not allowed, 404 not found).
Board ids may be the UUID or the numeric short id from the board URL. Wherever a user is expected, pass a user id, email, or full name.
curl -H "Authorization: Bearer jk_…" https://tallyweek.com/api/v1/meWorkspace
| Method | Path | Body / query | Scope |
|---|---|---|---|
| GET | /me | none | any |
| GET | /workspace | members, folders, boards | read |
| GET | /members | none | read |
| GET | /search?q= | limit | read |
Folders
| Method | Path | Body | Scope |
|---|---|---|---|
| GET | /folders | none | read |
| POST | /folders | { name, parentFolderId?, color? } | boards:write |
| PATCH | /folders/:id | { name?, color?, parentFolderId? (null = root), position? } | boards:write |
| DELETE | /folders/:id | boards inside move to the root | boards:delete |
Boards
| Method | Path | Body / query | Scope |
|---|---|---|---|
| GET | /boards | ?folderId=&includeArchived=&includeTrashed= | read |
| POST | /boards | { name, folderId?, template? (blank|crm|project|content|bugs), groups?: [names], columns?: [{name,type,settings}], description?, boardType? } | boards:write |
| GET | /boards/:id | ?items=false for structure only | read |
| PATCH | /boards/:id | { name?, description?, folderId? (null = root), visibility? (workspace|private), generalAccessRole? (editor|contributor|viewer|none), settings? } | boards:write |
| POST | /boards/:id/archive | { archived: true|false } | boards:delete |
| DELETE | /boards/:id | ?mode=trash (default) |permanent | boards:delete |
| POST | /boards/:id/restore | none | boards:delete |
GET /boards/:id returns statuses (keys + labels, including custom ones), columns (built-in owner/status/priority/due plus custom columns with ids and settings), column_order, hidden_native_columns, groups[].items[] (each item with values[], assignees[], subitems[], url) and automations.
Groups
| Method | Path | Body | Scope |
|---|---|---|---|
| POST | /boards/:id/groups | { name, color?, position?: "top"|"bottom" } | structure:write |
| PUT | /boards/:id/groups/order | { groupIds: [...] } | structure:write |
| PATCH | /groups/:id | { name?, color?, archived?, position? } | structure:write |
| DELETE | /groups/:id | deletes its items too | structure:delete |
Columns
| Method | Path | Body | Scope |
|---|---|---|---|
| GET | /boards/:id/columns | none | read |
| POST | /boards/:id/columns | { name?, type, options?, settings?, afterColumnId? } | structure:write |
| PUT | /boards/:id/columns/order | { keys: [column ids and/or owner|status|priority|due] } | structure:write |
| PUT | /boards/:id/columns/native/:key | { hidden: true|false } | structure:write |
| PATCH | /columns/:id | { name?, type?, settings?, options?, addOptions? } | structure:write |
| DELETE | /columns/:id | none | structure:delete |
Column types: text number date checkbox dropdown phone long_text timeline link files email rating progress tags time_tracking country connect dependency mirror, plus priority (creates a preset dropdown).
Items
| Method | Path | Body / query | Scope |
|---|---|---|---|
| GET | /boards/:id/items | ?groupId=&status=&priority=&assigneeId=&search=&includeSubitems=&includeArchived=&limit=&offset= | read |
| POST | /boards/:id/items | { name, groupId? | groupName?, status?, priority?, dueDate?, startDate?, assignees?: [user], values?: {}, position?: "top"|"bottom" } | items:write |
| GET | /items/:id | none | read |
| PATCH | /items/:id | { name?, status?, priority?, dueDate?, startDate?, groupId?, values?: {}, archived? } | items:write (+ moveItems for groupId) |
| POST | /items/:id/move | { groupId?, index? } (0-based; omit = end) | items:write |
| POST | /items/:id/subitems | same as create item | items:write |
| POST | /items/:id/assignees | { add?: [user], remove?: [user] } | items:write |
| DELETE | /items/:id | ?mode=trash (default) |permanent | items:delete |
| POST | /items/:id/restore | none | items:delete |
| GET | /items/:id/updates | ?limit= | read |
| POST | /items/:id/updates | { body, mentions?: [user], parentMessageId? } | updates:write |
| GET | /items/:id/activity | ?limit= | read |
values is keyed by column id or name. Shapes by type: text-like: string; number: number; rating: 0 to 5; progress: 0 to 100; date: YYYY-MM-DD; checkbox: boolean; dropdown: an option label; timeline: {start,end}; link: url string or {url,text}; tags: [strings]; country: 2-letter code; files: [{url,name,size?,type?}]; time_tracking: seconds; connect/dependency: [item ids]. null clears a value.
Status accepts a key (backlog in_motion in_review blocked shipped or a board's custom s_… key) or its label. Priority: low medium high urgent.
Sharing
| Method | Path | Body | Scope |
|---|---|---|---|
| GET | /boards/:id/members | none | read |
| PUT | /boards/:id/members | { user, role: owner|editor|contributor|assigned_contributor|viewer } | members:manage |
| DELETE | /boards/:id/members/:user | none | members:manage |
| POST | /invites | { email, role?, boardId? } returns { emailed, link, role } | members:manage |
What happens on a write
Writes go through the same paths the app uses: status changes record activity and notify assignees, moves reorder items, updates deliver @mentions and notifications. Every change is logged in the item's activity as the acting member, streams to open boards in real time, and runs the board's automations (item created, status, priority, column changed). Email notifications are not sent for API-made changes; in-app notifications are.
Example: build a board from scratch
K="Authorization: Bearer jk_…"; B=https://tallyweek.com/api/v1
curl -s -H "$K" -H 'Content-Type: application/json' $B/boards \
-d '{"name":"Launch plan","template":"project"}'
# returns data.id, data.groups[], data.columns[]
curl -s -H "$K" -H 'Content-Type: application/json' $B/boards/<id>/columns \
-d '{"name":"Channel","type":"dropdown","options":["Email","Social","Ads"]}'
curl -s -H "$K" -H 'Content-Type: application/json' $B/boards/<id>/items \
-d '{"name":"Draft announcement","groupName":"To do","status":"in_motion","priority":"high",
"dueDate":"2026-10-01","assignees":["dana@example.com"],"values":{"Channel":"Email","Progress":25}}'Related
- MCP server: the same operations as tools for AI assistants.
- Boards and columns: what each column type stores.
- Pricing: API keys are included in Pro.
Start a free workspace for your team.
14 days of Pro with no card, then Free for up to 3 members with every view and every automation.