Skip to content

[EXTERNAL] feat: expose revocationDate and revocationReason on StoreTransaction#6962

Merged
rickvdl merged 1 commit into
RevenueCat:external/feat-storetransaction-revocationfrom
mvanhorn:feat/6515-storetransaction-revocation
Jun 16, 2026
Merged

[EXTERNAL] feat: expose revocationDate and revocationReason on StoreTransaction#6962
rickvdl merged 1 commit into
RevenueCat:external/feat-storetransaction-revocationfrom
mvanhorn:feat/6515-storetransaction-revocation

Conversation

@mvanhorn

@mvanhorn mvanhorn commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Checklist

  • If applicable, unit tests
  • If applicable, create follow-up issues for purchases-android and hybrids

Motivation

Resolves #6515.

StoreKit 2 exposes Transaction.revocationDate and Transaction.revocationReason, but StoreTransaction does not surface either. Apps using CustomEntitlementComputation, transaction-history UIs, and custom refund analytics need to read revocation data directly off the transaction. A maintainer responded positively to the reporter's proposal.

Description

Adds revocationDate and revocationReason to StoreTransaction, mirroring the existing TransactionReason pattern.

  • revocationDate is exposed as @objc public var revocationDate: Date?.
  • revocationReason is a new public RevocationReason value type. Per the repo's no_new_public_enums rule, it is a RawRepresentable struct (not an enum) with .developerIssue / .other constants, so adding cases later stays source-compatible. Because it is a Swift struct it cannot be @objc, so the property is Swift-only (documented inline); revocationDate remains Obj-C accessible.
  • Populated from the underlying transaction in SK2StoreTransaction (iOS 15+); nil for SK1, test, simulated, and mock conformers.

Both fields are additive and nil-defaulted — no breaking change. swift build of the RevenueCat target passes.

Note: I was not able to regenerate the api/*.swiftinterface baselines locally (they require the multi-platform API digester). The check-api-changes job will flag the additive public surface; the baselines need to be regenerated for these intentional additions.

This PR scopes to revocationReason (.developerIssue / .other, iOS 15+). The separate iOS 26.4 Transaction.RevocationType (.proratedRefund etc.) is intentionally left for a follow-up.

AI was used for assistance.


Note

Low Risk
Additive, nil-defaulted public API with no changes to purchase or entitlement logic; only surfaces existing SK2 metadata.

Overview
StoreTransaction now exposes revocationDate and revocationReason so apps can read App Store refund/revocation metadata from StoreKit 2, matching the existing TransactionReason pattern.

A new public RevocationReason RawRepresentable struct (.developerIssue, .other) maps from SK2 and logs unknown values via sk2_unknown_revocation_reason. SK2StoreTransaction copies revocationDate and mapped revocationReason from the underlying transaction; SK1, mocks, simulated, test, and deprecated backend-parsed transactions return nil. revocationDate is @objc; revocationReason is Swift-only. API testers and unit tests cover the new surface.

Reviewed by Cursor Bugbot for commit 2986c95. Bugbot is set up for automated code reviews on this repo. Configure here.

@mvanhorn mvanhorn requested review from a team as code owners June 9, 2026 11:53
@rickvdl rickvdl changed the base branch from main to external/feat-storetransaction-revocation June 16, 2026 05:56

@rickvdl rickvdl left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looking great! Will make a slight change to the RevocationReason type before merging in order to keep Objc support, but other than that it's great as it is.

Thanks for your contribution! 🙌

@rickvdl rickvdl merged commit 79aedef into RevenueCat:external/feat-storetransaction-revocation Jun 16, 2026
3 checks passed
@rickvdl rickvdl changed the title feat: expose revocationDate and revocationReason on StoreTransaction [EXTERNAL] feat: expose revocationDate and revocationReason on StoreTransaction Jun 16, 2026
rickvdl pushed a commit that referenced this pull request Jun 16, 2026
…6515) (#6962)

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
rickvdl pushed a commit that referenced this pull request Jun 16, 2026
…6515) (#6962)

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
rickvdl added a commit that referenced this pull request Jun 16, 2026
…ransaction via @mvanhorn (#7012)

* feat: expose revocationDate and revocationReason on StoreTransaction (#6515) (#6962)

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>

* Add Objc support to the RevocationReason type

* Add RevocationReason to xcodeproj

* Fix RevocationReason StoreKit 2 compatibility

* Use canonical RevocationReason values for SK2 mapping

* Update baseline swiftinterface files

* Fix RevocationReason identity test

---------

Co-authored-by: Matt Van Horn <mvanhorn@users.noreply.github.com>
Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: RCGitBot <dev+RCGitBot@revenuecat.com>
@mvanhorn

Copy link
Copy Markdown
Contributor Author

Appreciate you merging this, @rickvdl. Exposing revocationDate and revocationReason gives callers the refund signal they were missing.

@mvanhorn

Copy link
Copy Markdown
Contributor Author

Thanks @rickvdl. Exposing revocationDate and revocationReason on StoreTransaction fills a real gap for anyone reconciling refunds against StoreKit 2.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Expose revocationDate and revocationReason on StoreTransaction (including iOS 26.4 RevocationType.proratedRefund)

2 participants