Lewati ke konten utama

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​

StageOrder StatusFunds StatusTech
Browse,,Flutter HomeFeed / React
Product Detail,,Flutter ProductDetail
Buy NowAWAITING_PAYMENT,POST /orders via NestJS backend
CheckoutAWAITING_PAYMENT,Xendit Create Invoice + Biteship Get Rates
PayAWAITING_PAYMENT,Buyer completes Xendit invoice
Payment SuccessREADY_TO_SHIPHELDXendit 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​

StageDetail
Order TrackingBiteship Realtime webhooks update shipment.status through picked_up → in_transit → out_for_delivery → delivered
DeliveredOrder transitions to DELIVERED. A 48-hour dispute window opens from deliveredAt.
Confirm ReceiptBuyer taps confirm → order becomes COMPLETED, funds released.
Auto-releaseIf buyer takes no action within 48h, funds auto-release via the in-process @nestjs/schedule EscrowRelease cron.

Escrow track​

StageLedger EntryDetail
Escrow Holdtype: HOLD + type: BPF_COLLECTFunds locked in platform wallet. BPF split goes to platform revenue. fundsStatus = HELD.
Dispute Window,48h window from deliveredAt. No action = auto-release.
Funds Releasedtype: RELEASESeller receives itemPrice + shippingFee. Platform keeps BPF. Triggers type: PAYOUT → bank transfer.
Funds Frozen,On dispute open. fundsStatus = FROZEN. Ops reviews in EscrowOverview.

Seller track​

StageDetail
Seller NotifiedPush notification: "Pesanan baru! Kirim dalam 48 jam". Order appears in OrderManager → READY_TO_SHIP tab.
Ready to ShipOrder status READY_TO_SHIP. 48h ship deadline starts from paidAt. Late-to-ship → LATE_TO_SHIP / funds frozen, buyer eligible for auto-refund.
Print LabelSeller calls Biteship POST /shipments. Returns waybillId, trackingNo, and label PDF. Courier was selected by buyer at checkout.
ShippedOrder 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.

StageOrder StatusFunds StatusSLA
Dispute OpenDISPUTE_OPENFROZENOps review within 24 hours
Funds FrozenDISPUTE_OPENFROZENAdmin acts in EscrowOverview; FraudMonitor surfaces alerts
Resolution: ReleaseCOMPLETEDRELEASEDSeller receives funds
Resolution: RefundREFUNDEDRELEASEDBuyer receives refund; ledger entry type: REFUND

Tech Stack​

LayerTechnology
FrontendFlutter (mobile), React + Vite (web), nginx-served on Dokploy
BackendNestJS 10 + Fastify + Drizzle ORM, external Postgres (Supavisor pooler), Dokploy VPS
PaymentsXendit, invoices, webhooks (invoice.paid)
LogisticsBiteship, waybills, tracking webhooks, label PDF
StorageDigitalOcean Spaces + imgproxy
Scheduling@nestjs/schedule in-process crons (48h auto-release, late-ship check, outbox delivery)

See Also​