curl --request POST \
--url https://{host}/v1/me/orders \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/vnd.api+json' \
--data '
{
"data": {
"type": "orders",
"attributes": {
"billingAddress": {
"id": "661"
},
"notes": "Graag vóór vrijdag",
"coupon": "WRISTLER10"
},
"relationships": {
"watch": {
"data": {
"type": "watches",
"id": "91827"
}
}
}
}
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/vnd.api+json'},
body: JSON.stringify({
data: {
type: 'orders',
attributes: {billingAddress: {id: '661'}, notes: 'Graag vóór vrijdag', coupon: 'WRISTLER10'},
relationships: {watch: {data: {type: 'watches', id: '91827'}}}
}
})
};
fetch('https://{host}/v1/me/orders', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://{host}/v1/me/orders",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'data' => [
'type' => 'orders',
'attributes' => [
'billingAddress' => [
'id' => '661'
],
'notes' => 'Graag vóór vrijdag',
'coupon' => 'WRISTLER10'
],
'relationships' => [
'watch' => [
'data' => [
'type' => 'watches',
'id' => '91827'
]
]
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/vnd.api+json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}import requests
url = "https://{host}/v1/me/orders"
payload = { "data": {
"type": "orders",
"attributes": {
"billingAddress": { "id": "661" },
"notes": "Graag vóór vrijdag",
"coupon": "WRISTLER10"
},
"relationships": { "watch": { "data": {
"type": "watches",
"id": "91827"
} } }
} }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/vnd.api+json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"data": {
"type": "orders",
"id": "7741",
"attributes": {
"number": "202610100",
"status": "processing",
"paid": false,
"reservationLapsed": false,
"subtotal": 1295000,
"shipping": 0,
"serviceCosts": 0,
"total": 1295000,
"applicationFee": null,
"payoutAmount": null,
"paymentMethod": null,
"buyerEmail": null,
"buyerPhone": null,
"receiptUrl": "https://api.wristler.eu/v1/me/orders/7741/receipt",
"paymentMethods": [
{
"code": "ideal",
"label": "iDeal",
"description": null,
"fee": 0,
"total": 1295000,
"available": true,
"unavailableReason": null
},
{
"code": "bancontact",
"label": "Bancontact",
"description": null,
"fee": 0,
"total": 1295000,
"available": true,
"unavailableReason": null
},
{
"code": "customer_balance",
"label": "Wire transfer",
"description": "Escrow account details are provided after order confirmation. Ensure your bank's daily limit is sufficient. Wire transfers may take up to 3 business days.",
"fee": 1500,
"total": 1296500,
"available": true,
"unavailableReason": null
},
{
"code": "card",
"label": "Credit card",
"description": "We only accept card payments in Euro\n3DS verification is included",
"fee": 19450,
"total": 1314450,
"available": false,
"unavailableReason": "Not accepted by this seller. Please choose another payment method."
}
],
"reservedUntil": "2026-09-27T12:02:11.000000Z",
"notes": "Graag vóór vrijdag",
"coupon": "WRISTLER10",
"courier": null,
"trackingNumber": null,
"trackingUrl": null,
"paidAt": null,
"shippedAt": null,
"cancelledAt": null,
"deliveredAt": null,
"timeline": [
{
"event": "placed",
"at": "2026-09-25T14:02:11+02:00"
}
],
"paidOutAt": null,
"createdAt": "2026-09-25T12:02:11.000000Z",
"updatedAt": "2026-09-25T12:02:11.000000Z"
},
"relationships": {
"seller": {
"links": {
"related": "https://api.wristler.eu/v1/me/orders/7741/seller"
}
},
"items": {
"links": {
"related": "https://api.wristler.eu/v1/me/orders/7741/items"
}
},
"addresses": {
"links": {
"related": "https://api.wristler.eu/v1/me/orders/7741/addresses"
}
}
},
"links": {
"self": "https://api.wristler.eu/v1/me/orders/7741"
}
},
"links": {
"self": "https://api.wristler.eu/v1/me/orders/7741"
}
}{
"data": {
"type": "orders",
"id": "7741",
"attributes": {
"number": "202610100",
"status": "processing",
"paid": false,
"reservationLapsed": false,
"subtotal": 1295000,
"shipping": 0,
"serviceCosts": 0,
"total": 1295000,
"applicationFee": null,
"payoutAmount": null,
"paymentMethod": null,
"buyerEmail": null,
"buyerPhone": null,
"receiptUrl": "https://api.wristler.eu/v1/me/orders/7741/receipt",
"paymentMethods": [
{
"code": "ideal",
"label": "iDeal",
"description": null,
"fee": 0,
"total": 1295000,
"available": true,
"unavailableReason": null
},
{
"code": "bancontact",
"label": "Bancontact",
"description": null,
"fee": 0,
"total": 1295000,
"available": true,
"unavailableReason": null
},
{
"code": "customer_balance",
"label": "Wire transfer",
"description": "Escrow account details are provided after order confirmation. Ensure your bank's daily limit is sufficient. Wire transfers may take up to 3 business days.",
"fee": 1500,
"total": 1296500,
"available": true,
"unavailableReason": null
},
{
"code": "card",
"label": "Credit card",
"description": "We only accept card payments in Euro\n3DS verification is included",
"fee": 19450,
"total": 1314450,
"available": false,
"unavailableReason": "Not accepted by this seller. Please choose another payment method."
}
],
"reservedUntil": "2026-09-27T12:02:11.000000Z",
"notes": "Graag vóór vrijdag",
"coupon": "WRISTLER10",
"courier": null,
"trackingNumber": null,
"trackingUrl": null,
"paidAt": null,
"shippedAt": null,
"cancelledAt": null,
"deliveredAt": null,
"timeline": [
{
"event": "placed",
"at": "2026-09-25T14:02:11+02:00"
}
],
"paidOutAt": null,
"createdAt": "2026-09-25T12:02:11.000000Z",
"updatedAt": "2026-09-25T12:02:11.000000Z"
},
"relationships": {
"seller": {
"links": {
"related": "https://api.wristler.eu/v1/me/orders/7741/seller"
}
},
"items": {
"links": {
"related": "https://api.wristler.eu/v1/me/orders/7741/items"
}
},
"addresses": {
"links": {
"related": "https://api.wristler.eu/v1/me/orders/7741/addresses"
}
}
},
"links": {
"self": "https://api.wristler.eu/v1/me/orders/7741"
}
},
"links": {
"self": "https://api.wristler.eu/v1/me/orders/7741"
}
}{
"errors": [
{
"status": "404",
"code": "watch_reserved",
"title": "Not Found",
"detail": "<string>",
"meta": {},
"source": {
"pointer": "/data/attributes/reference",
"parameter": "<string>"
}
}
],
"jsonapi": {
"version": "1.0"
}
}{
"errors": [
{
"status": "409",
"code": "watch_reserved",
"title": "Conflict",
"detail": "This watch is reserved for another buyer. It comes back up for sale if that order is not paid."
}
]
}{
"errors": [
{
"status": "404",
"code": "watch_reserved",
"title": "Not Found",
"detail": "<string>",
"meta": {},
"source": {
"pointer": "/data/attributes/reference",
"parameter": "<string>"
}
}
],
"jsonapi": {
"version": "1.0"
}
}Place order
Scope: checkout:write
{ "data": { "type": "orders",
"attributes": {
"billingAddress": { "id": "661" },
"shippingAddress": { "name": "Jeffrey", "lastName": "Ponsen",
"addressLine1": "Alexanderveld 5", "zipcode": "2585 DB",
"city": "Den Haag", "country": "NL" },
"notes": "Graag vóór vrijdag",
"coupon": "WRISTLER10"
},
"relationships": {
"watch": { "data": { "type": "watches", "id": "91827" } },
"offer": { "data": { "type": "messages", "id": "5512" } }
} } }
An address is either { "id": … } from /v1/me/addresses or the fields
themselves, in the same spelling that resource uses. Either way it is copied
onto the order: an order has to keep saying where it went after somebody moves
house. shippingAddress defaults to the billing one. An id that is not yours
does not exist (422). Typed, an address needs name, lastName, addressLine1
(with a house number in it), zipcode, city and a two-letter country;
companyName and addressLine2 are optional; every field is up to 255 characters.
phone is required when the account has no phone number yet (Stripe needs one to
reach the buyer), and may be left out once it has. notes is free text for the
seller.
offer is the message that carried a seller’s price proposal, and it is how a
negotiated price gets into a checkout — never an amount. The offer has to be a
price proposal, made to you, about this watch, still standing, and the newest in
its conversation; anything else is offer_refused, which says only that. The price
and the shipping costs come from the offer. Leaving offer out does not ignore
one: an offer that still stands for this buyer and this watch is applied anyway, as on
the website. A watch marked priceOnRequest has no price to charge and cannot be
bought without naming one.
coupon is a discount code, as the website’s checkout takes one: up to 255
characters of free text, kept on the order (coupon) for the seller to honour and
shown on the receipt and in the order mails. It changes no amount — not here,
not in paymentMethods, and not on the website either — so the summary before
paying shows the same totals with or without one. Too long is a 422 pointing at
/data/attributes/coupon. Re-entering the order without one leaves none.
The answer is the order, with paymentMethods for the next screen and
reservedUntil for the sentence above it. Posting again for the same watch
re-enters the order you already have (200) rather than opening a second —
until a payment has been asked for, after which it is payment_in_progress and
the order is the thing to read.
Send an Idempotency-Key. A request that times out leaves a client not knowing
whether it placed an order, and “find out by trying” is not an answer.
| Refusal | Status | code |
|---|---|---|
| Withdrawn, sold, or the shop is not taking payments | 422 | watch_not_for_sale |
An address (typed or saved) in a country we do not ship to; the pointer names the field, meta.country the code | 422 | country_not_shipped_to |
A saved address whose addressLine1 has no house number (saved before the address book asked for one); the pointer is /data/attributes/{billingAddress|shippingAddress}/addressLine1. A typed one is an ordinary validation error on the same pointer | 422 | house_number_missing |
| Somebody else is paying for it right now | 409 | watch_reserved |
| Priced on request, and no offer named | 422 | price_on_request |
Available on request (availabilityOnRequest), and no offer named | 422 | availability_on_request |
| The offer has expired, or was replaced | 422 | offer_refused |
A payment on your own order is already under way; meta.order is its id | 409 | payment_in_progress |
curl --request POST \
--url https://{host}/v1/me/orders \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/vnd.api+json' \
--data '
{
"data": {
"type": "orders",
"attributes": {
"billingAddress": {
"id": "661"
},
"notes": "Graag vóór vrijdag",
"coupon": "WRISTLER10"
},
"relationships": {
"watch": {
"data": {
"type": "watches",
"id": "91827"
}
}
}
}
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/vnd.api+json'},
body: JSON.stringify({
data: {
type: 'orders',
attributes: {billingAddress: {id: '661'}, notes: 'Graag vóór vrijdag', coupon: 'WRISTLER10'},
relationships: {watch: {data: {type: 'watches', id: '91827'}}}
}
})
};
fetch('https://{host}/v1/me/orders', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://{host}/v1/me/orders",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'data' => [
'type' => 'orders',
'attributes' => [
'billingAddress' => [
'id' => '661'
],
'notes' => 'Graag vóór vrijdag',
'coupon' => 'WRISTLER10'
],
'relationships' => [
'watch' => [
'data' => [
'type' => 'watches',
'id' => '91827'
]
]
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/vnd.api+json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}import requests
url = "https://{host}/v1/me/orders"
payload = { "data": {
"type": "orders",
"attributes": {
"billingAddress": { "id": "661" },
"notes": "Graag vóór vrijdag",
"coupon": "WRISTLER10"
},
"relationships": { "watch": { "data": {
"type": "watches",
"id": "91827"
} } }
} }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/vnd.api+json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"data": {
"type": "orders",
"id": "7741",
"attributes": {
"number": "202610100",
"status": "processing",
"paid": false,
"reservationLapsed": false,
"subtotal": 1295000,
"shipping": 0,
"serviceCosts": 0,
"total": 1295000,
"applicationFee": null,
"payoutAmount": null,
"paymentMethod": null,
"buyerEmail": null,
"buyerPhone": null,
"receiptUrl": "https://api.wristler.eu/v1/me/orders/7741/receipt",
"paymentMethods": [
{
"code": "ideal",
"label": "iDeal",
"description": null,
"fee": 0,
"total": 1295000,
"available": true,
"unavailableReason": null
},
{
"code": "bancontact",
"label": "Bancontact",
"description": null,
"fee": 0,
"total": 1295000,
"available": true,
"unavailableReason": null
},
{
"code": "customer_balance",
"label": "Wire transfer",
"description": "Escrow account details are provided after order confirmation. Ensure your bank's daily limit is sufficient. Wire transfers may take up to 3 business days.",
"fee": 1500,
"total": 1296500,
"available": true,
"unavailableReason": null
},
{
"code": "card",
"label": "Credit card",
"description": "We only accept card payments in Euro\n3DS verification is included",
"fee": 19450,
"total": 1314450,
"available": false,
"unavailableReason": "Not accepted by this seller. Please choose another payment method."
}
],
"reservedUntil": "2026-09-27T12:02:11.000000Z",
"notes": "Graag vóór vrijdag",
"coupon": "WRISTLER10",
"courier": null,
"trackingNumber": null,
"trackingUrl": null,
"paidAt": null,
"shippedAt": null,
"cancelledAt": null,
"deliveredAt": null,
"timeline": [
{
"event": "placed",
"at": "2026-09-25T14:02:11+02:00"
}
],
"paidOutAt": null,
"createdAt": "2026-09-25T12:02:11.000000Z",
"updatedAt": "2026-09-25T12:02:11.000000Z"
},
"relationships": {
"seller": {
"links": {
"related": "https://api.wristler.eu/v1/me/orders/7741/seller"
}
},
"items": {
"links": {
"related": "https://api.wristler.eu/v1/me/orders/7741/items"
}
},
"addresses": {
"links": {
"related": "https://api.wristler.eu/v1/me/orders/7741/addresses"
}
}
},
"links": {
"self": "https://api.wristler.eu/v1/me/orders/7741"
}
},
"links": {
"self": "https://api.wristler.eu/v1/me/orders/7741"
}
}{
"data": {
"type": "orders",
"id": "7741",
"attributes": {
"number": "202610100",
"status": "processing",
"paid": false,
"reservationLapsed": false,
"subtotal": 1295000,
"shipping": 0,
"serviceCosts": 0,
"total": 1295000,
"applicationFee": null,
"payoutAmount": null,
"paymentMethod": null,
"buyerEmail": null,
"buyerPhone": null,
"receiptUrl": "https://api.wristler.eu/v1/me/orders/7741/receipt",
"paymentMethods": [
{
"code": "ideal",
"label": "iDeal",
"description": null,
"fee": 0,
"total": 1295000,
"available": true,
"unavailableReason": null
},
{
"code": "bancontact",
"label": "Bancontact",
"description": null,
"fee": 0,
"total": 1295000,
"available": true,
"unavailableReason": null
},
{
"code": "customer_balance",
"label": "Wire transfer",
"description": "Escrow account details are provided after order confirmation. Ensure your bank's daily limit is sufficient. Wire transfers may take up to 3 business days.",
"fee": 1500,
"total": 1296500,
"available": true,
"unavailableReason": null
},
{
"code": "card",
"label": "Credit card",
"description": "We only accept card payments in Euro\n3DS verification is included",
"fee": 19450,
"total": 1314450,
"available": false,
"unavailableReason": "Not accepted by this seller. Please choose another payment method."
}
],
"reservedUntil": "2026-09-27T12:02:11.000000Z",
"notes": "Graag vóór vrijdag",
"coupon": "WRISTLER10",
"courier": null,
"trackingNumber": null,
"trackingUrl": null,
"paidAt": null,
"shippedAt": null,
"cancelledAt": null,
"deliveredAt": null,
"timeline": [
{
"event": "placed",
"at": "2026-09-25T14:02:11+02:00"
}
],
"paidOutAt": null,
"createdAt": "2026-09-25T12:02:11.000000Z",
"updatedAt": "2026-09-25T12:02:11.000000Z"
},
"relationships": {
"seller": {
"links": {
"related": "https://api.wristler.eu/v1/me/orders/7741/seller"
}
},
"items": {
"links": {
"related": "https://api.wristler.eu/v1/me/orders/7741/items"
}
},
"addresses": {
"links": {
"related": "https://api.wristler.eu/v1/me/orders/7741/addresses"
}
}
},
"links": {
"self": "https://api.wristler.eu/v1/me/orders/7741"
}
},
"links": {
"self": "https://api.wristler.eu/v1/me/orders/7741"
}
}{
"errors": [
{
"status": "404",
"code": "watch_reserved",
"title": "Not Found",
"detail": "<string>",
"meta": {},
"source": {
"pointer": "/data/attributes/reference",
"parameter": "<string>"
}
}
],
"jsonapi": {
"version": "1.0"
}
}{
"errors": [
{
"status": "409",
"code": "watch_reserved",
"title": "Conflict",
"detail": "This watch is reserved for another buyer. It comes back up for sale if that order is not paid."
}
]
}{
"errors": [
{
"status": "404",
"code": "watch_reserved",
"title": "Not Found",
"detail": "<string>",
"meta": {},
"source": {
"pointer": "/data/attributes/reference",
"parameter": "<string>"
}
}
],
"jsonapi": {
"version": "1.0"
}
}Authorizations
Headers
Optional. A UUID per logical operation, not per attempt: a retry carrying the same key gets the first attempt's answer back, headers and all, rather than performing the write twice. Honoured for 24 hours.
A refusal is an answer. A 422 is remembered like any other, so sending a
corrected body under the same key answers 422 idempotency_key_reuse rather
than accepting the correction — the point of a key is that one key means one
decision. Use a new key for a new attempt at the request, and keep the old one
only for retrying the same bytes after a timeout.
A 5xx is the exception: nothing was decided, so the key is released and the
same one may be retried.
| Refusal | Status | code |
|---|---|---|
| The same key with a different body | 422 | idempotency_key_reuse |
| The first request with this key is still running | 409 | idempotency_in_progress |
| The key's record vanished between two requests: retry with a new key | 409 | idempotency_conflict |
| A key longer than 191 characters | 400 | idempotency_key_invalid |
A replayed answer carries Idempotent-Replay: true.
191