Stripe + Razorpay vs. Airtable Revenue Ledger: Nightly Reconciliation with Claude Narrative to Microsoft Teams via Pipedream
Every night, pull raw charge data from Stripe and Razorpay, diff it against your Airtable ledger, let Claude write a plain-English mismatch summary, and have it in Microsoft Teams before your finance lead pours their first coffee.
The stack in the order it runs — data flows from the source through to where it lands.
The pain is specific. You're running Stripe for international cards and Razorpay for Indian UPI and netbanking. By the time your bookkeeper opens a spreadsheet Monday morning, the week's mismatch is already a mess — retried charges creating duplicates, refunds hitting one gateway but never your ledger, settlement delays stacking on each other. Manual reconciliation at this scale is a 2-hour job. It gets skipped.
Pipedream is the right orchestrator because it handles authenticated API calls to both Stripe and Razorpay natively — no OAuth flows to write yourself. Its scheduled workflow plus code step combo lets you diff arrays in JavaScript without spinning up a server. Airtable is the ledger because most early-stage ops teams already track expected revenue there. It's the source of truth they control, not a payment gateway they don't.
Claude does one specific job: take a JSON diff of mismatches and write 3–5 sentences a non-technical finance lead can act on. 'Stripe shows 3 charges totaling ₹12,400 with no matching Airtable record — likely a webhook lag from yesterday 11 PM IST' is more useful than a raw JSON dump in Teams. That's the entire scope. Don't overcomplicate it.
Skip this stack if your transaction volume exceeds ~5,000 charges per night — Pipedream's free-tier execution limits will bite you. Move to n8n self-hosted or a dedicated reconciliation service like Reconcile.ly. Also skip this if you already pipe both gateways into a data warehouse. Use dbt there instead.
The stack (5)
Chat + channels for Microsoft-365 shops.
If the company is on Outlook/365, Teams is where reports get read — push there, not a separate tool.
How it runs
- 1
Create the Airtable revenue ledger base
In Airtable, create a base called 'Revenue Ledger' with a table named 'Transactions'. Required fields: `transaction_id` (text), `gateway` (single select: Stripe / Razorpay), `amount` (currency), `currency` (text), `status` (single select: captured / refunded / disputed), `created_at` (date+time), `reconciled` (checkbox). This is your canonical record — the thing you diff against. Every expected charge lands here, either manually or via your existing billing webhook. Get this right before touching anything else.
- 2
Set up a Pipedream scheduled workflow
In Pipedream, create a new workflow with a Schedule trigger. Set it to run daily at 01:00 UTC — or 06:30 IST if your team is India-based. Name it 'Nightly Revenue Reconciliation'. Under Settings, enable 'Retry on failure' with 2 retries and a 5-minute delay. Gateway APIs occasionally 503 at night during settlement runs. The retries save you from a false alarm in Teams.
- 3
Fetch last 24 hours of Stripe charges
Add a Node.js code step. Use the Stripe SDK: call `stripe.charges.list({ created: { gte: yesterdayUnix, lte: todayUnix }, limit: 100 })` with pagination via `auto_paging_each`. Store results as an array of objects: `{ id, amount, currency, status, created }`. Watch the `amount_captured` vs `amount` distinction — only count `status: 'succeeded'` charges. Store the array as `stripeCharges` in the step's output.
- 4
Fetch last 24 hours of Razorpay payments
Add a second Node.js step. Call `GET https://api.razorpay.com/v1/payments?from=UNIX_YESTERDAY&to=UNIX_TODAY&count=100` using Basic Auth — key_id and key_secret stored as Pipedream environment variables. If `count` returns 100 items, paginate with the `skip` param. Normalize each record to match the Stripe shape: `{ id: payment.id, amount: payment.amount / 100, currency: payment.currency, status: payment.status, created: payment.created_at }`. Store as `razorpayPayments`. The normalization step matters — mismatched shapes will break your diff downstream.
- 5
Pull today's Airtable ledger records
Add a Pipedream Airtable action — 'List Records'. Point it at your Revenue Ledger base and Transactions table. Add a filter formula: `AND(IS_AFTER({created_at}, YESTERDAY()), IS_BEFORE({created_at}, TODAY()))`. Map the returned records to a flat array of `transaction_id` values. This becomes your `ledgerIds` set. If Airtable returns more than 100 records, enable the 'Return all records' toggle in the action config — don't leave it off and wonder why your diff is wrong.
- 6
Diff gateway charges against the ledger
Add a Node.js code step. Merge `stripeCharges` and `razorpayPayments` into a single `allGatewayTxns` array, tagging each item with a `gateway` field. Filter for mismatches: `const mismatches = allGatewayTxns.filter(txn => !ledgerIds.includes(txn.id))`. Also run the inverse — ledger records with no gateway match, your potential ghost entries. Output both as `missingFromLedger` and `missingFromGateway`. If both arrays are empty, set a flag `allClear: true` to short-circuit the Claude call. No point paying for a Claude call when everything matched.
- 7
Generate Claude narrative for mismatches
Add an HTTP request step to `https://api.anthropic.com/v1/messages`. Set the model to `claude-3-5-haiku-20241022` — fast and cheap for structured summaries. Prompt: 'You are a finance ops assistant. Given this JSON of revenue mismatches between payment gateways and our Airtable ledger, write 3–5 plain-English bullet points a non-technical finance lead can act on. Flag amounts over $500 USD equivalent as HIGH PRIORITY. JSON: {{mismatches}}'. If `allClear` is true, skip this step entirely and use a hardcoded message: '✅ All gateway charges matched the ledger. No action needed.'
- 8
Post the digest to Microsoft Teams
Add an HTTP POST step targeting your Teams Incoming Webhook URL — create it under your Finance channel → Connectors → Incoming Webhook. Send an Adaptive Card payload with: a header 'Nightly Revenue Reconciliation — {{date}}', a summary line '{{stripeCharges.length}} Stripe + {{razorpayPayments.length}} Razorpay charges reviewed', the Claude narrative as body text, and a count badge 'Mismatches: {{mismatches.length}}' colored red if greater than 0, green if 0. Keep the card under 28KB. Teams silently drops anything over that limit — you'll never know it failed.
- 9
Create an Airtable record for each mismatch
Add a Pipedream loop step over `missingFromLedger`. For each item, call the Airtable 'Create Record' action in your Revenue Ledger table, setting `reconciled` to false and a new field `flag` to 'GATEWAY_ONLY'. Your finance lead opens Airtable the next morning and sees a pre-populated list of charges to investigate — they don't need to re-read the Teams message to know where to start. Set a view filter in Airtable for `flag = GATEWAY_ONLY AND reconciled = false` and drop that view link directly into the Teams card.
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
Google Analytics 4 + HubSpot Lifecycle Stage: Weekly Acquisition-Quality Digest to Slack via Pipedream with Claude Narrative
Stop reporting traffic numbers. Report whether the traffic you paid for last week actually became pipeline — with a one-paragraph executive summary written by Claude.
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.
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.