Amounts and money

Micro-units, the string field, and why USDT does not have one number of decimals.

Micro-units everywhere

Every amount on this API is an integer in micro-units: six decimal places.

25000000  ==  25.000000 USDT
     100  ==   0.000100 USDT

Integers because money in a float is a bug with a delay on it. Six places because that is USDT's own precision on the chain where it has the fewest.

The string is not decoration

Every amount field comes twice:

{ "amount": 25000000, "amount_decimal": "25.000000" }

amount_decimal exists because JavaScript has no integers in JSON. JSON.parse gives you a double, and 25000000 / 1e6 is not reliably 25. Above 2^53 micro-units — about 9 billion USDT — the integer itself stops being exact.

Rules that will save you:

Sending money works the same way. Send amount or amount_decimal, not both:

{ "amount_decimal": "25.00" }
{ "amount": 25000000 }

USDT decimals differ per chain

Six on Tron. Eighteen on BSC. This is a property of the token contract, not of the chain, and it is the single most common source of a transfer that is off by a factor of a trillion.

You never have to care: the API speaks micro-units on every field. The raw on-chain value is published per route as amount_raw, alongside token_contract, for the wallets that do care.

amount_raw is a string, for exactly the reason above — 25 × 10^18 does not fit in a double, and on BSC every amount is that size.

The exact amount is the identifier

Under the default shared-address strategy, several payments can be waiting on the same address at once. What distinguishes them is the exact amount, adjusted by a few micro-units so that no two open payments on one address ask for the same number.

That has two consequences:

  1. Show the customer the amount from the route, not the amount you asked for. They can differ by micro-units, and the route's value is the one that will match.
  2. A transfer of the wrong amount is not silently applied. It becomes underpaid or overpaid, both of which raise an event, and both of which you decide what to do about.

Rounding

There is none to do. Create payments with the exact figure you are charging; the gateway does not round, and an amount below the configured minimum is refused with amount_too_small rather than rounded up into something the customer did not agree to.