← All blueprints

Invoice Match Custom

blueprint · 4 agents · 3 MCP servers
1145★ stars
149forks
4.7rating

What it does

An extractor reads the invoice document and pulls vendor, line items, quantities, and totals. A matcher checks those against the purchase order and goods-receipt records in the database: does the price match the PO, was the quantity received, has this invoice number been paid before. The flow branches on the result: a clean match is summarized and paused for human approval; a mismatch produces an exception report that names each disagreement. No payment is executed by the workflow under any path.

The cast · 4 agents

Matchermatcherreasoning

Three-way match the invoice against the purchase order and goods-receipt records: price per line against the PO, quantity against what was received, and the invoice number against payment history for duplicates. Return an object with a 'clean' boolean and, per line, what matched or disagreed. Read-only.

db.query_dsl
Extractorextractorfast

Read the invoice document. Extract the vendor, invoice number, date, line items with quantities and unit prices, and the total. Flag anything illegible rather than guessing.

drive.read_doc
Approval ClerkapprovalClerkfast

Summarize the clean match in three lines — vendor, amount, what it matched against — and post it to the AP channel for sign-off. Do not pay anything.

chat.post_message
Exception WriterexceptionWriterreasoning

Write the exception: name each disagreement precisely (duplicate invoice number, price above PO, quantity short of receipt), what the records say, and what to check first. Post it to the AP channel.

chat.post_message

Flow

Extractorinvoice
Matchermatch
⑂ branch
match.clean == true
Approval Clerkdisposition
askdisposition

Interface

Inputs
invoiceRefstring
The invoice to process, as a drive document id or path.
Outputs
dispositionstring
Approved-and-queued, or the exception report, whichever path ran.

Depends on · 3 MCP servers

Multi-account MCP for Gmail, Calendar, Drive, Docs, and Sheets — 61 tools, tokenio.github.adelaidasofia/google-workspace-mcpdriveAVerified
io.github.supabase/postgres-mcpnot in the registry yetdb
io.github.slack/slack-mcpnot in the registry yetchat
⤓ Export runnable code
# Generated by @socketcat/compiler for target: langgraph
# blueprint: com.socketcat/invoice-match 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):
    invoiceRef: object
    disposition: object
    invoice: object
    match: object

def node_AgentInvoke_0(state):
    return _rt.run_agent("extractor", state, {"invoiceRef":"invoiceRef"}, "invoice")

def node_AgentInvoke_1(state):
    return _rt.run_agent("matcher", state, {"invoice":"invoice"}, "match")

def node_Branch_2(state):
    return {}

def node_Join_3(state):
    return {}

def node_AgentInvoke_4(state):
    return _rt.run_agent("approvalClerk", state, {"match":"match","invoice":"invoice"}, "disposition")

def node_Ask_5(state):
    return _rt.run_ask("Approve this invoice for payment, or send it back with notes.", state, "disposition")

def node_AgentInvoke_6(state):
    return _rt.run_agent("exceptionWriter", state, {"match":"match","invoice":"invoice"}, "disposition")

def route_Branch_2(state):
    if _rt.cond("match.clean == true", state): return "AgentInvoke_4"
    return "AgentInvoke_6"

def build():
    b = StateGraph(State)
    b.add_node("AgentInvoke_0", node_AgentInvoke_0)
    b.add_node("AgentInvoke_1", node_AgentInvoke_1)
    b.add_node("Branch_2", node_Branch_2)
    b.add_node("Join_3", node_Join_3)
    b.add_node("AgentInvoke_4", node_AgentInvoke_4)
    b.add_node("Ask_5", node_Ask_5)
    b.add_node("AgentInvoke_6", node_AgentInvoke_6)
    b.add_edge(START, "AgentInvoke_0")
    b.add_edge("AgentInvoke_0", "AgentInvoke_1")
    b.add_edge("AgentInvoke_1", "Branch_2")
    b.add_conditional_edges("Branch_2", route_Branch_2, {"AgentInvoke_4": "AgentInvoke_4", "AgentInvoke_6": "AgentInvoke_6"})
    b.add_edge("Join_3", END)
    b.add_edge("AgentInvoke_4", "Ask_5")
    b.add_edge("Ask_5", "Join_3")
    b.add_edge("AgentInvoke_6", "Join_3")
    return b.compile()

INPUTS = ["invoiceRef"]
OUTPUTS = ["disposition"]

if __name__ == "__main__":
    _rt.main(build, INPUTS, OUTPUTS)
blueprint.json (the portable format)
{
  "id": "com.socketcat/invoice-match",
  "flow": {
    "type": "sequence",
    "blocks": [
      {
        "in": {
          "invoiceRef": "invoiceRef"
        },
        "out": "invoice",
        "use": "extractor",
        "type": "agent"
      },
      {
        "in": {
          "invoice": "invoice"
        },
        "out": "match",
        "use": "matcher",
        "type": "agent"
      },
      {
        "else": [
          {
            "in": {
              "match": "match",
              "invoice": "invoice"
            },
            "out": "disposition",
            "use": "exceptionWriter",
            "type": "agent"
          }
        ],
        "type": "branch",
        "cases": [
          {
            "when": "match.clean == true",
            "blocks": [
              {
                "in": {
                  "match": "match",
                  "invoice": "invoice"
                },
                "out": "disposition",
                "use": "approvalClerk",
                "type": "agent"
              },
              {
                "out": "disposition",
                "type": "ask",
                "prompt": "Approve this invoice for payment, or send it back with notes."
              }
            ]
          }
        ]
      }
    ]
  },
  "tags": [
    "finance",
    "accounts-payable",
    "three-way-match",
    "human-in-the-loop"
  ],
  "title": "Invoice Match",
  "agents": {
    "matcher": {
      "model": {
        "hint": "reasoning"
      },
      "title": "Matcher",
      "tools": [
        "db.query_dsl"
      ],
      "output": {
        "type": "object",
        "required": [
          "clean"
        ],
        "properties": {
          "clean": {
            "type": "boolean"
          },
          "lines": {
            "type": "array"
          }
        }
      },
      "instructions": "Three-way match the invoice against the purchase order and goods-receipt records: price per line against the PO, quantity against what was received, and the invoice number against payment history for duplicates. Return an object with a 'clean' boolean and, per line, what matched or disagreed. Read-only."
    },
    "extractor": {
      "model": {
        "hint": "fast"
      },
      "title": "Extractor",
      "tools": [
        "drive.read_doc"
      ],
      "instructions": "Read the invoice document. Extract the vendor, invoice number, date, line items with quantities and unit prices, and the total. Flag anything illegible rather than guessing."
    },
    "approvalClerk": {
      "model": {
        "hint": "fast"
      },
      "title": "Approval Clerk",
      "tools": [
        "chat.post_message"
      ],
      "instructions": "Summarize the clean match in three lines — vendor, amount, what it matched against — and post it to the AP channel for sign-off. Do not pay anything."
    },
    "exceptionWriter": {
      "model": {
        "hint": "reasoning"
      },
      "title": "Exception Writer",
      "tools": [
        "chat.post_message"
      ],
      "instructions": "Write the exception: name each disagreement precisely (duplicate invoice number, price above PO, quantity short of receipt), what the records say, and what to check first. Post it to the AP channel."
    }
  },
  "estate": {
    "match": {
      "type": "object",
      "description": "The matcher's verdict, including a 'clean' flag and per-line results."
    },
    "invoice": {
      "type": "object",
      "description": "The extracted vendor, line items, and totals."
    }
  },
  "$schema": "socketcat.dev/blueprint/v0",
  "authors": [
    {
      "url": "https://socketcat.com",
      "name": "SocketCat"
    }
  ],
  "license": "MIT",
  "servers": [
    {
      "ref": "io.github.adelaidasofia/google-workspace-mcp",
      "alias": "drive"
    },
    {
      "ref": "io.github.supabase/postgres-mcp",
      "alias": "db"
    },
    {
      "ref": "io.github.slack/slack-mcp",
      "alias": "chat"
    }
  ],
  "summary": "Extracts an invoice, three-way matches it against PO and receipt records, and routes to approval or a written exception.",
  "targets": [
    "langgraph",
    "*"
  ],
  "version": "1.0.0",
  "interface": {
    "inputs": {
      "invoiceRef": {
        "type": "string",
        "description": "The invoice to process, as a drive document id or path."
      }
    },
    "outputs": {
      "disposition": {
        "type": "string",
        "description": "Approved-and-queued, or the exception report, whichever path ran."
      }
    }
  },
  "extensions": {
    "dev.langgraph": {
      "checkpointer": "memory"
    }
  },
  "description": "An extractor reads the invoice document and pulls vendor, line items, quantities, and totals. A matcher checks those against the purchase order and goods-receipt records in the database: does the price match the PO, was the quantity received, has this invoice number been paid before. The flow branches on the result: a clean match is summarized and paused for human approval; a mismatch produces an exception report that names each disagreement. No payment is executed by the workflow under any path."
}

More in Finance & legal

Browse all →

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

Revenue Reconciler

com.socketcat/revenue-reconciler
LangGraph

Pulls Stripe charges and your warehouse's invoice records for the period in parallel, reconciles them line by line, and reports only the discrepancies — with likely causes.

10684 servers
136

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