Concepts
Learn the vocabulary first and the endpoint pages become much easier to read. This page only explains what each thing is and why it is designed that way; for fields, see the relevant endpoint page.
Core concepts
| Concept | Field | What it is | Why it matters |
|---|---|---|---|
| Merchant number | merchantNo | Your public identifier on the platform | Used in checkout links and QR entry points. It is a public identifier, not a credential — leaking it at worst reveals your collection name |
| API KEY | apiKey (header X-Pay-Api-Key) | Your server's credential for the Open API | It is also the callback signing key. Leaking it means someone can forge "your order was paid", so keep it server-side and store only a hash |
| Merchant order no | merchantOrderNo | Your own order number | It is the idempotency key. Retries must reuse it, and that is how we guarantee no duplicate orders |
| Platform order no | orderNo | The order number we generate | Also the source of the on-chain identify code. It is public to the buyer too (the checkout page looks up an order by knowing its number) |
| Collection address | payAddress | Where this payment should be sent | Snapshotted at order creation. Changing your address later does not affect existing orders |
| Checkout | cashier | The page the buyer sees | Two entry points: the fixed counter (/pay/cashier/m/{merchantNo}) and the per-order checkout page |
| Open API | /api/pay/open/ | Server-to-server endpoints | The caller is your server; identity comes only from the API KEY, and no identity parameter is accepted in the request |
| Chain | chainId / chainKey | Which blockchain the payment is collected on | chainKey is the short code used in code (e.g. tron, bsc); chainId is the internal number |
| Token | tokenId / tokenSymbol | Which coin on that chain | A chain may carry several tokens; precision is per token and all amount conversion depends on it |
| Decimals | decimals | The token's smallest-unit precision | USDT is commonly 6, but another token may be 18. One digit of difference is a factor of ten |
| Smallest unit | *Minimal | Amount expressed as an integer in the smallest unit | Avoids floating-point error. Callback and query amounts are integer strings in the smallest unit |
| Identify data | identify | The marker that lets us match an on-chain payment to this order | The scanner uses it to separate two identical transfers to the same address. Pass it through untouched |
| Callback | notifyUrl | Where we notify you of the order result | It is "we notify you" — it can fail and be missed, which is why the query API exists |
| Signature | X-Pay-Signature | The proof that a callback is genuine | HMAC-SHA256 with your API KEY as the key and timestamp concatenated with the raw body |
Order states
An order state is a finite state machine, not a continuous measure of "how paid" it is. Compare by name; never use >=.
| Value | Name | Meaning |
|---|---|---|
| 1 | Pending | Order created; the payment is not on-chain yet |
| 2 | Submitted | The transaction is on-chain but confirmations are not enough |
| 3 | Confirmed | Confirmations are met. The only state that triggers a merchant callback |
| 4 | Finished | Callback succeeded; final state |
| 5 | Expired | The validity window passed with no valid payment |
| 6 | Manual | An on-chain payment could not be attributed to exactly one order; a human must decide — the system will not guess |
Do not use numeric comparison to decide "paid"
The values are not ordered by degree of payment: Expired (5) and Manual (6) are numerically greater than Confirmed (3) while meaning something unrelated to being paid. Treat only 3 and 4 as paid.
Order types
| Value | Name | Description |
|---|---|---|
| 1 | Online (SDK) | Created by your server through the Open API, carrying your merchantOrderNo |
| 2 | In-person QR | Created by the buyer entering an amount on the checkout page; the merchant order no is generated for you |
This field decides whether we call the merchant back — only online orders get callbacks. Do not use "is the merchant order number empty" to decide, because both types carry a value.
The Open API trust model
The Open API and the buyer-facing public endpoints are two entirely different trust lines. This is the most common source of confusion:
Open API /api/pay/open/* | Buyer-facing public /api/pay/* | |
|---|---|---|
| Who calls | Your server | Anyone who opens the checkout page (buyers have no account) |
| Where identity comes from | Header X-Pay-Api-Key | "Knowing something" (merchant number, platform order no) |
| Identity in the request | Not accepted; passing one has no way to be read | Merchant id not accepted; the merchant is resolved from the merchant number |
| Response fields | Your full fields (including received amount and your order number) | Field-by-field trimmed public fields |
| Middleware order | Per-IP fallback limit → API KEY auth → per-merchant limit | Per-IP fallback limit (write endpoints add a per-merchant one) |
The first two limits matter for this reason: before authentication there is no merchant identity, so only IP can stop a flood of "scripts hammering the KEY". After authentication we limit per merchant, because one merchant can rotate IPs — and the party that suffers is its own order table.
Deployment shape: merchant side and platform side
The platform keeps platform-level and merchant-level configuration apart:
- Platform side owns chains and tokens, rates and rules, which merchants may use which chains, and the public checkout domain.
- Merchant side owns only its own collection addresses, credentials, orders and reports.
The two run as separate deployments. Merchants see their own business data in the console, never platform configuration; and the platform side has read-only access to merchant collection addresses — changing an address is always the merchant's own action, so that "who swapped the address" has an auditable answer.
A few things that do not exist yet
Not yet available
The following are not part of the MVP. These docs deliberately do not give URLs for them; use the website registration entry point or email us instead:
- Merchant self-service registration and its email verification code — accounts are opened by our team.
- Passwordless access to the merchant console — the console still requires a username and password.
- Anonymous live chat — reach us by email or through the existing channels.