Prototype: in-sheet checkout session update for billing address tax#13233
Draft
cttsai-stripe wants to merge 18 commits into
Draft
Prototype: in-sheet checkout session update for billing address tax#13233cttsai-stripe wants to merge 18 commits into
cttsai-stripe wants to merge 18 commits into
Conversation
When a checkout session has automatic tax enabled with billing address as the source, update the session with billing details before dismissing the FC/embedded sheet. This ensures the amount includes tax before confirmation, preventing the checkout_amount_mismatch error. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
The server returns tax_meta with requires_location_inputs even without billing_address_collection set. The only fix needed was the parser. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
- Make withInternalStateForInSheetUpdate private - Add SERVER_UPDATE_TIMEOUT_MS to withInternalStateLocked - Fix parseTaxStatusFromMeta default to UNKNOWN (not REQUIRES_BILLING_ADDRESS) - Fail early when billing address has no country Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
Network-layer timeouts in StripeNetworkClient already handle server hangs. The SERVER_UPDATE_TIMEOUT_MS is only for merchant server calls in runServerUpdate where we don't control the network layer. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
Instead of a separate withInternalStateForInSheetUpdate method, add a flag to the existing withInternalState. Future in-sheet updates just pass allowWhileSheetPresented = true (analogous to iOS's requireOpenSessionForInSheetUpdate vs requireOpenSession). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
No need for a separate method. The existing updateBillingAddress now accepts allowWhileSheetPresented to bypass the integration guard. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
The public API delegates to an internal function that accepts the allowWhileSheetPresented flag. Avoids breaking the API contract. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
Clarifies that this flag means the mutation originates from the currently presented sheet, not that arbitrary mutations are allowed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
Resolve Checkout from CheckoutInstances at construction time instead of passing PaymentMethodMetadata and doing the lookup internally. Makes the dependency explicit and removes coupling to the singleton. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
cttsai-stripe
commented
Jun 11, 2026
| import com.stripe.android.paymentsheet.repositories.CheckoutSessionResponse | ||
|
|
||
| @OptIn(CheckoutSessionPreview::class) | ||
| internal class InSheetCheckoutSessionUpdater( |
Contributor
Author
There was a problem hiding this comment.
Add tests and make it injected when ready for prod.
The caller doesn't need to know what specific update is needed. The class now handles the decision internally and can be extended for shipping address tax or other pre-dismiss updates without changing call sites. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
cttsai-stripe
commented
Jun 11, 2026
Comment on lines
+115
to
+120
| private fun currentExpectedAmount(): Long? { | ||
| val checkout = CheckoutInstances[integrationMetadata.instancesKey].firstOrNull() | ||
| ?: return null | ||
| return checkout.internalState.checkoutSessionResponse.amount | ||
| } | ||
|
|
Contributor
Author
There was a problem hiding this comment.
We should find a better way to pass along the updated expected amount.
- Generic naming unrelated to tax (supports future update types) - FC path: show PrimaryButton.State.StartProcessing spinner during update - Embedded path: uses setProcessing which disables button during update Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
The "tax" field format was speculatively added but never existed in real server responses. iOS and web both read tax_meta + tax_context. Align Android with the actual server format. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
…ion-open check 1. Align with iOS/web: default to REQUIRES_BILLING_ADDRESS for unrecognized address source (only shipping if explicitly stated) 2. Suppress _isLoading during in-sheet updates to avoid triggering merchant's CurrencySelectorContent loading state 3. Extract resolveCheckout() into InSheetCheckoutSessionUpdater.create() factory to remove duplication from both callers 4. Add session-open status check in withInternalState (aligned with iOS's requireOpenSessionForInSheetUpdate validation) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
The merchant's Activity is paused while the sheet is presented, so lifecycle-aware collectors won't observe the emission. Even if they did, the sheet occludes their UI. Let Checkout.isLoading behave uniformly for all mutations. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
MPE doesn't have a shipping address component. Shipping goes through the Address Element (a separate sheet). Only billing address tax applies to the L4 FC/Embedded form sheet. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
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.
Summary
automatic_taxenabled with billing address as the source, the SDK now updates the session with billing details before dismissing the FC/embedded sheetcheckout_amount_mismatcherrorInSheetCheckoutSessionUpdateras shared logic for both FlowController and Embedded pathsCheckoutSessionResponseJsonParserto read tax status fromtax_meta/tax_contextfieldswithInternalStateForInSheetUpdateto bypass theintegrationLaunchedguard (analogous to iOS'srequireOpenSessionForInSheetUpdate)Test plan
checkout.checkoutSessionStateFlow emits updated totals after dismiss🤖 Generated with Claude Code
Screen_recording_20260611_160322.mp4