Why agent-to-agent payments are different
Paying a third-party API is straightforward: you make a request, it costs a fixed amount, done. Agent-to-agent payments introduce complexity that traditional payment infrastructure wasn't designed to handle:
- Dynamic pricing: Sub-agents may not know their fee until the task is complete (e.g., "charge per token consumed")
- Conditional settlement: The orchestrator may only want to pay if the output meets a quality threshold
- Concurrent execution: Multiple sub-agents running in parallel can trigger race conditions in naive payment implementations
- Retry safety: If a sub-agent crashes mid-task, the orchestrator needs idempotent payment semantics to avoid double-paying on retry
Proco was designed with these constraints in mind. The patterns below are what we've seen work in production multi-agent systems.
The invoice-on-completion pattern
Rather than pre-paying sub-agents, the cleanest approach is to have each sub-agent issue a payment request upon successful task completion. The orchestrator then validates the output and settles the invoice atomically.
(with taskId + budget ceiling)
Sub-Agent ── complete + invoice ──> Orchestrator
(taskId + result + amount)
Orchestrator ─── validate + settle ──> Proco
(one atomic operation)
The key properties of this pattern:
- The
taskIdis a nonce that makes settlement idempotent — paying the same invoice twice returns the first receipt, not two charges - The orchestrator validates output quality before calling
settle()— no payment for bad work - Budget ceilings are enforced at the protocol level — sub-agents can't invoice more than the ceiling, even if they try
Idempotency and the double-payment problem
In distributed systems, retries happen. A network timeout while calling settle() might cause your orchestrator to retry the payment call — potentially paying twice. Proco's settlement API is idempotent by design: if you call settle(invoiceId) twice with the same invoice ID, the second call returns the original receipt without charging again.
The invoiceId is the idempotency key. It's generated by the sub-agent when it completes the task and tied to the taskId you provided at dispatch time. As long as you use stable task IDs (not random UUIDs regenerated on retry), your payment flow is safe to retry at any point.
Rule of thumb: Generate task IDs deterministically from your task parameters rather than randomly. For example: taskId = hash(agentId + query + timestamp_rounded_to_hour). This way, retries within the same hour window are idempotent, while truly new tasks get fresh IDs.
Batch settlement for efficiency
If your orchestrator runs many small tasks — think 50 web scraping jobs per research request — settling invoices one by one adds latency and overhead. Use batchSettle() to settle multiple invoices in a single atomic transaction:
Handling failed sub-agents
If a sub-agent crashes before invoicing, your orchestrator's awaitInvoices() call will time out on that task. Use the timeout and fallback pattern to handle this gracefully:
The economics of agent networks
As multi-agent systems mature, we're starting to see emergent economic behaviors: orchestrators that shop around for the cheapest sub-agent offering a given service, sub-agents that adjust their rates based on demand, and reputation systems where consistently high-quality work commands a premium.
This is agent-native commerce. The infrastructure for it — wallets, spending policies, invoices, idempotent settlement, batch payments — needs to work at machine speed and machine scale. That's what Proco is built for.
What to read next
- Why Your AI Agent Needs Its Own Wallet — the identity and policy model underpinning this payment pattern
- LangChain + Proco — implement payment tools in a LangChain agent
- Orchestrator API reference — full docs for dispatch, awaitInvoices, and batchSettle