Skip to main content

Currencies and Amounts

Learn how to specify amounts correctly, understand currency units, and work with multi-currency transactions in the Omise API.

Overview

When working with the Omise API, all monetary amounts must be specified in the smallest unit of the given currency. This ensures precision and avoids floating-point errors that can occur with decimal values.

Smallest Currency Unit

Each currency has a smallest unit (also called a subunit):

CurrencyCodeSmallest UnitDecimal PlacesExample
Thai BahtTHBSatang2฿100.00 = 10000
Japanese YenJPYYen0¥100 = 100
Singapore DollarSGDCent2S$100.00 = 10000
Malaysian RinggitMYRSen2RM100.00 = 10000
US DollarUSDCent2$100.00 = 10000
EuroEURCent2€100.00 = 10000

Examples

// Thai Baht: ฿1,000.00 = 100,000 satangs
const amount = 100000;
const currency = 'thb';

// Japanese Yen: ¥1,000 = 1,000 yen (no subunit)
const amount = 1000;
const currency = 'jpy';

// Singapore Dollar: S$50.50 = 5,050 cents
const amount = 5050;
const currency = 'sgd';

Common Mistakes

// ❌ WRONG - Using decimal values
const charge = await omise.charges.create({
amount: 1000.00, // This is ฿10.00, not ฿1,000!
currency: 'thb'
});

// ✅ CORRECT - Using smallest unit
const charge = await omise.charges.create({
amount: 100000, // This is ฿1,000.00
currency: 'thb'
});

Converting Amounts

Display Amount to Smallest Unit

function toSmallestUnit(amount, currency) {
const zeroDecimalCurrencies = ['jpy', 'krw', 'vnd'];

if (zeroDecimalCurrencies.includes(currency.toLowerCase())) {
return Math.round(amount);
}

return Math.round(amount * 100);
}

// Usage
toSmallestUnit(1000.00, 'thb'); // 100000
toSmallestUnit(1000, 'jpy'); // 1000
toSmallestUnit(99.99, 'sgd'); // 9999

Smallest Unit to Display Amount

function toDisplayAmount(amount, currency) {
const zeroDecimalCurrencies = ['jpy', 'krw', 'vnd'];

if (zeroDecimalCurrencies.includes(currency.toLowerCase())) {
return amount;
}

return amount / 100;
}

// Usage
toDisplayAmount(100000, 'thb'); // 1000.00
toDisplayAmount(1000, 'jpy'); // 1000
toDisplayAmount(9999, 'sgd'); // 99.99

Formatting for Display

function formatCurrency(amount, currency) {
const displayAmount = toDisplayAmount(amount, currency);

return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: currency.toUpperCase()
}).format(displayAmount);
}

// Usage
formatCurrency(100000, 'thb'); // "฿1,000.00"
formatCurrency(1000, 'jpy'); // "¥1,000"
formatCurrency(9999, 'sgd'); // "S$99.99"

Supported Currencies

Charges (Credit/Debit Cards)

The currencies available for charges depend on your account's registered country:

CountrySupported Currencies
ThailandTHB
JapanJPY
SingaporeSGD, USD
MalaysiaMYR

Charge Limits

CountryCurrencyMinimumMaximum
ThailandTHB฿20 (2000)฿150,000 (15000000)
JapanJPY¥100 (100)¥6,000,000 (6000000)
SingaporeSGDS$1 (100)S$99,999 (9999900)
MalaysiaMYRRM1 (100)RM30,000 (3000000)

Transfers

CountryCurrencyMinimumMaximum
ThailandTHB฿30 (3000)฿2,000,000 (200000000)
JapanJPY¥1 (1)¥10,000,000 (10000000)
SingaporeSGDS$1 (100)S$200,000 (20000000)
MalaysiaMYRRM1 (100)RM500,000 (50000000)

Settlement Currency

Charges are always settled in your account funding currency, which is determined by your account's registered country:

Account CountrySettlement Currency
ThailandTHB (Thai Baht)
JapanJPY (Japanese Yen)
SingaporeSGD (Singapore Dollar)
MalaysiaMYR (Malaysian Ringgit)
Multi-Currency Charges

If you accept payments in a currency different from your settlement currency, Omise automatically converts the amount at the current exchange rate.

Zero-Decimal Currencies

Some currencies don't have a fractional unit. For these currencies, the amount value represents the full currency unit:

CurrencyCodeExample
Japanese YenJPY¥500 = 500
Korean WonKRW₩500 = 500
Vietnamese DongVND₫500 = 500

API Examples

Creating a Charge

curl https://api.omise.co/charges \
-u skey_test_YOUR_SECRET_KEY: \
-d "amount=100000" \
-d "currency=thb" \
-d "card=tokn_test_xxx"

This charges ฿1,000.00 (100,000 satangs).

Creating a Transfer

curl https://api.omise.co/transfers \
-u skey_test_YOUR_SECRET_KEY: \
-d "amount=500000" \
-d "recipient=recp_test_xxx"

This transfers ฿5,000.00 (500,000 satangs) to the recipient.

Creating a Refund

curl https://api.omise.co/charges/chrg_test_xxx/refunds \
-u skey_test_YOUR_SECRET_KEY: \
-d "amount=50000"

This refunds ฿500.00 (50,000 satangs) from the charge.

Rounding

When dealing with calculations that may result in fractional smallest units, always round to the nearest integer:

// Calculate 10% discount on ฿999.00
const originalAmount = 99900; // ฿999.00 in satangs
const discount = 0.10;
const discountAmount = Math.round(originalAmount * discount); // 9990 satangs (฿99.90)
const finalAmount = originalAmount - discountAmount; // 89910 satangs (฿899.10)
Avoid Floating Point

Never use floating-point arithmetic for currency calculations. Always work with integers (smallest units) and round appropriately.

FAQ

Why use smallest currency units instead of decimal amounts?

Using smallest currency units (integers) prevents floating-point precision errors that can occur with decimal calculations. For example:

// Floating point issue
0.1 + 0.2 === 0.3 // false! (0.30000000000000004)

// Integer calculation (no issues)
10 + 20 === 30 // true

Working with integers ensures exact calculations for financial transactions.

How do I handle currency conversion?

Omise handles currency conversion automatically for multi-currency accounts. When a charge is made in a different currency than your settlement currency, it's converted at the current exchange rate. The conversion rate is included in the charge response:

{
"object": "charge",
"amount": 10000,
"currency": "usd",
"funding_amount": 350000,
"funding_currency": "thb",
"exchange_rate": 35.0
}
What happens if I send the wrong amount format?

The API expects integer values. If you send a decimal value, it will be truncated:

  • Sending 1000.50 becomes 1000 (the .50 is lost)
  • This would charge ฿10.00 instead of ฿1,000.50

Always validate amounts before sending to the API.

Can I charge partial amounts (e.g., ฿10.25)?

Yes, but you must specify the amount in satangs:

  • ฿10.25 = 1025 satangs
  • ฿99.99 = 9999 satangs

The smallest chargeable amount varies by currency and is typically the equivalent of the minimum charge limit.

How do I display amounts to customers?

Convert the smallest unit back to display format:

const amountInSatangs = 99999;
const displayAmount = (amountInSatangs / 100).toFixed(2); // "999.99"
const formatted = `฿${displayAmount}`; // "฿999.99"

Or use Intl.NumberFormat for proper locale-aware formatting.

Are there any currencies with 3 decimal places?

Some currencies like KWD (Kuwaiti Dinar), BHD (Bahraini Dinar), and OMR (Omani Rial) use 3 decimal places (fils). However, these currencies are not currently supported by Omise. All supported currencies use either 0 or 2 decimal places.