Events | laravel-mobile-pass | Spatie

 SPATIE

  Laravel Mobile Pass
======================

spatie.be/open-source

  [Docs](https://spatie.be/docs)  [Laravel-mobile-pass](https://spatie.be/docs/laravel-mobile-pass/v1)  Advanced-usage  Events

 Version   v1

 Other versions for crawler [v1](https://spatie.be/docs/laravel-mobile-pass/v1)

  Events
- [ Introduction ](https://spatie.be/docs/laravel-mobile-pass/v1/introduction)
- [ Support us ](https://spatie.be/docs/laravel-mobile-pass/v1/support-us)
- [ Requirements ](https://spatie.be/docs/laravel-mobile-pass/v1/requirements)
- [ Installation &amp; setup ](https://spatie.be/docs/laravel-mobile-pass/v1/installation-setup)
- [ Getting credentials from Apple ](https://spatie.be/docs/laravel-mobile-pass/v1/getting-credentials-from-apple)
- [ Getting credentials from Google ](https://spatie.be/docs/laravel-mobile-pass/v1/getting-credentials-from-google)
- [ Questions and issues ](https://spatie.be/docs/laravel-mobile-pass/v1/questions-issues)
- [ Changelog ](https://spatie.be/docs/laravel-mobile-pass/v1/changelog)
- [ About us ](https://spatie.be/docs/laravel-mobile-pass/v1/about-us)

Basic usage
-----------

- [ Generating your first pass ](https://spatie.be/docs/laravel-mobile-pass/v1/basic-usage/generating-your-first-pass)
- [ Delivering passes to users ](https://spatie.be/docs/laravel-mobile-pass/v1/basic-usage/handing-out-passes)
- [ Adding images ](https://spatie.be/docs/laravel-mobile-pass/v1/basic-usage/adding-images)
- [ Adding barcodes ](https://spatie.be/docs/laravel-mobile-pass/v1/basic-usage/adding-barcodes)
- [ Updating a pass ](https://spatie.be/docs/laravel-mobile-pass/v1/basic-usage/updating-a-pass)
- [ Retrieving mobile passes ](https://spatie.be/docs/laravel-mobile-pass/v1/basic-usage/retrieving-mobile-passes)
- [ Expiring passes ](https://spatie.be/docs/laravel-mobile-pass/v1/basic-usage/expiring-passes)

Available pass types
--------------------

- [ Introduction ](https://spatie.be/docs/laravel-mobile-pass/v1/available-pass-types/introduction)
- [ Boarding pass ](https://spatie.be/docs/laravel-mobile-pass/v1/available-pass-types/boarding-pass)
- [ Event ticket ](https://spatie.be/docs/laravel-mobile-pass/v1/available-pass-types/event-ticket)
- [ Coupon ](https://spatie.be/docs/laravel-mobile-pass/v1/available-pass-types/coupon)
- [ Loyalty card ](https://spatie.be/docs/laravel-mobile-pass/v1/available-pass-types/loyalty)
- [ Generic ](https://spatie.be/docs/laravel-mobile-pass/v1/available-pass-types/generic)

Apple Wallet
------------

- [ Field zones ](https://spatie.be/docs/laravel-mobile-pass/v1/apple-wallet/field-zones)
- [ Apple-specific methods ](https://spatie.be/docs/laravel-mobile-pass/v1/apple-wallet/apple-specific-methods)
- [ Pass relevance ](https://spatie.be/docs/laravel-mobile-pass/v1/apple-wallet/pass-relevance)
- [ NFC passes ](https://spatie.be/docs/laravel-mobile-pass/v1/apple-wallet/nfc)
- [ Attaching Wi-Fi credentials ](https://spatie.be/docs/laravel-mobile-pass/v1/apple-wallet/attaching-wifi-credentials)
- [ Storing mobile passes ](https://spatie.be/docs/laravel-mobile-pass/v1/apple-wallet/storing-mobile-passes)

Google Wallet
-------------

- [ Pass classes ](https://spatie.be/docs/laravel-mobile-pass/v1/google-wallet/pass-classes)
- [ Object methods ](https://spatie.be/docs/laravel-mobile-pass/v1/google-wallet/object-methods)
- [ Hosting pass images ](https://spatie.be/docs/laravel-mobile-pass/v1/google-wallet/hosting-images)

Advanced usage
--------------

- [ Handling errors ](https://spatie.be/docs/laravel-mobile-pass/v1/advanced-usage/handling-errors)
- [ Customizing actions ](https://spatie.be/docs/laravel-mobile-pass/v1/advanced-usage/customizing-actions)
- [ Customizing models ](https://spatie.be/docs/laravel-mobile-pass/v1/advanced-usage/customizing-models)
- [ Reading stored passes ](https://spatie.be/docs/laravel-mobile-pass/v1/advanced-usage/reading-stored-passes)
- [ Events ](https://spatie.be/docs/laravel-mobile-pass/v1/advanced-usage/events)
- [ Testing your passes ](https://spatie.be/docs/laravel-mobile-pass/v1/advanced-usage/testing-your-passes)

 Events
======

###  On this page

1. [ MobilePassAdded ](#content-mobilepassadded)
2. [ MobilePassRemoved ](#content-mobilepassremoved)
3. [ AppleMobilePassLogsReceived ](#content-applemobilepasslogsreceived)
4. [ Registering listeners ](#content-registering-listeners)
5. [ Checking whether a pass is currently in the wallet ](#content-checking-whether-a-pass-is-currently-in-the-wallet)
6. [ Querying the underlying history ](#content-querying-the-underlying-history)

The package dispatches Laravel events at key moments in the pass lifecycle so your app can react without having to extend any action classes.

MobilePassAdded
-----------------------------------------------------------------------------------------------------

The `Spatie\LaravelMobilePass\Events\MobilePassAdded` event fires when a user adds the pass to their wallet. It covers both platforms:

- Apple, when an iPhone calls the register-device endpoint after the user taps Add in Wallet. The event fires once per new `(device, pass)` registration. Re-registrations of the same device don't re-fire.
- Google, when Google sends a `save` callback for the pass.

The event carries the `MobilePass` model. If you need to branch on platform, call `$event->mobilePass->isApple()` or `$event->mobilePass->isGoogle()`, or read the full enum at `$event->mobilePass->platform`.

```
namespace App\Listeners;

use Spatie\LaravelMobilePass\Events\MobilePassAdded;

class TrackPassInstalls
{
    public function handle(MobilePassAdded $event): void
    {
        $event->mobilePass->user->update([
            'wallet_pass_installed_at' => now(),
        ]);
    }
}
```

For Apple passes this is your chance to record that a specific device has the pass. The full registration row (device id, push token, pass type) is reachable through `$event->mobilePass->registrations` if you need it.

MobilePassRemoved
-----------------------------------------------------------------------------------------------------------

The `Spatie\LaravelMobilePass\Events\MobilePassRemoved` event fires when the user removes the pass from their wallet. Like the added event, it covers both platforms:

- Apple, when the device calls the unregister-device endpoint. The event fires once per deleted registration, so a pass removed from three devices fires three times.
- Google, when Google sends a `del` callback.

Same payload shape:

```
namespace App\Listeners;

use Spatie\LaravelMobilePass\Events\MobilePassRemoved;

class ReactToUninstall
{
    public function handle(MobilePassRemoved $event): void
    {
        // e.g. send a follow-up email, flip a flag, log an analytics event
    }
}
```

On Apple, a user can keep the pass on other devices after removing it from one, so don't treat a single `MobilePassRemoved` as "the pass is gone from this user's life." If you need that, check `$event->mobilePass->registrations()->exists()` in the listener.

AppleMobilePassLogsReceived
-----------------------------------------------------------------------------------------------------------------------------------------

The `Spatie\LaravelMobilePass\Events\AppleMobilePassLogsReceived` event fires when Apple posts error log entries to the package's log endpoint (`/passkit/v1/log`). Apple devices use this to report problems they hit while handling a pass.

```
namespace App\Listeners;

use Illuminate\Support\Facades\Log;
use Spatie\LaravelMobilePass\Events\AppleMobilePassLogsReceived;

class ForwardAppleWalletLogs
{
    public function handle(AppleMobilePassLogsReceived $event): void
    {
        foreach ($event->logEntries as $line) {
            Log::channel('apple-wallet')->info($line);
        }
    }
}
```

The payload is a plain `array` of log lines. There's no Google equivalent; Google Wallet doesn't post back error logs.

Registering listeners
-----------------------------------------------------------------------------------------------------------------------

Laravel 11+ auto-discovers listeners in `app/Listeners` by convention. If you've opted into explicit registration, add entries to your `EventServiceProvider`:

```
protected $listen = [
    \Spatie\LaravelMobilePass\Events\MobilePassAdded::class => [
        \App\Listeners\TrackPassInstalls::class,
    ],
    \Spatie\LaravelMobilePass\Events\MobilePassRemoved::class => [
        \App\Listeners\ReactToUninstall::class,
    ],
];
```

Checking whether a pass is currently in the wallet
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

If you don't care about the event stream and just want to know whether the pass is installed right now, use the unified helper:

```
if ($mobilePass->isCurrentlyInWallet()) {
    // Apple: at least one device has it registered
    // Google: latest save/remove callback was a save
}
```

The helper dispatches by platform so you don't need to care which one the pass belongs to.

Querying the underlying history
-----------------------------------------------------------------------------------------------------------------------------------------------------

Both platforms also expose their raw history if you want it.

For Google, every callback is persisted as a `GoogleMobilePassEvent` row tied to the `MobilePass`:

```
$mobilePass->googleEvents;

$mobilePass->googleEvents()->saves()->get();
$mobilePass->googleEvents()->removes()->get();
```

Or use the Google-specific helper if you want just the "is it saved" check:

```
$mobilePass->isCurrentlySavedToGoogleWallet();
```

For Apple, `$mobilePass->registrations` gives you the set of currently registered devices. Every row is an `AppleMobilePassRegistration`; Google passes always have an empty collection here. An empty collection on an Apple pass means no iPhone currently has the pass installed (or the device never called the unregister endpoint, which does happen; Apple isn't strict about it).

 A good
match?
-------------

### What we do best

- All things Laravel
- Custom frontend components
- Building APIs
- AI-powered features
- Simplifying things
- Clean solutions
- Integrating services

### Not our cup of tea

- WordPress themes
- Cutting corners
- Free mockups to win a job
- "Just execute the briefing"

 In short: we'd like to be a **substantial part** of your project.

 [ Get in touch via email ](mailto:info@spatie.be?subject=A%20good%20match%21&body=Tell%20us%20as%20much%20as%20you%20can%20about%0A-%20your%20online%20project%0A-%20your%20planning%0A-%20your%20budget%0A-%20%E2%80%A6%0A%0AAnything%20that%20helps%20us%20to%20start%20straightforward%21)
