Skip to main content

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..."
}
}
FieldTypeDescription
event_typestringOne of the documented event types
event_idstringUnique event identifier (stable across retries)
org_idstringOrganization the event belongs to
envelope_idstring | nullEnvelope ID (null for events like webhook.test)
timestampstringISO 8601 event time
dataobjectEvent-specific payload

Headers

Loyva sends these headers with every webhook request:

HeaderDescription
Content-Typeapplication/json
User-AgentLoyva-Webhooks/1.0
X-Loyva-EventEvent type (mirrors event_type in body)
X-Loyva-DeliveryUnique delivery ID for correlating retries
X-Loyva-Signaturesha256=<hex> HMAC-SHA256 signature of the raw body (only present if a webhook_secret is configured)

Responding to webhooks

  • Return a 2xx status 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 200 immediately and process in the background
  • Use event_id for 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