Skip to main content
Read-only, with one exception: an order records something that already happened.

Pull incrementally

Without updatedSince you walk the whole history every time. With it, and cursor paging, one call per run keeps you in step.
string
The sold listing beside the order — carrying the externalIdentifier you gave it, which is how you recognise your own product.
string
The name and address the buyer entered, which is what you need to ship. kind says which is which: SHIPPING or BILLING. The buyer’s account is not reachable: an order gives you what the order needs.
Item names and prices are copies taken at the moment of sale, so a listing edited or removed afterwards does not change what somebody bought.

Finding an order, and counting them

filter[q] is the dashboard’s order search, by the same rule: the order number (with or without #), the buyer’s name or email, the street, postcode or city of one of its addresses, or the name, model or brand of the watch.
Every page carries meta.statusCounts: how many orders the business has in each status — the dashboard’s seven tabs always, at 0 when empty, plus any other status it has orders in — across all of its orders, whatever you filtered.

What the order page shows

paymentMethod is how the buyer paid: card, ideal, bancontact, eps, p24, paypal, or customer_balance for a bank transfer. buyerEmail and buyerPhone are how to reach the buyer, as the dashboard shows them — to our own app only, and only once the order has gone through: null while it is awaiting_payment or awaiting_manual_review. A partner’s system gets the addresses shipping needs, not a person’s contact details. receiptUrl is the receipt as a PDF, at /v1/sellers/{sellerId}/orders/{id}/receipt: the file the dashboard downloads, and the one the buyer has. It is null until the order is paid: a receipt proves a purchase, and the address answers 404 for an unpaid order.

Recording a shipment

The one thing about an order a seller decides. Only the number has to be sent:
We recognise the courier from the number (ups, here) and build the link the buyer follows from it. Spaces are taken out of the number and letters made capitals, as it is stored.
string
Leave it out and we recognise it from the number. A number that fits several couriers goes to the one with the lowest detectionPriority; one that fits none we know, or only couriers without a priority, is recognised as none: then you are asked for it with a 422 on courier. One you send is used, whatever the number looks like.
string
The link the buyer’s shipping email and order page send them to. Leave it out for a courier we build the link for (buildsTrackingUrl in GET /v1/couriers); some, like PostNL, need the postcode, which we take from the order’s shipping address. For other, a courier we have no link for, or an address without the postcode the link needs, it is required: a 422 on trackingUrl. One you send is kept as it is.
This is not three fields being filled in: the order moves to in_transit and the buyer is told, exactly as from the dashboard. It needs orders:write, so a token that only pulls orders cannot reach it. Only an order that is paid and not sent yet can be shipped: payment_received, or one you are bringing to us in person that has no tracking yet.

Correcting the tracking

A wrong number can be put right while the parcel is on its way, with the same PATCH:
  • in_transit: the buyer gets an email with the new link — but only when the courier, number or link actually changed. Sending the same details again tells nobody anything.
  • awaiting_delivery with tracking: it is stored, and the buyer is not told, as when it was recorded.
A shipment is described whole each time. What you leave out is worked out again from the number, not kept from before: a corrected number sent alone does not keep the courier and link of the parcel it replaces. Once the order is delivered, completed, cancelled, refunded or returned, the tracking is the record of how it went. Anything other than the statuses above answers 409 with order_not_shippable, and meta.status names the status it is in.

The carriers we know

courier must be one of these, so a name we do not know is refused with 422. GET /v1/couriers answers the same list with the names the dashboard shows, and per courier what the dashboard uses to fill in the rest:
string[]
How its numbers look: regular expressions using only anchors, classes and counts, so they read the same on every platform. Match them against the number without spaces and in capitals, and preselect the courier when exactly one matches. When several match, take the one with the lowest detectionPriority — what we do on the server.
number | null
1 to 5 for the couriers most shops ship with — DHL Express, FedEx, UPS, DHL, PostNL — and null for the rest. A number several patterns fit (twelve digits are FedEx and GLS alike) goes to the lowest; if none of them has one, recognise none.
boolean
Whether we build the link, so trackingUrl may be left out.
string | null
The link we build, to show as a preview: {number}, and where the carrier needs them {country} (ISO 3166 alpha-2) and {postcode} (without spaces) from the order’s shipping address. Leave the link out when you can; we make it.
And other, for a carrier we do not have yet. The order still moves and the buyer is still told.
Read this list from GET /v1/couriers rather than copying it into your code: it is the same list the server validates against, and we add carriers.
The exception is an order the seller is bringing to us in person (awaiting_delivery), where recording a courier does not move it and does not tell the buyer a second time. Every other attribute of an order is the record of what happened, and the body never changes one: anything but courier, trackingNumber and trackingUrl — status, total, payoutAmount, buyerEmail, createdAt and the rest — is refused with 403 read_only_field, one error per field.