This is the complete reference for the edits array of POST /v1/edit.
Each edit is a JSON object with a type and the fields that type defines. Unknown fields are
refused, and edits are applied in request order. The full machine-readable definition of each
edit is in the API's OpenAPI specification under components.schemas.EditRequest.
Edits name the things they act on by locators, and the locators come from the document content:
the response of GET /v1/files/{file_id}/content?format=json. Read that first and copy the
locators it prints instead of computing them. How a request is applied
says how several edits in one request combine.
Operations at a glance
| Operation | Changes | Names | Tracked |
|---|---|---|---|
insert | new text, breaks, fields, cross-references, notes and links at a point | paragraphs and a point | yes; a cross-reference's bookmark, a new notes part and note styles are not |
replace, delete | text, or a page break | paragraphs and a selector | yes |
format | character formatting | paragraphs, and optionally a selector | yes |
insert_paragraphs | new paragraphs | a destination | yes; a new list's definitions are not |
delete_paragraphs | whole paragraphs, and tables a range covers | paragraphs | yes |
move_paragraphs | where paragraphs and tables are | paragraphs and a destination | yes |
split_paragraph | one paragraph into two | a paragraph and a point | yes |
join_paragraphs | a range of paragraphs into one | a range | yes |
set_paragraph_style | paragraph style | paragraphs | yes |
set_paragraph_format | alignment, indents, spacing, pagination | paragraphs | yes |
set_numbering | list numbering | paragraphs | yes; new list instances and definitions are not |
insert_section_break | a new section break | the paragraph that ends the section | yes |
remove_section_break | a section break | a section | yes |
set_page_setup | orientation, paper, margins, first page, page numbering | sections | yes |
add_header_footer | a new header or footer | a section | its content; the new part and its reference are not |
insert_table | a new table | a destination | yes |
delete_table | a table | a table | yes |
insert_table_row, delete_table_row | a row | a row | yes |
insert_table_column, delete_table_column | a column | a column | yes |
add_hyperlink | a link on existing text | a paragraph, and optionally a selector | yes |
set_hyperlink, remove_hyperlink | a link's address, or the link | a paragraph, and optionally a selector | yes |
refresh_fields | when Word updates fields | nothing | no |
insert_table_of_contents | a new table of contents | a destination | yes; its update-on-open flags are not |
delete_note | a footnote or endnote | a note | yes |
add_comment | a new comment | a paragraph or range, and optionally a selector | no: a comment is an annotation |
reply_comment, resolve_comment | a comment thread | a comment | no |
accept_revision, reject_revision | existing tracked changes | revisions | settles them |
set_document_settings | Track Changes, editing restriction, personal information | nothing | no |
Tracked and untracked
Every change to document content is a real Word tracked change carrying the request's author
and date: the redline shows it for review, the clean copy accepts it, and accept_revision
or reject_revision decides it like any other revision. What Word cannot track is applied
directly, to both outputs, and stays when revisions are accepted or rejected:
set_document_settings: the settings it names (w:trackRevisions,w:documentProtection,w:removePersonalInformation) and the file properties' author names.refresh_fieldsandinsert_table_of_contents: fields'w:dirtyflags andw:updateFieldsin the settings. The table of contents' paragraph is tracked.- Comments from
add_comment,reply_commentandresolve_comment: annotations, not revisions. - New list instances (
w:num) and definitions (w:abstractNum), andnumbering.xmlwhen the document has none, thatset_numberingandinsert_paragraphslists need. The paragraphs that use them change as tracked changes. - A
cross_referencerun: the hidden_Refbookmark on the paragraph pointed to, when it has none. - A
footnoteorendnoterun: the notes part, with Word's separator notes, and the note styles, when the document lacks them. add_hyperlinkandhyperlinkruns: the Hyperlink character style, when the document lacks one.add_header_footer: the new header or footer part and the section's reference to it; its content is tracked.
Locators
Everything an edit names is a locator object, never a bare number. The document content prints every locator, so you copy locators instead of computing them.
Paragraph locators
{"index": 12} // body paragraph 12
{"part": {"kind": "footnote", "number": 3}, "index": 0} // first paragraph of footnote 3
{"part": {"kind": "header", "type": "first", "section": {"number": 2}}, "index": 0}
{"part": {"ref": "fn1"}, "index": 0} // a note or header this request creates
{"ref": "p1"} // a paragraph this request createsindex. It counts the paragraphs of a part from 0, in the order the document content lists them, including paragraphs in table cells.- Tracked text. The document is seen as the content shows it: tracked insertions are included and tracked deletions left out. A paragraph whose mark is a tracked deletion is still listed and counted.
- Parts.
kindisbody(the default whenpartis omitted),footnote,endnote,headerorfooter.- A note's
numberis its position among notes of its kind, in document order. That isn't the mark the reader sees, which can be custom or restart per section. The document content prints both, asnumberandlabel. - A header or footer has a
type(default,firstoreven) and asectionlocator. Together they name the part that section's pages show. - A part that several sections show through Word's linking is one part. The document content prints it once, with its canonical locator (the first section that shows it) and every section that shows it. A locator naming any of those sections reaches the same part.
- Editing a shared part changes every section that shows it; the content's
sectionssays which. - A section that
insert_section_breakcreates shows the same parts as the section it was split from, as in Word, so its header locator reaches those parts. - Even-page headers and footers that already exist can be edited but not created. Creating one needs the document-wide even-and-odd setting, which would leave every other section's even pages blank.
- Out of reach. Text boxes and comment bodies have no locator, and
"all"doesn't reach them. When an edit over"all"leaves out a text box holding text it would otherwise have acted on, nothing reports it. Content controls sit inside paragraphs, so their text is ordinary paragraph text.
Other locators
| Names | Locator |
|---|---|
| a section | {"number": 2}; set_page_setup also takes an array of section locators, or "all" |
| a table | {"number": 2}: the tables of a part in document order, an outer table before the tables nested in it. Body is the default; a table elsewhere adds part |
| a row or column | {"table": {"number": 2}, "number": 4}, or a paragraph locator inside one of its cells ({"index": 142}), which names the row or column of the innermost table holding that paragraph. Columns count grid columns, and a paragraph in a cell that spans several grid columns can't name a column |
| a comment thread | {"number": 3}: top-level threads in document order. Replies aren't counted, since replying and resolving act on a thread |
| a note | {"kind": "footnote", "number": 3} |
| revisions | {"number": 5}, one entry of the document content's revisions; "all"; or a filter {"author": "...", "kind": "insertion"} where both keys are optional and kind is insertion, deletion, move or property. property covers every formatting, paragraph, numbering, table and section property change |
Any locator may instead be {"ref": "..."}, which names something this request creates
(Refs).
Counting
index is the only value counted from 0, because it is a position in the content's arrays.
Everything else counts from 1, as a reader counts: note, comment, revision, section, table,
row and column numbers; occurrence; list level (1 to 9, as Word's interface shows it), so
pattern writes level 3 as %3; and table-of-contents heading levels.
The paragraphs field
Every operation that acts on paragraphs names them in one required field, paragraphs:
| Form | Names |
|---|---|
| a locator | that paragraph |
{"from": locator, "through": locator} | the uploaded paragraphs between the two, inclusive, in document order, within one part. A range of refs from one insert_paragraphs names those new paragraphs |
| an array of locators and ranges | each of them; a paragraph named twice counts once |
"all" | every paragraph of every part (body, headers, footers, footnotes, endnotes) |
{"all": true, "part": {...}} | every paragraph of the matching parts; a part with only kind matches every part of that kind. part is required in this form |
- No implicit scope. A whole-document
replacesays"paragraphs": "all". - Only uploaded paragraphs. The
"all"forms, and ranges between uploaded locators, name uploaded paragraphs only (How a request is applied). - Ranges and tables.
- A range that covers a whole table includes the table, so moving or deleting the range moves or deletes the table.
- A range for
delete_paragraphs,move_paragraphsorjoin_paragraphsthat covers only part of a table is refused, whichever end is inside it. So is one that spans more than one cell. A range wholly inside one cell is fine. - Deleting every paragraph of a cell is refused.
- How many.
split_paragraph,add_hyperlink,set_hyperlinkandremove_hyperlinktake exactly one locator, since a Word hyperlink can't cross paragraphs.add_commenttakes one locator or one range; a range makes one comment spanning it.join_paragraphstakes one range.
Destinations
insert_paragraphs, move_paragraphs, insert_table and insert_table_of_contents place
content with "destination": {"paragraph": locator, "position": "before" | "after"}.
- A destination at a paragraph in a table cell places the content in that cell. An
insert_tablethere makes a nested table. {"table": locator, "position": "before" | "after"}places content directly before or after a table.- Content placed after one paragraph or table comes before content placed before the next one.
insert_table_rowuses{"row": locator, "position": ...}, andinsert_table_columnuses{"column": locator, "position": ...}.
Refs
An edit that creates something can carry "ref": "<name>", and later edits use
{"ref": "<name>"} wherever that kind of locator is expected. Ref names form one namespace per
request, and each is defined once, before it is used.
| Created by | Names |
|---|---|
new_paragraphs items | the new paragraph |
split_paragraph | the second half |
insert_section_break | the new section after the break; the original {"number": N} still names the section before it |
insert_table, insert_table_row, insert_table_column | the new table, row or column |
add_header_footer | the new part: {"part": {"ref": "hdr1"}, "index": 0} |
| note runs | the new note: {"part": {"ref": "fn1"}, "index": 0} |
add_comment | the new thread: reply_comment with "comment": {"ref": "c1"} |
Selecting text
text selects text in the named paragraphs, and at names an insertion point:
"text": {"match": "Series A Preferred Stock", "prefix": "the ", "suffix": " issued", "occurrence": 2}
"at": "start" | "end"
"at": {"after": {"match": "Name:\t"}} // a selector: prefix, suffix and occurrence apply
"at": {"before": {"match": "Exhibit"}}insert and split_paragraph take at. An insert applies once at each point it names: with
"start" or "end", once per named paragraph; with a selector, once per match.
- What it matches. A selector matches only the uploaded text of the named paragraphs, and a match never crosses a paragraph boundary.
- Matching rules.
- Matching is case-sensitive.
- In a
matchstring,\tmatches a tab run and\na line break. - These characters are read alike: a non-breaking, thin or hair space and a space; curly and
straight quotes; en and em dashes and a hyphen; a character with a one-character Unicode
compatibility form and that form. Nothing else is folded (
…is not...).
- Run form. A
matchis a string or an array of runs. The run form is for content with no characters:[{"type": "break", "kind": "page"}]matches a page break, fordeleteonly, withoutprefixorsuffix. prefixandsuffix. Optional text that must sit immediately before and after the match. They filter the candidates before counting, and the edit never acts on them.occurrence. It counts across every paragraph the edit names, in document order: the body; for each section in turn, its header then its footer, each in the orderdefault,first,even; footnotes; endnotes. A shared part counts once, at its canonical section.- Omitted: the match must be unique across them.
N: the Nth match, for example the second "Acme" in the document with"paragraphs": "all"."all": every match. At least one must exist.
- Character ranges are half-open. Two that touch end to end don't overlap.
- One match when an edit creates something.
add_comment,add_hyperlink,set_hyperlink,remove_hyperlinkandsplit_paragraphmust select exactly one range or point.- So must an
insertwhosecontentholds a note run with aref. split_paragraphat"start"or"end"is refused, since it would make an empty paragraph. Useinsert_paragraphsfor that.add_hyperlinkover text that is already linked is refused. Useset_hyperlink.
- Required or optional.
deleteandreplacerequiretext.format,add_commentandadd_hyperlinkwithouttextact on the whole paragraph.set_hyperlinkandremove_hyperlinkwithouttextact on the paragraph's only hyperlink.
- New content. Text in a paragraph this request creates can't be selected, since it isn't in the document content. The paragraph itself can be named by ref for paragraph-level edits. New sections, tables, rows, columns, notes and comments can be named by ref by any edit that takes that kind of locator.
- Hidden content. Note references, comment anchors, bookmarks and images are skipped by
matching, so
"409A."matches across a footnote mark between "409A" and ".". Areplaceordeletewhose range would contain a note reference or image is refused. Comment anchors and bookmarks stay in place. - Field results. A field's computed result counts as text, as the document content shows
it, and can anchor a selector, but a
replace,deleteorformatrange holding part of a result, and an insertion point strictly inside one, are refused, since updating the field would undo the edit; edit the field's target instead. A range holding a whole result, such as "Section 1.3 below" where "1.3" is aREFresult, removes the field and is accepted. AHYPERLINKfield's result is ordinary link text. - Splits and joins. A split or join doesn't change what a selector sees. Text is selected through the uploaded paragraph that held it: the original locator of a split paragraph, or the merged-in paragraph's own locator.
A selector that matches nothing, or more than once without occurrence, is refused naming the
count and, when the text is elsewhere, the paragraphs holding it:
edit at index 0 (replace): "Preferred" matches 3 times in paragraph 8; give prefix or suffix
so it matches once, or occurrence (1 to 3, or "all")Signature lines
A signature line is usually a label, a plain tab to where the line starts, and an underlined
tab drawing the line to the next tab stop ("Name:", tab, underlined tab). Insert the value
after the label's tab, "at": {"after": {"match": "Name:\t"}}: it takes the plain tab's
formatting and the underlined tab still draws the rest of the line. To have the value replace
the line, replace the underlined tab: "text": {"match": "\t", "prefix": "Name:\t"}. The new
text takes the tab's formatting, underlined; a run with "format": {"underline": false} gives
plain text.
Content
New text is always content: in insert, replace, add_comment, reply_comment and
add_header_footer, in note runs, in table cells and in new_paragraphs items. content is a
string or an array of runs, in the shapes the document content uses.
| Run | Inserts |
|---|---|
{"text": "..."} | text |
{"type": "tab"} | a tab |
{"type": "break", "kind": "line" | "page" | "column"} | a break; page and column breaks only in the body and its tables |
{"type": "field", "code": "PAGE"} | a field (Field and cross-reference runs) |
{"type": "cross_reference", "to": locator, "show": "text" | "number" | "page" | "above_below"} | a reference to a paragraph |
{"type": "footnote" | "endnote", "content": ...} or {..., "new_paragraphs": [{"content": ...}]} | a note, with one paragraph or several (Note runs) |
{"type": "hyperlink", "url": "...", "content": ...} | new linked text |
- Any run can carry
format(Property values). A note run can carry aref. - In a
contentstring or a text run,\tbecomes a tab run and\na line break. New paragraphs come only frominsert_paragraphs,split_paragraphand thenew_paragraphsforms. - A table cell's value is
content(one paragraph) or{"new_paragraphs": [...]}, whose items areinsert_paragraphsitems. - A comment's
content(add_comment,reply_comment) is one paragraph: a string, or text, tab and line-break runs. Other runs are refused. replacerequires non-emptycontent. Removing text is adelete.- Plain new text takes the formatting of the text before it, or of the text after it at a
paragraph's start, as typing does in Word; in an empty paragraph, the paragraph mark's. A
replace's plaincontenttakes the formatting of the first character it replaces. - Text an edit writes may not hold a control character other than tab, newline and carriage return, nor U+FFFE or U+FFFF, which a Word document cannot store.
Naming rules
- Reserved keys.
type,textandatare reserved among an edit's keys. Inside a run,typeis the run's type andtextits characters, as in the document content. - Property objects. As a key,
formatalways holds a character-format object. Paragraph properties nest underparagraph_formatand page properties underpage_setup, the same objects the document content returns. - Field names. Styles are named by
style_id.insert_paragraphstakesnew_paragraphs, becauseparagraphsis a locator field. - Operation names.
insert_*places new content at a position, andadd_*attaches something to existing content.delete*removes content, andremove_*unwraps something and keeps its content. - Enums. Every enum value is snake_case:
lower_roman,next_page,at_least.
Property values
For every property in format, paragraph_format and page_setup:
| Value | Effect |
|---|---|
| a value | sets the property |
false | turns it off, even where the style turns it on |
null | removes the direct setting, so the style decides |
| key omitted | leaves the property alone |
- Toggles.
bold,italic,small_caps,keep_with_nextand the like taketrue,falseornull. - Enums with an off state.
underline,highlightandstriketake an enum value,falsefor off, ornull.truemeans"single"forunderlineandstrike; it is refused forhighlight. - Everything else. Other properties take a value or
null. - Page setup. A section has no style for
nullto fall back to, so inpage_setuponlydifferent_first_pageandpage_numbering(and its fields) takenull. - Nested objects merge field by field.
- For example,
{"indent": {"left": 108}}keeps the paragraph's other direct indent values. - Setting
first_lineremoveshanging, and settinghangingremovesfirst_line. nullfor a whole object ("indent": null) removes all of its direct values.- The same merge applies to
margins,spacing(which holdsbefore,afterandline_spacing),page_numberingandsettings. line_spacingis one value in one of three forms ({"multiple": 1.15},{"exact": 14}or{"at_least": 14}), so it is replaced whole.
- For example,
- Whole paragraphs. A
formatwithouttextformats the paragraph mark too, as selecting a whole paragraph in Word does. - Removing everywhere. To "remove X everywhere", send
false.nullonly removes direct formatting, so a heading that is bold through its style would stay bold. - Units. Indents, spacing, margins, paper size and
font_sizeare in points.
How a request is applied
Three rules:
- Addresses mean the document as you read it. Every locator and selector refers to the uploaded document, the one the document content described, whatever earlier edits in the request have done.
- Edits apply in request order. When two edits set the same property of the same text or paragraph, the later one wins.
- An edit whose target an earlier edit removed or rewrote is refused, and so is the whole request.
The result is the same as sending each edit as its own request in turn, except that every
edit's addresses come from the one read of the document. The request is all or nothing: if any
edit is refused, or fails while being applied, nothing is applied and no file is produced.
Decisions on existing tracked changes (accept_revision, reject_revision) go alone: a
request that contains one contains only decisions. To accept changes and then edit, send two
requests, the second against the first's result. See Edit for the
request and response around the edits array.
Addresses
- Indexes don't shift. If edit 1 inserts a paragraph after paragraph 5, edit 2's
{"index": 10}still means the paragraph the document content called 10, now eleventh in the document. - Positions don't shift. A selector matches the uploaded text of the paragraphs it names. Text that earlier edits inserted is never matched; text they removed can't be matched (rule 3).
- Wide forms.
"all",{"all": ...}, ranges and arrays name uploaded paragraphs. Paragraphs an earlier edit removed are skipped. - Refs name what an earlier edit created. A ref used before the edit that creates it is
refused. A new paragraph can be named by ref for paragraph-level edits:
set_paragraph_style,set_paragraph_format,set_numbering,formatwithouttext,add_commentwithouttext,insertat"start"or"end", and as adestinationor cross-referenceto. Its text can't be selected, since it isn't in the document content; give it its formatting in the creating edit, or format the whole paragraph. - Moved paragraphs. A locator for a paragraph that an earlier edit moved still names it, in its new place. A destination at it places content next to its new place.
- Split paragraphs. The original locator names both halves for paragraph-level edits. Its text is selected through the original locator. The second half can also be named by the split's ref.
- Joined paragraphs. A paragraph that an earlier
join_paragraphsmerged away can't be named for paragraph-level edits. Its text is still selected through its own locator, since joining keeps the text. - Deleted paragraphs as destinations. A destination at a paragraph an earlier edit deleted places the content where that paragraph was.
style_templatestyles are imported before the first edit.- Field results are computed after the last edit, so a new table of contents or
cross-reference reflects the edited document.
refresh_fieldsdoes the same for existing fields. Results that need page layout are those the field tables below say the API can compute; any others are marked for Word to update on open.
Order
- Later wins. "Unbold everything" then "bold Purchase Price" leaves only Purchase Price bold. Listed the other way round, everything ends up unbolded.
- Lists and indents. The indent a list level brings never overrides a direct
indent, in either order, as in Word. - Same position. Content inserted at the same point appears in request order, across
operation types.
- A
replaceputs its new text at the start of its range, so aninsertat that point and the replacement come out in request order. - An insert at the end of a replaced or deleted range goes after it.
- Two destinations are the same point only when they name the same paragraph or table and position. Content placed after one paragraph or table comes before content placed before the next one.
- Content placed after the paragraph holding a new section break goes into the new section.
- A
- Comments. Comments added to the same range, and replies to one thread, appear in request
order. A comment's range follows its text, so a later
replaceinside it leaves the deleted and the new text inside the comment. - Revision decisions apply in request order too, and the later decision wins for a
revision. "Reject everything, then accept author A's" is
reject_revisionwith"all", thenaccept_revisionwith{"author": "A"}.
Positions
- Points. An insertion point is a position in the uploaded text.
"start"is before everything in the paragraph, and"end"after everything, hidden content included. - Hidden content. Matching skips note references, comment anchors, bookmarks and tracked
deletions, so a point next to them needs a side.
- A point after a match sits immediately after its last character, before any hidden content.
- A point before a match sits immediately before its first character, after any hidden content.
- In a paragraph ending in a footnote mark, after the last word and
"end"are different points.
- Formatting of plain new text. See Content.
- Clearing never deletes characters. A leading tab is removed with a
delete. - New table cells copy the paragraph and run formatting of a neighbouring cell. A new row copies the row above (or below, for a new first row), and a new column copies the column to the left (or right, for a new first column).
Refused
Every refusal in a request is reported together, naming the edits involved.
Rule 3: the target is gone or rewritten.
| An edit that... | after an earlier edit... |
|---|---|
selects text (text or an at anchor; prefix and suffix excluded) overlapping characters | replaced or deleted them |
| has an insertion point strictly inside a range | replaced or deleted that range |
| names a paragraph for a paragraph-level edit, or as a destination | merged it away with join_paragraphs, or deleted it (except as a destination, above) |
| names a table, row, column, section or note | deleted it, or removed the section's break |
has an insertion point at a split point, or a replace or delete crossing one | split the paragraph there |
| splits inside a range | replaced or deleted that range |
| names a header or footer through a section that now shows a different part | added a header or footer with add_header_footer (name the new part by its ref) |
prefix and suffix only check context, so they may overlap text an earlier edit changed.
Refused in any order.
| Combination | Why |
|---|---|
A replace, delete, insert or format inside a field result | Updating the field would undo it. Edit the field's target instead |
Two add_hyperlink ranges that overlap | Word can't nest hyperlinks |
A move_paragraphs whose destination is inside the paragraphs it moves | The destination moves with them |
| A row insert inside a vertically merged span, or a column insert or delete through a cell spanning several grid columns | The grid can't keep or split the merge |
| Selecting text in a paragraph this request creates | It isn't in the document content. Describe it in the creating edit |
A ref on something an edit would create more than once | It couldn't name one thing |
Text
insert
insert puts content at at in each named paragraph: once per paragraph with "start" or
"end", once per match with a selector. Inserted content is a tracked insertion (w:ins);
accepting keeps it and rejecting removes it.
{"type": "insert", "paragraphs": {"index": 304}, "at": {"after": {"match": "Name:\t"}}, "content": "Jordan Bryan"}
{"type": "insert", "paragraphs": {"index": 27}, "at": "start", "content": "2026"}
{"type": "insert", "paragraphs": {"index": 31}, "at": {"after": {"match": "Signature:"}},
"content": [{"type": "tab", "format": {"underline": true}}, {"type": "break", "kind": "line"},
{"text": "Name and title", "format": {"bold": true}}]}
{"type": "insert", "paragraphs": {"index": 9}, "at": {"after": {"match": "See "}},
"content": [{"type": "hyperlink", "url": "https://example.com/schedule-a", "content": "Schedule A"}]}To fill an empty paragraph, insert at "start". A break is a run holding w:br (a line break
has no type; w:type="page" or "column") and a tab one holding w:tab, inside the
insertion. A hyperlink run is written as a HYPERLINK field, the form in which Word can
track a link, in one w:ins.
Page breaks
A page break is a break run of kind page. Insert one with insert, and remove one with
delete whose match is that run (with occurrence when the paragraph holds several). Each
is tracked: the break's run in w:ins, or in w:del split from any text sharing it. A
paragraph that starts a new page through page_break_before holds no break:
set_paragraph_format with "page_break_before": false removes the
property. Turning a page break into a section break that restarts page numbering is three
edits:
[{"type": "delete", "paragraphs": {"index": 129}, "text": {"match": [{"type": "break", "kind": "page"}]}},
{"type": "insert_section_break", "paragraphs": {"index": 129}, "section_type": "next_page", "ref": "schedule"},
{"type": "set_page_setup", "section": {"ref": "schedule"}, "page_setup": {"page_numbering": {"start": 1}}}]Inserting one:
{"type": "insert", "paragraphs": {"index": 42}, "at": "start", "content": [{"type": "break", "kind": "page"}]}A page or column break goes in the body and its tables only: Word offers neither in a header, footer, note or text box.
replace and delete
replace deletes the selected text and inserts content (required, non-empty) at the start of
its range; delete deletes it. Deleted text is a tracked deletion (w:del), new text a
tracked insertion.
{"type": "replace", "paragraphs": {"index": 8}, "text": {"match": "Preferred", "prefix": "other Series A "}, "content": "Common"}
{"type": "replace", "paragraphs": "all", "text": {"match": "Acme Ltd", "occurrence": "all"}, "content": "Acme Holdings Ltd"}
{"type": "delete", "paragraphs": {"index": 71}, "text": {"match": "[", "occurrence": "all"}}A replace or delete whose text isn't in the named paragraphs is refused, naming the
paragraphs where the text is. A page break is removed with delete; replace can't select
one.
format
format changes the character formatting of the selected text, or of whole paragraphs, marks
included, without text. The text is split into runs of its own, each recording its previous
formatting in a w:rPrChange, a tracked formatting change: the redline shows "Formatted"
changes and the clean copy keeps the new formatting.
{"type": "format", "paragraphs": {"index": 12}, "text": {"match": "Effective Date"}, "format": {"bold": true, "highlight": "yellow"}}
{"type": "format", "paragraphs": "all", "format": {"bold": false}}format property | Values |
|---|---|
bold, italic, small_caps, all_caps, superscript, subscript | true, false or null |
underline | true (single), single, double, thick, dotted, dash, wave, words, false or null |
strike | true (single), single, double, false or null |
highlight | a Word highlight color (yellow, green, cyan, magenta, blue, red, darkBlue, ..., lightGray), false or null |
color | six hex digits (1F3864), or null |
font_size | points, in halves (10.5), or null |
font | a font family name, or null |
At least one property is required, and superscript and subscript cannot both be true. The
document content reads formatting back in the same terms: each text segment's format holds
the properties above that the text has through its styles; color, font_size and font
appear where they differ from the document's default text formatting.
Paragraphs
insert_paragraphs
insert_paragraphs places new_paragraphs at a destination, each item a Word paragraph in
array order and a tracked insertion of its text and paragraph mark.
{"type": "insert_paragraphs", "destination": {"paragraph": {"index": 24}, "position": "after"},
"style_id": "Normal", "list": {"new": "bulleted"}, "paragraph_format": {"indent": {"left": 108, "hanging": 18}},
"new_paragraphs": [{"content": "Constitutional Amendments.", "style_id": "Heading3", "list": null},
{"content": "First Amendment (1791): freedom of religion and speech"},
{"content": [{"text": "Second Amendment", "format": {"italic": true}}, {"text": " (1791)"}], "ref": "second"}]}- Items. Each takes
content(omitted, an empty paragraph) and, optionally,style_id,paragraph_format,list,level(1 to 9) andref. - Operation-level values.
style_id,paragraph_format,listandlevelon the edit apply to items that don't set their own; an item'sparagraph_formatmerges over the operation's. With no style from either, the document's default paragraph style applies. list.{"new": "bulleted" | "numbered"}on the edit makes its items one new list; on an item it starts a list of its own.{"same_as": locator}joins an existing list. An item's"list": nullleaves it out of the operation's list, so its style's numbering, if any, applies;falsegives it no numbering.leveldefaults to the operation's, else thesame_asparagraph's, else 1.
A destination is a paragraph directly in the body or a table cell. A missing paragraph style
fails the edit with INVALID_EDIT. For Markdown input, parse it in the client and send each
paragraph's text, runs and style; .md and .txt uploads are unsupported, so start from a
blank DOCX.
delete_paragraphs
delete_paragraphs deletes whole paragraphs as tracked deletions of their text and paragraph
marks, so accepting it leaves the following paragraph exactly as it was. A range covering a
whole table deletes the table's rows as tracked row deletions.
{"type": "delete_paragraphs", "paragraphs": [{"from": {"index": 9}, "through": {"index": 11}}, {"index": 171}]}Refused: a range covering part of a table or more than one of its cells; every paragraph of a
cell (delete the row, column or table); the last paragraph of the document, a header, a footer
or a note (delete its text with delete); a paragraph that ends a section; and paragraphs that
are all that keeps two tables apart, since Word joins tables that touch.
move_paragraphs
move_paragraphs moves paragraphs, marks included, to a destination as a Word tracked move. A
range covering whole tables moves them too: Word can't track a table move, so the table's rows
are deleted where they were and an inserted copy, keeping the ids, goes to the destination.
{"type": "move_paragraphs", "paragraphs": {"from": {"index": 9}, "through": {"index": 11}},
"destination": {"paragraph": {"index": 19}, "position": "after"}}At the old place a copy of each paragraph stays as moved-from content (w:moveFrom, between
w:moveFromRangeStart and w:moveFromRangeEnd); at the destination the paragraphs themselves,
keeping their ids, are moved-to content (w:moveTo), the two ranges sharing one w:name.
Accepting leaves the paragraphs at the destination only; rejecting restores them, and the
copies have new ids. Deciding either half decides the whole move. A moved footnote or endnote
reference refers to a new note holding the note's paragraphs, marked inserted, while the old
note's text is marked deleted; deciding the move decides them, so each note is in the document
once either way. Bookmark and comment anchors inside the moved paragraphs move with them; a
bookmark reaching outside them that no field or hyperlink names keeps its inside end at the old
place.
Refused: a destination among the moved paragraphs, where they already are, or after the last
paragraph of the body or a cell; paragraphs outside the body and its tables; a range covering
part of a table; moving the last paragraph of the body or a cell, a paragraph that ends a
section, or paragraphs that keep two tables apart; moved paragraphs or their notes holding
tracked changes, pictures, embedded objects, content controls, permission ranges, or a field
that fetches or runs content (INCLUDETEXT, INCLUDE, INCLUDEPICTURE, DDE, DDEAUTO,
IMPORT, LINK, MACROBUTTON, DATABASE, RD); part of a field or comment reaching outside
them; and a moved table holding tracked changes, notes, comments or bookmarks.
split_paragraph
split_paragraph ends a paragraph at one point with a new paragraph mark, as pressing Enter
does. at is a selector matching once; "start" and "end" are refused (use
insert_paragraphs). ref names the second half.
{"type": "split_paragraph", "paragraphs": {"index": 12}, "at": {"after": {"match": "as follows:"}}, "ref": "rest"}The split is tracked as an inserted paragraph mark (w:pPr/w:rPr/w:ins) ending the first
half, which keeps the paragraph's id; the second half has a new id. Both keep the paragraph's
properties, and the second half takes the original mark with what it carries (a section break,
the mark's formatting). Accepting keeps two paragraphs; rejecting merges them back. The
original locator names both halves for paragraph-level edits. A point inside a hyperlink, a
field, a content control or a tracked change fails the edit with INVALID_EDIT.
join_paragraphs
join_paragraphs merges a range of paragraphs into its first, as deleting the pilcrows does in
Word.
{"type": "join_paragraphs", "paragraphs": {"from": {"index": 40}, "through": {"index": 41}}}Each join is tracked as a deleted paragraph mark (w:pPr/w:rPr/w:del). The joined paragraph
keeps the first paragraph's properties: where a following paragraph's differ, they change as a
tracked property change (w:pPrChange). Accepting leaves one paragraph; rejecting restores
them. Refused: a range of fewer than two paragraphs, across table cells or partly in a table; a
paragraph ending a section, one whose mark is already deleted, or one followed by a table.
set_paragraph_style
set_paragraph_style gives paragraphs a paragraph style of the document or of the
style_template. clear takes any of typography, numbering and paragraph, or "all".
{"type": "set_paragraph_style", "paragraphs": [{"index": 3}, {"from": {"index": 5}, "through": {"index": 9}}],
"style_id": "Heading3", "clear": "all"}typography: direct font family (theme fonts included), size, colour and character spacing. Bold, italics, underline, caps, highlight and character styles are kept.numbering: direct list numbering.paragraph: spacing, indentation, alignment, tab stops and outline level. Pagination and section boundaries are kept.
Anything outside those three categories, such as borders and shading, is kept.
The style and the cleared paragraph properties are one tracked paragraph property change
(w:pPrChange), and cleared typography a tracked formatting change (w:rPrChange). Clearing
never deletes text: a leading tab is removed with a delete. A style the paragraph already
has, with nothing to clear, records nothing. A style the document and style_template lack
fails the edit with INVALID_EDIT.
set_paragraph_format
set_paragraph_format sets alignment, indents, spacing and pagination.
{"type": "set_paragraph_format", "paragraphs": [{"index": 12}, {"index": 13}],
"paragraph_format": {"alignment": "justify", "indent": {"left": 36, "first_line": 18},
"spacing": {"before": 0, "after": 6, "line_spacing": {"multiple": 1.15}}, "keep_with_next": true}}| Property | Values |
|---|---|
alignment | left, center, right, justify, or null |
indent | left and right (points, -1584 to 1584), and first_line or hanging (0 to 1584) |
spacing | before and after (points, 0 to 1584), line_spacing |
keep_with_next, keep_lines_together, page_break_before, widow_control | true, false or null |
Measures are rounded to the twentieth of a point and replace the paragraph's own value in every
form Word reads. The change is tracked: each paragraph's previous properties go into a
w:pPrChange, so rejecting restores them; a format the paragraph already has records nothing.
Header, footer, note and table-cell paragraphs are formatted the same way. The document content
gives each paragraph a paragraph_format in these terms where it sets a property or differs
from the document's default.
set_numbering
set_numbering changes list numbering by action. Levels count from 1, as the document
content's level does.
{"type": "set_numbering", "paragraphs": {"from": {"index": 20}, "through": {"index": 22}}, "action": "apply", "list": {"same_as": {"index": 19}}}
{"type": "set_numbering", "paragraphs": [{"index": 5}, {"index": 6}], "action": "apply", "list": {"new": "bulleted"}, "level": 1}
{"type": "set_numbering", "paragraphs": {"index": 21}, "action": "set_level", "level": 2}
{"type": "set_numbering", "paragraphs": {"index": 30}, "action": "restart", "start": 1}
{"type": "set_numbering", "paragraphs": {"index": 31}, "action": "continue"}
{"type": "set_numbering", "paragraphs": {"index": 40}, "action": "remove"}
{"type": "set_numbering", "paragraphs": {"from": {"index": 24}, "through": {"index": 41}},
"action": "set_number_format", "level": 3, "number_format": "lower_roman", "pattern": "(%3)"}apply. The paragraphs become one list instance: a{"new": "bulleted" | "numbered"}list, with Word's own nine levels for its Bullets or Numbering button, or the list of asame_asparagraph. Each keeps its level (1 if it had none) unlesslevelis given.restartandcontinue. At the first named paragraph,restartnumbers fromstart, andcontinueresumes the previous list of the same definition, as Word's "Continue numbering" does. The items after it in its list, up to the next item at a higher level, go with it.set_number_format. Changes one level'snumber_format(decimal,decimal_zero,lower_roman,upper_roman,lower_letter,upper_letter,ordinal,cardinal_text,ordinal_text,bullet,none) and optionalpattern((%3)shows level 3's number in brackets) for the named paragraphs at that level. A run is a maximal sequence of named paragraphs at that level with only deeper-level paragraphs between them; a paragraph at that level that isn't named, or any paragraph at a parent level, ends the run. Each run gets its own list instance, with that level overridden, starting at the run's first current number, so numbers keep their values and change only their format; the deeper-level paragraphs between and directly after them move into it, so numbering still restarts under each item. A pattern showing another level's number is refused, and so, when the edit runs, is a deeper level moving into the instance whose pattern shows a level above the changed one (level 4"%2.%4"when level 3 changes).
Each paragraph's numbering change is a tracked paragraph property change (w:pPrChange);
removing numbering a style gives writes w:numId 0, as Word does. The list instances and
definitions a new list, a restart or a format change needs are added untracked: Word cannot
track numbering definitions. The document content shows each numbered paragraph's number,
level and list_id, and list_styles. Refused: a paragraph that isn't numbered for
set_level, restart, continue or remove, a level the list doesn't define, and a
continue with no earlier list of the same definition.
Sections
A section break is the end of a paragraph that carries the properties of the section it ends:
the document content shows them as that paragraph's section, and the last section's as
final_section. OOXML keeps one record of a section's earlier properties, so a section edit
that must record a change on a section whose properties already carry a tracked change is
refused (accept or reject it first).
insert_section_break
insert_section_break ends a section at each named paragraph, which must be directly in the
body, not already end a section and not be the body's last paragraph. section_type is how the
new section starts: next_page, continuous, even_page or odd_page. ref names the
section after the break; the original number still names the one before it.
{"type": "insert_section_break", "paragraphs": {"index": 129}, "section_type": "next_page", "ref": "schedule"}Both sections keep the original's page setup, columns, headers and footers; the new one starts
as section_type says. The break is tracked as Word tracks an inserted section break: the
paragraph ends with an inserted paragraph mark carrying the new section's properties, and its
original mark, tracked as deleted, ends an empty paragraph after it; a change to how the
following section starts is a w:sectPrChange. All of it is one revision.
remove_section_break
remove_section_break removes the break that ends section. Its content joins the next
section and takes that section's properties, headers and footers, as in Word.
{"type": "remove_section_break", "section": {"number": 2}}The merged section starts as the removed one started (its section type and page-number
restart), a tracked w:sectPrChange. The break is tracked as a deleted paragraph mark carrying
the removed section's properties; a paragraph holding nothing but the break is deleted whole.
All of it is one revision. Refused: the last section, a break that is itself a tracked
insertion (reject that revision instead), and a paragraph mark already tracked as deleted or
moved.
set_page_setup
set_page_setup changes the page of section: a section locator, an array of them, or
"all".
{"type": "set_page_setup", "section": "all",
"page_setup": {"orientation": "landscape", "paper": "a4", "margins": {"left": 72, "right": 72, "top": 54},
"different_first_page": true, "page_numbering": {"start": 1, "number_format": "lower_roman"}}}| Field | Values |
|---|---|
orientation | portrait or landscape |
paper | letter, legal or a4; or page_width and page_height (points, 72 to 1584) instead |
margins | points by side: top, bottom, left, right, header, footer, gutter |
different_first_page | true gives the first page its own header and footer (w:titlePg) |
page_numbering | start (0 to 32767) and number_format (decimal, lower_roman, upper_roman, lower_letter, upper_letter) |
null is accepted only for different_first_page and page_numbering (and its fields), since
a section has no style to fall back to. The change is tracked: the section's earlier properties
are kept in a w:sectPrChange, and a setting the section already has records nothing.
different_first_page alone leaves the first page with whatever first-page header and footer
the section has, usually none; add them with add_header_footer.
add_header_footer
add_header_footer gives a section a header or footer of its own: part names kind
(header or footer), type (default or first) and section. Its text is content (one
paragraph) or new_paragraphs (1 to 100, each content, style_id and paragraph_format).
ref names the new part.
{"type": "add_header_footer", "part": {"kind": "footer", "type": "default", "section": {"number": 1}}, "ref": "ftr",
"new_paragraphs": [{"content": [{"text": "Page "}, {"type": "field", "code": "PAGE"}, {"text": " of "},
{"type": "field", "code": "NUMPAGES"}], "paragraph_format": {"alignment": "center"}}]}
{"type": "format", "paragraphs": {"part": {"ref": "ftr"}, "index": 0}, "format": {"font_size": 9}}The content is tracked as Word tracks typing into a new header: every run is a tracked
insertion and every paragraph mark but the last an inserted one, so rejecting leaves it empty.
The new part (header1.xml, footer1.xml, ...) and the section's reference to it are applied
untracked: Word records neither as a revision. The section stops linking to an earlier
section's part, and later sections that linked to it show the new one. A first part shows
only while different_first_page is on, and adding one doesn't turn that on. Refused: a
section that already has its own part of that kind and type (edit its paragraphs), and an
even part, since creating one needs the document-wide even-and-odd setting. After it, a
locator naming that header or footer through a section that now shows the new part is refused;
name the new part by its ref.
Tables
The document content shows a table's number, id and style_id, each row's header flag
and tracked change, and each cell's row, column, span and change. Every table edit is
tracked, and accept_revision and reject_revision decide each row, cell, grid and text
revision it makes. A cell value is content (one paragraph; \n is a line break) or
{"new_paragraphs": [...]}, whose items are insert_paragraphs items
(content, style_id, paragraph_format, list, level, ref).
insert_table
insert_table places a table at a destination. rows holds each row's cell values, every row
the same length (at most 63); header_row (default false), when true, repeats the first
row on each page and gives it the table style's header-row formatting. ref names the table.
{"type": "insert_table", "destination": {"paragraph": {"index": 49}, "position": "after"}, "header_row": true,
"rows": [["Class", "Shares authorized"], ["Common stock", "[__________]"],
[{"new_paragraphs": [{"content": "Preferred stock"}, {"content": "Series A", "style_id": "Normal"}]}, "—"]]}Every row is a tracked row insertion (w:trPr/w:ins) and its text a tracked insertion, so
rejecting removes the table. The table has single borders like Word's Table Grid, and its
columns share the text width of the section (or of the cell, for a nested table). Where it
would touch another table or end its container, an empty paragraph with a tracked inserted mark
is added beside it. Headers, footers and notes hold tables too, tracked the same way.
delete_table
delete_table deletes a table as tracked row deletions of every row and its text; accepting
removes it.
{"type": "delete_table", "table": {"number": 3}}A row another author already deleted is left as it is.
insert_table_row and delete_table_row
insert_table_row adds a row before or after row, with one cell value per grid column; ref
names it. delete_table_row deletes a row as a tracked row deletion (w:trPr/w:del) with its
text deleted.
{"type": "insert_table_row", "destination": {"row": {"index": 311}, "position": "after"}, "ref": "google",
"cells": ["Google LLC", "Google Cloud Support", "AI-Enhanced PDF Conversion"]}
{"type": "delete_table_row", "row": {"table": {"number": 1}, "number": 4}}The new row copies the neighbouring row's cell layout and formatting, without its revisions, vertical merges or header flag (the row above, or below for a new first row), and is a tracked row insertion with its text tracked. Each new cell's text takes the run formatting carried by the most plain text in the neighbouring cell, as text typed into a row Word inserts does. Refused: a row inside a vertically merged span, and a cell count other than the grid's.
insert_table_column and delete_table_column
insert_table_column adds a grid column before or after column, with one cell value per row;
delete_table_column deletes a column.
{"type": "insert_table_column", "destination": {"column": {"table": {"number": 2}, "number": 3}, "position": "after"},
"cells": ["Q3", "12", "9"]}
{"type": "delete_table_column", "column": {"index": 143}}Word does not record inserting or deleting a column as one tracked change; it displays and
decides tracked cell insertions and deletions, which is what these edits write. Each new cell
is a tracked cell insertion (w:cellIns) with its text a tracked insertion, formatted like the
cell beside it, and the table grid's earlier columns are kept in w:tblGridChange, which
carries no author: a decision that settles all of a table's cell insertions and deletions
settles its grid change the same way. A deleted column's cells are tracked cell deletions
(w:cellDel) with their text deleted; accepting gives each cell's width to the cell before it.
Refused: a column through a cell spanning several grid columns, a cell count other than the
table's rows, and a paragraph locator in a spanning cell, which names no one column.
Fields and links
Field and cross-reference runs
A field run inserts a document field by its Word field code; a cross_reference run inserts
a field pointing to another paragraph, to.
{"type": "insert", "paragraphs": {"part": {"kind": "footer", "type": "default", "section": {"number": 1}}, "index": 0},
"at": {"after": {"match": "Page "}}, "content": [{"type": "field", "code": "PAGE \\* ROMAN"}]}
{"type": "insert", "paragraphs": {"index": 12}, "at": {"after": {"match": "see Section "}},
"content": [{"type": "cross_reference", "to": {"index": 30}, "show": "number"}]}| Field code | Result the API writes |
|---|---|
PAGE, NUMPAGES, SECTIONPAGES | 1, which Word replaces when it lays out the pages |
DATE | the edit's date; Word shows the current date on open |
CREATEDATE, SAVEDATE | the document's created or last-saved date |
TITLE, AUTHOR | the document's title or author |
DOCPROPERTY | the named property: a custom property, or Title, Subject, Author, Keywords, Comments, Category, Company, Manager, LastSavedBy |
FILENAME | none; marked for Word to compute on open |
A field is one tracked insertion: begin, instruction, result and end inside a w:ins, in the
formatting of the text before it. No field that fetches or runs content (INCLUDETEXT,
INCLUDEPICTURE, DDE, DDEAUTO, IMPORT, LINK, MACROBUTTON, ...) is offered.
show | Field | Result |
|---|---|---|
number | REF _Ref... \r \h | the paragraph's list number, without trailing periods (2.1) |
text | REF _Ref... \h | the paragraph's text |
page | PAGEREF _Ref... \h | 1, marked for Word to compute on open |
above_below | REF _Ref... \p \h | "above" or "below", by where the paragraph is |
A cross-reference's result is the one its paragraph has after the last edit, with every
revision accepted. The paragraph pointed to needs a hidden _Ref bookmark around its text: an
existing one is reused, otherwise one is added, untracked, and stays if the cross-reference is
rejected; the field is a tracked insertion. number for a paragraph without a list number, and
text for one without text, are refused.
add_hyperlink
add_hyperlink links existing text: the one match of text, or the whole paragraph without
it. url is an absolute http, https or mailto address.
{"type": "add_hyperlink", "paragraphs": {"index": 4}, "text": {"match": "our website"}, "url": "https://example.com"}The link is a HYPERLINK field, the form Word can track: its code is inserted before and after
the text (w:ins) and the text takes the Hyperlink character style as a tracked formatting
change. Accepting gives the link; rejecting restores the text. The Hyperlink style is added,
untracked, when the document has none. Refused: addresses that run code, reach local files or
embed content (javascript:, vbscript:, file:, data:), other schemes, relative and UNC
addresses, and addresses with spaces, quotes, backslashes or angle brackets (percent-encode
them); text that is already a link (use set_hyperlink); and two add_hyperlink ranges that
overlap.
set_hyperlink and remove_hyperlink
set_hyperlink gives a hyperlink a new url; remove_hyperlink unlinks it and keeps its
text. With text, the hyperlink holding the match; without it, the paragraph's only
hyperlink.
{"type": "set_hyperlink", "paragraphs": {"index": 4}, "text": {"match": "our website"}, "url": "https://example.com/new"}
{"type": "remove_hyperlink", "paragraphs": {"index": 4}}Both are tracked: a new address deletes the old field code (w:delInstrText in w:del) and
inserts the new one; unlinking deletes the field code and removes the Hyperlink style as a
tracked formatting change. A link held as a w:hyperlink element or a simple field is first
rewritten as the equivalent HYPERLINK field. Refused when the selection covers no hyperlink,
or more than one. The document content shows a link on its segments as
"link": {"url": ..., "anchor": ...}, and each paragraph's fields and bookmarks.
refresh_fields
refresh_fields marks every field in the body, headers, footers and notes for update
(w:dirty) and sets w:updateFields, so Word asks the reader to update fields when the
document opens.
{"type": "refresh_fields"}Both changes are applied untracked, to both outputs. A document holding a field that fetches or
runs content (as listed for moves, RD included) is refused, since refreshing would run it on
open.
insert_table_of_contents
insert_table_of_contents places a TOC field as a new paragraph at a destination in the body
outside tables. from_level and to_level (1 to 9) are the heading levels; hyperlinks
(\h) and page_numbers default to true.
{"type": "insert_table_of_contents", "destination": {"paragraph": {"index": 2}, "position": "after"},
"from_level": 1, "to_level": 3}The defaults with levels 1 to 3 give Word's own TOC \o "1-3" \h \z \u; "page_numbers": false adds \n. The API cannot lay out pages, so the field shows a placeholder and is marked
for update, with w:updateFields set, both untracked: Word writes the entries when the
document opens. The paragraph is one tracked insertion. A heading above it is an
insert_paragraphs at the same destination, earlier in the request.
Footnotes and endnotes
Note runs
A footnote or endnote run in an insert's content adds a note whose reference goes at that
point. Its text is content, or new_paragraphs for several paragraphs; it holds text, tabs,
line breaks, fields, cross-references and links, not page or column breaks or other notes.
ref names the note, and {"part": {"ref": ...}, "index": n} its paragraphs.
{"type": "insert", "paragraphs": {"index": 56}, "at": {"after": {"match": "409A."}},
"content": [{"type": "footnote", "ref": "fn1",
"content": [{"text": "As defined in "}, {"text": "Section 1", "format": {"italic": true}}, {"text": "."}]}]}
{"type": "insert", "paragraphs": {"index": 30}, "at": {"before": {"match": "Schedule"}},
"content": [{"type": "endnote", "content": "See the Schedule."}]}The reference and the note's text are tracked insertions, written as Word writes a note inserted with Track Changes on, and share one revision, so deciding it decides the note whole. The notes part, with Word's separator notes, and the note styles are added untracked when the document lacks them.
delete_note
delete_note deletes a note and its reference mark.
{"type": "delete_note", "note": {"kind": "footnote", "number": 2}}The reference run and the note's text become tracked deletions; accepting removes the note.
Text edits reach a note's paragraphs through its part locator. The document content shows each
note's part, label, paragraph (where its reference is), text_before (the 200 characters
before the reference) and blocks, its paragraphs.
Comments
add_comment
add_comment anchors a comment to the one match of text in a paragraph, to the whole
paragraph, or to a range of paragraphs. content is a string or text, tab and line-break runs;
author overrides the request's for this comment; ref names the thread.
{"type": "add_comment", "paragraphs": {"index": 7}, "text": {"match": "30 days"}, "content": "Should this be 45?", "ref": "c1"}
{"type": "add_comment", "paragraphs": {"from": {"index": 25}, "through": {"index": 27}}, "content": "Double check this section."}A comment is not a tracked change: it appears in the redline's comment pane and is kept in the
clean copy, unless its reference goes with deleted text. A comment's range follows its text, so
a later replace inside it leaves the deleted and the new text inside the comment. Comments go
on body and table-cell paragraphs; Word doesn't support them in headers or footers, and they
aren't added to notes.
reply_comment and resolve_comment
reply_comment answers a thread, and resolve_comment marks it resolved. comment is a
thread's number from the document content's comments, or the ref of a thread this request
adds.
[{"type": "reply_comment", "comment": {"ref": "c1"}, "content": "Agreed; changed to 45.", "author": "Lawyer A"},
{"type": "resolve_comment", "comment": {"number": 3}}]Replies and resolutions are annotations, applied untracked. Replies to one thread appear in
request order. The document content gives each thread's number, author, date, text,
paragraph, anchor_text, resolved and replies.
Tracked revisions
accept_revision and reject_revision
accept_revision and reject_revision decide the document's existing tracked changes.
revision is one entry of the document content's revisions ({"number": n}), "all", or a
filter by author and/or kind (insertion, deletion, move, or property: every
formatting, paragraph, numbering, table and section property change).
[{"type": "reject_revision", "revision": "all"},
{"type": "accept_revision", "revision": {"author": "Jane Doe"}},
{"type": "accept_revision", "revision": {"number": 4}}]A request holding a decision holds only decisions; to decide and then edit, send two requests.
Decisions apply in request order and the later one wins for a revision, so the example rejects
everything but Jane Doe's changes and revision 4. Accepting keeps what an insertion or a move's
destination adds, drops what a deletion or a move's source removes, and keeps a property
change's new properties; rejecting does the opposite. A decision is not itself a tracked
change: the redline keeps every revision no decision covered, under its original author and
date. Decisions cover the body, headers, footers and notes. Rejecting all of an edit set's
revisions gives back the document it was applied to. An empty filter is refused. One revision
entry is one thing to decide: a move (both halves), one author's contiguous insertion or
deletion, or one property change; a replacement is two entries. A Word 2003 numbering change
(w:numberingChange) cannot be rejected; rejecting it fails the edit.
Document settings
set_document_settings
set_document_settings sets how the output behaves in Word. Settings are not document content
and Word cannot track them, so they are applied untracked to both outputs, and deciding
revisions doesn't change them.
{"type": "set_document_settings",
"settings": {"track_changes": true, "protection": {"edit": "tracked_changes", "password": "s3cret"},
"remove_personal_information": true}}| Field | Effect in the output |
|---|---|
track_changes | true turns on Track Changes (w:trackRevisions); false turns it off |
protection | Restrict Editing, enforced (w:documentProtection), replacing any protection the document had. edit is tracked_changes (every change is tracked and tracking can't be turned off), read_only or comments. With password, Word asks for it to stop the protection. false removes protection |
remove_personal_information | true sets Word's "remove personal information from file properties on save" and clears the output's creator and last-modified-by names; false turns it off |
Fields left out are left as the document has them; at least one is required. password is 1 to
15 printable ASCII characters, hashed when the request arrives as Word hashes it, and only the
hash is stored and written; Restrict Editing guards against accidental changes and is not
encryption. A request holds at most one set_document_settings edit. track_changes: false
with tracked_changes protection is refused. The even-and-odd headers setting isn't included.
The document content shows the document's own settings.