A webhook arrives over HTTP, but it does not behave like an ordinary user request. Providers retry, networks delay packets, and events can arrive twice or out of order. A reliable Laravel webhook endpoint treats those conditions as routine rather than exceptional.
Verify the raw request before trusting it
Most providers sign the exact request body with a shared secret or asymmetric key. Verify the signature against the raw bytes before parsing or changing whitespace. Use a constant-time comparison and follow the provider’s documented scheme rather than designing your own.
If a timestamp is part of the signature, reject events outside a reasonable tolerance to reduce replay risk. Store secrets outside source control and support rotation with a short overlap where necessary.
Acknowledge quickly, process asynchronously
Providers usually have short timeouts. Verify the signature, record the event durably, dispatch work, and return a successful response. Do not call several internal services or send email while the provider waits.
Persisting before acknowledgement is important. If you return 200 and then the process dies before the event is stored, the provider believes delivery succeeded while your system has lost it.
Make processing idempotent
Use the provider’s event ID as a unique key. Insert the receipt once and skip an already processed business effect. Database uniqueness is stronger than a check-then-insert sequence that can race under concurrent delivery.
$event = WebhookEvent::firstOrCreate(
['provider' => 'example', 'external_id' => $payload['id']],
['payload' => $payload, 'status' => 'received']
);
if (! $event->wasRecentlyCreated) {
return response()->noContent();
}
The operation triggered by the event should also be idempotent. A duplicated payment confirmation must not credit an account twice even if the receipt layer is bypassed.
Expect events to arrive out of order
An “updated” event may arrive before “created,” or an old delivery can follow a new one. Compare provider sequence numbers or event timestamps where the contract supports them. Better still, treat some events as a reason to fetch current state from the provider instead of replaying every intermediate mutation.
Retry only transient failures
Timeouts and selected 5xx responses may recover. Invalid payloads and missing configuration usually will not. Configure exponential backoff with a maximum attempt count, then move permanent failures to a visible failed state. Infinite retries can bury a queue and amplify an outage.
Keep an audit trail without leaking secrets
Record provider, event ID, type, received time, processing status, attempts, and safe error context. Payload retention should reflect privacy requirements; redact tokens and unnecessary personal data. A support tool to search and replay an event is extremely useful, but replay must run the same idempotent path.
Reconcile important state
Webhooks are notifications, not always a complete ledger. For payments, subscriptions, and logistics, schedule reconciliation against the provider’s API. It catches missed delivery, prolonged outages, and bugs in processing logic.
Test the failure modes
- Valid and invalid signatures
- Duplicate delivery, including concurrent duplicates
- Out-of-order events
- Queue failure and safe replay
- Provider timeout and malformed payload
For broader integration design, read resilient third-party APIs in Laravel. The API and backend architecture service covers webhooks, queues, and operational monitoring as one connected workflow.
Frequently asked questions
Why should a webhook endpoint respond quickly?
Providers enforce short timeouts and retry failures. Verify, persist, enqueue, and return before doing expensive business work.
How do I stop duplicate webhook processing?
Store a provider event ID or a derived idempotency key and enforce uniqueness before applying the business effect.