---
title: "Webhook routes — Purchases for Laravel | Roundly"
description: "An opt-in POST /purchases/webhooks/{provider} endpoint that verifies, records, fires events and answers 204."
url: https://roundly-consulting.com/open-source/docs/purchases-for-laravel/webhooks
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)

# Webhook routes

The bundled webhook route is disabled by default, and only an explicit on value enables it: a switch that is not set (missing from a partly published routes array, null, blank or an unset env var) keeps it off — up to 1.1.8 such a switch loaded it. Enable it and the package registers POST {prefix}/webhooks/{provider} (route name purchases.webhooks), which verifies, records, fires events and returns 204 No Content:

```bash
PURCHASES_ROUTES_ENABLED=true
PURCHASES_ROUTES_PREFIX=purchases
```

- 204 — verified and recorded (or queued), or only audited — an informational notification, a Google RTDN for another app.
- 400 — signature or credential verification failed, a Google push wasn’t authenticated, an Apple request carried no signedPayload string, or a Google RTDN named a . or .. token.
- 404 — no provider is registered under that id.
- 500 — a store read during verification failed (a Google subscription read with any error but 410, Stripe’s Invoice Payments lookup) or the store was unreachable. The store redelivers.

Point each store’s server notifications at its URL:

```
POST https://your-app.test/purchases/webhooks/apple
POST https://your-app.test/purchases/webhooks/google
POST https://your-app.test/purchases/webhooks/stripe
```

The route takes signed store events only. Verify a client’s Google purchase token or Stripe redirect from your own route with callback() — see Client callbacks.

## Customising the route

routes.prefix and routes.middleware shape the route; the default api middleware group carries no CSRF check. For full control, publish the routes file with the purchases-routes tag, or call Purchases::handle() from your own controller — see The Purchases facade:

```php
// config/purchases.php
'routes' => [
    'enabled' => env('PURCHASES_ROUTES_ENABLED', false),
    'prefix' => env('PURCHASES_ROUTES_PREFIX', 'purchases'),
    'middleware' => ['api'],
],
```

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