Upgrading from 1.x
2.0.0 changes one thing: the root namespace moves from Webhooks\ to Pushery\Webhooks\,
matching every other package in the family (Pushery\WireKit\, Pushery\LegalConsent\).
No behavior changes, no configuration keys move, no table changes. Every class keeps its
name and its position; only the root in front of it is different. The Composer package name
is unchanged — pushery/webhooks-for-laravel.
The change, in one line
-use Webhooks\Server\PendingWebhook;
+use Pushery\Webhooks\Server\PendingWebhook;
For most applications a search and replace over use Webhooks\ and \Webhooks\ is the
whole upgrade. The rest of this page is the part that search and replace does not reach.
1. Drain the queue before you deploy
This is the one that bites, and it bites in production rather than in CI.
A queued job is stored as a serialized payload carrying its own class name. Any
Webhooks\Server\Jobs\CallWebhookJob or Webhooks\Client\Jobs\ProcessWebhookJob still
waiting when the new code goes live cannot be unserialized — the class it names no longer
exists, and the worker fails the job rather than running it.
# Before deploying: let the queue empty, or stop enqueueing and wait it out.
php artisan queue:monitor webhooks
Check failed_jobs too. A failed job retried after the upgrade hits the same wall, so
retry anything you care about before you deploy, or accept that those entries are no longer
replayable and prune them.
Deliveries themselves are safe: a delivery is a row, not a job, and rows carry no class name (see below). Only the in-flight job wrapper is affected.
2. Fix bootstrap/providers.php by hand
The search and replace above does not reach this file, and it is the one that stops the application from booting at all.
Four providers are auto-discovered from composer.json and move with the package. Four are
not, and you register those yourself — so check every one of these four lines, not only the
layers you remember switching on:
// bootstrap/providers.php
Webhooks\Dashboard\WebhooksDashboardServiceProvider::class, // the observability dashboard
Webhooks\Platform\SelfServicePortalServiceProvider::class, // the self-service portal
Webhooks\WebhooksUiServiceProvider::class, // the operator console
Webhooks\Pulse\WebhookPulseServiceProvider::class, // the Laravel Pulse card
A provider list holds a bare class name — no use, no leading backslash — so neither
use Webhooks\ nor \Webhooks\ matches it. Prefix the ones you have:
-Webhooks\Dashboard\WebhooksDashboardServiceProvider::class,
+Pushery\Webhooks\Dashboard\WebhooksDashboardServiceProvider::class,
Miss it and the application does not start: Laravel resolves the provider list on every request, and a class name that no longer exists is a fatal on boot rather than a feature that quietly stops working. If you registered none of the three, this step is empty.
3. Re-publish anything you published
Published copies live in your application and still carry the old imports. Re-run the tags you use, or edit the imports by hand:
php artisan vendor:publish --tag=webhooks-migrations --force
php artisan vendor:publish --tag=webhooks-client-migrations --force
php artisan vendor:publish --tag=webhooks-server-migrations --force
php artisan vendor:publish --tag=webhooks-dashboard-migrations --force
php artisan vendor:publish --tag=webhooks-dashboard-views --force
php artisan vendor:publish --tag=webhooks-self-service-views --force
php artisan vendor:publish --tag=webhooks-views --force
# The operator console — ONE of these two, whichever variant you published.
# They write to the same destination, so running both leaves you with the second.
php artisan vendor:publish --tag=webhooks-ui --force
php artisan vendor:publish --tag=webhooks-ui-wirekit --force
--force overwrites your editsIf you have customized a published view or migration, do not use --force. Fix it in place
instead.
For a published view there is one more edit than the imports, and it is easy to miss because nothing about it looks like a namespace:
- wire:click="delete({{ $subscription->id }})"
+ wire:click="destroy({{ $subscription->id }})"
delete() still exists and still works, so a published copy that keeps calling it is not
broken by this release. What it already was, before 2.0, is broken under a strict
Content-Security-Policy: without unsafe-eval Livewire parses wire: expressions with its
own parser, and delete is a keyword there — the expression never was a call, so the button
rendered, the confirmation appeared, and nothing happened. That is why the method was renamed.
Change the one line, or re-publish the view, and the button works under a CSP too.
A published migration that already ran does not need to run again. Its imports still have to be corrected, or the file fails to load the next time Laravel scans the directory.
The Livewire component aliases are unchanged (webhooks.self-service.endpoint-list and the
rest are plain strings, not class names), so a view that mounts a panel by alias needs no
edit at all.
4. Clear every cache that stores a resolved class name
php artisan config:clear
php artisan route:clear
php artisan optimize:clear
A cached configuration holds the resolved signature-scheme class, a cached route table
holds the controller class. Both name the old root and neither is refreshed by
composer update. If you rebuild caches in your deploy, make sure the clear happens after
the new code is in place.
5. Update config values that name a package class
Only if you set them — each defaults to a package class that the new version resolves for
you. Look for these keys in your published config/webhooks.php:
| Key | Names a class when you set it |
|---|---|
core.signing.scheme | a SignatureScheme |
client.configs.*.scheme | a SignatureScheme |
client.configs.*.profile | a WebhookProfile |
client.configs.*.response | a RespondsToWebhook |
client.configs.*.model | a WebhookCall subclass |
client.configs.*.dedupe_id | a DedupeKeyResolver |
dashboard.source_model | a WebhookDelivery subclass |
A class of your own in any of these — a custom verifier, your own job — is unaffected.
Only names starting Webhooks\ move.
6. Your tests
Type hints, expect(...)->toBeInstanceOf(...), Event::assertDispatched(...), mocks and
Bus::assertDispatched(...) all name package classes. The same search and replace covers
them.
What you do NOT have to do
No database migration. No stored row holds a package class name — verified rather than assumed:
- The package registers no morph map, and
owner_typeonwebhook_subscriptionsandwebhook_deliveriesholds your model (App\Models\User,App\Models\Team), never a package class. - No shipped migration writes a class name into a column.
event_typeholds your event strings;statusholds an enum value, not its class.
So the delivery log, the subscriptions and their secrets all survive the upgrade untouched. The only place a package class name is stored anywhere is a pending queue payload, which is why draining the queue is step one and the only step with a deadline.
Why the namespace moved at all
Every other package in this family is namespaced Pushery\…, and this one was the
exception. A consuming application wrote use Pushery\Webhooks\Enums\DeliveryStatus; from
memory, got a class-not-found at runtime, and was right about the convention and wrong about
this package. Making the odd one out match is worth one breaking release; leaving it is a
tax on every developer who knows the rest of the family.