MPP — Auto-pay sub-cent calls on Tempo
MPP (Multi-Provider Payments) is an HTTP authentication standard for agent-initiated payments. When a server requires payment for a resource, it returns a 401 Unauthorized with a WWW-Authenticate: Payment challenge that names a method (e.g. tempo), an intent (charge), and the price. The client signs a credential, retries with Authorization: Payment …, and the server verifies and serves the response.
Canopy supports MPP on Tempo today. Tempo's sub-cent fees and fast finality make it the natural rail for high-frequency agent calls — research feeds, embeddings, ranking, anything where x402's per-tx cost on Base is too coarse.
canopy.fetch() handles both x402 and MPP transparently. The same call works against either rail; the SDK picks the funded chain based on your treasury balance.
Calling an MPP-paywalled API
Same surface as x402 — your code never sees the 401:
import { Canopy } from "@canopy-ai/sdk";
const canopy = new Canopy({
apiKey: process.env.CANOPY_API_KEY!,
agentId: process.env.CANOPY_AGENT_ID!,
});
const res = await canopy.fetch("https://feed.example.tempo/depth/btc-usd");
const data = await res.json();res = canopy.fetch("https://feed.example.tempo/depth/btc-usd")
data = res.json()The agent's policy gates MPP charges the same way it gates x402 — caps, allowlists, approvals all apply. Outcomes (allowed / pending_approval / denied) are uniform across rails.
When MPP, when x402
| Question | Answer |
|---|---|
| Single call costs more than ~$0.10 | x402 on Base is fine — the per-tx fee is a small fraction of the call |
| Calls cost cents or sub-cent, made many times | MPP on Tempo — Tempo's fees keep the spread workable |
| You don't know in advance | Use canopy.discover() and check paymentMethods — it lists the rails each service supports |
| The provider only supports one | Whatever they support |
Treasury funding across rails
The treasury is one wallet, two chains. Canopy routes balance to the chain that needs to settle:
- Treasury starts with USDC on Base.
- When an MPP charge needs Tempo USDC.e and the Tempo balance is empty, Canopy bridges via Stargate / LayerZero and retries.
- Bridge events are recorded as
treasury_movements(separate from agent-attributedtransactions).
In the dashboard, the Treasury page surfaces both balances. In the SDK, canopy.discover() returns each service's preferredBaseUrl already biased toward the chain currently funded — so the agent doesn't have to think about it.
Discovering MPP services
const services = await canopy.discover({ category: "data" });
const mpp = services.filter((s) =>
s.paymentMethods.some((pm) => pm.protocol === "mpp")
);services = canopy.discover(category="data")
mpp = [s for s in services if any(pm["protocol"] == "mpp" for pm in s["payment_methods"])]Where to go next
- x402 — the EVM-native counterpart
- Payment outcomes — the same
allowed/pending_approval/deniedshape applies to MPP charges - Treasury — how the org wallet funds both rails