Skip to main content
Every Droplinked order moves through four phases: init, payment intent, distribution calculation, and confirmation. Phases 1–3 are synchronous request/response; phase 4 is driven by a payment-provider webhook.

High-level sequence

1. Initialize order

  • Endpoint: POST /v2/orders
  • Input: cartId (UUID)
The API snapshots the current cart state (items, shipping, totals), creates a generic Order record in PENDING status, and locks the cart to prevent further changes. Returns: orderId

2. Create payment intent

  • Endpoint: POST /v2/orders/:orderId/payment-intent
  • Input: orderId, paymentMethod (e.g. STRIPE, PAYPAL, CRYPTO, BONUM, TELR)
The API validates the order is pending, runs the distribution calculation (step 3), then contacts the payment provider to create a payment intent. Distribution metadata (splits + orderId) is attached to the provider’s intent so reconciliation can happen later. Returns: clientSecret (Stripe) or checkoutUrl (PayPal, hosted PSPs).

3. Calculate distribution (internal)

Runs synchronously inside step 2. Computes:
  • Droplinked commission — platform fee
  • Provider fees — pass-through PSP charges
  • Merchant share — what settles to the merchant
  • Affiliate / referral splits — when an attribution session is active
This determines exactly how funds will be split before the payment is initialized.
For PSPs that settle off-platform (e.g. Bonum), the saga records the split plan without executing a live transfer — settlement happens out-of-band and is reconciled later.

4. Confirmation (webhook-driven)

  • Trigger: a signed webhook from the payment provider — for Stripe, payment_intent.succeeded.
  • Ingress: the provider’s own mount (for example POST /stripe/acp/webhook), or the normalised POST /payment/webhook/generic for events relayed by Integration Services. The full list is on Webhooks.
There is no client-callable confirm endpoint. Confirmation is not something an integrator triggers — it is what the platform does when a provider’s signed webhook says the money moved. Earlier revisions of this page named a POST /v2/orders/:orderId/confirm-payment route; that route is not mounted and returns 404. Treat the webhook as the only source of truth for “paid”.
PayPal is the one exception worth knowing: because the approval return happens in the buyer’s browser, the checkout front end calls POST /v2/orders/:orderId/capture-paypal on return to capture and confirm. That route is recovery-safe — an already-captured order confirms cleanly, and an already-confirmed order is a no-op. The handler verifies the signature, then executes the confirmation saga:
1

Validate

Checks order status; rejects if already terminal.
2

Process products

Routes each line item to the right fulfillment path — POD via Printful, physical via EasyPost, and digital items get their delivery handled inline.
3

Distribute revenue

Executes the splits calculated in step 3 (or records them for off-platform settlement).
4

Finalize

Updates order status to CONFIRMED.

Retry and replay safety

Two mechanisms, and it is worth knowing which one is load-bearing:
  • Forward-only order state — the durable guarantee. A stale AUTHORIZED event arriving after CAPTURED is dropped rather than rewinding the order, and re-applying a terminal transition is a no-op.
  • Event-id dedupe — a per-provider cache keyed on the provider’s event id with a 24-hour window. It absorbs a retry that lands on the same application instance. It is in-process: it does not span instances and does not survive a restart, so treat it as an optimisation rather than a guarantee.
Re-delivering a webhook is therefore safe. Re-calling POST /v2/orders is not — that creates a second order. See Idempotency and retries for the per-endpoint table, and note that Droplinked does not read an Idempotency-Key request header. For the full webhook + replay matrix, see Checkout stability.