Closed-won vs. paid reconciliation: match Salesforce wins to Stripe invoices and flag the gaps
Stripe + Salesforce
Who it's for
RevOps teams who want every closed-won opportunity checked against what was actually invoiced and paid in Stripe, before commissions go out or the month is closed. Everything stays read-only. Salesforce can be swapped for HubSpot, Attio or Pipedrive.
What you get
Mismatches between closed-won and paid, grouped by owner. Sample output: every company and person in it is fictional.
Closed Won in September (Salesforce): 18 opportunities, $412,000. Matched to a Stripe customer: 17. Nothing has been changed in Salesforce or Stripe. Mismatches only: | Opportunity | Owner | Won amount | Stripe | Flag | |---|---|---|---|---| | Quarry Lane Analytics (fictional), new logo | Alex Rivera | $33,000 | No invoice for customer quarrylane.example up to Oct 30 | Missing | | Mossgate Labs (fictional), expansion | Priya Raman | $40,000 | INV-0440, $40,000, open since Sep 29 | Invoiced, not paid | | Larkspur Freightworks (fictional), renewal | Sam Whitlock | $46,000 | INV-0436, $41,400 paid (10% coupon on the invoice) | Different amount, -$4,600 | | Brightwater Dental Group (fictional), annual | Sam Whitlock | $18,000 | Quarterly subscription, $4,500 paid so far | Billing schedule, not an error | Match basis: 15 by Stripe customer ID field on the account, 2 by email domain, 1 not matched (Quarry Lane). Commission check: Larkspur's won amount in Salesforce is $46,000, but $41,400 was paid. Ask finance which number the plan uses before commissions are paid. Paid in Stripe with no closed-won opportunity: 1 invoice, $12,000, customer tidewell.example (Tidewell Robotics, fictional). All amounts are subtotals before tax, in USD.
Time and cost
Estimate About 20–30 minutes for a month of closed-won deals, most of it checking the mismatches.
Assumptions: One monthly run over about 20 closed-won opportunities and their Stripe customers.
- Stripe: Reads only: a few list or search calls for customers, invoices and subscriptions in the period. No writes. Credit use not confirmed by Stripe.
- Salesforce: Reads only: one schema lookup and one or two SOQL queries for closed-won opportunities, their accounts and owners. Each call counts against the org's daily API request quota. Every call uses credits. No paid credits; every tool call counts against the org's daily Salesforce API request quota (one or more API calls per tool). Source: github.com, checked 2026-10-16
Exact credit costs depend on your plan with each vendor. Check the tool pages before a large run.
MCP servers
Every server is confirmed in: ClaudeChatGPTCursor
-
ClaudeChatGPTClaude CodeCursorRead + writeCredits not confirmed
https://mcp.stripe.com -
ClaudeChatGPTCursorRead + writeEvery call uses creditsNeeds admin or IT
https://api.salesforce.com/platform/mcp/v1/platform/sobject-all
Set up in a chat app
Every server in this recipe is confirmed for Claude and ChatGPT. Connect each one, then paste the prompts below into one conversation.
- Connect Stripe without code (Claude, ChatGPT)
- Connect Salesforce without code (Claude, ChatGPT)
Developer setup
Auth setup and mcp.json for Claude Code and Cursor
- Stripe: Sign in with OAuth, or pass an API key as a Bearer token for headless use.
- Salesforce: Sign in with OAuth in your client (run
/mcpin Claude Code). Do it once interactively, and the client stores and refreshes the token.
Put this in .mcp.json (Claude Code, project root) or ~/.cursor/mcp.json (Cursor). Swap the example keys for your own, and don't commit real ones. Remove the // comment lines if your client requires strict JSON.
{
"mcpServers": {
"stripe": {
"url": "https://mcp.stripe.com"
// headless alternative: "headers": { "Authorization": "Bearer YOUR_STRIPE_API_KEY" }
},
"salesforce": {
"url": "https://api.salesforce.com/platform/mcp/v1/platform/sobject-all"
}
}
}
Step-by-step prompts
- Look at the Opportunity and Account schema in Salesforce and tell me which fields hold the amount, close date, owner, account website and any Stripe customer ID. Then use SOQL to list opportunities marked Closed Won with a close date in {period}: name, account, website, owner, amount and close date. Don't change any records.
- In Stripe, read the customers, invoices and subscriptions for those accounts, from the start of {period} to 30 days after it ends. Match each opportunity to a Stripe customer by {stripe id field} if it's set, otherwise by email domain. Show how each match was made. Read only. Don't change anything in Stripe.
- For each opportunity, compare the won amount with what was invoiced and what was paid, using subtotals before tax. Flag: no invoice, invoiced but unpaid, partly paid, or a different amount. If a subscription bills in instalments, compare against what should have been billed so far and mark it as a schedule, not a gap.
- Give me a table of the mismatches only, grouped by owner, then a list of paid Stripe invoices with no closed-won opportunity. Add a line for each owner where the Salesforce amount and the paid amount differ, so I can check commissions. Don't change anything in Salesforce or Stripe.
Run it on a schedule (optional)
- Run it monthly, a few days after month end and before the commission run, so late invoices have had time to go out.
- In a scheduled run, produce the table and send it to yourself. The recipe never changes anything, so there's nothing to approve, but read the mismatches before they go to finance.
- For a headless run, Stripe accepts an agent API key. From December 2026 it rejects full-access secret keys and restricted keys without the Agent tag, so use a restricted Agent key with read access only. Salesforce needs an admin to set up the connection first.
Where this goes wrong
- Wrong customer matched. A Stripe customer name often differs from the Salesforce account name. Match on a Stripe customer ID field if your org stores one, otherwise on email domain. Show the match basis for every row and list unmatched opportunities instead of guessing.
- A billing schedule flagged as partial payment. A quarterly or monthly subscription won't have paid the full contract yet. Read the subscription, compare what should have been billed so far, and mark those rows as a schedule rather than a gap.
- Late invoices flagged as missing. A deal won on the last day of the month is often invoiced the next week. Look at invoices up to 30 days after the period ends before marking anything missing.
- Tax or currency read as a different amount. An invoice total can include tax, or be in another currency. Compare subtotals before tax, show the currency on every row, and flag currency mismatches separately.
Gotchas
- Salesforce needs admin or IT setup: its MCP server needs Enterprise Edition or above, and an admin must create an External Client App for each client. In ChatGPT it also needs developer mode. Ask for the read-only platform/sobject-reads server for this recipe.
- Every Salesforce tool call counts against the org's daily API request quota, so pull the closed-won list in one query, not one opportunity at a time.
- Stripe's MCP server can write: it creates, finalizes and voids invoices, cancels subscriptions, creates payment links and coupons, and issues refunds with human confirmation. Connect with an account or restricted key that only has read access.
- In Claude Team and Enterprise, an owner must add the Stripe connector to the workspace before you can connect it.
- Using HubSpot instead? HubSpot's connector covers CRM search, so the same steps work on closed-won deals and their companies. Non-admin users need a Super Admin to approve the HubSpot connector first.
Download
Get the prompts, guardrails and expected output as one Markdown file. Paste it into a Claude Project or ChatGPT project's instructions, or save it as CLAUDE.md for Claude Code.
Download revenue-reconciliation.md