PapermarkDocs

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_abc123

The 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_oldver1

The 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_abc123 needs to be replaced with the new file at https://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_abc123 and 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_headers from 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.

On this page