← All blueprints

Revenue Reconciler LangGraph

blueprint · 4 agents · 4 MCP servers
1068★ stars
136forks
4.7rating

What it does

A payments agent lists the period's charges, refunds, and payouts from Stripe while a ledger agent pulls the invoice and revenue records from the warehouse. A reconciler matches the two sets line by line and keeps only the discrepancies: charges with no invoice, invoices marked paid with no charge, amount drift after partial refunds, currency mismatches. Each break gets a likely cause and where to look first. A reporter writes the full reconciliation to a file and posts the breaks to the finance channel. Read-only throughout; no records are changed and no money moves.

The cast · 4 agents

Reporterreporterfast

Write the full reconciliation to a file: totals, match rate, and each break with its likely cause. Post the breaks to the finance channel; if there are none, post a single all-clear line with the matched total.

fs.write_filechat.post_message
Reconcilerreconcilerreasoning

Match the two sets line by line on customer, amount, and date. Keep only the breaks: charge without invoice, paid invoice without charge, amount drift, currency mismatch. For each, state the likely cause (timing, partial refund, manual entry, webhook miss) and where to look first. Report the matched totals so the clean volume is visible too.

no tools · reasoning only
LedgerledgerAgentfast

Pull the invoice and recognized-revenue records for the period from the warehouse with id, amount, currency, and status. Return the raw set with totals. Read-only.

db.query_dsl
PaymentspaymentsAgentfast

List every charge, refund, and payout in the period from Stripe with id, amount, currency, and customer. Return the raw set with totals. Read-only.

pay.list_chargespay.list_refunds

Flow

⇉ parallel
PaymentsstripeActivity
LedgerledgerRecords
Reconcilerbreaks
Reporterreport

Interface

Inputs
periodstring
The period to reconcile, e.g. '2026-06'.
Outputs
reportstring
The reconciliation summary: matched totals and each break with its likely cause.

Depends on · 4 MCP servers

com.stripe/payments-mcpnot in the registry yetpay
io.github.supabase/postgres-mcpnot in the registry yetdb
io.github.modelcontextprotocol/filesystemnot in the registry yetfs
io.github.slack/slack-mcpnot in the registry yetchat
⤓ Export runnable code
# Generated by @socketcat/compiler for target: langgraph
# blueprint: com.socketcat/revenue-reconciler v1.0.0   schema: socketcat.dev/blueprint/v0
# This code is yours. Edit it freely. The socketcat_runtime helper is optional and can be vendored.

from typing import TypedDict
from langgraph.graph import StateGraph, START, END
import socketcat_runtime as _rt

class State(TypedDict, total=False):
    period: object
    report: object
    stripeActivity: object
    ledgerRecords: object
    breaks: object

def node_Fork_0(state):
    return {}

def node_Join_1(state):
    return {}

def node_AgentInvoke_2(state):
    return _rt.run_agent("paymentsAgent", state, {"period":"period"}, "stripeActivity")

def node_AgentInvoke_3(state):
    return _rt.run_agent("ledgerAgent", state, {"period":"period"}, "ledgerRecords")

def node_AgentInvoke_4(state):
    return _rt.run_agent("reconciler", state, {"ledgerRecords":"ledgerRecords","stripeActivity":"stripeActivity"}, "breaks")

def node_AgentInvoke_5(state):
    return _rt.run_agent("reporter", state, {"breaks":"breaks"}, "report")

def build():
    b = StateGraph(State)
    b.add_node("Fork_0", node_Fork_0)
    b.add_node("Join_1", node_Join_1)
    b.add_node("AgentInvoke_2", node_AgentInvoke_2)
    b.add_node("AgentInvoke_3", node_AgentInvoke_3)
    b.add_node("AgentInvoke_4", node_AgentInvoke_4)
    b.add_node("AgentInvoke_5", node_AgentInvoke_5)
    b.add_edge(START, "Fork_0")
    b.add_edge("Fork_0", "AgentInvoke_2")
    b.add_edge("Fork_0", "AgentInvoke_3")
    b.add_edge("Join_1", "AgentInvoke_4")
    b.add_edge("AgentInvoke_2", "Join_1")
    b.add_edge("AgentInvoke_3", "Join_1")
    b.add_edge("AgentInvoke_4", "AgentInvoke_5")
    b.add_edge("AgentInvoke_5", END)
    return b.compile()

INPUTS = ["period"]
OUTPUTS = ["report"]

if __name__ == "__main__":
    _rt.main(build, INPUTS, OUTPUTS)
blueprint.json (the portable format)
{
  "id": "com.socketcat/revenue-reconciler",
  "flow": {
    "type": "sequence",
    "blocks": [
      {
        "type": "parallel",
        "blocks": [
          {
            "in": {
              "period": "period"
            },
            "out": "stripeActivity",
            "use": "paymentsAgent",
            "type": "agent"
          },
          {
            "in": {
              "period": "period"
            },
            "out": "ledgerRecords",
            "use": "ledgerAgent",
            "type": "agent"
          }
        ]
      },
      {
        "in": {
          "ledgerRecords": "ledgerRecords",
          "stripeActivity": "stripeActivity"
        },
        "out": "breaks",
        "use": "reconciler",
        "type": "agent"
      },
      {
        "in": {
          "breaks": "breaks"
        },
        "out": "report",
        "use": "reporter",
        "type": "agent"
      }
    ]
  },
  "tags": [
    "finance",
    "reconciliation",
    "parallel",
    "month-end"
  ],
  "title": "Revenue Reconciler",
  "agents": {
    "reporter": {
      "model": {
        "hint": "fast"
      },
      "title": "Reporter",
      "tools": [
        "fs.write_file",
        "chat.post_message"
      ],
      "instructions": "Write the full reconciliation to a file: totals, match rate, and each break with its likely cause. Post the breaks to the finance channel; if there are none, post a single all-clear line with the matched total."
    },
    "reconciler": {
      "model": {
        "hint": "reasoning"
      },
      "title": "Reconciler",
      "instructions": "Match the two sets line by line on customer, amount, and date. Keep only the breaks: charge without invoice, paid invoice without charge, amount drift, currency mismatch. For each, state the likely cause (timing, partial refund, manual entry, webhook miss) and where to look first. Report the matched totals so the clean volume is visible too."
    },
    "ledgerAgent": {
      "model": {
        "hint": "fast"
      },
      "title": "Ledger",
      "tools": [
        "db.query_dsl"
      ],
      "instructions": "Pull the invoice and recognized-revenue records for the period from the warehouse with id, amount, currency, and status. Return the raw set with totals. Read-only."
    },
    "paymentsAgent": {
      "model": {
        "hint": "fast"
      },
      "title": "Payments",
      "tools": [
        "pay.list_charges",
        "pay.list_refunds"
      ],
      "instructions": "List every charge, refund, and payout in the period from Stripe with id, amount, currency, and customer. Return the raw set with totals. Read-only."
    }
  },
  "estate": {
    "breaks": {
      "type": "object",
      "description": "The reconciler's discrepancies with likely causes."
    },
    "ledgerRecords": {
      "type": "object",
      "description": "Invoice and revenue records from the warehouse for the period."
    },
    "stripeActivity": {
      "type": "object",
      "description": "Charges, refunds, and payouts from Stripe for the period."
    }
  },
  "$schema": "socketcat.dev/blueprint/v0",
  "authors": [
    {
      "url": "https://socketcat.com",
      "name": "SocketCat"
    }
  ],
  "license": "MIT",
  "servers": [
    {
      "ref": "com.stripe/payments-mcp",
      "alias": "pay"
    },
    {
      "ref": "io.github.supabase/postgres-mcp",
      "alias": "db"
    },
    {
      "ref": "io.github.modelcontextprotocol/filesystem",
      "alias": "fs"
    },
    {
      "ref": "io.github.slack/slack-mcp",
      "alias": "chat"
    }
  ],
  "summary": "Pulls Stripe activity and warehouse invoice records in parallel, reconciles line by line, and reports only the breaks with likely causes.",
  "targets": [
    "langgraph",
    "*"
  ],
  "version": "1.0.0",
  "interface": {
    "inputs": {
      "period": {
        "type": "string",
        "description": "The period to reconcile, e.g. '2026-06'."
      }
    },
    "outputs": {
      "report": {
        "type": "string",
        "description": "The reconciliation summary: matched totals and each break with its likely cause."
      }
    }
  },
  "extensions": {
    "dev.langgraph": {
      "checkpointer": "memory"
    }
  },
  "description": "A payments agent lists the period's charges, refunds, and payouts from Stripe while a ledger agent pulls the invoice and revenue records from the warehouse. A reconciler matches the two sets line by line and keeps only the discrepancies: charges with no invoice, invoices marked paid with no charge, amount drift after partial refunds, currency mismatches. Each break gets a likely cause and where to look first. A reporter writes the full reconciliation to a file and posts the breaks to the finance channel. Read-only throughout; no records are changed and no money moves."
}

More in Finance & legal

Browse all →

Invoice Match

com.socketcat/invoice-match
Custom

Reads an incoming invoice, matches it against the purchase order and receipt in your database, and branches: clean ones queue for approval, mismatches get a written exception.

11453 servers
149

Contract Redline

com.socketcat/contract-redline
LangGraph

Extracts a contract's clauses, checks each against your playbook, and loops a redliner against a reviewer until it's clean — then a lawyer approves.

11243 servers
146

Dispute Responder

com.socketcat/dispute-responder
Autogen

A Stripe dispute goes to two agents who argue it out — advocate versus risk — then draft an evidence packet you approve before it's filed.

6882 servers
82