# Laravel Mobile Pass Laravel Mobile Pass is a comprehensive Laravel package for generating mobile passes for Apple Wallet. It provides builder classes for various pass types including airline boarding passes, coupons, generic passes, and store cards. The package handles the complete lifecycle of mobile passes from creation to automatic updates, storing pass data as Eloquent models rather than files. The package seamlessly integrates with Laravel's ecosystem, offering automatic device registration handling, push notifications for pass updates, and the ability to associate passes with any Eloquent model. When users add passes to their Apple Wallet, the package tracks registrations and enables real-time updates that automatically sync to users' devices without requiring them to manually download new versions. ## Installation and Configuration Installing and configuring the package in Laravel application ```bash # Install via Composer composer require spatie/laravel-mobile-pass # Publish configuration file php artisan vendor:publish --tag="mobile-pass-config" # Publish and run migrations php artisan vendor:publish --tag="mobile-pass-migrations" php artisan migrate ``` ```php // config/mobile-pass.php return [ 'apple' => [ 'organisation_name' => env('MOBILE_PASS_APPLE_ORGANISATION_NAME'), 'type_identifier' => env('MOBILE_PASS_APPLE_TYPE_IDENTIFIER'), 'team_identifier' => env('MOBILE_PASS_APPLE_TEAM_IDENTIFIER'), 'certificate_path' => env('MOBILE_PASS_APPLE_CERTIFICATE_PATH'), 'certificate_password' => env('MOBILE_PASS_APPLE_CERTIFICATE_PASSWORD'), 'webservice' => [ 'secret' => env('MOBILE_PASS_APPLE_WEBSERVICE_SECRET'), 'host' => env('MOBILE_PASS_APPLE_WEBSERVICE_HOST'), ], ], ]; ``` ```php // routes/web.php - Register package routes for Apple callbacks use Illuminate\Support\Facades\Route; Route::mobilePass(); ``` ```env # .env - Configure Apple credentials MOBILE_PASS_APPLE_ORGANISATION_NAME="Your Company" MOBILE_PASS_APPLE_TYPE_IDENTIFIER="pass.com.yourcompany.passtype" MOBILE_PASS_APPLE_TEAM_IDENTIFIER="ABCD123456" MOBILE_PASS_APPLE_CERTIFICATE_PATH="/path/to/certificate.p12" MOBILE_PASS_APPLE_CERTIFICATE_PASSWORD="certificate_password" MOBILE_PASS_APPLE_WEBSERVICE_SECRET="your_secret_key" MOBILE_PASS_APPLE_WEBSERVICE_HOST="https://yourdomain.com" ``` ## Creating an Airline Boarding Pass Building a complete airline boarding pass with semantic fields and visual elements ```php use Spatie\LaravelMobilePass\Builders\Apple\AirlinePassBuilder; use Spatie\LaravelMobilePass\Builders\Apple\Entities\FieldContent; use Spatie\LaravelMobilePass\Builders\Apple\Entities\Image; use Spatie\LaravelMobilePass\Builders\Apple\Entities\Seat; $mobilePass = AirlinePassBuilder::make() ->setOrganisationName('Etihad Airways') ->setSerialNumber('EY066-' . time()) ->setDescription('Boarding Pass - Abu Dhabi to London') ->setDownloadName('boarding-pass-ey066') // Header fields - displayed at top ->setHeaderFields( FieldContent::make('flight-no') ->withLabel('Flight') ->withValue('EY066'), FieldContent::make('seat') ->withLabel('Seat') ->withValue('66F') ) // Primary fields - largest display ->setPrimaryFields( FieldContent::make('departure') ->withLabel('Abu Dhabi International') ->withValue('AUH'), FieldContent::make('destination') ->withLabel('London Heathrow') ->withValue('LHR') ) // Secondary fields - medium display ->setSecondaryFields( FieldContent::make('name') ->withLabel('Name') ->withValue('Dan Johnson'), FieldContent::make('gate') ->withLabel('Gate') ->withValue('D68') ) // Auxiliary fields - smaller details ->setAuxiliaryFields( FieldContent::make('departs') ->withLabel('Departs') ->withValue(now()->toIso8601String()), FieldContent::make('class') ->withLabel('Class') ->withValue('Economy') ) // Images ->setIconImage(Image::make(x1Path: storage_path('passes/airline-icon.png'))) ->setLogoImage(Image::make(x1Path: storage_path('passes/airline-logo.png'))) // Semantic fields for Apple intelligence features ->setAirlineCode('EY') ->setFlightCode('EY066') ->setFlightNumber('066') ->setDepartureAirportCode('AUH') ->setDepartureAirportName('Abu Dhabi International') ->setDepartureLocationDescription('Abu Dhabi International Airport') ->setDepartureGate('D68') ->setDepartureTerminal('3') ->setDestinationAirportCode('LHR') ->setDestinationAirportName('London Heathrow') ->setDestinationLocationDescription('London Heathrow Airport') ->setSeats(Seat::make(number: '66F')) ->save(); // Returns MobilePass model with id, content, images stored in database ``` ## Creating a Coupon Pass Generating a promotional coupon pass with barcode and styling ```php use Spatie\LaravelMobilePass\Builders\Apple\CouponPassBuilder; use Spatie\LaravelMobilePass\Builders\Apple\Entities\FieldContent; use Spatie\LaravelMobilePass\Builders\Apple\Entities\Barcode; use Spatie\LaravelMobilePass\Builders\Apple\Entities\Colour; use Spatie\LaravelMobilePass\Builders\Apple\Entities\Image; use Spatie\LaravelMobilePass\Enums\BarcodeType; $coupon = CouponPassBuilder::make() ->setOrganisationName('Coffee Shop') ->setSerialNumber('COUPON-' . uniqid()) ->setDescription('20% Off Your Next Purchase') // Styling ->setBackgroundColour(Colour::make(red: 247, green: 167, blue: 0)) ->setForegroundColour(Colour::make(red: 255, green: 255, blue: 255)) ->setLabelColour(Colour::make(red: 255, green: 255, blue: 255)) // Barcode for scanning ->setBarcode( Barcode::make( format: BarcodeType::QR, message: 'DISCOUNT20-USER12345', messageEncoding: 'iso-8859-1' )->withAltText('Scan at checkout') ) ->setHeaderFields( FieldContent::make('offer') ->withLabel('Offer') ->withValue('20% OFF') ) ->setPrimaryFields( FieldContent::make('deal') ->withLabel('Deal') ->withValue('20% Off Your Next Purchase') ) ->setSecondaryFields( FieldContent::make('expires') ->withLabel('Expires') ->withValue(now()->addDays(30)->format('M d, Y')) ) ->setAuxiliaryFields( FieldContent::make('terms') ->withLabel('Terms') ->withValue('Valid on purchases over $10') ) ->setIconImage(Image::make(x1Path: storage_path('passes/coffee-icon.png'))) ->save(); ``` ## Creating a Generic Pass Building a generic pass for membership cards or tickets ```php use Spatie\LaravelMobilePass\Builders\Apple\GenericPassBuilder; use Spatie\LaravelMobilePass\Builders\Apple\Entities\FieldContent; use Spatie\LaravelMobilePass\Builders\Apple\Entities\Image; $membershipPass = GenericPassBuilder::make() ->setOrganisationName('Fitness Club Pro') ->setSerialNumber('MEMBER-' . $user->id) ->setDescription('Gym Membership Card') ->setHeaderFields( FieldContent::make('member-type') ->withLabel('Membership') ->withValue('Premium') ) ->setPrimaryFields( FieldContent::make('name') ->withLabel('Member Name') ->withValue($user->name), FieldContent::make('member-id') ->withLabel('Member ID') ->withValue($user->membership_id) ) ->setSecondaryFields( FieldContent::make('since') ->withLabel('Member Since') ->withValue($user->created_at->format('Y')), FieldContent::make('expires') ->withLabel('Valid Until') ->withValue($user->membership_expires_at->format('M Y')) ) ->setIconImage(Image::make(x1Path: storage_path('passes/gym-icon.png'))) ->setLogoImage(Image::make(x1Path: storage_path('passes/gym-logo.png'))) ->save(); ``` ## Creating a Store Card Pass Generating a loyalty store card with point balance ```php use Spatie\LaravelMobilePass\Builders\Apple\StoreCardPassBuilder; use Spatie\LaravelMobilePass\Builders\Apple\Entities\FieldContent; use Spatie\LaravelMobilePass\Enums\NumberStyleType; $storeCard = StoreCardPassBuilder::make() ->setOrganisationName('SuperMart') ->setSerialNumber('LOYALTY-' . $customer->id) ->setDescription('SuperMart Loyalty Card') ->setHeaderFields( FieldContent::make('points') ->withLabel('Points') ->withValue((string) $customer->loyalty_points) ->usingNumberStyle(NumberStyleType::Decimal) ) ->setPrimaryFields( FieldContent::make('balance') ->withLabel('Rewards Balance') ->withValue('$' . number_format($customer->loyalty_points * 0.01, 2)) ) ->setSecondaryFields( FieldContent::make('card-number') ->withLabel('Card Number') ->withValue($customer->card_number), FieldContent::make('tier') ->withLabel('Tier') ->withValue($customer->tier) ) ->setIconImage(Image::make(x1Path: storage_path('passes/store-icon.png'))) ->save(); ``` ## Downloading Passes from Controller Returning passes as downloadable responses in controllers ```php use App\Models\User; use Spatie\LaravelMobilePass\Models\MobilePass; use Illuminate\Http\Request; class PassDownloadController { public function download(Request $request, $passId) { $pass = MobilePass::findOrFail($passId); // Simply return the model - package handles the response return $pass; // Downloads as: pass.pkpass } public function downloadWithCustomName($passId) { $pass = MobilePass::findOrFail($passId); // Override download name return $pass->download('my-custom-pass-name'); // Downloads as: my-custom-pass-name.pkpass } public function downloadUserPass(User $user) { // Get user's first pass $pass = $user->firstMobilePass(); if (!$pass) { abort(404, 'No pass found'); } return $pass; } } ``` ## Updating Passes with Notifications Modifying pass fields and triggering automatic updates on user devices ```php use App\Models\User; use Spatie\LaravelMobilePass\Builders\Apple\Entities\FieldContent; // Simple field update $user = User::find(1); $mobilePass = $user->firstMobilePass(); $mobilePass ->builder() ->updateField('seat', fn (FieldContent $field) => $field->setValue('13A') ) ->save(); // Apple is notified automatically, device fetches updated pass // Update with notification message $mobilePass ->builder() ->updateField('gate', fn (FieldContent $field) => $field ->setValue('B42') ->showMessageWhenChanged('Your gate has changed to B42') ) ->save(); // Users see lock screen notification with message // Update multiple fields $mobilePass ->builder() ->updateField('gate', fn (FieldContent $field) => $field->setValue('B42') ) ->updateField('boarding-time', fn (FieldContent $field) => $field ->setValue(now()->addMinutes(30)->toIso8601String()) ->showMessageWhenChanged('Boarding time updated') ) ->save(); ``` ## Associating Passes with Models Using the HasMobilePasses trait to link passes to any Eloquent model ```php use Illuminate\Database\Eloquent\Model; use Spatie\LaravelMobilePass\Models\Concerns\HasMobilePasses; use Spatie\LaravelMobilePass\Builders\Apple\CouponPassBuilder; use Spatie\LaravelMobilePass\Enums\PassType; class User extends Model { use HasMobilePasses; } // Create and associate pass with user $couponPass = CouponPassBuilder::make() ->setOrganisationName('My Store') ->setDescription('Welcome Coupon') ->setSerialNumber('WELCOME-' . $user->id) // ... other fields ->save(); $user->addMobilePass($couponPass); // Retrieve all passes for user $allPasses = $user->mobilePasses; // Get first pass $firstPass = $user->firstMobilePass(); // Get first pass of specific type $couponPass = $user->firstMobilePass(PassType::Coupon); // Get pass with custom query $expiredPass = $user->firstMobilePass(filter: function ($query) { $query->where('created_at', '<', now()->subMonths(6)); }); // Associate with any model class Order extends Model { use HasMobilePasses; } $order = Order::find(1); $order->addMobilePass($ticketPass); ``` ## Using Passes as Email Attachments Attaching passes to Laravel Mailables for delivery via email ```php use Illuminate\Mail\Mailable; use Spatie\LaravelMobilePass\Models\MobilePass; class BoardingPassEmail extends Mailable { public function __construct( public MobilePass $pass ) {} public function build() { return $this->view('emails.boarding-pass') ->subject('Your Boarding Pass is Ready'); } public function attachments() { return [ $this->pass, ]; // Attached as: pass.pkpass } } // Usage $mobilePass = AirlinePassBuilder::make() ->setDownloadName('boarding-pass-flight-ey066') ->setOrganisationName('Etihad Airways') // ... other fields ->save(); Mail::to($user)->send(new BoardingPassEmail($mobilePass)); // Email sent with: boarding-pass-flight-ey066.pkpass attached ``` ## Generating Passes Without Model Storage Creating pass files directly without database persistence ```php use Spatie\LaravelMobilePass\Builders\Apple\CouponPassBuilder; use Illuminate\Support\Facades\Storage; // Generate pass content without saving to database $passContent = CouponPassBuilder::make() ->setOrganisationName('Coffee Shop') ->setSerialNumber('TEMP-' . uniqid()) ->setDescription('One-time Coupon') ->setHeaderFields(/* fields */) ->generate(); // Save to file system Storage::disk('local')->put('passes/temp-coupon.pkpass', $passContent); // Or send directly to user return response($passContent, 200) ->header('Content-Type', 'application/vnd.apple.pkpass') ->header('Content-Disposition', 'attachment; filename="coupon.pkpass"'); // Note: Without model, users won't receive automatic updates ``` ## Retrieving Stored Pass Content Reading pass data from saved MobilePass models ```php use Spatie\LaravelMobilePass\Models\MobilePass; $pass = MobilePass::find(1); // Generate pass file content $pkpassContent = $pass->generate(); // Save to custom location file_put_contents(storage_path('passes/backup.pkpass'), $pkpassContent); // Get builder instance to inspect/modify $builder = $pass->builder(); // Access pass properties $serialNumber = $pass->serial_number; $builderName = $pass->builder_name; // e.g., 'airline' $platform = $pass->platform; // Platform::Apple $content = $pass->content; // JSON array of pass data $images = $pass->images; // JSON array of image paths // Check registrations $registrations = $pass->registrations; // AppleMobilePassRegistration models $devices = $pass->devices; // AppleMobilePassDevice models $registeredCount = $pass->registrations()->count(); // Check if updated after date $hasUpdates = $pass->wasUpdatedAfter($lastCheckDate); ``` ## Apple Wallet API Routes Package-registered routes for handling Apple Wallet device communication ```php // routes/web.php use Illuminate\Support\Facades\Route; Route::mobilePass(); // Registers all routes with default prefix // Or with custom prefix Route::mobilePass('api/wallet'); // Registered routes (automatic, do not define manually): // POST /passkit/v1/devices/{deviceId}/registrations/{passTypeId}/{passSerial} // Register device for pass updates // Called when user adds pass to Wallet // GET /passkit/v1/passes/{passTypeId}/{passSerial} // Check for pass updates // Called by device to fetch updated pass // DELETE /passkit/v1/devices/{deviceId}/registrations/{passTypeId}/{passSerial} // Unregister device from pass updates // Called when user removes pass from Wallet // GET /passkit/v1/devices/{deviceId}/registrations/{passTypeId} // Get all pass serials registered to device // Called by Apple to sync registrations // POST /passkit/v1/log // Receive logs from Wallet app // Diagnostic logging from devices ``` ## Customizing Package Behavior Extending models and actions for custom business logic ```php // app/Models/CustomMobilePass.php namespace App\Models; use Spatie\LaravelMobilePass\Models\MobilePass as BaseMobilePass; class CustomMobilePass extends BaseMobilePass { protected static function boot() { parent::boot(); static::creating(function ($pass) { // Custom logic before creating pass $pass->serial_number = 'CUSTOM-' . $pass->serial_number; }); static::updated(function ($pass) { // Custom logic after pass update \Log::info("Pass {$pass->id} was updated"); }); } public function user() { return $this->belongsTo(User::class); } } // config/mobile-pass.php return [ 'models' => [ 'mobile_pass' => App\Models\CustomMobilePass::class, 'apple_mobile_pass_registration' => App\Models\CustomRegistration::class, 'apple_mobile_pass_device' => App\Models\CustomDevice::class, ], 'actions' => [ 'notify_apple_of_pass_update' => App\Actions\CustomNotifyAction::class, 'register_device' => App\Actions\CustomRegisterAction::class, 'unregister_device' => App\Actions\CustomUnregisterAction::class, ], 'builders' => [ 'apple' => [ 'airline' => App\Builders\CustomAirlineBuilder::class, // ... other builders ], ], ]; ``` ## Summary Laravel Mobile Pass provides a complete solution for integrating Apple Wallet passes into Laravel applications. The primary use cases include airline boarding passes for travel apps, event tickets for entertainment platforms, coupons and promotional offers for retail, membership and loyalty cards for customer rewards programs, and gift cards for e-commerce. The package handles all technical complexity of the Apple Wallet specification while providing an elegant, Laravel-style API. The package excels in scenarios requiring real-time pass updates, as it automatically manages device registrations and push notifications when pass data changes. Developers can associate passes with any Eloquent model using the HasMobilePasses trait, making it seamless to integrate into existing applications. The builder pattern provides type-safe pass creation with validation, while the automatic database storage enables querying and updating passes without managing physical files. Whether generating single-use passes or managing thousands of dynamic passes that update in real-time, Laravel Mobile Pass provides the tools needed with minimal configuration.