Webhooks · Available now
Delivery & events
Webhooks are how most apps integrate with Valverna. Instead of polling GET /v1/transactions, subscribe once and receive signed HTTPS callbacks the instant a
transaction is created on a business that authorized your app.
How delivery works
Event types
Subscribe to any subset per endpoint. New event types will be added behind feature flags so existing subscriptions never break.
transaction.created A new transaction document was ingested from any connected source. Documents are immutable — refunds, credit notes, voids, and exchanges arrive as new linked documents, each firing its own event.
authorization.granted A merchant approved your app's access request.
authorization.revoked A merchant revoked your app's access. Stop making requests with that token.
source.connected The merchant connected a new payment platform (Stripe, Klarna, etc).
source.disconnected A payment platform connection was removed. Backfill may be incomplete.
Payload shape
Every webhook carries the same envelope — including a top-level schemaVersion string (currently "2.1"). The data field matches the shape of the underlying resource — for transaction events, this is a full canonical transaction.
Example event
{ "eventId": "evt_7c4b1d9f", "schemaVersion": "2.1", "type": "transaction.created", "businessId": "biz_9f3a2c81", "createdAt": "2026-05-12T12:32:20Z", "data": { "id": "txn_a1b2c3d4", "profileId": "se-receipt-1", "documentTier": "receipt", "type": "sale", "settled": true, "currency": "SEK", "totals": { "subtotal": 28200, "discount": 0, "tax": 3733, "rounding": 0, "total": 28200 }, "source": { "platform": "izettle", "externalId": "iz_pay_9f8e7d6c", … }, … } }
Verifying signatures
Every request carries a Valverna-Signature header of the form t=<unix>,nonce=<hex>,v1=<hmac>.
The v1 value is an HMAC-SHA256, keyed with your signing secret, over the
string <t>.<nonce>.<rawBody>. Recompute it and reject any request where it doesn't match.
Request headers
Valverna-Signature: t=1743588842,nonce=9f2a4c8e1b...,v1=c7b3a8e2... Valverna-Event: transaction.created Content-Type: application/json
Reject any request whose t is outside a tolerance window — we recommend 5 minutes — to bound replays. For stricter protection, record the nonce values you've accepted within that window and reject repeats; a retried delivery
carries a fresh nonce, so dedupe events on the body's eventId, not the nonce.
Retries & delivery guarantees
Delivery is at-least-once. If your endpoint returns non-2xx or times out (>10s), Valverna retries on an exponential backoff schedule.
Attempt 1
Immediate
Attempt 2
+ 30 seconds
Attempt 3
+ 5 minutes
Attempt 4
+ 30 minutes
Attempt 5
+ 2 hours
Attempt 6
+ 12 hours — final
After six failed attempts, the event is marked failed and stops retrying.
Fetch any missed state via GET /v1/transactions — it stays the source of truth for backfill and reconciliation.