Skip to content

Wire checkout session customerEmail into Google Pay PM billing details#13362

Merged
cttsai-stripe merged 5 commits into
masterfrom
cttsai/mobilesdk4640-gpay-billing-email-override
Jul 7, 2026
Merged

Wire checkout session customerEmail into Google Pay PM billing details#13362
cttsai-stripe merged 5 commits into
masterfrom
cttsai/mobilesdk4640-gpay-billing-email-override

Conversation

@cttsai-stripe

@cttsai-stripe cttsai-stripe commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

go/o/req_BAWvlsMkOoCamA

Summary

  • When confirming Google Pay in a checkout session, the backend validates payment_method.billing_details.email. Google Pay doesn't return an email by default (isEmailRequired is false in the checkout flow), so the PM gets created without one and confirm fails with checkout_email_missing.
  • Reads customerEmail from the merged configuration (defaultBillingDetails.email, populated by CheckoutConfigurationMerger from the checkout session response) and passes it as a fallback into PaymentMethodCreateParams.createFromGooglePay().
  • If Google Pay provides an email (from the card stored in the wallet), use it; otherwise fall back to the checkout session's customer email.

Changes

  • PaymentMethodCreateParams.createFromGooglePay(): new billingEmailFallback param, used when Google Pay doesn't provide an email
  • GooglePayPaymentMethodLauncherContractV2.Args: new billingEmailFallback field threaded through the launcher
  • GooglePayConfirmationOption.Config: carries the fallback from the merged config
  • ConfirmationOptionKtx: reads configuration.defaultBillingDetails?.email when constructing the GPay option
  • TestGooglePay: new testCheckoutSessionWithFlowController test (requires real device)

Test plan

  • testCheckoutSessionWithFlowController passes on real device with Google Pay (checkout session, FlowController, guest customer, automatic tax disabled)
  • CI passes (detekt, apiCheck)

MOBILESDK-4640

🤖 Generated with Claude Code

When confirming a Google Pay payment in a checkout session, the backend
requires billing_details.email on the payment method. Google Pay doesn't
return an email unless isEmailRequired=true, which isn't set in the
checkout session flow. This mirrors stripe-js's __billingDetailsEmailOverride
pattern by injecting the checkout session's customerEmail into the PM
creation params.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Committed-By-Agent: claude
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Diffuse output:

OLD: paymentsheet-example-release-master.apk (signature: V1, V2)
NEW: paymentsheet-example-release-pr.apk (signature: V1, V2)

          │            compressed            │           uncompressed           
          ├───────────┬───────────┬──────────┼───────────┬───────────┬──────────
 APK      │ old       │ new       │ diff     │ old       │ new       │ diff     
──────────┼───────────┼───────────┼──────────┼───────────┼───────────┼──────────
      dex │   4.6 MiB │   4.6 MiB │   +296 B │   9.7 MiB │   9.7 MiB │   +864 B 
     arsc │   3.8 MiB │   3.8 MiB │      0 B │   3.8 MiB │   3.8 MiB │      0 B 
 manifest │   5.8 KiB │   5.8 KiB │      0 B │  30.7 KiB │  30.7 KiB │      0 B 
      res │     1 MiB │     1 MiB │      0 B │   1.7 MiB │   1.7 MiB │      0 B 
   native │   2.7 MiB │   2.7 MiB │      0 B │   2.7 MiB │   2.7 MiB │      0 B 
    asset │  19.4 KiB │  20.9 KiB │ +1.5 KiB │  29.5 KiB │    31 KiB │ +1.5 KiB 
    other │ 245.5 KiB │ 245.5 KiB │    +18 B │ 505.4 KiB │ 505.4 KiB │      0 B 
──────────┼───────────┼───────────┼──────────┼───────────┼───────────┼──────────
    total │  12.3 MiB │  12.3 MiB │ +1.8 KiB │  18.4 MiB │  18.4 MiB │ +2.4 KiB 

 DEX     │ old   │ new   │ diff       
─────────┼───────┼───────┼────────────
   files │     1 │     1 │  0         
 strings │ 45332 │ 45333 │ +1 (+4 -3) 
   types │ 14262 │ 14262 │  0 (+0 -0) 
 classes │ 11604 │ 11604 │  0 (+0 -0) 
 methods │ 63336 │ 63335 │ -1 (+4 -5) 
  fields │ 41196 │ 41198 │ +2 (+2 -0) 

 ARSC    │ old  │ new  │ diff 
─────────┼──────┼──────┼──────
 configs │  320 │  320 │  0   
 entries │ 7492 │ 7492 │  0
APK
     compressed      │     uncompressed     │                                           
──────────┬──────────┼───────────┬──────────┤                                           
 size     │ diff     │ size      │ diff     │ path                                      
──────────┼──────────┼───────────┼──────────┼───────────────────────────────────────────
  8.9 KiB │ +1.5 KiB │   8.8 KiB │ +1.5 KiB │ ∆ assets/dexopt/baseline.prof             
  4.6 MiB │   +296 B │   9.7 MiB │   +864 B │ ∆ classes.dex                             
 58.9 KiB │    +16 B │ 130.8 KiB │      0 B │ ∆ META-INF/CERT.SF                        
    272 B │     +3 B │     120 B │      0 B │ ∆ META-INF/version-control-info.textproto 
  1.2 KiB │     -3 B │   1.2 KiB │      0 B │ ∆ META-INF/CERT.RSA                       
 55.6 KiB │     +2 B │ 130.7 KiB │      0 B │ ∆ META-INF/MANIFEST.MF                    
──────────┼──────────┼───────────┼──────────┼───────────────────────────────────────────
  4.7 MiB │ +1.8 KiB │    10 MiB │ +2.4 KiB │ (total)
DEX
STRINGS:

   old   │ new   │ diff       
  ───────┼───────┼────────────
   45332 │ 45333 │ +1 (+4 -3) 
  
  + , billingEmailOverride=
  + VLLJLLLLLZLLL
  + r8-map-id-5739503953e3285b9187ed55e9fd60693f2801efd3e683c799368e7cb31e2f0f
  + ~~R8{"backend":"dex","compilation-mode":"release","has-checksums":false,"min-api":23,"pg-map-id":"5739503953e3285b9187ed55e9fd60693f2801efd3e683c799368e7cb31e2f0f","r8-mode":"full","version":"8.13.19"}
  
  - VLLJLLLLLZLL
  - r8-map-id-66863c0c11bdc2fdf93d597bda75a207df52dc902a1ae5c6e1aa2cee305ce89f
  - ~~R8{"backend":"dex","compilation-mode":"release","has-checksums":false,"min-api":23,"pg-map-id":"66863c0c11bdc2fdf93d597bda75a207df52dc902a1ae5c6e1aa2cee305ce89f","r8-mode":"full","version":"8.13.19"}
  

METHODS:

   old   │ new   │ diff       
  ───────┼───────┼────────────
   63336 │ 63335 │ -1 (+4 -5) 
  
  + ai.i7 o(i7, b6, h8, j, int) → i7
  + oi.b <init>(p2, String, String, String, Long, String, s1, a, b, List, List, String)
  + sb.b b0(x, a, j0, b, List, String) → n
  + ug.k0 <init>(b0, String, long, String, String, a, b, q, boolean, String, List, String)
  
  - ai.i7 o(i7, h8, j, int) → i7
  - androidx.lifecycle.u0 D(Object) → Object
  - oi.b <init>(p2, String, String, String, Long, String, s1, a, b, List, List)
  - sb.b b0(x, a, j0, b, List) → n
  - ug.k0 <init>(b0, String, long, String, String, a, b, q, boolean, String, List)
  

FIELDS:

   old   │ new   │ diff       
  ───────┼───────┼────────────
   41196 │ 41198 │ +2 (+2 -0) 
  
  + oi.b p: String
  + ug.k0 p: String

cttsai-stripe and others added 3 commits July 6, 2026 21:39
- Fix line length in EmbeddedConfirmationHelper
- Fix import ordering in PaymentSheetViewModel
- Add testCheckoutSessionWithFlowController to TestGooglePay

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Committed-By-Agent: claude
…mGooglePay

- Remove GooglePayBillingEmailFactory; read email from
  configuration.defaultBillingDetails.email (already merged by
  CheckoutConfigurationMerger)
- Move billingEmailOverride logic into PaymentMethodCreateParams.createFromGooglePay
  instead of post-hoc modification in the ViewModel
- Add checkout session GPay test with FlowController and guest customer
- Fix test flow: use launchCustom(clickMultiStep=false) + playgroundBuyButton

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Committed-By-Agent: claude
- Rename to billingEmailFallback since it's a fallback, not an override
- Remove default value from @RestrictTo param (internal code omits defaults)
- Rename test method to confirmGooglePayWithCheckoutSession with only
  the relevant params (merchant, customerEmail)
- Hardcode FlowController + CheckoutSession + no auto tax inside the
  test method since it's specific to this scenario

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Committed-By-Agent: claude
@cttsai-stripe cttsai-stripe marked this pull request as ready for review July 7, 2026 06:05
@cttsai-stripe cttsai-stripe requested review from a team as code owners July 7, 2026 06:05
amk-stripe
amk-stripe previously approved these changes Jul 7, 2026
cardBrandFilter = PaymentSheetCardBrandFilter(configuration.cardBrandAcceptance),
cardFundingFilter = cardFundingFilter,
displayItems = displayItems,
billingEmailFallback = configuration.defaultBillingDetails?.email,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's also a customerEmail on the checkout session object -- is that always the same as this email? Or should we additionally fallback to that customerEmail value too?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1, we need to ensure that if customerEmail is on the CS we try to use it if available. I'm guessing we merge it into the defaultBillingDetails tho?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. I added tests to cover that.

@cttsai-stripe cttsai-stripe force-pushed the cttsai/mobilesdk4640-gpay-billing-email-override branch 2 times, most recently from 530ed34 to e473a6f Compare July 7, 2026 17:36
- createFromGooglePay uses billingEmailFallback when GPay has no email
- createFromGooglePay prefers GPay email when present
- toConfirmationOption wires customerEmail from merged config to
  billingEmailFallback on the Google Pay confirmation option

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Committed-By-Agent: claude
@cttsai-stripe cttsai-stripe force-pushed the cttsai/mobilesdk4640-gpay-billing-email-override branch from e473a6f to 093d43e Compare July 7, 2026 17:46
@cttsai-stripe cttsai-stripe requested a review from amk-stripe July 7, 2026 17:59
@cttsai-stripe cttsai-stripe merged commit b884008 into master Jul 7, 2026
55 checks passed
@cttsai-stripe cttsai-stripe deleted the cttsai/mobilesdk4640-gpay-billing-email-override branch July 7, 2026 21:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants