The pattern in one call
curl https://orbchain.io/v1/payment/static-address \ -X POST \ -H "merchant_api_key: YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "currency": "USDT_TRC20", "user_id": "player-8841" }'
The response is an address that belongs to player-8841 permanently. Call it again for the same user and coin — same address back, no duplicate. Render it (with its QR) on the user's deposit screen once and never touch payment UX again: no amounts, no expiry countdowns, no "generate new invoice" button. The user sends 20 USDT today and 500 next month to the same address, from an exchange withdrawal or a wallet, and every deposit lands attributed.
Under the hood each address is HD-derived on its own path — user addresses never collide, and a new user costs one API call, not a wallet-ops ticket. Whether users see a fresh address per session or one address for life is a account-level switch (customer-static mode); platforms almost always want one-for-life, because that's what users paste into their exchange's withdrawal whitelist.
The webhook does the crediting
When a deposit reaches its confirmation threshold, you get a signed webhook carrying the coin, the amount, the tx hash, the USD value — and your own user_id. Your handler becomes one line of business logic: credit that user's balance. No matching engine, no memo parsing, no "send exactly 19.99 or we can't find you" instructions that users get wrong.
- Sub-threshold deposits are visible, not lost. Deposits appear with a pending status while confirmations accumulate — show "arriving" in your user's UI, credit on the confirmed event.
- Confirmation thresholds are yours to tune per coin, above platform floors — a site crediting instantly-spendable balance may want more depth on volatile chains than a merchant shipping T-shirts.
- Dedupe like always: webhooks carry deterministic event IDs, so your credit handler is naturally idempotent under retries.
What you never have to build
The reason this pattern usually gets bought instead of built: the address is only the visible tenth of it. Behind each deposit address sits detection across every chain, confirmation tracking, reorg handling, and the unglamorous plumbing of moving funds off thousands of small addresses into a spendable balance — including chains like Tron where the deposit address itself needs energy/bandwidth economics handled before value can move at all. You see a balance and a webhook; the sweep logistics never surface in your integration.
From that single balance, the rest of the platform composes: user withdrawals go out through the payout API (single or batch), volatile deposits can auto-settle into a stablecoin, and the standard 0.4% on deposits is the whole price — no per-address fee, no monthly per-user charge, which matters when "users" means tens of thousands of mostly-dormant addresses.
Invoice or address? The one-question test
Does the payment complete an order, or fund an account? Orders want invoices — amounts, expiry, over/underpayment semantics, a hosted page. Account funding wants static addresses — permanent, amountless, attributed by construction. Most platforms end up using both (invoices for a premium purchase, addresses for wallet top-ups), and they share the same keys, webhooks, and balance underneath. But if you've been forcing top-ups through invoice flows and watching users fumble expired payment windows: this is the pattern you were missing.