POST /v1/compare/selective compares a range of paragraphs in one document with a range in
another, or two ranges of the same document, such as one clause in two drafts. It answers in the
same response with the comparison as JSON and Markdown, and stores it as a new PDF file. It makes
no Word redline; to redline whole documents, use Compare.
| Base URL | https://api.versionstory.com |
| Auth | Authorization: Bearer vs_.... See Authentication |
The flow
- Upload each document with
POST /v1/files, or use thefile_idof a file you have already uploaded. - Pick the ranges. Read each file with
GET /v1/files/{file_id}/contentand note theindexof the first and last paragraph of each range. - Compare with
POST /v1/compare/selective. The response carries the comparison and its PDF file.
POST /v1/compare/selective
application/json, with an original and a modified range. Each names its file and its first
and last paragraph, either by index or by paragraph id; one side can use indexes while the
other uses ids.
| Field | Required | Meaning |
|---|---|---|
file_id | Yes | The file holding the range |
start_paragraph_index, end_paragraph_index | One pair | The range's first and last paragraph, as the file's content numbers them |
start_paragraph_id, end_paragraph_id | One pair | Instead of the indexes: the paragraphs' ids from the content's JSON |
curl -sS https://api.versionstory.com/v1/compare/selective \
-H "Authorization: Bearer vs_live_..." \
-H "Content-Type: application/json" \
-d '{
"original": {"file_id": "3f2a9c1e-...", "start_paragraph_index": 12, "end_paragraph_index": 18},
"modified": {"file_id": "8c41d7b2-...", "start_paragraph_index": 12, "end_paragraph_index": 19}
}'Ranges are inclusive and follow document order, including paragraphs inside tables. Each paragraph is read with its tracked changes accepted, and Word's list numbering is compared apart from the text. Paragraphs are lined up first, with identical paragraphs as anchors and the rest paired by how similar their words are, and then each pair is compared word by word.
{
"comparison": {
"schema_version": 1,
"original": { "file_id": "3f2a9c1e-...", "file_name": "v1 NDA.docx", "paragraph_count": 7 },
"modified": { "file_id": "8c41d7b2-...", "file_name": "v2 NDA.docx", "paragraph_count": 8 },
"summary": { "unchanged": 5, "modified": 2, "inserted": 1, "deleted": 0 },
"paragraphs": [
{
"status": "modified",
"original_id": "...",
"modified_id": "...",
"original_number": "2.",
"modified_number": "2.",
"content": [
{ "text": "through no fault" },
{ "type": "insertion", "text": ", action, or omission" },
{ "text": " of the Recipient;" }
]
}
]
},
"markdown": "...",
"file": {
"file_id": "b4056e05-...",
"file_name": "Selective Compare - v1 NDA to v2 NDA.pdf",
"status": "ready",
"downloads": [
{
"format": "pdf",
"url": "https://documents.versionstory.com/...",
"file_name": "Selective Compare - v1 NDA to v2 NDA.pdf",
"expires_at": "2026-10-19T19:30:00+00:00"
}
]
}
}comparison.paragraphslists the lined-up paragraphs in reading order.statusisunchanged,modified,inserted(with onlymodified_id) ordeleted(with onlyoriginal_id). A content segment withouttypeis unchanged text: skip the insertions to read the original, and the deletions to read the modified.markdownis the same result with changes marked by<ins>and<del>, each paragraph opened by<p original-unid="..." modified-unid="..."/>.fileis a new file holding the same result as a PDF, the one the Selective Compare panel exports in the Version Story app: inserted text blue and underlined, deleted text red and struck through, each paragraph on its own line after its list number.
The PDF file
The PDF is written before the response is sent, so file is always ready. Its download URL is
valid for one hour; GET /v1/files/{file_id} with
its file_id mints a fresh one. It is served as pdf only, and it cannot be compared, edited or
read as content. For an organization with
zero-day retention, it is deleted an hour after
it is made, or as soon as you call
POST /v1/files/{file_id}/acknowledge.
Each request makes a new file, so send it once and keep the file_id. It counts toward your
usage as a document with the words of the compared text; downloading its PDF, then or later,
does not count again.
Errors
| Status | Code | Cause |
|---|---|---|
| 400 | INVALID_REQUEST | A range named both ways or neither, a start after its end, or a file without paragraphs to compare (a redline, a created document, another selective comparison's PDF) |
| 400 | PARAGRAPH_NOT_FOUND | A paragraph index or id is not in its file |
| 400 | RANGE_TOO_LARGE | The ranges are too large to compare in one request: more than 40,000 pairs of paragraphs between identical ones, or a comparison of more than 300,000 characters. Compare smaller ranges |
| 400 | UNSUPPORTED_FILE_TYPE | A workbook or presentation, which has no paragraphs |
| 401 | INVALID_API_KEY | Missing, malformed, unknown, revoked, or expired key |
| 404 | DOCUMENT_NOT_FOUND | No such file, or it belongs to another organization |
| 409 | CONFLICT | A file is still being prepared (retry after Retry-After), or its preparation failed (upload it again) |
| 410 | CONTENT_DELETED | A file's content was deleted under zero-day retention |
Related
- Compare: a Word redline of two whole documents
- Files: upload documents and download the comparison's PDF again
- Data handling: what is kept, and for how long