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

Cosmetic Wholesale

Partner Order API

Maak en lees dropshippingbestellingen vanuit uw eigen systeem.

Dit document vervangt het vorige Turor OMS-pakket (POST /restApi/v1/dropShippingOrder, GET /restApi/v1/dropShippingOrderItem/{id}). Die endpoints en hun HTTP Basic-inloggegevens zijn verouderd en mogen niet meer worden gebruikt. Zie Bijlage A aan het eind van deze pagina voor de veld-voor-veld-mapping.


Heeft u deze API nodig?

De meeste partners niet. Gebruikt u WooCommerce of Shopify, neem dan onze plugin — zie WooCommerce of Shopify. Bouw alleen tegen deze API aan wanneer u een maatwerk- of eigen systeem heeft.

Het importeren van de catalogus en het actueel houden van voorraad en prijzen staat apart beschreven in Catalogusfeed.

Er is een pdf-versie van deze pagina beschikbaar voor uw ontwikkelaars: Partner Order API v1.0 (PDF).

1. Omgevingen

OmgevingBasis-URL
Productiehttps://cosmeticwholesale.eu/api/v1
Staging (integratietests)https://cosmeticwholesale1.bookgurusapi.com/api/v1

Alle voorbeelden in dit document gebruiken de basis-URL van productie. Tokens worden niet gedeeld tussen omgevingen — vraag uw accountmanager om een staging-token als u eerst wilt testen.


2. Authenticatie

Elk verzoek bevat uw accounttoken als bearer-token:

Authorization: Bearer YOUR_ACCOUNT_TOKEN

Dit is hetzelfde token dat u gebruikt voor de productcatalogusfeed (GET /api/v1/feeds/catalog.csv). U vindt het op de pagina Account van uw Cosmetic Wholesale-login, samen met uw feed-URL.

Aandachtspunten:

  • Het token identificeert uw account. Maak het nooit zichtbaar in client-side code of in een publieke repository.
  • Tokens kunnen op elk moment vanuit uw account worden ingetrokken en opnieuw uitgegeven. Een ingetrokken token geeft 401.
  • Er wordt geen gebruikersnaam/wachtwoord gebruikt. De oude HTTP Basic-inloggegevens zijn niet meer geldig voor het indienen van bestellingen.
  • X-Feed-Token: YOUR_ACCOUNT_TOKEN wordt geaccepteerd als alternatieve header.

3. Voorwaarden

Een bestelling wordt alleen geaccepteerd wanneer aan alle onderstaande punten is voldaan:

  1. Uw account is goedgekeurd en zit op het dropshipping-kanaal.
  2. Uw dropshipping-abonnement is actief — anders geeft elk verzoek 403 subscription_required.
  3. Uw wallet heeft voldoende saldo om de bestelling te dekken — anders wordt de bestelling aangemaakt en vastgehouden (402, zie paragraaf 6).
  4. Elke ean in de bestelling bestaat in uw catalogusfeed en is op voorraad.

Producttitels, afbeeldingen en prijzen stuurt u niet mee — die komen uit onze catalogus. U stuurt alleen de EAN en het aantal.


4. Een bestelling aanmaken

POST /dropshipping/orders

Request-headers

Authorization: Bearer YOUR_ACCOUNT_TOKEN
Content-Type: application/json

Request-body

{
  "externalRef": "ORD123456",
  "payment": "WALLET",
  "shipping": {
    "firstName": "Name",
    "lastName": "LastName",
    "company": "TestCompany",
    "address1": "Main Street 123",
    "address2": "",
    "postcode": "1072 HM",
    "city": "Amsterdam",
    "country": "NL",
    "phone": "",
    "email": "customer@example.com"
  },
  "lines": [
    { "ean": "6291107455365", "quantity": 2 },
    { "ean": "3607348816552", "quantity": 3 }
  ]
}

Velden

VeldTypeVerplichtToelichting
externalRefstringjaUw eigen bestelnummer. Moet uniek zijn binnen uw account. Dit is de idempotentiesleutel — zie paragraaf 5.
paymentstringneeAlleen "WALLET" wordt ondersteund. Standaardwaarde is "WALLET".
lines[].eanstringjaEAN zoals gepubliceerd in uw catalogusfeed.
lines[].quantityintegerjaMoet ≥ 1 zijn.
shipping.firstNamestringaanbevolen
shipping.lastNamestringaanbevolen
shipping.address1stringja
shipping.address2stringnee
shipping.postcodestringja
shipping.citystringja
shipping.countrystringjaISO 3166-1 alpha-2, bijv. NL, BE, DE. Moet een land zijn waarnaar wij verzenden.
shipping.companystringnee
shipping.statestringnee
shipping.phonestringneeAanbevolen — sommige vervoerders vereisen dit.
shipping.emailstringneeWordt gebruikt voor meldingen van de vervoerder waar dat wordt ondersteund.

Voor compatibiliteit worden snake_case-aliassen geaccepteerd: external_ref, first_name, last_name, address_1, address_2, en qty voor quantity.

Response

{
  "id": "8f1c0b2e-6a3d-4f21-9b7e-0c5a4d2e1f33",
  "externalRef": "ORD123456",
  "omsReference": "ds:usr_2f9a1c:ORD123456",
  "createdVia": "dropshipping-api",
  "status": "PAID",
  "walletDebited": true,
  "omsPushStatus": "pending",
  "omsOrderItemIds": [],
  "tracking": []
}
VeldBetekenis
idCosmetic Wholesale-bestel-id (UUID). Sla dit op.
externalRefWeergave van uw bestelnummer.
omsReferenceInterne magazijnreferentie, ds:{accountId}:{externalRef}.
statusZie paragraaf 7.
walletDebitedtrue zodra de bestelling vanuit uw wallet is betaald.
omsPushStatusVoortgang van de overdracht naar ons magazijn: pending, pushed, retry, failed, skipped, of null.
omsOrderItemIdsMagazijnregel-id's, ingevuld nadat de overdracht is afgerond. Leeg bij de eerste response — poll met GET.
trackingLeeg tot het pakket is verzonden. Zie paragraaf 8.

HTTP-statuscodes

CodeBetekenisWat uw systeem moet doen
201Bestelling aangemaakt en betaald vanuit de wallet.Markeer als verzonden.
200Deze externalRef bestaat al. De body bevat de huidige status van die bestelling.Niets — dit is een veilige nieuwe poging.
402Bestelling aangemaakt maar vastgehouden: het walletsaldo is ontoereikend.Niet annuleren. Zie paragraaf 6.
400Validatiefout.Corrigeer de payload; probeer het niet ongewijzigd opnieuw.
401Ontbrekend, ongeldig of ingetrokken token.Controleer de inloggegevens.
403Geen actief dropshipping-abonnement.Neem contact met ons op.
404(Alleen GET) Bestelling niet gevonden op uw account.
409Onvoldoende voorraad voor een of meer regels.Probeer het later opnieuw of verlaag het aantal.

5. Idempotentie

externalRef is de idempotentiesleutel. Dezelfde externalRef twee keer versturen leidt nooit tot een tweede bestelling en debiteert uw wallet nooit twee keer:

  • Is de eerste poging geslaagd, dan geeft de tweede 200 met de bestaande bestelling.
  • Werd de eerste poging vastgehouden wegens onvoldoende saldo, dan probeert de tweede poging de walletbetaling opnieuw en geeft 201/200 zodra het saldo toereikend is.

Daardoor kunt u het endpoint veilig opnieuw aanroepen bij time-outs en netwerkfouten. Probeer het altijd opnieuw met dezelfde externalRef — genereer nooit een nieuwe voor dezelfde klantbestelling.


6. Onvoldoende saldo: het 402 HOLD-contract

Dit gedrag heeft geen equivalent in de oude OMS API en is de meest voorkomende integratiefout.

Wanneer uw wallet de bestelling niet kan dekken:

HTTP/1.1 402 Payment Required
{
  "id": "8f1c0b2e-6a3d-4f21-9b7e-0c5a4d2e1f33",
  "externalRef": "ORD123456",
  "status": "HOLD",
  "reason": "INSUFFICIENT_WALLET",
  "walletDebited": false,
  "omsPushStatus": null,
  "omsOrderItemIds": [],
  "tracking": []
}

Wat dit betekent:

  • De bestelling bestaat in ons systeem en is gereserveerd. De bestelling wordt niet geweigerd en niet verwijderd.
  • Er is niets gedebiteerd.
  • Er is nog niets naar het magazijn gestuurd.

Wat uw systeem moet doen:

  • Annuleer of verwijder de bestelling niet aan uw kant. Houd hem in een pending-/processing-status.
  • Waardeer uw wallet op.
  • Stuur dezelfde externalRef opnieuw met POST, of wacht gewoon af: vastgehouden bestellingen worden automatisch opnieuw geprobeerd zodra het saldo toereikend is.
  • Poll met GET tot walletDebited op true staat en status niet langer HOLD is.

Annuleren bij 402 is precies wat de afstemming verstoort — de bestelling blijft bij ons gereserveerd terwijl uw systeem denkt dat hij is mislukt.


7. Een bestelling opvragen

GET /dropshipping/orders/{id}
GET /dropshipping/orders?externalRef=ORD123456

{id} accepteert zowel de Cosmetic Wholesale-id (UUID) als uw eigen externalRef. Beide vormen geven dezelfde body terug als de aanmaakaanroep. Bestellingen zijn afgebakend op uw token — u kunt alleen uw eigen bestellingen opvragen.

GET https://cosmeticwholesale.eu/api/v1/dropshipping/orders?externalRef=ORD123456
Authorization: Bearer YOUR_ACCOUNT_TOKEN

Statuswaarden van een bestelling

statusBetekenis
HOLDVastgehouden wegens onvoldoende walletsaldo (zie paragraaf 6).
PENDING_PAYMENTWalletbetaling wordt verwerkt.
ON_HOLDWacht op verzend-/btw-verwerking.
PAIDBetaald vanuit de wallet.
PROCESSINGWordt klaargemaakt in het magazijn.
SHIPPEDOvergedragen aan de vervoerder — tracking is gevuld.
COMPLETEDBezorgd / afgesloten.
CANCELLED, REFUNDEDEindstatussen.

8. Track & trace

Track & trace wordt teruggegeven bij dezelfde GET, als array (een bestelling kan in meerdere pakketten worden verzonden):

{
  "id": "8f1c0b2e-6a3d-4f21-9b7e-0c5a4d2e1f33",
  "externalRef": "ORD123456",
  "status": "SHIPPED",
  "walletDebited": true,
  "omsPushStatus": "pushed",
  "omsOrderItemIds": ["418224", "418225", "418226"],
  "tracking": [
    {
      "provider": "postnl-3s",
      "trackingNumber": "3SXXXX00000000",
      "dateShipped": "2026-05-06T17:39:20.000Z"
    }
  ]
}

Poll maximaal één keer per uur per bestelling. Poll geen bestellingen die al COMPLETED, CANCELLED of REFUNDED zijn.


9. Foutcodes

Fouten geven { "error": "<message>", "code": "<code>" } terug.

codeHTTPOorzaak
external_ref_required400externalRef ontbreekt of is leeg.
lines_required400lines ontbreekt of is leeg.
ean_required400Een regel heeft geen ean.
invalid_qty400quantity is geen positief geheel getal.
unknown_ean400De EAN staat niet in uw catalogus.
forbidden_ean400De EAN kan niet via dit endpoint worden besteld.
shipping_required400Object shipping ontbreekt.
shipping_incomplete400address1, city, postcode of country ontbreekt.
shipping_country_required400Land leeg of niet in onze verzendzones.
payment_wallet_only400payment was op iets anders dan WALLET gezet.
invalid_json400Body is geen geldige JSON.
401Token ontbreekt, is ongeldig of is ingetrokken.
subscription_required403Geen actief dropshipping-abonnement.
not_found404Geen bestelling met dat nummer op uw account.
insufficient_stock409Onvoldoende voorraad voor een of meer regels.

10. Voorbeelden

cURL — aanmaken

curl -X POST https://cosmeticwholesale.eu/api/v1/dropshipping/orders \
  -H "Authorization: Bearer YOUR_ACCOUNT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "externalRef": "ORD123456",
    "shipping": {
      "firstName": "Name",
      "lastName": "LastName",
      "address1": "Main Street 123",
      "postcode": "1072 HM",
      "city": "Amsterdam",
      "country": "NL"
    },
    "lines": [
      { "ean": "6291107455365", "quantity": 2 }
    ]
  }'

cURL — opvragen

curl "https://cosmeticwholesale.eu/api/v1/dropshipping/orders?externalRef=ORD123456" \
  -H "Authorization: Bearer YOUR_ACCOUNT_TOKEN"

PHP — aanmaken

<?php

$token = 'YOUR_ACCOUNT_TOKEN';
$url   = 'https://cosmeticwholesale.eu/api/v1/dropshipping/orders';

$payload = [
    'externalRef' => 'ORD123456',
    'shipping' => [
        'firstName' => 'Name',
        'lastName'  => 'LastName',
        'address1'  => 'Main Street 123',
        'postcode'  => '1072 HM',
        'city'      => 'Amsterdam',
        'country'   => 'NL',
    ],
    'lines' => [
        ['ean' => '6291107455365', 'quantity' => 2],
    ],
];

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer ' . $token,
    'Content-Type: application/json',
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));

$response = curl_exec($ch);
$status   = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

$order = json_decode($response, true);

if ($status === 402) {
    // Held for insufficient wallet balance.
    // Keep your order open and retry with the SAME externalRef after topping up.
} elseif ($status === 201 || $status === 200) {
    // Accepted. Store $order['id'] and poll for tracking.
}
?>

PHP — opvragen

<?php

$token       = 'YOUR_ACCOUNT_TOKEN';
$externalRef = 'ORD123456';
$url = 'https://cosmeticwholesale.eu/api/v1/dropshipping/orders/' . rawurlencode($externalRef);

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Authorization: Bearer ' . $token]);
$response = curl_exec($ch);
curl_close($ch);

echo $response;
?>

Bijlage A — Migreren vanaf de Turor OMS-endpoints

Het oude pakket wees naar https://omsback.turor.org/restApi/v1 met HTTP Basic-inloggegevens. Die inloggegevens hoorden bij een gedeeld systeemaccount en omzeilden de wallet-, voorraad- en abonnementslaag. Ze worden niet meer uitgegeven en bestaande gegevens worden ingetrokken.

Endpoints

OudNieuw
POST /restApi/v1/dropShippingOrderPOST /api/v1/dropshipping/orders
GET /restApi/v1/dropShippingOrderItem/{id}GET /api/v1/dropshipping/orders/{id} (op bestelniveau, niet op regelniveau)
HTTP Basic username / passwordAuthorization: Bearer <account token>

Requestvelden

OudNieuw
order_numberexternalRef
line_items[]lines[]
line_items[].eanlines[].ean
line_items[].quantitylines[].quantity
line_items[].namevervallen — komt uit onze catalogus
line_items[].image_srcvervallen — komt uit onze catalogus
shipping.first_name / last_nameshipping.firstName / lastName (snake_case wordt nog geaccepteerd)
shipping.address_1 / address_2shipping.address1 / address2 (snake_case wordt nog geaccepteerd)
shipping.country, city, postcode, company, phoneongewijzigd
payment: "WALLET"

Responsevelden

OudNieuw
orderCreated: 1HTTP 201
orderCreated: 0 (bestaat al)HTTP 200
productCreated / productUpdated / orderUpdatedvervallen
omsOrderItemIds: "8059,8060" (kommagescheiden string)omsOrderItemIds: ["8059","8060"] (array van strings)
statusCode / message in de bodyHTTP-statuscode; fouten bevatten error + code
data.status, data.trackingNumber, data.trackingDatestatus, tracking[].trackingNumber, tracking[].dateShipped
data.serializedData, shippingProviderNametracking[].provider
walletDebited, omsPushStatus, 402 HOLD

Gedragswijzigingen om in uw code na te lopen

  1. 402 is geen fout. De oude API had geen walletlaag. Behandel 402 als "vastgehouden, opnieuw proberen met dezelfde referentie" — nooit als "annuleer de bestelling".
  2. Nieuwe pogingen zijn veilig. externalRef ontdubbelt; de oude controle op orderCreated: 0 is vervangen door het onderscheid tussen 200 en 201.
  3. Track & trace is verplaatst naar de bestelling. Eén GET per bestelling vervangt één GET per bestelregel, en het resultaat is een array.
  4. De productdata is van ons. Stuur geen titels en afbeeldings-URL's meer mee.