How amounts are written
Amounts are decimal strings, never numbers. JSON has no safe big integers and a float loses precision on an 18-decimal asset, so a figure that leaves your code as a number can arrive as a different figure.
Two things follow:
- Keep what you receive as a string. Precision follows the asset, so an 18-decimal figure comes back as an 18-decimal string. Convert to a number only for display, and only after you have stored the string.
- Check the unit before you compare. A token amount and a fiat amount for the same transfer are in different units. The quote states both sides; do not derive one from the other.
Which side of a quote is fixed
A quote pins down one side of the trade and lets the other flex:- Fix what the payer spends (
exact-inon a deposit quote; the source amount on a payout quote). Whatever arrives, arrives. The default. - Fix what has to land (
target-outon a deposit quote; the destination amount on a payout quote). We solve backwards for what the payer sends. This is the mode for a set price - an invoice, a checkout total.
deliveredAmount, never the amount that was charged.
Fees sit inside the quoted figures, never on top - the structure is on
Fees.
Where to look up currencies and limits
Coverage moves faster than any page, so read it at runtime. Which lookup depends on the rail:
The human-readable version of all of it is on Coverage. Validate an
amount against the limit before quoting - an amount outside the window fails at
execution, which is a worse experience than a disabled button.
A rail’s limit is not a user’s limit. A buyer’s own ceiling can be lower than the
card rail’s, depending on their verification tier, so a payment inside the published
window can still be declined for that buyer.