Webhooks are the backbone of any asynchronous payment system. They notify your application when a payment succeeds, fails, or is refunded. However, handling them at scale presents unique challenges.
The Challenge: Reliability
What happens if your server is down when Lumen Pay sends a webhook? Or if your database locks up? If you miss a "payment.success" webhook, you might never deliver the product to the customer.
Best Practices
1. Idempotency
Always design your webhook handler to be idempotent. This means that processing the same webhook event twice should have the same effect as processing it once. We send a unique `event_id` with every webhook. Store this ID and check it before processing.
if (Event::exists($payload['id'])) {
return response('Already processed', 200);
}2. Respond Quickly
Do not perform heavy logic (like sending emails or generating PDFs) inside the webhook controller. Acknowledge receipt with a `200 OK` immediately, and push the actual work to a background queue.
3. Verify Signatures
As mentioned in our security post, always verify the `HTTP_X_LUMEN_SIGNATURE` to ensure the request actually came from us.
4. Handle Retries Gracefully
Lumen Pay uses exponential backoff. If your server returns a 500 error, we will retry sending the webhook after 1 minute, then 5 minutes, then 30 minutes, up to 24 hours. Ensure your logs monitor for these failures.