Documents

Edit an in-house Space document by block id or quoted words with prose ops (insert, replace, delete, move, set, restore), guarded by block hash and revision

Edit a Space document with prose ops, applied in order and all-or-nothing on the latest version (text people type meanwhile is kept). Ops: insert {target, side, source} · replace {target, with} · delete {target} · move {target, to:{target, side}} · set {target, attrs:{kind|checked|background|rows|spec|caption}} · restore {rev} (the only op in its call, with payload.ifRev = the latest rev). Targets: {"kind":"find","text":"…","nth"?} words as they stand · {"kind":"blocks","ids":[…]} full ids off a read or ack · {"kind":"root"} with side start/end · {"kind":"cell","table","row","col"}. source/with = {"from":{"kind":"inline","content":…},"as":"text"|"markdown"|"blocks"}: text re-words in place keeping formatting; markdown re-creates blocks; blocks is a JSON node tree (table rows: [{"type":"row","content":[{"type":"cell",…}]}]). A pending block is filled by replacing its id with "## Heading" + body (no guard); later edits use the ids in that ack. A whole-block replace/delete carries "ifHash" (its newest h) and "ifRev" (the rev of the read that showed it); several ids or a cell take "ifRev"; "force" only when told to overwrite. side "end" on a heading id = end of its section; on a list/table/row id = append inside it. set: list kind bullet|ordered|check, checked on a check-list item, cell background one of #f0efec #fbebeb #f9ece7 #f9eeda #e5f4e4 #e7f1fb #efedff (null clears). Column: insert with "each":true at every row id. Charts and diagrams: a chart block is drawn from rows + spec, never a picture; a diagram block from boxes + connectors. Place one with the embed chip <?claude block chart?> + blocks {"chart":{"type":"chart","spec":{…},"rows":[…],"caption":"…"}} (or "type":"diagram"); change it with set attrs {rows|spec|caption} on its id. Chips: put <?claude block key?> in the markdown and the chip in "blocks": mention {"user":"me"} (the requesting user), an existing member's user id, or an email only when the user named it — never guess one; mention {"ref":"project/<doc id>"} links another document; date {"value":"YYYY-MM-DD"} for actionable dates only. Only members and documents of this workspace resolve. Images and files: create a blob first (create_space_document_blob), then insert its markdown (alt); a blob/<id> of another workspace is refused. A refusal writes nothing: 409 with error.code (guard_mismatch: the block changed, error.data shows it as it stands, redo from it and never force; find_none: re-read and quote what it says now; block_gone: someone removed it, never re-create it; missing_guard, cell_none, last_block, same_anchor, place_arity, shape, bad_request) and error.param (the op path).

POST
/v1/space/documents/{document_id}/edit
curl -X POST "https://api.orchestor.io/v1/space/documents/%3Cdocument_id%3E/edit" \  -H "Authorization: Bearer $API_KEY" \  -H "X-Workspace-ID: wks_abc123" \  -H "Content-Type: application/json" \  -d '{  "answering": "string",  "ifRev": 1,  "ops": [    {      "each": true,      "op": "insert",      "side": "before",      "source": {        "as": "text",        "blocks": {},        "from": {          "content": "string",          "kind": "inline"        }      },      "target": {        "kind": "find",        "nth": 1,        "text": "string",        "within": {          "col": 1,          "kind": "cell",          "row": 1,          "table": "string"        }      }    }  ]}'
{  "data": {    "ops": [      {        "notices": [          "<string>"        ],        "op": "<string>",        "xml": "<string>"      }    ],    "rev": 0  }}

Get your Orchestor API key

Create an API key in your workspace settings.

Authorizations

Satisfy one of these options:

  • Session cookie
  • API key

Authentication details

cookie
wos-session

Browser session established by signing in to the web app. The server checks your workspace membership and permissions. Supply X-Workspace-ID for workspace-scoped operations. For server-to-server requests, use an API key when the operation supports it.

Path Parameters

document_idstringpathrequired
Pattern
^doc_[a-f0-9]{24}$

Headers

X-Workspace-IDstringheader

Workspace to access. With a workspace-scoped API key, the server derives this value from the key, so the header is optional. If supplied, it must match the credential workspace or the request returns 403 workspace_mismatch. For interactive session requests, supply this header to select a workspace where you are a member. A project ID cannot be used as a workspace ID.

Example"wks_abc123"

Bodyapplication/jsonrequired

answeringstringbody

The thread (its first comment id) this edit answers, when a comment asked for it.

Pattern
^dcm_[a-f0-9]{24}$
ifRevintegerbody
Value range
≥ 0
ops(object | object | object | object | object | object)[]bodyrequired
Item count
≥ 1, ≤ 64
ops[]object | object | object | object | object | objectbody

Match at least one of the following

Variant 1: object

ops[].eachbooleanbody
ops[].opstringenum<string>bodyrequired
Allowed
insert
ops[].sidestringenum<string>bodyrequired
Allowed
beforeafterstartend
ops[].sourceobjectbodyrequired
ops[].source.asstringenum<string>bodyrequired
Allowed
textmarkdownblocks
ops[].source.blocksobjectbody

Chips for <?claude block key?> tokens in the markdown, e.g. {"s1":{"type":"pending","intent":"Risks: …"}}, {"me":{"type":"mention","user":"me"},"due":{"type":"date","value":"2026-11-01"},"plan":{"type":"mention","ref":"project/doc_…"}} or {"chart":{"type":"chart","spec":{…},"rows":[…],"caption":"<where the numbers come from>"}}.

ops[].source.blocks.*object | object | object | object | object | object | objectbody

Match at least one of the following

Variant 1: object

ops[].source.blocks.*.intentstringbodyrequired
String length
≤ 2000
ops[].source.blocks.*.typestringenum<string>bodyrequired
Allowed
pending

Variant 2: object

ops[].source.blocks.*.typestringenum<string>bodyrequired
Allowed
paragraph

Variant 3: object

ops[].source.blocks.*.captionstringbody
ops[].source.blocks.*.rowsobject[]bodyrequired

The rows the chart draws, as measured (≤ 2000 rows, 256 KiB).

Item count
≤ 2000
ops[].source.blocks.*.rows[]objectbody
ops[].source.blocks.*.rows[].*string | number | boolean | nullbody

Match at least one of the following

Variant 1: string

ops[].source.blocks.*.rows[].*stringbody

Variant 2: number

ops[].source.blocks.*.rows[].*numberbody

Variant 3: boolean

ops[].source.blocks.*.rows[].*booleanbody

Variant 4: null

ops[].source.blocks.*.rows[].*nullbody
ops[].source.blocks.*.specobjectbodyrequired
ops[].source.blocks.*.spec.kindstringenum<string>bodyrequired
Allowed
linebarpie
ops[].source.blocks.*.spec.seriesstringbody

A column whose VALUES name the series: one row per series and period.

ops[].source.blocks.*.spec.titlestringbodyrequired

The finding, with its number, not the topic.

String length
≥ 1
ops[].source.blocks.*.spec.unitstringbody
ops[].source.blocks.*.spec.xstringbodyrequired

The column along the axis (or the pie slices).

String length
≥ 1
ops[].source.blocks.*.spec.ystringbodyrequired

The measured column (numbers).

String length
≥ 1
ops[].source.blocks.*.typestringenum<string>bodyrequired
Allowed
chart

Variant 4: object

ops[].source.blocks.*.captionstringbody
ops[].source.blocks.*.specobjectbodyrequired
ops[].source.blocks.*.spec.directionstringenum<string>bodyrequired
Allowed
rightdown
ops[].source.blocks.*.spec.edgesobject[]bodyrequired
Item count
≤ 120
ops[].source.blocks.*.spec.edges[]objectbody
ops[].source.blocks.*.spec.edges[].fromstringbodyrequired
ops[].source.blocks.*.spec.edges[].labelstringbody
ops[].source.blocks.*.spec.edges[].tostringbodyrequired
ops[].source.blocks.*.spec.nodesobject[]bodyrequired
Item count
≥ 1, ≤ 60
ops[].source.blocks.*.spec.nodes[]objectbody
ops[].source.blocks.*.spec.nodes[].detailstringbody
ops[].source.blocks.*.spec.nodes[].idstringbodyrequired
Pattern
^[\w-]{1,64}$
ops[].source.blocks.*.spec.nodes[].labelstringbodyrequired
String length
≥ 1
ops[].source.blocks.*.spec.titlestringbodyrequired
String length
≥ 1
ops[].source.blocks.*.typestringenum<string>bodyrequired
Allowed
diagram

Variant 5: object

ops[].source.blocks.*.typestringenum<string>bodyrequired
Allowed
mention
ops[].source.blocks.*.userstringbodyrequired
String length
≥ 1, ≤ 320

Variant 6: object

ops[].source.blocks.*.refstringbodyrequired
Pattern
^project\/doc_[a-f0-9]{24}$
ops[].source.blocks.*.typestringenum<string>bodyrequired
Allowed
mention

Variant 7: object

ops[].source.blocks.*.typestringenum<string>bodyrequired
Allowed
date
ops[].source.blocks.*.valuestringbodyrequired
Pattern
^\d{4}-\d{2}-\d{2}$
ops[].source.fromobjectbodyrequired
ops[].source.from.contentstring | object[] | objectbodyrequired

Match at least one of the following

Variant 1: string

ops[].source.from.contentstringbody

Variant 2: object[]

ops[].source.from.content[]objectbody
ops[].source.from.content[].*anybody

Variant 3: object

ops[].source.from.content.*anybody
ops[].source.from.kindstringenum<string>bodyrequired
Allowed
inline
ops[].targetobject | object | object | objectbodyrequired

Match at least one of the following

Variant 1: object

Words exactly as they stand in your last read or ack; "nth" when they repeat (default 1).

ops[].target.kindstringenum<string>bodyrequired
Allowed
find
ops[].target.nthintegerbody
Value range
≥ 1
ops[].target.textstringbodyrequired
String length
≥ 1
ops[].target.withinobjectbody

A table cell by position: 0 = first row (the header row) / first column, -1 = last.

ops[].target.within.colintegerbodyrequired
ops[].target.within.kindstringenum<string>bodyrequired
Allowed
cell
ops[].target.within.rowintegerbodyrequired
ops[].target.within.tablestringbodyrequired

A full block id as a read or ack prints it, e.g. "1938274.12".

Pattern
^\d+\.\d+$

Variant 2: object

ops[].target.idsstring[]bodyrequired
Item count
≥ 1, ≤ 4096
ops[].target.ids[]stringbody

A full block id as a read or ack prints it, e.g. "1938274.12".

Pattern
^\d+\.\d+$
ops[].target.kindstringenum<string>bodyrequired
Allowed
blocks

Variant 3: object

ops[].target.kindstringenum<string>bodyrequired
Allowed
root

Variant 4: object

A table cell by position: 0 = first row (the header row) / first column, -1 = last.

ops[].target.colintegerbodyrequired
ops[].target.kindstringenum<string>bodyrequired
Allowed
cell
ops[].target.rowintegerbodyrequired
ops[].target.tablestringbodyrequired

A full block id as a read or ack prints it, e.g. "1938274.12".

Pattern
^\d+\.\d+$

Variant 2: object

ops[].forcebooleanbody
ops[].ifHashstringbody
Pattern
^[0-9a-f]{8}$
ops[].ifRevintegerbody
Value range
≥ 0
ops[].opstringenum<string>bodyrequired
Allowed
replace
ops[].targetobject | object | object | objectbodyrequired

Match at least one of the following

Variant 1: object

Words exactly as they stand in your last read or ack; "nth" when they repeat (default 1).

ops[].target.kindstringenum<string>bodyrequired
Allowed
find
ops[].target.nthintegerbody
Value range
≥ 1
ops[].target.textstringbodyrequired
String length
≥ 1
ops[].target.withinobjectbody

A table cell by position: 0 = first row (the header row) / first column, -1 = last.

ops[].target.within.colintegerbodyrequired
ops[].target.within.kindstringenum<string>bodyrequired
Allowed
cell
ops[].target.within.rowintegerbodyrequired
ops[].target.within.tablestringbodyrequired

A full block id as a read or ack prints it, e.g. "1938274.12".

Pattern
^\d+\.\d+$

Variant 2: object

ops[].target.idsstring[]bodyrequired
Item count
≥ 1, ≤ 4096
ops[].target.ids[]stringbody

A full block id as a read or ack prints it, e.g. "1938274.12".

Pattern
^\d+\.\d+$
ops[].target.kindstringenum<string>bodyrequired
Allowed
blocks

Variant 3: object

ops[].target.kindstringenum<string>bodyrequired
Allowed
root

Variant 4: object

A table cell by position: 0 = first row (the header row) / first column, -1 = last.

ops[].target.colintegerbodyrequired
ops[].target.kindstringenum<string>bodyrequired
Allowed
cell
ops[].target.rowintegerbodyrequired
ops[].target.tablestringbodyrequired

A full block id as a read or ack prints it, e.g. "1938274.12".

Pattern
^\d+\.\d+$
ops[].withobjectbodyrequired
ops[].with.asstringenum<string>bodyrequired
Allowed
textmarkdownblocks
ops[].with.blocksobjectbody

Chips for <?claude block key?> tokens in the markdown, e.g. {"s1":{"type":"pending","intent":"Risks: …"}}, {"me":{"type":"mention","user":"me"},"due":{"type":"date","value":"2026-11-01"},"plan":{"type":"mention","ref":"project/doc_…"}} or {"chart":{"type":"chart","spec":{…},"rows":[…],"caption":"<where the numbers come from>"}}.

ops[].with.blocks.*object | object | object | object | object | object | objectbody

Match at least one of the following

Variant 1: object

ops[].with.blocks.*.intentstringbodyrequired
String length
≤ 2000
ops[].with.blocks.*.typestringenum<string>bodyrequired
Allowed
pending

Variant 2: object

ops[].with.blocks.*.typestringenum<string>bodyrequired
Allowed
paragraph

Variant 3: object

ops[].with.blocks.*.captionstringbody
ops[].with.blocks.*.rowsobject[]bodyrequired

The rows the chart draws, as measured (≤ 2000 rows, 256 KiB).

Item count
≤ 2000
ops[].with.blocks.*.rows[]objectbody
ops[].with.blocks.*.rows[].*string | number | boolean | nullbody

Match at least one of the following

Variant 1: string

ops[].with.blocks.*.rows[].*stringbody

Variant 2: number

ops[].with.blocks.*.rows[].*numberbody

Variant 3: boolean

ops[].with.blocks.*.rows[].*booleanbody

Variant 4: null

ops[].with.blocks.*.rows[].*nullbody
ops[].with.blocks.*.specobjectbodyrequired
ops[].with.blocks.*.spec.kindstringenum<string>bodyrequired
Allowed
linebarpie
ops[].with.blocks.*.spec.seriesstringbody

A column whose VALUES name the series: one row per series and period.

ops[].with.blocks.*.spec.titlestringbodyrequired

The finding, with its number, not the topic.

String length
≥ 1
ops[].with.blocks.*.spec.unitstringbody
ops[].with.blocks.*.spec.xstringbodyrequired

The column along the axis (or the pie slices).

String length
≥ 1
ops[].with.blocks.*.spec.ystringbodyrequired

The measured column (numbers).

String length
≥ 1
ops[].with.blocks.*.typestringenum<string>bodyrequired
Allowed
chart

Variant 4: object

ops[].with.blocks.*.captionstringbody
ops[].with.blocks.*.specobjectbodyrequired
ops[].with.blocks.*.spec.directionstringenum<string>bodyrequired
Allowed
rightdown
ops[].with.blocks.*.spec.edgesobject[]bodyrequired
Item count
≤ 120
ops[].with.blocks.*.spec.edges[]objectbody
ops[].with.blocks.*.spec.edges[].fromstringbodyrequired
ops[].with.blocks.*.spec.edges[].labelstringbody
ops[].with.blocks.*.spec.edges[].tostringbodyrequired
ops[].with.blocks.*.spec.nodesobject[]bodyrequired
Item count
≥ 1, ≤ 60
ops[].with.blocks.*.spec.nodes[]objectbody
ops[].with.blocks.*.spec.nodes[].detailstringbody
ops[].with.blocks.*.spec.nodes[].idstringbodyrequired
Pattern
^[\w-]{1,64}$
ops[].with.blocks.*.spec.nodes[].labelstringbodyrequired
String length
≥ 1
ops[].with.blocks.*.spec.titlestringbodyrequired
String length
≥ 1
ops[].with.blocks.*.typestringenum<string>bodyrequired
Allowed
diagram

Variant 5: object

ops[].with.blocks.*.typestringenum<string>bodyrequired
Allowed
mention
ops[].with.blocks.*.userstringbodyrequired
String length
≥ 1, ≤ 320

Variant 6: object

ops[].with.blocks.*.refstringbodyrequired
Pattern
^project\/doc_[a-f0-9]{24}$
ops[].with.blocks.*.typestringenum<string>bodyrequired
Allowed
mention

Variant 7: object

ops[].with.blocks.*.typestringenum<string>bodyrequired
Allowed
date
ops[].with.blocks.*.valuestringbodyrequired
Pattern
^\d{4}-\d{2}-\d{2}$
ops[].with.fromobjectbodyrequired
ops[].with.from.contentstring | object[] | objectbodyrequired

Match at least one of the following

Variant 1: string

ops[].with.from.contentstringbody

Variant 2: object[]

ops[].with.from.content[]objectbody
ops[].with.from.content[].*anybody

Variant 3: object

ops[].with.from.content.*anybody
ops[].with.from.kindstringenum<string>bodyrequired
Allowed
inline

Variant 3: object

ops[].forcebooleanbody
ops[].ifHashstringbody
Pattern
^[0-9a-f]{8}$
ops[].ifRevintegerbody
Value range
≥ 0
ops[].opstringenum<string>bodyrequired
Allowed
delete
ops[].targetobject | object | object | objectbodyrequired

Match at least one of the following

Variant 1: object

Words exactly as they stand in your last read or ack; "nth" when they repeat (default 1).

ops[].target.kindstringenum<string>bodyrequired
Allowed
find
ops[].target.nthintegerbody
Value range
≥ 1
ops[].target.textstringbodyrequired
String length
≥ 1
ops[].target.withinobjectbody

A table cell by position: 0 = first row (the header row) / first column, -1 = last.

ops[].target.within.colintegerbodyrequired
ops[].target.within.kindstringenum<string>bodyrequired
Allowed
cell
ops[].target.within.rowintegerbodyrequired
ops[].target.within.tablestringbodyrequired

A full block id as a read or ack prints it, e.g. "1938274.12".

Pattern
^\d+\.\d+$

Variant 2: object

ops[].target.idsstring[]bodyrequired
Item count
≥ 1, ≤ 4096
ops[].target.ids[]stringbody

A full block id as a read or ack prints it, e.g. "1938274.12".

Pattern
^\d+\.\d+$
ops[].target.kindstringenum<string>bodyrequired
Allowed
blocks

Variant 3: object

ops[].target.kindstringenum<string>bodyrequired
Allowed
root

Variant 4: object

A table cell by position: 0 = first row (the header row) / first column, -1 = last.

ops[].target.colintegerbodyrequired
ops[].target.kindstringenum<string>bodyrequired
Allowed
cell
ops[].target.rowintegerbodyrequired
ops[].target.tablestringbodyrequired

A full block id as a read or ack prints it, e.g. "1938274.12".

Pattern
^\d+\.\d+$

Variant 4: object

ops[].opstringenum<string>bodyrequired
Allowed
move
ops[].targetobjectbodyrequired
ops[].target.idsstring[]bodyrequired
Item count
≥ 1, ≤ 4096
ops[].target.ids[]stringbody

A full block id as a read or ack prints it, e.g. "1938274.12".

Pattern
^\d+\.\d+$
ops[].target.kindstringenum<string>bodyrequired
Allowed
blocks
ops[].toobjectbodyrequired
ops[].to.sidestringenum<string>bodyrequired
Allowed
beforeafterstartend
ops[].to.targetobject | objectbodyrequired

Match at least one of the following

Variant 1: object

ops[].to.target.idsstring[]bodyrequired
Item count
≥ 1, ≤ 4096
ops[].to.target.ids[]stringbody

A full block id as a read or ack prints it, e.g. "1938274.12".

Pattern
^\d+\.\d+$
ops[].to.target.kindstringenum<string>bodyrequired
Allowed
blocks

Variant 2: object

ops[].to.target.kindstringenum<string>bodyrequired
Allowed
root

Variant 5: object

ops[].attrsobjectbodyrequired
ops[].attrs.backgroundstring | nullbody
ops[].attrs.captionstringbody
ops[].attrs.checkedbooleanbody
ops[].attrs.kindstringenum<string>body
Allowed
bulletorderedcheck
ops[].attrs.rowsobject[]body

The rows the chart draws, as measured (≤ 2000 rows, 256 KiB).

Item count
≤ 2000
ops[].attrs.rows[]objectbody
ops[].attrs.rows[].*string | number | boolean | nullbody

Match at least one of the following

Variant 1: string

ops[].attrs.rows[].*stringbody

Variant 2: number

ops[].attrs.rows[].*numberbody

Variant 3: boolean

ops[].attrs.rows[].*booleanbody

Variant 4: null

ops[].attrs.rows[].*nullbody
ops[].attrs.specobject | objectbody

Match at least one of the following

Variant 1: object

ops[].attrs.spec.kindstringenum<string>bodyrequired
Allowed
linebarpie
ops[].attrs.spec.seriesstringbody

A column whose VALUES name the series: one row per series and period.

ops[].attrs.spec.titlestringbodyrequired

The finding, with its number, not the topic.

String length
≥ 1
ops[].attrs.spec.unitstringbody
ops[].attrs.spec.xstringbodyrequired

The column along the axis (or the pie slices).

String length
≥ 1
ops[].attrs.spec.ystringbodyrequired

The measured column (numbers).

String length
≥ 1

Variant 2: object

ops[].attrs.spec.directionstringenum<string>bodyrequired
Allowed
rightdown
ops[].attrs.spec.edgesobject[]bodyrequired
Item count
≤ 120
ops[].attrs.spec.edges[]objectbody
ops[].attrs.spec.edges[].fromstringbodyrequired
ops[].attrs.spec.edges[].labelstringbody
ops[].attrs.spec.edges[].tostringbodyrequired
ops[].attrs.spec.nodesobject[]bodyrequired
Item count
≥ 1, ≤ 60
ops[].attrs.spec.nodes[]objectbody
ops[].attrs.spec.nodes[].detailstringbody
ops[].attrs.spec.nodes[].idstringbodyrequired
Pattern
^[\w-]{1,64}$
ops[].attrs.spec.nodes[].labelstringbodyrequired
String length
≥ 1
ops[].attrs.spec.titlestringbodyrequired
String length
≥ 1
ops[].opstringenum<string>bodyrequired
Allowed
set
ops[].targetobject | objectbodyrequired

Match at least one of the following

Variant 1: object

ops[].target.idsstring[]bodyrequired
Item count
≥ 1, ≤ 4096
ops[].target.ids[]stringbody

A full block id as a read or ack prints it, e.g. "1938274.12".

Pattern
^\d+\.\d+$
ops[].target.kindstringenum<string>bodyrequired
Allowed
blocks

Variant 2: object

A table cell by position: 0 = first row (the header row) / first column, -1 = last.

ops[].target.colintegerbodyrequired
ops[].target.kindstringenum<string>bodyrequired
Allowed
cell
ops[].target.rowintegerbodyrequired
ops[].target.tablestringbodyrequired

A full block id as a read or ack prints it, e.g. "1938274.12".

Pattern
^\d+\.\d+$

Variant 6: object

ops[].opstringenum<string>bodyrequired
Allowed
restore
ops[].revintegerbodyrequired
Value range
≥ 1

Response

application/json

What each op wrote, as a read prints it, and the new revision

dataSpaceDocumentEditAckrequired
data.opsobject[]required
data.ops[]object
data.ops[].noticesstring[]
data.ops[].notices[]string
data.ops[].opstringrequired
data.ops[].xmlstringrequired
data.revintegerrequired