production writes → app.brandsgateway.com Examples on this page target the live marketplace.
BG Vendor Integration
Menu
The contract

Taxonomy & IDs

BrandsGateway accepts integer term IDs, never names or slugs. You can let the portal resolve your vocabulary for you, or hold the lookup tables yourself — this page is the second option.

Most vendors do not need this page
Send the words already in your feed in a values block and the portal maps them to IDs for you — on POST /api/v1/validate and on the product write alike. Read on only if you want to hold the lookup tables yourself, for offline mapping or because your feed needs rules ours do not cover.
Map once, apply forever
A mapping is per value, not per product. Mapping the brand “DOLCE & GABBANA” once fixes every product from that brand, in this run and every run after. This is why the dashboard ranks failures by cause rather than listing rows.

The reference sets

Brands

product_brand Fetch & cache

The designer or label. One brand per product. Brands are curated by BrandsGateway — a brand that is not on the platform cannot be created from a feed.

brands[].id /api/v1/reference/brands

Categories

product_cat Fetch & cache

The shop's browsable category tree. A product usually carries both a parent and a leaf category (e.g. Women 19 and Knitwear 26).

categories[].id /api/v1/reference/categories

Product groups

product_group Fetch & cache

The merchandising hierarchy that drives filtering, size axes and harmonised codes. Send the full ancestor chain, leaf last — e.g. Clothing 71651, Sweaters 71673, Sweatshirts 71675.

groups[].id /api/v1/reference/groups

Genders

product_gender Fixed set

Exactly three terms. Fixed platform-wide.

genders[].id /api/v1/reference/genders
ID Name Slug Note
71575 Men men
71576 Women women
71577 Unisex unisex

Conditions

product_condition Fixed set

Stock condition. Drives whether returns are accepted, so it is never inferred — it must be sent.

conditions[].id /api/v1/reference/conditions
ID Name Slug Note
71354 New with tags new-with-tags The default for new-season stock.

Attributes (colour & size)

pa_* Fixed set

Colour is attribute 14 and is never a variation axis. Size attributes are per sizing system; pick the one that matches how your feed expresses sizes and send its term slugs in variation attributes.

attributes[].id /api/v1/reference/attributes
ID Name Slug Note
14 Colour pa_color Always sent with variation: false.
10 Italian Size WOMEN pa_italian-size-women variation: true
11 Italian Size MEN pa_italian-size-men variation: true
25 Shoe Size EU pa_shoe-size-eu variation: true

Seeing what we accept

The values BrandsGateway accepts for a field come back from the validator, in the payload you are already sending. Put your own words in a values block and POST it to /api/v1/validate: anything that maps is resolved silently, and anything that does not is listed in unresolved — with the closest accepted values, how many values that field has, and a few examples of them.

ask the validator what maps
# One call, your own words, no credential needed.

curl -s -X POST https://vendors.brandsgateway.com/api/v1/validate \
  -H 'Content-Type: application/json' \
  -d '{
        "values": { "brand": "Gucci", "gender": "Donna", "color": "Nero" },
        "product": { "type": "simple", "name": "Leather Bag" }
      }' | jq '.unresolved'
an unmapped value, with what would have worked
[
  {
    "field": "gender",
    "value": "Donna",
    "code": "missing_gender",
    "message": "Could not map gender \"Donna\".",
    "suggestions": [ { "name": "Women", "confidence": 0.86 } ],
    "accepted": { "count": 3, "examples": ["Men", "Women", "Unisex"] }
  }
]
Do not query BrandsGateway for taxonomy
Brands, categories, groups and attributes are shared across every vendor on the marketplace. Your BrandsGateway application password is for writing your products, and nothing else — reading the shared taxonomy is the portal's job, which is why the mapping happens inside the calls above.
Coming later
GET /api/v1/reference and GET /api/v1/reference/{set} will serve the full sets for offline mapping. They are not available yet; the validator above is how you see accepted values today.

Matching your values

Vendor feeds are inconsistent in ways that break naive equality: casing varies, ampersands arrive HTML-encoded, whitespace doubles up. Normalise both sides before comparing, and never fall back to fuzzy matching in production — a silently wrong brand is worse than a recorded failure.

resolving a brand
// Build the map once, then never think about names again.
// Normalise aggressively — vendor feeds are inconsistent about case,
// ampersands and HTML entities.

const normalise = (s) =>
  String(s)
    .replace(/&/g, "&")
    .replace(/&#0?39;/g, "'")
    .replace(/\s+/g, " ")
    .trim()
    .toLowerCase();

const brandIndex = new Map(
  brands.map((b) => [normalise(b.name), b.id])
);

function resolveBrand(vendorBrandName) {
  const id = brandIndex.get(normalise(vendorBrandName));
  if (!id) {
    // Do NOT guess, and do NOT invent an ID. Record it and skip the
    // product — an unmapped brand is a mapping task, not a data error.
    throw new UnmappedValue("missing_brand", vendorBrandName);
  }
  return [{ id }];
}

Sizes deserve their own attention

Colour is one attribute (id 14) and is never a variation axis. Sizes are many attributes, one per sizing system — Italian women's, Italian men's, EU shoe sizes, and so on. Choose the attribute that matches how your feed already expresses sizes and use its term slugs directly.

resolving a size
// Sizes are the hardest mapping, because the axis differs by product.
// Pick the attribute that matches how YOUR feed expresses sizes, then use
// that attribute's term slugs — do not translate between sizing systems.

const attribute = { id: 10, slug: "pa_italian-size-women" };

const sizeIndex = new Map(
  termsFor(attribute.id).map((t) => [normalise(t.name), t.slug])
);

function variationAttributes(vendorSize) {
  const slug = sizeIndex.get(normalise(vendorSize));
  if (!slug) throw new UnmappedValue("missing_size_mapping", vendorSize);
  return { [attribute.slug]: slug };
}
Do not convert between sizing systems
Converting an IT 42 to a FR 38 in your own code introduces an error you cannot see and we cannot audit. Declare the attribute that matches your source and let the shop handle presentation.

Product groups vs categories

They look similar and do different jobs, so both are required:

  • Categories are the shop's browsable navigation — what a customer clicks through.
  • Groups are the merchandising hierarchy. They drive filtering, determine which size axis a product has, and carry the harmonised-code prefix used for customs paperwork.

Send the full ancestor chain of groups with the leaf last. A product in Sweatshirts sends Clothing, Sweaters and Sweatshirts — sending only the leaf loses filtering, and sending only the container leaves the product with no size axis.

Countries of origin

meta_data._bgorigincountry takes an ISO-3166-1 alpha-2 code. Any valid code is accepted; these are the ones that appear most often in vendor feeds.

IT Italy CN China PT Portugal RO Romania TR Turkey ES Spain FR France BG Bulgaria TN Tunisia IN India VN Vietnam RS Serbia
“Made in E.U.” is not a country
Values like EU, * or Made in Italy fail as missing_country. Resolve them to a real country code in your own mapping layer.