# Supplier Payment Decision Agent: buyer quickstart The service recommends; it never moves invoice money or provides bank Confirmation of Payee. A valid IBAN checksum does not prove account ownership. Document matches compare supplied PO/GRN/invoice data, not independently authenticated ERP records. Confidence 1.0 is a rule result, not certainty of safety. ## Try a synthetic example without paying Use-case guide: https://supplier-payment-verifier-production.up.railway.app/use-cases/supplier-invoice-verification Versioned offline scenarios: https://supplier-payment-verifier-production.up.railway.app/examples.json (assumed outcomes, not executed checks). GET https://supplier-payment-verifier-production.up.railway.app/demo The fixed response is prominently marked SYNTHETIC_ILLUSTRATION, not a live verification. It accepts no supplier inputs and does not contact registries, register keys or move money. ## Runnable REST buyer Public MIT-licensed standalone client: https://github.com/LKennedyShare/supplier-payment-assistant python -m pip install supplier-payment-assistant supplier-payment-assistant --demo # Completely offline: generates an RSA signature and prints a clearly labelled illustrative response. Prepare an unsigned JSON request with transaction_id, supplier, invoice, purchase_order and goods_receipt; omit signature. Keep a stable transaction_id for the same business request. See /schemas/decision.schema.json. Do not submit the synthetic placeholder company/VAT as if it were a real supplier. supplier-payment-assistant https://supplier-payment-verifier-production.up.railway.app --request .\invoice.json # Inspection only: fetches empty x402 quote probes for both operations. No wallet key or payment signing. To pay, set X402_CLIENT_PRIVATE_KEY in your local shell to a throwaway wallet funded with a small USDC balance on the quoted network. Never put a private key in source code, a prompt, request JSON or a log. supplier-payment-assistant https://supplier-payment-verifier-production.up.railway.app --request .\invoice.json --pay --max-usdc 0.055 Explicit --pay permits one paid retry for registration (0.005 USDC) and one decision (0.05 USDC), at most 0.055 USDC combined. Base mainnet spends real USDC. Quotes, scheme, token contract, network and remaining budget are validated before signing; redirects are refused. No automatic payment retries. The RSA signing key is ephemeral: a new public key/key_id is generated per run. The wallet is separate and identifies the tenant. A later rerun may pay registration again. Partial failures report authorized and confirmed spend; missing settlement metadata is unconfirmed and stops the flow. Python integration: from supplier_payment_assistant import run_live, PaymentRequest. run_live(base_url, unsigned_request) only inspects quotes; pay=True explicitly authorizes service fees. MIT covers the client code, not service data or API usage terms. ## LangChain and OpenAI Agents SDK python -m pip install "supplier-payment-assistant[langchain,openai]>=0.2.0" from supplier_payment_assistant import SupplierPaymentTools session = SupplierPaymentTools() langchain_tools = session.langchain_tools() openai_tools = session.openai_tools() Default tools: offline_demo and inspect_supplier. Paid verification is exposed only with an operator-defined approval_policy comparing validated canonical request digests to trusted records. The model cannot approve payments or set wallet, URL or budget parameters. Retain one instance across calls: 0.055 USDC cumulative reservation ceiling, one paid attempt by default; failures retain reservations. Limits are in-memory and reset on recreation/restart: use durable external policy/budgets for production. Invoice data and results may reach your chosen model/tracing provider; obtain authorization and configure privacy controls. No invoice money is moved. Runnable offline framework examples: https://github.com/LKennedyShare/supplier-payment-assistant/tree/main/examples ## Exact request signing Use PaymentRequest.model_validate with a placeholder signature, then PaymentRequest.signed_body(). This normalizes Decimal fields and serializes sorted-key compact JSON excluding signature. Sign those bytes using RSA-PSS, SHA-256, MGF1(SHA-256), salt_length=PSS.DIGEST_LENGTH. The buyer client does this automatically. Hand-signing the original JSON without model normalization can produce a signature mismatch. ## MCP Complete public handbook: https://supplier-payment-verifier-production.up.railway.app/llms-full.txt VS Code download: https://supplier-payment-verifier-production.up.railway.app/integrations/vscode-mcp.json (merge into .vscode\mcp.json). Cursor download: https://supplier-payment-verifier-production.up.railway.app/integrations/cursor-mcp.json (merge into .cursor\mcp.json). Operator: inspect the URL and review/merge the entry into existing configuration; do not overwrite other servers. Downloading never connects, auto-installs, registers keys or pays. Configuration trust approval is not payment approval. All supplier-operation MCP tools are paid; the public synthetic demo is HTTP-only and the offline buyer demo is client-only, not a free MCP tool. Endpoint: https://supplier-payment-verifier-production.up.railway.app/mcp/ Use tools/list as the exact runtime schema. Check tools wrap their payload in request; the decision tool uses payment_request; key registration stays flat: {"name": "check_iban", "arguments": {"request": {"iban": "IE29AIBK93115212345678"}}} {"name": "decide_supplier_payment", "arguments": {"payment_request": ""}} A normal MCP connection does not supply a wallet. An x402-capable MCP client reads the payment-required tool result, then retries with _meta['x402/payment']; successful settlement is in _meta['x402/payment-response']. ## A2A (JSON-RPC 0.3 binding) POST https://supplier-payment-verifier-production.up.railway.app/a2a with method message/send and one JSON data part: {"jsonrpc": "2.0", "id": "check-1", "method": "message/send", "params": {"message": {"kind": "message", "messageId": "message-1", "role": "user", "parts": [{"kind": "data", "data": {"operation": "check_iban", "request": {"iban": "IE29AIBK93115212345678"}}}]}}} Use operation=register_signing_key, then operation=decide_supplier_payment with the same flat REST request objects. Each operation is priced as its REST counterpart. Unwrapped legacy verification messages still return RELEASE/REVIEW/BLOCK/INSUFFICIENT_EVIDENCE, not the five-gate decision. Unpaid A2A calls return HTTP 200 with task input-required and x402.payment.required metadata. Retry with PAYMENT-SIGNATURE. Results include settlement receipts; failed settlement withholds artifacts. tasks/get reads completed tasks for the paying tenant; it retains the configured A2A verification-call price (not the cheaper REST get-verification price). ## Failures and limits HTTP 400/422 means invalid input, 409 means transaction/key conflict, 429 means wait and honor Retry-After; no automatic payment retry. A paid call returning FLAG_FOR_HUMAN_REVIEW is a valid billable decision, not a payment-processing error. Provider outages cannot produce EXECUTE_PAYMENT. x402 pays for this service only. execution_payload contains advisory invoice details: this client never submits them to a bank. Keep customer-controlled payment approval and account-ownership checks.