A failed payment is not a lost customer — yet. Razorpay's own data shows automated retry systems recover 15-20% of failed transactions. We've shipped this n8n workflow for 4 D2C clients in the last 90 days, and the median recovery is ~12% of all drops within 24 hours. This post is the actual workflow — the trigger, the classifier, the message rules, the Sheets log — with the real Razorpay webhook payload and the n8n node config.
What this workflow does
In one sentence: it catches every Razorpay payment.failed webhook, classifies the failure into one of four buckets, fires the right recovery message via WhatsApp or email, and logs the outcome to Google Sheets so you can attribute revenue back to the workflow.
The four buckets matter because the message you send a customer whose card was declined is different from the one you send a customer whose UPI mandate timed out. Generic "your payment failed, try again" emails recover ~3%. Bucket-specific messages recover ~12%.
The Razorpay webhook payload (real)
This is what arrives at your n8n webhook URL when payment.failed fires. Trimmed for readability — the real payload includes a few more nested fields.
{
"entity": "event",
"account_id": "acc_DEMO12345abcd",
"event": "payment.failed",
"contains": ["payment"],
"payload": {
"payment": {
"entity": {
"id": "pay_OkqL3xR8nFvY7T",
"entity": "payment",
"amount": 89900,
"currency": "INR",
"status": "failed",
"order_id": "order_NjK4xR8nFvY7T",
"method": "upi",
"amount_refunded": 0,
"captured": false,
"description": "Order #INV-2026-04-1138",
"email": "rohit@example.com",
"contact": "+919876543210",
"notes": {
"cart_id": "cart_88291",
"customer_segment": "returning"
},
"fee": null,
"tax": null,
"error_code": "BAD_REQUEST_ERROR",
"error_description": "Payment failed due to UPI mandate timeout. Please try again.",
"error_source": "customer",
"error_step": "payment_authentication",
"error_reason": "payment_timed_out",
"vpa": "rohit@okhdfcbank",
"created_at": 1715162842
}
}
},
"created_at": 1715162844
} The two fields you'll use heavily: error_reason and method. They drive the bucket classification.
The n8n workflow — node by node
Total nodes: 7. Setup time on a fresh n8n install: ~45 minutes. Self-hosted on a Hetzner CX22 with managed Postgres (as of May 2026).
The attribution loop (often skipped)
Without attribution, you can't tell whether the workflow is helping. We add a daily 9am Cron in n8n that:
After 30 days you have real numbers, not vibes. For our 4 clients, the steady state is 11-14% recovery on bucket B1+B2+B3 combined (B4 is excluded since we don't message).
When NOT to use this workflow
Three cases where automated recovery hurts more than it helps:
Real example — a Bangalore D2C personal-care brand, ₹1.4 Cr GMV/month
Client: a 5-person D2C team running on Shopify with Razorpay. Monthly drops: ~3,400 failed payments worth ~₹21 lakh GMV.
Before: their existing recovery was a 24-hour-delay generic email. Recovery rate: ~3.1%, ~₹65k recovered/month.
- After we shipped the n8n workflow (3 working days, fixed fee + the self-hosted infra):
- B1 (insufficient funds): 22% recovery, ~₹1.6 lakh/month recovered.
- B2 (card decline): 14% recovery, ~₹85k/month.
- B3 (UPI timeout): 28% recovery, ~₹1.1 lakh/month.
- B4 (fraud): zero, by design.
Weighted recovery: 11.7% of drops. Recovered GMV: ~₹2.45 lakh/month. Net of WhatsApp template and email costs, the workflow keeps almost all of that. Payback on the build: 6 days.
The Reddit thread on r/IndiaBusiness where Indian merchants compare their recovery setups is worth scanning — most are still on generic-email recovery and leaving money on the table.
A note on a client platform as an internal case study
We use a similar n8n workflow on a client platform. A client platform's parents who try to upgrade to a paid plan and hit a UPI mandate timeout get a re-collect link via WhatsApp within 30 seconds. Our internal recovery rate on UPI timeouts ran ~31% in March 2026 — slightly higher than client averages, likely because the buying intent is stronger (mid-funnel parent, not impulse purchase).
Variations worth shipping
Once the base workflow is live, three extensions usually pay for themselves:
Bucket-by-bucket recovery rates we have measured
| Bucket | Trigger condition | Median recovery rate (4 clients, Q1 2026) | Best message channel |
|---|---|---|---|
| B1 — insufficient funds | error_reason in [insufficient_funds, low_balance] | ~22% within 24h | WhatsApp utility, 1h delay |
| B2 — card decline / 3DS | method=card AND error_reason in [payment_failed, 3ds_failed] | ~14% within 24h | WhatsApp utility + email, 2min delay |
| B3 — UPI mandate timeout | method=upi AND error_reason in [payment_timed_out, mandate_failed] | ~28% within 24h | WhatsApp utility, immediate |
| B4 — fraud / hard decline | error_source=issuer_bank AND error_step=fraud_check | 0% (silent log only) | None — do not message |
Pre-launch checklist for the workflow
- Razorpay webhook secret stored as env var, not hardcoded
- HMAC-SHA256 signature verification node tested with both valid and invalid payloads
- WhatsApp utility templates pre-approved by Meta for all 3 buckets
- Sheets log columns include payment_id, captured_at, bucket, recovery_status
- Daily cron set to flip recovery_status from "pending" to "recovered" / "lost"
- Postgres dedupe (or Sheets check) on payment_id before WhatsApp send
- n8n WEBHOOK_URL env var set to public URL, not localhost
- Slack channel / dashboard set up for weekly recovery summary
How to set up the Razorpay webhook on the dashboard
People ask this often. The Razorpay-side setup takes about 6 minutes:
Razorpay sends a test ping when you save. Your n8n workflow should fire and write a row to Google Sheets. If nothing happens, check the Razorpay dashboard webhook logs first — they'll show 4xx/5xx responses from your side.
Common operational mistakes
Three things that have burnt our clients' workflows in the first two weeks of running:
How this scales
At 50,000 events/month (typical for a ₹2 Cr GMV D2C), the workflow runs comfortably on the same Hetzner CX22 we mentioned. CPU stays below 30%; memory below 1.2GB. Postgres growth is ~80MB/month for the queue tables.
Above 200,000 events/month, you'll want to either upgrade the VM (CX32, doubles the resources) or move heavy classification logic to a dedicated worker (Bull queue, separate Node service). At our largest D2C client running this pattern, monthly events exceed 600,000 and the workflow runs on a dedicated CPX31.
The decision on when to upgrade is usually obvious from execution times in n8n's logs — if average execution time creeps above 2 seconds for a workflow that should run in 200ms, it's time.
FAQ
Where do I find the error_reason values?
Razorpay's error codes documentation lists every error_code, error_reason, and error_source combination. The list grows; check it quarterly. Most production failures fall into ~12 distinct error_reasons.
Why use WhatsApp utility template, not marketing?
Cost. Utility templates cost a fraction of marketing templates per message in India. A "your payment didn't go through, retry here" message qualifies as utility (it's transactional, follow-up to a customer-initiated action) under Meta's content policy. Get the template approved as utility, not marketing, for the lower rate.
Will Razorpay retry the webhook if my n8n is down?
Yes. Razorpay follows at-least-once delivery — it retries on any non-2xx response with exponential backoff for up to 24 hours. Make sure your webhook node responds with 200 quickly even if downstream nodes fail; otherwise you'll get duplicate sends.
Can I run this on n8n Cloud instead of self-hosted?
Yes. n8n Cloud's Pro plan handles ~10k executions/month — fine for most D2C SMBs. We default to self-hosted for clients above ~30k executions/month or who want their data inside their own VPC.
How do I prevent duplicate recovery messages?
Add a Postgres node before the WhatsApp send: SELECT 1 FROM payment_recovery_log WHERE payment_id = $1 AND created_at > now() - interval '7 days'. If the row exists, skip the send. Razorpay sometimes fires payment.failed twice for the same payment — this dedupes.
What about UPI mandate failures specifically?
UPI mandate failures (recurring UPI not approved by customer) are the highest-recovery bucket because the customer's intent is strong — they had set up the mandate and just missed the in-app prompt. Re-trigger via Razorpay's Create Order with method=upi, send the new link in WhatsApp, recovery rates cluster around 25-35%.
Can I use Pabbly Connect or Zapier instead of n8n?
Yes, with caveats. Pabbly is cheaper but lacks the Code node flexibility for HMAC verification and complex routing. Zapier is more polished but ~3-5x the cost at this volume. For Indian SMBs running 5k-50k executions/month, n8n self-hosted is the sweet spot.
Want This Payment-Recovery Flow for Your Business?
We ship this n8n + Razorpay workflow end-to-end in 5 working days — webhook setup, signature verification, bucket classification, WhatsApp BSP integration, Sheets attribution, and a 30-day post-launch review. Suitable for D2C, edtech, marketplaces with ₹50 lakh+ GMV/month.
Book a 20-min Workflow ReviewIf you want the exact n8n JSON export for the workflow, drop a mail to contact@softechinfra.com — we'll send it (with placeholder credentials) along with the WhatsApp template language we've had approved as utility.
