Skip to content
Docs
Sign in

Files API

Organise folders and files, upload whole trees, read versions and properties, and make bulk changes from your own systems.

For integrators

The Files API does everything the Files page does: browse and search, upload single files or whole trees, read versions and properties, and move, tag or trash many files at once. Every endpoint is under your team's address, /a/<team_slug>/files/api/v1/, and needs an API key (see the API overview). The endpoints are in the OpenAPI schema under the tag files.

To copy a whole archive from a file server, start from the ready-made script in Move your customer archive to the cloud.

Conventions#

Errors are JSON with a stable code, a detail sentence you can show people, and often the item the error is about:

{"code": "name_taken", "detail": "Something with that name is already here.", "item": "Postcard A.pdf"}
Status Codes
400 invalid (with the field errors in errors), name_invalid, depth_exceeded, unknown_property, invalid_property
403 forbidden: only team admins can do this
404 not_found: not in this team
409 name_taken, folder_trashed, cycle, kind_change, in_use, not_ready, upload_incomplete, upload_mismatch
412 stale: someone changed it since you read it
413 too_large, batch_too_large
507 quota_exceeded, with needed, free and limit in bytes

Batches. Endpoints that take a list answer 200 with one result per item. One item's error never fails the others: check each item's status.

Pages. Lists return {"results": [...], "next": <url or null>, "next_cursor": <token or null>}. Follow next until it is null. limit sets the page size (100 by default, at most 1,000), and ordering is name, -name, updated_at, -updated_at, size or -size. Names sort naturally: "Label 2" before "Label 10".

Safe changes. Every file and folder has a revision, also sent as the ETag header. Send it back as If-Match: "7" (or as a revision field) when you PATCH. If someone changed it in between, you get 412 stale: read it again and retry.

Safe retries. Send an Idempotency-Key header (any unique string, such as a UUID) with uploads/complete/, bulk/ and downloads/. Retrying with the same key within 24 hours returns the first answer, marked with Idempotent-Replay: true, instead of doing the work twice.

Rate limits. 1,200 requests a minute per user, and 120 a minute for the upload calls (uploads/, uploads/sign/, uploads/claim/ and uploads/complete/). Over the limit you get 429: wait and retry.

Folders and files#

  • Browse. GET folders/?parent=root lists the folders in the root (or pass a folder id). GET files/?folder=42 lists a folder's files; add recursive=true for its subfolders too, or leave folder out to search the whole team.
  • Find by path. GET resolve/?path=/Customers/C-102/Postcard A.pdf returns the folder or file at a path, with its id.
  • Create folders. POST folders/ creates one folder. POST folders/ensure/ takes up to 2,000 relative paths ("Customers/C-102/Proofs") and creates whatever is missing, parents included. It is safe to call again and returns the id of every path.
  • Change. PATCH folders/{id}/ and PATCH files/{id}/ rename (name) and move (parent for a folder, folder for a file). For a file, properties are merged (null removes a key) and tags replace the old ones.
  • Trash. DELETE folders/{id}/ and DELETE files/{id}/ move to the trash and return the trash_batch.
  • Download. GET files/{id}/download/ redirects to a download link that works for 5 minutes.

Search filters on GET files/: q (every word must appear in the name; spaces, hyphens, underscores and dots count alike), kind (pdf, image, vector, document, archive, font, other), tag, ink (a spot ink, such as PMS 185 C, in any case), dieline, preflight (pass, warn, fail, error, none; a file's preflight_status is running while a check runs), pages__gte and pages__lte, trim (millimetres, 90x50, either way round), modified_after and modified_before, trashed, and properties: prop.customer=C-102, prop.<key>__gte, prop.<key>__lte and prop.<key>__isnull=true.

A file's facts hold what Files read from its current version: kind, pages, trim_mm, spot_names (and spot_keys, the same names in lower case, which ink matches), dieline, overprint and layers. Lists that span folders (no folder, or recursive=true) also give each file's folder_path, the folder names below the root. preview_url is the 1600 px preview of page 1 once it is made.

Versions#

GET files/{id}/versions/ returns the ready versions, newest first, in results, and how many are still being processed in pending_count. Each version has its number, size, sha256, source (upload, api, restore, copy and the apps' sources), note, original_name, client_path, client_modified, the actor who made it, facts and, when the same content is stored elsewhere, identical_to. For a CF2 or DXF die drawing, facts.die holds what Files read from it (see Files): its status (read, too_large, unreadable or timeout), format (cf2 or dxf), the units it is drawn in, ups, kinds (each distinct shape's key, count and size_mm), grid ([across, around], or null when the ups aren't in regular rows), rule (the millimetres of cut, crease, perforation, score and partial_cut rule), bbox_mm ([x0, y0, x1, y1] of the drawing) and issues (codes such as units_missing). A die imported through Tools & dies adds that app's own keys.

  • GET files/{id}/versions/{number}/download/ downloads one version.
  • POST files/{id}/versions/{number}/restore/ adds a copy of that version as the next one (see Versions). It stores no bytes.
  • DELETE files/{id}/versions/{number}/ deletes a version (admins only); 409 in_use names what still uses it.

Uploads#

Small files (up to 100 MiB) can be sent in one request: POST files/ as multipart/form-data with file, folder (an id or root), and optionally name, on_conflict, note, properties (a JSON object), client_path and last_modified. The answer's status is new or version (201), or unchanged or skipped (200), with the file and the version:

curl -sS -H "Authorization: Api-Key $API_KEY" \
  -F "file=@Postcard A.pdf" -F "folder=root" -F "on_conflict=version" \
  "https://app.example.com/a/acme/files/api/v1/files/"

Many or large files use an upload session, which sends the bytes straight to storage:

  1. Plan. POST uploads/ with up to 1,000 items, each {client_id, relative_path, size, last_modified} (or folder and name instead of relative_path, or target_file to add a version to a file). Missing folders of relative_path are created. on_conflict is version (the default), rename, skip or error (see Folders and uploads). With quick_check (on by default), a file whose size and last_modified match the current version comes back unchanged and needn't be sent. dry_run: true only reports what would happen: a summary of the counts, and in quota the bytes needed and free.

json {"batch": "00000000-0000-0000-0000-000000000000", "quick_check": true, "items": [ {"client_id": "c-102-postcard-a", "relative_path": "Customers/C-102/Postcard A.pdf", "size": 48213, "last_modified": 1790000000000}]}

last_modified is in milliseconds since 1970 (as browsers give it) or an ISO date and time. Each item comes back with a status (upload, unchanged, exists, skipped or error) and, to upload, an upload with its id. 2. Send the bytes as each item's upload says. method post: a multipart/form-data POST to url with the fields first and the bytes last as file. method multipart: a PUT of each part to its URL, every part part_size bytes except the last. Up to 20 part URLs come at a time: POST uploads/sign/ with {"items": [{"id", "parts": [21, 22]}]} gives more, and re-signs anything that expired (403 from storage). 3. Complete. POST uploads/complete/ with up to 50 {"id"} items. Files then checks each file's content. 4. Wait. GET uploads/?batch=<batch> lists the batch's uploads with their result (new, version, unchanged, skipped or failed); poll every few seconds until settled is true.

Planning the same client_id again returns the same upload while it is pending, as long as the file is the same: same place, name, size and last_modified. GET uploads/{id}/parts/ lists the parts storage already has, so an interrupted upload only sends what is missing. A file that changed since (even to the same size) starts a new upload, so parts of two contents are never mixed; always send last_modified. DELETE uploads/{id}/ cancels an upload. Unfinished uploads expire after 48 hours.

A plan that doesn't fit in your storage answers 507 before anything is reserved (see Storage).

Properties#

  • GET property-definitions/ lists your team's properties; GET property-definitions/schema/ returns them as a JSON Schema (draft 2020-12) to validate against in your own tools. The API validates every value itself.
  • Values are JSON: text as strings, numbers as numbers, dates as "YYYY-MM-DD", yes / no as true or false, multiple choice as a list. An unknown key answers 400 unknown_property.
  • GET property-definitions/{key}/values/?q= suggests values already used.
  • Admins create, change and archive definitions with POST property-definitions/, PATCH and DELETE property-definitions/{key}/ (?purge=true also removes the values), and add the starter set with POST property-definitions/starter-set/.

Bulk changes, trash and storage#

POST bulk/ applies one action to file_ids and folder_ids: move or copy (with target, and on_conflict; all_versions to copy the history), trash, restore, set_properties (with properties), add_tags or remove_tags (with tags). Up to 1,000 items run at once, with a result per item; more answer 202 with an operation to poll at GET operations/{id}/.

  • POST downloads/ builds a ZIP of files and folders in the background and returns an operation; its result has the download_url when it is done.
  • GET trash/ lists what is in the trash; POST trash/{batch}/restore/ restores one entry. Admins can delete one entry (DELETE trash/{batch}/) or empty the trash (DELETE trash/).
  • GET usage/ returns your storage in bytes: limit (null when unlimited), used, reserved, free, the breakdown, and enforce, which says whether uploads over the limit are refused yet.
  • GET activity/?since= is the team's change feed, for keeping another system in sync; add folder or file to follow one of them.
  • GET settings/ returns the team's automation switches, auto_preflight and carry_over_prepress; admins change them with PATCH settings/ (see Files).

Reference#

API operations tagged files
MethodPathWhat it does
GET /a/{team_slug}/files/api/v1/activity/ files_activity_list
POST /a/{team_slug}/files/api/v1/bulk/ files_bulk
POST /a/{team_slug}/files/api/v1/downloads/ files_downloads_create
GET /a/{team_slug}/files/api/v1/files/ files_files_list
POST /a/{team_slug}/files/api/v1/files/ files_files_create
GET /a/{team_slug}/files/api/v1/files/{file_id}/versions/ files_versions_list
GET /a/{team_slug}/files/api/v1/files/{file_id}/versions/{number}/ files_versions_retrieve
DELETE /a/{team_slug}/files/api/v1/files/{file_id}/versions/{number}/ files_versions_destroy
GET /a/{team_slug}/files/api/v1/files/{file_id}/versions/{number}/download/ files_versions_download
POST /a/{team_slug}/files/api/v1/files/{file_id}/versions/{number}/restore/ files_versions_restore
GET /a/{team_slug}/files/api/v1/files/{file_id}/versions/{number}/usages/ files_versions_usages
GET /a/{team_slug}/files/api/v1/files/{id}/ files_files_retrieve
PATCH /a/{team_slug}/files/api/v1/files/{id}/ files_files_partial_update
DELETE /a/{team_slug}/files/api/v1/files/{id}/ files_files_destroy
GET /a/{team_slug}/files/api/v1/files/{id}/activity/ files_files_activity
GET /a/{team_slug}/files/api/v1/files/{id}/download/ files_files_download
GET /a/{team_slug}/files/api/v1/files/{id}/usages/ files_files_usages
GET /a/{team_slug}/files/api/v1/folders/ files_folders_list
POST /a/{team_slug}/files/api/v1/folders/ files_folders_create
GET /a/{team_slug}/files/api/v1/folders/{id}/ files_folders_retrieve
PATCH /a/{team_slug}/files/api/v1/folders/{id}/ files_folders_partial_update
DELETE /a/{team_slug}/files/api/v1/folders/{id}/ files_folders_destroy
POST /a/{team_slug}/files/api/v1/folders/{id}/apply-defaults/ files_folders_apply_defaults
POST /a/{team_slug}/files/api/v1/folders/ensure/ files_folders_ensure
GET /a/{team_slug}/files/api/v1/operations/{id}/ files_operations_retrieve
GET /a/{team_slug}/files/api/v1/operations/{id}/download/ files_operations_download
GET /a/{team_slug}/files/api/v1/property-definitions/ files_property_definitions_list
POST /a/{team_slug}/files/api/v1/property-definitions/ files_property_definitions_create
PATCH /a/{team_slug}/files/api/v1/property-definitions/{key}/ files_property_definitions_partial_update
DELETE /a/{team_slug}/files/api/v1/property-definitions/{key}/ files_property_definitions_destroy
GET /a/{team_slug}/files/api/v1/property-definitions/{key}/values/ files_property_definitions_values
GET /a/{team_slug}/files/api/v1/property-definitions/schema/ files_property_definitions_schema
POST /a/{team_slug}/files/api/v1/property-definitions/starter-set/ files_property_definitions_starter_set
GET /a/{team_slug}/files/api/v1/resolve/ files_resolve
GET /a/{team_slug}/files/api/v1/settings/ files_settings_retrieve
PATCH /a/{team_slug}/files/api/v1/settings/ files_settings_partial_update
GET /a/{team_slug}/files/api/v1/trash/ files_trash_list
DELETE /a/{team_slug}/files/api/v1/trash/ files_trash_empty
DELETE /a/{team_slug}/files/api/v1/trash/{batch}/ files_trash_destroy
POST /a/{team_slug}/files/api/v1/trash/{batch}/restore/ files_trash_restore
GET /a/{team_slug}/files/api/v1/uploads/ files_uploads_list
POST /a/{team_slug}/files/api/v1/uploads/ files_uploads_plan
DELETE /a/{team_slug}/files/api/v1/uploads/{id}/ files_uploads_abort
GET /a/{team_slug}/files/api/v1/uploads/{id}/parts/ files_uploads_parts
POST /a/{team_slug}/files/api/v1/uploads/claim/ files_uploads_claim
POST /a/{team_slug}/files/api/v1/uploads/complete/ files_uploads_complete
POST /a/{team_slug}/files/api/v1/uploads/sign/ files_uploads_sign
GET /a/{team_slug}/files/api/v1/usage/ files_usage_retrieve

All “files” operations in the API reference

Last updated Oct. 1, 2026