Skip to main content
One seller’s whole stock lives under the business it belongs to:
Drafts, sold listings, everything in review — which the public catalogue deliberately does not give you. This is what you sync against.

Give every listing an externalIdentifier

Your own id for it, unique within one seller’s inventory.
It is how you find your listing again without keeping our ids, and how a sold item is matched back to your product through the order’s items:
The filter takes a list, so you can look several up in one call: filter[externalIdentifier]=PIM-10294,PIM-10295, or as filter[externalIdentifier][]=PIM-10294&filter[externalIdentifier][]=PIM-10295. One works without the [] too. An identifier with a comma in it has to go in the [] form, since the other splits on commas.

Finding one, and counting them

filter[q] is the dashboard’s listing search, by the same rule: the words in the name, the reference, your dealerProductCode or externalIdentifier, or brand and model as one phrase.
Every page carries meta.statusCounts: how many listings the business has in each status, all seven present, across the whole inventory whatever you filtered — the numbers on the dashboard’s tabs. It is there only for a token that acts for the business: our own app reading another shop’s listings, as a visitor, gets what is for sale and no counts.

The price, and what a sale costs

The dashboard’s quick edit is a PATCH of name, price and priceOnRequest. A listing needs a price of at least 100000 (€1,000.00) unless it is priced on request: price: null without priceOnRequest: true is a 422. applicationFee on a listing is what we charge the business when it sells at its price, in cents — the figure the dashboard shows beside the price, worked out with the business’s own VAT. For a price that is not saved yet, while somebody types it:
answers in meta: the price you asked about, its applicationFee, and the table it comes from — fixedFee up to and including threshold, percentage of the price above it. Show what comes back; do not work it out yourself. A price that is missing or not a whole number of cents is a 400 with invalid_price.

Creating one

string
required
The manufacturer’s reference.
string
required
What the listing is called.
string
required
The text on the listing.
integer
required
In cents. 1450000 is €14,500.00. At least 100000 (€1,000.00). Leave it out, or send null, only with priceOnRequest: true.
object
required
A flat map of names to values: {"CONDITION": "VERY_GOOD"}. Four are required — AVAILABILITY, STATE, CONDITION, YEAR_OF_PRODUCTION — and a value we do not know is refused rather than stored, because the whole point of the list is that STEEL means one thing.GET /v1/specifications is that list: every name, every value it accepts, and which four are required. Generate your mapping from it rather than hard-coding one; we add values.On an update, the names you send are replaced and the ones you leave out stay as they are. Send one as null to clear it: {"DIAL_COLOR": null}. The four required ones cannot be cleared — a listing cannot be reviewed without them.
relationship
required
Which model it is, from our own list: GET /v1/watch-models, by brand or by the words somebody types.
The business comes from the address, so there is no need to name it in the body — and if you do, it has to be the same one.
A new listing never starts live. Every one goes into review, the same as one added in the dashboard. Leave status out or send available and it lands in awaiting_review — so it needs a photo (imageHandles or imageSources) and a price or priceOnRequest, or the create is refused with 422 on /data/attributes/status; send draft and it stays a draft only you can see, with or without them. Anything else on a create is refused.

The status is a word

You may set available, sold, unavailable and draft. awaiting_review, awaiting_update and unsubscribed_trader are states a listing reaches on its own — a new listing lands in review by itself, and billing decides the third. Publishing is sending available, and what happens depends on where the listing is: A shop without a subscription has nothing for sale: a listing that would go live there lands in unsubscribed_trader instead, and comes back when the subscription does. visible on the shop (GET /v1/sellers/{id}) says whether it is on show. The answer carries the status it actually landed in, so read it rather than assuming available. A listing that has not been through review (draft, awaiting_review, awaiting_update) can go to review or back to draft, and nothing else: unavailable or sold are refused with 422, because either would be a way round review. A draft may be saved without photos or a price, but review needs them: publishing a draft without at least one photo and a price of at least € 1,000 (or priceOnRequest) is refused with 422 on /data/attributes/status, as the dashboard refuses it. Photos or a price sent in the same request count. The same holds for a new listing created into review, and for a duplicateOf copy sent with available, which is judged on the gallery and price it takes from its source unless the body sends others. A sold listing stays sold, and is not deleted. Any other status for it is 409 listing_sold, and so is DELETE — an order, an invoice and a buyer’s thread point at it, and the dashboard offers neither. To sell the same watch again, start a new listing from it with duplicateOf (see the business guide): a draft, which goes through review when you publish it. A listing a buyer is paying for right now cannot be deleted either (409 listing_reserved). A listing in awaiting_update was sent back by a reviewer. reviewNote says what they want changed; it is null in every other state.

A nightly run

1

Walk what we have

GET /v1/sellers/{id}/watches?fields[watches]=externalIdentifier,price,status and follow links.next. Sparse fields keep it small.
2

Send only what changed

A PATCH says only what it changes. Sending a listing whose price has not moved is a write we both pay for and nobody needed.
3

Mark what is gone

PATCH it to sold or unavailable rather than deleting it — an order that already exists still points at the listing that was bought. sold is final, so use unavailable for a watch that may come back.
Put an Idempotency-Key on every write in that run. A timeout halfway through is the normal failure, and a retry that duplicates a listing is the expensive one.

Listings you do not own

A listing from a Connect feed is maintained in the seller’s own application. The fields that feed supplies answer 409 here, and the error names them. Why →