OnLink
Concepts

Money representation

Amounts are decimal strings on the wire and integer minor units internally. Never a floating-point number, in either direction.

Every amount this API accepts or returns is a string. Not a JSON number.

{ "kesAmount": "10000.00", "usdtAmount": "100.000000" }

Never parse an amount into a float

JSON.parse converts a JSON number to an IEEE-754 double before any code of yours runs. By the time you could check it, the rounding has already happened. That is why these fields are strings on the wire: it makes the unsafe operation something you have to choose, rather than something the parser does to you.

The two units

Internally, and in any field named Minor or Micro, money is an integer count of the smallest unit. There are exactly two:

CurrencyUnitFactor1 unit is
KEScents (minor)100KES 0.01
USDTmicro1,000,0000.000001 USDT

USDT's factor is 1e6 because Tron USDT has six decimal places. It is not 1e18 — that is a different chain's convention and using it would misstate every amount by twelve orders of magnitude.

So:

  • KES 10,000.00 is 1000000 minor units.
  • 100.000000 USDT is 100000000 micro units.

Decimal places are enforced, not rounded

The API validates the shape of the string and refuses anything it cannot represent exactly. It does not round for you.

FieldMaximum decimal placesRejected examples
kesAmount210.001, 1e4, +10, 10,000, 0x64, ""
usdtAmount61.0000001, 1e2, -1, 1 with a trailing space

The patterns are deliberately strict — no sign, no exponent, no separators, no whitespace. That strictness is load-bearing rather than fussy: BigInt('0x64') is 100 and BigInt('') is 0n, so a permissive parser silently produces an amount nobody typed.

A value with too many decimal places is a 400. Round it yourself, in the direction your own accounting requires, before you send it.

Working with amounts correctly

Read the string. Do not coerce it.

// Wrong — the rounding already happened.
const kes = Number(order.kesAmount) * 100;

// Right — exact, and it throws rather than silently truncating.
const kesMinor = BigInt(order.kesAmount.replace('.', '').padEnd(/* … */));

In practice, use a decimal library (decimal.js, big.js) or your language's native decimal type, and convert to an integer minor-unit count once at the boundary.

Do arithmetic in minor units, as integers.

Add, subtract and compare integers. BigInt in JavaScript, int64/bigint elsewhere. A KES total assembled from cents is exact; one assembled from doubles is approximately exact, which in a ledger means wrong.

Convert back to a decimal string only to display or to send.

Format from the integer, with a fixed number of decimal places — 2 for KES, 6 for USDT. Format once, at the very last step, so no rounded value ever feeds another calculation.

Compare exchange rates as decimals, never as floats.

rate is also a string. Two rates that differ in the last place are different rates, and a float comparison will sometimes tell you they are the same.

Amount limits

Your account carries a per-order cap and a rolling 24-hour cap, both denominated in KES minor units. The daily cap is rolling rather than calendar-based: it does not reset at midnight, precisely so that an order cannot be doubled by splitting it across the boundary.

Exceeding either returns 422 with ORDER_EXCEEDS_PER_ORDER_CAP or ORDER_EXCEEDS_DAILY_CAP. Your specific caps are set on your account — we do not publish a default here, because the number that matters is yours and is more honest than a figure that is not.

Summary

  • Amounts are strings on the wire, in both directions.
  • KES has 2 decimal places, USDT has 6. Over-precision is a 400, not a rounding.
  • Convert to integer minor units at your boundary, do all arithmetic there, and format back to a string only to display or send.
  • Never let an amount pass through a floating-point number at any point.

On this page