Order Lifecycle Guide
Audience: Engineers building order flows in a Dr Green-backed store. TL;DR: Orders pass through five conceptual stages — placed, admin-reviewed, paid, dispatched, delivered. Each stage updates one of three independent status fields. Polling is your only signal for transitions.
The three status fields
Every order has three independent statuses. They evolve in parallel, not strictly sequentially.
Critical: these three are independent. An order can be
adminApproval=VERIFIED while paymentStatus=PENDING (admin pre-approves, customer hasn’t paid yet) and vice versa. Always check all three before considering an order “complete.”
🔒 The complete enum lists above are partly inferred. Verified live values: orderStatus=PENDING|DELIVERED, adminApproval=PENDING|VERIFIED|REJECTED, paymentStatus=PENDING. Other values are likely supported but not yet seen in production data — defensively render unknown values as the raw string.
The lifecycle visualised
Reading the order through this lifecycle
Stage 1 — placed
Right afterPOST /dapp/orders, every status is PENDING:
invoiceNumber as the customer-facing reference (Dr Green generates it; don’t make your own).
Stage 2 — admin review
A Dr Green admin reviews each order before it can proceed. This is a manual step and can take hours to days, especially during business off-hours. After review,adminApproval flips:
🔒 Reason for rejection — whether Dr Green surfaces a reason in the order detail isn’t formally documented. Defensively render: if you find a rejectionReason field, surface it; otherwise, “Your order could not be approved at this time.”
Stage 3 — payment
Payment is collected via the processor specified inpaymentMethod at order time:
CRYPTO→ CoinRemitter (BTC, ETH, USDT, etc.)FIAT→ Payinn (card / bank transfer depending on country)PGPAY→ PGPay (alternate fiat in supported regions)
🔒 Customer-facing payment UX — whether Dr Green provides a hosted checkout, sends a payment link via email, or relies on your store to render a checkout isn’t formally documented from the API surface. Confirm with Dr Green which model applies. The most common pattern is “Dr Green emails a payment link to the customer” — but verify before building.When payment completes (the processor’s webhook fires to Dr Green),
paymentStatus flips:
Stage 4 — dispatch
When the order ships,orderStatus flips to SHIPPED. Dr Green handles the dispatch from their distribution partner (e.g. Takoda1 in the UK).
🔒 Tracking number visibility — whether the order detail exposes a courier tracking number or transactions[] array entries are not yet captured live. The order detail does include a transactions array which is empty in observed data; this may populate with shipping info, payment info, or both.
Stage 5 — delivered
orderStatus = DELIVERED is the terminal happy-path state. At this point, the holder’s commission for this order accrues — visible via /dapp/commissions.
How to detect transitions in your store
There are no outbound webhooks, so polling is your signal. The pattern:Per-order polling (active orders)
Notedata.orderDetails(notdatadirectly) — order detail wraps in an extraorderDetailsfield, unlike most other endpoints.
Bulk polling (all active orders across customers)
For at-scale stores, use/dapp/orders/recent as a heartbeat:
recent returns the most recent ~10 orders without pagination — ideal for catching changes across customers cheaply.
For older orders (>1 day old, not in recent anymore), poll them individually but at lower frequency (e.g. every 30 min until terminal).
Recommended polling cadence
Customer notifications by transition
Suggested template for what to email/notify the customer at each transition:
Important: these are emails YOUR store sends, separate from any transactional emails Dr Green sends (KYC instructions, payment links). You own the customer relationship; Dr Green handles the parts that require their direct involvement.
Idempotency and retry semantics
POST /dapp/orders is not idempotent. There’s no Idempotency-Key header support. Naive retries produce duplicate orders.
The pattern that works
-
Generate a correlation ID client-side at checkout, store it in your DB before the API call:
-
POST the order:
-
For any retry, first check Dr Green’s side:
Idempotency-Key support is a reasonable backend ask.
Pricing and currency
The order detail returns prices in two currencies:totalAmount(USD) — accounting / reporting figurelocalPrice.totalAmount(customer’s local currency) — what the customer was charged
localPrice.currency + localPrice.totalAmount.
For internal reporting / accounting: use totalAmount (USD).
The exchange rate is captured at order time and frozen for that order — even if FX moves, the customer is charged the locked-in localPrice.totalAmount.
Anti-patterns to avoid
Where to next
- reference/orders.md — full endpoint detail
- reference/commissions.md — what happens after
DELIVERED - 04-errors.md § Idempotency — the no-
Idempotency-Keyworkaround - 06-webhooks.md § The polling pattern — battle-tested polling at scale