Skip to content

Agent-to-agent payments

The invoice protocol makes agent-to-agent payment a two-call operation. Agent A creates an invoice. Agent B pays it. Both sides are autonomous — no human approval, no shared credentials, no out-of-band coordination.

This is the clearest expression of what DPX is for.


Agent A Agent B
│ │
├─ POST /invoice ──────────────────► │ (invoiceId returned)
│ │
│ ◄── share invoiceId via any channel (message, webhook, shared state)
│ │
│ GET /invoice/{id}
│ │ (verify amount + description)
│ │
│ POST /invoice/{id}/pay
│ │
│ ◄── receipt (settlementId, txHash, aiDecision)

No wallet needed for Agent A. No API key needed for Agent B. The compliance screen and oracle gate run automatically at pay time.


If both agents are running with the DPX MCP server:

{
"mcpServers": {
"dpx": { "command": "npx", "args": ["-y", "@untitledfinancial/dpx-mcp"] }
}
}

Agent A:

Create an invoice for $5,000 USD payable to 0x... for data processing services rendered.

Agent B (receives the invoiceId):

Check invoice dpx-inv-abc123 and pay it if the amount and description look legitimate.

Terminal window
curl -X POST https://agent.untitledfinancial.com/invoice \
-H "Content-Type: application/json" \
-d '{
"amount": 5000,
"recipientAddress": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
"description": "Data processing services — batch job #2026-0042",
"currency": "USD"
}'

Response:

{
"invoiceId": "dpx-inv-abc123",
"amount": 5000,
"currency": "USD",
"description": "Data processing services — batch job #2026-0042",
"recipientAddress": "0xd8...",
"payUrl": "https://agent.untitledfinancial.com/invoice/dpx-inv-abc123/pay",
"status": "pending",
"expiresAt": "2026-07-25T20:00:00.000Z"
}
Terminal window
curl -X POST https://agent.untitledfinancial.com/invoice/dpx-inv-abc123/pay \
-H "Content-Type: application/json" \
-d '{
"payerAddress": "0x1234...",
"sandbox": true
}'

Response:

{
"settlementId": "dpx_abc123...",
"status": "sandbox",
"netAmount": 4917.5,
"aiDecision": "EXECUTE",
"aiConfidence": 0.96,
"txHash": null
}

import httpx
AGENT = "https://agent.untitledfinancial.com"
# Agent A: issue invoice
invoice = httpx.post(f"{AGENT}/invoice", json={
"amount": 5000,
"recipientAddress": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
"description": "Data processing services — batch job #2026-0042",
"currency": "USD",
}).json()
invoice_id = invoice["invoiceId"]
print(f"Invoice created: {invoice_id}")
# --- invoiceId passed to Agent B via any channel ---
# Agent B: verify and pay
details = httpx.get(f"{AGENT}/invoice/{invoice_id}").json()
print(f"Amount: ${details['amount']}{details['description']}")
receipt = httpx.post(f"{AGENT}/invoice/{invoice_id}/pay", json={
"payerAddress": "0x1234567890123456789012345678901234567890",
"sandbox": True,
}).json()
print(f"Paid: {receipt['settlementId']} decision={receipt['aiDecision']}")

When Agent B is a sub-agent operating under an orchestrator’s spend limit, add a policy check before paying:

import httpx
POLICY = "https://policy.untitledfinancial.com"
AGENT = "https://agent.untitledfinancial.com"
# Orchestrator created this policy; sub-agent received policy_id
policy_id = "pol-xyz789"
# 1. Check policy before paying
check = httpx.post(f"{POLICY}/policy/{policy_id}/check", json={
"amount": 5000,
"purpose": "vendor-invoice",
}).json()
if check["decision"] != "APPROVED":
print(f"Blocked by policy: {check['reason']}")
else:
# 2. Pay the invoice
receipt = httpx.post(f"{AGENT}/invoice/{invoice_id}/pay", json={
"payerAddress": "0x...",
"sandbox": True,
}).json()
# 3. Record against policy ledger
httpx.post(f"{POLICY}/policy/{policy_id}/record", json={
"amount": 5000,
"settlementId": receipt["settlementId"],
"purpose": "vendor-invoice",
})
print(f"Paid and recorded: {receipt['settlementId']}")

Agent B doesn’t need to run any checks manually. At POST /invoice/{id}/pay DPX runs:

CheckWhat it does
Oracle gateBlocks settlement if global conditions are UNSTABLE
AML screenSanctions + graph risk on both addresses
FATF R16Travel Rule compliance
ESG scoreAdjusts fee based on counterparty ESG score
AI decisionaiDecision: EXECUTE / HOLD / BLOCK with confidence + reasoning

Everything is in the receipt.