Skip to main content

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 after POST /dapp/orders, every status is PENDING:
Your UI: Show “Order received — awaiting review by Dr Green.” Include the 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 in paymentMethod 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)

Note data.orderDetails (not data directly) — order detail wraps in an extra orderDetails field, 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).

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

  1. Generate a correlation ID client-side at checkout, store it in your DB before the API call:
  2. POST the order:
  3. For any retry, first check Dr Green’s side:
This is verbose but safe. If you find yourself implementing this, please also raise the gap with Dr Green — Idempotency-Key support is a reasonable backend ask.

Pricing and currency

The order detail returns prices in two currencies:
  • totalAmount (USD) — accounting / reporting figure
  • localPrice.totalAmount (customer’s local currency) — what the customer was charged
For customer-facing UI: always use 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