Shotoku
← Blog

x402 spend controls compared: Shotoku, AgentPay MCP, x402-cfo and PolicyLayer

· By the Shotoku team

Short answer: x402 defines how an agent pays for a request. A budget that spans many requests has to come from something else, and the check has to run after the 402 response and before the agent signs. Four tools do this in different ways:

How we did this.We build Shotoku, so read this with that in mind. We reviewed each project’s npm README on November 6, 2026 and ran Shotoku’s own example. We did not run the other three tools, so their columns describe what their documentation says, not behavior we tested.

How do the four tools compare?

ShotokuAgentPay MCPx402-cfoPolicyLayer SDK
What it isPolicy engine and ledger. Authorizes payments, never makes them.MCP server with wallet and payment toolsClient library around your x402 walletSDK around your wallet, with decisions from a hosted API
Version reviewedmain branch (npm: @shotoku/core 0.2.2)4.3.00.5.01.4.0
Last npm releaseAugust 2026October 2026March 2026January 2026
LicenseMITMITMIT, with paid hosted dashboard tiersMIT SDK. Needs a PolicyLayer API key.
Signing keyNever sees itLoaded into the server processStays in the wallet you pass inStays on your server, per its README
Where the decision runsYour machineYour machine, in the server processYour machine, in your processapi.policylayer.com
Spend limitsPer payment, per rule per day, per agent per daySpend policy in the process, plus optional on-chain limitsPer request, hourly, daily, sessionSet in PolicyLayer, plus optional client-side limits
Recipient rulesPin allowed payTo addresses per ruleNot covered in the READMEHost allowlist and blocklistAllowed and blocked recipients
Human approvalBuilt in: terminal, local dashboard, TelegramApproval queue. A real gate only if the owner key is separate from the agent key.None documented. Anomaly detection has a review mode.None documented in the SDK README
Payment recordHash-chained JSONL, checked against signed snapshotsOn-chain wallet events. x402 receipts are in memory, capped at 256.Ledger with JSON and CSV exportNone documented in the SDK README
After a restartLedger and budgets persistRolling policy state is clearedPersists with JsonFileStorageHeld by the service
x402 integrationYou call authorize, then signx402_pay toolagent.fetch() replaces fetchx402Client.pay()

Where should an x402 budget check run?

Between the 402 response and the signature. Before the 402, there is no amount to check. After the signature, the payment can settle. That gap is the only point where the agent knows the full cost and nothing irreversible has happened. All four tools work there. What differs is who can override the check and what is left afterward.

What should you check in any x402 spend control?

  1. Can the agent change its own limit?AgentPay’s README is direct about this: the same agent can call set_spend_policy again. Its on-chain limits avoid that, but only if the wallet owner sets them on the contract.
  2. Does spending history survive a restart? If rolling totals live in memory, a restart resets the budget. AgentPay documents this. x402-cfo fixes it with a storage adapter, so make sure you configure one.
  3. Is the human gate separate from the agent? An approval the agent can grant itself is not an approval. Check where the approval key or command lives.
  4. Does it trust the 402 body? The server asking to be paid writes that response. A hostile server can name an allowlisted vendor as the resource and put its own address in payTo. Ask which fields come from the server and which come from your own request.
  5. Can you prove the log later? A plain log can be edited without trace. A hash chain breaks if a past entry changes.

What does this look like in Shotoku?

This policy allows small payments to one API at one address, caps every agent at $5 a day, and sends everything else to a human:

policy.yaml
rules:
  - resource: api.weather.xyz
    recipients: ["0x000000000000000000000000000000000000dEaD"]
    actions: [purchase]
    verdict: approved
    maxAmount: 0.10
    maxDailyAmount: 1.00

defaultVerdict: pending_approval

budgets:
  - actor: "*"
    maxDailyAmount: 5.00

The check goes between the 402 and your signing code:

pay.ts
import { authorizeX402Payment, parseX402Response } from "@shotoku/core";

const requirements = parseX402Response(body, { requestUrl: url });
const decision = await authorizeX402Payment("agent-1", requirements, {
  policyPath: "./policy.yaml",
  ledgerPath: "./data/decisions.jsonl",
});

if (decision.approved) {
  return signPayment(requirements.option); // your wallet signs, not Shotoku
}
throw new Error(`Payment blocked: ${decision.status} [${decision.decisionId}]`);

We ran this policy against five simulated 402 responses, using USDC on Base:

402 responseResult
$0.05 from the allowed host to the allowed addressapproved
$0.50 from the allowed hostdenied: over the $0.10 limit
$0.05 from the allowed host to a different addresspending_approval
$0.05 from an unknown hostpending_approval
Unknown host claiming to be the allowed APIrejected before evaluation: resource and request host differ

Where does Shotoku fall short?

Which x402 spend control should you use?

If you needUse
The fastest setup, with budgets and analyticsx402-cfo
An agent wallet and payments in one MCP serverAgentPay MCP
Limits a compromised process can't changeAgentPay MCP with on-chain limits and a separate owner key
Human approval for anything outside policyShotoku
A record you can verify laterShotoku
The same policy across x402, PayPal and MCP toolsShotoku
No signing key in the tool that decidesShotoku or x402-cfo

These aren’t all exclusive. On-chain limits work as a hard ceiling underneath a local policy that decides each payment.

Common questions

Can a prompt enforce an x402 budget?

No. A prompt is an instruction the model can misread or ignore, and a prompt injection can override it. A budget has to be enforced by code outside the model.

Does a spend control need to hold my private key?

No. A decision only needs the amount, the recipient and the resource. Shotoku and x402-cfo leave signing to your wallet, and PolicyLayer says keys stay on your server. AgentPay loads the key because it is also the wallet.

What about AWS, Visa and Mastercard?

Platforms such as Amazon Bedrock AgentCore Payments are adding agent payments with their own limits. We left them out because this post covers tools you can add to an x402 client yourself.

Try it

Read the x402 guide or start with the quickstart. Shotoku is open source, deterministic, holds no funds and runs on your machine.

Sources

Related