Skip to main content
Every monetary field in this API ends in _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.
That is 500,000 Ugandan shillings, not 5,000.

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.
Assuming two decimals everywhere is a 100× error in UGX, RWF, XAF and XOF. This is the single most expensive mistake available in this API. The gateway never defaults an exponent — an unrecognised currency is rejected with unknown_currency rather than guessed.

Converting

money.ts
Do the conversion once, at the boundary where a human-entered string becomes a number, and keep minor units everywhere inside your system. Converting back and forth in the middle of a flow is where rounding creeps in.

Never use floats

Amounts are integers. The gateway’s own money math is string-based and refuses to do floating-point arithmetic on amounts, because 0.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 becoming 123456.
  • 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/corridors rather 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 the amount_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.