Orders
Every request a buyer submits on your storefront becomes an
order — with a per-workspace number (#1, #2, …), a status, a
payment status, a quote, and a message thread. Work them at
/dashboard/orders.
Two independent state machines live on every order: status (the work) and paymentStatus (the money). A buyer can pay before you start, after you deliver, or never — the two tracks don't gate each other.
The order lifecycle (status)
requested ──► confirmed ──► in_progress ──► delivered ──► completed
│
└──► declined
canceled ◄── from any state that isn't completed/declined/canceled
| Status | Meaning |
|---|---|
requested |
Just arrived — needs your yes/no |
confirmed |
You accepted; work hasn't started |
in_progress |
You're working on it |
delivered |
Work handed over, awaiting the buyer's OK |
completed |
Done. Terminal |
declined |
You said no at the start. Terminal |
canceled |
Called off mid-flight (your action). Terminal |
Only the seller moves status — buyers never drive it. Transitions
are validated: an illegal move (e.g. requested → delivered)
returns 409 INVALID_TRANSITION. The buyer is emailed on every
status change, with their private order link.
The payment track (paymentStatus)
unpaid ──► payment_claimed ──► payment_confirmed
└──────────────────────────────────┘
unpaid— the starting state.payment_claimed— the buyer tapped "I have transferred" on their order page (manual-transfer flow).payment_confirmed— you confirmed the money arrived (or, with the Payment module, an online payment settled). You can confirm directly fromunpaidtoo — cash in hand, transfer spotted before the buyer clicked. Terminal: confirming an already-confirmed payment is a409.
The full payment story — bank details, proof upload, online checkout — is on the Payments page.
Quotes
Every order carries quotedPriceIdr — what the buyer owes:
- Fixed services: the service price.
- Package services: the chosen package's price.
- Hourly services: the hourly rate, as a starting point — set the real total once you've scoped the job.
- A valid discount code is already subtracted at creation.
Adjust the quote any time before the order reaches a terminal state
(PATCH /api/v1/orders/:id with {"quotedPriceIdr": …} — or just
edit it in the portal). Changing the quote of a completed/declined/
canceled order is a 409.
The message thread
Each order is also a conversation:
- Buyer replies come from the buyer's order page
(
/o/<token>). - Your replies notify the buyer by email.
- Internal notes (
isInternal: true) are seller-only — never shown to the buyer, never emailed.
The order list sorts by latest activity, so a fresh buyer message bubbles the order to the top.
The buyer's side
The buyer's only credential is an opaque access token, minted at
order creation and delivered in every email — their order page is
https://serront.com/o/<token>. It shows status, the quote, the
thread, and (while payment is pending) your payment instructions.
Anyone with the link can see the order, so buyers should treat it
like a private link. Repeat buyers can also see all their orders in
the client portal.
API
| Method + path | Does |
|---|---|
GET /api/v1/orders |
List — filters status, paymentStatus, serviceId, free-text q; cursor-paged by latest activity; per-status counts included |
GET /api/v1/orders/:id |
One order + the full thread (incl. internal notes) |
PATCH /api/v1/orders/:id |
Move status and/or set quotedPriceIdr |
POST /api/v1/orders/:id/messages |
Reply ({"body": …}), or internal note ("isInternal": true) |
POST /api/v1/orders/:id/confirm-payment |
unpaid/payment_claimed → payment_confirmed |
GET /api/v1/orders/:id/proof |
The buyer's payment-proof image (binary) |
# Everything that needs your attention
curl -H "Authorization: Bearer sk_live_xxx" \
"https://serront.com/api/v1/orders?status=requested"
# Accept an order
curl -X PATCH https://serront.com/api/v1/orders/ord_01jx… \
-H "Authorization: Bearer sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{"status": "confirmed"}'
# Reply to the buyer
curl -X POST https://serront.com/api/v1/orders/ord_01jx…/messages \
-H "Authorization: Bearer sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{"body": "Confirmed! Starting on Monday.", "authorName": "Adi"}'
Orders are created by buyers on the public surface
(POST /api/v1/public/storefront/:slug/order) — there is no
seller-side create endpoint in v1. Webhook events fire on creation,
replies, status changes, and payment confirmation — see the
event catalog.