Version: 1.0
Updated 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/….
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.
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.
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.
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.
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.
| What you call today | What you call instead |
|---|---|
GET /Gallery/{ProductId} | GET /product-gallery/v1/products/{productId}/galleries?view=FULL |
GET /Gallery/{ProductId}/{GalleryId} | GET /product-gallery/v1/images/{imageId} |
POST /Gallery/{ProductId} | POST /product-gallery/v1/images |
PUT /Gallery/{ProductId} | POST /product-gallery/v1/images, or one batch item under a replacing policy |
PATCH /Gallery/{ProductId}/{GalleryId} | PATCH /product-gallery/v1/images/{imageId} — except OrderNumber, see section 5 |
POST /Gallery/{ProductId}/Locale | POST /product-gallery/v1/images/{imageId}/copies |
PUT /Gallery/{ProductId}/Policy/{PolicyName} | POST /product-gallery/v1/products/{productId}/batch-sync, then …/batch |
| Today | On the new API | |
|---|---|---|
| Host | bo.icecat.biz/restful/v3 | api.icecat.biz |
| Credential | a session key in the query string, or the Api-Token header | both still work — but both as headers: Access-Key for the session key, Api-Token for the token |
| A picture | GalleryId, used together with ProductId | imageId, enough on its own |
| A gallery | implied — a product had one | (productId, taxonomyId), both required on every write |
| A physical file | not addressable | sourceId, used when you write an order |
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.
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.
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.
| Today | On the new API | Notes |
|---|---|---|
Link | imageUrl | http, https, ftp, ftps, up to 1999 characters — unchanged |
LanguageId | languageId | now required, with no default — send 0 explicitly for INT |
| — | taxonomyId | new, required, no default — send 0 for the Icecat gallery |
OrderNumber | placements[] | see section 5 |
IsPrivate | isPrivate | same meaning; allowed only when taxonomyId is 0 |
ExpiryDate | expiryDate | same format, same rules |
Type | imageType | same values. The list is in the Gallery API manual, section 5 |
FileName | fileName | unchanged: letters, digits, _, -, no dot, up to 35 |
Visible | isActive | same meaning, new name. false still means the picture is not distributed and can be switched back on |
GalleryId | imageId | |
Md5, IsCropped, Origin, High, Medium, Low, Thumb | inside image.source | as md5, isCropped, origin, high, medium, low, thumbnail, plus sourceId |
ImageFingerprint | — | not carried by the new API. The old one answers it as an empty string today |
RemoveLanguageIds | removeLanguageIds | same meaning |
DeduplicateBetweenLocales | deduplicateBetweenLocales | same meaning |
| — | extraTaxonomyIds | new: names galleries to act on beyond the ones your items mention |
OrderNumber becomes placementsBoth 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:
{
"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.
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.
| Policy you name today | What you send instead |
|---|---|
ReplaceAllForAllLocales | BATCH_POLICY_REPLACE_ALL_FOR_ALL_LOCALES |
ReplaceAll | BATCH_POLICY_REPLACE_ALL |
CreateOrReplace | BATCH_POLICY_CREATE_OR_REPLACE |
KeepMainAndReplaceGallery | discontinued |
ReplaceOwn | discontinued |
ReplaceOwnAndUpdateImageTypes | discontinued |
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 — answers when the work is done, with a verdict per item. This is the same shape you have today, so it is the smaller change to make first;POST …/batch — answers at once with a job ID, and you read the verdicts from GET /product-gallery/v1/jobs/{jobId} when the job has finished. Move here when you submit anything large: it does not hold your connection open while files are fetched.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.
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.
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.
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:
fileName — letters, digits, _, -, no dot, up to 35 characters;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:
| Items in one batch | 2000 |
| Pictures in one activate / deactivate call | 2000, all of one product |
Everything else — file size, dimensions, field lengths, order numbers — is what you are already working within.
| Message | What happened | What to do |
|---|---|---|
Policy "…" is no longer supported. Supported policies: … | one of the three retired policies | see section 6 — do not substitute a neighbor |
languageId is required / taxonomyId is required | a field that used to be optional, or did not exist | send both explicitly, 0 included |
isPrivate is only allowed on the Icecat gallery (taxonomyId=0) | isPrivate sent on a partner gallery | drop the flag there |
picture N is not in this sequence | an order names a sourceId that is not in that gallery and locale | sourceId identifies a file, not a product — take it from a gallery read |
Missing credentials | neither header reached us — most often a session key still in the query string | move it to the Access-Key header; see section 3 |
Invalid API token | the token was not accepted | check it in your profile; the reason is not disclosed |
The full list is in the Gallery API manual, section 12.
FedEx has introduced Global Trade Navigator, a new suite of digital tools designed to help…
The team is not slowing down between big releases. Icecat PIM 3.17.2 lands with a…
Amazon Ads is expanding into conversational AI through a new integration with ChatGPT, giving advertisers…
Version: 1.0Updated on: September 21st, 2026 This manual is for brand partners publishing images for their…
AI is becoming a regular part of online shopping, but consumers are not abandoning traditional…
Sprint 104 is about making what we already have more dependable. Publication status is now…