Errors · Guides
Tell the people it hit
Errors knows people only by id, so it asks your app to tell them, in your own words and language: "we're on it" while you work, "it's fixed" once the fix is live.
1. Turn on the webhook
With MYBEAST_ERRORS_WEBHOOK_SECRET in .env, the Laravel SDK answers POST /mybeast/errors/webhook, outside the web group, so no session and no CSRF token: the signature is the check. The secret is in Errors' Settings → Keys, or already in Secrets.
Then a project admin puts the address in Errors' Settings → Customer notices → Webhook, such as https://app.example.com/mybeast/errors/webhook. Until it is set, nobody can be told from Errors.
2. Listen for the event
Each request whose signature holds becomes a CustomersShouldBeNotified event in your app. Send your own e-mail, in-app message or push from a listener:
use App\Notifications\IssueUpdate;
use App\Models\User;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Event;
use MyBeast\Errors\Laravel\Events\CustomersShouldBeNotified;
// AppServiceProvider::boot()
Event::listen(function (CustomersShouldBeNotified $notice) {
// The same delivery can come again after a failed answer: act once per id.
if (! Cache::add('errors-notice:'.$notice->deliveryId, true, now()->addDay())) {
return;
}
foreach ($notice->people as $person) {
// $notice->kind: 'working-on-it' or 'fixed'
// $person['path']: where they were the last time it happened, such as /invoices/{invoice}
User::find($person['subject'])?->notify(new IssueUpdate($notice->kind, $person['path']));
}
});kindisworking-on-itorfixed.peoplelists each person by the id your app sent, with their account, the last time it hit them, and the method and route they were on, so your message can say where.issuehas the issue's id, title, environment and its address in Errors, for your own log, not for customers.releaseis the release live in that environment.
Your app answers 204 once your listeners have run. A listener that throws makes it 500, and Errors tries again after 1 minute, 5 minutes, 30 minutes, 2 hours and 6 hours, with the same deliveryId: act once per id.
"We're on it"
On an issue that hit customers, Tell them we're on it asks your app to tell everyone it hit. Customers told before hear it again. On Telegram the same button asks first, so a tap in a pocket tells nobody.
"It's fixed"
Resolving an issue asks when its customers should hear it's fixed:
- When the next release is live: the notice waits. When your deploy runs
php artisan mybeast:errors-releasewith a newer release in that environment, it goes out, and the command says how many people will be told. If the issue comes back first, the notice is cancelled; while the project has no webhook, it keeps waiting. - Now - the fix is already live: it goes out at once.
- Don't tell them.
Your own people, marked internal, are never told (Your own people). Each issue's activity says who was asked to tell how many, and when.
The request
A POST with a JSON body, and the headers X-MyBeast-Delivery (the id), X-MyBeast-Event and X-MyBeast-Signature. The SDK reads it for you; this is what it reads.
{
"id": "0193f1c2-5b7e-7a41-9d2e-6f3c1a8b9e04",
"event": "issue.notify",
"created_at": "2026-11-01T09:14:03+00:00",
"data": {
"issue": {
"id": "0193f0aa-1c2d-7e3f-8a4b-5c6d7e8f9a0b",
"title": "Call to a member function total() on null",
"environment": "production",
"url": "https://services.my-beast.com/acme/shop/errors/issues/0193f0aa-1c2d-7e3f-8a4b-5c6d7e8f9a0b"
},
"kind": "fixed",
"release": "4f2a9c81d0e3",
"people": [
{ "subject": "1042", "account": "77", "last_at": "2026-10-31T16:02:11+00:00", "method": "GET", "path": "/invoices/{invoice}" }
]
}
}X-MyBeast-Signature is t=<unix seconds>,v1=<hex>: an HMAC-SHA256 of <t>.<body> under the webhook secret's part after its first dot (whsec_<id>.<secret>). While a secret is being replaced, two v1 values come, and one match is enough. A signature older than five minutes is refused with 401, so a captured request can't be sent again later.
Keep the webhook secret on the server