Skip to content

Commit 512e921

Browse files
authored
Merge pull request #59 from makeplane/issue-attachments-api
Added issue attachments API endpoint
2 parents cfc1a21 + 8130421 commit 512e921

File tree

7 files changed

+376
-41
lines changed

7 files changed

+376
-41
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
title: Complete upload
3+
description: Notifies the server that an attachment has been successfully uploaded to S3. This endpoint should be called after you've [uploaded the file](/api-reference/issue-attachments/upload-file).
4+
api: PATCH /api/v1/workspaces/{workspace-slug}/projects/{project_id}/issues/{issue_id}/issue-attachments/{asset_id}/
5+
---
6+
7+
### Path parameters
8+
9+
<ParamField path="workspace-slug" type="string" required>
10+
The workspace-slug represents the unique workspace identifier for a workspace in Plane. It can be found in the URL. For example, in the URL `https://app.plane.so/my-team/projects/`, the workspace slug is `my-team`.
11+
12+
</ParamField>
13+
<ParamField path="project_id" type="string" required>The unique identifier of the project</ParamField>
14+
<ParamField path="issue_id" type="string" required>The unique identifier of the issue</ParamField>
15+
16+
<ParamField path="asset_id" type="string" required>The unique identifier of the attachment generated by the [Get upload credentials](/api-reference/issue-attachments/get-upload-credentials#response) endpoint. </ParamField>
17+
18+
19+
20+
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
---
2+
title: Get attachments
3+
description: Gets all the attachments in the issue.
4+
api: GET /api/v1/workspaces/{workspace-slug}/projects/{project_id}/issues/{issue_id}/issue-attachments/
5+
---
6+
7+
### Path parameters
8+
9+
<ParamField path="workspace-slug" type="string" required>
10+
The workspace-slug represents the unique workspace identifier for a workspace in Plane. It can be found in the URL. For example, in the URL `https://app.plane.so/my-team/projects/`, the workspace slug is `my-team`.
11+
12+
</ParamField>
13+
<ParamField path="project_id" type="string" required>The unique identifier of the project</ParamField>
14+
<ParamField path="issue_id" type="string" required>The unique identifier of the issue</ParamField>
15+
16+
### Response
17+
18+
```json
19+
{
20+
"id": "<asset-id>",
21+
"created_at": "2024-10-30T09:32:32.815273Z",
22+
"updated_at": "2024-10-30T09:32:35.533136Z",
23+
"deleted_at": null,
24+
"attributes": {
25+
"name": "example.png",
26+
"size": 135686,
27+
"type": "image/png"
28+
},
29+
"asset": "<workspace-id>/<unique-id>-example.png",
30+
"entity_type": "ISSUE_ATTACHMENT",
31+
"is_deleted": false,
32+
"is_archived": false,
33+
"external_id": null,
34+
"external_source": null,
35+
"size": 135686.0,
36+
"is_uploaded": true,
37+
"storage_metadata": {
38+
"ETag": "<etag-hash>",
39+
"Metadata": {},
40+
"ContentType": "image/png",
41+
"LastModified": "2024-10-30T09:32:34+00:00",
42+
"ContentLength": 135686
43+
},
44+
"created_by": "<user-id>",
45+
"updated_by": "<user-id>",
46+
"workspace": "<workspace-id>",
47+
"project": "<project-id>",
48+
"issue": "<issue-id>"
49+
}
50+
```
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
---
2+
title: Get upload credentials
3+
description: Creates a pre-signed POST form data for uploading an attachment directly to S3. This endpoint handles the first step of the two-and-a-half step upload process where you first get the upload credentials and then use them to upload the actual file.
4+
api: POST /api/v1/workspaces/{workspace-slug}/projects/{project_id}/issues/{issue_id}/issue-attachments/
5+
---
6+
7+
### Path parameters
8+
9+
<ParamField path="workspace-slug" type="string" required>
10+
The workspace-slug represents the unique workspace identifier for a workspace in Plane. It can be found in the URL. For example, in the URL `https://app.plane.so/my-team/projects/`, the workspace slug is `my-team`.
11+
12+
</ParamField>
13+
<ParamField path="project_id" type="string" required>The unique identifier of the project</ParamField>
14+
<ParamField path="issue_id" type="string" required>The unique identifier of the issue</ParamField>
15+
16+
### Body
17+
18+
<ParamField body="name" type="string" required>Original filename of the attachment</ParamField>
19+
<ParamField body="type" type="string" required>Size of the file in bytes</ParamField>
20+
<ParamField body="size" type="integer" required>MIME type of the file (e.g., `image/png`, `application/pdf`)</ParamField>
21+
22+
23+
### Response
24+
Returns an object containing the S3 pre-signed POST data for direct upload.
25+
26+
```json
27+
{
28+
"upload_data": {
29+
"url": "<upload-url>",
30+
"fields": {
31+
"Content-Type": "image/png",
32+
"key": "<workspace-id>/<unique-id>-filename",
33+
"x-amz-algorithm": "AWS4-HMAC-SHA256",
34+
"x-amz-credential": "<REDACTED_AWS_KEY>/<date>/<region>/s3/aws4_request",
35+
"x-amz-date": "<ISO8601_TIMESTAMP>",
36+
"policy": "<BASE64_ENCODED_POLICY>",
37+
"x-amz-signature": "<SIGNATURE_HASH>"
38+
}
39+
},
40+
"asset_id": "<uuid>",
41+
"attachment": {
42+
"id": "<uuid>",
43+
"created_at": "2025-01-03T12:07:35.621734Z",
44+
"updated_at": "2025-01-03T12:07:35.621766Z",
45+
"deleted_at": null,
46+
"attributes": {
47+
"name": "filename",
48+
"type": "image/png",
49+
"size": 5242880
50+
},
51+
"asset": "<workspace-id>/<unique-id>-filename",
52+
"entity_type": "ISSUE_ATTACHMENT",
53+
"is_deleted": false,
54+
"is_archived": false,
55+
"external_id": null,
56+
"external_source": null,
57+
"size": 5242880.0,
58+
"is_uploaded": false,
59+
"storage_metadata": {},
60+
"created_by": "<user-id>",
61+
"updated_by": null,
62+
"workspace": "<workspace-id>",
63+
"project": "<project-id>",
64+
"issue": "<issue-id>",
65+
},
66+
"asset_url": "/api/assets/v2/workspaces/<workspace-slug>/projects/<project-id>/issues/<issue-id>/attachments/<asset-id>/"
67+
}
68+
```
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
---
2+
title: Overview
3+
description: Allows you to manage file attachments associated with issues. You can upload new attachments and retrieve existing attachments for a specific issue.
4+
---
5+
6+
```http
7+
GET /api/v1/workspaces/:workspace-slug/projects/:project_id/issues/:issue_id/issue-attachments/
8+
POST /api/v1/workspaces/:workspace-slug/projects/:project_id/issues/:issue_id/issue-attachments/
9+
PATCH /api/v1/workspaces/:workspace-slug/projects/:project_id/issues/:issue_id/issue-attachments/asset-id/
10+
```
11+
12+
## Upload Process
13+
14+
1. Get the [upload credentials](/api-reference/issue-attachments/get-upload-credentials).
15+
2. [Upload the file](/api-reference/issue-attachments/upload-file) to storage.
16+
3. [Complete attachment upload](/api-reference/issue-attachments/complete-upload) to notify server.
17+
18+
## Issue attachment object
19+
20+
**Attributes**
21+
22+
* `id` _string_
23+
24+
Unique identifier for the attachment
25+
26+
* `created_at` , `updated_at`, `deleted_at` _timestamp_
27+
28+
Timestamp when the attachment was created, when it was last modified or deleted
29+
30+
* `attributes` _object_
31+
32+
Contains file metadata:
33+
34+
* `name` _string_
35+
36+
Original filename of the attachment
37+
38+
* `size` _integer_
39+
40+
File size in bytes
41+
42+
* `type` _string_
43+
44+
MIME type of the file
45+
46+
* `asset` _string_
47+
48+
Storage path/identifier for the attachment file
49+
50+
* `entity-type` _string_
51+
52+
Always `ISSUE_ATTACHMENT` for issue attachments
53+
54+
* `is_deleted` _boolean_
55+
56+
Whether the attachment has been deleted
57+
58+
* `is_archived` _boolean_
59+
60+
Whether the attachment has been archived
61+
62+
* `external_id` _string_ or _null_
63+
64+
External identifier if the issue and its attachments are imported to Plane
65+
66+
* `external_source` _string_ or _null_
67+
68+
Name of the source if the issue and its attachments are imported to Plane
69+
70+
* `size` _integer_
71+
72+
File size in bytes
73+
74+
* `is_uploaded` _boolean_
75+
76+
Whether the file has been successfully uploaded
77+
78+
* `storage_metadata` _object_
79+
80+
Cloud storage metadata:
81+
82+
* `ETag` _string_
83+
84+
Storage provider's entity tag
85+
86+
* `Metadata` _object_
87+
88+
Additional storage metadata
89+
90+
* `ContentType` _object_
91+
92+
MIME type of stored file
93+
94+
* `LastModified` _timestamp_
95+
96+
Last modification time in storage
97+
98+
* `ContentLength` _integer_
99+
100+
File size in bytes
101+
102+
* `created_by` _string_
103+
104+
ID of user who created the attachment
105+
106+
* `updated_by` _string_
107+
108+
ID of user who last modified the attachment
109+
110+
* `updated_by` _string_
111+
112+
ID of user who last modified the attachment
113+
114+
* `workspace` _string_
115+
116+
ID of workspace containing the attachment
117+
118+
* `project` _string_
119+
120+
ID of project containing the issue
121+
122+
* `issue` _string_
123+
124+
ID of issue containing the attachment
125+
126+
127+
<ResponseExample>
128+
```json JSON
129+
{
130+
"id": "8caf3ed5-4f57-9674-76c4fce146b2",
131+
"created_at": "2024-10-30T09:32:32.815273Z",
132+
"updated_at": "2024-10-30T09:32:35.533136Z",
133+
"deleted_at": null,
134+
"attributes": {
135+
"name": "plane-logo.png",
136+
"size": 135686,
137+
"type": "image/png"
138+
},
139+
"asset": "9b8aab8a-9052-fc735350abe8/6893d862ecb740d4b7f9f6542cda539c-plane.png",
140+
"entity_type": "ISSUE_ATTACHMENT",
141+
"is_deleted": false,
142+
"is_archived": false,
143+
"external_id": null,
144+
"external_source": null,
145+
"size": 135686.0,
146+
"is_uploaded": true,
147+
"storage_metadata": {
148+
"ETag": "\"72d0d4be99999fe60c2fbc08c8b\"",
149+
"Metadata": {},
150+
"ContentType": "image/png",
151+
"LastModified": "2024-10-30T09:32:34+00:00",
152+
"ContentLength": 135686
153+
},
154+
"created_by": "575de6bf-e120-43bb-9f6a-eae276210575",
155+
"updated_by": "575de6bf-e120-43bb-9f6a-eae276210575",
156+
"workspace": "9b8aab8a-9s6a-99ac-fc735350abe8",
157+
"project": "1790bd-5262-42fb-ac55-568c19a5",
158+
"issue": "7ba090-7702-4e26-a61e-aa6b866f7",
159+
}
160+
```
161+
</ResponseExample>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
title: Upload file
3+
description: Upload the file using the credentials generated by the [Get upload credentials](/api-reference/issue-attachments/get-upload-credentials) endpoint.
4+
api: POST paste-upload-url
5+
---
6+
7+
### Body
8+
9+
<ParamField body="Content-Type" type="string" required>The MIME type of the file</ParamField>
10+
<ParamField body="key" type="string" required>The target path/filename in S3</ParamField>
11+
<ParamField body="x-amz-algorithm" type="string" required>AWS signature algorithm (AWS4-HMAC-SHA256)</ParamField>
12+
<ParamField body="x-amz-credential" type="string" required>AWS signature algorithm (AWS4-HMAC-SHA256)</ParamField>
13+
<ParamField body="x-amz-date" type="string" required>Request timestamp</ParamField>
14+
<ParamField body="policy" type="string" required>Base64-encoded policy document</ParamField>
15+
<ParamField body="x-amz-signature" type="string" required>Request signature</ParamField>
16+
<ParamField body="file" type="file" required>The file to be uploaded</ParamField>
17+

0 commit comments

Comments
 (0)