Define the unit before choosing a number type
A payment value of 1000 is not self-explanatory: it might mean a thousand major units or ten. Adyen requires a currency code and a value, with most APIs expressing that value in minor units.[1] Our editorial recommendation is to define amount, currency, scale and operation together. A display string helps a person read the price; a calculation value supports arithmetic; a request value follows the receiving API contract. This article is documentation research, not a description of PayIn fields or supported capabilities. If an integration does not document its unit, resolve that ambiguity before implementation. A live charge is not an appropriate experiment for discovering the multiplier.
Replace the universal multiplier with a reviewed mapping
Adyen lists JPY with zero decimal places and BHD with three. Its ISK entry specifies two and explicitly marks a difference from the standard.[1] A general currency table therefore cannot automatically substitute for a provider contract. We recommend a reviewed mapping keyed by provider, operation and currency, with its source and effective version. As an arithmetic illustration, decimal text 12.34 becomes integer 1234 at scale two; 12.340 becomes 12340 at scale three. Treat unknown currencies, missing scales and excessive fractional digits as explicit validation outcomes. Do not silently assume two places or discard extra digits. A deliberate conversion policy should distinguish accepted equivalent spellings from inputs that would change the amount.
Combine integer storage with controlled decimal arithmetic
The Fintech Engineering Handbook describes integer minor-unit storage and arbitrary-precision intermediate calculation as compatible choices rather than opposing designs.[4] Our recommendation is to represent committed payable amounts with a controlled-scale integer or exact decimal type, while retaining the precision needed for rates, unit prices and intermediate calculations. Integer division can still leave a remainder, and decimal arithmetic does not make every division terminate. Parse original decimal text directly, configure calculation precision and check the range of multiplication results. Converting through a binary floating-point value first can lose the very information the decimal representation is intended to protect. Formatting a value to two places should not overwrite the calculation inputs or determine a charge by accident. Also distinguish precision, meaning the supported significant digits, from scale, meaning the fractional places. A generous scale does not guarantee enough total digits for a large accumulated value.
Specify both the rounding mode and its location
Python documents HALF_EVEN as rounding ties to the nearest even integer, HALF_UP as rounding ties away from zero, and FLOOR as rounding toward negative infinity.[3] Applied at two decimal places, the first two rules turn 1.005 into 1.00 and 1.01 respectively; for -1.005 they produce -1.00 and -1.01. Our recommendation is to document scale, mode, sign handling and calculation step together. Location matters independently: rounding three exact values of 0.005 individually with HALF_UP gives a total of 0.03, while rounding their sum gives 0.02. These are worked examples, not processing measurements. Follow applicable contractual or tax requirements for line-level calculation; “round only at the end” is not a universal legal rule.
Allocate a remainder instead of losing it
A Stack Overflow engineering discussion separates exact storage from remainders introduced by division, illustrating the missing 0.01 when 10.00 becomes three amounts of 3.33.[5] This is useful problem discovery, not an accounting standard. Where the business rules permit allocation, we recommend fixing the total first and distributing integer units with a documented method. Splitting 1000 units into 334, 333 and 333 preserves that total. A largest-remainder implementation also needs a stable tie-break rule when fractional remainders are equal. Record which recipient receives the additional unit and why. If a contract forbids redistribution, handle the difference under an approved policy rather than silently editing a line to make the numbers match.
Protect precision across JSON and database boundaries
RFC 8259 identifies integers from -(2^53)+1 through (2^53)-1 as interoperable with exact agreement under the commonly used numeric implementations it discusses.[6] This is an interoperability observation, not a prohibition on larger numbers in JSON syntax. We recommend checking every transition: browser parsing, server arithmetic, database drivers and exported data. Verify that no component implicitly converts a protected amount to a floating-point representation. For values beyond a receiver’s safe numeric range, use a string with a suitable integer or decimal parser only if the protocol permits it. An external API requiring a numeric field cannot be fixed by unilaterally changing its type. Validate the range before transmission, not after a parser has already changed the value.
Accept the implementation using boundary cases
Our proposed acceptance set covers zero-, two- and three-place scales, provider exceptions, zero, one minor unit, maximum permitted amounts, out-of-range values, excessive fractional digits and positive and negative ties. Negative inputs should be accepted only for operations whose business contract allows them. Add cases for line-versus-total rounding, allocation ties, serialization round trips and database read-back types. Preserve input text, scale version, rounding policy and expected output so an independent calculation can check the result. The examples above are illustrations, not claims that payment tests were performed. A disagreement between components should block release. Actual charge amounts and rounding sequences still require review against the applicable contract, law and API specification. Keep rejected inputs in the acceptance checklist as well as successful ones. A system that correctly displays a small price but silently accepts an overflowing amount has not satisfied the same contract. Record outstanding cases as unverified rather than treating them as passing.
Sources and dates
Verified on 2026-09-20. Source dates distinguish explicitly stated publication and update dates; an unspecified date does not mean the source was published today. This is public-document research, not a live payment test, security audit or accessibility certification. Vendor facts apply to the cited vendor; proposed workflows are editorial synthesis.
More new articles
A payment API key leaked: how do you rotate every consumer? →
Payment troubleshooting logs: redact sensitive data without losing investigation clues →
Payment review and errors that keyboard and screen-reader users can check →
Payment lookups returning 429 or 503: backoff, retry budgets and recovery →
Stablecoin address poisoning: checks before copying a past recipient →
All field guides →