Skip to Content
APIOriginal-file storage

Original-file storage

When a markup is created from an uploaded file (image, PDF, or video), MarkUp can keep the original file so it can be downloaded later. Whether originals are kept is controlled by the workspace’s original-file storage policy:

PolicyBehaviour
STORE_ALWAYSKeep the original for every markup created from a file.
NEVER_STORENever keep originals.
ASK_PER_PROJECTDecide per markup (the per-project retainOriginal override).

A workspace that has never set a policy defaults to NEVER_STORE, so originals are not accumulated until the workspace opts in.

These endpoints are scoped to the API key’s workspace. Organization-scoped keys must pass ?workspaceId=<id>. Reading the policy is always available; changing the policy, archiving originals, and the storage breakdown require the storage feature to be enabled for the workspace — contact support to enable it.

Read the current policy

GET /api/v2/workspace/settings
curl "https://api.markup.io/api/v2/workspace/settings" \ -H "Authorization: Bearer <API-KEY-SECRET>" \ -H "Markup-API-Version: 2023-02-22"
200 OK
{ "data": { "originalFileStoragePolicy": "NEVER_STORE" } }

Recipe: switch a workspace to NEVER_STORE and archive existing originals

This is the most common migration: stop keeping originals and clear out the ones already stored to reduce storage. Do it in a single call by combining the policy change with applyToExisting: true.

PATCH /api/v2/workspace/settings
curl "https://api.markup.io/api/v2/workspace/settings" \ -X PATCH \ -H "Authorization: Bearer <API-KEY-SECRET>" \ -H "Markup-API-Version: 2023-02-22" \ -H "Content-Type: application/json" \ --data '{ "originalFileStoragePolicy": "NEVER_STORE", "applyToExisting": true }'
200 OK
{ "data": { "originalFileStoragePolicy": "NEVER_STORE", "appliedToExistingCount": 42 } }

appliedToExistingCount is the number of originals queued for archival. applyToExisting only triggers the bulk archive when the new policy is NEVER_STORE; it is ignored for other policies.

Prefer to change the policy and archive separately? Set the policy first, then call the bulk-archive endpoint:

POST /api/v2/workspace/originals/archive-all
curl "https://api.markup.io/api/v2/workspace/originals/archive-all" \ -X POST \ -H "Authorization: Bearer <API-KEY-SECRET>" \ -H "Markup-API-Version: 2023-02-22"
200 OK
{ "data": { "archivedCount": 42 } }

Archiving is irreversible — once an original is archived it is scheduled for deletion from storage and can no longer be downloaded or re-retained.

Verify the result

Use the storage breakdown to confirm the originals bucket has dropped. Values are in bytes.

GET /api/v2/workspace/storage-breakdown
curl "https://api.markup.io/api/v2/workspace/storage-breakdown" \ -H "Authorization: Bearer <API-KEY-SECRET>" \ -H "Markup-API-Version: 2023-02-22"
200 OK
{ "data": { "pdfs": 12000000, "videos": 0, "images": 3400000, "attachments": 800000, "originals": 0, "total": 16200000 } }

Per-markup override

With ASK_PER_PROJECT (or to keep a single original even under NEVER_STORE), set the override on an individual markup. This works only while the original is still available; once archived it cannot be re-retained.

PATCH /api/v2/markups/:id/original
curl "https://api.markup.io/api/v2/markups/<MARKUP-ID>/original" \ -X PATCH \ -H "Authorization: Bearer <API-KEY-SECRET>" \ -H "Markup-API-Version: 2023-02-22" \ -H "Content-Type: application/json" \ --data '{ "retainOriginal": true }'

The markup response carries retainOriginal (the override) and hasRetainedOriginal (whether a downloadable original is currently available). Download a retained original with GET /api/v2/markups/:id/original/download-url, or archive one with DELETE /api/v2/markups/:id/original.

Last updated on