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 or a document 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; its type is determined by the extension in the file name. PNG, JPEG, WebP, and GIF images are re-encoded on the server: PNG, JPEG, and WebP are converted to WebP, and GIF is re-encoded as GIF, preserving animation. TXT, MD, CSV, HTML, XLSX, and ZIP documents are stored unchanged. Limits: up to 10 MB per file, up to 24 million pixels per image, up to 5 attachments per message and up to 25 per ticket.

Request fields (multipart/form-data)

Field Type Required Description
Fieldfile Typefile Requiredyes DescriptionA file up to 10 MB. An image — extension .png, .jpg, .jpeg, .webp, or .gif. A document — .txt, .md, .csv, .html, .htm, .xlsx, or .zip

Examples

curl — personal key

Terminal
curl -X POST https://vibecode.bitrix24.com/v1/feedback/attachments \
  -H "X-Api-Key: YOUR_API_KEY" \
  -F "file=@screenshot.png"

curl — OAuth application

Terminal
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

javascript
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

javascript
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
Fieldsuccess Typeboolean DescriptionAlways true on success
Fielddata Typeobject DescriptionThe uploaded attachment
Fielddata.id Typestring DescriptionAttachment UUID. Passed in attachmentIds when creating a ticket or comment
Fielddata.kind Typestring DescriptionAttachment class: IMAGE or DOCUMENT
Fielddata.mime Typestring DescriptionType after processing. For an image — image/webp for PNG, JPEG, and WebP, image/gif for GIF. For a document — the type by extension, for example text/plain or application/zip
Fielddata.sizeBytes Typenumber DescriptionSize of the stored file in bytes
Fielddata.width Typenumber DescriptionWidth in pixels. 0 for a document
Fielddata.height Typenumber DescriptionHeight in pixels. 0 for a document
Fielddata.thumbnailUrl Typestring · null DescriptionPath to the attachment thumbnail. null for a document
Fielddata.originalName Typestring · null DescriptionOriginal file name. null if the image was uploaded without a file name. A document without a name gets attachment.<extension>
Fielddata.expiresAt Typestring DescriptionThe time after which an unlinked attachment is deleted (ISO 8601)

Response example

The image screenshot.png was uploaded:

JSON
{
  "success": true,
  "data": {
    "id": "15ae6203-e67c-4378-912c-9b0465360c79",
    "kind": "IMAGE",
    "mime": "image/webp",
    "sizeBytes": 560,
    "width": 640,
    "height": 360,
    "thumbnailUrl": "/v1/feedback/_orphan/15ae6203-e67c-4378-912c-9b0465360c79/thumb",
    "originalName": "screenshot.png",
    "expiresAt": "2026-10-09T09:27:47.506Z"
  }
}

The document note.txt was uploaded — no thumbnail and no dimensions:

JSON
{
  "success": true,
  "data": {
    "id": "f4ec1f18-431b-49ec-85bb-bedcfce6da7d",
    "kind": "DOCUMENT",
    "mime": "text/plain",
    "sizeBytes": 16,
    "width": 0,
    "height": 0,
    "thumbnailUrl": null,
    "originalName": "note.txt",
    "expiresAt": "2026-10-09T09:25:40.292Z"
  }
}

Error response example

413 — file larger than 10 MB:

JSON
{
  "success": false,
  "error": {
    "code": "IMAGE_TOO_LARGE",
    "message": "File too large: a feedback attachment is capped at 10 MB (10485760 bytes)",
    "hint": "Shrink the image below 10 MB (lower the resolution or re-encode as JPEG or WebP) and upload it again. The cap applies to each file and is not raised by retrying."
  }
}

Errors

HTTP Code Description
HTTP400 CodeNO_FILE DescriptionNo file was passed in the file field
HTTP400 CodeINVALID_MIME DescriptionThe file name extension is not on the allowed list. A file without an extension is rejected unless its Content-Type is image/png, image/jpeg, image/webp, or image/gif
HTTP400 CodeMIME_MISMATCH DescriptionThe contents do not match the type: an image signature is not recognized as PNG, JPEG, WebP, or GIF, or a .zip or .xlsx file lacks the ZIP archive signature. A mismatch between two image formats is not an error — processing follows the actual contents
HTTP400 CodeINVALID_FILE_EMPTY DescriptionThe file is empty
HTTP400 CodeIMAGE_DECODE_FAILED DescriptionThe 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
HTTP400 CodeIMAGE_TOO_MANY_PIXELS DescriptionMore than 24 million pixels
HTTP400 CodeTOO_MANY_FRAMES DescriptionThe animation has more than 30 frames
HTTP402 CodeACCOUNT_FROZEN DescriptionThe balance is frozen — uploading attachments is unavailable while it is frozen
HTTP403 CodeMANAGEMENT_KEY_READ_ONLY DescriptionA management key cannot upload attachments
HTTP403 CodeWRITE_BLOCKED_READONLY_KEY DescriptionThe key is read-only — see access rights
HTTP413 CodeIMAGE_TOO_LARGE DescriptionFile larger than 10 MB. The same code applies to images and documents
HTTP401 CodeMISSING_API_KEY DescriptionThe X-Api-Key header was not passed
HTTP429 CodeRATE_LIMITED DescriptionMore than 5 uploads per minute from one key. This is the platform-wide cap; the current limit is returned 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. A document is stored byte for byte; its mime is determined by the extension, not the contents. An archive is never unpacked — for .zip and .xlsx only the ZIP signature is checked.

The attachment class is chosen by the file name extension, not by Content-Type. An image is processed by its actual contents, so a JPEG saved as image.png is accepted, and the mime in the response is the result of re-encoding. A file without an extension — for example blob, the default name FormData.append assigns to a Blob object — is accepted only as an image and only when its Content-Type is image/png, image/jpeg, image/webp, or image/gif.

Operations on a linked attachment

Once linked to a ticket, an attachment is available for download and deletion by its id (the data.attachments[].id field in Get a ticket). These operations work with binary data, so they have no JSON body and no standard set of 4 examples.

Download an attachment

GET /v1/feedback/:id/attachments/:attId/file

Returns the attachment file. Available to a key that has access to the ticket. An image arrives with its own type — image/webp or image/gif — and supports ETag and If-None-Match: a conditional request returns 304 Not Modified. A document always arrives as application/octet-stream with the Content-Disposition: attachment header and the original file name, without ETag.

Parameter Type Required Description
Parameterid (path) Typestring Requiredyes DescriptionTicket UUID
ParameterattId (path) Typestring Requiredyes DescriptionAttachment UUID from data.attachments[].id
Terminal
curl -H "X-Api-Key: YOUR_API_KEY" \
  "https://vibecode.bitrix24.com/v1/feedback/a1b2c3d4-1111-2222-3333-444455556666/attachments/1209c405-1f99-4240-95e5-d5cc0cd43560/file" \
  -o attachment.webp

If the attachment does not exist, is not accessible to the key, or does not belong to the specified ticket, the request returns 404 NOT_FOUND. If the balance is frozen, it returns 402 ACCOUNT_FROZEN.

Attachment thumbnail

GET /v1/feedback/:id/attachments/:attId/thumb

Returns a scaled-down thumbnail of an image. Content-Type is always image/jpeg. Parameters and access rules are the same as for the file download. A document has no thumbnail — the request returns 404 NOT_FOUND.

Terminal
curl -H "X-Api-Key: YOUR_API_KEY" \
  "https://vibecode.bitrix24.com/v1/feedback/a1b2c3d4-1111-2222-3333-444455556666/attachments/1209c405-1f99-4240-95e5-d5cc0cd43560/thumb" \
  -o thumb.jpg

Delete an attachment

DELETE /v1/feedback/:id/attachments/:attId

Deletes the attachment. Available to whoever uploaded it. On success, returns 204 No Content with an empty body. Deletion is not allowed if the other side has already replied after the attachment was uploaded.

Parameter Type Required Description
Parameterid (path) Typestring Requiredyes DescriptionTicket UUID
ParameterattId (path) Typestring Requiredyes DescriptionAttachment UUID
Parameterreason (body) Typestring Requiredno DescriptionDeletion reason, 3–500 characters
Terminal
curl -X DELETE -H "X-Api-Key: YOUR_API_KEY" \
  "https://vibecode.bitrix24.com/v1/feedback/a1b2c3d4-1111-2222-3333-444455556666/attachments/1209c405-1f99-4240-95e5-d5cc0cd43560"
HTTP Code Description
HTTP402 CodeACCOUNT_FROZEN DescriptionThe balance is frozen
HTTP403 CodeDELETE_NOT_ALLOWED DescriptionThe other side has already replied after the attachment was uploaded
HTTP403 CodeWRITE_BLOCKED_READONLY_KEY DescriptionThe key is read-only — see access rights
HTTP400 CodeREASON_INVALID Descriptionreason shorter than 3 or longer than 500 characters
HTTP404 CodeNOT_FOUND DescriptionThe attachment was not found, is not owned by the key, or does not belong to the ticket

See also