Merchant API
References

Currency

Minor units, decimal strings (never numbers), ISO 4217, and a few token symbols.

Money is a string. Currency is a code. The platform never accepts a JSON number for a money value, and it never returns one.

Amounts are minor-unit decimal strings

amount is the number of minor units encoded as a positive integer string. Pass "10000" for MYR 100.00, not 10000 and not 100.00.

Why a string:

  • JavaScript's Number.MAX_SAFE_INTEGER is 2^53 - 1. A merchant with high-value flows or a low-precision currency exceeds it.
  • A string crossing the JSON boundary is unambiguous. There is no implicit decimal coercion, no floating-point round trip.
  • The platform parses to bigint server-side. Your client should treat the wire value the same way.

The accepted shape:

^[1-9]\d*$

Rejected: "0", "-1", "01", "100.00", "1e3", the number 100.

Examples

CurrencyMinor unitamountRenders as
MYRsen (1/100)"10000"MYR 100.00
USDcent (1/100)"5000"USD 50.00
JPYyen (whole)"500"JPY 500
USDTwei-style (1e-6)"1000000"USDT 1.00

If you do not know the minor exponent for a currency, look it up before you POST. The platform stores and reports the value you sent.

Currency codes

currency matches ^[A-Z]{3,6}$. ISO 4217 codes (MYR, USD, JPY) are three letters. Token symbols (USDT, USDC) are typically four. The widened upper bound covers token symbols up to six characters.

Rules:

  • The code must be in the merchant's effective currency allowlist. A currency that is not enabled returns 400 invalid_currency.
  • The code is case-sensitive on the wire — always uppercase.

Country codes

country is ISO 3166-1 alpha-2: MY, SG, TH, JP, US. Two uppercase letters, no exceptions.

A country that is not in the merchant's country allowlist returns 400 invalid_country.

Reading values back

Response bodies return amount as a string for the same reason: precision and unambiguity. Parse to BigInt if you need to do arithmetic; format with the currency-aware code your stack already has.

import { format } from "@my-app/money";

const display = format(BigInt(intent.amount), intent.currency);

Never do this:

const wrong = Number(intent.amount) / 100;

A high-value MYR amount, a JPY value (no minor unit), and a USDT value (six decimals) all break under that line — precision loss and the wrong divisor.

On this page