Work is already done. Lock payment in XRPL escrow as a confirmed payment intent — the supplier submits a matching invoice and receives payment automatically. No manual AP approval, no payment chasing, no trusted intermediary. Works for humans, agents, or any mix of both.
A business hires an individual to deliver coffee to a warehouse. Terms are agreed over email: supplier name, XRPL wallet address, amount, description.
A week later, the warehouse confirms receipt. The finance team creates an escrow — funds are locked on-chain as confirmed payment intent. The supplier receives an email: "Your payment of $500 RLUSD is ready to claim at our supplier portal. Use PO reference PO-2024-0042."
The supplier visits the portal, fills in their invoice details (or uploads a PDF), and submits. The AI referee checks whether the invoice matches the PO — supplier name, amount, description. If it matches: payment hits their wallet within seconds. If something's wrong: they see exactly what to correct and resubmit.
The finance team's accounts inbox receives a copy of the verified invoice automatically. No manual approval step. No chasing.
Key insight: the escrow isn't a payment gate against future work — it's a confirmed payment intent for work already done. The supplier sees locked funds before submitting anything. That's the difference from a normal invoice chase.
Only one side needs to be "smart" for the system to work. A business can deploy this unilaterally — every supplier benefits without changing their behaviour much.
Finance team raises a PO manually and locks escrow via the portal. Supplier visits the supplier portal, fills in their invoice, clicks submit. Both sides use a web form — no code required on either side.
Finance team locks escrow as normal. The supplier's billing system needs to know the escrow_id to submit against. There are three practical paths today: (1) the buyer's system calls the supplier's API endpoint directly after POST /escrow/generate returns the ID; (2) the supplier's system watches the XRPL ledger for EscrowCreate transactions pointing to their wallet address — the escrow ID and task spec are in the on-chain memo, no off-chain notification needed; or (3) the supplier parses the notification email sent to worker_email. The supplier agent then generates a conforming invoice and calls POST /evaluate automatically.
A warehouse management system or ERP confirms delivery and automatically creates the escrow via POST /escrow/generate — no finance team involvement. The supplier (a small courier, an individual contractor) receives an email to the worker_email address containing the escrow ID, invoice requirements, and a direct submission link. They visit the portal and upload their invoice manually. They need no technical knowledge.
Delivery confirmed → buyer agent calls POST /escrow/generate → buyer agent calls supplier agent's API with the returned escrow_id → supplier agent generates invoice and calls POST /evaluate → payment released. Alternatively, the supplier agent watches the XRPL ledger for escrows landing at its wallet address — no off-chain notification channel needed at all. Zero human involvement in the payment cycle.
A contractor works for a week. Goods are delivered to a warehouse. Terms were agreed beforehand — amount, supplier, description — outside of AgentTrust, just as normal.
The buyer creates an escrow specifying the supplier wallet, amount, and a description of what the invoice must contain. Includes an accounts email so verified invoices are forwarded to the right inbox automatically. The escrow ID is shared with the supplier (by email, portal link, or webhook).
Human: visits the supplier portal, fills in their invoice details. Agent: receives a webhook, generates the invoice programmatically, calls POST /evaluate directly. Either way — escrow ID, invoice number, company name, amount, description of services delivered.
PASS: payment released to supplier wallet instantly. Invoice PDF emailed to the buyer's accounts address. FAIL: supplier sees exactly what to correct and can resubmit (up to the configured limit).
Enable Invoice Mode on the main escrow form. Toggle it on, fill in your PO details (reference, supplier name, services description), and the requirements are emailed to the supplier automatically when you create the escrow. Supplier submits their proof of work and invoice to claim payment.
Open escrow formEmbed the buyer and supplier forms directly into your supplier portal or ERP. Your brand, your domain, your workflow. AgentTrust handles the escrow and AI verification invisibly behind the scenes.
Two HTML forms: one for the buyer (raises the PO and locks escrow), one for the supplier (submits their invoice to claim payment). Style them to match your brand.
Used by your finance team (or triggered automatically by your ERP) to lock payment. Posts to your own backend endpoint — your wallet secret never touches the browser. The accounts email field ensures a copy of every verified invoice lands in the right inbox.
<!-- AgentTrust Buyer Form — embed in your supplier portal -->
<style>
.at-form { font-family: system-ui, sans-serif; max-width: 480px; }
.at-form label { display: block; font-size: .85rem; font-weight: 600; margin-bottom: .3rem; }
.at-form input, .at-form textarea, .at-form select {
width: 100%; padding: .6rem .8rem; border: 1px solid #dde0ea;
border-radius: 8px; font-size: .9rem; margin-bottom: 1rem; font-family: inherit;
}
.at-form button { padding: .65rem 1.5rem; background: #0066FF; color: #fff;
border: none; border-radius: 8px; font-size: .9rem; font-weight: 700; cursor: pointer; }
.at-status { margin-top: 1rem; font-size: .85rem; padding: .75rem 1rem;
border-radius: 8px; display: none; }
.at-status.success { background: #f0fdf8; border: 1px solid #bbf7d0; color: #166534; display: block; }
.at-status.error { background: #fef2f2; border: 1px solid #fecaca; color: #991b1b; display: block; }
</style>
<form class="at-form" onsubmit="atCreateEscrow(event)">
<h3>Lock Payment for Supplier</h3>
<label>Purchase Order Number</label>
<input id="at-po" placeholder="PO-2024-0042" required>
<label>Supplier Company Name</label>
<input id="at-supplier-name" placeholder="Acme Logistics Ltd" required>
<label>Supplier XRPL Wallet Address</label>
<input id="at-supplier-wallet" placeholder="rXXX…" required>
<label>Amount (RLUSD)</label>
<input id="at-amount" type="number" min="1" step="0.01" placeholder="500.00" required>
<label>Services / Goods Description</label>
<textarea id="at-description" rows="3"
placeholder="e.g. Coffee delivery to Warehouse B — 200kg, delivered week of 14 Aug" required></textarea>
<label>Send verified invoices to (accounts email)</label>
<input id="at-accounts-email" type="email" placeholder="accounts@yourcompany.com" required>
<label>Payment Window</label>
<select id="at-deadline">
<option value="168">7 days</option>
<option value="336">14 days</option>
<option value="720" selected>30 days</option>
</select>
<button type="submit">Lock Payment in Escrow</button>
<div class="at-status" id="at-buyer-status"></div>
</form>
<script>
async function atCreateEscrow(e) {
e.preventDefault();
const status = document.getElementById('at-buyer-status');
status.className = 'at-status';
status.textContent = 'Creating escrow…';
status.style.display = 'block';
const po = document.getElementById('at-po').value;
const supplier = document.getElementById('at-supplier-name').value;
const wallet = document.getElementById('at-supplier-wallet').value;
const amount = parseFloat(document.getElementById('at-amount').value);
const desc = document.getElementById('at-description').value;
const acctEmail = document.getElementById('at-accounts-email').value;
const hrs = parseInt(document.getElementById('at-deadline').value);
const spec = [
`Invoice Verification — ${po}`,
`Supplier: ${supplier}`,
`Amount: ${amount} RLUSD`,
`Services: ${desc}`,
``,
`PAYMENT RELEASES when the supplier submits an invoice matching:`,
`- Supplier name: ${supplier}`,
`- Amount: ${amount} RLUSD`,
`- PO reference: ${po}`,
`- Description consistent with: ${desc}`,
].join('\n');
try {
// POST to YOUR backend — wallet secret stays server-side
const res = await fetch('/api/create-escrow', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
po_number: po, supplier_name: supplier,
supplier_wallet: wallet, amount_rlusd: amount,
task_description: spec, cancel_after_hrs: hrs,
accounts_email: acctEmail,
}),
});
const data = await res.json();
if (data.escrow_id) {
status.className = 'at-status success';
status.innerHTML = `✓ Payment locked. Share with your supplier:<br>
<strong>Escrow ID: ${data.escrow_id}</strong><br>
Verified invoices will be sent to ${acctEmail}`;
} else {
throw new Error(data.detail || 'Unknown error');
}
} catch (err) {
status.className = 'at-status error';
status.textContent = `Error: ${err.message}`;
}
}
</script>
Your suppliers use this to claim payment. They enter the escrow ID shared by the buyer, fill in their invoice, and submit. No AgentTrust account needed. This form calls the AgentTrust API directly — no wallet secret required on the supplier side.
<!-- AgentTrust Supplier Form — embed in your supplier portal -->
<style>
.at-form { font-family: system-ui, sans-serif; max-width: 480px; }
.at-form label { display: block; font-size: .85rem; font-weight: 600; margin-bottom: .3rem; }
.at-form input, .at-form textarea {
width: 100%; padding: .6rem .8rem; border: 1px solid #dde0ea;
border-radius: 8px; font-size: .9rem; margin-bottom: 1rem; font-family: inherit;
}
.at-form button { padding: .65rem 1.5rem; background: #0066FF; color: #fff;
border: none; border-radius: 8px; font-size: .9rem; font-weight: 700; cursor: pointer; }
.at-status { margin-top: 1rem; font-size: .85rem; padding: .75rem 1rem;
border-radius: 8px; display: none; }
.at-status.success { background: #f0fdf8; border: 1px solid #bbf7d0; color: #166534; display: block; }
.at-status.fail { background: #fefce8; border: 1px solid #fde68a; color: #92400e; display: block; }
.at-status.error { background: #fef2f2; border: 1px solid #fecaca; color: #991b1b; display: block; }
</style>
<form class="at-form" onsubmit="atSubmitInvoice(event)">
<h3>Claim Your Payment</h3>
<p style="font-size:.85rem;color:#666;margin-bottom:1rem;">
Enter the escrow ID your buyer shared with you, then fill in your invoice details.
</p>
<label>Escrow ID (from your buyer)</label>
<input id="at-escrow-id" placeholder="e.g. INV-A1B2C3D4" required>
<label>Your Invoice Number</label>
<input id="at-inv-number" placeholder="INV-2025-0099" required>
<label>Your Company Name</label>
<input id="at-company" placeholder="Acme Logistics Ltd" required>
<label>Amount Invoiced (RLUSD)</label>
<input id="at-inv-amount" type="number" min="0.01" step="0.01" placeholder="500.00" required>
<label>Services or Goods Delivered</label>
<textarea id="at-inv-desc" rows="3"
placeholder="Describe exactly what was delivered, matching your agreement with the buyer" required></textarea>
<label>Purchase Order Reference <span style="font-weight:400;">(from your buyer)</span></label>
<input id="at-po-ref" placeholder="PO-2024-0042">
<label>Delivery Evidence URL <span style="font-weight:400;">(optional — tracking, photo, etc.)</span></label>
<input id="at-evidence" type="url" placeholder="https://…">
<button type="submit">Submit Invoice & Claim Payment</button>
<div class="at-status" id="at-supplier-status"></div>
</form>
<script>
async function atSubmitInvoice(e) {
e.preventDefault();
const status = document.getElementById('at-supplier-status');
status.className = 'at-status';
status.textContent = 'Submitting invoice for verification…';
status.style.display = 'block';
const escrowId = document.getElementById('at-escrow-id').value.trim();
const invNum = document.getElementById('at-inv-number').value.trim();
const company = document.getElementById('at-company').value.trim();
const amount = document.getElementById('at-inv-amount').value.trim();
const desc = document.getElementById('at-inv-desc').value.trim();
const poRef = document.getElementById('at-po-ref').value.trim();
const evidence = document.getElementById('at-evidence').value.trim();
const invoice = [
`INVOICE ${invNum}`,
`From: ${company}`,
`Amount: ${amount} RLUSD`,
poRef ? `PO Reference: ${poRef}` : '',
`Services delivered: ${desc}`,
].filter(Boolean).join('\n');
const body = { escrow_id: escrowId, work: invoice };
if (evidence) body.evidence_links = [evidence];
try {
const res = await fetch('https://mcp.cryptovault.co.uk/evaluate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});
const data = await res.json();
if (data.verdict === 'PASS') {
status.className = 'at-status success';
status.textContent =
`✓ Invoice verified (${data.score}/100). Payment released to your wallet automatically. ` +
`A copy of your invoice has been forwarded to the buyer's accounts team.`;
} else {
status.className = 'at-status fail';
status.textContent =
`Invoice could not be verified (${data.score}/100). Reason: ${data.summary}. ` +
`Please check the details and resubmit.`;
}
} catch (err) {
status.className = 'at-status error';
status.textContent = `Error: ${err.message}`;
}
}
</script>
Server-side only: the buyer form posts to /api/create-escrow on your own backend — this is intentional. Your wallet secret must never be in browser JavaScript. Your backend holds the secret, pays the protocol fee, signs the EscrowCreate on XRPL, and returns the escrow_id. The supplier form calls AgentTrust directly — no wallet secret needed.
The accounts_email is stored in the escrow spec. When the referee returns a PASS verdict it emails the verified invoice to that address. You can also handle this yourself via a webhook callback.
Works directly with your accounting software. Most accounting platforms accept invoices by email and create draft bills automatically — no manual data entry. Set accounts_email to your platform's bills inbox address:
Xero: yourorg@bills.xero.com (Settings → Invoice Settings → Email to Bills inbox)
QuickBooks Online: vendor receipts inbox (Settings → Receive invoices by email)
FreshBooks: your auto-billing import email (Accounting → Expenses → Import)
Sage: Sage Capture email address or Sage Accounting bills import
Zoho Books: vendor email import address (Settings → Email Preferences)
The verified invoice arrives pre-labelled with the PO reference, supplier name, and amount — your accounting system picks it up as a draft bill, already matched. No native API integration required.
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Optional
import httpx, secrets
from xrpl.clients import JsonRpcClient
from xrpl.models.transactions import Payment, EscrowCreate
from xrpl.wallet import Wallet
from xrpl.utils import xrp_to_drops
from xrpl.transaction import submit_and_wait
app = FastAPI()
REFEREE = "https://mcp.cryptovault.co.uk"
PROTOCOL_WALLET = "rmcSrkpZ2i2kuvtCPeTVetee9SixP4djR"
buyer_wallet = Wallet.from_seed("sYOUR_BUYER_SECRET") # server-side only
client = JsonRpcClient("https://s1.ripple.com:51234/")
class EscrowRequest(BaseModel):
po_number: str
supplier_name: str
supplier_wallet: str
amount_rlusd: float
task_description: str
accounts_email: str # verified invoices forwarded here
cancel_after_hrs: int = 720
callback_url: Optional[str] = None # optional webhook on PASS/FAIL
metadata: Optional[str] = None # JSON string — round-trip your ref IDs
@app.post("/api/create-escrow")
async def create_escrow(req: EscrowRequest):
# Embed accounts_email in the task spec so the referee knows where to forward
full_spec = (
req.task_description
+ f"\n\nAccounts email for verified invoices: {req.accounts_email}"
)
# 1. Pay protocol fee ($0.10 — XRP, RLUSD, or USDC)
fee_tx = Payment(account=buyer_wallet.address,
amount=xrp_to_drops(0.1),
destination=PROTOCOL_WALLET)
fee_hash = submit_and_wait(fee_tx, client, buyer_wallet).result["hash"]
# 2. Generate escrow parameters
escrow_id = f"INV-{secrets.token_hex(4).upper()}"
body = {
"escrow_id": escrow_id,
"fee_hash": fee_hash,
"buyer_name": "Your Company",
"buyer_address": buyer_wallet.address,
"worker_address": req.supplier_wallet,
"task_description": full_spec,
"currency": "RLUSD",
"amount_rlusd": req.amount_rlusd,
"cancel_after_hrs": req.cancel_after_hrs,
"category": "invoice",
"max_submissions": 5,
}
if req.callback_url:
body["buyer_callback_url"] = req.callback_url
if req.metadata:
body["metadata"] = req.metadata
params = httpx.post(f"{REFEREE}/escrow/generate", json=body, timeout=30).json()
# 3. Sign and submit EscrowCreate on XRPL
escrow_tx = EscrowCreate(
account = buyer_wallet.address,
destination = req.supplier_wallet,
amount = params["escrow_amount"], # RLUSD token dict
condition = params["condition"],
finish_after = params["finish_after_ripple"],
cancel_after = params["cancel_after_ripple"],
)
tx_hash = submit_and_wait(escrow_tx, client, buyer_wallet).result["hash"]
# 4. Confirm with referee (starts the clock)
httpx.post(f"{REFEREE}/escrow/{escrow_id}/confirm",
json={"tx_hash": tx_hash}).raise_for_status()
return {"escrow_id": escrow_id, "tx_hash": tx_hash}
const express = require('express');
const { Client, Wallet, xrpToDrops } = require('xrpl');
const fetch = require('node-fetch');
const crypto = require('crypto');
const app = express();
app.use(express.json());
const REFEREE = 'https://mcp.cryptovault.co.uk';
const PROTOCOL_WALLET = 'rmcSrkpZ2i2kuvtCPeTVetee9SixP4djR';
const BUYER_SECRET = process.env.BUYER_WALLET_SECRET; // never hardcode
app.post('/api/create-escrow', async (req, res) => {
const {
po_number, supplier_name, supplier_wallet,
amount_rlusd, task_description, accounts_email,
cancel_after_hrs = 720, callback_url, metadata,
} = req.body;
// Embed accounts_email so the referee knows where to forward verified invoices
const fullSpec = `${task_description}\n\nAccounts email for verified invoices: ${accounts_email}`;
const client = new Client('wss://s1.ripple.com');
await client.connect();
const wallet = Wallet.fromSeed(BUYER_SECRET);
// 1. Protocol fee
const feeTx = await client.submitAndWait({
TransactionType: 'Payment',
Account: wallet.address,
Destination: PROTOCOL_WALLET,
Amount: xrpToDrops('0.1'),
}, { wallet });
// 2. Generate escrow parameters
const escrowId = `INV-${crypto.randomBytes(4).toString('hex').toUpperCase()}`;
const body = {
escrow_id: escrowId, fee_hash: feeTx.result.hash,
buyer_name: 'Your Company', buyer_address: wallet.address,
worker_address: supplier_wallet, task_description: fullSpec,
currency: 'RLUSD', amount_rlusd, cancel_after_hrs,
category: 'invoice', max_submissions: 5,
};
if (callback_url) body.buyer_callback_url = callback_url;
if (metadata) body.metadata = metadata;
const params = await fetch(`${REFEREE}/escrow/generate`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
}).then(r => r.json());
// 3. Submit EscrowCreate
const escrowTx = await client.submitAndWait({
TransactionType: 'EscrowCreate',
Account: wallet.address,
Destination: supplier_wallet,
Amount: params.escrow_amount,
Condition: params.condition,
FinishAfter: params.finish_after_ripple,
CancelAfter: params.cancel_after_ripple,
}, { wallet });
// 4. Confirm with referee
await fetch(`${REFEREE}/escrow/${escrowId}/confirm`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ tx_hash: escrowTx.result.hash }),
});
await client.disconnect();
res.json({ escrow_id: escrowId, tx_hash: escrowTx.result.hash });
});
app.listen(3000);
For fully automated AP, both sides run code. The buyer side triggers on a delivery event; the supplier side triggers on an escrow-ready webhook. Each operates independently — neither needs to know the other's implementation.
Your warehouse management system, ERP, or delivery platform fires a webhook when a delivery is confirmed. This handler creates the escrow automatically and notifies the supplier — no human AP involvement.
from fastapi import FastAPI
from pydantic import BaseModel
import httpx, secrets, smtplib
from email.message import EmailMessage
from xrpl.clients import JsonRpcClient
from xrpl.models.transactions import Payment, EscrowCreate
from xrpl.wallet import Wallet
from xrpl.utils import xrp_to_drops
from xrpl.transaction import submit_and_wait
app = FastAPI()
REFEREE = "https://mcp.cryptovault.co.uk"
PROTOCOL_WALLET = "rmcSrkpZ2i2kuvtCPeTVetee9SixP4djR"
buyer_wallet = Wallet.from_seed("sYOUR_BUYER_SECRET")
client = JsonRpcClient("https://s1.ripple.com:51234/")
class DeliveryConfirmed(BaseModel):
"""Payload from your WMS/ERP when a delivery is confirmed."""
po_number: str
supplier_name: str
supplier_wallet: str
supplier_email: str # to notify the supplier
amount_rlusd: float
description: str
accounts_email: str = "accounts@yourcompany.com"
@app.post("/webhooks/delivery-confirmed")
async def on_delivery_confirmed(event: DeliveryConfirmed):
"""Triggered automatically when WMS marks a delivery as received."""
spec = (
f"Invoice Verification — {event.po_number}\n"
f"Supplier: {event.supplier_name}\n"
f"Amount: {event.amount_rlusd} RLUSD\n"
f"Services: {event.description}\n\n"
f"PAYMENT RELEASES when the invoice matches the above.\n"
f"Accounts email for verified invoices: {event.accounts_email}"
)
# 1. Protocol fee
fee_hash = submit_and_wait(
Payment(account=buyer_wallet.address,
amount=xrp_to_drops(0.1),
destination=PROTOCOL_WALLET),
client, buyer_wallet
).result["hash"]
# 2. Generate escrow
escrow_id = f"INV-{secrets.token_hex(4).upper()}"
params = httpx.post(f"{REFEREE}/escrow/generate", json={
"escrow_id": escrow_id,
"fee_hash": fee_hash,
"buyer_name": "Your Company",
"buyer_address": buyer_wallet.address,
"worker_address": event.supplier_wallet,
"task_description": spec,
"currency": "RLUSD",
"amount_rlusd": event.amount_rlusd,
"cancel_after_hrs": 720,
"category": "invoice",
"max_submissions": 5,
}, timeout=30).json()
# 3. Submit EscrowCreate
tx_hash = submit_and_wait(EscrowCreate(
account=buyer_wallet.address, destination=event.supplier_wallet,
amount=params["escrow_amount"], condition=params["condition"],
finish_after=params["finish_after_ripple"],
cancel_after=params["cancel_after_ripple"],
), client, buyer_wallet).result["hash"]
# 4. Confirm
httpx.post(f"{REFEREE}/escrow/{escrow_id}/confirm",
json={"tx_hash": tx_hash}).raise_for_status()
# 5. Email the supplier with their claim link
_send_supplier_email(event.supplier_email, event.supplier_name,
escrow_id, event.po_number, event.amount_rlusd)
return {"escrow_id": escrow_id}
def _send_supplier_email(to, name, escrow_id, po, amount):
msg = EmailMessage()
msg["Subject"] = f"Payment ready to claim — {po}"
msg["From"] = "noreply@yourcompany.com"
msg["To"] = to
msg.set_content(
f"Hi {name},\n\n"
f"Your payment of {amount} RLUSD for {po} is locked and ready to claim.\n\n"
f"Visit our supplier portal and enter your Escrow ID: {escrow_id}\n\n"
f"https://yourcompany.com/supplier-portal\n\n"
f"Submit your invoice and payment will be released automatically."
)
# Set SMTP_HOST, SMTP_USER, SMTP_PASSWORD in your environment before deploying
with smtplib.SMTP(os.getenv("SMTP_HOST", "smtp.yourcompany.com"), 587) as s:
s.starttls()
s.login(os.getenv("SMTP_USER"), os.getenv("SMTP_PASSWORD"))
s.send_message(msg)
The supplier's system listens for a webhook from AgentTrust when an escrow is created for their wallet. It auto-generates a conforming invoice and submits it immediately — no human involvement on the supplier side.
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Optional
import httpx
from datetime import date
app = FastAPI()
REFEREE = "https://mcp.cryptovault.co.uk"
class EscrowReadyWebhook(BaseModel):
"""Webhook payload from AgentTrust when an escrow is created for your wallet."""
escrow_id: str
amount_rlusd: Optional[float] = None
amount_xrp: Optional[float] = None
task_description: str
buyer_name: str
# AgentTrust calls this URL when an escrow targets your wallet address.
# Set buyer_callback_url on your side, or register a webhook in your profile.
@app.post("/webhooks/escrow-ready")
async def on_escrow_ready(event: EscrowReadyWebhook):
"""Auto-generate and submit a conforming invoice."""
amount = event.amount_rlusd or event.amount_xrp
currency = "RLUSD" if event.amount_rlusd else "XRP"
# Generate invoice from your own records (billing system, job data, etc.)
invoice_number = f"INV-{date.today().strftime('%Y%m%d')}-{event.escrow_id[-4:]}"
# Build the invoice text — must match the escrow task_description
invoice = _generate_invoice(invoice_number, event.buyer_name, amount, currency, event.task_description)
# Submit to AgentTrust — PASS releases payment automatically
result = httpx.post(f"{REFEREE}/evaluate", json={
"escrow_id": event.escrow_id,
"work": invoice,
}, timeout=120).json()
verdict = result.get("verdict")
score = result.get("score")
print(f"Escrow {event.escrow_id}: {verdict} ({score}/100)")
if verdict == "PASS":
print(f"Payment released. Invoice {invoice_number} accepted.")
else:
# FAIL — log the reason; could auto-correct and resubmit
print(f"Invoice rejected: {result.get('summary')}")
# Optional: alert a human, or adjust and resubmit
return {"status": verdict, "score": score}
def _generate_invoice(inv_num, buyer_name, amount, currency, task_desc):
"""Build a conforming invoice from your billing records."""
return "\n".join([
f"INVOICE {inv_num}",
f"Date: {date.today().isoformat()}",
f"From: Your Supplier Company Ltd",
f"To: {buyer_name}",
f"Amount: {amount} {currency}",
f"",
f"Services delivered:",
# Extract the key details from the task description to match exactly
task_desc.split("Services:")[1].split("\n")[0].strip()
if "Services:" in task_desc else task_desc[:200],
])
MCP shortcut: if your agent is MCP-compatible (Claude, GPT-4o with MCP, etc.), skip writing REST calls entirely. Connect the AgentTrust MCP server and instruct your agent: "Submit an invoice for escrow INV-XXXX for 500 RLUSD, delivered coffee to warehouse." It calls evaluate_escrow_work automatically.