Webhook Documentation
PaymentRescue sends webhook events to your endpoint when payment recovery events occur. Use these to trigger actions in your email platform, CRM, or custom system.
Overview
Webhooks allow your application to receive real-time HTTP POST notifications when recovery events happen. Each event includes a JSON payload with customer details and payment information.
Configure your webhook endpoint in the PaymentRescue dashboard under Settings → Webhooks. You can subscribe to specific event types or receive all events.
Endpoint Configuration
| Method | POST |
| Content-Type | application/json |
| Timeout | 10 seconds — respond within this window |
| Expected Response | 2xx status code |
| Max Payload Size | ~4 KB per event |
Request Headers
| Header | Description |
|---|---|
| X-PaymentRescue-Signature | HMAC-SHA256 signature of the payload for verification |
| X-PaymentRescue-Event | The event type (e.g., payment.failed) |
| X-PaymentRescue-Delivery | Unique delivery ID for deduplication |
Event Types
payment.failed
Fired immediately when a subscription payment fails. Includes customer details, failure reason, and the amount at risk.
{
"id": "evt_abc123def456",
"type": "payment.failed",
"created_at": "2026-04-14T10:30:00Z",
"data": {
"customer_email": "jane@example.com",
"customer_name": "Jane Smith",
"amount": 9900,
"currency": "usd",
"invoice_id": "in_1234567890",
"failure_reason": "card_declined",
"recovery_step": 0
}
}payment.recovered
Fired when a previously failed payment is successfully collected. This means the customer updated their payment method or a retry succeeded.
{
"id": "evt_xyz789ghi012",
"type": "payment.recovered",
"created_at": "2026-04-15T14:22:00Z",
"data": {
"customer_email": "jane@example.com",
"customer_name": "Jane Smith",
"amount": 9900,
"currency": "usd",
"invoice_id": "in_1234567890",
"failure_reason": "card_declined",
"recovery_step": 2
}
}payment_method.updated
Fired when a customer clicks the recovery link and successfully updates their payment method via the Stripe-hosted portal.
{
"id": "evt_mno345pqr678",
"type": "payment_method.updated",
"created_at": "2026-04-15T14:20:00Z",
"data": {
"customer_email": "jane@example.com",
"customer_name": "Jane Smith",
"amount": 9900,
"currency": "usd",
"invoice_id": "in_1234567890",
"failure_reason": "card_declined",
"recovery_step": 2
}
}Payload Schema
| Field | Type | Description |
|---|---|---|
| id | string | Unique event identifier |
| type | string | Event type: payment.failed, payment.recovered, or payment_method.updated |
| created_at | string (ISO 8601) | When the event was created |
| data.customer_email | string | Customer's email address |
| data.customer_name | string | Customer's display name |
| data.amount | number | Amount in cents (e.g., 9900 = $99.00) |
| data.currency | string | Three-letter ISO currency code |
| data.invoice_id | string | Stripe invoice ID |
| data.failure_reason | string | Reason for failure: card_declined, insufficient_funds, expired_card, etc. |
| data.recovery_step | number | Current dunning step (0 = just failed, 1-3 = email sequence step) |
Signature Verification
Every webhook request includes an X-PaymentRescue-Signature header. Verify this to ensure the request is authentically from PaymentRescue.
// Node.js verification example
import crypto from "crypto";
function verifyWebhookSignature(
payload: string,
signature: string,
secret: string
): boolean {
const expected = crypto
.createHmac("sha256", secret)
.update(payload)
.digest("hex");
return signature === `sha256=${expected}`;
}
// In your webhook handler:
app.post("/webhooks/paymentrescue", (req, res) => {
const signature = req.headers["x-paymentrescue-signature"];
const isValid = verifyWebhookSignature(
JSON.stringify(req.body),
signature,
process.env.PAYMENTRESCUE_WEBHOOK_SECRET
);
if (!isValid) {
return res.status(401).json({ error: "Invalid signature" });
}
// Process the event
const event = req.body;
switch (event.type) {
case "payment.failed":
// Add to email recovery campaign
break;
case "payment.recovered":
// Send celebration email, update CRM
break;
case "payment_method.updated":
// Log the update, notify team
break;
}
res.json({ received: true });
});Retry Policy
If your endpoint returns a non-2xx status code or times out, PaymentRescue will retry the delivery with exponential backoff:
| Attempt | Delay | Total Elapsed |
|---|---|---|
| 1st retry | 1 minute | 1 minute |
| 2nd retry | 5 minutes | 6 minutes |
| 3rd retry | 30 minutes | 36 minutes |
| 4th retry | 2 hours | ~2.5 hours |
| 5th retry (final) | 24 hours | ~26.5 hours |
After 5 failed delivery attempts, the webhook is marked as failed. You can view failed deliveries and manually retry them from the dashboard.
Best Practices
- Respond quickly: Return a 200 status within 10 seconds. Process events asynchronously if needed.
- Verify signatures: Always validate the X-PaymentRescue-Signature header before processing.
- Handle duplicates: Use the event ID for idempotency. The same event may be delivered more than once.
- Use HTTPS: Only HTTPS endpoints are supported. Your endpoint must have a valid SSL certificate.
Integration Examples
Use webhooks to connect PaymentRescue with your favorite tools:
Brevo / Mailchimp
On payment.failed, add customer to a recovery email campaign. On payment.recovered, remove from campaign.
Slack / Discord
Send real-time notifications to a channel when payments fail or recover. Include amount and customer details for context.
HubSpot / Salesforce CRM
Update customer records with payment status. Create tasks for account managers when high-value payments fail.
Custom Analytics
Track recovery metrics in your own data warehouse. Calculate real-time recovery rates and revenue saved.
Ready to integrate?
Set up webhooks in your PaymentRescue dashboard. Start receiving real-time recovery events in minutes.