Downloads
Download the n8n workflow (JSON)
razorpay-receipts-n8n.json · n8n workflow · 23 steps · starts with Razorpay payment webhook · uses Google Sheets, Anthropic, Slack, Google Drive, Google Docs, Gmail, WhatsApp · 42 KB
Import into n8n: Create Workflow, then the menu, then Import from File.
How to import it into n8n
- In n8n, create a new workflow.
- Open the ⋯ menu at the top right and choose Import from File, then pick the downloaded .json. (Or open the file, copy everything and paste it on the canvas.)
- Open each node with a warning and connect your own account: the file carries no passwords or keys.
- Run it once with Test workflow, check the result, then switch it to Active.
What it does
Every time a payment is captured on Razorpay, Razorpay calls your n8n webhook. n8n replies at once, checks the signature with your webhook secret, and drops anything that is fake, failed or already handled. The payment is cleaned up (paise to rupees, time to IST). Claude reads the messy description and notes, matches the payment to one product in your Products sheet, and picks out a company name and GSTIN if the buyer typed them. A Code node, not the AI, does the tax maths: taxable value, CGST plus SGST or IGST, and the next consecutive receipt number. If anything is unclear, you check it in Slack first. Then a copy of your Google Docs receipt template is filled in, logged in your Accounts sheet, exported as a PDF, emailed to the customer, and a WhatsApp thank-you goes out.
Who it is for
Coaches, course sellers, clinics, studios and D2C brands that take payments through Razorpay payment links or pages and still make receipts by hand.
What you need
- An n8n account (n8n Cloud or self-hosted, reachable from the internet)
- A Razorpay account with access to Settings > Webhooks
- A Google Docs receipt template with [[PLACEHOLDERS]], a Receipts folder in Drive and a Google Sheet
- An Anthropic API key for Claude
- Gmail to send receipts
- A WhatsApp Business Cloud number with an approved 'payment_receipt' template
- A Slack channel such as #payments
How the workflow runs, node by node
The slides show the same steps. Open the workflow in n8n and you will see a sticky note over each one.
Step 1 · Razorpay tells n8n the moment money lands
Razorpay calls your n8n webhook on every payment. n8n answers straight away, checks Razorpay's signature with your secret, keeps only captured payments, and drops any payment it has already handled.
- Razorpay payment webhook: Receives Razorpay's webhook for every payment. Raw body is kept so the signature can be checked.
- Reply 200 to Razorpay: Answers Razorpay straight away, so it does not retry while the receipt is being made.
- Verify signature: Recomputes Razorpay's HMAC SHA256 signature with your webhook secret and compares it, so nobody can fake a payment by calling your URL.
- Real and captured?: Keeps only payments with a valid signature and the event payment.captured. Failed or authorised-only payments stop here.
- Skip duplicates: Remembers every Razorpay payment id. If Razorpay sends the same webhook twice, only one receipt is made.
Step 2 · Clean the payment, load your products
Paise become rupees and the time becomes IST. Name, email, phone and notes are picked out. Your Products sheet, with HSN/SAC codes and GST rates, is loaded once and passed along as one list.
- Normalise payment: Turns paise into rupees and Unix time into IST, and keeps only payment id, amount, method, email, phone, description and notes.
- Load price list: Reads your Products tab: Code, Product, Price, HSN/SAC, GST rate. Runs once per payment.
- Price list as one item: Packs every product row into one list, so Claude sees the whole price list in a single call.
Step 3 · Claude matches it to the right product
Razorpay notes are messy, like 'Nov batch + GST bill pls'. Claude matches the payment to one product in your sheet, picks out a company name and GSTIN only if the buyer typed one, and writes a one-line thank-you.
- Match product with Claude: Matches messy Razorpay notes ('Nov batch + 2 extra') to one product in your sheet, picks out a company name and GSTIN only if the buyer typed one, and writes a one-line thank-you. It never does tax maths.
- Claude: Claude (claude-sonnet-5-5) at temperature 0.1, so answers stay consistent from run to run.
- Receipt schema: Forces fixed fields (product_code, customer_name, company_name, buyer_gstin, thank_you_line, confidence).
Step 4 · GST by formula, a check only when unsure
n8n, not Claude, does the tax maths from your rate: taxable value, CGST plus SGST or IGST, and the next receipt number. If the product didn't match, the GSTIN looks wrong or the amount isn't a list price, you check it in Slack first.
- Work out GST: Does the tax maths by formula from your GST rate: taxable value, CGST plus SGST (same state) or IGST (other state), and the next receipt number in your series. It lists any reason to double-check.
- Needs a check?: True when the product did not match, Claude was unsure, the GSTIN looks wrong or the amount is not a list price.
- Approve receipt details: Only for unclear payments: posts the amount, product, GSTIN and the reason to #payments and waits up to 24 hours.
- Approved?: True only when you tapped 'Looks right, send'.
- Flag for manual receipt: Leaves a note in #payments with the payment id and the reserved receipt number when you chose to do it by hand.
Step 5 · Receipt made, logged and sent
A copy of your Google Docs receipt template is filled in and saved to Drive. The row goes to your Accounts sheet first, then the PDF goes by email and the customer gets a WhatsApp thank-you. If a send fails, you get an alert.
- Copy receipt template: Copies your Google Docs receipt template into the Receipts folder, named with the receipt number and customer.
- Fill receipt: Replaces the [[PLACEHOLDERS]] in the copy with receipt number, date, buyer, GSTIN, item, HSN/SAC, taxable value, CGST, SGST, IGST, total and payment id.
- Log to accounts sheet: Writes the payment to your Accounts tab, keyed on Payment ID, with every tax column your CA needs. It runs before sending, so the books are right even if a send fails.
- Download as PDF: Exports the filled Google Doc as a PDF file.
- Email receipt: Emails the PDF receipt to the payer with your thank-you line. Its error output goes to the alert.
- WhatsApp thank-you: Sends your approved 'payment_receipt' WhatsApp template: name, amount, product and receipt number. A template is needed because the customer may not have messaged you in the last 24 hours.
- Alert owner: Tells you in Slack if the email or WhatsApp failed, so you can resend by hand. The accounts row is already saved.
Setup
- In n8n, create a new workflow, open the menu and choose Import from File, then pick the JSON file.
- Make a Google Doc receipt with your business name, GSTIN, address and the placeholders [[RECEIPT_NO]], [[DATE]], [[CUSTOMER]], [[BUYER_GSTIN]], [[ITEM]], [[HSN_SAC]], [[TAXABLE]], [[CGST]], [[SGST]], [[IGST]], [[TOTAL]], [[PAYMENT_ID]]. Put its id in Copy receipt template and your Receipts folder id next to it.
- Make a Google Sheet with a
Productstab (Code, Product, Price, HSN/SAC, GST rate) and anAccountstab (Payment ID, Receipt No, Date, Customer, Company, Buyer GSTIN, Product, HSN/SAC, Taxable, CGST, SGST, IGST, Total, Method, Receipt link). Paste its URL in both sheet nodes. - In Work out GST, set MY_STATE to the first two digits of your GSTIN, PREFIX to your receipt series and START_AT to your next receipt number.
- Activate the workflow and copy the production URL of Razorpay payment webhook. In Razorpay, go to Settings > Webhooks > Add new webhook, paste the URL, pick the event
payment.captured, and set a secret. Paste the same secret in Verify signature. - Self-hosted n8n only: allow the crypto module with the environment variable NODE_FUNCTION_ALLOW_BUILTIN=crypto.
- Create an Anthropic credential on Claude, connect Slack, Google Drive, Google Docs, Gmail and WhatsApp, and replace
YOUR_BUSINESS,YOUR_NAMEandYOUR_PHONE_NUMBER_ID. - Submit a
payment_receipttemplate in WhatsApp Manager with four variables (name, amount, product, receipt number) and wait for approval. - Make a payment in Razorpay test mode, then check the PDF, the email, the WhatsApp and the Accounts row.
How to customise it
- Use Razorpay's Invoices API instead of a Docs template if you already issue invoices inside Razorpay.
- Add a product field to your Razorpay payment page so the match is exact and Claude only writes the thank-you.
- Send a monthly export of the Accounts tab to your CA with a scheduled workflow.
- Add refunds: a second webhook on
refund.processedthat logs a credit note row. - Skip the email for walk-in customers without an email and send only WhatsApp.
Guardrails
Claude never calculates tax. Anything unclear waits for your tap in Slack before a receipt goes out.
- Claude never calculates tax or changes the amount. The maths is a formula in Work out GST.
- Every webhook is checked against Razorpay's signature, so nobody can fake a payment by calling your URL.
- Unclear payments (no product match, low confidence, odd GSTIN, amount not a list price) wait for your approval.
- The Accounts row is written before anything is sent, so your books are right even if a send fails.
- Receipt numbers are consecutive per financial year. Check the template fields and HSN/SAC codes with your CA before going live.
Troubleshooting
- Every payment stops at Real and captured? The signature does not match. Make sure the secret in Verify signature is exactly the one in Razorpay, and that the webhook has the raw body option on.
- Code node says 'crypto is not allowed'. On self-hosted n8n set NODE_FUNCTION_ALLOW_BUILTIN=crypto and restart.
- Receipt numbers restart or skip. Static data is only saved on production (active) runs, not manual tests. Test numbers do not count.
- Fill receipt does nothing. The placeholders in your Doc must match exactly, including the double square brackets.
- WhatsApp fails with a template error. The template name and language (payment_receipt, en) must match an approved template with four variables.
Want the members-only resources too?
A free account unlocks them all, including the ones shared in DMs.

