Skip to content

Workspace page attachments overview ​

A workspace page attachment is a file that belongs to a wiki page, such as an image, a PDF, or a spreadsheet. The file bytes never pass through the Plane API. You ask the API for an upload credential, upload the file straight to object storage with it, and then tell the API the upload is done.

This resource serves only workspace (wiki) pages. A project page id in {page_id} returns 404, the same answer as a page that doesn't exist or that you can't see.

Learn more about attachments in pages

The workspace page attachment object ​

Attributes ​

  • id string (uuid)

    Unique identifier for the attachment. The create response also returns it as asset_id.

  • page_id string (uuid)

    The wiki page the attachment belongs to.

  • name string

    The file name you sent when you requested the upload.

  • content_type string

    The MIME type you sent when you requested the upload, for example image/png.

  • size number

    The size in bytes that the upload credential allows. It is the smaller of the size you sent and your plan's file size limit.

  • attributes object

    The stored file metadata, with name, type, and size keys. The API reads name and content_type from here.

  • asset_url string

    A relative path to the asset on the Plane server. To fetch the file, use Download a workspace page attachment.

  • is_uploaded boolean

    false from the moment you request the upload until you confirm it, then true.

  • created_at string (date-time)

    When the upload was requested.

  • updated_at string (date-time)

    When the attachment was last updated.

  • created_by_id string (uuid)

    The user who requested the upload. Confirming the upload sets it to the user who confirmed it.

  • updated_by_id string (uuid)

    The user who last updated the attachment.

Response200
json
{
  "id": "8f4c2b1e-0d3a-4f7b-9c21-6e5a8b7d4f13",
  "page_id": "9c1f0b3d-6d2e-4c9a-8b41-2f7e5a0d6c88",
  "name": "architecture-diagram.png",
  "content_type": "image/png",
  "size": 482133.0,
  "attributes": {
    "name": "architecture-diagram.png",
    "type": "image/png",
    "size": 482133
  },
  "asset_url": "/api/assets/v2/workspaces/my-team/projects/None/8f4c2b1e-0d3a-4f7b-9c21-6e5a8b7d4f13/",
  "is_uploaded": true,
  "created_at": "2026-01-14T09:22:41.478363Z",
  "updated_at": "2026-01-14T09:23:05.112907Z",
  "created_by_id": "16c61a3a-512a-48ac-b0be-b6b46fe6f430",
  "updated_by_id": "16c61a3a-512a-48ac-b0be-b6b46fe6f430"
}

Endpoints ​

MethodPathDescription
GET/api/v2/workspaces/{slug}/pages/{page_id}/attachments/List workspace page attachments
GET/api/v2/workspaces/{slug}/pages/{page_id}/attachments/{pk}/Get a workspace page attachment
POST/api/v2/workspaces/{slug}/pages/{page_id}/attachments/Create a workspace page attachment upload
PATCH/api/v2/workspaces/{slug}/pages/{page_id}/attachments/{pk}/Confirm a workspace page attachment upload
DELETE/api/v2/workspaces/{slug}/pages/{page_id}/attachments/{pk}/Delete a workspace page attachment
GET/api/v2/workspaces/{slug}/pages/{page_id}/attachments/{pk}/download/Download a workspace page attachment

Upload a file in three steps ​

  1. Call Create a workspace page attachment upload with the file's name, type, and size. The response carries upload_data (a storage URL and form fields) and asset_id.
  2. Send a multipart/form-data POST to upload_data.url. Include every entry of upload_data.fields as a form field, then the file itself as the last field, named file. Storage rejects a file larger than the attachment's size or a Content-Type other than the one you declared.
  3. Call Confirm a workspace page attachment upload with the asset_id. The attachment's is_uploaded becomes true.

Until step 3, List workspace page attachments leaves the attachment out, and Download answers 400. You can still read it by id, so a client that crashed between steps can find and confirm it.

Creating an attachment doesn't change the page body. The page's description_html stays as it was.

Locked and archived pages ​

Reads work on any page you can see. Create, confirm, and delete need edit access to the page, and the page must be active and unlocked:

  • A locked page returns 400 invalid_request with detail Page is locked.
  • An archived page returns 400 invalid_request with detail Page is archived.
  • A private page, or a page in a private collection, needs Edit access on the page or the collection. Without it, the write returns 403 forbidden.

Response shaping ​

Every read of the attachment object accepts ?fields= for sparse responses. See Sparse fields. Errors follow the shared problem+json contract.

Changed from v1 ​

  • v2 adds the list and the create. In v1 you request a page attachment upload through the workspace assets endpoint with entity_type set to PAGE_DESCRIPTION, and there is no way to list a page's attachments.
  • The confirm, read, delete, and download routes keep the v1 paths, with {pk} in place of {attachment_id}.

See Migrating from v1 for the full list.