Webhooks are HTTP POST requests that Lyel Pay sends to your server when something happens — a payment completes, fails, or expires. They are the recommended way to trigger business logic like fulfilling orders or sending receipts.
How to set up a webhook endpoint
1. Create the endpoint
Your endpoint must:
- Accept
POST requests
- Return
2xx within a reasonable time (we recommend < 5 seconds)
- Process the raw request body (not parsed JSON) for signature validation
2. Register your URL in the dashboard
Go to your dashboard → Settings → Webhooks → Add endpoint.
Copy the Webhook Secret shown — you’ll need it for signature validation.
Signature validation
Every webhook request includes a lyel-signature header:
| Part | Description |
|---|
t | Unix timestamp (seconds) when the event was sent |
v1 | HMAC-SHA256 signature |
The signature is computed as:
constructEvent() handles this automatically, including:
- Parsing the header
- Recomputing the signature
- Rejecting events older than 5 minutes (to prevent replay attacks)
- Using
timingSafeEqual to prevent timing attacks
If you parse the body with express.json() before the raw body middleware, the signature check will fail because the body will be re-serialized and the bytes will differ.
Event types
payment.completed
Fired when a payment intent reaches COMPLETED status.
payment.failed
Fired when a payment attempt fails (e.g. insufficient balance, wrong OTP).
payment.expired
Fired when a payment intent passes its expiry time without being completed.
Idempotency
Webhooks may be delivered more than once. Design your handler to be idempotent — processing the same event twice should not cause double charges or duplicate fulfillments.
Retries
If your endpoint returns a non-2xx status, Lyel Pay will retry the delivery. The retry schedule is:
| Attempt | Delay |
|---|
| 1st retry | 5 minutes |
| 2nd retry | 30 minutes |
| 3rd retry | 2 hours |
| 4th retry | 12 hours |
After 4 failed retries, the event is marked as undelivered. You can manually replay events from your dashboard.
Testing webhooks locally
Use a tunneling tool to expose your local server:
Register the generated HTTPS URL as your webhook endpoint in the dashboard during development.