Skip to content

Attach a file to a bug

POST
/v1/bugs/{id}/files
curl --request POST \
--url 'https://beta-api.plune.ai/v1/bugs/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/files?name=example' \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: image/png' \
--data binary

A file onto a bug (#1066, ADR 0057: screenshots are attachments of the bug, not pictures in its text), an owner’s or a member’s. The body IS the file, as for a result’s (POST /v1/results/{id}/files): a picture (PNG, JPEG, WebP) at most 2 MiB, or a text (application/json, text/plain) at most 512 KiB as UTF-8, cleaned of credentials before it is kept. Up to 30 files, 20 pictures and 10 texts of them in the database. The project’s files share one budget of 1 GiB: an upload that would pass it first deletes the project’s oldest files kept in the database — a person’s as much as a reporter’s — and its answer says what went (evicted). The list of the same files says beforehand what one more would cost (budget.evicts). Another file — a video, an archive — needs the project’s own bucket: …/files/uploads, then PUT, then POST /v1/files/{id}/complete. A reader of the project cannot add one; someone else’s case, run or bug is a 404, the same as an invented one. 600 requests a minute a person. Like the bug’s copies, a file attached to a bug is never sent away by the budget, so the files of bugs together take at most 50% of it (413 bug_files_share). It goes when the bug goes, or by DELETE /v1/files/{id}. Audited on the bug: bug/event with the file’s name and size.

id
required
string format: uuid
X-Plune-Project
string

Which of your projects to act in — an id from GET /v1/projects. Absent, your default project. A project you are not a member of answers 404, the same as one that does not exist. Ignored under a bearer token, which is bound to the project it was minted in.

name
required
string
<= 200 characters

What the file is called; only the last segment of a path is kept, cleaned of credentials.

string format: binary

Stored. evicted is there only when the budget sent files of results or cases away for it

Media type application/json

A person’s file just stored, and — only when it sent anything away — what the budget evicted for it.

object
id
required
string
name
required

The last segment of the name it was uploaded with, cleaned of credentials as a text is.

string
contentType
required

In the database (storage: db): image/png, image/jpeg, image/webp, application/json or text/plain — a log is text/plain. In the bucket (storage: bucket): the media type it was announced with, lower case and without parameters, any type.

string
size
required

Bytes as kept: in the database a picture at most 2 MiB and a text at most 512 KiB, counted after its credentials are cleaned, so it can differ from what was sent; in the bucket the size that was announced and found there.

integer
storage
required

db: Plune keeps the bytes, GET /v1/files/{id} returns them. bucket: they are in the project’s own bucket, and GET /v1/files/{id} answers 409 in_bucket (the way to read them is GET /v1/files/{id}/link).

string
Allowed values: db bucket
createdAt
required
string format: date-time
createdBy
required

The user who added it; null once that account is gone.

string
nullable
evicted

What the 1 GiB budget of the project sent away to make room (#1234): the project’s oldest files kept in the database, a person’s as much as a reporter’s.

object
count
required
integer
>= 1
bytes
required
integer
>= 1
Example
{
"id": "3f0c2a7e-1b5d-4c8e-9a61-2d7f4e8b0c15",
"name": "price-list-eur.png",
"contentType": "image/png",
"size": 48213,
"storage": "db",
"createdAt": "2026-10-13T09:00:00.000Z",
"createdBy": "6f1c2b3a-0000-4000-8000-0000000000a2"
}

No name (or one over 200 characters once cleaned), an empty file, or a text with nothing left once cleaned

Media type application/json
object
error
required
string
Example generated
{
"error": "example"
}

No / invalid token or session

A reader of the project

Media type application/json
object
error
required
string
Example generated
{
"error": "example"
}

No such bug in this project

Media type application/json
object
error
required
string
Example generated
{
"error": "example"
}

It already has 20 pictures (or 10 texts, for a text)

Media type application/json
object
error
required
string
Example generated
{
"error": "example"
}

A picture larger than 2 MiB, or a text larger than 512 KiB — as sent, or once cleaned; or the files of bugs would take more than 50% of the storage budget (code: bug_files_share)

Media type application/json
object
error
required
string
Example generated
{
"error": "example"
}

A type that is not listed — it needs the project’s bucket; a text in a charset other than UTF-8; or bytes that are not UTF-8 text

Media type application/json
object
error
required
string
Example generated
{
"error": "example"
}

Rate-limited: the per-route throttle, or the per-minute request limit of the plan an API token counts by (#1442; the body names the plan, #2092). Retry-After carries the seconds until the window rolls over.

Media type application/json
object
error
required
string
Example generated
{
"error": "example"
}
Retry-After
integer

Seconds until the window rolls over