Webhooks
Webhooks push event notifications to your server as payments move through their lifecycle. ZendFi signs every webhook delivery with HMAC-SHA256 so you can verify authenticity, and retries failed deliveries with exponential backoff.How It Works
Webhook Configuration
Set your webhook URL in the ZendFi Dashboard or duringzendfi init with the CLI. Every webhook registered under your merchant account receives all event types.
Event Types
All events your webhook endpoint can receive:Payment Events
| Event | Description |
|---|---|
PaymentCreated | A new payment has been created |
PaymentConfirmed | Payment confirmed on-chain |
PaymentFailed | Payment failed or was rejected |
PaymentExpired | Payment expired before completion |
Payment Intent Events
| Event | Description |
|---|---|
PaymentIntentCreated | Payment intent created |
PaymentIntentRequiresPayment | Intent awaiting customer payment |
PaymentIntentSucceeded | Intent completed successfully |
PaymentIntentCanceled | Intent was cancelled |
PaymentIntentFailed | Intent failed |
Settlement Events
| Event | Description |
|---|---|
SettlementCompleted | Funds settled to merchant wallet |
SettlementFailed | Settlement transfer failed |
Withdrawal Events
| Event | Description |
|---|---|
WithdrawalInitiated | Withdrawal request submitted |
WithdrawalCompleted | Withdrawal confirmed on-chain |
WithdrawalFailed | Withdrawal failed |
Subscription Events
| Event | Description |
|---|---|
SubscriptionCreated | New subscription started |
SubscriptionCancelled | Subscription cancelled |
SubscriptionRenewed | Subscription successfully renewed |
SubscriptionPaymentFailed | Subscription renewal payment failed |
Installment Events
| Event | Description |
|---|---|
InstallmentPaid | Installment payment confirmed |
InstallmentLate | Installment past due date |
InstallmentDefaulted | Installment defaulted (past grace period) |
InstallmentPlanCompleted | All installments paid |
Payment Link Events
| Event | Description |
|---|---|
PaymentLinkCreated | Payment link generated |
PaymentLinkUsed | Customer paid via payment link |
Invoice Events
| Event | Description |
|---|---|
InvoiceCreated | Invoice created |
InvoiceSent | Invoice emailed to customer |
InvoicePaid | Invoice payment confirmed |
Webhook Payload Structure
Every webhook delivery is an HTTP POST with a JSON body:Payload Fields
The event type (see table above).
Payment data. Present for payment, payment link, installment, and subscription events.Key fields:
id, merchant_id, amount_usd, status, transaction_signature, customer_wallet, payment_token, mode, description, metadata, splits, created_at, expires_at.Settlement data. Present for
SettlementCompleted and SettlementFailed.Key fields: id, payment_id, merchant_id, amount_usd, settlement_token, settlement_amount, transaction_signature, merchant_wallet, status.Withdrawal data. Present for withdrawal events.Key fields:
id, merchant_id, to_address, from_address, amount, token, transaction_signature, status.ISO 8601 timestamp of when the event was generated.
Signature Verification
Every webhook includes ax-zendfi-signature header with the format:
- Create the signed payload:
{timestamp}.{json_body} - Compute HMAC-SHA256 using your webhook secret
- Compare the hex-encoded result to the
v1=value
Verification Examples
Using the SDK
The SDK provides built-in verification:- Express
- Next.js
Delivery and Retries
ZendFi uses exponential backoff for failed webhook deliveries:| Attempt | Delay | Total Elapsed |
|---|---|---|
| 1 | Immediate | 0s |
| 2 | 30 seconds | 30s |
| 3 | 2 minutes | ~2.5 min |
| 4 | 10 minutes | ~12.5 min |
| 5 | 1 hour | ~1 hour |
exhausted and moved to the dead letter queue. You will receive an email alert if you have notifications enabled.
Webhook Statuses
| Status | Description |
|---|---|
pending | Queued for delivery |
delivered | Successfully delivered (received 2xx response) |
failed | Delivery attempt failed, will retry |
exhausted | All retry attempts failed |
List Webhook Events
Retry a Webhook
Webhook event ID.
Verify Webhook Configuration
The raw webhook payload body.
The signature string to verify (
t=...,v1=...).Response
Best Practices
Always verify signatures
Always verify signatures
Never trust webhook payloads without verifying the HMAC signature. This prevents spoofed events from triggering actions in your system.
Return 200 quickly
Return 200 quickly
Process webhook data asynchronously. Return a 200 response immediately and handle the business logic in a background job. ZendFi interprets slow responses as failures.
Handle duplicate deliveries
Handle duplicate deliveries
Webhooks may be delivered more than once. Use the
payment.id or event ID for idempotency checks before processing.Use raw body for verification
Use raw body for verification
Parse the JSON body only after verifying the signature against the raw string. Parsing and re-serializing can change whitespace and break the signature check.