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
| Omgeving | Basis-URL |
|---|---|
| Productie | https://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_TOKENwordt geaccepteerd als alternatieve header.
3. Voorwaarden
Een bestelling wordt alleen geaccepteerd wanneer aan alle onderstaande punten is voldaan:
- Uw account is goedgekeurd en zit op het dropshipping-kanaal.
- Uw dropshipping-abonnement is actief — anders geeft elk verzoek
403 subscription_required. - Uw wallet heeft voldoende saldo om de bestelling te dekken — anders wordt de bestelling aangemaakt en vastgehouden (
402, zie paragraaf 6). - Elke
eanin 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
| Veld | Type | Verplicht | Toelichting |
|---|---|---|---|
externalRef | string | ja | Uw eigen bestelnummer. Moet uniek zijn binnen uw account. Dit is de idempotentiesleutel — zie paragraaf 5. |
payment | string | nee | Alleen "WALLET" wordt ondersteund. Standaardwaarde is "WALLET". |
lines[].ean | string | ja | EAN zoals gepubliceerd in uw catalogusfeed. |
lines[].quantity | integer | ja | Moet ≥ 1 zijn. |
shipping.firstName | string | aanbevolen | |
shipping.lastName | string | aanbevolen | |
shipping.address1 | string | ja | |
shipping.address2 | string | nee | |
shipping.postcode | string | ja | |
shipping.city | string | ja | |
shipping.country | string | ja | ISO 3166-1 alpha-2, bijv. NL, BE, DE. Moet een land zijn waarnaar wij verzenden. |
shipping.company | string | nee | |
shipping.state | string | nee | |
shipping.phone | string | nee | Aanbevolen — sommige vervoerders vereisen dit. |
shipping.email | string | nee | Wordt 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": []
}
| Veld | Betekenis |
|---|---|
id | Cosmetic Wholesale-bestel-id (UUID). Sla dit op. |
externalRef | Weergave van uw bestelnummer. |
omsReference | Interne magazijnreferentie, ds:{accountId}:{externalRef}. |
status | Zie paragraaf 7. |
walletDebited | true zodra de bestelling vanuit uw wallet is betaald. |
omsPushStatus | Voortgang van de overdracht naar ons magazijn: pending, pushed, retry, failed, skipped, of null. |
omsOrderItemIds | Magazijnregel-id's, ingevuld nadat de overdracht is afgerond. Leeg bij de eerste response — poll met GET. |
tracking | Leeg tot het pakket is verzonden. Zie paragraaf 8. |
HTTP-statuscodes
| Code | Betekenis | Wat uw systeem moet doen |
|---|---|---|
201 | Bestelling aangemaakt en betaald vanuit de wallet. | Markeer als verzonden. |
200 | Deze externalRef bestaat al. De body bevat de huidige status van die bestelling. | Niets — dit is een veilige nieuwe poging. |
402 | Bestelling aangemaakt maar vastgehouden: het walletsaldo is ontoereikend. | Niet annuleren. Zie paragraaf 6. |
400 | Validatiefout. | Corrigeer de payload; probeer het niet ongewijzigd opnieuw. |
401 | Ontbrekend, ongeldig of ingetrokken token. | Controleer de inloggegevens. |
403 | Geen actief dropshipping-abonnement. | Neem contact met ons op. |
404 | (Alleen GET) Bestelling niet gevonden op uw account. | |
409 | Onvoldoende 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
200met de bestaande bestelling. - Werd de eerste poging vastgehouden wegens onvoldoende saldo, dan probeert de tweede poging de walletbetaling opnieuw en geeft
201/200zodra 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
externalRefopnieuw met POST, of wacht gewoon af: vastgehouden bestellingen worden automatisch opnieuw geprobeerd zodra het saldo toereikend is. - Poll met
GETtotwalletDebitedoptruestaat enstatusniet langerHOLDis.
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
status | Betekenis |
|---|---|
HOLD | Vastgehouden wegens onvoldoende walletsaldo (zie paragraaf 6). |
PENDING_PAYMENT | Walletbetaling wordt verwerkt. |
ON_HOLD | Wacht op verzend-/btw-verwerking. |
PAID | Betaald vanuit de wallet. |
PROCESSING | Wordt klaargemaakt in het magazijn. |
SHIPPED | Overgedragen aan de vervoerder — tracking is gevuld. |
COMPLETED | Bezorgd / afgesloten. |
CANCELLED, REFUNDED | Eindstatussen. |
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.
code | HTTP | Oorzaak |
|---|---|---|
external_ref_required | 400 | externalRef ontbreekt of is leeg. |
lines_required | 400 | lines ontbreekt of is leeg. |
ean_required | 400 | Een regel heeft geen ean. |
invalid_qty | 400 | quantity is geen positief geheel getal. |
unknown_ean | 400 | De EAN staat niet in uw catalogus. |
forbidden_ean | 400 | De EAN kan niet via dit endpoint worden besteld. |
shipping_required | 400 | Object shipping ontbreekt. |
shipping_incomplete | 400 | address1, city, postcode of country ontbreekt. |
shipping_country_required | 400 | Land leeg of niet in onze verzendzones. |
payment_wallet_only | 400 | payment was op iets anders dan WALLET gezet. |
invalid_json | 400 | Body is geen geldige JSON. |
| — | 401 | Token ontbreekt, is ongeldig of is ingetrokken. |
subscription_required | 403 | Geen actief dropshipping-abonnement. |
not_found | 404 | Geen bestelling met dat nummer op uw account. |
insufficient_stock | 409 | Onvoldoende 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
| Oud | Nieuw |
|---|---|
POST /restApi/v1/dropShippingOrder | POST /api/v1/dropshipping/orders |
GET /restApi/v1/dropShippingOrderItem/{id} | GET /api/v1/dropshipping/orders/{id} (op bestelniveau, niet op regelniveau) |
HTTP Basic username / password | Authorization: Bearer <account token> |
Requestvelden
| Oud | Nieuw |
|---|---|
order_number | externalRef |
line_items[] | lines[] |
line_items[].ean | lines[].ean |
line_items[].quantity | lines[].quantity |
line_items[].name | vervallen — komt uit onze catalogus |
line_items[].image_src | vervallen — komt uit onze catalogus |
shipping.first_name / last_name | shipping.firstName / lastName (snake_case wordt nog geaccepteerd) |
shipping.address_1 / address_2 | shipping.address1 / address2 (snake_case wordt nog geaccepteerd) |
shipping.country, city, postcode, company, phone | ongewijzigd |
| — | payment: "WALLET" |
Responsevelden
| Oud | Nieuw |
|---|---|
orderCreated: 1 | HTTP 201 |
orderCreated: 0 (bestaat al) | HTTP 200 |
productCreated / productUpdated / orderUpdated | vervallen |
omsOrderItemIds: "8059,8060" (kommagescheiden string) | omsOrderItemIds: ["8059","8060"] (array van strings) |
statusCode / message in de body | HTTP-statuscode; fouten bevatten error + code |
data.status, data.trackingNumber, data.trackingDate | status, tracking[].trackingNumber, tracking[].dateShipped |
data.serializedData, shippingProviderName | tracking[].provider |
| — | walletDebited, omsPushStatus, 402 HOLD |
Gedragswijzigingen om in uw code na te lopen
402is geen fout. De oude API had geen walletlaag. Behandel402als "vastgehouden, opnieuw proberen met dezelfde referentie" — nooit als "annuleer de bestelling".- Nieuwe pogingen zijn veilig.
externalRefontdubbelt; de oude controle oporderCreated: 0is vervangen door het onderscheid tussen200en201. - Track & trace is verplaatst naar de bestelling. Eén
GETper bestelling vervangt éénGETper bestelregel, en het resultaat is een array. - De productdata is van ons. Stuur geen titels en afbeeldings-URL's meer mee.