Orders
Reading orders needs orders:read; generating a label and marking an order shipped
need orders:write.
The slice model
A buyer's checkout can contain listings from several sellers at once, and several listings from you in
the same checkout. Every individual listing sold becomes its own order row (one row per item, per
seller). The rows that share a slice_key are exactly the rows from one checkout
that belong to you: they were created together, and they ship together. GET
/orders lists individual rows; GET /orders/{id}, the label endpoint and
the ship endpoint all operate on the whole slice that the given row id belongs to, not just that
one row.
List orders
GET /ordersQuery parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
status |
string | Optional | pending, shipped, received, cancelled or disputed; see Values. |
since |
string | Optional | ISO date/datetime. Only orders created at or after this point. |
page / per_page |
integer | Optional | See Pagination. |
Each row includes the sold item, tracking, and your financial breakdown for that row
(seller_net, seller_fee, commission,
refunded_amount). Those figures describe the article only. The buyer's shipping
fee is never part of a row: it is reported once per slice, in the slice detail's
shipping block, together with who it is paid to. The buyer's name is included,
but not their shipping address: that only appears on the slice detail below.
Response fields
Returns a paginated list of order rows:
| Field | Type | Description |
|---|---|---|
id |
integer | The order row's id. |
slice_key |
string | Rows sharing this key belong to the same checkout and ship together. |
checkout_id |
integer or null | The checkout the row came from. |
status |
string | Order status, see Values. |
quantity |
integer | Units sold on this row. |
price |
number | Unit price at the moment of the order. |
currency |
string | Always EUR in v1. |
item.name |
string or null | Display name of the sold item, frozen at order time. |
item.subtitle |
string or null | Display subtitle, e.g. the card's set and number. |
item.image |
string or null | Item image URL. |
item.condition |
string or null | Condition code (see Values). Null for sealed products. |
item.language |
string or null | Language code (see Values). |
item.type |
string or null | card or product. Null for legacy orders created before this snapshot existed. |
item.id |
string or null | The catalog id: feed it straight into GET /cards/{id} or GET /products/{slug}. |
item.friendly_id |
string or null | Cards only; null when the set has no shortcut, and for products. |
listing_id |
integer or null | The listing that was sold. Null if it was deleted since. |
tracking.code |
string or null | Tracking barcode. |
tracking.url |
string or null | Track and trace URL. |
tracking.status |
string or null | The carrier's latest tracking status. |
tracking.updated_at |
string or null | When that tracking status last changed. ISO 8601. |
tracking.fulfilment |
string | platform (TCG Plein buys the label) or self_ship (you ship this order yourself via one of your own shipping options; no platform label exists and the ship endpoint requires a tracking code for tracked options). |
financial.seller_net |
number | Your net for this article line: price × quantity minus commission. The buyer's shipping fee is never inside a line; see the slice's shipping block. |
financial.seller_fee |
number | Total fees deducted from this row. |
financial.commission |
number | The commission part of that fee. |
financial.refunded_amount |
number | Amount refunded to the buyer so far. |
buyer.name |
string or null | The buyer's display name. The shipping address only appears on the slice detail. |
created_at |
string or null | ISO 8601. |
shipped_at / received_at / cancelled_at / disputed_at |
string or null | Lifecycle timestamps, ISO 8601. Null until the row reaches that state. |
curl "https://tcgplein.nl/api/v1/orders?status=pending" \
-H "Authorization: Bearer tcgp_live_K7mP2xQ9vZ4nR8wT3yL6bC1jD5sF0gH7uM2oA9iE"
Get an order (slice detail)
GET /orders/{id}
Returns every row in the slice that {id} belongs to, the buyer's full shipping
address, aggregated totals, and the current shipping/label status. {id} can be
any row's id from that slice, not necessarily the first one; the response is identical either way.
Besides the required {id} path parameter (integer) there are no query or body
parameters.
Response fields
| Field | Type | Description |
|---|---|---|
slice_key |
string | The slice's key. |
orders |
array of objects | Every row in the slice, each the same shape as a GET /orders row above. |
buyer.name |
string or null | The buyer's display name. |
buyer.address |
object or null | The delivery address to ship to. |
buyer.address.full_name |
string | Addressee. |
buyer.address.street |
string | Street name. |
buyer.address.house_number |
string | House number. |
buyer.address.house_number_suffix |
string or null | Suffix like A or bis. |
buyer.address.zip |
string | Postal code. |
buyer.address.city |
string | City. |
buyer.address.country |
string | ISO country code, e.g. NL. |
buyer.address.phone |
string or null | Phone number, when the buyer provided one. |
totals.merchandise |
number | Sum of the slice's item prices. |
totals.shipping |
number | What the buyer paid for this slice's shipping. |
totals.seller_net |
number | Your net for the whole slice: the sum of every line's financial.seller_net plus shipping.seller_share. This is the figure that is paid out to you. |
totals.currency |
string | The currency every amount in this block is expressed in, always EUR in v1. All amounts are decimal, never cents. |
shipping.method |
string or null | The shipping method the buyer chose. |
shipping.price |
number | Same value as totals.shipping. |
shipping.paid_to |
string | Who keeps the buyer's shipping fee. seller: you ship this order yourself via one of your own shipping options, and the fee is paid out to you 1:1 as part of totals.seller_net. platform: TCG Plein buys the label and keeps the fee to pay for it; nothing of it reaches your payout. |
shipping.seller_share |
number | The part of totals.seller_net that is the shipping fee: equal to shipping.price when paid_to is seller, otherwise 0. Subtract it from totals.seller_net to get your article earnings for the slice. |
shipping.provider |
string or null | The carrier platform a label was generated with, e.g. myparcel. Null before a label exists. |
shipping.has_label |
boolean | Whether a label was generated for the slice. |
shipping.tracking_code |
string or null | The slice's tracking barcode. |
shipping.tracking_status |
string or null | The carrier's latest tracking status. |
shipping.label_url |
string or null | Signed label download URL, when a label PDF is available. |
shipping.expires_at |
string or null | When that label URL expires. ISO 8601. |
curl "https://tcgplein.nl/api/v1/orders/9012" \
-H "Authorization: Bearer tcgp_live_K7mP2xQ9vZ4nR8wT3yL6bC1jD5sF0gH7uM2oA9iE"
Generate a shipping label
POST /orders/{id}/label
Purchases (or re-reads) a shipping label for the order's slice. Calling it again for the same slice is
safe and does not purchase a second shipment; it re-checks the existing one. Besides the required
{id} path parameter (integer) there are no query or body parameters. The
response's data.status is one of four values:
| Status | Meaning |
|---|---|
| ready | label_url is populated: the PDF is available. |
| processing | The shipment was created but the label file isn't available yet. Retry the call shortly. |
| action_required | The shipment was created with the carrier, but the label couldn't be retrieved, typically because of a MyParcel balance or payment method issue on your account. Nothing about this resolves on its own: fix the account issue in MyParcel, then call this endpoint again. |
| self_ship |
Terminal. This order ships via one of your own shipping options
(tracking.fulfilment is self_ship), so no platform
label will ever exist. Ship it yourself and report the tracking code via
POST /orders/{id}/ship.
|
label_url is a signed download URL, valid for 5 days and requiring no
authentication of its own: anyone with the link can fetch the PDF. A fresh URL (with a fresh 5-day
expiry) is minted on every successful call, so don't assume yesterday's link still matches today's
expires_at.
A successful label generation also fires an order.label_ready webhook; see
Webhooks for why that event can arrive twice for
the same order.
Response fields
| Field | Type | Description |
|---|---|---|
status |
string | ready, processing, action_required or self_ship (see above). |
label_url |
string or null | Signed PDF download URL. Populated only when status is ready. |
expires_at |
string or null | When label_url expires. ISO 8601. |
message |
string or null | Human-readable detail, populated for action_required and some edge cases. |
tracking_code |
string or null | The shipment's tracking barcode. Can lag behind the label if the carrier assigns it asynchronously. |
tracking_url |
string or null | Track and trace URL. |
provider |
string or null | The carrier platform, e.g. myparcel. |
shipped_lines |
integer | Rows in the slice covered by the shipment. |
order |
object | The order's slice detail, the same shape as GET /orders/{id}. |
curl -X POST "https://tcgplein.nl/api/v1/orders/9012/label" \
-H "Authorization: Bearer tcgp_live_K7mP2xQ9vZ4nR8wT3yL6bC1jD5sF0gH7uM2oA9iE"
Mark an order shipped
POST /orders/{id}/ship
Marks every still-pending row in the slice as shipped in one call (not just {id}'s
own row), and notifies the buyer once per shipped row. If nothing in the slice is still pending, this
returns 409 conflict.
Shipping needs a fully verified Stripe payout account: until the account behind the key can receive
payouts, both this endpoint and POST /orders/{id}/label answer
409 conflict with the message Complete and verify your Stripe payout setup
before shipping. Listing never requires it; a sale only ships once the seller can be paid out.
Whether tracking_code is allowed follows the order's
tracking.fulfilment. For self_ship orders on one of your
own tracked shipping options the code is required: it is the buyer's only
delivery evidence. Your letter options carry no tracking, so the field is refused there. For
platform orders the field is also refused (422): the tracking code comes from
the label generated on TCG Plein.
Body
| Parameter | Type | Required | Description |
|---|---|---|---|
tracking_code |
string | Conditional | Max 100 characters, recorded against every row shipped by this call. Required for self_ship orders on a tracked own option; refused (422) for own letter options and for platform-label orders. |
Response fields
Returns the order's updated slice detail under data, plus a
shipped_lines count:
| Field | Type | Description |
|---|---|---|
slice_key |
string | The slice's key. |
orders |
array of objects | Every row in the slice, now with their updated status, each the same shape as a GET /orders row above. |
buyer.name |
string or null | The buyer's display name. |
buyer.address |
object or null | The delivery address. |
buyer.address.full_name |
string | Addressee. |
buyer.address.street |
string | Street name. |
buyer.address.house_number |
string | House number. |
buyer.address.house_number_suffix |
string or null | Suffix like A or bis. |
buyer.address.zip |
string | Postal code. |
buyer.address.city |
string | City. |
buyer.address.country |
string | ISO country code, e.g. NL. |
buyer.address.phone |
string or null | Phone number, when the buyer provided one. |
totals.merchandise |
number | Sum of the slice's item prices. |
totals.shipping |
number | What the buyer paid for this slice's shipping. |
totals.seller_net |
number | Your net for the whole slice: the sum of every line's financial.seller_net plus shipping.seller_share. This is the figure that is paid out to you. |
totals.currency |
string | The currency every amount in this block is expressed in, always EUR in v1. All amounts are decimal, never cents. |
shipping.method |
string or null | The shipping method the buyer chose. |
shipping.price |
number | Same value as totals.shipping. |
shipping.paid_to |
string | Who keeps the buyer's shipping fee. seller: you ship this order yourself via one of your own shipping options, and the fee is paid out to you 1:1 as part of totals.seller_net. platform: TCG Plein buys the label and keeps the fee to pay for it; nothing of it reaches your payout. |
shipping.seller_share |
number | The part of totals.seller_net that is the shipping fee: equal to shipping.price when paid_to is seller, otherwise 0. Subtract it from totals.seller_net to get your article earnings for the slice. |
shipping.provider |
string or null | The carrier platform a label was generated with, e.g. myparcel. Null before a label exists. |
shipping.has_label |
boolean | Whether a label was generated for the slice. |
shipping.tracking_code |
string or null | The slice's tracking barcode. |
shipping.tracking_status |
string or null | The carrier's latest tracking status. |
shipping.label_url |
string or null | Signed label download URL, when a label PDF is available. |
shipping.expires_at |
string or null | When that label URL expires. ISO 8601. |
shipped_lines |
integer | Rows marked shipped by this call. |
curl -X POST "https://tcgplein.nl/api/v1/orders/9012/ship" \
-H "Authorization: Bearer tcgp_live_K7mP2xQ9vZ4nR8wT3yL6bC1jD5sF0gH7uM2oA9iE" \
-H "Content-Type: application/json" \
-d '{"tracking_code": "3SMYPXXXXXXXXXX"}'