imdhemy/laravel-purchases
Laravel Purchases helps you validate and manage in-app purchases and subscriptions from Apple App Store and Google Play. It provides receipt verification, server notification handling, and subscription lifecycle tools with a Laravel-friendly API.
Architecture fit. imdhemy/laravel-purchases sits at the exact seam where a Laravel backend meets the mobile app stores: it wraps Apple App Store / StoreKit 2 and Google Play Billing receipt validation behind a small set of contracts (Receipt, Purchase, Subscription, Transaction) and a Purchases facade, plus optional webhook routes for App Store Server Notifications V2 and Google Real-time Developer Notifications. For a Laravel monolith or modular monolith with a server-authoritative entitlement model, that is a clean fit — it is a library, not a service, so it introduces no new runtime, no new datastore, and no vendor contract. It is a poor fit for teams who want entitlement logic outsourced entirely (RevenueCat/Superwall territory) or for polyglot stacks where PHP is not the system of record for purchases.
Integration feasibility. High. Standard Composer install, publishable config, publishable migrations, service provider auto-discovery. Credentials are configuration-driven (Apple shared secret / .p8 API key + issuer ID + key ID; Google service-account JSON). The main integration work is not the package — it is the surrounding plumbing: secure secret storage, a public HTTPS webhook endpoint, GCP Pub/Sub topic + push subscription for Google, and an internal entitlement model that the package's models should not replace.
Technical risk.
verifyReceipt endpoint in favor of the App Store Server API; Google Play Billing has moved through several major versions. A wrapper library must chase both. Release cadence is a positive signal — 1.19.2 → 1.20.0 shipped with a focused feature (immutable subscription and renewal dates, PR #533) rather than a stall — but it remains a single-maintainer project (bus factor 1) with MIT licensing and zero dependent packages — meaning no downstream library has stress-tested its interfaces, and there is no ecosystem pressure to preserve backward compatibility.Subscription model — the exact surface the "don't use the shipped tables as your system of record" guidance is meant to insulate you from. Teams that consumed these attributes directly will see changed object semantics (immutability affects in-place mutation patterns, ->addDay()-style code, and JSON/array serialization shape) even without a schema migration.Purchase/Subscription tables as your system of record couples your domain to a third-party schema — and, as of 1.20.0, to its date-casting conventions.Key questions.
Subscription date attributes directly (API resources, reporting jobs, admin screens)? If yes, 1.20.0 requires a compatibility check on immutable-date semantics before adoption.Stack fit. Requires a modern PHP/Laravel baseline (PHP 8.x, Laravel 10+). Assumes a queue-capable runtime (Redis/SQS/database queue) and a relational database for persistence. It fits a Laravel-first organization with an existing entitlement or account service; it does not fit organizations standardizing on a mobile-BFF in Node/Go or on a managed entitlement vendor.
Migration path. The package is best adopted behind an internal adapter interface (EntitlementGateway) rather than called directly from controllers. That makes three migration scenarios tractable: (a) from hand-rolled cURL validation — the adapter absorbs the difference and lets you shadow-run both paths and diff results; (b) from RevenueCat or a similar vendor — the adapter becomes a swap point, so vendor exit is a strategy decision rather than a rewrite; (c) greenfield — build the adapter first so the package is replaceable before it is load-bearing. The 1.20.0 date-casting change is precisely the kind of churn this boundary absorbs; it is a second concrete argument for building the adapter before the first production call.
Compatibility. Pin the exact version and lockfile; verify the PHP/Laravel support matrix against your platform version before committing. 1.20.0 is a minor release and reads as additive/non-breaking, but "immutable dates" is a behavioral change to model attributes, not a new endpoint — so the compatibility check is: (i) run your existing test suite against 1.20.0, (ii) diff serialized subscription payloads before/after, (iii) confirm no code mutates the returned date objects in place, and (iv) confirm no migration is required or, if one ships, that it coexists with your schema conventions (UUIDs vs. auto-increment, timestamps, soft deletes). Watch transitive dependencies on Google API client and Guzzle, which often conflict with other installed packages.
Sequencing.
Do not start with both platforms in parallel; the second platform is where the abstraction either holds or breaks. Upgrade to future minors (1.21.x+) on a defined cadence — monthly review, quarterly adoption — rather than at release time.
Maintenance. Low surface area (no infrastructure, no sidecar) but non-zero ongoing cost: platform API deprecations, credential rotation (Apple .p8 keys, Google service accounts), and dependency bumps. 1.20.0 does not change this budget, but it does illustrate the shape of the cost: a small, well-scoped feature release that still requires a read of the diff and a test run because it touches model semantics. Budget roughly 1–2 engineer-days per month plus an unplanned 1–2 week surge once or twice a year when Apple or Google ships a breaking change. Treat the pinned version as a deliberate decision with a documented upgrade owner.
Support. No commercial SLA; MIT-licensed community project with a single primary maintainer. There is no vendor to escalate to. Mitigation: wrap behind the adapter, keep a fork-ready posture, and pre-authorize a "maintain ourselves if abandoned" contingency in the technical roadmap. The zero-dependents metric means upstream interface changes will not be socially dampened by other consumers — you are effectively the first integrator for any breaking change. The 1.20.0 release is mildly reassuring on liveness (active, reviewable, scoped changes) but does not move the bus-factor number.
Scaling. Validation calls are network-bound to Apple/Google, so they must be queued and cached (validation results, Google OAuth tokens, Apple keys). Webhook handlers must be idempotent and ordering-tolerant — assume duplicates and out-of-order delivery. Plan for monotonically growing notification-history tables with a retention/archive policy. Throughput is generally modest (purchase and renewal events, not request-path traffic), so the scaling story is about correctness under retry, not raw QPS.
Failure modes to instrument explicitly.
Ramp-up. Expect 2–4 weeks for one mid-level backend engineer to reach production confidence on the first platform, plus a second engineer for cross-review on the security boundary (webhook auth, secret handling) and one mobile engineer for sandbox test harnesses. Prerequisites that are frequently underestimated: App Store Connect Admin and Play Console Admin access, a GCP project with Pub/Sub permissions, and a publicly reachable HTTPS endpoint in the environment where webhooks land — none of which the TPM can defer to the integration week.
TPM recommendation. Adopt, but as a validated implementation detail behind an internal entitlement abstraction, not as the domain model. The package is recent, well-shaped, and appropriately licensed; 1.20.0 is a small, contained feature release that reinforces the liveness signal without changing the risk profile. The material risks remain single-maintainer dependency and the inherent volatility of store APIs — both contained by the adapter boundary and a reconciliation job. Gate the decision on the week-one spike proving credential flow and notification signature verification on real sandbox traffic, and add the 1.20.0 date-semantics check to that spike's exit criteria.
How can I help you explore Laravel packages today?