Place a legal hold on a file
const url = 'https://files.centralcodestation.com/api/v1/tenants/example/applications/example/files/example/hold';const options = { method: 'PUT', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"reason":"example","until":"2026-04-15T12:00:00Z","acting_user_id":"example"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request PUT \ --url https://files.centralcodestation.com/api/v1/tenants/example/applications/example/files/example/hold \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "reason": "example", "until": "2026-04-15T12:00:00Z", "acting_user_id": "example" }'Or change the reason and the end of the one in place. While the hold is in force the file cannot be purged (by anyone, nor by the trash’s retention or emptying), its versions are neither deleted nor pruned, and a storage migration keeps its source copies; it can still be trashed and restored, edited and given new versions. files.manage. The reason is visible to everyone who can view the file.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”A file id (ULID).
The Identity Server tenant id.
The Identity Server application id: a tenant application, or (platform clients) the client’s own platform application.
Request Bodyrequired
Section titled “Request Bodyrequired”object
Why the file is held; shown to everyone who can view the file and kept in the audit log.
A future date when the hold ends by itself; omitted or null: until released.
Machine tokens: the member the change is recorded for.
Example generated
{ "reason": "example", "until": "2026-04-15T12:00:00Z", "acting_user_id": "example"}Responses
Section titled “Responses”Success.
object
object
Your own reference (for example post:123); a list and search filter.
object
The stable URL of a public file.
Derived from the bytes: width, height, duration_ms, pages, …
object
One outcome per processing step.
object
object
object
Only on skipped and failed: why, e.g. source_smaller, duration_exceeds_limit, size_exceeds_limit, duration_unknown.
object
object
A legal hold: while it is in force the file cannot be purged and its versions are kept.
object
The user who placed it, or the client id of a machine caller without acting_user_id.
When the hold ends by itself; null: until released.
Application-managed: the item is a folder an application marked, or lies below one. Read-only for people (403 folder_managed); only the application’s machine clients change it.
Who manages it and which folder carries the mark; null when not managed.
object
The machine client that marked the managing folder.
A display name for it: the tenant application’s name, or a platform application’s slug.
The folder that carries the mark (the item itself, or its nearest marked ancestor). The tenant owner releases this one.
Example
{ "type": "file", "file_id": "01J9Z6S9Q5F5R6Y2W2GZ3B3K4D", "tenant_id": "fitness-co", "application_id": "fitness-app", "folder_id": "01J9Z6R2M3N4P5Q6R7S8T9V0W1", "path": "/posts/IMG_5913.jpg", "name": "IMG_5913.jpg", "extension": "jpg", "mime_type": "image/jpeg", "kind": "image", "size": 4194304, "content_sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", "title": "Beach", "description": null, "category": "photo", "department": null, "tags": [ "beach" ], "custom": { "post_id": "123" }, "external_ref": "post:123", "owner_id": "u-ana", "created_by": { "user_id": "u-ana", "client_id": "fitness-backend" }, "created_at": "2026-10-22T09:12:33.120Z", "updated_at": "2026-10-22T09:12:33.120Z", "state": "available", "status": "draft", "visibility": "application", "public_url": null, "current_version_no": 1, "versions_count": 1, "revision": 3, "media": { "width": 4032, "height": 3024 }, "processing": { "sniff": "done", "policy": "done", "hash": "done", "scan": "skipped", "metadata": "done", "sanitize": "done", "renditions": "done", "text": "skipped", "publish": "skipped", "notify": "done" }, "renditions": { "thumbnail": { "status": "ready", "mime_type": "image/webp", "size": 8123, "width": 256, "height": 192 }, "preview": { "status": "ready", "mime_type": "image/webp", "size": 98123, "width": 1280, "height": 960 } }, "public_renditions": null, "duplicate_of": null, "lock": null, "editable": false, "hold": null, "managed": true, "managed_by": { "client_id": "fitness-backend", "name": "Fitness", "managed_folder_id": "01J9Z6R2M3N4P5Q6R7S8T9V0W1", "managed_at": "2026-10-22T09:12:33.120Z" }, "inherit": true, "acl_scope_id": "root", "entries_count": 0, "trashed_at": null, "trashed_by": null, "my_actions": [ "view", "download", "edit", "share", "delete" ]}Error. error is one of: invalid_request.
object
Stable snake_case error code.
Example
{ "status_code": 400, "error": "invalid_request", "message": "The request is malformed: a required field is missing, a value has the wrong type or format, or a field the route does not accept was sent", "path": "/api/v1/tenants/fitness-co/applications/fitness-app/files/01J9Z6S9Q5F5R6Y2W2GZ3B3K4D", "timestamp": "2026-10-22T09:12:33.120Z"}Error. error is one of: invalid_token.
object
Stable snake_case error code.
Example
{ "status_code": 401, "error": "invalid_token", "message": "The bearer token is missing, malformed, expired, signed by an unknown key, or has the wrong audience (`aud` must be `files-api`).", "path": "/api/v1/tenants/fitness-co/applications/fitness-app/files/01J9Z6S9Q5F5R6Y2W2GZ3B3K4D", "timestamp": "2026-10-22T09:12:33.120Z"}Error. error is one of: not_tenant_member, no_application_access, tenant_not_available, insufficient_scope, client_context_mismatch, files_access_not_granted, missing_capability.
object
Stable snake_case error code.
Example
{ "status_code": 403, "error": "not_tenant_member", "message": "The user is not an active member of the tenant in the URL.", "path": "/api/v1/tenants/fitness-co/applications/fitness-app/files/01J9Z6S9Q5F5R6Y2W2GZ3B3K4D", "timestamp": "2026-10-22T09:12:33.120Z"}Error. error is one of: application_not_found, not_found, file_not_found.
object
Stable snake_case error code.
Example
{ "status_code": 404, "error": "application_not_found", "message": "The application in the URL is not an active application of the tenant.", "path": "/api/v1/tenants/fitness-co/applications/fitness-app/files/01J9Z6S9Q5F5R6Y2W2GZ3B3K4D", "timestamp": "2026-10-22T09:12:33.120Z"}Error. error is one of: file_pending.
object
Stable snake_case error code.
Example
{ "status_code": 409, "error": "file_pending", "message": "The file's upload has not been completed yet.", "path": "/api/v1/tenants/fitness-co/applications/fitness-app/files/01J9Z6S9Q5F5R6Y2W2GZ3B3K4D", "timestamp": "2026-10-22T09:12:33.120Z"}Error. error is one of: rate_limited.
object
Stable snake_case error code.
Example
{ "status_code": 429, "error": "rate_limited", "message": "Too many requests in the current window; `retry_after` (and the `Retry-After` header) says when to retry.", "path": "/api/v1/tenants/fitness-co/applications/fitness-app/files/01J9Z6S9Q5F5R6Y2W2GZ3B3K4D", "timestamp": "2026-10-22T09:12:33.120Z"}Error. error is one of: identity_unavailable.
object
Stable snake_case error code.
Example
{ "status_code": 503, "error": "identity_unavailable", "message": "The service could not reach the Identity Server and has no fresh cached answer.", "path": "/api/v1/tenants/fitness-co/applications/fitness-app/files/01J9Z6S9Q5F5R6Y2W2GZ3B3K4D", "timestamp": "2026-10-22T09:12:33.120Z"}default
Section titled “default”Error: see error for the code.
object
Stable snake_case error code.
Example
{ "status_code": 403, "error": "invalid_request", "message": "This client is not bound to this tenant/application", "path": "/api/v1/tenants/t1/applications/a1/files/01J9Z6S9Q5F5R6Y2W2GZ3B3K4D"}