Skip to main content
POST
Upsert one retailer product listing

Authorizations

X-API-Key
string
header
required

Path Parameters

retailer_id
string<shortuuid>
required

Unique identifier of the retailer this listing belongs to.

Required string length: 22
Pattern: ^[23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{22}$

Body

application/json

A single listing plus the same provenance and dry-run knobs.

gtin
string
required

GTIN of the product being listed, digits only. Normalised to GTIN-14 before lookup, so an 8, 12 or 13-digit barcode is accepted as sent. The product must already exist — a listing never creates one, so that per-field provenance is only ever written by the import engine.

Pattern: ^\d{8,14}$
sku
string
default:""

The retailer's internal SKU for this product.

Maximum string length: 100
badges
ListingBadgeIn · object[]

Designations the retailer applies to this product. Retailer-scoped and attached to the listing, never to the shared product — a badge is a retailer's marketing claim, not a certification. Repeats of the same derived slug are collapsed rather than rejected, because feeds routinely repeat a badge. Syncing is exact: a badge absent from this payload stops rendering.

urls
ListingURLItemIn · object[]

One product URL per retailer web property, at most one per storefront. An empty list means 'this feed carries no URL information' and deactivates nothing — deliberately not symmetric with a non-empty list, which deactivates the properties it omits. A feed with no URL column (Ulta's PSV) would otherwise switch off every URL another feed supplied.

attributes
Attributes · object

Retailer-scoped facts with no typed column yet, under their original feed names. A bounded staging area, not a document store: at most 200 keys, keys 1-60 characters, string values up to 8000 characters, lists up to 250 items. Exceeding a bound fails the row loudly — the pressure to promote a recurring key to a real column is the point.

is_active
boolean
default:true

False when the retailer has dropped the product.

source_reference
string
default:""

The retailer's own product identifier in the feed.

Maximum string length: 255
source
string
default:""

Dataset name recorded for provenance.

Maximum string length: 100
dry_run
boolean
default:false

Execute everything and roll back.

Response

OK

Batch census plus the per-row results.

created + updated + unknown_gtin + invalid + errors equals the number of submitted rows for any 200 response. Per-row failures are reported here rather than aborting the batch; only request-level failures are 4xx.

committed
boolean
required

False when this was a dry run and the transaction was rolled back.

submitted_rows
integer
required

Number of rows in the request.

Required range: x >= 0
created
integer
required

Rows that produced a new listing.

Required range: x >= 0
updated
integer
required

Rows that refreshed an existing listing.

Required range: x >= 0
unknown_gtin
integer
required

Rows whose GTIN has no product. Nothing was written for them.

Required range: x >= 0
invalid
integer
required

Rows rejected by barcode or storefront validation.

Required range: x >= 0
errors
integer
required

Rows that raised.

Required range: x >= 0
rows
ListingRowResultOut · object[]

One result per submitted row, in request order.