Images
Lookup and management of the images attached to products — single-product lookup, cursor-paginated global inventory, gallery metadata, image roles and explicit store_id support.
Overview
The image API lets you:
- list every image of a specific product;
- walk the global image inventory of the catalog;
- tell enabled and disabled images apart;
- identify the
image,small_imageandthumbnailroles; - work deterministically with
store_id; - run an initial load and a full reconciliation using cursor pagination;
- keep using the existing endpoints to create, update and delete images;
- remove every image of a product in a single call;
- remove specific images from several products in a single call.
Method map
| Method | Route | Purpose |
|---|---|---|
| GET | /api2/products/imagem | Look up a product's images |
| GET | /api2/products/imagens | Paginated global inventory |
| POST | /api2/products/imagem | Create an image |
| PUT | /api2/products/imagem | Update an image |
| DELETE | /api2/products/imagem | Delete one image |
| DELETE | /api2/products/imagens | Delete all or delete selectively in bulk |
PATCH /api2/products/imagem responds 405. Updates use PUT.limit.limit is omitted.has_next + next_cursor. No page or offset.store_id=0 is the administrative/global scope.OAuth2 permissions
Reading and writing images use different permissions. When configuring the OAuth2 client in the admin panel, grant only what the integration needs.
| Operation | Permission | In the admin panel |
|---|---|---|
GET /api2/products/imagemGET /api2/products/imagens | products/read | Products › View products |
POST, PUT and DELETE /api2/products/imagemDELETE /api2/products/imagens | products/images | Products › Manage product images |
products/read can query and reconcile images but receives 403 when trying to create, update or delete — bulk deletes included.Look up a product's images New
Read-only operation: returns every image in a product's gallery, including disabled ones, with the roles and label in the context of the requested store.
List the images attached to a specific product.
GET /api2/products/imagem?type=sku&product_id=27.9353&store_id=1&limit=100
Authorization: Bearer {access_token}
store_id=1 because it is a common storefront store. Each project must send the ID of its own store; store_id=0 is the administrative/global scope.Parameters
product_id is interpreted: sku or id, following the same convention as the other image endpoints. The certified example uses sku.type.0. Sending the integration's storefront store explicitly is recommended.100; accepts 1 to 200.next_cursor returned by the previous call.Response example
{
"success": true,
"product_id": 115973,
"sku": "27.9353",
"store_id": 1,
"images": [
{
"image_id": "690992",
"file": "/e/s/escova-robinson-taca-soft.jpg_1.jpg",
"label": "Imagem 1",
"position": 1,
"types": [
"image",
"small_image",
"thumbnail"
],
"disabled": false,
"url": "https://www.exemplo.com.br/media/catalog/product/e/s/escova-robinson-taca-soft.jpg_1.jpg"
}
],
"has_next": false,
"next_cursor": null
}
Image fields
| Field | Type | Description |
|---|---|---|
image_id | string | Stable identifier of the image record in the catalog. Same value used by PUT and DELETE. |
file | string | Relative path of the file inside the catalog media folder. |
label | string / null | Image label in the context of the requested store. |
position | int / null | Position of the image in the gallery. |
types | array | Roles assigned to the image in the requested context. |
disabled | boolean | Whether the image is disabled for the gallery in that context. |
url | string | Public URL built for the image file. |
Image roles (types)
types lists the roles the image plays on the product. Possible values are image (base image), small_image and thumbnail.
"types": [
"image",
"small_image",
"thumbnail"
]
An image can belong to the gallery without playing any of these roles:
"types": []
types=[] is valid
An empty array only means the image is in the gallery with no role assigned in that context. It does not mean the image is missing and must not be treated as an error by the integration.
Disabled images
Read operations include disabled images. This is intentional: the integration can use disabled to correctly reconcile existing images that must not be shown as active.
{
"image_id": "653867",
"file": "/p/o/ponta-diamantada_58.jpg",
"label": "Imagem 1",
"position": 1,
"types": [],
"disabled": true,
"url": "https://www.exemplo.com.br/media/catalog/product/p/o/ponta-diamantada_58.jpg"
}
disabled=false on the consumer side.Store and fallback
store_id=0 is the administrative/global scope. For storefront integrations, send the ID of the store used by the project explicitly — for example store_id=1. Multi-store environments may have store_id=1, store_id=2, store_id=3 and so on.
- Gallery fields (
label,position,disabled) use the requested store context and may inherit values from the global scope when there is no store-specific override. - The roles in
typesalso follow the configuration of the requested context. store_id=1is only a common example — it is not a universal value on the Yep Platform.
Existing product with no images
An existing product with no images returns HTTP 200 with an empty list:
{
"success": true,
"product_id": 116022,
"sku": "25.5979",
"store_id": 0,
"images": [],
"has_next": false,
"next_cursor": null
}
| Situation | Response |
|---|---|
| Existing product with no images | 200 + images: [] |
| Product not found | 404 |
Global image inventory New
Returns the catalog's image inventory, paginated by cursor. Intended for initial load and full reconciliation.
Walk every image in the catalog, one page per call.
GET /api2/products/imagens?store_id=1&limit=100
Authorization: Bearer {access_token}
Parameters
0. Sending it explicitly is recommended.1 and 200. Default 100.next_cursor. Omit on the first call.There is no page or offset
This endpoint paginates by cursor only. Requests containing page or offset are treated as invalid and return 400.
Response example
{
"success": true,
"store_id": 1,
"images": [
{
"image_id": "160031",
"product_id": 98622,
"sku": "25.0886",
"file": "/b/r/broca-carbide-fg-36.jpg_10.jpg",
"label": "Imagem 1",
"position": 1,
"types": [],
"disabled": false,
"url": "https://www.exemplo.com.br/media/catalog/product/b/r/broca-carbide-fg-36.jpg_10.jpg"
}
],
"has_next": true,
"next_cursor": "160115"
}
Inventory semantics
The plural endpoint is an inventory of images, not of products. Therefore:
- a product with several images appears several times — each record is one image;
- products with no images do not appear in the inventory;
- disabled images appear with
disabled=true; - product status and visibility are not used as gallery filters.
Cursor pagination
Every listing that can exceed one page returns has_next and next_cursor. The integration advances by passing the received cursor back, without computing anything.
GET /api2/products/imagens?store_id=1&limit=100
{ "has_next": true, "next_cursor": "163608" }
GET /api2/products/imagens?store_id=1&limit=100&cursor=163608
Recommended flow
- start without
cursor; - process
images; - if
has_next=true, call again withcursorequal tonext_cursor; - repeat;
- stop when
has_next=falseandnext_cursor=null.
Avoid
- Incrementing the cursor manually.
- Reusing an arbitrary cursor as if it were a page number.
- Sending
pageoroffset.
The cursor is not a permanent change marker
The cursor exists only to continue the current sweep. It does not represent an update date, a product version, an immutable snapshot or an incremental change feed. Do not store the last cursor indefinitely hoping to discover images changed days later: an old image whose metadata changed does not get a new image_id.
For a new full reconciliation: start again without cursor → walk every page again → stop when has_next=false.
Integration recommendations
GET /api2/products/imagens?store_id={STORE_ID}&limit=100 and follow every next_cursor to the end.GET /api2/products/imagem?type=sku&product_id={SKU}&store_id={STORE_ID}&limit=100 for a known SKU.Summary
Initial load / reconciliation: GET /api2/products/imagens with next_cursor pagination.
Single product lookup: GET /api2/products/imagem.
HTTP responses of the lookups
| Situation | Status |
|---|---|
| Successful lookup | 200 |
| Existing product with no images | 200 |
| Invalid parameter | 400 |
| Missing authentication or invalid token | 401 |
| No permission | 403 |
| Product not found (single endpoint) | 404 |
| Internal failure | 500 |
Inputs that return 400
limit=0,limit=201orlimit=abcpage=2oroffset=10- invalid
cursor - invalid
store_id
Read-only, no side effects
GET /api2/products/imagem and GET /api2/products/imagens do not update the product, do not change updated_at, do not change the gallery, do not enqueue work, do not reindex and do not change stock or price.
The returned url is built from the media record. The lookup does not verify that the remote file physically exists.
Write operations
Creating, updating and deleting a single image remain available on the singular route, distinguished by HTTP method. They require the products/images permission. The GETs do not replace these operations. To remove several images at once, see full deletion and selective bulk deletion.
Upload a base64-encoded image.
{
"type": "sku",
"product_id": "novo_produto",
"position": 1,
"label": "Image",
"file_name": "my_image.png",
"file_mime_type": "image/png",
"file_content": "iVBORw0KGgoAAAANS...",
"types": ["image"]
}
product_id, file_content, file_mime_type, label and position. type accepts sku or id (default id). file_name is optional — when omitted a unique name is generated. Success responds 201 with the created image_id.Update image metadata.
{
"type": "sku",
"product_id": "produtoteste",
"image_id": "70449",
"position": 999,
"label": "Updated image",
"types": ["image"]
}
product_id and image_id. Optional: label, position, types and exclude (1 disables the image in the gallery; default 0). Success responds 200.Delete a product image.
{
"type": "sku",
"product_id": "produtoteste",
"image_id": "70449"
}
product_id and image_id. Success responds 200. Still the recommended way to remove one image per call.Updates use PUT, not PATCH
Unlike /api2/products, the image route accepts PUT for updates. A PATCH /api2/products/imagem request responds 405 (method not allowed). Earlier versions of this documentation showed PATCH by mistake.
image_id used by PUT and DELETE is the same one returned by the lookups on this page and by the upload POST.Delete every image of a product New
Removes the entire global gallery of a single product in one request.
Clear a product's whole gallery (delete_all mode).
DELETE /api2/products/imagens
Authorization: Bearer {access_token}
Content-Type: application/json
{
"type": "sku",
"product_id": "PRODUTO-001",
"delete_all": true
}
Identification by ID is also accepted:
{
"type": "id",
"product_id": 12345,
"delete_all": true
}
Parameters
product_id is interpreted: sku or id.type.true, strictly. The values "true", 1, false, null or a missing field are rejected.store_idis not accepted: the cleanup is global for the product's gallery.delete_allanditemsare mutually exclusive modes in the same request.
Response example
{
"success": true,
"product_id": 12345,
"sku": "PRODUTO-001",
"deleted_count": 3
}
A product that already has no images responds 200 with deleted_count: 0:
{
"success": true,
"product_id": 12345,
"sku": "PRODUTO-001",
"deleted_count": 0
}
| Situation | Response |
|---|---|
| Gallery removed | 200 + deleted_count with the number removed |
| Existing product with no images | 200 + deleted_count: 0 |
| Product not found | 404 |
/media directory.No blind retry after a new upload
Each delete_all=true call expresses the intent to clear the current gallery. If the integration has already started uploading new images, do not resend an old delete_all call: it would also remove the images just uploaded.
Delete specific images in bulk New
Removes specific images from one or several products in a single call. SKU and ID identification can be mixed in the same batch.
Delete a list of image_ids per product (items mode).
{
"items": [
{
"type": "sku",
"product_id": "PRODUTO-001",
"image_ids": ["10001", "10002"]
},
{
"type": "id",
"product_id": 12346,
"image_ids": ["10003"]
}
]
}
items.image_ids per requestMaximum unique IDs across all items.Payload rules
itemsmust be a non-empty array.- Each item requires
type,product_idandimage_ids. typeaccepts onlyskuorid.image_idsmust be a non-empty array.- Each existing
image_idmust belong to the product given in the same item.
- The same product cannot appear twice, even if one entry uses SKU and the other uses ID.
- The same
image_idcannot be repeated in the batch. store_idis not accepted: the deletion is global.itemsanddelete_allcannot be sent together.
Response example
{
"success": true,
"products_processed": 2,
"requested_count": 3,
"deleted_count": 2,
"already_absent_count": 1,
"results": [
{
"product_id": 12345,
"sku": "PRODUTO-001",
"requested_count": 2,
"deleted_count": 2,
"already_absent_count": 0
},
{
"product_id": 12346,
"sku": "PRODUTO-002",
"requested_count": 1,
"deleted_count": 0,
"already_absent_count": 1
}
]
}
Response fields
| Field | Description |
|---|---|
products_processed | Number of products in the batch. |
requested_count | Number of image_ids requested, in total and per product. |
deleted_count | Number of images actually removed by this call. |
already_absent_count | Number of image_ids that no longer existed. Not an error. |
results | Per-product breakdown, with resolved product_id and sku. |
Idempotent for already removed IDs
Resending the same batch does not fail: IDs already removed are counted in already_absent_count and deleted_count stays at 0. When the API returns success, every requested image_id is absent from its product at the end of the operation.
Bulk delete guarantees
Validation before deleting
The batch is validated before any deletion is applied. Missing products, wrong ownership, duplicates or an invalid payload never cause a partial deletion of the other items: the whole request is rejected and no image is removed.
| Batch error | Status | Effect |
|---|---|---|
image_id belongs to another product | 400 | Nothing deleted |
Repeated product or image_id | 400 | Nothing deleted |
| Invalid payload | 400 | Nothing deleted |
| Any product not found | 404 | Nothing deleted |
Duplicate images and roles
Two gallery associations can point to the same file. If only one image_id is removed and another association of the same product still uses the same file, the image, small_image and thumbnail roles remain valid.
Roles are cleared only when the last association of that file no longer exists on the product.
Operational recommendations
For gallery reconciliation:
- query the images or the inventory;
- group the deletions by product;
- build batches of up to 50 products and 500
image_ids; - send one batch;
- wait for the response;
- only then send the next one.
Reads per store, deletes global
Lookups keep using the integration's store_id, for example store_id=1. Bulk DELETEs are global and do not take store_id.
HTTP responses of write operations
| Situation | Status |
|---|---|
| Deletion completed | 200 |
Product already without images (delete_all) | 200 |
| IDs already absent in the batch | 200 |
| Invalid payload | 400 |
| Wrong ownership | 400 |
Repeated product or image_id | 400 |
| Missing authentication or invalid token | 401 |
Missing the products/images permission | 403 |
| Product not found | 404 |
Incompatible method, such as PATCH /api2/products/imagem | 405 |
| Internal failure | 500 |