Skip to content

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

MethodPOST
Content-Typeapplication/json
Timeout10 seconds — respond within this window
Expected Response2xx status code
Max Payload Size~4 KB per event

Request Headers

HeaderDescription
X-PaymentRescue-SignatureHMAC-SHA256 signature of the payload for verification
X-PaymentRescue-EventThe event type (e.g., payment.failed)
X-PaymentRescue-DeliveryUnique 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

FieldTypeDescription
idstringUnique event identifier
typestringEvent type: payment.failed, payment.recovered, or payment_method.updated
created_atstring (ISO 8601)When the event was created
data.customer_emailstringCustomer's email address
data.customer_namestringCustomer's display name
data.amountnumberAmount in cents (e.g., 9900 = $99.00)
data.currencystringThree-letter ISO currency code
data.invoice_idstringStripe invoice ID
data.failure_reasonstringReason for failure: card_declined, insufficient_funds, expired_card, etc.
data.recovery_stepnumberCurrent 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:

AttemptDelayTotal Elapsed
1st retry1 minute1 minute
2nd retry5 minutes6 minutes
3rd retry30 minutes36 minutes
4th retry2 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.