spatie/laravel-mobile-pass
Laravel package to generate Apple Wallet mobile passes (boarding passes, tickets, coupons, cards) with support for pushing updates to issued passes so they stay current on users’ devices. In development—don’t use in production yet.
Installation:
composer require spatie/laravel-mobile-pass
php artisan vendor:publish --provider="Spatie\MobilePass\MobilePassServiceProvider"
php artisan migrate
config/mobile-pass.php) and creates a passes table.First Use Case: Generate a simple boarding pass:
use Spatie\MobilePass\Pass;
use Spatie\MobilePass\PassType;
$pass = Pass::create([
'passType' => PassType::boardingPass(),
'serialNumber' => 'ABC123',
'teamIdentifier' => 'com.yourcompany.app',
'organizationName' => 'Your Company',
'description' => 'Boarding Pass',
'relevantDate' => now()->addDay(),
'foregroundColor' => '#000000',
'backgroundColor' => '#FFFFFF',
'logoText' => 'Your Company',
'storeCard' => false,
'webServiceURL' => 'https://your-app.com/pass/verify',
'authenticationToken' => 'your-secret-token',
'headerFields' => [
['key' => 'name', 'label' => 'Name', 'value' => 'John Doe'],
],
'barcode' => [
'message' => 'ABC123',
'format' => 'PKBarcodeFormatQR',
'messageEncoding' => 'iso-8859-1',
],
]);
return $pass->toWebPass();
/passes/{id}/webpass in a browser to download the .pkpass file.config/mobile-pass.php (adjust team_identifier, certificate_path, etc.).database/migrations/xxxx_create_passes_table.php (customize fields as needed).app/Providers/MobilePassServiceProvider.php (extend if needed).Pass Generation:
Pass::create() with a PassType (e.g., PassType::boardingPass(), PassType::eventTicket()).serialNumber, webServiceURL, and authenticationToken.foregroundColor, backgroundColor, logoText, etc.headerFields, primaryFields, or secondaryFields.Barcode Integration:
$pass->barcode([
'message' => 'UNIQUE_ID_123',
'format' => 'PKBarcodeFormatPDF417', // or QR, AZTEC, etc.
'messageEncoding' => 'iso-8859-1',
]);
PDF417 for high-density data (e.g., boarding passes) or QR for simplicity.Pass Updates:
$pass = Pass::find($id).relevantDate, headerFields) and save:
$pass->update(['relevantDate' => now()->addHour()]);
$pass->updateBarcode(['message' => 'NEW_UNIQUE_ID']);
webServiceURL is reachable.Web Pass Delivery:
.pkpass file via:
route('passes.webpass', function (Pass $pass) {
return $pass->toWebPass();
});
$pass->toWebPass()->saveTo($path);
Validation:
Pass::validate() to check if a pass is valid (e.g., for redemption):
if (Pass::validate($serialNumber, $authToken)) {
// Pass is valid
}
webServiceURL with API tokens or signed requests.Pass::fake() in tests to mock pass generation:
Pass::fake([
PassType::boardingPass()->withSerialNumber('TEST123'),
]);
Certificate Requirements:
.p12 certificate for signing .pkpass files. Without it, passes won’t install.certificate_path in config/mobile-pass.php:
'certificate_path' => storage_path('app/certificates/wallet_cert.p12'),
'certificate_password' => env('WALLET_CERT_PASSWORD'),
Team Identifier:
teamIdentifier (e.g., com.yourcompany.app) must match your Apple Developer account’s bundle ID.config/mobile-pass.php and regenerate certificates if mismatched.Barcode Validation:
PKBarcodeFormat) may cause pass generation to fail silently.PKBarcodeFormatPDF417, PKBarcodeFormatQR, PKBarcodeFormatAztec, or PKBarcodeFormatCode128.Web Service URL:
webServiceURL is unreachable, users won’t receive updates./api/passes/validate/{serialNumber}) and test with:
curl -X GET "https://your-app.com/pass/verify?serialNumber=ABC123&authToken=your-token"
Return a 200 status for valid passes.Pass Expiration:
relevantDate is in the past or expirationDate is set.config/mobile-pass.php:
'debug' => env('APP_DEBUG', false),
.pkpass files with Pass Inspector (macOS) to validate structure.Invalid signature: Certificate or password issue.Pass not found: webServiceURL misconfiguration.Barcode error: Invalid message or format.Custom Pass Types:
Extend Spatie\MobilePass\PassType to create reusable pass templates:
namespace App\PassTypes;
use Spatie\MobilePass\PassType;
class LoyaltyCard extends PassType
{
public static function create(): PassType
{
return (new static())
->withPassTypeIdentifier('pass.com.yourcompany.loyalty')
->withOrganizationName('Your Company')
->withLogoText('LOYALTY')
->withForegroundColor('#000000')
->withBackgroundColor('#FFFFFF');
}
}
Dynamic Field Generation: Use closures to generate fields dynamically:
$pass->headerFields([
['key' => 'event', 'label' => 'Event', 'value' => fn () => 'Conference 2025'],
]);
Event Listeners: Listen for pass events (e.g., creation/updates) to trigger notifications:
Pass::created(function (Pass $pass) {
// Send email/SMS to user
});
Batch Processing: Generate passes in bulk for events or promotions:
$users = User::where('attending_event', true)->get();
foreach ($users as $user) {
Pass::create([
'serialNumber' => 'EVENT_' . $user->id,
// ... other fields
]);
}
Localization:
Support multiple languages by localizing label and value fields:
$pass->headerFields([
['key' => 'name', 'label' => __('Name'), 'value' => $user->name],
]);
How can I help you explore Laravel packages today?