PHPackages                             laulamanapps/apple-passbook-bundle - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [PDF &amp; Document Generation](/categories/documents)
4. /
5. laulamanapps/apple-passbook-bundle

ActiveLibrary[PDF &amp; Document Generation](/categories/documents)

laulamanapps/apple-passbook-bundle
==================================

Generate Apple Wallet passes (PassKit) from your Symfony application

v2.0.0(1mo ago)319.5k↓92.3%2[1 issues](https://github.com/LauLamanApps/apple-passbook-bundle/issues)[1 PRs](https://github.com/LauLamanApps/apple-passbook-bundle/pulls)MITPHPPHP ^8.1CI passing

Since Dec 7Pushed 1mo ago1 watchersCompare

[ Source](https://github.com/LauLamanApps/apple-passbook-bundle)[ Packagist](https://packagist.org/packages/laulamanapps/apple-passbook-bundle)[ RSS](/packages/laulamanapps-apple-passbook-bundle/feed)WikiDiscussions master Synced 2w ago

READMEChangelog (3)Dependencies (17)Versions (6)Used By (0)

Apple Passbook Bundle
=====================

[](#apple-passbook-bundle)

This package provides Symfony integration for the [LauLamanApps Apple Passbook Package](https://github.com/LauLamanApps/apple-passbook).

[![GithubCi](https://github.com/LauLamanApps/apple-passbook-bundle/workflows/CI/badge.svg)](https://github.com/LauLamanApps/apple-passbook-bundle/actions?query=workflow%3ACI)[![Latest Stable Version](https://camo.githubusercontent.com/9794f3f7ffb9398adb39224e44ff344b8ce80ac5f0a79225328f4a1d191259fb/68747470733a2f2f706f7365722e707567782e6f72672f6c61756c616d616e617070732f6170706c652d70617373626f6f6b2d62756e646c652f762f737461626c65)](https://packagist.org/packages/laulamanapps/apple-passbook-bundle)[![License](https://camo.githubusercontent.com/39dc963d73ef7fc3f6f90636bbed071966a4a9254398e0e90a5cf1020bb6b49c/68747470733a2f2f706f7365722e707567782e6f72672f6c61756c616d616e617070732f6170706c652d70617373626f6f6b2d62756e646c652f6c6963656e7365)](https://packagist.org/packages/laulamanapps/apple-passbook-bundle)

Requirements
------------

[](#requirements)

- PHP 8.1+
- Symfony 6.4, 7.x, or 8.x

Installation
------------

[](#installation)

```
composer require laulamanapps/apple-passbook-bundle
```

Run Tests
---------

[](#run-tests)

```
make tests-unit
make tests-functional
```

Get Certificate
---------------

[](#get-certificate)

Head over to the [Apple Developer Portal](https://developer.apple.com/account/resources/certificates/list) to get yourself a certificate to sign your passbooks with.

Export the certificate and key to a `.p12` file using **Keychain Access**.

Configure Bundle
----------------

[](#configure-bundle)

```
# config/packages/laulamanapps_apple_passbook.yaml

laulamanapps_apple_passbook:
    certificate: '%env(APPLE_PASSBOOK_CERTIFICATE)%'
    password: '%env(APPLE_PASSBOOK_CERTIFICATE_PASSWORD)%'
    team_identifier: '%env(APPLE_PASSBOOK_TEAM_IDENTIFIER)%'
    pass_type_identifier: '%env(APPLE_PASSBOOK_PASS_TYPE_IDENTIFIER)%'
    environment: 'production' # or 'sandbox'
```

Add the ENV variables to the `.env` file:

```
###> laulamanapps/apple-passbook-bundle ###
APPLE_PASSBOOK_CERTIFICATE=config/certificates/pass.p12
APPLE_PASSBOOK_CERTIFICATE_PASSWORD=password
APPLE_PASSBOOK_PASS_TYPE_IDENTIFIER=pass.com.your.pass.identifier
APPLE_PASSBOOK_TEAM_IDENTIFIER=YOUR_TEAM_ID
APPLE_PASSBOOK_WEB_SERVICE_URL='https://example.com/'
###< laulamanapps/apple-passbook-bundle ###
```

> **Security note:** always reference the certificate password through `%env(...)%` as shown above. A literal password in the bundle configuration would be written into Symfony's compiled container in `var/cache`.

### Configuration reference

[](#configuration-reference)

KeyRequiredDefaultDescription`certificate`yes—Path to the `.p12` or `.pem` certificate file`password`no`null`Certificate password (required for `.p12` files)`team_identifier`no`null`Apple Team Identifier`pass_type_identifier`no`null`Pass Type Identifier`environment`no`'production'`APNs environment: `'production'` or `'sandbox'`Create &amp; Compile Passbook
-----------------------------

[](#create--compile-passbook)

```
namespace App\Controller;

use LauLamanApps\ApplePassbook\Build\Compiler;
use LauLamanApps\ApplePassbook\GenericPassbook;
use LauLamanApps\ApplePassbook\MetaData\Barcode;
use LauLamanApps\ApplePassbook\Style\BarcodeFormat;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;

final class PassbookController
{
    public function __construct(
        private readonly Compiler $passbookCompiler,
    ) {
    }

    #[Route('/download/passbook/', name: 'download_passbook')]
    public function download(): Response
    {
        $passbook = new GenericPassbook('8j23fm3');
        $passbook->setTeamIdentifier('');
        $passbook->setPassTypeIdentifier('');
        $passbook->setOrganizationName('Toy Town');
        $passbook->setDescription('Toy Town Membership');

        $barcode = new Barcode();
        $barcode->setFormat(BarcodeFormat::Pdf417);
        $barcode->setMessage('123456789');
        $passbook->setBarcode($barcode);

        $data = $this->passbookCompiler->compile($passbook);

        $response = new Response($data);
        $response->headers->set('Content-Description', 'File Transfer');
        $response->headers->set('Content-Type', 'application/vnd.apple.pkpass');
        $response->headers->set('Content-Disposition', 'filename="passbook.pkpass"');

        return $response;
    }
}
```

Push Notifications
------------------

[](#push-notifications)

The bundle registers the `Notifier` service from the core library for sending push notifications to devices when a pass is updated:

```
use LauLamanApps\ApplePassbook\Build\Notifier;

final class PassUpdateService
{
    public function __construct(
        private readonly Notifier $notifier,
    ) {
    }

    public function notifyDevice(string $pushToken): void
    {
        $this->notifier->notify($pushToken);
    }
}
```

The notifier uses Apple's HTTP/2 APNs API. It uses the same certificate configured for the bundle. Set `environment: 'sandbox'` in the bundle configuration when testing against the APNs sandbox.

Built-in Web Service Controllers
--------------------------------

[](#built-in-web-service-controllers)

This package comes with built-in controllers for all Apple PassKit [Web Service](https://developer.apple.com/documentation/walletpasses/adding-a-web-service-to-update-passes) endpoints. It uses Symfony's `EventDispatcher` to delegate request handling to your application.

### Enable routes

[](#enable-routes)

Add the following to your route configuration:

```
// config/routes/apple_passbook.php
use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator;

return function (RoutingConfigurator $routes): void {
    $routes->import('@ApplePassbookBundle/Resources/config/routes.php');
};
```

Or in YAML:

```
# config/routes/apple_passbook.yaml
apple_passbook:
    resource: '@ApplePassbookBundle/Resources/config/routes.php'
```

### Events

[](#events)

The controllers dispatch events that you handle by implementing listeners or subscribers. Each event starts with `Status::Unhandled` — your listener must set the appropriate status.

EventDispatched when`DeviceRegisteredEvent`A device registers for pass updates`DeviceUnregisteredEvent`A device unregisters from pass updates`DeviceRequestUpdatedPassesEvent`A device requests a list of updated pass serial numbers`RetrieveUpdatedPassbookEvent`A device requests an updated pass### Logging endpoint

[](#logging-endpoint)

Apple devices `POST` diagnostic messages to the `/v1/log` endpoint. The bundle's `LogController` handles these automatically and writes them to the PSR `LoggerInterface` (Symfony's `logger` service) at `info` level — no event or listener is required.

### Example subscriber

[](#example-subscriber)

```
namespace App\EventSubscriber;

use DateTimeImmutable;
use LauLamanApps\ApplePassbook\GenericPassbook;
use LauLamanApps\ApplePassbookBundle\Event\DeviceRegisteredEvent;
use LauLamanApps\ApplePassbookBundle\Event\DeviceRequestUpdatedPassesEvent;
use LauLamanApps\ApplePassbookBundle\Event\DeviceUnregisteredEvent;
use LauLamanApps\ApplePassbookBundle\Event\RetrieveUpdatedPassbookEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

final class ApplePassbookSubscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents(): array
    {
        return [
            DeviceRegisteredEvent::class => 'onDeviceRegistered',
            DeviceRequestUpdatedPassesEvent::class => 'onDeviceRequestUpdatedPasses',
            RetrieveUpdatedPassbookEvent::class => 'onRetrieveUpdatedPassbook',
            DeviceUnregisteredEvent::class => 'onDeviceUnregistered',
        ];
    }

    public function onDeviceRegistered(DeviceRegisteredEvent $event): void
    {
        $passbook = $this->passbookRepository->getBySerial($event->getSerialNumber());

        // isAuthenticatedBy() uses hash_equals() internally: a timing-safe comparison.
        // Never compare authentication tokens with === or !==.
        if (!$event->isAuthenticatedBy($passbook->getAuthToken())) {
            $event->notAuthorized();

            return;
        }

        // Save device registration to database

        $event->deviceRegistered();
    }

    public function onDeviceRequestUpdatedPasses(DeviceRequestUpdatedPassesEvent $event): void
    {
        $passbooks = $this->passbookRepository->getSerialsSince(
            $event->getPassTypeIdentifier(),
            $event->getDeviceLibraryIdentifier(),
            $event->getPassesUpdatedSince(),
        );

        if ($passbooks) {
            $serials = [];
            foreach ($passbooks as $passbook) {
                $serials[] = $passbook->getSerialNumber();
            }

            $event->setSerialNumbers($serials, new DateTimeImmutable());

            return;
        }

        $event->notFound();
    }

    public function onRetrieveUpdatedPassbook(RetrieveUpdatedPassbookEvent $event): void
    {
        $entity = $this->passbookRepository->findBySerial($event->getSerialNumber());

        if ($entity === null) {
            $event->notFound();

            return;
        }

        if (!$event->isAuthenticatedBy($entity->getAuthToken())) {
            $event->notAuthorized();

            return;
        }

        if ($event->getUpdatedSince() && $entity->getUpdatedAt() < $event->getUpdatedSince()) {
            $event->notModified();

            return;
        }

        $passbook = new GenericPassbook($event->getSerialNumber());
        // Build the passbook...

        $event->setPassbook($passbook, $entity->getUpdatedAt());
    }

    public function onDeviceUnregistered(DeviceUnregisteredEvent $event): void
    {
        $passbook = $this->passbookRepository->getBySerial($event->getSerialNumber());

        if (!$event->isAuthenticatedBy($passbook->getAuthToken())) {
            $event->notAuthorized();

            return;
        }

        // Remove device registration from database

        $event->deviceUnregistered();
    }
}
```

Upgrading
---------

[](#upgrading)

See [UPGRADE.md](UPGRADE.md) for the migration guide from 1.x to 2.0 (PHP 8.1+, Symfony 6.4+, native `Status` enum, moved `Notifier`, PHP-based route/service config) and [CHANGELOG.md](CHANGELOG.md) for the full list of changes.

Credits
-------

[](#credits)

This package has been developed by [LauLaman](https://github.com/LauLaman).

###  Health Score

53

—

FairBetter than 96% of packages

Maintenance85

Actively maintained with recent releases

Popularity30

Limited adoption so far

Community11

Small or concentrated contributor base

Maturity71

Established project with proven stability

 Bus Factor1

Top contributor holds 94.4% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~1202 days

Total

3

Last Release

41d ago

Major Versions

v1.1 → v2.0.02026-07-08

PHP version history (3 changes)v1.0PHP &gt;=7.2

v1.1PHP &gt;=7.3

v2.0.0PHP ^8.1

### Community

Maintainers

![](https://www.gravatar.com/avatar/930ca3b1756d00a63c8ff3363e81f16f961cf3ef79ff0c9d362670c36d97e456?d=identicon)[LauLaman](/maintainers/LauLaman)

---

Top Contributors

[![LauLaman](https://avatars.githubusercontent.com/u/8283992?v=4)](https://github.com/LauLaman "LauLaman (17 commits)")[![noahlvb](https://avatars.githubusercontent.com/u/6873972?v=4)](https://github.com/noahlvb "noahlvb (1 commits)")

---

Tags

phpappleiphonewalletiospassbookstore cardcouponevent ticketboarding passiPod Touchpkpass

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/laulamanapps-apple-passbook-bundle/health.svg)

```
[![Health](https://phpackages.com/badges/laulamanapps-apple-passbook-bundle/health.svg)](https://phpackages.com/packages/laulamanapps-apple-passbook-bundle)
```

###  Alternatives

[easycorp/easyadmin-bundle

Admin generator for Symfony applications

4.3k18.3M430](/packages/easycorp-easyadmin-bundle)[symfony/framework-bundle

Provides a tight integration between Symfony components and the Symfony full-stack framework

3.6k257.3M12.4k](/packages/symfony-framework-bundle)[sylius/sylius

E-Commerce platform for PHP, based on Symfony framework.

8.5k6.0M777](/packages/sylius-sylius)[shopware/storefront

Storefront for Shopware

674.7M285](/packages/shopware-storefront)[shopware/core

Shopware platform is the core for all Shopware ecommerce products.

595.8M672](/packages/shopware-core)[pimcore/pimcore

Content &amp; Product Management Framework (CMS/PIM/E-Commerce)

3.8k3.9M535](/packages/pimcore-pimcore)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
