Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Appstore Purchases Laravel Package

aporat/laravel-appstore-purchases

Laravel package for verifying Apple App Store in-app purchase receipts and subscriptions server-side. Validate transactions, inspect purchase data, and integrate iOS payments into your app with a simple, framework-friendly API.

View on GitHub
Deep Wiki
Context7

Product Decisions This Supports

  • Server-authoritative entitlements, not client-trusted. The Subscriptions\ layer treats webhooks and the worker as the source of truth and lets a client credential only extend access, never shorten or grant it. That is the decision that kills the most common revenue-leak and fraud vector in mobile subscriptions (a jailbroken/replayed client claiming a longer expiry), so it's a policy you can commit to rather than re-litigate per feature.
  • Build vs. buy for subscription infrastructure. This package gives you receipt validation, App Store Server Notifications, Google Play RTDN, dedupe, and a reconciliation command inside your Laravel app, with publishable migrations meaning the subscription data lives in your database. That's the "build on a library instead of paying RevenueCat a percentage" fork in the road: you keep data ownership and margin, and you accept owning the operational surface (webhook endpoints, scheduled reconciliation, secrets).
  • One entitlement row per store per account. The shape (subscriptions row per store, keyed against the account) directly supports roadmap items like: cross-platform entitlement display ("subscribed on iOS, not Android"), per-store revenue reporting, and upgrade/downgrade flows — because the data model already separates stores instead of flattening them.
  • Reconciliation as a schedulable job, not a hope. VerifyStoreSubscriptions as a command base means "our entitlement state is auditable" can be a standing operational commitment with an SLA, rather than a manual support workflow when a webhook is dropped.
  • Dedupe window on purchase recording (SubscriptionRecorder, signed transactions, Play tokens, opt-in StoreKit 1 receipts) is the decision that duplicate purchase submissions don't double-extend a subscription — protects both revenue accounting and your support queue.
  • Extensibility for store-side changes you can't schedule. Events\UnhandledNotification surfaces Apple notification types the package doesn't map (PRICE_CHANGE, MIGRATION, RESCIND_CONSENT, METADATA_UPDATE, plus future types). Product call: you can ship a response to Apple's changes on your timeline, not the package's release cadence — worth writing into the risk section of the roadmap.
  • Cost/latency budget for store APIs. Google Play access tokens are now cached and shared across requests and workers, and Google's OIDC signing certs are cached for their max-age. This moves "every request mints a token / every push refetches certs" from a scaling liability to a solved problem — it changes how confidently you can size a launch spike.
  • Sequencing signal. v5 is a maturity release, not a greenfield one: the breaking key_path → private_key change plus the aporat/store-receipt-validator ^11.1 floor means an upgrade is a discrete piece of work with a secrets-management migration, best scheduled outside a launch window.

When to Consider This Package

Consider it when all of these hold:

  • You ship a Laravel/PHP backend for a native iOS and/or Android app selling auto-renewable subscriptions or non-consumables in-app.
  • You need server-side receipt/transaction validation and webhook-driven entitlement state — i.e. you cannot trust the client and you don't want a third-party billing vendor in the money path.
  • You're willing to own the operational surface: publicly reachable notification endpoints, a secret-managed App Store In-App Purchase key and Google service account, and a scheduled reconciliation job.
  • You want subscription records in your own schema (reporting, joins to your user/org tables, data residency) rather than synced from a vendor.
  • You expect modest volume with spiky pushes — the new shared token/certificate caching plus cache locks is the difference between comfortable and rate-limited.

Look elsewhere when:

  • You need subscription management UI, analytics dashboards, churn/cohort reporting, or A/B paywall experimentation out of the box — that's RevenueCat/Adapty territory, and this package deliberately stops at validated state in your DB.
  • Your billing is web/Stripe-first — you want Laravel Cashier, not store receipt validation.
  • You're not on Laravel (or you're on a Laravel version outside the tested matrix — note the CI fix below, verify the lane you care about actually resolves).
  • You need one-off receipt validation only — the added subscription layer, migrations, and listeners are surface area you'd be carrying for nothing.
  • You can't hold secrets in a manager / can't run queue workers on schedule — the worker being authoritative is a hard dependency, not optional.
  • You want the vendor to handle store API changes and edge-case notifications for you — here that's your on-call rotation.

Adoption gate for this specific release: the key_path removal is a hard config break (a config still carrying key_path fails loudly), and APPLE_APPSTORE_KEY_PATH is no longer read. Treat the upgrade as: bump validator to ^11.1, migrate the Apple key to private_key (path or inline PEM from the secrets manager — the inline form and the whitespace/\n repair now make secrets-manager storage viable), add the google_cache block or accept its defaults, and confirm phpseclib is ^3.0.36 so Google RTDN verification doesn't 401 on every push.

How to Pitch It (Stakeholders)

For executives: This upgrade turns our in-app subscription handling from client-trusted to store-verified. Apple and Google become the authority on who's paid; our backend records it, and a client can only ever extend access, never grant it — that's direct protection against revenue leakage and refund/chargeback abuse. It also avoids handing a percentage of subscription revenue to a billing middleman while keeping the subscription data in our own database for reporting. The release itself is mostly hardening: shared Google token caching cuts per-request latency and API quota burn, and correctly-signed notifications we don't yet recognise now get recorded and surfaced as an event instead of being rejected and retried forever.

For engineering: Breaking change — key_path is gone from the apple-app-store validator; it's private_key only, accepting either a .p8 path or inline PEM (secrets-manager friendly, with collapsed line breaks repaired before OpenSSL). APPLE_APPSTORE_KEY_PATH is no longer read, and a leftover key_path fails with an explanatory message. Validator floor moves to aporat/store-receipt-validator ^11.1 and the 11.0.0 compatibility path is removed. New hard requirements: phpseclib/phpseclib ^3.0.36 (fixes RTDN push verification returning 401 for everyone when Composer resolved phpseclib 4 — google/auth is phpseclib-3-only and doesn't declare it) and psr/cache ^2.0 || ^3.0. New google_cache config (enabled, store, token_refresh_margin) shares Play access tokens across requests and workers with a cache lock on concurrent misses, falls back to a direct exchange if the store misbehaves, and never logs tokens; disabling it restores per-process minting. Google OIDC certs are cached for their max-age with a once-a-minute refetch on unknown key IDs, and the fetch now has 5s connect / 10s request timeouts — check those against your push endpoint's own timeout budget. Apple notifications of types the validator doesn't know now parse, fully verify, and dispatch UnhandledNotification instead of returning 400 and triggering Apple retries; AppleAppStoreServerNotificationController takes an optional TokenVerifier so tests can use their own signing chain. Composer dist no longer ships tests/ (including test signing keys), .github/, composer.lock, or PHPUnit/PHPStan configs. Finally, the CI matrix previously installed composer.lock in every lane, so the "Laravel 12" lanes were actually running Laravel 13 — worth re-confirming our target framework version against a green lane before we rely on the compatibility claim.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route