E-Commerce Transaction Flow
This page documents the full transaction lifecycle on the Pasarseken marketplace, from a buyer browsing to funds landing in the seller's wallet. It mirrors the interactive flow map visible in the Ops Dashboard at /ops/prototype.
Overview​
The Pasarseken e-commerce flow is built on three parallel tracks that run from the moment a buyer pays:
- Buyer track: order status, tracking, receipt confirmation, dispute window
- Escrow track: fund hold, BPF split, release or freeze
- Seller track: notification, label print, shipment, 48-hour ship deadline
Stage Reference​
Main Purchase Flow​
| Stage | Order Status | Funds Status | Tech |
|---|---|---|---|
| Browse | , | , | Flutter HomeFeed / React |
| Product Detail | , | , | Flutter ProductDetail |
| Buy Now | AWAITING_PAYMENT | , | POST /orders via NestJS backend |
| Checkout | AWAITING_PAYMENT | , | Xendit Create Invoice + Biteship Get Rates |
| Pay | AWAITING_PAYMENT | , | Buyer completes Xendit invoice |
| Payment Success | READY_TO_SHIP | HELD | Xendit webhook invoice.paid → NestJS webhook controller |
BPF formula: round(itemPrice × 5%) + Rp 3.000
Invoice expiry: 12 hours. Unpaid invoices cancel the order automatically.
Supported payments: QRIS, ShopeePay, GoPay, DANA, Virtual Account.
Buyer-Seller-Escrow Handshake (post-payment)​
After invoice.paid is received, three parallel tracks activate simultaneously.
Buyer track​
| Stage | Detail |
|---|---|
| Order Tracking | Biteship Realtime webhooks update shipment.status through picked_up → in_transit → out_for_delivery → delivered |
| Delivered | Order transitions to DELIVERED. A 48-hour dispute window opens from deliveredAt. |
| Confirm Receipt | Buyer taps confirm → order becomes COMPLETED, funds released. |
| Auto-release | If buyer takes no action within 48h, funds auto-release via the in-process @nestjs/schedule EscrowRelease cron. |
Escrow track​
| Stage | Ledger Entry | Detail |
|---|---|---|
| Escrow Hold | type: HOLD + type: BPF_COLLECT | Funds locked in platform wallet. BPF split goes to platform revenue. fundsStatus = HELD. |
| Dispute Window | , | 48h window from deliveredAt. No action = auto-release. |
| Funds Released | type: RELEASE | Seller receives itemPrice + shippingFee. Platform keeps BPF. Triggers type: PAYOUT → bank transfer. |
| Funds Frozen | , | On dispute open. fundsStatus = FROZEN. Ops reviews in EscrowOverview. |
Seller track​
| Stage | Detail |
|---|---|
| Seller Notified | Push notification: "Pesanan baru! Kirim dalam 48 jam". Order appears in OrderManager → READY_TO_SHIP tab. |
| Ready to Ship | Order status READY_TO_SHIP. 48h ship deadline starts from paidAt. Late-to-ship → LATE_TO_SHIP / funds frozen, buyer eligible for auto-refund. |
| Print Label | Seller calls Biteship POST /shipments. Returns waybillId, trackingNo, and label PDF. Courier was selected by buyer at checkout. |
| Shipped | Order transitions to SHIPPED. fundsStatus stays HELD. Biteship webhook tracking.updated fires. |
Dispute Path​
Triggered when the buyer opens a dispute during the 48-hour window after delivery.
| Stage | Order Status | Funds Status | SLA |
|---|---|---|---|
| Dispute Open | DISPUTE_OPEN | FROZEN | Ops review within 24 hours |
| Funds Frozen | DISPUTE_OPEN | FROZEN | Admin acts in EscrowOverview; FraudMonitor surfaces alerts |
| Resolution: Release | COMPLETED | RELEASED | Seller receives funds |
| Resolution: Refund | REFUNDED | RELEASED | Buyer receives refund; ledger entry type: REFUND |
Tech Stack​
| Layer | Technology |
|---|---|
| Frontend | Flutter (mobile), React + Vite (web), nginx-served on Dokploy |
| Backend | NestJS 10 + Fastify + Drizzle ORM, external Postgres (Supavisor pooler), Dokploy VPS |
| Payments | Xendit, invoices, webhooks (invoice.paid) |
| Logistics | Biteship, waybills, tracking webhooks, label PDF |
| Storage | DigitalOcean Spaces + imgproxy |
| Scheduling | @nestjs/schedule in-process crons (48h auto-release, late-ship check, outbox delivery) |
See Also​
- Checkout Flow: deep-dive into the Xendit + Biteship checkout sequence
- Cuan Bidirectional Comms: how the finance hub (Cuan) receives fund-release signals from the main platform