​

Migrating to restricted access files

Restricted access files are the new way of working with files and replace the current one. This guide helps you migrate your integrations if you use the Kaiten API to work with files.

They are protected by the permissions of their parent entity: a card, a comment or a custom property. They have no permanent public link — before a download the access of the user is checked and a temporary signed link is issued.

The feature is enabled for the whole company under Company settings → Restricted file access. It is on by default for companies created on or after 21 May 2026; older companies have to enable it. Previously uploaded files are not protected automatically.

After the migration an integration has to:

  1. use the new file API;
  2. request the temporary signed link right before the download;
  3. keep supporting old and new files at the same time, until the old files are deleted.

In all examples <your_domain> is the company subdomain and <token> is an API token.

Upload a file

To upload a file, send a POST request with the Content-Type: multipart/form-data header and a file field. One request uploads one file.

An example of uploading a file to a card:

curl -X POST "https://<your_domain>.kaiten.ru/api/v1/cards/{card_uid}/files" \
  -H "Authorization: Bearer <token>" \
  -F "file=@/path/to/report.pdf"
Upload targetPath
To a card/cards/{card_uid}/files
To a comment/cards/{card_uid}/comments/{comment_uid}/files
To a custom property/cards/{card_uid}/custom-properties/{property_uid}/files

The new methods use a UUID instead of a numeric id in the path. The uid field is returned together with the entity. For example:

  • GET /cards/{card_id} and GET /cards — for cards;
  • POST /cards/{card_id}/comments and GET /cards/{card_id}/comments — for comments;
  • GET /company/custom-properties — for custom properties.
Download a file

A restricted access file is downloaded through a temporary signed link. There are two ways to do it, both shown here for a file of a card:

  1. Call GET /cards/{card_uid}/files/{id}. The response contains the file metadata, including the url field with the temporary signed link.

    curl "https://<your_domain>.kaiten.ru/api/v1/cards/{card_uid}/files/{id}" \
      -H "Authorization: Bearer <token>"
    {
      "id": "9c1f0b7a-4f3d-4a2e-8c11-6b5d7e0a9f21",
      "name": "report.pdf",
      "size": "6848",
      "mime_type": "application/pdf",
      "entity_type": "card",
      "created": "2026-08-11T11:21:23.390Z",
      "updated": "2026-08-11T11:21:23.390Z",
      "card_uid": "c50b47ab-0da2-480b-b9af-0e8593a4b850",
      "author_uid": "ce7c915b-fedd-462a-bf8f-27b2d40467ee",
      "card_cover": false,
      "url": "https://<signed-file-url>"
    }

    Every field is described on the Get card file page.

  2. Call GET /cards/{card_uid}/files/{id}?redirect=true. In this case the server answers with a 302 redirect to the temporary signed link.

    curl -L "https://<your_domain>.kaiten.ru/api/v1/cards/{card_uid}/files/{id}?redirect=true" \
      -H "Authorization: Bearer <token>"

By default images, videos and PDF files are served with Content-Disposition: inline and every other type as an attachment; with ?download=true the file is always served as an attachment. Both parameters work together: ?redirect=true&download=true redirects to a link that downloads the file.

Files uploaded earlier

Old files are not converted once the setting is enabled. They keep their numeric id and public URL and are still served by the current routes.

The files array returned by GET /api/v1/cards/{card_id} may contain files of every type. The signal that tells a restricted access file apart is type = 11.

SignalCurrent fileRestricted access file
type1 for a regular attachment11
ida numbera UUID
entity_typeabsentcard, comment or custom_property
Route reference

The card, comment and custom property file routes support the same five operations, each with its own reference page:

OperationCardCommentCustom property
POST
upload a file
Attach file to cardAttach file to commentAttach file to custom property
GET /{id}
get the file metadata with a signed link, or redirect=true to be redirected to the file
Get card fileGet comment fileGet custom property file
PATCH /{id}
change name or card_cover
Update card fileUpdate comment fileUpdate custom property file
DELETE /{id}
delete a file
Delete card fileDelete comment fileDelete custom property file
Old routes can be turned off

These upload routes are deprecated; each has a restricted access replacement:

Deprecated routeReplacement
PUT /cards/{card_id}/filesRestricted access card files → Attach file to card
POST /cards/{card_id}/comments with files[]Restricted access comment files → Attach file to comment
PATCH /cards/{card_id}/comments/{comment_id} with files[]Restricted access comment files → Attach file to comment

The restriction can be switched on in advance, without waiting for the shutdown date. In Company settings → Files turn on Restricted file access and then the option nested under it — Forbid uploading files without restricted access through the public API.

Once it is on, the deprecated upload routes are closed immediately. While it is off they keep working and keep creating files without restricted access — anyone who has the link can open them.

For companies created on or after 21 May 2026 the option is on from the start: they have never had the old routes open, so a new integration should use the new file API right away.

An attempt to upload a file through a deprecated route is rejected with 403. This applies to multipart requests specifically:

  • POST|PUT /cards/{card_id}/files with multipart/form-data
  • POST|PUT /cards/{card_id}/comments and PATCH /cards/{card_id}/comments/{comment_id} carrying files[]

Everything else on these routes keeps working: editing comment text, renaming a file through PATCH /cards/{card_id}/files/{id} and the other non-upload changes.

{
  "code": "PUBLIC_API_LEGACY_FILE_UPLOAD_DISABLED",
  "message": "Uploading files outside of restricted file access is disabled for the public API by company settings."
}
Quick check

After updating the integration, verify that:

  • a file of every type you use can be uploaded and downloaded;
  • files with type = 11 are downloaded through a signed link;
  • old files are still handled by the current code;
  • signed links are neither stored nor cached — they expire.
logo
Kaiten
If you have any questions or need help with integration feel free to write us at support@kaiten.ru