Order Management
The lifecycle
pending → process → matched → settled
│ │ │
│ └───────────┴──→ failed (SASOM operations only)
│
└──→ cancelled (you, while still pending)
Pre-orders insert a leg: pending → pre_order → process → matched → settled.
| Status | Meaning | Your action |
|---|---|---|
pending | Listed, not sold | Reprice or cancel |
pre_order | Pre-order sold, awaiting your commitment | PUT /partner/confirm/preorder |
process | Sold, awaiting your confirmation | PUT /partner/confirm/order |
matched | Confirmed — ship it | Set tracking, get label, confirm shipping |
settled | Complete, payout due | Nothing |
failed | Cancelled or refunded by SASOM | Nothing |
cancelled | You cancelled it while pending | Nothing |
Once an order reaches process you cannot cancel or refund it through the API.
PUT /partner/reject/order does not exist — it returns 404. If you cannot
fulfil an order, contact your SASOM account manager; cancellation and refund are
handled by operations.
There are no webhooks
Order state is discovered by polling. There is no callback, no push notification, and no event stream.
curl -sS https://partners.sasomapi.com/partner/processing/orders \
-u "$SASOM_API_KEY:$SASOM_API_SECRET"
{
"type": "processing",
"orders": [
{
"order_id": "kR3mQp7xY2nB8vLc4dFg",
"sku": "FZ5246-100",
"size": "10",
"size_option": null,
"price": 5500,
"status": "process",
"type": "ask",
"category": "sneakers",
"asker": "...",
"asker_email": "...",
"product": {
"name": "Air Jordan 1 Retro High OG",
"brand": "Nike",
"gender_size": "men",
"size_type": "US"
},
"process_timestamp": "2026-09-08T04:11:23.000Z",
"operation": { "authenticated": "pending" }
}
],
"nextCursor": null
}
This returns orders in pre_order, process and matched — so it is your
whole open work queue, not just new sales. Page size 100; follow nextCursor until
it is null.
The response carries Cache-Control: max-age=60. Poll on that cadence — once a
minute is the design point. Polling faster does not surface orders sooner and burns
your 200 requests/minute.
type: "r2s" in an order means the listing was pre-verified and ships from the
SASOM warehouse; you have nothing to ship for it.
Confirming an order
An order in process (or pre_order) is waiting for you:
curl -sS -X PUT https://partners.sasomapi.com/partner/confirm/order \
-u "$SASOM_API_KEY:$SASOM_API_SECRET" \
-H 'Content-Type: application/json' \
-d '{"order_id": "kR3mQp7xY2nB8vLc4dFg"}'
{ "message": "success - order been confirmed" }
Confirming records a shipping-leg fee and, on seller-shipping arrangements,
deducts it from your expected payout. The status transition it starts is
asynchronous, and there is no idempotency key — a retry sent before the order
leaves process passes the status check again and deducts the fee a second
time.
On a timeout or an ambiguous failure: re-read the order with
GET /partner/{order_id} and resend only if the status has not moved off
process.
Refusals:
{ "statusCode": 400, "message": "status not allowed status: matched" }
Already confirmed — this is the response to a duplicate confirm that arrived after the transition landed. Treat it as success, not as an error to retry.
{ "statusCode": 400, "message": "uid not match" }
That order belongs to another supplier. Note it is 400, not 403 or 404.
Pre-orders confirm in two legs
curl -sS -X PUT https://partners.sasomapi.com/partner/confirm/preorder \
-u "$SASOM_API_KEY:$SASOM_API_SECRET" \
-H 'Content-Type: application/json' \
-d '{"order_id": "kR3mQp7xY2nB8vLc4dFg"}'
{
"message": "success: preorder first leg confirmed please confirm shipping when item leaves warehouse"
}
Requires status pre_order. This is your commitment to source the item; you still
confirm shipping later.
Checking your payout
curl -sS https://partners.sasomapi.com/partner/payout/kR3mQp7xY2nB8vLc4dFg \
-u "$SASOM_API_KEY:$SASOM_API_SECRET"
{ "order_id": "kR3mQp7xY2nB8vLc4dFg", "expected_payout": 5325 }
Read this after confirming — the shipping-leg fee is deducted at confirmation, so the value before and after differs. It is a THB amount.
Setting tracking
curl -sS -X PUT https://partners.sasomapi.com/partner/update/tracking \
-u "$SASOM_API_KEY:$SASOM_API_SECRET" \
-H 'Content-Type: application/json' \
-d '{
"order_ids": ["kR3mQp7xY2nB8vLc4dFg", "8pWx2vNm4kQr7yTz1bCd"],
"tracking_code": "TH12345678"
}'
{ "status": "success" }
The field names are order_ids (an array) and tracking_code. There is no
order_id, tracking_number, logistics_provider or carrier field.
Several orders can share a tracking code — that is how you declare a consolidated shipment.
200 here does not mean every order was updated- Order IDs that do not exist are skipped silently and the call still returns
200. - If an ID belongs to another supplier, the call stops there with an
Unauthorizedbody — and the orders earlier in the array are already written. There is no rollback, so the call is partially applied.
Send only your own order IDs, keep arrays small, and reconcile against
GET /partner/processing/orders afterwards rather than trusting the 200.
Also: use each tracking code once, as issued by your carrier. Reusing a code that another shipment already used appends your orders to that existing consolidated shipment record.
Getting the shipping label
curl -sS https://partners.sasomapi.com/partner/label/kR3mQp7xY2nB8vLc4dFg \
-u "$SASOM_API_KEY:$SASOM_API_SECRET"
{
"status": "success",
"url": "https://sasom-label-bucket-prod.s3.ap-southeast-1.amazonaws.com/..."
}
The order must be matched, and the correct tracking code must already be set —
otherwise you get {"statusCode":400,"message":"Invalid Tracking code"}.
Which label you get is decided automatically:
- Warehouse has not received the item → ship-in label (you → SASOM warehouse)
- Warehouse has received it and shipping is confirmed → ship-out label (SASOM → buyer)
The PDF contains the buyer's full name, address and phone number, and the presigned URL grants access to it to anyone holding the link for up to 1 hour.
- Do not log the URL, paste it into a ticket, or send it to a third party.
- Download the PDF immediately, use it for the shipment, and do not retain buyer personal data beyond what your fulfilment and legal obligations require.
- Do not persist the URL — request a fresh one instead. Each call regenerates it.
Confirming shipping
curl -sS -X PUT https://partners.sasomapi.com/partner/update/shipping \
-u "$SASOM_API_KEY:$SASOM_API_SECRET" \
-H 'Content-Type: application/json' \
-d '{"order_id": "kR3mQp7xY2nB8vLc4dFg"}'
{ "message": "success: shipping confirmed" }
Requires status matched.
Reading a single order and settled history
# One order — max-age=30
curl -sS https://partners.sasomapi.com/partner/kR3mQp7xY2nB8vLc4dFg \
-u "$SASOM_API_KEY:$SASOM_API_SECRET"
# Settled orders, paginated — max-age=600
curl -sS https://partners.sasomapi.com/partner/settled/orders \
-u "$SASOM_API_KEY:$SASOM_API_SECRET"
Settled history is the endpoint to reconcile payouts against. It caches for 10 minutes — pull it on a schedule, not on demand.
A reconciliation loop
// Poll once a minute — matching the max-age=60 on the endpoint.
// Confirmation is deliberately serial and never blind-retried: a retry that
// lands before the async transition can deduct the shipping fee twice.
async function processOpenOrders() {
const orders = await fetchProcessingOrders();
for (const order of orders) {
if (order.status !== 'process' && order.status !== 'pre_order') continue;
try {
const path =
order.status === 'pre_order'
? '/partner/confirm/preorder'
: '/partner/confirm/order';
await sasomRequest('PUT', path, { order_id: order.order_id });
await markConfirmedLocally(order.order_id);
} catch (error) {
// "status not allowed" means the transition already happened — this
// order is confirmed, not failed. Anything else needs a human.
if (error.status === 400 && /status not allowed/.test(error.message)) {
await markConfirmedLocally(order.order_id);
continue;
}
await alert(`Confirm failed for ${order.order_id}: ${error.message}`);
}
}
}
Practices worth following
- Poll once a minute. That is what the cache header is set for.
- Confirm once, never blind-retry. Re-read the order first; treat "status not allowed" as already-confirmed.
- Send only your own order IDs to
update/tracking. A foreign ID partially applies the batch. - Handle the label URL as personal data. Do not log it, do not store it.
- Reconcile against
settled/orders. Do not assume a200means your local state and SASOM's agree. - Escalate, don't work around. There is no partner path to cancel or refund a sold order. If you cannot fulfil, contact your account manager rather than letting the order sit.