Version: 1.0Updated on: September 23rd, 2026
This manual is for brand partners who already push images through the old gallery endpoints at bo.icecat.biz/restful/v3/Gallery/… and are moving to the Icecat Gallery API at api.icecat.biz/product-gallery/v1/….
bo.icecat.biz/restful/v3/Gallery/…
api.icecat.biz/product-gallery/v1/…
Read it next to the Manual for Brand Partners: Icecat Gallery API, which describes the new API in full. This page only covers the move: what each of your calls becomes, what each field becomes, and the handful of places where porting the names is not enough.
Both sets of endpoints are live. Nothing you run today stops working because the new API exists. The old gallery endpoints will be retired once integrations have moved, and you will be told before that happens — this page is how you get ahead of it.
The old endpoints already run on the new service. When you call PATCH /restful/v3/Gallery/… today, the picture is validated, stored, and published by exactly the same system that serves api.icecat.biz/product-gallery/v1/…. The old address is a façade in front of it.
PATCH /restful/v3/Gallery/…
Three things follow, and they make this migration much smaller than it looks:
What actually changes is how you address things and the shape of what you send.
Each step is independently verifiable, and each leaves you with a working integration.
Step 0 — optional: move to the API token. Both ways of authenticating stay. If you authenticate with a session key today, you can carry on doing so on the old endpoints and the new ones alike, and nothing on this page depends on changing it.
If you do want the token, this is the cheapest moment: it works on both addresses, so the change touches no URL and no payload, and it removes the session, its expiry, and its IP binding from your integration before you start moving calls. You generate it yourself in your profile on icecat.biz.
Step 1 — Point your reads at the new API. Replace your verification step with GET /product-gallery/v1/products/{productId}/galleries?view=FULL. It changes nothing, and it teaches you the new shapes against your own live data.
GET /product-gallery/v1/products/{productId}/galleries?view=FULL
Step 2 — Move the single-image writes. Add, update, deactivate. Keep placements to one entry naming the base order, and ordering behaves exactly as it does today.
placements
Step 3 — Move the batch. First to batch-sync, which answers with the results the way your policy call does today; then to batch with a job, when you are ready to stop waiting on the connection.
batch-sync
batch
Step 4 — Only then use what is new: partner galleries and per-locale orders.
One rule while you are half-migrated: do not write the same product from both addresses in the same push. They write the same galleries, so the two writes do not conflict — they simply overwrite one another, and the last one wins. Finish a product on one address before the other touches it.
GET /Gallery/{ProductId}
GET /Gallery/{ProductId}/{GalleryId}
GET /product-gallery/v1/images/{imageId}
POST /Gallery/{ProductId}
POST /product-gallery/v1/images
PUT /Gallery/{ProductId}
PATCH /Gallery/{ProductId}/{GalleryId}
PATCH /product-gallery/v1/images/{imageId}
OrderNumber
POST /Gallery/{ProductId}/Locale
POST /product-gallery/v1/images/{imageId}/copies
PUT /Gallery/{ProductId}/Policy/{PolicyName}
POST /product-gallery/v1/products/{productId}/batch-sync
…/batch
bo.icecat.biz/restful/v3
api.icecat.biz
Api-Token
Access-Key
GalleryId
ProductId
imageId
(productId, taxonomyId)
sourceId
taxonomyId is the field that did not exist before. Send 0 and you are writing the gallery you have always written. Any other value is a gallery for one partner, which is new ground.
taxonomyId
0
The credential moves out of the URL. If you authenticate with a session key today, you are most likely appending ?AccessKey=…&SessionType=Rest to every request. The new API does not read it there: the key goes in the Access-Key header, and there is no query parameter for it. Anything left in the query string is not ignored — an unrecognized parameter is answered 400 — so strip it when you move a call over.
?AccessKey=…&SessionType=Rest
400
Keeping the session key is a perfectly good choice; only where you put it changes. The token, if you use one, travels as the Api-Token header on both addresses and needs no change at all.
Link
imageUrl
http
https
ftp
ftps
LanguageId
languageId
placements[]
IsPrivate
isPrivate
ExpiryDate
expiryDate
Type
imageType
FileName
fileName
_
-
Visible
isActive
false
Md5
IsCropped
Origin
High
Medium
Low
Thumb
image.source
md5
isCropped
origin
high
medium
low
thumbnail
ImageFingerprint
RemoveLanguageIds
removeLanguageIds
DeduplicateBetweenLocales
deduplicateBetweenLocales
extraTaxonomyIds
Both examples below add one German picture and put it second. The comments are there to be read — strip them before sending; JSON has no comments.
Today, on POST /restful/v3/Gallery/{ProductId}, one number says where the picture goes:
POST /restful/v3/Gallery/{ProductId}
{ "Link": "https://images.example.com/your-product/front.jpg", "LanguageId": 4, // the locale the picture belongs to — German "OrderNumber": 2 // its place, in the only order there is }
On the new API, the same thing on POST /product-gallery/v1/images:
{ "productId": {productId}, "taxonomyId": 0, // which gallery — 0 is the one you write today "languageId": 4, // the locale the picture belongs to — German, as before "imageUrl": "https://images.example.com/your-product/front.jpg", "placements": [ { "languageId": 0, // WHICH ORDER to write into — 0 is the gallery's base order "orderNumber": 2 } // its place in that order ] }
The one thing to read twice: inside placements, languageId names the order, not the locale of the picture. The picture is German — "languageId": 4 at the top — and it is being placed in the gallery’s base order, which is "languageId": 0 in the placement. The two numbers are answering different questions.
"languageId": 4
"languageId": 0
The minimal migration is one entry naming the base order. That is exactly what your OrderNumber does today — the old endpoint writes it into the base order of the Icecat gallery, and nowhere else. Reproduce that and nothing about your gallery changes.
When you want more, you can then give one market a different first picture without touching anyone else:
"placements": [ { "languageId": 0, "orderNumber": 2 }, // second in the gallery's base order { "languageId": 4, "orderNumber": 1 } // first in Germany's own order ]
— second in the gallery overall, first for Germany. The rules that govern this are in the Gallery API manual, section 6.
One thing that is easy to worry about and should not be: the numbers themselves do not have to be tidy. Only the relative order matters, and a partner receives the gallery renumbered from 1 with no gaps, whatever numbers you used.
The old call names the policy in the path; the new one carries it in the body, and it is required — there is no default.
ReplaceAllForAllLocales
BATCH_POLICY_REPLACE_ALL_FOR_ALL_LOCALES
ReplaceAll
BATCH_POLICY_REPLACE_ALL
CreateOrReplace
BATCH_POLICY_CREATE_OR_REPLACE
KeepMainAndReplaceGallery
ReplaceOwn
ReplaceOwnAndUpdateImageTypes
The last three were discontinued because nobody used them: across five years of production, they were never chosen once, while ReplaceAllForAllLocales carried the overwhelming majority of submissions and ReplaceAll most of the rest.
They are already refused today, on the old endpoint, with Policy “…” is no longer supported. Supported policies: ReplaceAll, ReplaceAllForAllLocales, CreateOrReplace. So if your integration is running, it is not using them, and this row of the table costs you nothing.
If you were planning to reach for one, talk to Icecat rather than picking the closest-looking neighbor. They were not dropped onto a substitute deliberately: the policies differ in exactly what they deactivate, and a wrong choice takes a gallery down rather than replacing it.
The old policy call waits for the work and answers with the results. The new one has two doors:
POST …/batch-sync
POST …/batch
GET /product-gallery/v1/jobs/{jobId}
Verdicts appear all at once with the finished status. There is no progress and no partial result: check for a finished job, not for a counter.
Four things will show up as unexpected 400s if you port the field names and nothing else.
languageId and taxonomyId have no defaults. An omitted LanguageId used to be tolerated in places. Both are now required on every write, and 0 is a value you send, not one you leave out.
A batch item is not a patch. A field you leave out means its default, not “leave what is there”: an item without imageType resets the type, an item without fileName clears the name. Build each item as the complete state you want that picture to have. The single-picture PATCH is the opposite — there, absent means untouched.
PATCH
An order is written through its own endpoint. PATCH /images/{imageId} does not carry order numbers. Placing a picture happens either when you add it, through placements, or afterward through the order endpoints.
PATCH /images/{imageId}
The whole submission is refused, or none of it is. A structurally invalid batch answers 400 and creates no job at all — there is no partly accepted submission to inspect.
The old endpoints answer in the Brand API’s shape:
{ "Code": 400, "Error": "Bad Request", "Message": "…", "DetailedCode": 0 }
The Gallery API, being a service of its own, answers in its own:
{ "code": 3, "message": "…", "details": [] }
The HTTP status carries the class in both: 400 wrong request or file, 401 credential, 403 not permitted, 404 unknown id, 409 conflict, 429 too many, 500 ours, 503 retry.
401
403
404
409
429
500
503
If you log these, branch on the status and on the numeric code — never on the message text, whose wording can be improved without notice. The messages you are most likely to meet are listed in the Gallery API manual, section 12.
So you do not spend time re-testing it:
The limits are the Gallery API’s, and they are listed in full in the Manual for Brand Partners: Icecat Gallery API, section 16. Two of them are worth checking against what your integration sends today:
Everything else — file size, dimensions, field lengths, order numbers — is what you are already working within.
Policy "…" is no longer supported. Supported policies: …
languageId is required
taxonomyId is required
isPrivate is only allowed on the Icecat gallery (taxonomyId=0)
picture N is not in this sequence
Missing credentials
Invalid API token
The full list is in the Gallery API manual, section 12.
Read further: Icecat, API, e-commerce, ecommerce, Icecat, product content