Skip to content

Amounts and currencies

Money representation is field-specific in the public schema. The checkout-session request accepts its declared number or decimal-string shape, and its currency is a three-letter uppercase code. Checkout-session responses represent amount as a decimal string. Transaction money fields are JSON numbers, while explicitly suffixed fields such as refunded_amount_cents are integers in minor units.

The response amount is a value, not your string

Section titled “The response amount is a value, not your string”

A checkout session stores the amount in the currency’s minor units, and the response carries what that number is worth — not the text you sent. Trailing zeros do not survive it. "10.00" comes back as "10", "1.50" as "1.5", and "49.95" unchanged, because it has no trailing zero to lose. An integration that confirms its own order by comparing the response string with the request string passes on some amounts and fails on others.

Compare it as a decimal number, and format it for display yourself.

currency is a three-letter uppercase ISO 4217 code that is still legal tender somewhere. USD, EUR, BRL and JPY are all accepted; there is no narrower allow-list to look up, and no default worth relying on.

Four kinds of value that look like a currency are refused with 422 and is not a valid ISO 4217 currency code: an invented code, a metal (XAU), a code reserved for testing (XTS), and a withdrawn currency (DEM). A lowercase usd is refused too, by the pattern rather than the vocabulary.

Send the amount at the currency’s own precision. A currency with no minor unit takes no decimals at all, and 1234.56 in JPY is refused with 422 and amount for JPY cannot have more than 0 decimal places rather than rounded.

Accepting the code is not accepting the payment. Maxana checks that currency names a real currency, and — once it knows the account’s primary settlement currency — opens the session only in that one currency.

PayPal reports a single primary settlement currency per account and no list of the others it might also accept or convert, so Maxana opens a PayPal session only in that primary. This is Maxana’s own restriction, not a statement that PayPal could not process another currency for the account.

A mismatch can fail at three layers, and creation now catches the one that used to reach the buyer. The code being a real currency is checked first, at creation. A currency the provider itself does not process — a code that is legal tender somewhere but outside the provider’s own accepted set — is refused when Maxana creates the order with the provider, before the buyer has signed in. A currency the provider accepts but that is not the account’s primary settlement currency is now refused at session creation with 400, naming the account’s settlement currency and the one you asked for, so no session is opened and the buyer never reaches a payment that would fail in the provider’s words after they committed.

That last check only fires once Maxana has learned the account’s settlement currency, and it applies to a session that settles through PayPal. The channel onboarding status read reports it as paypal_primary_currency — the account’s primary settlement currency, or null until the account has been read once. Read it and open each session in that currency: a channel provisioning merchants across countries no longer has to ask the merchant which currency their account takes. While it is still null, creation cannot check the account and a mismatched currency falls through to the provider as before, so treat an unknown settlement currency as not yet safe to bill in a second currency.

Prove a new currency with a single small payment before offering it to buyers, per currency and per merchant: a merchant settling one currency is no evidence about a second.

  • Parse and validate money with decimal arithmetic. Do not use binary floating-point for totals, comparisons, or ledger entries.
  • Preserve the currency beside every amount. Never combine different currencies into one total unless you perform and record an explicit conversion outside the Maxana contract.
  • Follow the exact request and response schema for the operation. Do not infer that every integer means cents or that every number has two decimal places.
  • Reconcile by identifier, amount, and currency; display formatting is not a ledger representation.

For channel statements, use each field’s _cents, _minor_units, _display, and currency naming literally. Do not substitute a display string for the machine value.

Maxana does not convert currencies or publish a cross-currency total for an integration. A display string is not accepted as a machine amount, and no single representation applies to every money field; follow each operation’s schema.