Agent-to-Agent Payments
Two patterns for agent payments: MPP for paying external services via HTTP 402, and direct transfers for settling value between agents in a multi-agent system.
Two payment patterns
MPPPal supports two distinct ways agents pay each other or external parties:
| Pattern | When to use | Settlement |
|---|---|---|
| MPP (HTTP 402) | Agent calling a paid external service or API | Charge: per-request on-chain. Session: batched. |
| Direct transfer | Orchestrator paying sub-agents for completed tasks | Immediate on-chain USDC transfer |
Pattern 1: MPP payments to external services
When your agent needs to call a paid API endpoint — an inference provider, a data feed, a search service — the service responds with an HTTP 402 and a payment challenge. MPPPal resolves it automatically.
Charge intent (per-request)
Each request triggers an independent on-chain settlement. Use for low-frequency or high-value calls where you want per-request auditability.
import { MPPPal } from "@mpppal/sdk";
const agent = new MPPPal.Agent({
wallet: process.env.MPPPAL_WALLET_ID,
apiKey: process.env.MPPPAL_AGENT_KEY,
intent: "charge",
});
const http = agent.createHttpClient();
// 402 challenge resolved automatically — agent pays and retries
const result = await http.post("https://api.inference.xyz/summarize", {
body: JSON.stringify({ text: documentContent }),
});
Session intent (batch settlement)
Pre-authorize a spending cap for a provider. Micropayments are streamed off-chain during the session. A single Solana transaction settles the net amount when the session closes. Use for high-frequency calls to the same provider.
const agent = new MPPPal.Agent({
wallet: process.env.MPPPAL_WALLET_ID,
apiKey: process.env.MPPPAL_AGENT_KEY,
intent: "session",
sessionCap: "10.00", // lock up to $10 USDC in escrow
});
const http = agent.createHttpClient();
// 200 inference calls → 0 on-chain txs during the session
for (const doc of documents) {
results.push(await http.post("https://api.inference.xyz/summarize", { body: JSON.stringify({ text: doc }) }));
}
// Close session → 1 on-chain settlement tx
const receipt = await agent.closeSession();
console.log(`Settled $${receipt.settled_usdc} USDC. Tx: ${receipt.tx_signature}`);
Pattern 2: Direct transfers between agents
A common multi-agent architecture has one orchestrator delegating tasks to specialized sub-agents and paying them upon completion. Each agent has its own MPPPal account. When the sub-agent finishes, the orchestrator calls POST /v1/transfers — peer-to-peer USDC, settled on Solana, no human in the loop.
Setup: provisioning two accounts
const client = new MPPPal({ apiKey: process.env.MPPPAL_OPERATOR_KEY });
// Orchestrator — funded, can send
const orchestrator = await client.accounts.create({
name: "orchestrator-prod"
});
await client.policy.update(orchestrator.account_id, {
max_single_transfer: 100,
max_daily_spend: 1000,
categories: ["agent-reward"],
require_memo: true,
});
// Sub-agent — receives payments, no spending policy needed
const subAgent = await client.accounts.create({
name: "research-sub-agent-prod"
});
console.log("Sub-agent receives USDC at:", subAgent.usdc_token_account);
Paying a sub-agent on task completion
async function payForCompletedTask(taskId: string, agentAccountId: string, amount: string) {
const transfer = await orchestratorClient.transfers.create({
from: process.env.ORCHESTRATOR_ACCOUNT_ID,
to: agentAccountId, // MPPPal account_id or raw SPL address
amount,
memo: `Task reward: ${taskId}`,
idempotency_key: `task-reward-${taskId}`, // deterministic — safe to retry
});
if (transfer.status === "settled") {
console.log(`Paid $${amount} USDC for task ${taskId}. Tx: ${transfer.tx_signature}`);
}
return transfer;
}
// In your orchestrator's task loop:
const result = await subAgent.executeResearchTask("Summarize earnings calls Q3");
if (result.completed) {
await payForCompletedTask("task-88", result.agentAccountId, "35.00");
}
Trust between agents
MPPPal handles settlement, not negotiation or quality verification. If a sub-agent returns bad work, the orchestrator must handle that at the application layer — there is no built-in dispute mechanism. The current model is optimistic: pay on completion, recover out-of-band if needed.
Agentic freelance network pattern
An orchestrator that dynamically discovers and hires sub-agents by capability:
// Sub-agents register their MPPPal account IDs with a service registry
const subAgentRegistry: Record<string, string> = {
"research": "acct_03x1m7p9k2qrst4ab",
"code-review": "acct_04y2n8q0l3rsuv5cd",
"data-labeling": "acct_05z3o9r1m4stvw6ef",
};
async function hireAndPay(taskType: string, taskId: string, budget: string) {
const agentAccountId = subAgentRegistry[taskType];
// Dispatch task (your application logic)
const result = await dispatchTask(taskType, taskId);
if (!result.completed) throw new Error(`Task ${taskId} did not complete`);
// Settle on MPPPal
return orchestratorClient.transfers.create({
from: process.env.ORCHESTRATOR_ACCOUNT_ID,
to: agentAccountId,
amount: budget,
memo: `${taskType} task ${taskId}`,
idempotency_key: `${taskType}-${taskId}`,
});
}
Combining both patterns
Most production multi-agent systems use both patterns simultaneously: sub-agents pay external MPP services (via HTTP 402) to complete their tasks, and the orchestrator pays sub-agents (via direct transfer) for the completed work. Each layer is settled separately on-chain.
Orchestrator
│ direct transfer → sub-agent (task reward)
▼
Sub-agent
│ MPP session → inference API (pays per inference call, batched on-chain)
│ MPP charge → data provider (pays per query, per on-chain tx)
▼
External Services (MPP-native)