Loading...
Loading...
Webhook docs
This page keeps the webhook story direct: what headers arrive, how to verify signatures, when retries fire, and which event payloads your handler will actually receive.
The best validation loop is to create one sandbox payment, let the webhook fire into your test endpoint, and confirm the same payload contract you will rely on in production.
Delivery check
Signed delivery
What to confirm
Every webhook request includes `webhook-id`, `webhook-timestamp`, and `webhook-signature` so the payload can be verified without an SDK dependency.
Delivery check
Mode-safe rollout
What to confirm
You can rehearse your handler with test events first, then keep the same verification logic when you promote to live deliveries.
Delivery check
Retry visibility
What to confirm
The retry schedule is explicit, so operators know when a failed endpoint is still recoverable and when the queue needs attention.
Keep this page open when the live question is not "which events exist?" but "what exactly gets signed, retried, and delivered right now?"
Overview
Payvra sends webhook deliveries as signed HTTP POST requests. Each delivery contains the event payload plus the headers required to prove the request came from Payvra.
The contract mirrors the rest of the product: explicit event names, explicit retry behavior, and enough metadata to make handlers idempotent and debuggable.
Getting started
Create an endpoint
Accept POST requests, store the raw body, and return a 2xx response quickly so the retry queue does not engage unnecessarily.
Register the endpoint in Payvra
Create the endpoint in the dashboard, subscribe only to the events you need, and save the generated endpoint signing secret immediately.
Verify before processing
Check the timestamp, compute the HMAC signature, and only then hand the event to your application logic or job queue.
Event catalog
Expand any event below to inspect the JSON schema or copy an example payload for handler tests.
Review each event contract before you subscribe the endpoint to this category.
10 documented events
payment.detected
Fired when an incoming transaction is detected for a payment.
Payment event
Version 1.0
Status: active
payment.confirmed
Fired when a payment reaches required confirmations and is finalized.
Payment event
Version 1.0
Status: active
payment.settled
Fired when a payment is auto-converted and the merchant's balance is credited.
Payment event
Version 1.0
Status: active
payment.failed
Fired when a payment fails.
Payment event
Version 1.0
Status: active
payment.expired
Fired when a payment expires before being confirmed.
Payment event
Version 1.0
Status: active
payment.overpaid
Fired when a payment is detected with an amount exceeding the expected amount beyond the configured tolerance.
Payment event
Version 1.0
Status: active
payment.underpaid
Fired when a payment is detected with an amount below the expected amount beyond the configured tolerance.
Payment event
Version 1.0
Status: active
payment.rate_updated
Fired when a fiat-denominated payment's exchange rate is refreshed after the rate lock expires.
Payment event
Version 1.0
Status: active
payment.underpayment_resolved
Fired when a merchant resolves an underpaid payment (accepts as-is or initiates refund).
Payment event
Version 1.0
Status: active
payment.topup_detected
Fired when an additional transfer is detected on an underpaid payment's deposit address, supplementing the original shortfall.
Payment event
Version 1.0
Status: active
Review each event contract before you subscribe the endpoint to this category.
3 documented events
withdrawal.initiated
Fired when a merchant initiates a withdrawal.
Withdrawal event
Version 1.0
Status: active
withdrawal.completed
Fired when a withdrawal is completed and confirmed on-chain.
Withdrawal event
Version 1.0
Status: active
withdrawal.failed
Fired when a withdrawal fails.
Withdrawal event
Version 1.0
Status: active
Review each event contract before you subscribe the endpoint to this category.
3 documented events
settlement.completed
Fired when the scheduled settlement job creates and debits a settlement withdrawal for a merchant.
Settlement event
Version 1.0
Status: active
settlement.schedules_paused
Fired when a merchant pauses all active settlement schedules during a treasury freeze.
Settlement event
Version 1.0
Status: active
settlement.schedules_resumed
Fired when a merchant resumes schedules previously suspended by pause-all.
Settlement event
Version 1.0
Status: active
Review each event contract before you subscribe the endpoint to this category.
3 documented events
refund.initiated
Fired when a merchant initiates a refund for a payment.
Refund event
Version 1.0
Status: active
refund.completed
Fired when a refund is completed and the merchant's balance has been debited.
Refund event
Version 1.0
Status: active
refund.failed
Fired when a refund fails.
Refund event
Version 1.0
Status: active
Review each event contract before you subscribe the endpoint to this category.
2 documented events
batch_payout.completed
Fired when a batch payout completes (fully or partially).
Batch Payout event
Version 1.0
Status: active
batch_payout.failed
Fired when all recipients in a batch payout fail.
Batch Payout event
Version 1.0
Status: active
Review each event contract before you subscribe the endpoint to this category.
3 documented events
user.created
Fired when a new user account is created.
User event
Version 1.0
Status: active
user.updated
Fired when a user profile is updated.
User event
Version 1.0
Status: active
user.deleted
Fired when a user account is permanently deleted.
User event
Version 1.0
Status: active
Review each event contract before you subscribe the endpoint to this category.
2 documented events
user.signed_in
Fired when a user signs in to their account.
Auth event
Version 1.0
Status: active
user.signed_out
Fired when a user signs out of their account.
Auth event
Version 1.0
Status: active
Review each event contract before you subscribe the endpoint to this category.
2 documented events
api_key.created
Fired when a new API key is created.
API Key event
Version 1.0
Status: active
api_key.revoked
Fired when an API key is revoked.
API Key event
Version 1.0
Status: active
Live tester
Run a demo scenario to see the full payload for each event in a payment lifecycle. Every event below uses real example data from the event registry.
Press Run demo to simulate a payment lifecycle.
Events will stream in as they would from a live Pusher channel.
Headers
Header
webhook-idPurpose
Unique delivery identifier. Use it as your idempotency key and as the first lookup field when an operator reports a duplicate send.
Example
msg_2xAu8K0QmL...Header
webhook-timestampPurpose
Unix timestamp in seconds. Reject stale requests before doing any application work.
Example
1705312800Header
webhook-signaturePurpose
HMAC-SHA256 signature in the `v1,<base64>` format computed over `{webhookId}.{timestamp}.{body}` using the endpoint signing secret.
Example
v1,K7gNU3sdo+O...Header
webhook-account-signaturePurpose
Optional HMAC-SHA256 signature using the account-level signing secret. Only sent when an account secret is configured for the active environment; verifiers can accept either signature.
Example
v1,b9rQ3yLP4qz...Header
content-typePurpose
Always `application/json`. The raw body is part of the signed content, so store it exactly as received.
Example
application/jsonSigning secrets
Every Payvra webhook endpoint is created with its own endpoint signing secret. It is the default verifier and it is what you will configure first.
An optional account-level signing secret lives on the developer page. When configured, every delivery for that environment also carries a webhook-account-signature header. Verifiers can accept either signature, which is useful when one shared HMAC key is easier to operate than dozens of per-endpoint secrets.
Endpoint signing secret (default)
Per-endpoint, rotated independently, scoped to a single destination. Choose this when you want incident blast-radius contained to one endpoint and when you operate a small number of webhooks.
Account-level signing secret (optional)
One shared verifier per environment for every webhook your account dispatches. Choose this when you operate many endpoints and prefer one HMAC key in your handler. Add it on the developer page; rotation has the same 24-hour grace window as the endpoint secret.
Both (recommended for large fleets)
When the account-level secret is configured, deliveries carry both signatures. Verifiers can prefer one and fall back to the other, which makes endpoint secret rotation invisible to handlers that already trust the account secret.
Signature verification
The signed content is built as{webhookId}.{timestamp}.{body}using the raw JSON body string.
Compute the HMAC-SHA256 digest with your endpoint signing secret, base64 encode it, and compare it against the received value after the v1, prefix. When an account-level secret is configured, you can run the same computation against webhook-account-signature and accept either match.
Replay protection rule:reject requests older than five minutes before you inspect the payload.
import crypto from "crypto";function verifyWebhookSignature( rawBody: string, headers: Record<string, string>, secret: string,): boolean { const webhookId = headers["webhook-id"]; const timestamp = headers["webhook-timestamp"]; const signature = headers["webhook-signature"]; const now = Math.floor(Date.now() / 1000); if (Math.abs(now - Number(timestamp)) > 300) { return false; } const signedContent = `${webhookId}.${timestamp}.${rawBody}`; const expected = crypto .createHmac("sha256", secret) .update(signedContent) .digest("base64"); const received = signature.replace("v1,", ""); return crypto.timingSafeEqual( Buffer.from(received, "base64"), Buffer.from(expected, "base64"), );}Retry policy
If an endpoint does not return a 2xx status code within 30 seconds, Payvra retries the delivery. Each event is attempted up to five times.
Attempt
1
Delay
1 minute
Time since first attempt
1 minute
Attempt
2
Delay
5 minutes
Time since first attempt
6 minutes
Attempt
3
Delay
15 minutes
Time since first attempt
21 minutes
Attempt
4
Delay
1 hour
Time since first attempt
1 hour 21 minutes
Attempt
5
Delay
4 hours
Time since first attempt
5 hours 21 minutes
Auto-disable rule
If an endpoint fails ten consecutive deliveries, Payvra disables it automatically and sends an email so the operator can fix the handler before re-enabling the endpoint.
Best practices
Respond quickly with 2xx
Return 200 or 202 as soon as you have durably accepted the event, then continue the heavier work asynchronously.
Use webhook-id for idempotency
Persist the delivery id before processing so retries and duplicate sends cannot create double side effects.
Reject stale timestamps
A five-minute tolerance is enough to stop replay attacks without breaking legitimate deliveries delayed by short network hiccups.
Log enough for recovery
Store the delivery id, event name, response status, and handler error so operators can reconcile failures quickly.
Testing
Dashboard test send
Use the dashboard to send a signed test event to a registered endpoint and confirm the handler path end to end.
webhook.site
Register a temporary capture URL when you need to inspect headers and payload shape before wiring application code.
ngrok or local tunnel
Expose your local handler for real signed deliveries while you finish verification and idempotency logic.