Amounts & Currencies
AccruPay represents all monetary amounts in minor units — the smallest denomination of the currency — using JavaScript BigInt. Getting this right is a prerequisite to correct payment processing. A single digit off in your amount representation charges the wrong amount to every customer.
Minor units
Every currency has a smallest unit. AccruPay amounts are always expressed in that unit:
| Currency | Code | Minor unit | Example |
|---|---|---|---|
| US Dollar | USD | Cent (1/100) | 10000n = $100.00 |
| Euro | EUR | Cent (1/100) | 5000n = €50.00 |
| Pound Sterling | GBP | Penny (1/100) | 7500n = £75.00 |
| Japanese Yen | JPY | Yen (no subdivision) | 1000n = ¥1,000 |
JPY has no minor unit — one yen is the smallest denomination. For JPY, the amount you pass is the exact yen amount.
Why BigInt
JavaScript's Number type is a 64-bit float. Floating-point arithmetic cannot represent all integers exactly above 2^53 − 1 (9,007,199,254,740,991). For everyday transaction amounts this limit is rarely hit, but:
- Large transaction amounts in low-value currencies can exceed safe integer range
- Payment processors operate on exact integer arithmetic — any precision loss causes silent discrepancies
BigInt is an exact integer type. There is no rounding, no floating-point drift, no silent truncation. AccruPay uses BigInt for amounts throughout the SDK so that correctness is enforced by the type system, not by developer discipline.
Writing amounts in code
Always use the n suffix to create a BigInt literal:
const amount = 10000n; // $100.00 in USD cents — correct
const amount = 10000; // number — type error, rejected by the SDK
const amount = '10000'; // string — type error, rejected by the SDK
import AccruPay, { CURRENCY, COUNTRY_ISO_2 } from '@accrupay/node';
const sdk = new AccruPay({ apiSecret: process.env.ACCRUPAY_API_SECRET });
const session = await sdk.transactions.clientSessions.payments.start({
data: {
amount: 10000n, // $100.00
currency: CURRENCY.USD,
merchantInternalCustomerCode: 'customer-123',
merchantInternalTransactionCode: 'order-456',
billing: {
billingFirstName: 'Jane',
billingLastName: 'Smith',
billingEmail: 'jane@example.com',
billingAddressCountry: COUNTRY_ISO_2.US,
},
storePaymentMethod: false,
},
});
BigInt and JSON serialization
JSON.stringify(10000n) throws a TypeError: Do not know how to serialize a BigInt. BigInt values are not natively serializable to JSON.
If you need to pass an amount through a JSON boundary (HTTP response body, message queue, cache), convert it to a string first:
// Safe: convert before serializing
const payload = JSON.stringify({ amount: String(session.amount) });
// or
const payload = JSON.stringify({ amount: session.amount.toString() });
// Parse back when you receive it
const amount = BigInt(parsed.amount);
Do not convert to Number — this defeats the purpose of using BigInt and may lose precision.
Computing amounts safely
When you calculate amounts programmatically, keep everything in BigInt until the moment you need to serialize or display:
const unitPrice = 2999n; // $29.99
const quantity = 3n; // must also be BigInt for arithmetic
const total = unitPrice * quantity; // 8997n = $89.97
// For display only — convert to Number here is fine because
// display values are approximate by nature
const displayAmount = Number(total) / 100; // 89.97
Avoid mixing BigInt and number in arithmetic expressions — JavaScript throws a TypeError. Keep your amount calculation in BigInt and convert only at display or serialization boundaries.
Currency codes
AccruPay uses the CURRENCY enum, which maps to ISO 4217 currency codes. Import it from @accrupay/node:
import { CURRENCY } from '@accrupay/node';
CURRENCY.USD // US Dollar
CURRENCY.EUR // Euro
CURRENCY.GBP // Pound Sterling
CURRENCY.JPY // Japanese Yen
// ... all ISO 4217 codes
Always use the enum rather than raw strings. The enum is validated against what AccruPay supports; raw strings can silently fail validation.
Country codes
Billing fields that take a country accept the COUNTRY_ISO_2 enum — ISO 3166-1 alpha-2 two-letter country codes:
import { COUNTRY_ISO_2 } from '@accrupay/node';
COUNTRY_ISO_2.US // United States
COUNTRY_ISO_2.GB // United Kingdom
COUNTRY_ISO_2.DE // Germany
State and subdivision codes
billingAddressState uses ISO 3166-2 subdivision codes — the part after the country prefix:
| Country | State/Region | Code to pass |
|---|---|---|
| United States | New York | NY |
| United States | California | CA |
| United Kingdom | England | ENG |
| United Kingdom | Scotland | SCT |
| Germany | Bavaria | BY |
Not all providers validate billingAddressState against the selected billingAddressCountry. Passing a US state code alongside a non-US country may be accepted but could cause downstream reconciliation issues. Always pass subdivision codes that match the country.
Common mistakes
Passing 100 to charge $100. This charges $1.00. The amount 100n in USD is 100 cents. To charge $100.00, pass 10000n.
// Wrong: charges $1.00
amount: 100n,
// Correct: charges $100.00
amount: 10000n,
Using number for calculated amounts. If you compute quantity * unitPrice and either operand is a regular number, you get a number result that the SDK will reject. Keep both operands as BigInt.
Calling JSON.stringify directly on a session object. Session objects contain BigInt fields (including amount). Serializing them directly throws. Always extract and convert the fields you need.
Using raw string currency codes. 'USD' instead of CURRENCY.USD bypasses enum validation. If AccruPay does not support that code or it is misspelled, the error surfaces later rather than at the call site.