Home · Catalogue API

Catalogue API

A read-only JSON feed of the VESTRA wholesale catalogue, for partners who want the range inside their own shop or ERP rather than in a spreadsheet. Brands, articles, size runs, colours, minimum order quantities, tiered wholesale prices in EUR, photograph URLs and a link back to each product page.

Two things this feed does not carry. Both are stated here rather than discovered later, because a missing field found after you have written an importer costs more than one found before.

No live stock. Per-unit inventory is not tracked, so every product returns "stock": {"tracked": false, "quantity": null}. Do not resell against a quantity from this feed — confirm availability before you promise a delivery date.

No EAN / GTIN. Barcode data is not held for this catalogue, so there is no barcode field at all. If your marketplace requires an EAN to list, this feed alone will not satisfy it.

Getting a key

Keys are issued per partner to verified trade accounts, because the feed carries wholesale pricing. Write to support@vestrasales.com from the address on your account. A key looks like vsk_…. We store only a one-way hash of it, so it appears in full exactly once — at the moment it is issued. Nobody here can read it back to you afterwards; if it goes missing we revoke it and issue another.

Send it on every request:

curl -H "Authorization: Bearer vsk_your_key_here" \
  "https://vestrasales.com/api/catalog?a=whoami"

A missing or revoked key returns 401 with {"ok": false, "error": "unauthorized"}. Revocation takes effect immediately.

Endpoints

GET /api/catalog?a=products

The catalogue, paginated. Parameters, all optional:

ParameterMeaning
page1-based page number. Default 1.
perItems per page, 1–200. Default 100.
brandExact brand name, case-insensitive. See a=brands.
catExact category name, case-insensitive.
sinceAny date your language can format, e.g. 2026-08-01. Returns articles added on or after it — use it for incremental syncs instead of pulling the whole catalogue each night.

The response carries next_page so you do not have to compute it; it is null on the last page. Walking until next_page is null is the whole of correct pagination here.

{
  "ok": true,
  "generated_at": "2026-08-27T12:40:11+00:00",
  "page": 1, "per_page": 100, "pages": 4, "total": 344,
  "next_page": 2,
  "items": [ { … } ]
}

GET /api/catalog?a=product&id=id

One article, same shape as an item above, under item. Unknown id returns 404.

GET /api/catalog?a=brands

Every brand in the catalogue with a product count — useful for building your own filter, and for checking a brand name before passing it to brand=.

GET /api/catalog?a=whoami

Confirms the key works and reports which partner it belongs to, the field list, and the same “not available” notes as above. Start here when wiring up.

The product object

FieldTypeNotes
idstringStable VESTRA reference. Use it as your foreign key.
skustringSupplier article number. May be empty on older listings.
brandstring
namestring
categorystring
descriptionstringPlain text.
unitstringUsually pc; some lines are sold in packs or boxes.
moqintegerMinimum order quantity in unit.
sizesstringThe size run as written on the listing, e.g. S–XXL or 44–54. Free text, not a list — it also carries pack rules where a line is sold in size runs.
coloursstring[]May be empty.
currencystringAlways EUR. See below.
pricingstringfixed, sale, or on_request. On on_request lines the tiers are indicative and the real number comes from an offer.
price_tiersobject[][{"min_qty":20,"price":34.00}, …], ascending. The price that applies is the one for the highest min_qty your quantity reaches.
price_fromnumber|nullConvenience: the first tier's price.
list_pricenumber|nullPre-discount price where a line is on sale.
rrpnumber|nullBrand recommended retail, where known.
originstringProvenance as declared by the seller, e.g. EEA stock · proof on request.
sellerstringvia VESTRA where the seller has chosen not to be named publicly.
imagesstring[]Absolute URLs. First image is the primary.
urlstringThe product page — trade prices there still require a signed-in trade account.
added_atstringISO 8601, or empty on catalogue lines that predate the field.
stockobject{"tracked": false, "quantity": null, "note": "…"}. See the note at the top.

Currency

Prices are always EUR here, with no conversion parameter. The website converts the shelf price for visitors outside the euro area as a reading convenience, but orders are contracted and invoiced in EUR — so a feed that quoted anything else would hand you a number your invoice will not match. Convert at your own rate, on your own schedule, in your own shop.

Rate and caching

There is no hard rate limit, and no charge for access. Responses carry Cache-Control: private, max-age=60: the catalogue does not change by the second, and a nightly full pull plus since= during the day is both gentler and more accurate than polling.

Ordering: the dropship API

The catalogue API above is read-only. Placing orders one piece at a time is a separate endpoint, /api/dropship, with its own key. It is open to verified trade partners buying for their own customers: you complete checkout and enter your customer's delivery address, and no contract of sale arises between VESTRA and that end customer. The commercial side of it — pricing rule, exclusions, availability, duties and photograph rights — is set out on the dropshipping page.

GET /api/dropship?a=list

Every article available for single-piece purchase, with its price. Ralph Lauren, Lacoste and boxershorts are excluded from dropshipping — treat this feed as the authority rather than filtering the catalogue yourself.

GET /api/dropship?a=stock&id=id

Price, the three shipping zones, and stock_tracked — which is false for catalogue articles, for the same reason the catalogue feed reports no stock. Also returns colours and sizes: the values the listing knows, for you to offer your customer. Either may be empty, which means the listing does not state them — not that none exist. shipping is keyed by zone and carries label, fee and transit_working_days for each.

POST /api/dropship?a=order

{ "id": "dsq-101211", "colour": "Black", "size": "M", "qty": 1,
  "country": "JP",
  "reference": "your-order-id",
  "customer_email": "…", "customer_name": "…" }

Returns { ok, ref, checkout_url }. Open checkout_url to pay. Your own reference is echoed back and shown on the order.

FieldNotes
zone / countryzone is EU or a destination ISO-2 code from the shipping table; or pass country as an ISO-2 code and we map it. Anything else falls back to EU.
colour, sizeWhat your customer ordered. Send one of the values a=stock lists for the article; where it lists none, send free text.

Price and shipping

The dropship price is the wholesale price of the smallest quantity tier plus 20%. Shipping is charged once per order by zone:

ZoneRateDelivers toTransit
EU€16.00the 27 EU member states5–7 working days
GB€30.00United Kingdom5–10 working days
US€30.00United States5–10 working days
JP€30.00Japan7–14 working days
SG€30.00Singapore7–14 working days
AE€30.00United Arab Emirates5–8 working days
SA€30.00Saudi Arabia5–8 working days
QA€30.00Qatar5–8 working days
AU€35.00Australia7–14 working days
CA€35.00Canada5–10 working days
KR€35.00South Korea7–14 working days

Transit is working days from dispatch, not calendar days, and does not include the time customs holds a consignment at destination.

Outside the EU the zone code is the destination's ISO-2 country code, so passing country is enough and zone is the same string. A country not in this table falls back to EU, whose session will then refuse that address rather than ship it at the wrong rate.

The zone is fixed before the payment session opens, and the session then accepts only that zone's countries — so the rate charged and the address entered cannot diverge.

Duties and import taxes are not included in the price or the shipping rate. They are payable on delivery and are yours to settle or to pass to your customer. Goods of EU preferential origin may attract zero customs duty entering Japan under the EU–Japan Economic Partnership Agreement when a statement on origin accompanies the consignment — that is the tariff only, and does not cover consumption tax or the carrier's clearance fee.

Availability is confirmed after the order, because per-unit stock is not tracked. If an article cannot be supplied, the order is refunded in full.

If you need something else

CSV and XLSX exports of the same catalogue are available to signed-in trade accounts from the price list — the XLSX carries the photographs embedded next to each row. There is no XML feed and no FTP drop.