v0.1 — Beta

What you'll build

By the end of this guide you will have:

  • A provisioned agent account on Solana with an associated USDC token account
  • A spending policy with sensible limits
  • An agent-scoped API key that can transfer USDC but cannot modify policy
  • A funded account ready to make direct transfers or pay MPP-enabled services via HTTP 402

Step 1 — Provision the account

Name your account after the agent's function. This name appears in the dashboard and in audit logs — make it meaningful.

typescript
import { MPPPal } from "@mpppal/sdk";

const client = new MPPPal({ apiKey: process.env.MPPPAL_OPERATOR_KEY });

const account = await client.accounts.create({
  name: "invoice-payment-agent-prod",
  metadata: {
    environment: "production",
    team: "payments",
    service: "billing-automation",
  },
});

console.log("Account ID:", account.account_id);
console.log("Fund this address with USDC:", account.usdc_token_account);

Step 2 — Set spending policy before funding

Set policy before you fund the account. An unfunded account with no policy is harmless. A funded account with no policy has no limits.

typescript
await client.policy.update(account.account_id, {
  max_single_transfer: 500,       // No single payment over $500
  max_daily_spend: 2000,          // $2,000/day cap
  categories: ["inference", "data"], // Only approved spend categories
  require_memo: true,             // Every transfer needs a reference
  paused: false,
});

console.log("Policy set. Account is ready to fund.");
Start restrictive. You can always relax limits later. It is much harder to claw back USDC that an agent sent to the wrong address because the daily limit was set too high.

Step 3 — Fund the account

Send USDC to the usdc_token_account address. This is a Solana SPL token account — fund it with USDC only. Do not send SOL.

Verify funding:

typescript
const { balance_usdc } = await client.accounts.getBalance(account.account_id);
console.log(`Balance: $${balance_usdc} USDC`);
// Balance: $500.000000 USDC

Step 4 — Issue an agent API key

Generate an agent-scoped key for this account. The agent will use this key — not your operator key — when making transfers or paying MPP services.

typescript
const { api_key } = await client.apiKeys.create({
  account_id: account.account_id,
  name: "invoice-payment-agent-prod-key",
});

// Store this key in your secrets manager — it will not be shown again
console.log("Agent key:", api_key);
// mpppal_agent_01j9m5p2q8rstu3vw...
Agent keys are shown once. Store the key in your secrets manager immediately. MPPPal does not store the plaintext key — if you lose it, you must rotate it.

Step 5 — Use the key in your agent

For direct transfers between agents:

typescript
// Your agent uses the agent-scoped key, not the operator key
const agentClient = new MPPPal({
  apiKey: process.env.MPPPAL_AGENT_KEY,
});

const transfer = await agentClient.transfers.create({
  from: process.env.MPPPAL_ACCOUNT_ID,
  to: "vendor-usdc-token-account-address",
  amount: "120.00",
  memo: "Invoice #1042 — Acme Corp",
  idempotency_key: `invoice-1042-${Date.now()}`,
});

console.log("Settled:", transfer.tx_signature);

For agents paying MPP-enabled services via HTTP 402:

typescript
const agent = new MPPPal.Agent({
  wallet: process.env.MPPPAL_ACCOUNT_ID,
  apiKey: process.env.MPPPAL_AGENT_KEY,
  intent: "session",
  sessionCap: "5.00",
});

const http = agent.createHttpClient();

// HTTP 402 payment challenges resolved automatically
const result = await http.post("https://api.someservice.xyz/inference", {
  body: JSON.stringify({ text: content }),
});

Checklist

  • Account provisioned and name is meaningful
  • Spending policy set before funding
  • Account funded with USDC (SPL token address, not SOL address)
  • Agent API key issued and stored in secrets manager
  • Agent uses agent-scoped key, not operator key
  • Webhook configured for transfer.rejected events so policy violations surface in your alerting