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
idstring (uuid)Unique identifier for the attachment. The create response also returns it as
asset_id.page_idstring (uuid)The wiki page the attachment belongs to.
namestringThe file name you sent when you requested the upload.
content_typestringThe MIME type you sent when you requested the upload, for example
image/png.sizenumberThe size in bytes that the upload credential allows. It is the smaller of the
sizeyou sent and your plan's file size limit.attributesobjectThe stored file metadata, with
name,type, andsizekeys. The API readsnameandcontent_typefrom here.asset_urlstringA relative path to the asset on the Plane server. To fetch the file, use Download a workspace page attachment.
is_uploadedbooleanfalsefrom the moment you request the upload until you confirm it, thentrue.created_atstring (date-time)When the upload was requested.
updated_atstring (date-time)When the attachment was last updated.
created_by_idstring (uuid)The user who requested the upload. Confirming the upload sets it to the user who confirmed it.
updated_by_idstring (uuid)The user who last updated the attachment.
{
"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
| Method | Path | Description |
|---|---|---|
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
- Call Create a workspace page attachment upload with the file's
name,type, andsize. The response carriesupload_data(a storage URL and form fields) andasset_id. - Send a
multipart/form-dataPOSTtoupload_data.url. Include every entry ofupload_data.fieldsas a form field, then the file itself as the last field, namedfile. Storage rejects a file larger than the attachment'ssizeor aContent-Typeother than the one you declared. - Call Confirm a workspace page attachment upload with the
asset_id. The attachment'sis_uploadedbecomestrue.
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_requestwithdetailPage is locked. - An archived page returns
400 invalid_requestwithdetailPage 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_typeset toPAGE_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.

