Queue, audit log & replay
Background processing
Set PURCHASES_QUEUE_ENABLED=true to verify synchronously but persist on a queue. The webhook still answers 204 immediately; a ProcessProviderNotification job records the result on the configured connection and queue and marks the audit row processed. The synchronous path is the default:
PURCHASES_QUEUE_ENABLED=true
PURCHASES_QUEUE_CONNECTION=redis
PURCHASES_QUEUE_NAME=purchasesWith the queue on, handle() returns the PurchaseNotification describing what was queued — or an unsaved placeholder when the audit log is off.
Audit log
With PURCHASES_AUDIT_ENABLED=true (the default), every verified notification is stored in purchase_notifications — provider, type, a signature-verified flag, a snapshot of the normalized result and raw payload, and processed_at — before it is reduced to model state. So is every result passed to Purchases::sync(), with signature_verified false and an origin of host, because the package never verified it (query it with where('payload->origin', 'host')):
use RoundlyConsulting\Purchases\Models\PurchaseNotification;
PurchaseNotification::forProvider('apple')->pending()->get(); // recorded, not yet processed
$notification->provider; // 'apple'
$notification->type; // 'subscription', 'purchase', 'refund' …
$notification->signature_verified; // bool — false for a sync() row
$notification->origin(); // NotificationOrigin::Provider, or ::Host for a sync() row
$notification->payload; // Collection — the stored snapshot
$notification->processed_at; // ?CarbonReplay
purchases:replay selects stored notifications and replays each through Purchases::replay() — events included — so you can recover from a downstream failure without waiting for a store to resend anything. One it must not or cannot replay (a provider notification that failed verification, or a snapshot that no longer rebuilds) is reported as skipped and the rest continue; host-synced rows replay:
php artisan purchases:replay # every stored notification
php artisan purchases:replay 42 # a single notification by id
php artisan purchases:replay --provider=stripe # one provider
php artisan purchases:replay --since=2026-01-01 # recorded on or after a dateShow your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.