---
title: "Queue, audit log & replay — Purchases for Laravel | Roundly"
description: "Persist verified notifications on a queue, keep a replayable audit log of every payload, and re-run it with purchases:replay."
url: https://roundly-consulting.com/open-source/docs/purchases-for-laravel/queue-and-audit
language: en
---

[All packages](https://roundly-consulting.com/open-source.md)

[Purchases for Laravel](https://roundly-consulting.com/open-source/docs/purchases-for-laravel.md)

# 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:

```bash
PURCHASES_QUEUE_ENABLED=true
PURCHASES_QUEUE_CONNECTION=redis
PURCHASES_QUEUE_NAME=purchases
```

With 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')):

```php
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;         // ?Carbon
```

## Replay

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:

```bash
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 date
```

## Show 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 crypto](https://roundly-consulting.com/support-us.md)

By donating, you agree to our [donation terms](https://roundly-consulting.com/donation-terms.md).

[Support our open source work (opens in a new tab)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Join us on Patreon (opens in a new tab)](https://www.patreon.com/cw/roundly)

## 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.

[Get a quote in 48 hours](https://roundly-consulting.com/contact.md) [Browse all packages](https://roundly-consulting.com/open-source/docs/purchases-for-laravel.md)
