# Edit a revision with typed operations

> Page: https://docs.plotwork.dev/api/post-orgs-org-boards-board-tabs-tab-revisions-revision-edits. Index of every page: https://docs.plotwork.dev/llms.txt

Applies edit_diagram operations to the revision, on its current source, as the tab route does for main.

`POST /orgs/{org}/boards/{board}/tabs/{tab}/revisions/{revision}/edits`

## TL;DR

| Question | Answer |
|---|---|
| What does it do? | Edit a revision with typed operations. |
| What does it take? | A JSON body of type [`EditBoardRevisionBody`](https://docs.plotwork.dev/api/schemas.md#editboardrevisionbody). |
| What does it return? | Status 200 with a body of type [`BoardRevisionResult`](https://docs.plotwork.dev/api/schemas.md#boardrevisionresult). |
| What can go wrong? | `400` the body is not valid, or names someone who is not a member of the organisation; `401` not signed in; `403` boards are not turned on for this organisation (boards.not_enabled), the caller may look but not change it (boards.forbidden), or the request came from an origin that may not make changes; `404` no such organisation, board, tab or revision, or one not open to the caller (boards.revision_not_found): the cases look alike; `409` the revision changed since the version sent (diagram.version_conflict), it is merged or discarded (boards.revision_closed), the tab has as many open revisions as it may (boards.revision_limit), or main and the revision changed the same statement (boards.merge_conflict, details.conflicts and details.mainVersion); `413` the source is longer than a tab may be, or the board holds as much as it may; `422` the source has errors (diagram.invalid), an edit did not apply (boards.operation_failed), or it holds something that looks like a secret and the organisation blocks them (boards.secret_blocked); `429` too many requests; `503` organisations or boards are not set up on this server. Every failure uses the one error envelope. |

## What it does

Applies edit_diagram operations to the revision, on its current source, as the tab route does for main. Main does not change. The result parses and passes the secret scan, and everyone watching the revision gets it live.

## Path parameters

| Field | Type | Required | Description |
|---|---|---|---|
| `org` | `string` | yes | The organisation's id or its slug. |
| `board` | `string` | yes | The board's id: 22 letters and digits. |
| `tab` | `string` | yes | The tab's id: 12 letters and digits. |
| `revision` | `string` | yes | The revision's id: 12 letters and digits. |

## Request body

The body has the type [`EditBoardRevisionBody`](https://docs.plotwork.dev/api/schemas.md#editboardrevisionbody).

| Field | Type | Required | Description |
|---|---|---|---|
| `baseVersion` | `integer` | yes |  |
| `operations` | `object[]` | yes |  |
| `operations[].op` | `"rename" \| "set" \| "add_node" \| "remove" \| "add_edge" \| "remove_edge" \| "move" \| "replace_text"` | yes |  |
| `operations[].target` | `string` | no | Id, label, table.column, or "header". at most 2000 characters. |
| `operations[].to` | `string` | no | rename: the new name. Edges: the end. at most 2000 characters. |
| `operations[].from` | `string` | no | Edges: the start. at most 2000 characters. |
| `operations[].option` | `string` | no | at most 40 characters; pattern `^[a-z][A-Za-z0-9_-]*$`. |
| `operations[].value` | `string \| null` | no | set: null removes the option. at most 2000 characters. |
| `operations[].id` | `string` | no | at most 2000 characters. |
| `operations[].label` | `string` | no | add_edge on sankey: the amount. at most 2000 characters. |
| `operations[].type` | `string` | no | add_node: node type, or statement word (c4 person, tree dir). at most 2000 characters. |
| `operations[].options` | `object` | no |  |
| `operations[].statement` | `string` | no | add_node: the whole line, for a kind with no plain node statement. at most 2000 characters. |
| `operations[].into` | `string \| null` | no | A block; null is the top level. at most 2000 characters. |
| `operations[].after` | `string` | no | at most 2000 characters. |
| `operations[].arrow` | `"<-->" \| "-->" \| "<->" \| "..>" \| "->" \| "--"` | no |  |
| `operations[].find` | `string` | no | at most 2000 characters. |
| `operations[].replace` | `string` | no | at most 2000 characters. |
| `operations[].all` | `boolean` | no |  |

## Responses

| Status | Meaning | Body |
|---|---|---|
| 200 | The revision, and what the action did. | [`BoardRevisionResult`](https://docs.plotwork.dev/api/schemas.md#boardrevisionresult) |
| 400 | The body is not valid, or names someone who is not a member of the organisation. | [`ErrorResponse`](https://docs.plotwork.dev/api/schemas.md#errorresponse) |
| 401 | Not signed in. | [`ErrorResponse`](https://docs.plotwork.dev/api/schemas.md#errorresponse) |
| 403 | Boards are not turned on for this organisation (boards.not_enabled), the caller may look but not change it (boards.forbidden), or the request came from an origin that may not make changes. | [`ErrorResponse`](https://docs.plotwork.dev/api/schemas.md#errorresponse) |
| 404 | No such organisation, board, tab or revision, or one not open to the caller (boards.revision_not_found): the cases look alike. | [`ErrorResponse`](https://docs.plotwork.dev/api/schemas.md#errorresponse) |
| 409 | The revision changed since the version sent (diagram.version_conflict), it is merged or discarded (boards.revision_closed), the tab has as many open revisions as it may (boards.revision_limit), or main and the revision changed the same statement (boards.merge_conflict, details.conflicts and details.mainVersion). | [`ErrorResponse`](https://docs.plotwork.dev/api/schemas.md#errorresponse) |
| 413 | The source is longer than a tab may be, or the board holds as much as it may. | [`ErrorResponse`](https://docs.plotwork.dev/api/schemas.md#errorresponse) |
| 422 | The source has errors (diagram.invalid), an edit did not apply (boards.operation_failed), or it holds something that looks like a secret and the organisation blocks them (boards.secret_blocked). | [`ErrorResponse`](https://docs.plotwork.dev/api/schemas.md#errorresponse) |
| 429 | Too many requests. | [`ErrorResponse`](https://docs.plotwork.dev/api/schemas.md#errorresponse) |
| 503 | Organisations or boards are not set up on this server. | [`ErrorResponse`](https://docs.plotwork.dev/api/schemas.md#errorresponse) |

## Response body

A 200 answer has the type [`BoardRevisionResult`](https://docs.plotwork.dev/api/schemas.md#boardrevisionresult).

| Field | Type | Required | Description |
|---|---|---|---|
| `changed` | `boolean` | yes |  |
| `revision` | `any` | yes |  |
| `revision.id` | `string` | yes | at least 12 characters; at most 12 characters; pattern `^[0-9A-Za-z]+$`. |
| `revision.tab` | `string` | yes |  |
| `revision.name` | `string` | yes |  |
| `revision.author` | `RevisionPerson` | yes |  |
| `revision.author.kind` | `"person" \| "agent" \| "key"` | yes |  |
| `revision.author.label` | `string` | yes |  |
| `revision.authorId` | `string \| null` | yes |  |
| `revision.visibility` | `"private" \| "board" \| "people"` | yes | private: the author only; board: everyone the board is open to; people: the author and the people named. |
| `revision.people` | `string[]` | yes | The account ids it is shared with by name. |
| `revision.status` | `"open" \| "pending" \| "merged" \| "discarded"` | yes | open, pending (a merge waits for approval), merged, or discarded. |
| `revision.baseVersion` | `integer` | yes | The main version it forked from, or was last updated from. |
| `revision.version` | `integer` | yes |  |
| `revision.behind` | `integer` | yes | Main versions made since baseVersion. |
| `revision.createdAt` | `integer` | yes |  |
| `revision.updatedAt` | `integer` | yes |  |
| `revision.updatedBy` | `RevisionPerson` | yes |  |
| `revision.updatedBy.kind` | `"person" \| "agent" \| "key"` | yes |  |
| `revision.updatedBy.label` | `string` | yes |  |
| `revision.readable` | `boolean` | yes | False for a private revision shown by its name only, to the people who manage the board. |
| `revision.mine` | `boolean` | yes |  |
| `revision.request` | `object \| null` | yes |  |
| `revision.request.by` | `RevisionPerson` | yes |  |
| `revision.request.at` | `integer` | yes |  |
| `revision.request.note` | `string \| null` | yes |  |
| `revision.review` | `object \| null` | yes |  |
| `revision.review.by` | `RevisionPerson` | yes |  |
| `revision.review.at` | `integer` | yes |  |
| `revision.review.comment` | `string \| null` | yes |  |
| `revision.mergedVersion` | `integer \| null` | yes |  |
| `revision.mergedBy` | `any` | yes |  |
| `revision.mergedBy.kind` | `"person" \| "agent" \| "key"` | yes |  |
| `revision.mergedBy.label` | `string` | yes |  |
| `revision.closedAt` | `integer \| null` | yes |  |
| `list` | `BoardRevisionList` | no |  |
| `list.mainVersion` | `integer` | yes |  |
| `list.protected` | `boolean` | yes | True when a merge into main needs the approval of a person who manages the board. |
| `list.revisions` | `BoardRevision[]` | yes |  |
| `list.revisions[].id` | `string` | yes | at least 12 characters; at most 12 characters; pattern `^[0-9A-Za-z]+$`. |
| `list.revisions[].tab` | `string` | yes |  |
| `list.revisions[].name` | `string` | yes |  |
| `list.revisions[].author` | `RevisionPerson` | yes |  |
| `list.revisions[].authorId` | `string \| null` | yes |  |
| `list.revisions[].visibility` | `"private" \| "board" \| "people"` | yes | private: the author only; board: everyone the board is open to; people: the author and the people named. |
| `list.revisions[].people` | `string[]` | yes | The account ids it is shared with by name. |
| `list.revisions[].status` | `"open" \| "pending" \| "merged" \| "discarded"` | yes | open, pending (a merge waits for approval), merged, or discarded. |
| `list.revisions[].baseVersion` | `integer` | yes | The main version it forked from, or was last updated from. |
| `list.revisions[].version` | `integer` | yes |  |
| `list.revisions[].behind` | `integer` | yes | Main versions made since baseVersion. |
| `list.revisions[].createdAt` | `integer` | yes |  |
| `list.revisions[].updatedAt` | `integer` | yes |  |
| `list.revisions[].updatedBy` | `RevisionPerson` | yes |  |
| `list.revisions[].readable` | `boolean` | yes | False for a private revision shown by its name only, to the people who manage the board. |
| `list.revisions[].mine` | `boolean` | yes |  |
| `list.revisions[].request` | `object \| null` | yes |  |
| `list.revisions[].review` | `object \| null` | yes |  |
| `list.revisions[].mergedVersion` | `integer \| null` | yes |  |
| `list.revisions[].mergedBy` | `any` | yes |  |
| `list.revisions[].closedAt` | `integer \| null` | yes |  |
| `list.hidden` | `integer` | yes | Open revisions the caller may not see. |
| `list.limit` | `integer` | yes | Open revisions a tab may have. |
| `source` | `string` | no |  |
| `results` | `object[]` | no |  |
| `results[].op` | `string` | yes |  |
| `results[].applied` | `boolean` | yes |  |
| `results[].lines` | `integer[]` | yes |  |
| `results[].message` | `string` | yes |  |
| `results[].hint` | `string \| null` | yes |  |
| `changes` | `object[]` | no |  |
| `changes[].change` | `string` | yes |  |
| `changes[].subject` | `string` | yes |  |
| `changes[].name` | `string` | yes |  |
| `changes[].line` | `integer \| null` | yes |  |
| `changes[].detail` | `string` | yes |  |
| `counts` | `object` | no |  |
| `counts.added` | `integer` | yes |  |
| `counts.removed` | `integer` | yes |  |
| `counts.renamed` | `integer` | yes |  |
| `counts.moved` | `integer` | yes |  |
| `counts.changed` | `integer` | yes |  |
| `warnings` | `Diagnostic[]` | no |  |
| `warnings[].code` | `"E100" \| "E101" \| "E110" \| "E111" \| "E120" \| "E121" \| "E123" \| "E124" \| "E125" \| "E130" \| "E131" \| "E132" \| "E133" \| "E134" \| "E135" \| "E136" \| "E137" \| "E138" \| "E139" \| "E140" \| "W200" \| "W201" \| "W202" \| "W203" \| "W204" \| "W205" \| "W206" \| "W207" \| "W208" \| "W500" \| "W600" \| "W601" \| "W700" \| "W701" \| "W702" \| "W703" \| "W704" \| "W705" \| "W706" \| "W707" \| "W708" \| "W709" \| "W710" \| "M100" \| "M101" \| "M102" \| "M103" \| "M104" \| "M110" \| "M200" \| "M201" \| "M202" \| "M203" \| "M204" \| "M205" \| "M206" \| "M207" \| "M208" \| "M209" \| "M210" \| "M211" \| "M212" \| "M213" \| "M214" \| "M215" \| "M216" \| "M217" \| "M218" \| "E300" \| "E301" \| "E302" \| "E303" \| "E304" \| "W300" \| "W301" \| "W302" \| "W303" \| "M120" \| "M220" \| "M221" \| "M222" \| "E340" \| "E341" \| "E342" \| "E343" \| "E344" \| "E345" \| "W320" \| "W321" \| "W322" \| "W323" \| "M240" \| "M241" \| "M242" \| "E360" \| "E361" \| "E362" \| "E363" \| "E364" \| "E365" \| "E366" \| "E367" \| "W330" \| "W331" \| "W332" \| "W333" \| "W334" \| "M250" \| "M251" \| "E400" \| "E401" \| "E402" \| "E403" \| "W350" \| "W351" \| "W352" \| "W353" \| "M270" \| "M271" \| "E420" \| "E421" \| "E422" \| "E423" \| "E424" \| "W360" \| "W361" \| "W362" \| "W363" \| "W364" \| "M180" \| "M280" \| "M281" \| "M282" \| "E320" \| "E321" \| "E322" \| "E323" \| "E324" \| "E325" \| "E326" \| "E327" \| "E328" \| "E329" \| "E330" \| "W310" \| "W311" \| "W312" \| "W313" \| "W314" \| "M130" \| "M131" \| "M132" \| "M230" \| "M231" \| "M232" \| "M233" \| "M234" \| "M235" \| "M236" \| "M237" \| "M238" \| "E380" \| "E381" \| "E382" \| "E383" \| "W340" \| "W341" \| "W342" \| "W343" \| "M260" \| "I100" \| "I101" \| "I102" \| "I103" \| "I104" \| "I105" \| "I200" \| "I201" \| "I202" \| "I203" \| "I204" \| "I206" \| "R100" \| "R101" \| "R200" \| "R201" \| "R202" \| "R203" \| "R204" \| "R205" \| "R206" \| "R207" \| "S100" \| "S200" \| "S101" \| "S102" \| "S103" \| "S104" \| "S201" \| "S202" \| "S203" \| "S204"` | yes | Stable code to branch on; E-codes are errors, W-codes are warnings. |
| `warnings[].severity` | `"error" \| "warning"` | yes | Errors stop rendering; warnings never do. |
| `warnings[].message` | `string` | yes | What is wrong, in one sentence. |
| `warnings[].line` | `integer` | yes | 1-based line in the submitted source. minimum 1. |
| `warnings[].column` | `integer` | yes | 1-based column in that line. minimum 1. |
| `warnings[].length` | `integer` | yes | Number of characters the problem covers. minimum 1. |
| `warnings[].hint` | `string \| null` | yes | A concrete suggestion for fixing it, or null. |
| `secrets` | `object` | no |  |
| `secrets.count` | `integer` | yes |  |
| `secrets.kinds` | `string[]` | yes |  |
| `entries` | `object[]` | no |  |
| `entries[].version` | `integer` | yes |  |
| `entries[].type` | `string` | yes |  |
| `entries[].actor` | `RevisionPerson` | yes |  |
| `entries[].actor.kind` | `"person" \| "agent" \| "key"` | yes |  |
| `entries[].actor.label` | `string` | yes |  |
| `entries[].counts` | `object` | yes |  |
| `entries[].counts.added` | `integer` | yes |  |
| `entries[].counts.removed` | `integer` | yes |  |
| `entries[].counts.renamed` | `integer` | yes |  |
| `entries[].counts.moved` | `integer` | yes |  |
| `entries[].counts.changed` | `integer` | yes |  |
| `entries[].at` | `integer` | yes |  |
| `compare` | `BoardRevisionCompare` | no |  |
| `compare.mainVersion` | `integer` | yes |  |
| `compare.version` | `integer` | yes |  |
| `compare.behind` | `integer` | yes |  |
| `compare.same` | `boolean` | yes |  |
| `compare.counts` | `object` | yes |  |
| `compare.counts.added` | `integer` | yes |  |
| `compare.counts.removed` | `integer` | yes |  |
| `compare.counts.renamed` | `integer` | yes |  |
| `compare.counts.moved` | `integer` | yes |  |
| `compare.counts.changed` | `integer` | yes |  |
| `compare.changes` | `object[]` | yes |  |
| `compare.changes[].change` | `string` | yes |  |
| `compare.changes[].subject` | `string` | yes |  |
| `compare.changes[].name` | `string` | yes |  |
| `compare.changes[].line` | `integer \| null` | yes |  |
| `compare.changes[].detail` | `string` | yes |  |
| `compare.truncated` | `boolean` | yes |  |
| `compare.summary` | `string` | yes |  |
| `compare.conflicts` | `BoardMergeConflict[]` | yes |  |
| `compare.conflicts[].key` | `string` | yes | The statement: its id, its label in quotes, or an edge by its ends. A resolution names it. |
| `compare.conflicts[].subject` | `string` | yes |  |
| `compare.conflicts[].base` | `string \| null` | yes |  |
| `compare.conflicts[].main` | `string \| null` | yes |  |
| `compare.conflicts[].revision` | `string \| null` | yes |  |
| `compare.mergeable` | `boolean` | yes |  |
| `compare.main` | `string` | yes | Main's source now. |
| `compare.merged` | `string \| null` | yes | Main as the merge would leave it; null while a conflict is open. |
| `compare.revision` | `string` | yes |  |
| `merge` | `object` | no |  |
| `merge.status` | `"merged" \| "pending"` | yes |  |
| `merge.mainVersion` | `integer` | yes |  |
| `merge.method` | `"same" \| "fast-forward" \| "replay" \| "statements" \| null` | yes |  |
| `sent` | `integer` | no |  |

## See also

| Doc | Why |
|---|---|
| [API reference](https://docs.plotwork.dev/api/reference.md) | Every endpoint, and the error envelope |
| [Schemas](https://docs.plotwork.dev/api/schemas.md) | Every request and response type |
| [Tool reference](https://docs.plotwork.dev/mcp/tools.md) | The operations as callable tools |
