PHPackages                             readdle/app-store-server-api - 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. [Mail &amp; Notifications](/categories/mail)
4. /
5. readdle/app-store-server-api

ActiveLibrary[Mail &amp; Notifications](/categories/mail)

readdle/app-store-server-api
============================

Pure-PHP library that allows managing customer transactions using the App Store Server API and handling server-to-server notifications using the App Store Server Notifications V2

3.16.0(2mo ago)74373.5k—6.8%241MITPHP

Since Oct 25Pushed 2mo ago6 watchersCompare

[ Source](https://github.com/readdle/app-store-server-api)[ Packagist](https://packagist.org/packages/readdle/app-store-server-api)[ Docs](https://github.com/readdle/app-store-server-api)[ RSS](/packages/readdle-app-store-server-api/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (10)Dependencies (6)Versions (44)Used By (1)

About
=====

[](#about)

This is a ***zero-dependencies\* pure PHP*** library that allows managing customer transactions using the [`App Store Server API`](https://developer.apple.com/documentation/appstoreserverapi) and handling server-to-server notifications by providing everything you need to implement the [`App Store Server Notifications V2`](https://developer.apple.com/documentation/appstoreservernotifications) endpoint.

\* Zero-dependencies means this library doesn't rely on any third-party library. At the same time, this library relies on such essential PHP extensions as `json` and `openssl`

> **NOTE**
>
> If you need to deal with receipts instead of (or additionally to) API, check out [this library](https://github.com/readdle/app-store-receipt-verification).

### App Store Server API version compatibility: 1.15 - 2025/02/21

[](#app-store-server-api-version-compatibility-115---20250221)

Installation
============

[](#installation)

Nothing special here, just use composer to install the package:

> composer require readdle/app-store-server-api

Usage
=====

[](#usage)

### App Store Server API

[](#app-store-server-api)

API initialization:

```
try {
    $api = new \Readdle\AppStoreServerAPI\AppStoreServerAPI(
        \Readdle\AppStoreServerAPI\Environment::PRODUCTION,
        '1a2b3c4d-1234-4321-1111-1a2b3c4d5e6f',
        'com.readdle.MyBundle',
        'ABC1234DEF',
        "-----BEGIN PRIVATE KEY-----\n\n-----END PRIVATE KEY-----"
    );
} catch (\Readdle\AppStoreServerAPI\Exception\WrongEnvironmentException $e) {
    exit($e->getMessage());
}

```

Performing API call:

```
try {
    $transactionHistory = $api->getTransactionHistory($transactionId, ['sort' => GetTransactionHistoryQueryParams::SORT__DESCENDING]);
    $transactions = $transactionHistory->getTransactions();
} catch (\Readdle\AppStoreServerAPI\Exception\AppStoreServerAPIException $e) {
    exit($e->getMessage());
}

```

### App Store Server Notifications

[](#app-store-server-notifications)

```
try {
    $responseBodyV2 = \Readdle\AppStoreServerAPI\ResponseBodyV2::createFromRawNotification(
        '{"signedPayload":"..."}',
        \Readdle\AppStoreServerAPI\Util\Helper::toPEM(file_get_contents('https://www.apple.com/certificateauthority/AppleRootCA-G3.cer'))
    );
} catch (\Readdle\AppStoreServerAPI\Exception\AppStoreServerNotificationException $e) {
    exit('Server notification could not be processed: ' . $e->getMessage());
}

```

Examples
========

[](#examples)

In `examples/` directory you can find examples for all implemented endpoints. Initialization of the API client is separated into `client.php` and used in all examples.

In order to run examples you have to create `credentials.json` and/or `notifications.json` inside `examples/` directory.

`credentials.json` structure should be as follows:

```
{
  "env": "Production",
  "issuerId": "1a2b3c4d-1234-4321-1111-1a2b3c4d5e6f",
  "bundleId": "com.readdle.MyBundle",
  "keyId": "ABC1234DEF",
  "key": "-----BEGIN PRIVATE KEY-----\n\n-----END PRIVATE KEY-----",
  "orderId": "ABC1234DEF",
  "transactionId": "123456789012345"
}

```

In most examples `transactionId` is used. Please, consider that `transactionId` is related to `environment`, so if you put `transactionId` from the sandbox the `environment` property should be `Sandbox` as well, otherwise you'll get `{"errorCode":4040010,"errorMessage":"Transaction id not found."}` error.

For `Order ID lookup` you have to specify `orderId`. This endpoint (and, consequently, the example) is not available in the sandbox environment.

`notification.json` structure is the same as you receive it in your server-to-server notification endpoint:

```
{"signedPayload":""}

```

What is covered
===============

[](#what-is-covered)

### In-app purchase history V1 (Deprecated, but left for backwards compatibility)

[](#in-app-purchase-history-v1-deprecated-but-left-for-backwards-compatibility)

#### [Get Transaction History](https://developer.apple.com/documentation/appstoreserverapi/get_transaction_history_v1)

[](#get-transaction-history)

`AppStoreServerAPI::getTransactionHistory(string $transactionId, array $queryParams)`

Get a customer’s in-app purchase transaction history for your app.

### In-app purchase history V2

[](#in-app-purchase-history-v2)

#### [Get Transaction History](https://developer.apple.com/documentation/appstoreserverapi/get_transaction_history)

[](#get-transaction-history-1)

`AppStoreServerAPI::getTransactionHistoryV2(string $transactionId, array $queryParams)`

Get a customer’s in-app purchase transaction history for your app.

### Transaction Info

[](#transaction-info)

#### [Get Transaction Info](https://developer.apple.com/documentation/appstoreserverapi/get_transaction_info)

[](#get-transaction-info)

`AppStoreServerAPI::getTransactionInfo(string $transactionId)`

Get information about a single transaction for your app.

### Subscription status

[](#subscription-status)

#### [Get All Subscription Statuses](https://developer.apple.com/documentation/appstoreserverapi/get_all_subscription_statuses)

[](#get-all-subscription-statuses)

`AppStoreServerAPI::getAllSubscriptionStatuses(string $transactionId, array $queryParams = [])`

Get the statuses for all of a customer’s auto-renewable subscriptions in your app.

### Consumption information

[](#consumption-information)

#### [Send Consumption Information](https://developer.apple.com/documentation/appstoreserverapi/send_consumption_information)

[](#send-consumption-information)

`AppStoreServerAPI::sendConsumptionInformation(string $transactionId, array $requestBody)`

Send consumption information about a consumable in-app purchase to the App Store after your server receives a consumption request notification.

### Order ID lookup

[](#order-id-lookup)

#### [Look Up Order ID](https://developer.apple.com/documentation/appstoreserverapi/look_up_order_id)

[](#look-up-order-id)

`AppStoreServerAPI::lookUpOrderId(string $orderId)`

Get a customer’s in-app purchases from a receipt using the order ID.

### Refund lookup

[](#refund-lookup)

#### [Get Refund History](https://developer.apple.com/documentation/appstoreserverapi/get_refund_history)

[](#get-refund-history)

`AppStoreServerAPI::getRefundHistory(string $transactionId)`

Get a list of all of a customer’s refunded in-app purchases for your app.

### Subscription-renewal-date extension

[](#subscription-renewal-date-extension)

#### [Extend a Subscription Renewal Date](https://developer.apple.com/documentation/appstoreserverapi/extend_a_subscription_renewal_date)

[](#extend-a-subscription-renewal-date)

`AppStoreServerAPI::extendSubscriptionRenewalDate(string $originalTransactionId, array $requestBody)`

Extends the renewal date of a customer’s active subscription using the original transaction identifier.

#### [Extend Subscription Renewal Dates for All Active Subscribers](https://developer.apple.com/documentation/appstoreserverapi/extend_subscription_renewal_dates_for_all_active_subscribers)

[](#extend-subscription-renewal-dates-for-all-active-subscribers)

`AppStoreServerAPI::massExtendSubscriptionRenewalDate(array $requestBody)`

Uses a subscription’s product identifier to extend the renewal date for all of its eligible active subscribers.

#### [Get Status of Subscription Renewal Date Extensions](https://developer.apple.com/documentation/appstoreserverapi/get_status_of_subscription_renewal_date_extensions)

[](#get-status-of-subscription-renewal-date-extensions)

`AppStoreServerAPI::getStatusOfSubscriptionRenewalDateExtensionsRequest(string $productId, string $requestIdentifier)`

Checks whether a renewal date extension request completed, and provides the final count of successful or failed extensions.

### App Store Server Notifications history

[](#app-store-server-notifications-history)

#### [Get Notification History](https://developer.apple.com/documentation/appstoreserverapi/get_notification_history)

[](#get-notification-history)

`AppStoreServerAPI::getNotificationHistory(array $requestBody)`

Get a list of notifications that the App Store server attempted to send to your server.

### App Store Server Notifications testing

[](#app-store-server-notifications-testing)

#### [Request a Test Notification](https://developer.apple.com/documentation/appstoreserverapi/request_a_test_notification)

[](#request-a-test-notification)

`AppStoreServerAPI::requestTestNotification()`

Ask App Store Server Notifications to send a test notification to your server.

#### [Get Test Notification Status](https://developer.apple.com/documentation/appstoreserverapi/get_test_notification_status)

[](#get-test-notification-status)

`AppStoreServerAPI::getTestNotificationStatus(string $testNotificationToken)`

Check the status of the test App Store server notification sent to your server.

###  Health Score

59

—

FairBetter than 99% of packages

Maintenance87

Actively maintained with recent releases

Popularity52

Moderate usage in the ecosystem

Community25

Small or concentrated contributor base

Maturity59

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 84.9% 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 ~31 days

Recently: every ~74 days

Total

41

Last Release

63d ago

Major Versions

1.0.5 → 2.0.02023-01-25

2.1.0 → 3.0.02023-08-18

2.1.1 → 3.5.12023-10-05

### Community

Maintainers

![](https://www.gravatar.com/avatar/4a4ea37904dcb40c4752a49ec501542f46b5863bc54aa48711a171b85c9aff36?d=identicon)[pkotets](/maintainers/pkotets)

---

Top Contributors

[![pkotets](https://avatars.githubusercontent.com/u/99185488?v=4)](https://github.com/pkotets "pkotets (62 commits)")[![vincentmary](https://avatars.githubusercontent.com/u/10231560?v=4)](https://github.com/vincentmary "vincentmary (2 commits)")[![VladKriachko](https://avatars.githubusercontent.com/u/46848530?v=4)](https://github.com/VladKriachko "VladKriachko (2 commits)")[![JamieSTV](https://avatars.githubusercontent.com/u/92726023?v=4)](https://github.com/JamieSTV "JamieSTV (1 commits)")[![sedlak477](https://avatars.githubusercontent.com/u/11231479?v=4)](https://github.com/sedlak477 "sedlak477 (1 commits)")[![vchori](https://avatars.githubusercontent.com/u/65335676?v=4)](https://github.com/vchori "vchori (1 commits)")[![anegve](https://avatars.githubusercontent.com/u/8741800?v=4)](https://github.com/anegve "anegve (1 commits)")[![xing393939](https://avatars.githubusercontent.com/u/2681291?v=4)](https://github.com/xing393939 "xing393939 (1 commits)")[![BasouKazuma](https://avatars.githubusercontent.com/u/2992557?v=4)](https://github.com/BasouKazuma "BasouKazuma (1 commits)")[![debug-sys](https://avatars.githubusercontent.com/u/70040636?v=4)](https://github.com/debug-sys "debug-sys (1 commits)")

---

Tags

appstorenotificationsphpserver-to-server-notificationsserverapiphpparseritunespurchaseapplein appapp\_storeserver-to-serverserver apiserver notifications

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/readdle-app-store-server-api/health.svg)

```
[![Health](https://phpackages.com/badges/readdle-app-store-server-api/health.svg)](https://phpackages.com/packages/readdle-app-store-server-api)
```

###  Alternatives

[php-mime-mail-parser/php-mime-mail-parser

A fully tested email parser for PHP 8.0+ (mailparse extension wrapper).

9979.6M27](/packages/php-mime-mail-parser-php-mime-mail-parser)[readdle/app-store-receipt-verification

Pure PHP App Store receipt parsing/validation/verification without API calls to App Store API.

25201.4k](/packages/readdle-app-store-receipt-verification)[aporat/store-receipt-validator

PHP receipt validator for Apple App Store and Amazon Appstore

6503.9M9](/packages/aporat-store-receipt-validator)[yanlongli/app-store-server-api

PHP client for App Store Server API. Manage your customers’ App Store transactions from your server.The App Store Server API is a REST API that you call from your server to request and provide information about your customers' in-app purchases. The App Store signs the transaction and subscription renewal information that this API returns using the JSON Web Signature (JWS) specification.App Store Server API is independent of the app’s installation status on the customer’s devices. The App Store server returns information based on the customer’s in-app purchase history regardless of whether the customer installed, removed, or reinstalled the app on their devices.To request transaction and subscription status information with this API, provide any original transaction identifier that belongs to the customer. The transaction history API responds with a complete list of transactions, 20 at a time, starting with the oldest first. The subscription status API returns the status for all of the customer’s subscriptions, organized by their subscription group identifier.Use the Send Consumption Information endpoint to send information to the App Store when customers request a refund for a consumable in-app purchase, after you receive the CONSUMPTION\_REQUEST App Store server notification. Your data helps inform refund decisions.

2532.0k](/packages/yanlongli-app-store-server-api)[tomatophp/filament-accounts

Manage your multi accounts inside your app using 1 table with multi auth and a lot of integrations

748.3k7](/packages/tomatophp-filament-accounts)[djunehor/laravel-sms

Send SMS from your laravel application

385.3k1](/packages/djunehor-laravel-sms)

PHPackages © 2026

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