Webhooks
Levl can notify your system in real time when events occur (e.g., transfer status changes). This page explains how to register webhook endpoints, what payloads look like, how to verify signatures, retries, and best practices.
Register and manage endpoints
Use the API to manage webhook endpoints:
- POST
/webhook-endpoints
— Register a webhook endpoint - GET
/webhook-endpoints
— List webhook endpoints - PUT
/webhook-endpoints/{webhookId}
— Update a webhook endpoint - DELETE
/webhook-endpoints/{webhookId}
— Delete a webhook endpoint
Your endpoint URL must be reachable over HTTPS in production.
Delivery format
Webhooks are sent as HTTP POST requests with JSON bodies.
Headers:
Content-Type: application/json
User-Agent: Levl-Webhooks/1.0
Levl-Signature: t={iso-8601-timestamp},v0={hex-hmac}
Body (example):
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"version": "2025-08-08",
"type": "transfer.status_changed",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440001",
"status": "SENT"
},
"created_at": "2025-08-12T10:48:12.123456"
}
Only status-change events are emitted; data
contains the final state for the entity.
Signature verification
Every webhook includes a Levl-Signature
header so you can verify authenticity.
Steps:
- Parse header into timestamp (
t
) and signature (v0
). - Create the signed payload string:
t + '.' + raw_request_body
. - Compute HMAC-SHA256 of that string using your endpoint's secret.
- Compare your computed hex digest to
v0
using a constant-time comparison. - Reject if the timestamp is older than 5 minutes from your current time.
Pseudocode:
header = request.headers["Levl-Signature"] // e.g. t=2025-08-12T10:48:12.123456,v0=abc123...
t, v0 = parse(header)
signed = t + "." + rawBody
expected = HMAC_SHA256_HEX(secret, signed)
if !constantTimeEquals(expected, v0) -> reject
if now() - parseIsoInstant(t) > 5 minutes -> reject
Secrets are supplied by you at registration time and are never returned by the API. To change a secret, register a new endpoint (you may reuse the same URL) with a different secret and switch over on your side.
Retries and idempotency
- Levl retries failed deliveries with exponential backoff (immediate, 5m, 30m, 2h, 6h, 24h).
- Use the event
id
to de-duplicate; process an event only once even if delivered multiple times.
Best practices
- Respond quickly with 2xx and process asynchronously.
- Verify signatures and timestamps on every request.
- Log failures and monitor consecutive failures; manage your own secret rotation by registering a new endpoint when you change the secret.
Updated 16 days ago