For AI agents: markdown of this page — /docs-content-en/feedback/attachments.md documentation index — /llms.txt
Upload an attachment
POST /v1/feedback/attachments
Uploads an image and returns its ID for later linking to a ticket or comment. The upload is two-step: first the file is sent here, then the returned id is passed in the attachmentIds field when creating a ticket or adding a comment.
The file is passed as multipart/form-data in the file field. PNG, JPEG, WebP, and GIF are accepted. PNG, JPEG, and WebP are converted to WebP on the server side; GIF is re-encoded as GIF, preserving animation. Limits: up to 10 MB and up to 24 million pixels per file, up to 5 attachments per message and up to 25 per ticket.
Request fields (multipart/form-data)
| Field | Type | Required | Description |
|---|---|---|---|
file |
file | yes | A PNG, JPEG, WebP, or GIF image, up to 10 MB |
Examples
curl — personal key
curl -X POST https://vibecode.bitrix24.com/v1/feedback/attachments \
-H "X-Api-Key: YOUR_API_KEY" \
-F "file=@screenshot.png"
curl — OAuth application
curl -X POST https://vibecode.bitrix24.com/v1/feedback/attachments \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Authorization: Bearer USER_SESSION_TOKEN" \
-F "file=@screenshot.png"
JavaScript — personal key
const form = new FormData()
form.append('file', fileInput.files[0])
const res = await fetch('https://vibecode.bitrix24.com/v1/feedback/attachments', {
method: 'POST',
headers: { 'X-Api-Key': 'YOUR_API_KEY' },
body: form,
})
const { data } = await res.json()
// pass data.id in attachmentIds when creating a ticket or comment
JavaScript — OAuth application
const form = new FormData()
form.append('file', fileInput.files[0])
const res = await fetch('https://vibecode.bitrix24.com/v1/feedback/attachments', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
},
body: form,
})
const { data } = await res.json()
Response fields
| Field | Type | Description |
|---|---|---|
success |
boolean | Always true on success |
data.id |
string | Attachment UUID. Passed in attachmentIds when creating a ticket or comment |
data.mime |
string | Type after processing: image/webp for PNG, JPEG, and WebP, image/gif for GIF |
data.sizeBytes |
number | Size of the processed file in bytes |
data.width |
number | Width in pixels |
data.height |
number | Height in pixels |
data.thumbnailUrl |
string | Path to the attachment thumbnail |
data.originalName |
string | Original file name |
data.expiresAt |
string | The time after which an unlinked attachment is deleted (ISO 8601) |
Response example
{
"success": true,
"data": {
"id": "1209c405-1f99-4240-95e5-d5cc0cd43560",
"mime": "image/webp",
"sizeBytes": 20480,
"width": 1280,
"height": 720,
"thumbnailUrl": "/v1/feedback/_orphan/1209c405-1f99-4240-95e5-d5cc0cd43560/thumb",
"originalName": "screenshot.png",
"expiresAt": "2026-04-19T11:30:00.000Z"
}
}
Error response example
413 — file larger than 10 MB:
{
"success": false,
"error": {
"code": "IMAGE_TOO_LARGE",
"message": "File too large"
}
}
Errors
| HTTP | Code | Description |
|---|---|---|
| 400 | NO_FILE |
No file was passed in the file field |
| 400 | INVALID_MIME |
The format is not one of PNG, JPEG, WebP, GIF — whether declared by the client or detected from the file contents |
| 400 | MIME_MISMATCH |
The file signature was not recognised at all: the contents belong to none of the four formats. A mismatch between two allowed formats is not an error — processing follows the actual contents |
| 400 | IMAGE_DECODE_FAILED |
The file could not be parsed as an image: the data is corrupted, the image has no dimensions, or processing did not finish within 5 seconds |
| 400 | IMAGE_TOO_MANY_PIXELS |
More than 24 million pixels |
| 400 | TOO_MANY_FRAMES |
The animation has more than 30 frames |
| 413 | IMAGE_TOO_LARGE |
File larger than 10 MB |
| 401 | MISSING_API_KEY |
The X-Api-Key header was not passed |
| 429 | RATE_LIMITED |
More than 5 uploads per minute from one key. This is the platform-wide cap and it is divided across the backend replicas, so the effective value arrives in the X-RateLimit-Limit header |
For the full list of common API errors, see Errors.
Known specifics
An attachment lives for an hour before it is linked. An uploaded attachment is initially not linked to any ticket and is deleted after expiresAt (in one hour) if its id is not passed in attachmentIds when creating a ticket or comment. Once linked, the attachment is stored together with the ticket.
Format after processing. PNG, JPEG, and WebP are converted to WebP, so their mime in the response is image/webp. GIF is re-encoded as GIF (image/gif), preserving animation, up to 30 frames; beyond that the upload is rejected with 400 TOO_MANY_FRAMES. The sizeBytes, width, and height fields refer to the processed file.
The file extension may not match its contents. The platform derives the client-declared type from the file extension, so a JPEG saved as image.png arrives as image/png. Such a file is accepted: processing follows the actual contents, and the mime in the response is the result of re-encoding. MIME_MISMATCH is reserved for the case where the signature is not recognised at all.