MRR Reconciliation Report: Stripe → Airtable → Claude → Slack Narrative

Every 1st of the month, this workflow pulls your Stripe data, reconciles MRR, writes a plain-English narrative via Claude, and posts it to Slack — no analyst required.

The flow
Stripe logo
Source
Stripe
Airtable logo
Process
Airtable
Claude logo
Process
Claude
n8n logo
Process
n8n
Slack logo
Destination
Slack

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

Why this stack

Manual MRR reconciliation takes about 2 hours and produces a spreadsheet nobody opens. The wall of numbers isn't the problem — the missing narrative is. Which cohort churned? Which plan drove expansion? What was net new MRR after you account for upgrades, downgrades, and pauses? Most founders skip the whole thing or pay someone to write it. Claude writes a better first draft than most analysts, in seconds.

Stripe's Subscriptions and Customers API gives you everything for a complete MRR waterfall: new subscriptions (new MRR), cancellations (churned MRR), plan changes (expansion/contraction MRR), and reactivations. Airtable holds the monthly snapshot — historical record, and the source Claude pulls last month's numbers from for comparison. The Claude API call uses a structured, templated prompt built from the reconciliation data, not a freeform chat message. n8n orchestrates it; Slack delivers it.

This is a monthly workflow, not a daily one. The insight density is higher and the audience is broader — founders, investors, the whole team. That's exactly why the narrative layer matters. Claude converts a reconciliation table into three sentences a non-technical co-founder reads in 30 seconds.

Don't use this if you're on Paddle or running complex billing — usage-based, per-seat enterprise — because the Stripe subscription model won't capture your actual MRR accurately. Pull from your internal billing database instead. Also: if your revenue data sits under audit requirements, keep the raw numbers in Airtable and only run Claude on the narrative layer. Never use Claude for the arithmetic.

The stack (5)

  1. Stripe logo

    Global payments with first-class APIs.

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

  2. Airtable logo

    Relational database with a spreadsheet face. Operational memory for every workflow I run.

    The audit trail across views, automations, and webhooks is unmatched in no-code land.

  3. Claude logo

    Long-context reasoning model from Anthropic — my daily driver for nuanced writing and orchestration.

    Better tone-matching and longer working memory than GPT for the tasks I care about most: guest messages, drafts, code review.

  4. n8n logo

    Self-hostable workflow automation.

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

  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

    Schedule the workflow for the 1st of each month at 7 AM

    In n8n, create a workflow with Schedule Trigger cron '0 7 1 * *'. Calculate the reporting period as: month_start = first day of last month 00:00:00 UTC as Unix timestamp, month_end = last day of last month 23:59:59 UTC. Store both as workflow variables accessible by all downstream nodes. One calculation point — that's it. Date math bugs across 4+ API calls are a real problem; this prevents them.

  2. 2

    Pull new subscriptions from Stripe

    HTTP Request node to 'https://api.stripe.com/v1/subscriptions'. Params: 'created[gte]' = month_start, 'created[lte]' = month_end, 'status' = 'active', 'limit' = 100. For each subscription, extract: customer ID, plan ID, plan amount, plan interval (if annual, divide by 12 for MRR contribution), created timestamp. This is your New MRR input. Handle pagination with a Loop node — don't skip this if you have more than 100 active subscriptions.

  3. 3

    Pull canceled and updated subscriptions from Stripe

    Two HTTP Request nodes. First: 'https://api.stripe.com/v1/subscriptions' with 'canceled_at[gte]' = month_start and 'status' = 'canceled' — churned MRR. Second: 'https://api.stripe.com/v1/events' with 'type' = 'customer.subscription.updated' and 'created[gte]' = month_start — plan upgrades and downgrades. For the events endpoint, diff 'previous_attributes.plan.amount' vs 'data.object.plan.amount' per customer to compute expansion or contraction MRR.

  4. 4

    Compute MRR waterfall in a Code node

    Code node: pull the previous month's total MRR from Airtable (queried at workflow start via 'Get Records' filtered to last month's row), then: add new MRR, subtract churned MRR, add expansion MRR, subtract contraction MRR. Output this object: { month, starting_mrr, new_mrr, churned_mrr, expansion_mrr, contraction_mrr, ending_mrr, net_new_mrr, churn_rate_pct, growth_rate_pct, new_customer_count, churned_customer_count }. All amounts in USD cents converted to dollars. churn_rate_pct = churned_mrr / starting_mrr * 100.

  5. 5

    Store monthly snapshot in Airtable

    Airtable 'Create Record' node targeting your 'MRR History' table. Map all waterfall fields. Set a 'Report Status' field to 'Pending Review' — you change it to 'Reviewed' manually after verifying the numbers. This record becomes the starting MRR for next month's run. Never delete rows from this table. It's your financial audit trail.

  6. 6

    Generate narrative with Claude API

    HTTP Request node to 'https://api.anthropic.com/v1/messages'. Auth: x-api-key header with your Claude API key. Model: 'claude-opus-4-5'. Build the prompt in a Set node before this step: 'You are writing a monthly MRR recap for a SaaS founder to share with their team. Be direct, specific, and use the exact numbers provided. Do not add caveats or filler sentences. Data: [inject waterfall object as JSON]. Write 3-4 sentences covering: what happened to MRR overall, the biggest driver (new/churn/expansion), churn rate vs last month, and one sentence on what to watch next month based on these trends.' Max tokens: 300.

  7. 7

    Format and post to Slack with narrative + numbers

    Slack 'Send Message' node to #founders or #monthly-metrics. Block Kit structure: header block 'MRR Recap — [Month Year]', a section block with the Claude narrative, a divider, then a fields block with waterfall numbers in two columns — Starting MRR / Ending MRR in row one, New / Churned in row two, Expansion / Contraction in row three, Net New / Growth % in row four. After posting, add a Slack 'Pin Message' node using the message timestamp returned from the post step. Pin it.

  8. 8

    Send a reconciliation exception alert if numbers look wrong

    Add an IF node before the Slack post. Conditions: if ending_mrr < 0, OR churn_rate_pct > 20, OR new_customer_count == 0 AND starting_mrr > 1000 — route to an alert Slack message tagging the founder: '⚠️ MRR reconciliation anomaly detected — please verify Stripe data before sharing this report.' These edge cases almost always mean a subscription plan is misconfigured or the date range caught a billing cycle edge. Post a wrong number to the whole team once and you'll wish you'd built this check.

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