A Razorpay payment link gets paid at 11:42 pm. By 11:42:08, the buyer has a GST-compliant invoice PDF in their inbox — correct GSTIN, the right HSN code, a sequential invoice number that survives a tax audit. No human touched it. We built this for a Jaipur handicrafts exporter (12 staff, ₹6.4 Cr turnover) who was hand-typing 40 invoices a day into Word. This post is the full n8n build — 16 nodes, the webhook setup, the Rule 46 fields most templates get wrong, and the sequential-numbering trick that keeps the GST officer happy.
The Answer in 60 Words
Set a Razorpay webhook for the payment_link.paid event. n8n catches it, pulls the customer GSTIN and line items, increments a sequential invoice number stored in a Postgres counter, renders a Rule 46-compliant PDF with HSN codes and a tax split, emails it to the buyer, and writes a row to your books. Total build time on a Saturday: about five hours. Run cost: one small self-hosted server.
Why this matters now (May 2026)
GST 2.0 went live on April 1, 2026, dropping the e-invoicing threshold to ₹5 crore. A trader who clocked ₹5.2 Cr in FY 2025-26 is now in scope. Manual invoicing was already painful — now a missing HSN code or a non-sequential number can get an invoice rejected at the Invoice Registration Portal. We covered the rollout in detail in our GST 2.0 six-software-changes checklist. This build automates the part that breaks first: getting a valid invoice out the door the second money lands.
What you'll need (prerequisites checklist)
- n8n v1.62 or later — self-hosted on a Hetzner CX22 or n8n Cloud
- A Razorpay account with API keys (test mode keys for the build, live keys for go-live)
- A Postgres database for the sequential invoice counter (the same Hetzner box works)
- Your firm's GSTIN, registered address, and HSN/SAC codes for what you sell
- An SMTP account or a transactional email service (we used Amazon SES)
- A 4-digit HSN for turnover under ₹5 Cr, or 6-digit for ₹5 Cr and above (Rule 46 requirement)
The Rule 46 fields most templates get wrong
Rule 46 of the CGST Rules, 2017 lists what a tax invoice must contain. Miss one and the invoice is technically invalid. Per the Razorpay GST invoice guide, the fields that trip up DIY templates are the HSN/SAC code, the place of supply, and the supplier-vs-recipient GSTIN pair that decides whether you charge IGST or CGST+SGST.
| Field | What breaks if you skip it | Where it comes from |
|---|---|---|
| Sequential invoice number (max 16 chars, per FY) | Audit flag; duplicate numbers void the invoice | Your Postgres counter |
| Supplier GSTIN + address | Invalid invoice | Hardcoded n8n env variable |
| Recipient GSTIN | No input tax credit for a B2B buyer | Razorpay notes or a lookup |
| HSN/SAC code | Rejected at IRP; penalty exposure | Mapped per product |
| Place of supply (state code) | Wrong tax split (IGST vs CGST+SGST) | Recipient state |
| Taxable value + tax rate + tax amount | Reconciliation mismatch in GSTR-1 | Computed in a Function node |
The 16-node flow (architecture)
Step-by-step build
The signature-verification node (copy this)
This is the Function node from step 2. It is the difference between a secure webhook and one anyone on the internet can forge.
const crypto = require('crypto');
const secret = $env.RAZORPAY_WEBHOOK_SECRET;
const signature = $request.headers['x-razorpay-signature'];
const rawBody = JSON.stringify($json.body); // use the raw body in n8n's binary/raw mode
const expected = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
if (expected !== signature) {
throw new Error('Invalid Razorpay signature — rejecting webhook');
}
// Only the paid event should reach the invoice path
if ($json.body.event !== 'payment_link.paid') {
return [];
}
const link = $json.body.payload.payment_link.entity;
return [{
json: {
amount: link.amount / 100, // Razorpay sends paise
currency: link.currency,
customerEmail: link.customer.email,
customerGstin: link.notes?.gstin || null,
stateCode: link.notes?.state_code || null,
hsn: link.notes?.hsn || null,
productName: link.description,
},
}]; Notice three things. The amount arrives in paise, so divide by 100. The GSTIN, HSN, and state code ride in Razorpay notes — you set these when you create the payment link, which keeps the build no-code on the data-entry side. And a non-paid event returns an empty array, so the flow short-circuits cleanly.
The atomic invoice-number query
The sequential-number requirement is where DIY invoicing quietly breaks. If two payments land in the same second and you read-then-write the counter in two steps, you get duplicate numbers. A duplicate invoice number voids both invoices in an audit. The fix is one atomic statement in the Postgres node:
UPDATE invoice_counter
SET last_number = last_number + 1
WHERE fy = '2026-27'
RETURNING last_number; Postgres runs this as a single locked operation, so concurrent payments queue and each gets a unique value. We format it in the next node as SI/2026-27/00042. The financial-year segment means the series naturally resets every April — which Rule 46 requires.
When NOT to build this yourself
Three situations where this flow is the wrong call. First, if your turnover is over ₹5 Cr and you need a real IRN, let Tally Prime or Zoho Books own the e-invoicing — they already handle the IRP handshake and the digitally signed QR code. Use n8n only for the customer-facing copy or skip it entirely. Second, if you issue fewer than five invoices a week, the five-hour build won't pay back; a paid template in Razorpay's own dashboard is faster. Third, if your line items are complex (multiple HSN codes per invoice, partial advances, credit notes), the simple single-product version here will fight you — that's a custom build, not a weekend flow.
Real example: the Jaipur exporter
The client, a handicrafts exporter in Jaipur with 12 staff, was sending 40 payment links a day through Razorpay and then hand-typing each invoice into a Word template. Two people spent roughly three hours a day on it, and roughly one in twenty invoices went out with a wrong HSN or a skipped number — which their CA caught at month-end and sent back. We shipped this flow in a single Saturday. The same pattern powers the reconciliation side of our Razorpay-to-Zoho Books auto-reconcile flow, and it sits next to the Claude Vision invoice-extraction build on the inbound side. We've shipped variations of it through our AI and automation team for four other Indian SMBs since. Built by Hrishikesh, our CTO, who also wrote our 22-minute daily Razorpay-Tally close.
We saw the same payback shape wiring the billing automation for Radiant Finance, where moving manual document generation into a webhook flow removed the month-end rework entirely. Outcome after one month: zero rejected invoices, six person-hours a day handed back to the team, and a clean GSTR-1 that reconciled on the first pass. We crosschecked the webhook approach against the r/n8n community, where the atomic-counter pattern is the consensus fix for the duplicate-number problem.
Cost comparison: build vs SaaS
The honest read: n8n self-hosted and Zoho Books cost almost the same per month. The reason to build is control — custom invoice layouts, your own numbering scheme, and the same n8n instance running ten other flows. If invoicing is all you need, Zoho Books is less work. We say so to clients before they pay us.
FAQ
Does this flow create a legal e-invoice with an IRN?
No. It creates a Rule 46-compliant tax invoice PDF and your internal record. An e-invoice with an IRN requires uploading to the Invoice Registration Portal. If your turnover is ₹5 Cr or more, add an IRP node after the PDF step, or let Tally/Zoho own the IRN.
How do I stop duplicate invoice numbers under load?
Use a single atomic SQL statement — UPDATE...RETURNING on a counter row — instead of reading then writing in two steps. Postgres locks the row, so concurrent payments each get a unique number. This is the consensus fix in the n8n community.
Where do the GSTIN and HSN come from if it's a payment link?
You set them in Razorpay notes when creating the link. The webhook delivers them back to n8n. For repeat B2B buyers, you can instead look up the GSTIN from a Postgres customer table keyed on email.
What does it cost to run per month?
It runs on a self-hosted Hetzner CX22, plus a small per-email charge through Amazon SES that stays low even at 40 invoices a day. The build itself was a one-time five-hour effort.
Can I send the invoice over WhatsApp instead of email?
Yes. Swap the SMTP node for a WhatsApp Business API node and attach the PDF as a document message. We do this for buyers who never open email — the WhatsApp open rate in our projects runs far higher than email for invoice delivery.
How do I handle a refund or a credit note?
Subscribe to payment_link.refunded as well and branch the flow. A refund triggers a credit-note PDF with its own sequential series (Rule 46 treats credit notes as a separate document type). Keep the credit-note counter separate from the invoice counter.
Will this reconcile cleanly with GSTR-1?
Yes, because every invoice writes a row with the taxable value, tax rate, and tax amount to a Postgres table. At month-end you export that table and tie it to GSTR-1. We pair this with our GSTR-3B reconciliation sprint for the filing side.
Want this invoicing flow built and self-hosted on your infra?
We ship a working v1 in 7 working days — Razorpay or Cashfree webhook, Rule 46-compliant PDFs, sequential numbering, and IRP wiring if your turnover needs it. Suitable if you're issuing 20+ invoices a day by hand. No slides — just your problem and our honest take.
Book a 20-min Call