PHP receipt validator for Apple iTunes, Google Play and Amazon App Store
PHP receipt validator for Apple iTunes, Google Play and Amazon App Store
A modern PHP library for validating in-app purchases from the Apple App Store (including legacy iTunes), Google Play and Amazon Appstore. Supports both production and sandbox environments with detailed response parsing.
composer require aporat/store-receipt-validator…ℹ️
Validator::validate()is deprecated as of v9. UsegetTransactionHistory()for paginated history, orgetTransactionInfo()for a single signed transaction.
The AppleAppStore\Validator now covers Apple's full API surface:
| Area | Methods |
|---|---|
| Transactions | getTransactionHistory(), getTransactionInfo(), getAppTransactionInfo(), finishTransaction(), setAppAccountToken(), sendConsumptionInformation() |
| Order / refunds | lookUpOrderId(), getRefundHistory() |
| Subscriptions | getAllSubscriptionStatuses(), extendSubscriptionRenewalDate(), extendSubscriptionRenewalDatesForAllActiveSubscribers(), getStatusOfSubscriptionRenewalDateExtensions() |
| Notifications | requestTestNotification(), getTestNotificationStatus(), getNotificationHistory() |
Each returns a typed response object (Transaction, AppTransaction, SubscriptionStatusResponse, RefundHistoryResponse, NotificationHistoryResponse, …). See the App Store Server API docs for endpoint semantics.
…Authentication uses a Google Cloud service account that has been granted access to your app in the Play Console ("Users and permissions" → invite the service account email with View financial data / Manage orders). Download its JSON key and pass the contents to the validator. Tokens are minted with the OAuth 2.0 JWT bearer flow and cached in memory; no extra Google SDK is required.
…ℹ️ Google has no sandbox endpoint. Licence-tester purchases come back from the production API with a
testPurchasemarker, which the response exposes asisTestPurchase()andEnvironment::SANDBOX.
| Area | Methods |
|---|---|
| Subscriptions | getSubscriptionPurchaseV2(), acknowledgeSubscription(), revokeSubscription() |
| One-time products | getProductPurchase(), acknowledgeProduct(), consumeProduct() |
| Refunds | getVoidedPurchases() |
…If you already use google/auth (or want to share a token cache), implement GooglePlay\JWT\AccessTokenProvider or wrap a callable:
use Google\Auth\Credentials\ServiceAccountCredentials;
use ReceiptValidator\GooglePlay\JWT\CallbackAccessTokenProvider;
$credentials = new ServiceAccountCredentials(
'https://www.googleapis.com/auth/androidpublisher',
'/path/to/service-account.json'
);
$validator = new GooglePlayValidator('com.example.app');
$validator->setAccessTokenProvider(
new CallbackAccessTokenProvider(fn () => $credentials->fetchAuthToken()['access_token'])
);…All validators support PSR-3 compatible logging via setLogger(). By default, a NullLogger is used so no output is produced unless you inject a logger.
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
$logger = new Logger('receipt-validator');
$logger->pushHandler(new StreamHandler('php://stdout'));
$validator = new AppleValidator($signingKey, $keyId, $issuerId, $bundleId);
$validator->setLogger($logger);The method returns $this for fluent chaining:
$response = $validator
->setLogger($logger)
->getTransactionHistory($transactionId);| Level | Events |
|---|---|
DEBUG |
Outgoing API request details (environment, URI, parameters) |
INFO |
Successful responses; environment retries (e.g. production → sandbox) |
WARNING |
API error responses, unexpected HTTP status codes |
ERROR |
Network/connection failures |
……Play publishes notifications to a Cloud Pub/Sub topic; a push subscription POSTs them to your endpoint wrapped in a Pub/Sub envelope. ServerNotification::fromPubSubMessage() unwraps the envelope and decodes the notification.
Unlike Apple's notifications, the payload is not signed and carries no purchase data: it only tells you which purchase token changed. Always re-read the purchase from the API before changing entitlement, and authenticate the push itself (Pub/Sub's OIDC bearer token) at the HTTP layer.
…composer test # Run tests with PHPUnit
composer lint # Run code style checks with PHP_CodeSniffer
composer analyze # Run static analysis with PHPStanContributions are welcome!
To get started:
Found a bug or want a new feature? Open an issue
Apache-2.0 License. See LICENSE.
No open issues yet, or sync has not completed.