Orders
An order has two tracks. status is its progress. payment_status is its money.
The order object
Money is a number. Times are ISO 8601 in UTC. balance is total minus paid. Staff names, internal notes and file paths are never shown.
{
"number": "NT-482913",
"status": "awaiting_payment",
"payment_status": "unpaid",
"payment_method": "bank",
"placed_at": "2026-11-02T08:15:00Z",
"updated_at": "2026-11-02T08:15:00Z",
"currency": "PHP",
"total": 1020,
"due_today": 1020,
"paid": 0,
"balance": 1020,
"freight": 120,
"sale_saving": 0,
"promo_code": null,
"promo_saving": 0,
"contact": { "name": "Maria Santos", "phone": "+639171234567", "email": "maria@example.test", "social": null },
"delivery": { "method": "jnt", "region": "NCR", "city": "Quezon City", "street": "12 Sample St", "landmark": "Blue gate", "courier": null, "tracking_number": null },
"lines": [
{ "product_id": "SKU-ROSE-50", "name": "Rose Mist 50 ml", "qty": 2, "unit_price": 450, "line_total": 900, "preorder": false }
],
"payments": []
}| Field | Meaning |
|---|---|
number | The order number, for example NT-482913. Show it to the shopper. |
status | Progress. See the list below. |
payment_status | Money. See the list below. |
payment_method | One of the shop payment method keys, for example bank. |
total, due_today, paid, balance | Amounts. A layaway or pre-order can have due_today lower than total. |
freight, sale_saving, promo_code, promo_saving | Delivery fee and savings. |
contact | name, phone, email, social. |
delivery | method (pickup or a courier), address parts, courier and tracking_number once shipped. |
lines | product_id, name, qty, unit_price, line_total, preorder. |
payments | Each payment: kind, method, amount, reference, status, reason, created_at. |
Statuses
| status | Meaning |
|---|---|
awaiting_payment | Placed. Waiting for the shopper to pay. |
proof_received | A payment screenshot is waiting for the shop to check. |
confirmed | Accepted. Cash orders start here. |
downpayment_confirmed | A pre-order downpayment was confirmed. Waiting for stock. |
balance_due | Stock arrived. The shopper pays the rest. |
preparing | The shop is packing the order. |
ready_for_pickup | Ready for the shopper to collect. |
shipped | With the courier. delivery.courier and delivery.tracking_number are set. |
completed | Done. |
cancelled | Cancelled. Stock is put back. |
Payment statuses
| payment_status | Meaning |
|---|---|
unpaid | No money yet. |
checking | A screenshot is being checked. |
part_paid | Some money in, a balance is left. |
paid | Paid in full. |
refund_due | A cancelled order held money. A refund is owed. |
refunded | The refund was recorded. |
Ignore any value you do not know. More can be added later.
Cash orders (cash on delivery, cash at the shop) arrive as confirmed with payment_status unpaid. Do not ask the shopper for a screenshot. Tell them they pay on delivery or at pickup.
Place an order
- Read the catalog with
GET /catalog. Price the order from it. - Send the order with
POST /orders. Save thenumberandtokenfrom the reply. - Upload a proof if the payment method is a transfer.
- Show the order to the shopper with
GET /orders/{number}?token=.
Your site prices the order. Xatern One refuses one that does not add up.
| Field | What to send |
|---|---|
idempotency_key | A UUID you make once per checkout. Sending it again returns the first order. |
payment_method | One of the shop payment method keys. |
contact | {name, phone, email, social}. Phone can be local (09171234567) or international (+639171234567). Email and social may be null. |
delivery | {method, region, city, street, landmark}. For pickup, {"method":"pickup"} is enough. |
lines | 1 to 100 lines of {product_id, name, qty, unit_price, line_total, preorder}. line_total is unit_price times qty. Each line must be a visible size at the current price. |
total, due_today, balance | Numbers with at most 2 decimals. balance is total minus due_today. |
freight, promo_code, promo_saving, sale_saving | Optional. total is the sum of line_total, minus promo_saving, plus freight. |
const res = await fetch("https://api.xatern.com/v1/orders", {
method: "POST",
headers: {
Authorization: "Bearer xpk_live_YOUR_PUBLISHABLE_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify(order)
});
const data = await res.json();
if (!data.ok) throw new Error(data.error);
const { number, token } = data.order;The request body can be up to 64 KB. Send it as JSON with Content-Type: application/json.
Upload a payment proof
For a transfer such as GCash or a bank transfer, the shopper sends a screenshot. Send it as multipart form data to POST /orders/{number}/payment-proof with token, reference and file. The file is a JPG, PNG, WebP or HEIC image up to 8 MB. Shrinking it to about 200 KB first makes uploads faster.
const form = new FormData();
form.append("token", token);
form.append("reference", "GC123456789");
form.append("file", fileInput.files[0]);
const res = await fetch("https://api.xatern.com/v1/orders/" + number + "/payment-proof", {
method: "POST",
headers: { Authorization: "Bearer xpk_live_YOUR_PUBLISHABLE_KEY" },
body: form
});
const data = await res.json();
if (!data.ok) throw new Error(data.error);The order moves to proof_received and waits for the shop. Only one payment is checked at a time. If the shop says the payment did not match, the shopper can send a new screenshot the same way.
Xatern One API v1. Example data on these pages is made up.