Pass personalization | 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)  Apple-wallet  Pass personalization

 Version   v1      

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

  Pass personalization    
- [ 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)
- [ Pass personalization ](https://spatie.be/docs/laravel-mobile-pass/v1/apple-wallet/pass-personalization)

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)

 Pass personalization
====================

###  On this page 

1. [ Setting up personalization ](#content-setting-up-personalization)
2. [ Personalization logo ](#content-personalization-logo)
3. [ Handling the personalization endpoint ](#content-handling-the-personalization-endpoint)
4. [ Listening for personalization ](#content-listening-for-personalization)
5. [ Why you handle account creation ](#content-why-you-handle-account-creation)

Apple Wallet lets you collect customer information right from the pass itself. A loyalty card can ask for the member's email address, a rewards pass can collect postal code or phone number, and a membership card can gather multiple fields. This is called pass personalization, and it's a streamlined way to build your customer database without redirecting to your website.

Personalization is Apple-only and NFC-only. The package enforces the NFC requirement: if you configure personalization without NFC, building the pass throws an `InvalidConfig` exception.

Setting up personalization
--------------------------------------------------------------------------------------------------------------------------------------

Use `setPersonalization()` on your builder, passing a `Personalization` instance created with `Personalization::make()`. Tell it what description to show in Wallet, which fields to ask for, and optionally a terms-and-conditions message:

```
use Spatie\LaravelMobilePass\Builders\Apple\Entities\Personalization;
use Spatie\LaravelMobilePass\Enums\PersonalizationField;

$builder->setPersonalization(
    Personalization::make(
        description: 'Complete your profile to unlock rewards',
        requiredPersonalizationFields: [
            PersonalizationField::Name,
            PersonalizationField::EmailAddress,
        ],
        termsAndConditions: "We'll use your email to send loyalty updates. You can unsubscribe anytime.",
    )
);
```

The four available fields are:

- `PersonalizationField::Name` — the member's name
- `PersonalizationField::PostalCode` — a postal code (e.g. ZIP for US, postcode for UK)
- `PersonalizationField::EmailAddress` — an email address
- `PersonalizationField::PhoneNumber` — a phone number

Personalization always requires NFC. Set it up with `setNfc()`, in either order relative to `setPersonalization()` — the package checks for NFC when the pass is built, not when either method is called:

```
$builder
    ->setNfc(
        message: 'Tap to earn points',
        encryptionPublicKey: 'your-public-key',
    )
    ->setPersonalization(
        Personalization::make(
            description: 'Complete your profile to unlock rewards',
            requiredPersonalizationFields: [PersonalizationField::EmailAddress],
        )
    );
```

Personalization logo
--------------------------------------------------------------------------------------------------------------------

Personalization shows a logo in Wallet during the enrollment flow. Provide it with `setPersonalizationLogo()`, just like other images in the pass:

```
$builder->setPersonalizationLogo(
    x1Path: 'resources/pass-images/personalization-logo@1x.png',
    x2Path: 'resources/pass-images/personalization-logo@2x.png',
    x3Path: 'resources/pass-images/personalization-logo@3x.png',
);
```

Only the `@1x` image is required; `@2x` and `@3x` are optional.

Handling the personalization endpoint
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------

The `/personalize` web-service endpoint that Wallet calls after the user submits their information is wired up automatically by the package. You don't need to define a route or controller — it's handled behind the scenes.

Listening for personalization
-----------------------------------------------------------------------------------------------------------------------------------------------

Once the user submits their information, the package fires the `PassPersonalized` event. This is where you should create the user's account, sync a CRM, send a welcome email, or do anything else your app needs:

```
namespace App\Listeners;

use Spatie\LaravelMobilePass\Events\PassPersonalized;

class CreateUserAccount
{
    public function handle(PassPersonalized $event): void
    {
        $mobilePass = $event->mobilePass;
        $submittedInfo = $event->submittedInfo; // array of user-entered data

        // Create or update the user
        // Note: field keys depend on what Wallet sends; this example assumes fullName and emailAddress
        $user = User::updateOrCreate(
            ['email' => $submittedInfo['emailAddress'] ?? null],
            [
                'name' => $submittedInfo['fullName'] ?? null,
                'email' => $submittedInfo['emailAddress'] ?? null,
                'phone' => $submittedInfo['phoneNumber'] ?? null,
                'postal_code' => $submittedInfo['postalCode'] ?? null,
            ]
        );

        // Link the mobile pass to the user
        $mobilePass->model()->associate($user)->save();

        // Send a welcome email, trigger onboarding, etc.
    }
}
```

The `$submittedInfo` array is a verbatim passthrough of the `requiredPersonalizationInfo` payload Wallet sends — its structure and key names are controlled by Apple, not this package. The example above uses `fullName` (for `PersonalizationField::Name`) and `emailAddress` (for `PersonalizationField::EmailAddress`); check your pass builder's `requiredPersonalizationFields` to understand which keys will be present in your listener.

Register your listener in `EventServiceProvider` or let Laravel 11+ auto-discover it from `app/Listeners`. See [Events](advanced-usage/events) for listener setup details.

Why you handle account creation
-----------------------------------------------------------------------------------------------------------------------------------------------------

Apple's spec explicitly places account creation on your server, not the package. The package delivers the submitted information and fires the event; your listener decides whether to create an account, sync an external system, update an existing user, or skip the whole thing. This keeps the package lightweight and lets your app apply your business logic.

 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)
