Stripe + Razorpay Weekly Fee Anomaly & Net Revenue Report to Slack via n8n
Stop doing gateway math in a spreadsheet — automate the weekly reconciliation across Stripe and Razorpay, and get a Slack alert the moment your blended fee rate goes sideways.
The stack in the order it runs — data flows from the source through to where it lands.
Most founders running Razorpay for India and Stripe for the rest of the world have never seen a single number that answers: what did we actually net this week? They're downloading CSVs, pasting into Sheets, and doing math that's wrong half the time — because Razorpay's 2% + GST compounds differently than Stripe's 2.9% + 30¢. That gap costs real money. A 0.3% fee creep on $50K/month is $150 gone silently, every month, with no one noticing.
n8n hits both the Stripe `/v1/balance_transactions` and Razorpay `/v1/settlements` REST endpoints inside one workflow, runs the math in a Code node, and posts to Slack — no middleware, no extra SaaS seat. Airtable holds the weekly snapshots so you can trend over time without standing up a database.
The Slack alert is threshold-based, not just a digest. If the blended fee rate clears your configured ceiling — say 3.2% — you get a red-flag message with the breakdown by gateway. Normal weeks get a green summary. That distinction matters. If every message looks the same, your team stops reading them.
Skip this if you're processing under $5K/month combined — the fee variance is noise at that scale, just check your Stripe dashboard monthly. Also skip n8n self-hosted if you don't have a persistent server; use n8n Cloud or swap the orchestration to Pipedream.
The stack (5)
How it runs
- 1
Create the Airtable base for weekly snapshots
Create a base called 'Gateway Reconciliation' with a table named 'Weekly Snapshots'. Fields: Week (Date), Stripe Gross (Currency), Stripe Fees (Currency), Stripe Net (Currency), Razorpay Gross (Currency), Razorpay Fees (Currency), Razorpay Net (Currency), Blended Fee Rate (Number, percentage), Flag (Single Select: Normal / Alert). This is your audit trail. Do not skip it.
- 2
Pull Stripe balance transactions for the past 7 days
In n8n, add an HTTP Request node. Method: GET. URL: `https://api.stripe.com/v1/balance_transactions?type=charge&created[gte]={{$now.minus(7,'days').toUnixInteger()}}&limit=100`. Auth: Header Auth, key `Authorization`, value `Bearer sk_live_YOURKEY`. If volume is high, page through using the `has_more` flag — add a loop with the `starting_after` cursor parameter. Sum `amount` across all returned objects for gross, and `fee` for fees.
- 3
Pull Razorpay settlements for the past 7 days
Add a second HTTP Request node. Method: GET. URL: `https://api.razorpay.com/v1/settlements?from={{$now.minus(7,'days').toUnixInteger()}}&to={{$now.toUnixInteger()}}`. Auth: Basic Auth — Razorpay Key ID as username, Key Secret as password. From each settlement object, extract `amount` (gross in paise — divide by 100 for INR) and derive fees from `amount - settled_amount`. Convert INR to your reporting currency using a hardcoded rate or a live FX API call.
- 4
Calculate blended fee rate and evaluate threshold
Add a Code node (JavaScript). Compute: `totalGross = stripeGross + razorpayGross`, `totalFees = stripeFees + razorpayFees`, `blendedRate = totalFees / totalGross`. Define your alert threshold as a constant at the top of the script — start at 0.032 (3.2%). Set `flag = blendedRate > threshold ? 'Alert' : 'Normal'`. Return all six monetary values plus blendedRate and flag as a single object for downstream nodes.
- 5
Write the snapshot row to Airtable
Add an Airtable node, operation 'Create Record'. Map every field from the Code node output to its corresponding Airtable column. Set Week to `{{$now.startOf('week').toISO()}}`. This write happens before the Slack message — intentionally. If Slack delivery fails, the record still exists. Order matters here.
- 6
Branch on flag value
Add an IF node. Condition: `{{$json.flag}} === 'Alert'`. True branch routes to the red Slack message node. False branch routes to the green summary node. This is what prevents alert fatigue — your team only gets paged when something is actually off.
- 7
Send Slack alert or digest
Alert branch: Slack node, channel `#ops-alerts`, message: `🔴 *Fee Anomaly Detected — Week of {{$json.week}}* Stripe: ${{$json.stripeGross}} gross / ${{$json.stripeFees}} fees Razorpay: ₹{{$json.razorpayGross}} gross / ₹{{$json.razorpayFees}} fees Blended fee rate: {{($json.blendedRate * 100).toFixed(2)}}% — above your {{threshold*100}}% ceiling.` Normal branch: same channel, swap 🔴 for 🟢 and drop the ceiling warning.
- 8
Schedule the workflow to run every Monday at 08:00
Add a Schedule Trigger node as the workflow entry point. Set interval to 'Week', day to Monday, time to 08:00 in your local timezone. On n8n Cloud, also enable 'Error Workflow' and point it to a fallback workflow that posts a plain-text failure notice to the same Slack channel. Silent failures in financial reconciliation are worse than noisy ones.
Want me to build this for you instead?
Product Audit and CTO Mode run out of this same thinking. If you’re reading this thinking “I want this, but in my product” — let’s talk.
See servicesMore like this
Gmail Thread Aging + Stripe Invoice Overdue: Unified AR Follow-Up Digest to Slack via Zapier
Surface overdue Stripe invoices and the exact age of your last Gmail thread with that customer — every morning at 8:30, automatically — so AR follow-up stops living in someone's head.
Intercom Ticket Volume + Razorpay Failed Payments: Daily Support-Cost-per-Revenue Alert to Slack via Zapier
Catch the support cost blowout from Razorpay failed payments before your agents are already buried.
Outlook Calendar Load + HubSpot Deal Velocity: Weekly Ops Digest to Microsoft Teams
Every Monday at 07:30, your revenue team gets one Teams card: last week's deal pipeline movement next to each rep's actual meeting load — so you stop guessing whether low close rates are a pipeline problem or a capacity problem.