v0.1 — Beta

Two payment patterns

MPPPal supports two distinct ways agents pay each other or external parties:

PatternWhen to useSettlement
MPP (HTTP 402)Agent calling a paid external service or APICharge: per-request on-chain. Session: batched.
Direct transferOrchestrator paying sub-agents for completed tasksImmediate 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.

typescript
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.

typescript
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}`);
Session efficiency. 200 inference calls with the Charge intent = 200 Solana transactions. The same 200 calls with the Session intent = 2 Solana transactions (open + settle). For high-frequency agents, sessions reduce on-chain costs by orders of magnitude.

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

typescript
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

typescript
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.

Post-beta: escrow. A formal escrow primitive is on the roadmap — funds held pending a quality check or condition, then released or returned. See the Roadmap.

Agentic freelance network pattern

An orchestrator that dynamically discovers and hires sub-agents by capability:

typescript
// 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.

text
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)