laravel-in-app-purchases

A Laravel package that validates App Store and Google Play purchase receipts and manages the full in-app subscription lifecycle.

Library
Composer
v1.19.0
389stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
61/100Good
Development Activity44
Maintenance48
Community64
Maturity60
Momentum28

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
73/100Good
Architecture80
Code Quality78
Innovation62
Learning Curve70

imdhemy/laravel-purchases (published on Packagist as laravel-purchases, developed under the laravel-in-app-purchases GitHub repo) gives Laravel applications a unified way to handle in-app purchases sold through Apple’s App Store and Google Play. Mobile purchase and subscription events happen inside the native store, and the backend needs a reliable way to hear about them, verify they’re genuine, and react to state changes like renewal, cancellation, grace period, or refund.

The package wraps both stores’ server-to-server notification formats (App Store Server Notifications v1/v2 and Google’s Real-time Developer Notifications) behind one Laravel-native interface: a service provider, Product and Subscription facades, a signed webhook route, and a typed event for every notification type each store can send. Receipt/JWS verification, JWT signing for App Store Server API calls, and provider-specific payload parsing are handled internally via the maintainer’s companion packages (imdhemy/appstore-iap, imdhemy/google-play-billing).

It targets teams shipping a mobile app with IAP or subscriptions who need their Laravel backend to stay in sync with entitlement state without hand-rolling receipt validation and webhook signature checks for two different vendors.

What You Get

  • A signed, configurable webhook route that accepts both App Store (v1 and v2/JWS) and Google Play RTDN payloads and dispatches the correct handler automatically
  • A Product facade and a Subscription contract for querying purchase/subscription state and verifying receipts directly against Apple and Google
  • Over 25 typed Laravel events (one per App Store and Google Play notification subtype: renewal, cancellation, grace period, price increase, refund, hold, and more) that you can attach listeners to individually
  • Artisan commands to publish config, generate the signed webhook URL for store console setup, and send a real test notification from Apple’s servers
  • JWS/JWT handling for App Store Server API authentication built in, so you don’t need a separate library for Apple’s newer notification format

Common Use Cases

  • Sync a user’s subscription tier in your database whenever Apple or Google reports a renewal, cancellation, or billing issue
  • Verify a receipt server-side immediately after a mobile client reports a completed purchase, before granting entitlement
  • Revoke access automatically on refund or chargeback notifications from either store
  • Acknowledge or consume a Google Play one-time product purchase per Google’s required purchase flow
  • Register the signed webhook URL with App Store Connect / Google Play Console via the built-in Artisan command instead of building the URL by hand

Under The Hood

Architecture The package registers itself through LiapServiceProvider, which merges config, boots a signed route group pointing at ServerNotificationController, and binds a small set of contracts (EventFactoryContract, UrlGeneratorContract, HandlerHelpersInterface, JwsServiceInterface) to concrete implementations. Incoming webhook requests flow through HandlerFactory::create(), which inspects the provider query param (and the presence of a signedPayload field to distinguish legacy App Store notifications from the newer JWS-based v2 format) and resolves one of AppStoreNotificationHandler, AppStoreV2NotificationHandler, or GooglePlayNotificationHandler out of the container. Each handler extends AbstractNotificationHandler, which centralizes signed-URL authorization, payload validation, and event dispatch, then delegates the payload-specific parsing to a per-provider EventFactory that maps the raw notification type to one of ~25 concrete event classes under src/Events/AppStore and src/Events/GooglePlay. This handler-factory-plus-event-factory layering means adding a new notification type is additive (a new event class + a match arm), and the core request lifecycle never changes.

Tech Stack PHP 8.4+ targeting Laravel 11+, distributed via Composer as imdhemy/laravel-purchases. It depends on two sibling packages from the same maintainer, imdhemy/appstore-iap (^1.9) and imdhemy/google-play-billing (^1.5), which do the actual HTTP calls to Apple’s and Google’s verification/receipt endpoints over Guzzle, plus lcobucci/jwt for decoding and verifying the JWS-signed App Store Server Notifications v2 payloads. Dev tooling is Psalm (via psalm/plugin-laravel) for static analysis, PHPUnit with Orchestra Testbench for package-context testing, and PHP-CS-Fixer for style, all wired into a GitHub Actions matrix across PHP 8.4 and 8.5.

Code Quality The tests/ directory mirrors src/ closely — dedicated suites for server notifications, subscriptions, facades, event factories, and a Feature/ directory that exercises the full webhook flow end-to-end (HandleAppStoreNotificationFeatureTest, HandleGoogleNotificationFeatureTest, HandleLegacyAppStoreNotificationFeatureTest), plus hand-written test doubles under tests/Doubles/ for the JWS verifier and test-notification service. CI runs the full suite, a Psalm static-analysis pass, and a coding-style check on every push, and the package uses declare(strict_types=1) throughout with typed properties and constructor promotion. Error handling favors explicit typed exceptions (InvalidNotificationTypeException, LiapException) over silent failure, and unauthorized/unsigned webhook requests are rejected via Laravel’s own AuthorizationException.

What Makes It Unique Most Laravel IAP integrations only cover Apple’s legacy notification format or leave Google Play’s RTDN parsing to the consumer; this package normalizes both stores’ current and legacy notification formats behind one handler-factory abstraction and turns every distinct lifecycle event Apple and Google can emit into its own strongly-typed Laravel event class, rather than a single generic “notification received” event with a raw payload to inspect. Combined with the Artisan command that generates the exact signed URL to paste into App Store Connect or the Play Console, it removes most of the plumbing work that would otherwise be reimplemented per project.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search