Changelog & versioning
The API is versioned by date. Your integration is pinned to a single date-stamped version. We won't change anything about that version's behaviour without you opting in.
How versioning works
The version pinned to your integration is visible at Settings → API version and on every response as the X-API-Version header. It's also embedded in every webhook event:
Newly-created integrations always pin to the latest dated version at creation time. To roll an existing integration forward (to opt into breaking changes from a newer version), email support@watchtraderhub.com. We don't auto-roll because we don't want to break your production integration on our schedule.
X-API-Version is response-only
X-API-Version on outbound requests; we do not read it. Version pinning happens at integration creation time and is enforced server-side. The header on every response and on every webhook envelope's api_version field is the canonical value, set entirely by us. Send the header defensively if you like (some integrators do for forward-compat breadcrumbs), but it has no effect.What counts as a breaking change
Breaking changes (mint a new dated version):
- Removing an endpoint, field, or event type.
- Renaming an endpoint, field, or event type.
- Tightening a validation rule (a payload that used to be accepted is now rejected).
- Changing the meaning of a field, e.g. a status enum value being repurposed.
- Changing the algorithm of webhook signing or any header format.
- Changing the cursor format or pagination semantics.
Non-breaking changes (ship continuously, pinned versions automatically benefit):
- Adding a new endpoint.
- Adding a new optional field to a request body.
- Adding a new field to a response body.
- Adding a new event type. Existing subscriptions still apply; the wildcard
*picks it up. - Adding a new error code (existing codes keep their meaning).
- Improving error
messagewording.
Match codes, not messages
error.code values part of the contract. error.message wording can change at any time in the name of better diagnostics. Branch on code.Versions
2026-05-07
CurrentInitial public release of the Custom Integration API. Includes the full REST surface (listings, customers, orders, integration metadata, test utilities) and the outbound webhook surface (10 event types, HMAC-SHA256 signing, retry + replay + dead-letter).
Additions, September 2026 (non-breaking)
All additive on 2026-05-07: nothing was removed or renamed, and existing integrations keep working unchanged.
- Listings:
title,quantity,labels(English display text for every enum field) anddescription_paragraphs; underwatch:case_thickness_mm,lug_width_mm,bezel_material,crystal_type,dial_numerals,bracelet_material,bracelet_color,bracelet_links,clasp_type,clasp_material,additional_details,handling_timeandtax_treatment. - Parts:
part.tax_treatment,labelsanddescription_paragraphs. - Photos (listings and parts):
width,heightand a squarethumbnail_url. - Promo prices (listings and parts): while the dealer runs a promo,
priceis the promo price and the newpromotionobject names the regular price it replaces (regular_amount,regular_amount_formatted) and when it ends (ends_at, or null).promotionis null otherwise. Starting, changing or ending a promo sendslisting.updated(part.updatedfor a part). descriptionno longer carries the" || "paragraph separator some imported descriptions used: it becomes a blank line. Line breaks the dealer typed are unchanged.- Orders: optional
shipping_amount,discount_amountandtax_amounton the order anddiscount_amounton each line. Shipping and coupons are recorded as shipping and discounts instead of fees; orders read back the amounts you reported. Orders without them behave exactly as before. GET /v1/ordersnow honoursupdated_after, as documented.listing.updatedandpart.updatednow also fire when the dealer changes photos or stock quantity, your integration's markup, rounding or image format, the business address or default tax treatment, a business unit or location name, or assigns stock numbers. Before, only an edit of the item itself sent one.order.cancellednow fires when the dealer dismisses one of your orders in WatchTraderHub, with the full order.order.receivedandcustomer.matchedare no longer listed: they could only ever describe your own API call, were never delivered to you, and a subscription that names them keeps working.- A failed database read now answers
500 query_failedinstead of serving a listing priced in a fallback currency. Retry it. - Corrected reference:
POST /v1/customers/bulkreturnsbulk_resultand is atomic;POST /v1/test/webhook_pingreturnsdelivery_idandenqueued; the signature header isX-WTH-Signature; customermetadatais accepted and not stored.
