1 month free dropshipping trial — then €39/month · Wholesale min €500
cosmeticwholesale

Cosmetic Wholesale

Catalog feed

Import the product catalog and keep stock and prices current from your own system.

The order API tells you how to send us an order. This page covers the other half: getting the products into your shop and keeping them current.

There is no "import" endpoint. We publish the catalog as a single file that you pull on a schedule — you keep the copy, you decide what to do with it. This is deliberate: we never write into your shop.

1. The endpoint

GET /api/v1/feeds/catalog.csv
GET /api/v1/feeds/catalog.json
Authorization: Bearer YOUR_ACCOUNT_TOKEN

Same token as the order API. The response is always gzip-compressed (Content-Encoding: gzip) — the catalog is large, so this is not optional.

ResponseMeaning
200The current catalog. ETag and X-CW-Feed-Rows headers tell you the version and the row count.
304Your If-None-Match matched — nothing has changed since your last pull. Does not count against the rate limit.
403Missing, invalid or revoked token.
429Rate limit: 30 full downloads per hour per token. Retry-After: 3600.
503feed_empty — no catalog is published yet. Keep your last copy and retry later.

2. CSV format

Header row, CRLF line endings, UTF-8:

ean,title,stock,price,processing_time,image_url
"6291107455365","Lattafa EDP Qaed Al Fursan 90 ml",42,18.40,"2-3","https://…/6291107455365.jpg"
ColumnMeaning
eanThe product key. Always quoted — treat it as a string, never as a number (leading zeros matter).
titleProduct title.
stockUnits available to you right now.
priceYour cost, in EUR, excluding VAT. Not a retail price.
processing_timeHandling time in working days, as published by the warehouse.
image_urlProduct image. Unlike our plugins, you are free to use it.

The JSON variant wraps the same rows in an envelope that states the terms explicitly:

{
  "channel": "DROPSHIPPING",
  "currency": "EUR",
  "tax": "ex_vat",
  "priceSource": "ds_channel_list",
  "generatedAt": "2026-09-07T09:00:00.000Z",
  "rowCount": 67412,
  "truncated": false,
  "rows": [ … ]
}

3. First import

Pull the feed once and create your products, keyed by EAN.

Write the EAN into your own SKU field. Order lines are matched by EAN — if the SKU on your side is anything else, the order push will not recognise the line and it will be dropped. Our Shopify app writes the EAN into both the SKU and the barcode for exactly this reason.

A realistic first import is tens of thousands of rows. Do it as a background job, not inside a web request, and make it resumable — store your position so a crash does not restart from zero.

4. Hourly update

Pull once an hour and send your last ETag:

GET /api/v1/feeds/catalog.csv
Authorization: Bearer YOUR_ACCOUNT_TOKEN
If-None-Match: "a3f19c…"

304 means nothing changed — stop there. A 200 means you have a new version: update stock and price for the EANs you already have.

Rules that keep this safe:

  • Update only. Do not create products on the hourly run, and do not delete.
  • A failed pull is not an empty catalog. On 429, 503, a timeout or a truncated download, keep your previous data and retry later. Never write zero stock across your catalog because a request failed — that is the single most damaging mistake in this integration.
  • stock: 0 is a real row, not a missing one. Products go to zero and come back.
  • A discontinued EAN stays in the feed at stock: 0 for at least 14 days before it disappears. So treat "not in the feed" as "no longer sold" only after it has been gone for a while — and even then, prefer hiding over deleting, so your order history stays intact.
  • Do not pull more than a few times an hour. The limit is 30 full downloads per hour; 304 responses are free.

5. Margin and your retail price

We do not store a margin for you. The feed gives you cost; what you charge your customer is your business, and nothing about it is configured on our side.

Our plugins apply this formula, and we recommend it for parity — if you ever migrate a shop between the plugin and your own system, the prices will not jump:

retail_price = round(cost × (1 + margin_percent / 100) + margin_fixed, 2)

Both numbers are yours to choose. 0 and 0 sells at our cost. Keep them in your own settings.

Two things worth remembering when you set them:

  • price is ex VAT. Add VAT according to your own registration and the customer's country.
  • Shipping is charged separately and is not in the feed.

6. Checklist before you go live

  • EAN is stored as text, and it is your SKU
  • First import completes and is resumable
  • Hourly job sends If-None-Match and handles 304
  • A failed or rate-limited pull leaves your catalog untouched
  • Hourly job never creates and never deletes products
  • stock: 0 hides the product instead of deleting it
  • Your margin formula matches what you had before, checked against ten known EANs
  • Retail price adds VAT on top of the feed cost