_minor. The suffix is part of the
contract, not decoration: it declares that the value is an integer count of
the currency’s smallest unit — never a decimal, never a float.
A field named amount could be read as 20.00 or 2000. A field named
amount_minor can only be read one way.
The exponent is per currency
Four of the currencies AptaPay supports are zero-decimal: they have no minor unit at all. One UGX is one UGX, not 100 cents.Converting
money.ts
Never use floats
Amounts are integers. The gateway’s own money math is string-based and refuses to do floating-point arithmetic on amounts, because0.1 + 0.2 in a
settlement path reconciles to a discrepancy nobody can explain a month later.
Rules the gateway enforces
- More precision than the currency allows is rejected, not silently
rounded. Sending
"1234.567"USD fails rather than becoming123456. - Unknown currencies throw. There is no default exponent.
- Corridor minimums and maximums apply per country, currency and method,
and they fail closed. Query them at
GET /v1/reference/corridorsrather than hardcoding. - Some corridors have a per-method floor — for example Uganda bank payouts have a UGX 10,000 minimum, while mobile money has none.
Fees
Collection fees are charged per provider, and theamount_minor you send
is always the net amount you expect to receive. Depending on the routed
provider, the fee is either appended on top of what the customer pays or
deducted from the gross. You do not need to model this difference — send the
net amount you want, and read the actual figures off the transaction once it
settles.
Payouts reserve the amount plus an estimated fee against your float, and
true up to the real fee when the payout settles. This is why a payout can be
refused with insufficient_tenant_float even when your balance looks like it
exactly covers the amount.