laulamanapps / wallet
Platform-agnostic SDK for generating mobile wallet passes (Apple Wallet, Google Wallet)
Requires
- php: ^8.1
Requires (Dev)
- laulamanapps/apple-passbook: ^2.0
- laulamanapps/google-wallet: ^1.1
- phpstan/phpstan: ^2.0
- phpunit/phpunit: ^10.0|^11.0
Suggests
- laulamanapps/apple-passbook: Required to generate Apple Wallet passes via the Apple bridge (^2.0)
- laulamanapps/google-wallet: Required to generate Google Wallet passes via the Google bridge (^1.1)
This package is auto-updated.
Last update: 2026-07-13 06:29:49 UTC
README
Platform-agnostic PHP SDK for generating mobile wallet passes. Describe a pass once, generate it for every supported platform:
- Apple Wallet (
.pkpassfiles) via laulamanapps/apple-passbook - Google Wallet ("Save to Google Wallet" links) via laulamanapps/google-wallet
The core of this package contains no Apple- or Google-specific code: it defines a generic Pass
model, a PassGenerator contract, and a Wallet orchestrator. The platform bridges live behind
that contract, and the platform packages are optional dependencies — install only the engines you
need.
Installation
composer require laulamanapps/wallet # For Apple Wallet passes: composer require laulamanapps/apple-passbook # For Google Wallet passes: composer require laulamanapps/google-wallet
Or use one of the framework integrations, which wire the Wallet service and the platform
bridges from configuration:
- Symfony: laulamanapps/wallet-symfony
- Laravel: laulamanapps/wallet-laravel
Describe a pass
use LauLamanApps\Wallet\MetaData\Barcode; use LauLamanApps\Wallet\MetaData\BarcodeFormat; use LauLamanApps\Wallet\MetaData\Field; use LauLamanApps\Wallet\MetaData\FieldSection; use LauLamanApps\Wallet\MetaData\Image; use LauLamanApps\Wallet\MetaData\ImageType; use LauLamanApps\Wallet\MetaData\Location; use LauLamanApps\Wallet\Pass; use LauLamanApps\Wallet\PassType; $pass = new Pass('ticket-8j23fm3', PassType::EventTicket, 'Toy Town', 'Toy Town Concert Ticket'); $pass->setBackgroundColor('#1a1a2e'); $pass->setLogoText('Toy Town'); $pass->addBarcode(new Barcode(BarcodeFormat::Qr, '123456789')); $pass->addField(FieldSection::Primary, new Field('event', 'The Beach Boys', 'Event')); $pass->addField(FieldSection::Header, new Field('seat', '12A', 'Seat')); $pass->setRelevantDate(new DateTimeImmutable('2026-08-01T20:00:00+02:00')); // Surface the pass on the lock screen / as a notification near the venue (max 10 locations): $pass->addLocation(new Location(52.3676, 4.9041)); // Enable pass updates and install/uninstall tracking (Apple PassKit Web Service; Google // tracks saves/deletions through class callbacks instead — see the google-wallet package): $pass->setWebService('https://passes.example.com/passkit', '<AuthenticationToken>'); // Apple embeds image files in the pass; Google references public URLs. // Provide whichever the platforms you target need: $pass->addImage(Image::fromLocalPath(ImageType::Icon, __DIR__ . '/images/icon.png')); $pass->addImage(Image::fromUrl(ImageType::Logo, 'https://example.com/logo.png'));
Generate for every platform
use LauLamanApps\ApplePassbook\Build\CompilerFactory; use LauLamanApps\GoogleWallet\SaveUrlFactory; use LauLamanApps\GoogleWallet\ServiceAccount; use LauLamanApps\Wallet\Bridge\Apple\ApplePassGenerator; use LauLamanApps\Wallet\Bridge\Google\GooglePassGenerator; use LauLamanApps\Wallet\Wallet; $compiler = (new CompilerFactory())->getCompiler('<PathToCertificate>', '<CertificatePassword>'); $compiler->setPassTypeIdentifier('pass.com.toytown'); $compiler->setTeamIdentifier('9X3HHK8VXA'); $serviceAccount = ServiceAccount::fromJsonFile('<PathToServiceAccountKey.json>'); $wallet = new Wallet([ new ApplePassGenerator($compiler), new GooglePassGenerator(new SaveUrlFactory($serviceAccount), '<GoogleIssuerId>'), ]); // One platform: $apple = $wallet->generate('apple', $pass); // GeneratedPass::isFile() — .pkpass binary $google = $wallet->generate('google', $pass); // GeneratedPass::isUrl() — Save to Google Wallet link // Or all registered platforms at once: foreach ($wallet->generateForAllPlatforms($pass) as $platform => $generated) { if ($generated->isFile()) { file_put_contents($generated->getFilename(), $generated->getContent()); } else { echo $platform . ': ' . $generated->getUrl() . PHP_EOL; } }
Serving the result
GeneratedPass tells you how the pass reaches the user:
| Apple | ||
|---|---|---|
| Delivery | Delivery::File |
Delivery::Url |
| Usage | Serve getContent() with getMimeType() (application/vnd.apple.pkpass) |
Redirect or link the user to getUrl() |
Custom platforms
Implement LauLamanApps\Wallet\PassGenerator and register it:
final class MyPlatformGenerator implements PassGenerator { public function getPlatform(): string { return 'my-platform'; } public function generate(Pass $pass): GeneratedPass { return GeneratedPass::url('my-platform', 'https://wallet.example.com/save/...'); } } $wallet->registerGenerator(new MyPlatformGenerator());
Lifecycle events
The package ships two platform-agnostic notification events:
LauLamanApps\Wallet\Event\PassInstalledEvent— a pass was added to a walletLauLamanApps\Wallet\Event\PassUninstalledEvent— a pass was removed from a wallet
Each event carries the platform ('apple', 'google', ...), the platform pass id (Apple serial
number, Google object id) and the native platform event for consumers that need platform detail.
The framework integrations dispatch them automatically: on Apple after a successful PassKit
device (un)registration, on Google after a signature-verified save/delete callback. Listen once,
cover every platform.
Platform notes
- Apple: the pass type identifier, team identifier and signing certificate are configured on
the apple-passbook
Compiler; the bridge mapsPassType::LoyaltyCardto Apple'sstoreCardstyle andPassType::BoardingPassto a generic transit type. Only images with a local path are embedded (ImageType::Herois Google-only). Locations become passlocations(lock-screen relevance);setWebService()becomeswebServiceURL/authenticationTokenin the pass. - Google: passes are generated as signed "Save to Google Wallet" links (no API call needed);
all pass types are mapped to Google's generic pass with your fields as text modules. Only images
with a public URL are used (
ImageType::LogoandImageType::Hero/ImageType::Strip). Locations becomemerchantLocations("Nearby Passes" notifications, first 10 locations);setWebService()is ignored — Google pushes updates through its REST API and reports saves/deletions via class callbacks. For Google-specific pass types (event ticket, offer, loyalty, transit objects) use laulamanapps/google-wallet directly.
Credits
License
This package is licensed under the MIT license.