For AI agents: markdown of this page — /docs-content-en/entities/catalog-products/images.md documentation index — /llms.txt
Product images
Reads, uploads and deletes images for a catalog product. All routes require an API key with the catalog scope; uploads and deletes require a write-enabled key.
The methods return only the product's native images: its detail picture, preview picture, and MORE_PHOTO gallery items. Files stored in other custom File properties (propertyNNN) are not included.
These routes use the shared product ID space for simple products, SKUs, variations and services.
Bitrix24 API: catalog.productImage.list, catalog.productImage.get, catalog.productImage.add, catalog.productImage.delete
Scope: catalog
Safe handling of the image address
Treat detailUrl as untrusted input. The API validates only the URL shape and returns it without normalization. Do not make a server-side HTTP request to this address: doing so creates a server-side request forgery (SSRF) risk. A path beginning with / is relative to the Bitrix24 account origin. For a user interface, pass the address to a safe client-side component instead of downloading it through your backend.
The downloadUrl download link is not included in the response because it may contain a webhook path and secret. The API neither proxies nor downloads the file. A detailUrl containing a webhook path is also rejected.
Upload product image
POST /v1/catalog-products/:productId/images
Uploads a catalog product image from base64 content: a detail picture, a preview picture or a gallery image. The request body is flat JSON.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
productId (path) |
number | yes | Product ID. List: GET /v1/catalog-products. The ID of an SKU from GET /v1/catalog-skus, an offer from GET /v1/catalog-offers or a service from GET /v1/catalog-services also works |
Request fields (body)
| Field | Type | Required | Description |
|---|---|---|---|
type |
string | yes | Image type: DETAIL_PICTURE — detail picture, PREVIEW_PICTURE — preview picture, MORE_PHOTO — gallery image. Any other value is rejected before calling Bitrix24 |
fileName |
string | yes | File name with an extension, for example photo.png. An empty name is rejected |
fileContent |
string | yes | File content in base64 |
The body accepts no other fields: an extra field such as description returns 400 INVALID_PARAMS. The request body limit is 40 MiB.
Examples
curl — personal key
curl -X POST "https://vibecode.bitrix24.com/v1/catalog-products/7257/images" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "MORE_PHOTO",
"fileName": "photo.png",
"fileContent": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIHWP4z8DwHwAFgAI/ScL/nwAAAABJRU5ErkJggg=="
}'
curl — OAuth application
curl -X POST "https://vibecode.bitrix24.com/v1/catalog-products/7257/images" \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Authorization: Bearer USER_SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type": "MORE_PHOTO",
"fileName": "photo.png",
"fileContent": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIHWP4z8DwHwAFgAI/ScL/nwAAAABJRU5ErkJggg=="
}'
JavaScript — personal key
const res = await fetch('https://vibecode.bitrix24.com/v1/catalog-products/7257/images', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
type: 'MORE_PHOTO',
fileName: 'photo.png',
fileContent: 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIHWP4z8DwHwAFgAI/ScL/nwAAAABJRU5ErkJggg==',
}),
})
const { success, data } = await res.json()
console.log('Image ID:', data.id)
JavaScript — OAuth application
const res = await fetch('https://vibecode.bitrix24.com/v1/catalog-products/7257/images', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({
type: 'MORE_PHOTO',
fileName: 'photo.png',
fileContent: 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIHWP4z8DwHwAFgAI/ScL/nwAAAABJRU5ErkJggg==',
}),
})
const { success, data } = await res.json()
Response fields
A successful upload responds with HTTP status 201 Created.
| Field | Type | Description |
|---|---|---|
success |
boolean | Always true on success |
data |
object | Uploaded image |
data.id |
number | Image ID |
data.productId |
number | ID of the product that owns the image |
data.type |
string | Image type: DETAIL_PICTURE — detail picture, PREVIEW_PICTURE — preview picture, MORE_PHOTO — gallery image |
data.name |
string | File name |
data.createTime |
string | null | Creation time in ISO 8601 format with a UTC offset, or null |
data.detailUrl |
string | Image address — a path starting with / relative to the Bitrix24 account origin, or an absolute http/https URL. Access without a Bitrix24 account session is not guaranteed. Treat it as untrusted input — see Product images |
Response example
{
"success": true,
"data": {
"id": 38993,
"productId": 7257,
"type": "MORE_PHOTO",
"name": "photo.png",
"createTime": "2026-10-08T20:59:02+00:00",
"detailUrl": "https://cdn.bitrix24.com/b00000000/iblock/2ba/2bae996b883855a3997fde84f01c7aee/photo.png"
}
}
Error response example
400 — an unknown type, an empty file name, content that is not base64, or an extra body field:
{
"success": false,
"error": {
"code": "INVALID_PARAMS",
"message": "type, fileName and base64 fileContent are required"
}
}
Errors
| HTTP | Code | Description |
|---|---|---|
| 400 | INVALID_PARAMS |
The body failed validation: an unknown type, an empty or missing fileName, fileContent that is not base64, or another field in the body |
| 400 | INVALID_PARAMS |
productId is not a canonical positive integer — for example, abc, 0 or a value outside the JavaScript safe integer range |
| 404 | ENTITY_NOT_FOUND |
No product with this productId exists |
| 413 | PAYLOAD_TOO_LARGE |
The request body exceeds 40 MiB |
| 422 | BITRIX_ERROR |
Bitrix24 did not accept the file, for example a name with a non-image extension such as note.txt |
| 422 | BITRIX_ERROR |
The new image was not saved: replacing DETAIL_PICTURE or PREVIEW_PICTURE left the previous picture in place. The message is Product image was not saved |
| 502 | BITRIX_UNAVAILABLE |
Bitrix24 is unavailable or returned a response that failed the shape and safety checks |
| 401 | MISSING_API_KEY |
The X-Api-Key header is missing |
| 401 | INVALID_API_KEY |
The key is invalid |
| 401 | TOKEN_MISSING |
The key has no Bitrix24 tokens |
| 403 | SCOPE_DENIED |
The key does not have the catalog scope |
| 403 | WRITE_BLOCKED_READONLY_KEY |
The key is read-only. Uploads and deletes require a write-enabled key |
| 403 | BITRIX_ACCESS_DENIED |
Bitrix24 denied access to the catalog |
| 429 | RATE_LIMITED |
The request limit was reached. Retry after the time in the Retry-After header |
| 429 | OPERATION_TIME_LIMIT |
The Bitrix24 operation-time limit was reached. Retry after the time in the Retry-After header |
| 503 | BITRIX_TIMEOUT |
Bitrix24 did not respond in time, so the write outcome is unknown. Check the product image list before retrying |
Full list of common API errors — Errors.
Known specifics
- Replacing the detail and preview pictures. A product has one detail picture and one preview picture. Uploading
DETAIL_PICTUREorPREVIEW_PICTUREagain replaces the previous one: the response carries a newid, and the previousidcan no longer be read.MORE_PHOTOadds a picture to the gallery. - File content is not checked. Text uploaded as
photo.pngis saved as a picture. Make surefileContentis an image before uploading. - Identical content shares one file. Uploading the same content again creates an image with a new
id, but itsnameanddetailUrlcome from the earlier file, even iffileNamecarries a different name.