On this page
Key takeaways
- Most integration pain comes from assumptions: decimals, networks, and finality are not the same everywhere.
- Design for the payer's mistakes — wrong network, wrong amount, late payment — before launch.
- Test on public test networks and simulate failures; do not learn on real funds.
- Keep a short list of implemented, tested networks and tokens, and resist adding more.
Integrating stablecoin payments is mostly ordinary software engineering with a few unusual failure modes. The unusual ones account for a disproportionate share of support tickets and weekend incidents. These tips come from patterns we see repeatedly. They are engineering observations, not financial or legal advice.
Amounts and tokens
Get the arithmetic and identity of the token right, or nothing downstream can be trusted.
1. Read decimals per token, per network
The same stablecoin can use six decimals on one network and eighteen on another, and the standard treats decimals as optional metadata [1]. Never hard-code it; read it and store it.
type TokenAmount = { units: bigint; decimals: number; tokenId: string };
function parseAmount(display: string, decimals: number): bigint {
const [whole, frac = ""] = display.split(".");
if (frac.length > decimals) throw new Error("too many decimal places");
return BigInt(whole + frac.padEnd(decimals, "0"));
}2. Use integers end to end
Store integer minor units; use BigInt in code. Floating point cannot represent most decimal amounts exactly [5].
3. Identify tokens by contract address, not by symbol
Symbols are not unique. Two different tokens can share a ticker. Always key on the network plus contract address.
4. Beware of look-alike tokens
Anyone can deploy a token with a familiar name. Only credit payments in tokens you have explicitly allow-listed.
5. Display precision is a UI concern
Show the payer a sensible number of decimals, but keep full precision in storage and matching.
Networks and addresses
Where the payer sends value is the most common source of support cases.
6. Show the network prominently at checkout
Wrong-network payments are the most common payer mistake. Put the network name next to the address and again in the instructions.
7. Prefer a unique address per payment
It makes matching unambiguous and removes reliance on the payer entering a reference correctly.
8. Support one network first
Each network adds RPC providers, confirmation policy, monitoring, and runbook entries. Add networks deliberately, each tested.
9. Show a copy button and a QR code, and validate the address format
Manual retyping causes errors. Also validate checksummed address formats where the network defines them.
10. Never reuse or reassign an address for a different customer
Reuse makes matching ambiguous and creates privacy and accounting problems.
Confirmations and time
When a payment counts as paid is a business decision.
11. Do not fulfil on first sight
A transaction visible in a block can still be replaced on some networks. Wait for your policy's finality point [4][3].
12. Use the network's finality signal where it exists
Some networks expose explicit tags for safer or finalised blocks [2]. Prefer them to hand-counted depth when your policy allows.
13. Tier confirmations by amount
A small purchase and a large settlement do not carry the same risk. Set thresholds per tier and per network.
14. Show progress to the payer
A payment that is seen but not yet confirmed should look like progress, not silence, or you will get duplicate payments and tickets.
15. Handle reorganisations
Store block hashes, not just numbers, and allow a payment to step back until final.
Payer behaviour
Design for what people actually do.
16. Plan for underpayment and overpayment
Decide tolerances, and decide who resolves the difference. Do not leave it to whoever sees the ticket first.
17. Handle payment after expiry
A payer may send value after the window closes. Hold it, contact them, and decide honour or refund — do not auto-fulfil an expired order.
18. Avoid the word 'instant'
Even fast networks need confirmations under your policy. Overpromising creates disputes.
Testing and operations
Learn on test networks, not with real funds.
19. Use public test networks with test tokens
Exercise every state, including failures, before any real value moves.
20. Simulate the ugly cases deliberately
Send the wrong amount, pay late, pay on an expired link, and block your provider.
21. Run two RPC providers
One provider is a single point of failure and a single point of error. Compare heads and alert on divergence.
22. Keep a short, honest support list
Publish which networks and tokens you support and which you do not. Anything else is a ticket waiting to happen.
Before you go live
- Decimals read per token and network; amounts stored as integers.
- Tokens identified by contract address and allow-listed.
- Network shown clearly at checkout.
- Confirmation policy written and tiered.
- Underpayment, overpayment, and late payment procedures defined.
- Tested on a public test network, including failures.
- Two RPC providers configured and monitored.
References & further reading
- 1EIP-20: Token Standard — Fabian Vogelsteller, Vitalik Buterin, Ethereum Improvement Proposals
- 2JSON-RPC API — ethereum.org developer documentation
- 3Proof-of-stake and finality (Gasper) — ethereum.org developer documentation
- 4Bitcoin: A Peer-to-Peer Electronic Cash System — Satoshi Nakamoto, 2008
- 5Money — Martin Fowler, Patterns of Enterprise Application Architecture
The product behind this post
StablePay
Self-hosted stablecoin payment infrastructure.
From $4,800 one-time license
About the authors
Layla Haddad
Principal Engineer, Payments Infrastructure
Designs the gateway architecture behind StablePay: state machines, indexing, and signing boundaries.
Mohamed Saad
Smart Contract Developer
Works on the on-chain side of payments: token transfers, event interfaces, and contract review for products that touch a chain.
Product behaviour described here reflects what is implemented and tested; anything else is marked as planned. Code samples are illustrative.
All writing