Recover failed Paddle payments
Paddle handles billing, tax and the merchant-of-record relationship. Their failure notifications carry the next retry date, which makes them a good input for a recovery layer that schedules customer messages around Paddle's own retry attempts instead of on top of them.
The Paddle events recovery depends on
- transaction.payment_failed
- A Paddle transaction failed — open a recovery case.
- transaction.completed
- Payment collected. Close the case and attribute the recovery.
- subscription.canceled
- Paddle ended the subscription after its dunning window.
Verifying Paddle webhooks
- Scheme
- HMAC-SHA256 over `${timestamp}:${rawBody}`
- Signature location
- Paddle-Signature
The header carries a timestamp and one or more h1 digests. Recompute the digest with your notification secret and compare timing-safely.
import { createHmac, timingSafeEqual } from "crypto";
const header = req.headers["paddle-signature"] as string; // ts=...;h1=...
const parts = Object.fromEntries(header.split(";").map((p) => p.split("=")));
const digest = createHmac("sha256", process.env.PADDLE_NOTIFICATION_SECRET!)
.update(`${parts.ts}:${rawBody}`)
.digest("hex");
if (!timingSafeEqual(Buffer.from(digest), Buffer.from(parts.h1))) {
return new Response("Invalid signature", { status: 401 });
}
const event = JSON.parse(rawBody);
if (event.event_type === "transaction.payment_failed") {
await rrlabs.enqueueRecovery({ provider: "paddle", externalId: event.data.id });
}Decline playbook for Paddle
| Failure signal | Recovery action |
|---|---|
| Paddle schedules another retry | Do not add a competing retry. Send a reminder message timed just before Paddle's next attempt. |
| Card requires an update | Send the Paddle update-payment-method link across email and, if unopened, WhatsApp. |
| Final Paddle retry approaching | Escalate to the highest-response channel available before the subscription is cancelled. |
What happens after a payment fails
T+0s
Payment failed
Provider webhook received and verified
T+2s
AI analysis
Decline reason classified, amount at risk scored
T+5s
Dynamic email
Copy generated for that decline code and customer
Day 2
Smart retry
Retry scheduled only when the decline code is retryable
Day 2
WhatsApp push
Second channel used when the email went unanswered
On success
Recovered
Counted only when the provider confirms the charge
Timings describe the configured workflow, not a guaranteed outcome. Every step is skipped when the decline reason makes it counter-productive.
Frequently asked questions
- How does RRLabs intercept Paddle subscription payment failures?
- Paddle posts a signed notification to an RRLabs endpoint. After signature verification, the failure is recorded and a recovery case opens with Paddle's own next-retry date taken into account.
- Does RRLabs interfere with Paddle's dunning?
- No. Paddle keeps retrying on its schedule. RRLabs adds the customer communication layer around it.
Connect Paddle with read-only credentials
RRLabs reads failure events and orchestrates recovery. It never holds card data and never becomes the merchant of record.
Get early access