Status values and exceptions
These are the values you read out of the tables and the exceptions you may catch. All of them are public API: the string values are what is stored, so a migration or a report can rely on them.
Status values
DeliveryStatus — the outbound delivery log
Stored in webhook_deliveries.status.
| Case | Stored | Means |
|---|---|---|
Pending | pending | Queued, not yet attempted or awaiting a retry |
Succeeded | succeeded | The endpoint answered with a success status |
Failed | failed | An attempt failed and another is still due |
Exhausted | exhausted | Every attempt is spent; nothing more will be tried |
Failed and Exhausted are the distinction that matters when you alert: Failed is in
flight, Exhausted is final and needs a human or a redelivery.
WebhookCallStatus — the inbound call log
Stored in webhook_calls.status.
| Case | Stored | Means |
|---|---|---|
Received | received | Verified and stored; the handler job has not finished |
Processed | processed | Your handler completed |
Failed | failed | Your handler threw |
A request whose signature does not verify is answered 401 and never stored, so it has no
status — see Receiving.
VerificationStatus — the result of checking a signature
Returned inside a VerificationResult, not stored.
| Case | Stored | Means |
|---|---|---|
Valid | valid | Signature matches and is inside the tolerance window |
Invalid | invalid | Signature does not match |
Expired | expired | Signature matches but the timestamp is outside the window |
Malformed | malformed | The header could not be parsed at all |
Expired and Invalid are deliberately distinct: a clock-skew problem and a wrong-secret
problem look identical if you collapse them, and they have different fixes.
HealthStatus — endpoint health scoring
Stored in webhook_subscriptions.health_status while
health scoring is on.
| Case | Stored | Means |
|---|---|---|
Healthy | healthy | Delivering normally |
Degraded | degraded | Failing enough to be worth watching |
Failing | failing | Failing badly enough to act on |
Unknown | unknown | Not enough recent deliveries to judge |
Unknown is not a mild Healthy — it means the score has no basis yet, so do not page on it.
OwnerKeyType — the shape of your tenant key
bigint, uuid or ulid. It is a configuration choice made before the first migration,
because it decides the column type of every owner_id — see
Choosing your database.
Exceptions
Worth catching
| Exception | Thrown when |
|---|---|
Webhooks\Exceptions\InvalidPayloadException | An event payload fails the JSON Schema declared for its type. Thrown at dispatch, so you can reject the bad payload where it originates rather than discovering it in the delivery log |
Webhooks\Core\Http\Exceptions\BlockedDestination | The SSRF guard refused the destination — a private, loopback or link-local address, or a host outside your allowlist. See Security |
Webhooks\Server\Exceptions\MissingSigningKey | Asymmetric signing is switched on but no key material is configured. A configuration error, not a runtime condition |
Webhooks\Server\Exceptions\UnknownSignatureScheme | A configured scheme class does not resolve to a real scheme. Also a configuration error |
Webhooks\Client\Exceptions\CorruptRawBody | A stored inbound call cannot return the bytes it received. Relevant if you replay from webhook_calls |
Thrown inside the delivery engine
You will see these in logs and failed-job payloads; catching them in application code is usually the wrong layer, because the engine already handles them.
| Exception | Thrown when |
|---|---|
Webhooks\Core\Http\Exceptions\NonRetryable | A failure that must not be retried. The delivery job marks the delivery final instead of scheduling another attempt |
Webhooks\Server\Exceptions\DeliveryRefused | A queued delivery was refused before it left — its endpoint was switched off or deleted between queueing and sending |
Webhooks\Core\Payload\Exceptions\OffloadFailed | A large body could not be written to, or read back from, the offload disk. See Reliability |
Webhooks\Core\Signing\Exceptions\InvalidMessage | A WebhookMessage was constructed with inconsistent parts — a programming error in a custom scheme |
The engine turns a failed attempt into a delivery row and a lifecycle event; listen to the events rather than catching inside the job.