Webhooks Guide
Webhooks Guide
Webhooks deliver real-time notifications when events occur in your RefundKit account. Use them to update your systems when refunds are processed, returns are received, or approvals are decided.
Event Types
| Event | Trigger |
|-------|---------|
| refund.initiated | Refund created (may be pending approval) |
| refund.approved | Refund approved (manual or auto) |
| refund.processing | Refund sent to payment processor |
| refund.completed | Refund successfully processed |
| refund.failed | Refund failed at the processor |
| refund.cancelled | Refund cancelled before completion |
| return.created | Return/RMA request created |
| return.approved | Return approved |
| return.shipped | Customer shipped the return |
| return.received | Warehouse received the return |
| return.inspected | Return items inspected |
| return.completed | Return fully processed |
| approval.pending | Refund queued for human review |
| approval.decided | Approval decision made |
| dispute.risk_flagged | Transaction flagged by risk engine |
| store_credit.issued | Store credit issued to customer |
| store_credit.redeemed | Store credit redeemed |
Webhook Payload
Every webhook delivery includes:
{
"id": "evt_1234567890_abc",
"type": "refund.completed",
"created": "2026-02-23T12:00:00.000Z",
"timestamp": 1740312000,
"data": {
"refundId": "ref_abc123",
"amount": 2500,
"currency": "usd",
"status": "completed"
}
}
Signature Verification
Every webhook is signed with HMAC-SHA256. Verify the signature to ensure the payload is authentic.
The signature is sent in the X-RefundKit-Signature header.
import { verifySignature } from '@refundkit/sdk';
function handleWebhook(payload: string, signature: string) {
const isValid = verifySignature(payload, signature, process.env.WEBHOOK_SECRET!);
if (!isValid) {
throw new Error('Invalid webhook signature');
}
const event = JSON.parse(payload);
// Process the event...
}
Replay Protection
Webhook payloads include a Unix timestamp. Reject payloads older than 5 minutes to prevent replay attacks:
import { isTimestampValid } from '@refundkit/sdk';
const event = JSON.parse(payload);
if (!isTimestampValid(event.timestamp)) {
throw new Error('Webhook timestamp is stale — possible replay attack');
}
Retry Policy
Failed deliveries are retried with exponential backoff:
| Attempt | Delay | |---------|-------| | 1 | Immediate | | 2 | 5 seconds | | 3 | 30 seconds | | 4 | 5 minutes | | 5 | 30 minutes | | 6 | 2 hours |
After 5 failed retries, the endpoint is marked as failing and your team is notified.
Response handling:
2xx— Success, delivery confirmed4xx(except 429) — Permanent failure, no retry429— Rate limited, retry with longer backoff5xx— Temporary failure, retry- Timeout (10s) — Retry
Next Steps
- Error Handling — Handle webhook processing errors gracefully.
- Authentication — Secure your webhook endpoint.