Daily Revenue Digest: Stripe + Razorpay → Google Sheets → Slack Alert

Stop manually reconciling Stripe and Razorpay every morning — automate the full digest into Google Sheets and Slack before standup.

The flow
Razorpay logo
Source
Razorpay
Stripe logo
Process
Stripe
n8n logo
Process
n8n
Google Sheets logo
Process
Google Sheets
Slack logo
Destination
Slack

The stack in the order it runs — data flows from the source through to where it lands.

Why this stack

The pain is specific: two payment processors, two dashboards, one person copy-pasting numbers into a spreadsheet every morning and hoping they remembered to subtract refunds and convert INR. That's 20-40 minutes of work that still produces errors. It compounds weekly.

n8n is the right orchestration layer here — not Zapier. It handles multi-step HTTP requests to both the Stripe and Razorpay REST APIs inside a single workflow, lets you write JavaScript transform nodes inline, and runs self-hosted so your payment data never touches a third-party iPaaS server. That last point matters when you're moving live revenue figures.

Google Sheets is the reconciliation ledger. Every run appends a new row — no database setup, permanent audit trail, finance can see it without touching n8n. Once you have 30 days of data, you can wire a Looker Studio chart on top of that sheet in under 10 minutes. Slack is the delivery layer because that's where your team already is.

Skip this if you're processing more than ~500 transactions/day — Stripe and Razorpay will paginate aggressively and your workflow runtime will push past 2-3 minutes. At that volume, use their webhook-based event streams into a Supabase table and run the aggregation query from there. Also skip this if your finance team needs GAAP-compliant reporting. This is an operational pulse check, not a revenue recognition tool.

The stack (5)

  1. Razorpay logo

    Payments + payouts built for India.

    Webhooks and the reports API make revenue an automatable signal, not a dashboard you check.

  2. Stripe logo

    Global payments with first-class APIs.

    Events + Sigma let you wire billing into any ops report or alert.

  3. n8n logo

    Self-hostable workflow automation.

    Own your data and run unlimited steps without per-task pricing.

  4. Google Sheets logo

    The universal data scratchpad.

    Still the fastest place to land tabular data everyone can read.

  5. Slack logo

    Team chat where most ops alerts and reports land.

    The default place a small team already lives — pipe reports here instead of email nobody opens.

How it runs

  1. 1

    Create the n8n workflow with a Schedule Trigger

    Create a new workflow in n8n and add a Schedule Trigger node. Set it to run daily at 8:00 AM in your local timezone using cron expression '0 8 * * *'. This is your single clock — everything downstream is deterministic from this trigger. Don't add any other entry points to this workflow.

  2. 2

    Fetch yesterday's Stripe revenue via HTTP Request node

    Add an HTTP Request node pointed at 'https://api.stripe.com/v1/charges'. Set authentication to Header Auth with key 'Authorization' and value 'Bearer sk_live_XXXX'. Add query params: 'created[gte]' = yesterday 00:00:00 UTC as a Unix timestamp using n8n's expression $now.minus({days:1}).startOf('day').toUnixInteger(), 'created[lt]' = today 00:00:00 UTC, 'limit' = 100. Add a second HTTP Request node for 'https://api.stripe.com/v1/refunds' with the same date params to capture refunds separately. Watch for 'has_more: true' in the response — if you're paginating, add a Loop node. Most teams under 500 txn/day won't hit this.

  3. 3

    Fetch yesterday's Razorpay revenue via HTTP Request node

    Add another HTTP Request node. URL: 'https://api.razorpay.com/v1/payments'. Auth: Basic Auth with your Razorpay Key ID as username and Key Secret as password. Query params: 'from' = yesterday 00:00:00 IST as Unix timestamp, 'to' = today 00:00:00 IST, 'count' = 100. Razorpay returns amounts in paise — 1 INR = 100 paise — so you'll divide by 100 in the next step. Filter only payments where 'status' = 'captured'. Anything else is not settled revenue.

  4. 4

    Aggregate and reconcile in a Code node

    Add a Code node in JavaScript. Sum Stripe's 'amount' field (in cents, divide by 100) minus refunds. Sum Razorpay's captured amounts (divide by 100 for INR, then convert to USD using a hardcoded or fetched exchange rate). Output a single object with these exact fields: { date, stripe_usd, razorpay_inr, razorpay_usd_equiv, total_usd, stripe_refunds_usd, net_usd, stripe_txn_count, razorpay_txn_count }. Log any Stripe charges where status != 'succeeded' to a separate 'flagged' array — those are your reconciliation exceptions and you need to see them every day.

  5. 5

    Append row to Google Sheets

    Add a Google Sheets node with action 'Append Row'. Map your sheet ID and tab name — e.g. 'Daily Revenue'. Map each field from the Code node output to the corresponding column in this order: Date, Stripe USD, Razorpay INR, Razorpay USD Equiv, Total USD, Stripe Refunds, Net USD, Stripe Txn Count, Razorpay Txn Count, Flagged Count. Never overwrite. Always append. This row is your audit trail and the dataset that powers any chart you build later.

  6. 6

    Format and post the digest to Slack

    Add a Slack node with action 'Send Message'. Target your #revenue or #standup channel. Use Block Kit formatting: a header block with the date, a section block with a two-column layout showing Stripe and Razorpay side by side, and a context block with refund totals and flagged transaction count. If flagged count > 0, append a '⚠️ N transactions need review' line to the message. Use a Slack Bot Token stored in n8n credentials — not a webhook URL. You'll want to thread replies to this message later, and webhook URLs don't support threading.

  7. 7

    Add a threshold alert branch

    Before the Slack node, add an IF node. Condition: net_usd < your expected daily floor — e.g. $300. If true, route to a separate Slack node that posts to #alerts with an @channel mention and a message like '🚨 Revenue below threshold: $X vs expected $300+'. This fires independently of the digest — the digest always goes out, the alert escalates separately. Set your threshold to roughly 60% of your 30-day daily average so you're not paging the team on a slow Sunday.

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 services

More like this