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):
| Currency | Code | Smallest Unit | Decimal Places | Example |
|---|---|---|---|---|
| Thai Baht | THB | Satang | 2 | ฿100.00 = 10000 |
| Japanese Yen | JPY | Yen | 0 | ¥100 = 100 |
| Singapore Dollar | SGD | Cent | 2 | S$100.00 = 10000 |
| Malaysian Ringgit | MYR | Sen | 2 | RM100.00 = 10000 |
| US Dollar | USD | Cent | 2 | $100.00 = 10000 |
| Euro | EUR | Cent | 2 | €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:
| Country | Supported Currencies |
|---|---|
| Thailand | THB |
| Japan | JPY |
| Singapore | SGD, USD |
| Malaysia | MYR |
Charge Limits
| Country | Currency | Minimum | Maximum |
|---|---|---|---|
| Thailand | THB | ฿20 (2000) | ฿150,000 (15000000) |
| Japan | JPY | ¥100 (100) | ¥6,000,000 (6000000) |
| Singapore | SGD | S$1 (100) | S$99,999 (9999900) |
| Malaysia | MYR | RM1 (100) | RM30,000 (3000000) |
Transfers
| Country | Currency | Minimum | Maximum |
|---|---|---|---|
| Thailand | THB | ฿30 (3000) | ฿2,000,000 (200000000) |
| Japan | JPY | ¥1 (1) | ¥10,000,000 (10000000) |
| Singapore | SGD | S$1 (100) | S$200,000 (20000000) |
| Malaysia | MYR | RM1 (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 Country | Settlement Currency |
|---|---|
| Thailand | THB (Thai Baht) |
| Japan | JPY (Japanese Yen) |
| Singapore | SGD (Singapore Dollar) |
| Malaysia | MYR (Malaysian Ringgit) |
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:
| Currency | Code | Example |
|---|---|---|
| Japanese Yen | JPY | ¥500 = 500 |
| Korean Won | KRW | ₩500 = 500 |
| Vietnamese Dong | VND | ₫500 = 500 |
API Examples
Creating a Charge
- Thai Baht
- Japanese Yen
- Singapore Dollar
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).
curl https://api.omise.co/charges \
-u skey_test_YOUR_SECRET_KEY: \
-d "amount=1000" \
-d "currency=jpy" \
-d "card=tokn_test_xxx"
This charges ¥1,000 (1,000 yen - no decimals).
curl https://api.omise.co/charges \
-u skey_test_YOUR_SECRET_KEY: \
-d "amount=10000" \
-d "currency=sgd" \
-d "card=tokn_test_xxx"
This charges S$100.00 (10,000 cents).
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)
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.50becomes1000(the.50is 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.
Related Resources
- Multi-Currency - Accept payments in multiple currencies
- Charges API - Create and manage charges
- Transfers API - Create and manage transfers
- Refunds - Process refunds