Tracked Changes
Contracts and offers often come back from reviewers with every edit marked: text that was inserted or deleted while change tracking was turned on, each change with its author and time. The review endpoints of the Web API read these tracked changes from a document and accept or reject them one at a time. Your application can apply the decisions a reviewer made in a web page, or a rule such as "accept the changes of the legal department", and keep a document without markup.
How Tracked Changes Work
A tracked change stays marked in the document until it is accepted, which keeps the change, or rejected, which undoes it: a rejected insertion is removed and a rejected deletion is restored. Two endpoints work with them:
| Endpoint | Request | Response |
|---|---|---|
| POST /v1/processing/review/trackedchanges | The document as a Base64 string in a JSON string | An array of TrackedChange objects |
| POST /v1/processing/review/removetrackedchange | The same body, and the query parameters id and accept | A ModifiedDocument object with the changed document and removed |
Both endpoints work as follows:
- Formats. The document can be RTF, DOC, DOCX or TX, the TX Text Control format. It is sent with each request; the endpoints don't work with the template storage. A document in another format isn't refused: trackedchanges returns an empty array for it, as for a document without tracked changes.
- One change per request. removetrackedchange accepts the change with the number
idwhenacceptistrueand rejects it whenacceptisfalse. It returns the whole document with this one change removed. - The result is TX. The returned document is a Base64 string in the TX format. Send it as it is with the next request, or convert it to DOCX or PDF with
POST /v1/document/convert, as Converting Documents shows. - Quota. removetrackedchange counts against the document quota, one document per successful request, also when it removes nothing. trackedchanges counts against no quota.
Every request carries an Authorization header, as Authentication describes.
List the Tracked Changes of a Document
The following commands send contract.docx to trackedchanges:
# Wrap the Base64 string of the document in a JSON string
base64 0 contract.docx | jq . > contract.json
curl POST "https://api.reporting.cloud/v1/processing/review/trackedchanges" \
"Authorization: ReportingCloud-APIKey $REPORTINGCLOUD_API_KEY" \
"Content-Type: application/json" \
@contract.json
The response has one object per tracked change. The first object of the reference's sample:
[
{
"changeKind": 4096,
"changeTime": "2019-01-01T00:00:00Z",
"defaultHighlightColor": "60, 255, 0, 0",
"highlightColor": "60, 87, 174, 168",
"highlightMode": 3,
"length": 13,
"start": 3,
"id": 0,
"text": "trackedchange",
"userName": "ReportingCloudUser"
}
]
A TrackedChange object holds:
| Property | Content |
|---|---|
id | The number of the change, which removetrackedchange takes as id. The ids start at 0, in the order of the array |
changeKind | 4096 for inserted text, 8192 for deleted text. Format changes are not listed, and moved text is listed as a deletion and an insertion |
text | The inserted or deleted text |
start, length | The one-based index of the first character of the change, counted in the main text, the header or the footer that holds it, and the length of the change. A paragraph end counts as one character |
userName | The name of the author, empty if the document names none |
changeTime | The time of the change, in UTC |
highlightMode | The highlight mode of the change: 1 (Never), 2 (Activated) or 3 (Always) |
highlightColor, defaultHighlightColor | The highlight color of this change and the default highlight color of tracked changes, as strings of four comma-separated numbers such as "60, 255, 0, 0" |
Accept or Reject a Change
The following command accepts the change with the number 1 and saves the response:
curl POST "https://api.reporting.cloud/v1/processing/review/removetrackedchange?id=1&accept=true" \
"Authorization: ReportingCloud-APIKey $REPORTINGCLOUD_API_KEY" \
"Content-Type: application/json" \
@contract.json \
modified.json
# true when the change was removed
jq .removed modified.json
# The document without the change, in the TX format
jq .document modified.json | base64 > contract.tx
The response is a JSON object such as {"document":"CAcBAA4AAAAAAAAAAAAAAAIAAABsAQAAAQ...==","removed":true}:
documentis the modified document as a Base64 string in the TX format.removedsays whether the change was removed. It isfalse, anddocumentisnull, if the document has no change with the given id. Setaccept=falseto reject the change instead.
To decide on the next change, send the modified document: jq .document modified.json > contract.json writes it as the JSON string the next request takes.
Warning
Change Ids Shift. Every request removes one change and returns a new document, in which the ids of the changes that followed the removed one are lower by 1, so read the remaining changes and their numbers from the modified document with trackedchanges before you remove the next one.
Accept the Changes of One Author With .NET
The NuGet package TXTextControl.ReportingCloud has both endpoints in rc.Processing.Review. The following console application accepts the changes of one author, rejects all others and saves the result as DOCX:
using TXTextControl.ReportingCloud;
var rc = new ReportingCloud(Environment.GetEnvironmentVariable("REPORTINGCLOUD_API_KEY"));
string trustedAuthor = "Alice Johnson";
byte[] document = File.ReadAllBytes("contract.docx");
List<TrackedChange> changes = rc.Processing.Review.GetTrackedChanges(document);
while (changes.Count > 0)
{
TrackedChange change = changes[0];
bool accept = change.UserName == trustedAuthor;
// Accept or reject the change; the result is the document in the TX format
TrackedChangeModifiedDocument result = rc.Processing.Review.RemoveTrackedChange(document, change.Id, accept);
if (!result.Removed)
{
Console.WriteLine($"Change {change.Id} was not removed.");
break;
}
Console.WriteLine($"{(accept ? "Accepted" : "Rejected")} {change.ChangeKind} by {change.UserName}: {change.Text}");
// Read the remaining changes from the modified document
document = result.Document;
changes = rc.Processing.Review.GetTrackedChanges(document);
}
// Convert the result from the TX format to DOCX
byte[] docx = rc.ConvertDocument(document, ReturnFormat.DOCX);
File.WriteAllBytes("contract-reviewed.docx", docx);
The code works as follows:
GetTrackedChangestakes the document as a byte array and returns a list ofTrackedChangeobjects withId,ChangeKind,Text,Start,Length,UserName,ChangeTimeand the highlight properties.ChangeKindis an enumeration with the valuesInsertedTextandDeletedText.RemoveTrackedChangetakes the document, the number of the change andtrueto accept orfalseto reject. It returns aTrackedChangeModifiedDocumentwhoseDocumentholds the modified document as a byte array and whoseRemovedsays whether the change was removed. When no change is removed, though, the response'sdocumentis null and the method throws anArgumentNullException, so a removal that fails ends the loop with an exception, not at the check ofRemoved.- The loop removes the first change of each list, then lists the changes of the modified document again, so that every number it sends belongs to the document it sends.
ConvertDocumentconverts the TX result withPOST /v1/document/convert, a request that counts against the document quota of your plan. Each change itself takes two requests, one to removetrackedchange, which counts against the document quota as well, and one to trackedchanges, which doesn't.
The PHP SDK has the methods getTrackedChanges($documentFilename) and removeTrackedChange($documentFilename, $id, $accept). They read the document from a file, and removeTrackedChange returns the modified document decoded, under the key document: write it to a .tx file to pass it on. PHP SDK 4.0.5 can't read a time stamp with fractions of a second, such as 2019-08-06T12:34:13.9188379Z: getTrackedChanges returns such a change with a change_time of 0.
Next Steps
- Converting Documents: convert the TX result to DOCX, PDF or another format.
- Spell Checking: check the spelling of a text.
- Managing Templates: store the reviewed document as a template.
- Errors and Status Codes: what a refused request means.