Start a run
A batch of product identities in, a run id back. 202, not 200: the work has been accepted, not done — poll GET /runs/{id}. Needs catalog:write and an Idempotency-Key header: a retried POST with the same key does not scrape the batch twice.
Send NDJSON (one object per line, application/x-ndjson) or a JSON array. Lines are accepted or rejected individually: a batch of 5,000 with one bad row scrapes 4,999 and tells you which line failed. Every line needs a vendor SKU (sku or vendorSku) — it is what the supplier's site is indexed by, and a line without one is rejected.
Each line needs something to scrape against: either a categoryId whose category has a golden mapping, or its own attributes. A line with neither is refused as no_gold_match rather than scraped for generic attributes.
apiKeyAuthorizationBearer <token>Your API key. X-Api-Key: <key> is accepted as an alternative.
A key belongs to an organization, not a user, so it outlives whoever created it. It carries two independent things, and both are checked: an org role (a member key cannot approve a publish or activate a mapping) and a set of scopes — catalog:read, catalog:write, enrichment:write, publishing:read, publishing:write, org:read, org:write. Holding a scope does not grant a role, and holding a role does not grant a scope.
GET /v1/me returns both for the key you are holding.
brandId*stringWhich of your brands this run belongs to. A brand outside your organization answers not found.
- body
One of these per line.
attributes?array<>brand?stringbreadcrumb?string1 <= lengthcategory?string1 <= lengthcategoryId?stringgtin?stringimageUrls?array<>known?knownUrl?stringurimerchantUrl?stringuriref*stringYour handle for this line, echoed back on every result. For a product in your Fabric catalog, send its id or its SKU — that is how a promotion lands on it.
1 <= length <= 512sku?stringThe supplier's code for the product. Required — as sku or vendorSku, whichever your feed calls it. It is what a supplier's site is indexed by; a line with neither is rejected.
styleCode?stringThe code all of this product's variants share, as the maker prints it (71866 for 71866-0911-M). Optional. A page on the maker's own site that carries it ranks above one that only matches the name.
title*string1 <= lengthvendorSku?stringThe same field as sku, under the name some feeds use.
vendorSkuDerived?booleanWhether the code above was inferred rather than read from your data — the part a product's variants' codes share. Leave it unset: you know where your codes came from, and Fabric's own catalog sets it when it worked one out. A code marked this way is weighed as weaker identity evidence, because many of a supplier's products can begin with the same stem.
Accepted.
application/json- response
accepted*integerLines that will be scraped.
-9007199254740991 <= value <= 9007199254740991refused*integerLines that were well-formed but had no attribute set to scrape against — a categoryId with no golden mapping and no attributes of their own. They appear in the results as no_gold_match.
-9007199254740991 <= value <= 9007199254740991rejected*array<>Malformed lines, each with why.
runId*stringcurl -X POST 'https://fabric.inc/api/v1/brands/string/catalog-builder/runs' \ -H 'Content-Type: application/json' \ -d '[ { "ref": "string", "title": "string" }]'{ "accepted": -9007199254740991, "refused": -9007199254740991, "rejected": [ { "line": -9007199254740991, "reason": "string", "ref": "string" } ], "runId": "string"}List runs GET
The brand's runs, newest first, counted as the Studio's run list counts them: a person's decision on a row outranks the grader's verdict. `?limit=` up to 200, default 50.
Start the run a plan described POST
Starts the run `POST /plans` described, for the same `productIds`. **202, not 200**: accepted, not done — poll `GET /runs/{id}`. Needs `catalog:write` and an `Idempotency-Key` header. The plan is made again and must agree with the `quoteId`: a selection that was never planned, or whose eligibility changed since, answers 409. Plan again and use the new quote.