Overview & Delivery
Webhook delivery model, registration, event envelope, and the 6-attempt retry schedule.
Webhooks deliver event notifications to your server via HTTP POST. Use them for server-side order fulfillment instead of polling for payment status.
Registering endpoints
Webhook endpoints are configured in the merchant dashboard — there is no public API for webhook CRUD. Go to Settings → Webhooks to add endpoints and subscribe to events.
Open dashboard webhooks
Go to Settings → Webhooks in the halfin dashboard.
Add your endpoint URL
Paste your HTTPS endpoint that will receive events.
Subscribe to events
Select the event types your integration needs. Use invoice.paid for payment confirmation; balance.credited when fulfillment depends on spendable balance.
Copy the webhook secret
Use it for signature verification.
Event envelope
Every webhook POST body follows this structure:
{
"event_id": "00000000-0000-0000-0000-000000000001",
"event": "invoice.paid",
"created_at": "2024-01-01T12:00:00Z",
"data": { ... }
}New canonical deliveries include a stable event_id UUID for merchant-side idempotency. It is optional in invoice, late-payment, payout, and refund schemas only because retries of legacy stored payloads may omit it. balance.credited always includes event_id.
Headers
Every webhook request includes:
X-Halfin-Signature: t=1735689900,v1=5d41402abc4b2a76b9719d...
X-Halfin-Event: invoice.paid
Content-Type: application/jsonAlways verify the X-Halfin-Signature header before processing the event. See Signature Verification.
Delivery semantics
- Method:
POSTwith a JSON body - At-least-once: the same event may be delivered more than once. De-duplicate by
event_idwhen present. For a legacy payload without it, fall back to the event type,created_at, and the event-specific resource ID indata. - Success: any
2xxresponse is treated as successful delivery - Timeout: your endpoint should respond within 15 seconds
Retry schedule
On non-2xx responses, halfin makes up to 6 total delivery attempts (the initial attempt plus 5 retries) with fixed backoff intervals:
| Attempt | Delay before retry |
|---|---|
| 1 (initial) | — |
| 2 | 30 seconds |
| 3 | 2 minutes |
| 4 | 10 minutes |
| 5 | 1 hour |
| 6 | 6 hours |
After the 6th failed attempt the delivery is marked failed. No further retries occur.
Webhook delivery is at-least-once. Prefer the stable event_id UUID as the idempotency key. Only legacy stored payloads may require the fallback key described above.
Event types
See Event Types for all 13 subscribable events with payload field descriptions.