Upload a new version of a document
Replace the file behind an existing document so every live link instantly serves the update.
Versions sit inside a document. The document id and every link pointing at it stay the same; only the file bytes change. Uploading a new version makes it primary in the same transaction, so the next viewer to open any existing link sees the new file. Older versions remain queryable and can be promoted back at any time.
Use this when you need to push a corrected deck, a redlined contract, or an updated pricing sheet without re-sharing URLs.
# 1. Find the document id (skip if you already have it)
papermark documents list | grep "Acme pitch"
# 2. Upload the replacement file as a new version
papermark documents versions add doc_abc123 ./pitch-v2.pdf
# → Version 2 added: dv_xyz789
# 3. Confirm the primary moved
papermark documents versions list doc_abc123The newly uploaded version becomes primary automatically. All
existing share links now serve pitch-v2.pdf on the next view.
To roll back to an earlier cut:
papermark documents versions promote doc_abc123 dv_oldver1The previous primary is demoted in the same transaction.
Same three-step upload as a fresh document — presign, PUT, register —
but the register step targets /v1/documents/{id}/versions instead
of /v1/documents.
TOKEN=pm_live_…
DOC_ID=doc_abc123
# 1. Get a presigned upload URL
UPLOAD=$(curl -sX POST https://api.papermark.com/v1/documents/upload-url \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"fileName":"pitch-v2.pdf","contentType":"application/pdf","contentLength":2048576}')
UPLOAD_URL=$(echo "$UPLOAD" | jq -r '.upload_url')
UPLOAD_ID=$(echo "$UPLOAD" | jq -r '.upload_id')
# 2. PUT the file bytes to S3. Forward every key in
# required_headers exactly as returned — omitting one yields 403.
# Today the presign returns Content-Type + Content-Disposition;
# if more keys appear, forward those too.
HEADER_ARGS=()
while IFS=$'\t' read -r k v; do
HEADER_ARGS+=(-H "$k: $v")
done < <(echo "$UPLOAD" | jq -r '.required_headers | to_entries[] | "\(.key)\t\(.value)"')
curl -X PUT "$UPLOAD_URL" \
--upload-file ./pitch-v2.pdf \
"${HEADER_ARGS[@]}"
# 3. Register as a new version
curl -X POST "https://api.papermark.com/v1/documents/$DOC_ID/versions" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"upload_id\":\"$UPLOAD_ID\"}"Alternative: skip steps 1–2 and have Papermark fetch the file from a public URL.
curl -X POST "https://api.papermark.com/v1/documents/$DOC_ID/versions" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"source_url":"https://cdn.acme.com/pitch-v2.pdf"}'The response includes version_number and is_primary: true.
Conversion / pre-processing kicks off in the background — viewers
hitting the link in the next few seconds may briefly see the prior
rendering while the new one is built.
Required scope: documents.write. To list or fetch existing
versions: documents.read.
To roll back:
curl -X PATCH "https://api.papermark.com/v1/documents/$DOC_ID/versions/dv_oldver1" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"is_primary":true}'The pitch deck at document id
doc_abc123needs to be replaced with the new file athttps://cdn.acme.com/pitch-v2.pdf. Upload it as a new version and tell me the version number.
The agent calls add_document_version with the document id and
source_url, then reports back the version_number so you can
roll back later if needed.
add_document_version only accepts an HTTPS URL the API can fetch —
local file paths aren't supported over MCP. For a file on your
laptop, either host it somewhere temporary (S3, a gist), use the
CLI papermark documents versions add flow, or upload through the
dashboard.
To roll back:
List the versions on document
doc_abc123and promote version 1 back to primary.
The agent chains list_document_versions → confirms the version id
with you → promote_document_version.
What viewers see
Anyone opening an existing share link after the new version is promoted lands on the new file. No re-share, no broken bookmarks. View analytics continue accumulating on the same link; per-version view counts are tracked separately if you need to know who saw which.
Versioning model in one paragraph
Each document has one primary version (is_primary: true) and
zero or more historical versions. Adding a new version always makes
it primary and demotes the previous primary in a single
transaction — there is never a window where two versions are
primary. Promoting an older version does the same swap in reverse.
Older versions are retained until the document itself is deleted.
Common pitfalls
- 403 on the S3 PUT: you dropped one of
required_headersfrom the presign response. Pass them all back verbatim. - The link still serves the old file: the rendered preview is cached for a few seconds while the new version is converted. Force a refresh, or wait 5–10 seconds.
- You meant to upload a different document: there's no in-place edit. Add another new version with the correct file — the wrong one stays in history but is no longer primary.