Webhooks
Webhooks notify your application in real-time when events occur in Loyva. Instead of polling the API, you receive signed HTTP POST requests at your configured URL.
Setup
Webhook URLs are configured on your partner API key. You can manage them self-serve at any time using PATCH /api/v2/partner/webhook:
curl -X PATCH https://api.stg.loyva.net/api/v2/partner/webhook \
-H "X-API-Key: lk_..." \
-H "Content-Type: application/json" \
-d '{
"webhook_url": "https://your-app.com/webhooks/loyva",
"webhook_secret": "your-hmac-signing-secret-min-16-chars"
}'
Changes take effect immediately on the next delivery. To rotate the secret without changing the URL, omit webhook_url. Pass null for either field to clear it.
To fire a one-off test event against your endpoint (useful for validating signature verification before going live), ask your Loyva point of contact to trigger a webhook.test delivery via the admin console.
Webhook payload format
Every webhook body is JSON with the following shape:
{
"event_type": "vault.stored",
"event_id": "evt_9f3a2b1c4d5e6f7a8b9c0d1e",
"org_id": "org_abc123",
"envelope_id": "env_x7k9m2p4q1w3",
"timestamp": "2026-04-11T10:15:00.000Z",
"data": {
"path": "ucc-vault/org_abc123/env_x7k9m2p4q1w3/signed.pdf",
"hash": "a1b2c3d4..."
}
}
| Field | Type | Description |
|---|---|---|
event_type | string | One of the documented event types |
event_id | string | Unique event identifier (stable across retries) |
org_id | string | Organization the event belongs to |
envelope_id | string | null | Envelope ID (null for events like webhook.test) |
timestamp | string | ISO 8601 event time |
data | object | Event-specific payload |
Headers
Loyva sends these headers with every webhook request:
| Header | Description |
|---|---|
Content-Type | application/json |
User-Agent | Loyva-Webhooks/1.0 |
X-Loyva-Event | Event type (mirrors event_type in body) |
X-Loyva-Delivery | Unique delivery ID for correlating retries |
X-Loyva-Signature | sha256=<hex> HMAC-SHA256 signature of the raw body (only present if a webhook_secret is configured) |
Responding to webhooks
- Return a
2xxstatus code to acknowledge receipt - Loyva retries on non-2xx responses or network errors with exponential backoff: 1 min, 5 min, 30 min, 2 hr, 8 hr (up to 5 total attempts)
- Process webhooks asynchronously — return
200immediately and process in the background - Use
event_idfor idempotency; it is stable across retries
app.post('/webhooks/loyva', (req, res) => {
// Verify signature first (see Verification page)
// Acknowledge immediately
res.status(200).json({ received: true });
// Process asynchronously (deduplicate on event_id)
processWebhookAsync(req.body);
});
Delivery log
Every attempted delivery is recorded by Loyva (delivery ID, status code, attempts, next retry time). Ask your Loyva point of contact for a paginated log against your key.
Next steps
- Events — Complete list of webhook events
- Verification — Verify webhook signatures