Razorpay + Stripe Weekly Revenue vs. Forecast Reconciliation: Variance Alert to Slack via Pipedream

Every Monday, auto-compare last week's actual revenue across Razorpay and Stripe against your Google Sheets forecast — and ping Slack only when the gap is real.

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

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

Why this stack

Most early-stage teams running dual gateways — Razorpay for India, Stripe for international — reconcile manually. A founder or ops person exports CSVs, pastes them into a sheet, eyeballs the delta against a forecast they typed two months ago. That takes 45–90 minutes and happens inconsistently. By the time someone notices a 15% shortfall, it's Wednesday.

Pipedream is the right glue here over Make or Zapier because it lets you write real JavaScript between API calls. You need actual arithmetic: summing Razorpay settlements, converting INR to USD, comparing against a forecast cell. Drag-and-drop tools handle that badly. The Razorpay API and Stripe API both have clean REST endpoints for listing charges and payouts. Pipedream has native auth for both.

Google Sheets holds the forecast because that's where the forecast already lives for 90% of teams at this stage. You don't need a database. Reading a single cell range via the Sheets API is two lines in a Pipedream code step.

Pipedream's free tier caps at 10,000 invocations per month — this runs once a week, so you'll never hit it. The real risk is Razorpay's settlement timing: T+2 or T+3 business days means a Monday run will miss weekend collections that haven't settled. Either shift to Wednesday or use charge totals instead of settlement totals and document which you're comparing. Skip this whole playbook if your forecast is multi-product or multi-currency blended margin — that belongs in Metabase on top of a Supabase table, not a Sheets cell. This is for teams with one MRR target per week who want to know if they're tracking.

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. Google Sheets logo

    The universal data scratchpad.

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

  4. Pipedream logo

    Code-level workflows with hosted triggers.

    Drop into Node/Python mid-flow when no-code hits a wall.

  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

    Scaffold the Pipedream workflow with a weekly CRON trigger

    Create a new workflow in Pipedream. Set the trigger to Schedule → CRON, expression `0 9 * * 1` (9 AM UTC every Monday). Name it `revenue-forecast-reconciliation`. This runs before standup without anyone remembering to kick it off. Don't use an HTTP trigger — you want it running whether or not a human shows up.

  2. 2

    Pull last week's Razorpay charge totals via API

    Add a Code step (Node.js). Hit Razorpay's `/v1/payments` endpoint with `created[gte]` and `created[lte]` set to last Monday 00:00 UTC and last Sunday 23:59 UTC. Filter for `status: captured`. Sum the `amount` fields — Razorpay returns paise, so divide by 100 for INR. Store as `razorpayINR`. Pull your Razorpay Key ID and Secret from Pipedream's environment variables, never hardcoded. Watch pagination: Razorpay caps at 100 results per call, so loop with the `from` cursor until the response is exhausted.

  3. 3

    Pull last week's Stripe charge totals via API

    Add a second Code step. Hit Stripe's `/v1/charges` endpoint with `created[gte]` and `created[lte]` matching the same window, `paid: true`. Sum `amount_captured` — Stripe returns cents, convert to USD. Store as `stripeUSD`. Convert `razorpayINR` to USD using a hardcoded weekly exchange rate stored in a Google Sheets cell (you'll read it in the next step). Don't call a forex API here — it adds a failure point you don't need. Add `razorpayUSD + stripeUSD` and store as `totalActualUSD`.

  4. 4

    Read the weekly forecast and FX rate from Google Sheets

    Add a Google Sheets step using Pipedream's built-in action → Get Values in Range. Point it at `WeeklyForecast!B2` for the forecast number and `FXRates!B2` for the INR/USD rate you update each Monday (manually or via a separate lightweight step). These two cells are the only inputs your finance team needs to maintain. In a subsequent code step, validate neither is empty — if either is blank, post a warning to Slack and halt the workflow.

  5. 5

    Calculate variance and apply threshold logic

    In a Code step, compute `variancePct = ((totalActualUSD - forecastUSD) / forecastUSD) * 100`. Define bands explicitly: green if within ±5%, yellow if ±5–15%, red if beyond ±15%. Store the band as a string (`UNDER`, `ON_TRACK`, or `OVER`) alongside the raw delta. Write this as explicit code, not a conditional branch in the workflow UI — it's easier to audit and change.

  6. 6

    Build the Slack message payload with context

    In a Code step, construct the Slack Block Kit JSON. Include: the week date range, Razorpay total in both INR and USD, Stripe total in USD, combined actual, forecast, variance percent, and the right band emoji (🟢/🟡/🔴). Add a footer: "Razorpay data = captured charges, not settled. Stripe data = captured charges." That line stops someone escalating a false alarm because they don't understand settlement lag.

  7. 7

    Post to Slack only when variance exceeds threshold

    Add Pipedream's Slack → Send Message action. Put a Filter step before it: only proceed if `Math.abs(variancePct) > 5`. If you're on-track, don't post — noise kills alert channels. Post to `#revenue-ops` or equivalent. If the band is red (beyond ±15% variance), add a second Slack step that @mentions the founder or CFO directly using `<@UXXXXXXXX>` syntax in the message text.

  8. 8

    Write the reconciliation row to Google Sheets for audit trail

    Add a Google Sheets → Append Row step that runs regardless of whether the Slack alert fired. Write: run date, razorpayINR, razorpayUSD, stripeUSD, totalActualUSD, forecastUSD, variancePct, band. This gives you a running ledger you can chart in Looker Studio later. Keep this step after the Slack step — a Slack failure shouldn't block the audit write.

  9. 9

    Test with a manual trigger and validate edge cases

    Use Pipedream's Test button to run the workflow against the prior week. Cover three scenarios: (1) no Razorpay payments that week — empty array shouldn't crash, default to 0; (2) Stripe API rate limit — add a try/catch and retry once after 2 seconds; (3) Google Sheets cell is blank — halt and notify. Check that the Slack message renders correctly in Block Kit Builder before going live.

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