PHP client for Apple Push Notification Service (APNs) - Send push notifications to iOS using the new APNs HTTP/2 protocol with token-based (JWT with p8 private key) or certificate-based authentication

Installs: 1 573 707

Dependents: 14

Suggesters: 0

Security: 0

Stars: 367

Watchers: 13

Forks: 119

Open Issues: 16

0.16.0 2024-02-26 10:34 UTC


PHP >= 8.1 Build Status Latest Version on Packagist Total Downloads Coverage Status Quality Score Software License StandWithUkraine

Do you like the library? Please consider donating to support Ukraine 🇺🇦

Pushok is a simple PHP library for sending push notifications to APNs.


  • Uses new Apple APNs HTTP/2 connection
  • Supports JWT-based authentication
  • Supports Certificate-based authentication
  • Supports new iOS 10 features such as Collapse IDs, Subtitles and Mutable Notifications
  • Uses concurrent requests to APNs
  • Tested and working in APNs production environment


  • PHP >= 8.1
  • lib-curl >= 7.46.0 (with http/2 support enabled)
  • lib-openssl >= 1.0.2e

Docker image that meets requirements can be found here. Or you can follow this tutorial to create your own docker image with curl with HTTP/2 support.


Via Composer

$ composer require edamov/pushok

Getting Started

Using JWT token. See Handling Notification Responses from APNs for more info.

require __DIR__ . '/vendor/autoload.php';

use Pushok\AuthProvider;
use Pushok\Client;
use Pushok\Notification;
use Pushok\Payload;
use Pushok\Payload\Alert;

$options = [
    'key_id' => 'AAAABBBBCC', // The Key ID obtained from Apple developer account
    'team_id' => 'DDDDEEEEFF', // The Team ID obtained from Apple developer account
    'app_bundle_id' => 'com.app.Test', // The bundle ID for app obtained from Apple developer account
    'private_key_path' => __DIR__ . '/private_key.p8', // Path to private key
    'private_key_secret' => null // Private key secret

// Be aware of thing that Token will stale after one hour, so you should generate it again.
// Can be useful when trying to send pushes during long-running tasks
$authProvider = AuthProvider\Token::create($options);

$alert = Alert::create()->setTitle('Hello!');
$alert = $alert->setBody('First push notification');

$payload = Payload::create()->setAlert($alert);

//set notification sound to default

//add custom value to your notification, needs to be customized
$payload->setCustomValue('key', 'value');

$deviceTokens = ['<device_token_1>', '<device_token_2>', '<device_token_3>'];

$notifications = [];
foreach ($deviceTokens as $deviceToken) {
    $notifications[] = new Notification($payload,$deviceToken);

// If you have issues with ssl-verification, you can temporarily disable it. Please see attached note.
// Disable ssl verification
// $client = new Client($authProvider, $production = false, [CURLOPT_SSL_VERIFYPEER=>false] );
$client = new Client($authProvider, $production = false);

$responses = $client->push(); // returns an array of ApnsResponseInterface (one Response per Notification)

foreach ($responses as $response) {
    // The device token
    // A canonical UUID that is the unique ID for the notification. E.g. 123e4567-e89b-12d3-a456-4266554400a0
    // Status code. E.g. 200 (Success), 410 (The device token is no longer active for the topic.)
    // E.g. The device token is no longer active for the topic.
    // E.g. Unregistered
    // E.g. The device token is inactive for the specified topic.

Using Certificate (.pem). Only the initilization differs from JWT code (above). Remember to include the rest of the code by yourself.


$options = [
    'app_bundle_id' => 'com.app.Test', // The bundle ID for app obtained from Apple developer account
    'certificate_path' => __DIR__ . '/private_key.pem', // Path to private key
    'certificate_secret' => null // Private key secret

$authProvider = AuthProvider\Certificate::create($options);


Note : Please see this post about ssl verification

Options to fiddle around. See Sending Notification Requests to APNs


$client = new Client($authProvider, $production = false);

// Set the number of concurrent requests sent through the multiplexed connections. Default : 20
$client->setNbConcurrentRequests( 40 );

// Set the number of maximum concurrent connections established to the APNS servers. Default : 1
$client->setMaxConcurrentConnections( 5 );

$responses = $client->push();


$ composer test


If you discover any security related issues, please email edamov@gmail.com instead of using the issue tracker.



The MIT License (MIT). Please see License File for more information.