PHPackages                             bestys-mobile/lumen-purchases - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. bestys-mobile/lumen-purchases

ActiveLibrary[API Development](/categories/api)

bestys-mobile/lumen-purchases
=============================

Lumen receipt validator for Apple and Google Play

v0.1.0(5y ago)013MITPHPPHP &gt;=7.1

Since Jan 6Pushed 5y ago1 watchersCompare

[ Source](https://github.com/bestys-mobile/lumen-purchases)[ Packagist](https://packagist.org/packages/bestys-mobile/lumen-purchases)[ RSS](/packages/bestys-mobile-lumen-purchases/feed)WikiDiscussions master Synced 2d ago

READMEChangelog (1)Dependencies (8)Versions (2)Used By (0)

[![Laravel In-app Purchase cover](cover.png)](cover.png)

 [![Packagist PHP Version Support](https://camo.githubusercontent.com/51f0d5f99aa9a81ffcf7fb616e3afbb3706b963b90e2541aa11a647eb367cf95/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f696d6468656d792f6c61726176656c2d707572636861736573)](https://camo.githubusercontent.com/51f0d5f99aa9a81ffcf7fb616e3afbb3706b963b90e2541aa11a647eb367cf95/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f696d6468656d792f6c61726176656c2d707572636861736573) [![Latest Version on Packagist](https://camo.githubusercontent.com/ced3d2dee4c2d3f018c1effe39623c4ddc4cb09ed420a76a6115ca6b6a97e270/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f696d6468656d792f6c61726176656c2d7075726368617365732e7376673f7374796c653d666c61742d737175617265)](https://camo.githubusercontent.com/ced3d2dee4c2d3f018c1effe39623c4ddc4cb09ed420a76a6115ca6b6a97e270/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f696d6468656d792f6c61726176656c2d7075726368617365732e7376673f7374796c653d666c61742d737175617265) [![Total Downloads](https://camo.githubusercontent.com/dd3cfae4d92f2f32bae830461a12c18814c783b35c3c8756e9750b9be6f2e530/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f696d6468656d792f6c61726176656c2d7075726368617365732e7376673f7374796c653d666c61742d737175617265)](https://camo.githubusercontent.com/dd3cfae4d92f2f32bae830461a12c18814c783b35c3c8756e9750b9be6f2e530/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f696d6468656d792f6c61726176656c2d7075726368617365732e7376673f7374796c653d666c61742d737175617265) [![GitHub last commit](https://camo.githubusercontent.com/a264200db5ee5aa00808fdfe9d04db9e4afec4d0a69c1c4bdba3bb56aec58cf4/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6173742d636f6d6d69742f696d6468656d792f6c61726176656c2d696e2d6170702d707572636861736573)](https://camo.githubusercontent.com/a264200db5ee5aa00808fdfe9d04db9e4afec4d0a69c1c4bdba3bb56aec58cf4/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6173742d636f6d6d69742f696d6468656d792f6c61726176656c2d696e2d6170702d707572636861736573)

 ✅ App Store ✅ Google Play

Laravel In-App purchase
=======================

[](#laravel-in-app-purchase)

Google Play and App Store provide the In-App Purchase (IAP) services. IAP can be used to sell a variety of content, including subscriptions, new features, and services. The purchase event and the payment process occurs on and handled by the mobile application (iOS and Android), then your backend needs to be informed about this purchase event to deliver the purchased product or update the user's subscription state.

**Laravel In-App purchase** comes to help you to parse and validate the purchased products and handle the different states of a subscription, like New subscription , auto-renew, cancellation, expiration and etc.

Table of contents
=================

[](#table-of-contents)

- [Installation](#installation)
- [Configuration](#configuration)
    - [i. Generic Configurations:](#i-generic-configurations)
        - [i.1 Routing](#i1-routing)
        - [i.2 Event Listeners](#i2-event-listeners)
    - [ii. Google Play Configurations:](#ii-google-play-configurations)
        - [ii.1 Google Application Credentials](#ii1-google-application-credentials)
        - [ii.2 Google Play Package Name](#ii2-google-play-package-name)
    - [iii. App Store Configurations](#iii-app-store-configurations)
        - [iii.1 App Store Sandbox](#iii1-app-store-sandbox)
        - [iii.2 App Store Password](#iii2-app-store-password)
- [Sell Products](#sell-products)
    - [Google Products](#google-products)
    - [App Store Products](#app-store-products)
- [Sell Subscriptions](#sell-subscriptions)
    - [Google Play Subscriptions](#google-play-subscriptions)
    - [App Store Subscriptions](#app-store-subscriptions)
- [Purchase Events](#purchase-events)
- [Testing](#testing)

Installation
============

[](#installation)

Install the package via composer:

`composer require imdhemy/laravel-purchases`

Publish the config file:

`php artisan vendor:publish --provider="Bestys\Purchases\PurchaseServiceProvider" --tag="config"`

Configuration
=============

[](#configuration)

The published config file `config/purchase.php` looks like:

```
return [
    'routing' => [],

    'google_play_package_name' => env('GOOGLE_PLAY_PACKAGE_NAME', 'com.example.name'),

    'appstore_sandbox' => env('APPSTORE_SANDBOX', true),

    'appstore_password' => env('APPSTORE_PASSWORD', ''),

    'eventListeners' => [
        /**
         * --------------------------------------------------------
         * Google Play Events
         * --------------------------------------------------------
         */
        SubscriptionPurchased::class => [],
        SubscriptionRenewed::class => [],
        SubscriptionInGracePeriod::class => [],
        SubscriptionExpired::class => [],
        SubscriptionCanceled::class => [],
        SubscriptionPaused::class => [],
        SubscriptionRestarted::class => [],
        SubscriptionDeferred::class => [],
        SubscriptionRevoked::class => [],
        SubscriptionOnHold::class => [],
        SubscriptionRecovered::class => [],
        SubscriptionPauseScheduleChanged::class => [],
        SubscriptionPriceChangeConfirmed::class => [],

        /**
         * --------------------------------------------------------
         * Appstore Events
         * --------------------------------------------------------
         */
        Cancel::class => [],
        DidChangeRenewalPref::class => [],
        DidChangeRenewalStatus::class => [],
        DidFailToRenew::class => [],
        DidRecover::class => [],
        DidRenew::class => [],
        InitialBuy::class => [],
        InteractiveRenewal::class => [],
        PriceIncreaseConsent::class => [],
        Refund::class => [],
    ],
];
```

Each configuration option is illustrated in the [configuration section](#configuration).

i. Generic Configurations:
--------------------------

[](#i-generic-configurations)

The generic configurations are not specific to a particular provider of the two supported providers (Google and Apple).

### i.1 Routing

[](#i1-routing)

This package adds two `POST` endpoints to receive the [Real-Time Developer Notifications](https://developer.android.com/google/play/billing/rtdn-reference), and the [The App Store Server Notifications](https://developer.apple.com/documentation/appstoreservernotifications).

ProviderURINameGoogle Play`/purchases/subscriptions/google``purchase.serverNotifications.google`App Store`/purchases/subscriptions/apple``purchase.serverNotifications.apple`These routes can be configured through the `routing` key in the config file. For example:

```
[
    // ..
   'routing' => [
        'middleware' => 'api',
        'prefix' => 'my_prefix'
    ],
    // ..
];
```

### i.2 Event Listeners

[](#i2-event-listeners)

Your application should handle the different states of a subscription life. Each state update triggers a specified event. You can create an event listener to update your backend on each case.

```
use Bestys\Purchases\Events\GooglePlay\SubscriptionRenewed;

class AutoRenewSubscription
{
    /**
    * @param SubscriptionRenewed $event
    */
    public function handle(SubscriptionRenewed $event)
    {
        // do some stuff
    }
}
```

Add the created listener to the associated event key.

```
    // ..
        SubscriptionRenewed::class => [AutoRenewSubscription::class],
    // ..
```

All events extend the `\Bestys\Purchases\Events\PurchaseEvent` abstract class, which implements the `\Bestys\Purchases\Contracts\PurchaseEventContract` interface. Check the [Purchase Events section](#purchase-events) for more information.

ii. Google Play Configurations:
-------------------------------

[](#ii-google-play-configurations)

The following set of configurations are specific to google play:

### ii.1 Google Application Credentials

[](#ii1-google-application-credentials)

Requests to the Google Play Developer API, requires authentication and scopes. To authenticate your machine create a service account, then upload the downloaded JSON file `google-app-credentials.json` to your server, and finally add `GOOGLE_APPLICATION_CREDENTIALS` key to your `.env` file and set it to the path of JSON file.

1. In the Cloud Console, go to the [Create service account](https://console.cloud.google.com/apis/credentials/serviceaccountkey?_ga=2.92610013.131807880.1603050486-1132570079.1602633482) key page.
2. From the **Service account** list, select **New service account**.
3. In the **Service account name** field, enter a name.
4. From the **Role** list, select **Project** &gt; **Owner**.
5. Click **Create**. A JSON file that contains your key downloads to your computer.
6. Upload the JSON file to your storage directory, or any other protected directory.
7. Set the `.env` key `GOOGLE_APPLICATION_CREDENTIALS` to the JSON file path.

### ii.2 Google Play Package Name

[](#ii2-google-play-package-name)

The package name of the application for which this subscription was purchased (for example, 'com.some.thing').

iii. App Store Configurations
-----------------------------

[](#iii-app-store-configurations)

The following set of configurations are specific to the App Store.

### iii.1 App Store Sandbox

[](#iii1-app-store-sandbox)

The configuration key `appstore_sandbox` is a boolean value that determines whether the requests sent to the App Store are in the sandbox or not.

### iii.2 App Store Password

[](#iii2-app-store-password)

Request to the App Store requires the key `appstore_password` to be set. Your app’s shared secret, which is a hexadecimal string.

Sell Products
=============

[](#sell-products)

Google Products
---------------

[](#google-products)

You can use the `\Bestys\Purchases\Facades\Product` facade to acknowledge or to get the receipt data from Google Play as follows:

```
use \Bestys\Purchases\Facades\Product;
use \Bestys\GooglePlay\Products\ProductPurchase;

$itemId = 'product_id';
$token = 'purchase_token';

Product::googlePlay()->id($itemId)->token($token)->acknowledge();
// You can optionally submit a developer payload
Product::googlePlay()->id($itemId)->token($token)->acknowledge("your_developer_payload");

/** @var ProductPurchase $productReceipt */
$productReceipt = Product::googlePlay()->id($itemId)->token($token)->get();
```

Each key has a getter method prefixed with `get`, for example: `getKind()` to get the `kind` value. For more information check:

1. [Google Developer documentation](https://developers.google.com/android-publisher/api-ref/rest/v3/purchases.products/get).
2. [PHP Google Play Billing Package](https://github.com/imdhemy/google-play-billing#get-the-consumption-state-of-a-product).

App Store Products
------------------

[](#app-store-products)

You can use the `\Bestys\Purchases\Facades\Product` to send a [verifyReceipt](https://developer.apple.com/documentation/appstorereceipts/verifyreceipt) request to the App Store. as follows:

```
use Bestys\AppStore\Receipts\ReceiptResponse;
use \Bestys\Purchases\Facades\Product;

$receiptData = 'the_base64_encoded_receipt_data';
/** @var ReceiptResponse $receiptResponse */
$receiptResponse = Product::appStore()->receiptData($receiptData)->verifyReceipt();
```

As usual each key has a getter method.

For more information check:

1. [App Store Documentation](https://developer.apple.com/documentation/appstorereceipts/responsebody)
2. [PHP App Store IAP package](https://github.com/imdhemy/appstore-iap)

Sell Subscriptions
==================

[](#sell-subscriptions)

Google Play Subscriptions
-------------------------

[](#google-play-subscriptions)

You can use the `\Bestys\Purchases\Facades\Subscription` facade to acknowledge or to get the receipt data from Google Play as follows:

```
use Bestys\GooglePlay\Subscriptions\SubscriptionPurchase;
use Bestys\Purchases\Facades\Subscription;

$itemId = 'product_id';
$token = 'purchase_token';

Subscription::googlePlay()->id($itemId)->token($token)->acknowledge();
// You can optionally submit a developer payload
Subscription::googlePlay()->id($itemId)->token($token)->acknowledge("your_developer_payload");

/** @var SubscriptionPurchase $subscriptionReceipt */
$subscriptionReceipt = Subscription::googlePlay()->id($itemId)->token($token)->get();
// You can optionally override the package name
Subscription::googlePlay()->packageName('com.example.name')->id($itemId)->token($token)->get();
```

The `SubscriptionPurchase` resource indicates the status of a user's inapp product purchase. This is its JSON Representation:

For more information check:

1. [Google Developer documentation](https://developers.google.com/android-publisher/api-ref/rest/v3/purchases.subscriptions/get).
2. [PHP Google Play Billing Package](https://github.com/imdhemy/google-play-billing#handling-the-subscription-lifecycle).

App Store Subscriptions
-----------------------

[](#app-store-subscriptions)

You can use the `\Bestys\Purchases\Facades\Subscription` to send a [verifyReceipt](https://developer.apple.com/documentation/appstorereceipts/verifyreceipt) request to the App Store. as follows:

```
use Bestys\Purchases\Facades\Subscription;
// To verify a subscription receipt
$receiptData = 'the_base64_encoded_receipt_data';
$receiptResponse = Subscription::appStore()->receiptData($receiptData)->verifyReceipt();

// If the subscription is an auto-renewable one,
//call the renewable() method before the trigger method verifyReceipt()
$receiptResponse = Subscription::appStore()->receiptData($receiptData)->renewable()->verifyReceipt();

// or you can omit the renewable() method and use the verifyRenewable() method instead
$receiptResponse = Subscription::appStore()->receiptData($receiptData)->verifyRenewable();
```

For more information check:

1. [Validating Receipts with the App Store](https://developer.apple.com/documentation/storekit/in-app_purchase/validating_receipts_with_the_app_store)
2. [PHP App Store IAP package](https://github.com/imdhemy/appstore-iap)

Purchase Events
===============

[](#purchase-events)

As mentioned the [configuration section](#i2-event-listeners), Your application should handle the different states of a subscription life. Each state update triggers a specified event. You can create an event listener to update your backend on each case.

All triggered events implement `Bestys\Purchases\Contracts\PurchaseEventContract` interface, which allows you to get a standard representation of the received notification through the `getServerNotification()` method.

The retrieved notification is of type `\Bestys\Purchases\Contracts\ServerNotificationContract` which allows you to get a standard representation of the subscription using the `getSubscription()` method.

The subscription object provides the following methods:

1. `getExpiryTime()` returns a `Time` object that tells the expiration time of the subscription.
2. `getItemId()` returns the purchased subscription id.
3. `getProvider()` returns the provider of this subscription, either `google_play` or `app_store`.
4. `getUniqueIdentifier()` returns a unique identifier for this subscription.
5. `getProviderRepresentation()` returns either `SubscriptionPurchase` or `ReceiptResponse` based on the provider.

Here is an example of an auto-renewed subscription:

```
use Bestys\Purchases\Events\GooglePlay\SubscriptionRenewed;

class AutoRenewSubscription
{
    /**
    * @param SubscriptionRenewed $event
    */
    public function handle(SubscriptionRenewed $event)
    {
       // The following data can be retrieved from the event
       $notification = $event->getServerNotification();
       $subscription = $notification->getSubscription();
       $uniqueIdentifier = $subscription->getUniqueIdentifier();
       $expirationTime = $subscription->getExpiryTime();

       // The following steps are up to you, this is only an imagined scenario.
       $user = $this->findUserBySubscriptionId($uniqueIdentifier);
       $user->getSubscription()->setExpirationTime($expirationTime);
       $user->save();

       $this->notifyUserAboutUpdate($user);
    }
}
```

Testing
=======

[](#testing)

TODO: add testing examples.

###  Health Score

19

—

LowBetter than 10% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity5

Limited adoption so far

Community4

Small or concentrated contributor base

Maturity38

Early-stage or recently created project

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

1953d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/77055705?v=4)[bestys-mobile](/maintainers/bestys-mobile)[@bestys-mobile](https://github.com/bestys-mobile)

---

Tags

lumengoogle\_playin\_app\_purchaseslumen-in-app-purchases

###  Code Quality

TestsPHPUnit

Static AnalysisPsalm

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/bestys-mobile-lumen-purchases/health.svg)

```
[![Health](https://phpackages.com/badges/bestys-mobile-lumen-purchases/health.svg)](https://phpackages.com/packages/bestys-mobile-lumen-purchases)
```

###  Alternatives

[spatie/laravel-fractal

An easy to use Fractal integration for Laravel applications

1.9k15.1M99](/packages/spatie-laravel-fractal)[flugger/laravel-responder

A Laravel Fractal package for building API responses, giving you the power of Fractal and the elegancy of Laravel.

8901.5M5](/packages/flugger-laravel-responder)[mollie/laravel-mollie

Mollie API client wrapper for Laravel &amp; Mollie Connect provider for Laravel Socialite

3624.1M28](/packages/mollie-laravel-mollie)[vluzrmos/slack-api

Wrapper for Slack.com WEB API.

102589.1k3](/packages/vluzrmos-slack-api)[darkaonline/swagger-lume

OpenApi or Swagger integration to Lumen

3372.3M3](/packages/darkaonline-swagger-lume)[nilportugues/jsonapi-bundle

Symfony 2 &amp; 3 JSON API Transformer Package

11446.0k](/packages/nilportugues-jsonapi-bundle)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
