Trigger /redeem after a successful native purchase#490
Draft
claude[bot] wants to merge 2 commits into
Draft
Conversation
A successful native (App Store) purchase only refreshed entitlements locally via `loadPurchasedProducts` and never called `/redeem`, so a new subscription for an already-identified user wasn't linked to them server-side until another trigger fired. Call `webEntitlementRedeemer.redeem(.existingCodes)` after `loadPurchasedProducts` in `TransactionManager.loadPurchasedProductsIfNeeded` so the freshly-loaded receipts + appTransactionId are pushed to the backend on every native purchase. This is the single funnel for both SK1 and SK2 purchases and, being gated by `shouldSkipReceiptLoading`, skips custom/web products and test mode. Restores go through `didRestore` and are unaffected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UrsXRkhSGciN62RK7mVpBV
Extend SW-5516 (already redeeming after a native purchase) to also fire webEntitlementRedeemer.redeem(.existingCodes) on the successful restore path. Added in TransactionManager.didRestore, which is only reached after a restore succeeds and after receipts/entitlements have been reloaded, so a freshly-restored subscription is linked to the identified user server-side. Skipped in test mode, mirroring the purchase path's shouldSkipReceiptLoading gate. Updated the purchase-path comment and CHANGELOG accordingly.
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.
Requested by David Granzin · Slack thread
Changes in this pull request
Before: A successful native (App Store) purchase only refreshed entitlements locally via
receiptManager.loadPurchasedProducts. It never called/redeem, so when an already-identified user started a new native subscription, that subscription was not linked to them server-side until some unrelated trigger fired (deep-link code, identity set, config reset, attribution change, or the one-time appTransactionId registration). Successful restores had the same gap.After: Per Linear SW-5516 ("always call redeem after a successful purchase & on restore"),
/redeemnow fires on both paths: after a successful native purchase and after a successful restore. Each call carries the fresh device receipts +appTransactionId, so new subscriptions are linked to the user on the backend immediately after the purchase or restore completes.How
Two success-only hooks, both re-sending the current codes plus the freshly-loaded native receipts and
appTransactionIdviaSuperwall.shared.dependencyContainer.webEntitlementRedeemer.redeem(.existingCodes)(seeWebEntitlementRedeemer.createRedeemRequest):Sources/SuperwallKit/StoreKit/Transactions/TransactionManager.swift,loadPurchasedProductsIfNeeded(for:)callsredeem(.existingCodes)right afterreceiptManager.loadPurchasedProducts(config: nil). This is the single funnel that both SK1 and SK2 purchases settle through (purchase→handle(result:state:)→didPurchase()), so no per-purchaser edits are needed.didRestorepath callsredeem(.existingCodes)after a successful restore, so restored subscriptions are linked server-side just like fresh purchases.Both calls sit behind the existing test-mode /
shouldSkipReceiptLoadingguards, so they are skipped for custom/web (Stripe) products and in test mode, and both fire only on success. It matches the existing access pattern used byReceiptManagerfor the one-time appTransactionId registration.Checklist
CHANGELOG.mdfor any breaking changes, enhancements, or bug fixes.swiftlintin the main directory and fixed any issues.Generated by Claude Code