Accept Google Pay amounts in minor units - #52
Merged
Conversation
Max Harrison (maxharrison)
force-pushed
the
android-amount-minor-units
branch
from
August 12, 2026 10:23
76ca72a to
6d76b27
Compare
Contributor
|
Google might not accept newly formatted strings, it required exactly 0 or 2 digits after decimal point worth doublechecking https://developers.google.com/pay/api/android/reference/request-objects#TransactionInfo |
Max Harrison (maxharrison)
force-pushed
the
android-amount-minor-units
branch
2 times, most recently
from
August 18, 2026 09:33
7663bd7 to
4b601f2
Compare
Max Harrison (maxharrison)
force-pushed
the
android-amount-minor-units
branch
from
August 18, 2026 10:45
4b601f2 to
0cbcef9
Compare
Max Harrison (maxharrison)
marked this pull request as ready for review
August 18, 2026 13:03
ana-maksimovskikh
approved these changes
Aug 18, 2026
ana-maksimovskikh
left a comment
Contributor
There was a problem hiding this comment.
A few nits, but overall looks good. Thanks Max 👍
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The Android Google Pay SDK can now take an amount as a whole number of a currency's smallest unit, the way our web SDKs already do. It also rejects an amount Google Pay cannot render, instead of letting it fail inside the payment sheet.
Part of CARD-1163. Android only; iOS and Apple Pay are untouched.
Context
evervault-payholds the Android and iOS wallet SDKs. A merchant building a Google Pay sheet on Android gives us aTransaction, and every price in it (the total and each line item) is anAmount.Most currencies have a minor unit 1/100th the size of the major unit: 5499 cents is 54.99 EUR. Not all do. JPY has no minor unit at all, so 5499 JPY is just
5499. KWD has three digits, so 5499 fils is 5.499 KWD. The number of digits is the currency's exponent.Until now
Amounttook only a major-unit decimal string, so the merchant converted from minor units themselves and had to know each currency's exponent to do it. Our web SDKs take minor-unit integers, so a merchant on both web and Android wrote the same charge two different ways. Nothing validated the string either, so a malformed amount reached Google's client and failed there.Source level change
Amountshipped asdata class Amount(val amount: String)inandroid-v0.0.30. It is now a sealed class with two cases: a decimal string and a count of minor units. Constructing anAmountfrom Kotlin is unchanged, which is what merchant code overwhelmingly does. Reading one back is not.transaction.total.amountAmountalone.amount.copy(...), destructuring,component1()new Amount("54.99")(Java)Amount.Companion.invoke("54.99")Stricter at runtime too.
Amount("54.999"),Amount("-1.00")andAmount("ten")used to construct fine and then fail inside Google's sheet. They now throwIllegalArgumentExceptionat construction, with a message naming the problem.Ships in
android-v0.0.31. Version bump still to do, perandroid/README.md.How it works
Amount.ofMinorUnits(5499)stores the integer. The currency is applied later, when the request JSON is built, so the amount is always resolved against the transaction's own currency and there is no way to pass a second, conflicting one.java.util.Currency.defaultFractionDigits.BigDecimaldoes the shift, so the conversion is exact.Amount("54.99")still constructs the same way, but now rejects anything Google's client will not accept.Three-decimal currencies reach hundredths, not thousandths
Google Pay carries at most two fraction digits. KWD, BHD, OMR, JOD and TND have three, so they work down to hundredths of a major unit and no further:
ofMinorUnitsin KWD1000(1.000 KWD)"1.00"1250(1.250 KWD)"1.25"1005(1.005 KWD)An amount needing the third digit is rejected rather than rounded, because rounding would charge something other than what was asked for.
Existing integrations are unaffected. The currency is only consulted for the minor-units case, so
Amount("1.00")with KWD behaves exactly as before. The limit only applies toofMinorUnits, which is new API.Establishing the real two-digit limit (device and browser testing)
Google's docs give
totalPriceas^[0-9]+(\.[0-9][0-9])?$. That is not the rule the client applies. Play Services returns the real one in the error for an over-precise display item:So one fraction digit is accepted, and negatives are accepted on display items. The two-digit ceiling is real.
Tested on a real device and against
pay.jsin Chrome:10.123fails10.12completes1.000fails1.00completes1.500fails1.50completes2.345fails2.34completes9.750fails9.75completesEach currency completing at two digits rules out the currency itself being unsupported.
10.5completes, confirming one digit is fine. A legal total with an over-precise line item also fails, sodisplayItems[].priceis validated the same way.An over-precise price is not rejected when the request is built. It opens the sheet and fails there:
statusCode 10(DEVELOPER_ERROR) with an empty message on Android, and anOR_BIBED_06dialog on web reading "This merchant is having trouble accepting your payment right now". Validating in the SDK turns that into an error an integrator can act on.