POST /api/actions is the workspace mutation boundary. Clients send an array of typed operations, the exact expectedRevision they reviewed, and confirmed:true when the batch requires confirmation. Manual edits and reviewed AI drafts pass through the same validation and persistence boundary. Proposing an operation is separate from applying it.
{
"operations": [
{
"action": "update_item",
"spaceId": "sheet_projects",
"itemId": "record_example",
"notes": "Approved for the next review."
}
],
"expectedRevision": 7
}This example changes only notes on an existing synthetic record. Read actual sheet/record IDs and the current revision first. A successful result contains authoritative workspace data, a summary, historyId, and runs. With external workers, runs is empty because background scheduling occurs separately. Use paged response mode when you want metadata rather than a fully loaded workspace.
Supported operation names#
| Action | Payload besides action |
|---|---|
| create_insight | document: InsightDocument |
| update_insight | insightId; changes with name, description and/or blocks |
| delete_insight | insightId |
| create_rule | rule: RecordRule |
| update_rule | ruleId; changes (excluding id and createdAt) |
| delete_rule | ruleId |
| create_workbook | workbook: Workbook |
| update_workbook | workbookId; changes with name, description, color and/or archived |
| move_space | spaceId; workbookId:string|null; optional index |
| reorder_workbooks | workbookIds:string[] |
| create_workflow | workflow: Workflow |
| update_workflow | workflowId; changes with name, description, trigger, conditions, steps, instructions, mode and/or enabled |
| delete_workflow | workflowId |
| create_space | space: Space |
| rename_space | spaceId; name |
| create_item | spaceId; item: Item |
| start_timer | spaceId; itemId; fieldId |
| stop_timer | spaceId; itemId; fieldId |
| update_item | spaceId; itemId; values and/or notes |
| delete_item | spaceId; itemId |
| archive_item | spaceId; itemId |
| restore_item | spaceId; itemId |
| create_field | spaceId; field: Field |
| update_field | spaceId; fieldId; optional name/type/options/optionColors/width/relation/formula/rollup/format |
| move_field | spaceId; fieldId; index |
| delete_field | spaceId; fieldId |
| create_view | spaceId; view: View |
| update_view | spaceId; viewId; optional name/type/filters/sorts/groupBy/config |
| bulk_update | spaceId; itemIds:string[]; values |
| bulk_archive | spaceId; itemIds:string[] |
The table follows the current Operation union and engine. It is exhaustive for operation names, but nested objects still require their own valid fields, references, and constraints. There is no generic arbitrary-property mutation, SQL endpoint, predicate-based bulk write, delete_space action, or delete_view action. Bulk edits identify concrete, unique records in a specific sheet.
Use IDs and typed values#
Item.values is keyed by field ID, not a displayed column name. A CellValue is a string, number, boolean, string array, timer object, or null, with the permitted choice determined by the field. Relation values reference real records; Person values reference real members. Formula and rollup fields are computed and cannot be treated as ordinary stored editable values. Timer actions let the server control start timestamps rather than trusting a client-written start time.
- Field types: text, long_text, number, duration, timer, rating, phone, checkbox, date, status, select, multi_select, person, url, email, attachment, relation, formula, rollup.
- View types: table, board, calendar, timeline, flow, gallery, list, chart, form, workload. The UI may use a friendlier label such as Pipeline for flow.
- Choice colors: slate, blue, indigo, violet, pink, red, orange, amber, green, teal.
- Creating an Item requires id, values, notes, archived, createdAt, and updatedAt; nested IDs/references must be valid in the proposed workspace.
Validate the whole batch#
The route accepts at most 500 operations within a 4 MiB JSON body. Later operations can reference entities created earlier in the same batch. Validation, references, permissions, record rules, and optimistic revision checks all apply before commit. A failed batch does not leave its earlier operations partially applied. Confirmation is an explicit reviewed choice; do not automatically add confirmed:true to every failing request.
When applying a saved AI proposal, include its aiJobId and use that proposal’s baseRevision as expectedRevision. The server checks ownership, completed/unapplied state, and the saved proposal against the requested operation batch. The mutation and job application receipt commit together. An arbitrary job ID cannot authorize a change.
Read the result and preserve history semantics#
After a successful write, replace or reconcile local state with the authoritative response. Do not treat an old local snapshot as current simply because the HTTP request was sent. POST /api/history accepts direction undo or redo and an expectedRevision; history operations advance the workspace revision. They respect top-of-history actor checks and do not perform selective merging over teammates’ later edits.