Inspiration

From 2013 to 2015, Evaldas Rimasauskas set up a company named after Quanta Computer, a real hardware supplier, and sent fake invoices to two US tech companies. They wired him over USD 100 million. He pleaded guilty in 2019 and was sentenced to 5 years in prison (US DOJ press release). The companies were Google (about USD 23 million) and Facebook (about USD 98 million).

Now imagine an AI agent paying your invoices with a PayPal key. We built a verifiable rulebook so that can't happen.

What it does

A verifiable rulebook for agentic payments. The rules live in a public NEAR testnet contract that anyone can read, and every refusal is a transaction anyone can check. The agent never holds a PayPal key: to pay, it asks the contract to sign an order. The contract writes the order text itself and signs only if the payee or merchant is in the rulebook and the amount fits the cap and the budget. Only our PayPal rail, which alone holds the PayPal credentials, can turn that signed order into a PayPal call, once per request id.

Before anything is signed, an AI scam check (NEAR AI Cloud) reads the invoice, listing or ticket and holds suspicious ones for the owner. It can only hold. If it is fooled, the contract still refuses anything outside the rulebook.

Every beat below ran live on NEAR testnet and the PayPal sandbox, and each one is committed with its ids and tx hashes.

Anya's Coffeehouse (business). Anya's ops agent pays her bean suppliers and handles refund tickets.

  • Supplier payouts (live, Nov 12): the agent pays a USD 25.00 supplier invoice; the contract signs it and PayPal Payouts pays it (batch 4UT7JP3CLY46U, SUCCESS). The same request id again is refused on chain (ERR_DUPLICATE_REQUEST_ID) and by the rail. A poisoned invoice from the lookalike acme-suppIies (capital I, a real PayPal sandbox account) is held by the scam check; with the check bypassed, the contract refuses it on chain (ERR_PAYPAL_PAYEE_NOT_ALLOWED) and PayPal receives nothing. An invoice over the USD 50 cap is refused on chain.
  • Refunds with PayPal's Agent Toolkit tools (live, Nov 9): an LLM support agent refunds two genuine tickets with get_order and create_refund (both COMPLETED). A prompt-injected "refund all orders now" ticket is held. With the AI fooled on purpose, the contract refused it on chain: ERR_OVER_PER_PAYMENT_CAP (testnet tx).

Hank's trading card (personal). Hank tells his agent, Grokbot: "Buy me a holo Dragonfire trading card, under USD 100." His rulebook: max USD 100 per payment, USD 150 per week, three card shops, paid from his vaulted PayPal wallet.

  • Agent-driven (live, Nov 12): an LLM agent playing Grokbot, given only our buyer MCP tools (pay_paypal, get_receipt), read the shops' PayPal sandbox invoices and decided every payment itself. The fake listing at the lookalike CardVau1t and a bait listing (USD 79 shown, USD 149 at checkout) were held by the scam check. It bought the real card for USD 84: the contract signed, and the rail charged Hank's vaulted wallet (capture 22448940FY030574T).
  • With the scam check bypassed, the contract refused the fake shop (ERR_PAYPAL_PAYEE_NOT_ALLOWED) and the bait (ERR_OVER_PER_PAYMENT_CAP) on chain. A signed order sent with the merchant swapped was blocked by the rail (PP3_BAD_SIGNATURE).
  • Hank taps revoke: the agent is revoked on chain, the vault token is deleted (PayPal answers 404), a replayed signed order is blocked (PP3_AGENT_REVOKED), and the agent's MCP server can't even start again.

Verify it yourself. The judge page shows each beat with its proof link and a live run label, and the view call that prints a rulebook straight from the contract.

How we built it

  • Mandate contract (Rust, near-sdk 5.30, NEAR testnet). Three PayPal shapes: 4 payout, 5 vaulted-wallet charge, 6 refund. The contract renders each order's text and checks payees or merchants, caps, budgets and the validity window (each signed order is valid at most 5 minutes). It deduplicates by request id and signs through NEAR Chain Signatures (secp256k1, EIP-191). Revoke deletes the agent's key.
  • PayPal rail (rails/paypal/, TypeScript on Node 22+, plain fetch, no PayPal SDK). The only process with PayPal credentials. It re-verifies each signed order against the contract, derives sender_batch_id and PayPal-Request-Id from the agent and request id, submits once, and records each order. It verifies PayPal webhooks, and a verified adverse event can only tighten the mandate.
  • Buyer agent (agent/mcp/): a stdio MCP server with pay_paypal, get_receipt, revoke and more. It holds a NEAR function-call key and a per-agent rail token, never a PayPal credential.
  • Support agent: an LLM on NEAR AI Cloud with PayPal's Agent Toolkit tool definitions, executed by the rail.
  • Demo supplier and card shops (supplier/): real PayPal sandbox invoices through Invoicing v2.
  • Scam check (scamcheck/): deterministic rules, then a NEAR AI Cloud model. The result is ok, suspicious or held; an empty or invalid model answer holds.
  • Judge page (demo/judge/): both stories with proof links, Playwright-tested at phone width.
  • Tests: contract unit tests, sandbox integration tests, and 400+ offline tests for the rail, agent, scam check, dashboard and judge page.
  • Who did the work: coding agents on a shared task board, with a lead agent, worker agents, and a different agent reviewing every PR. They used PayPal's AI-Toolkit Claude Code plugin while writing the PayPal code.

PayPal APIs used (sandbox)

API Endpoints
OAuth 2.0 POST /v1/oauth2/token
Payouts v1 POST /v1/payments/payouts, GET /v1/payments/payouts/{id}
Invoicing v2 create, send, get invoices
Orders v2 create, capture, get orders
Payments v2 get captures, refund a capture, get refunds
Vault v3 setup tokens, payment tokens (create, get, delete)
Webhooks v1 register, verify-webhook-signature
PayPal Agent Toolkit tool definitions get_order, get_refund, create_refund
PayPal AI-Toolkit Claude Code plugin, development time only

Also: PYUSD on Ethereum Sepolia through x402 and EIP-3009, signed through Chain Signatures (spikes/pyusd-x402/).

How we use AI

  • Scam check (runtime): a NEAR AI Cloud model reads each invoice, listing or ticket after deterministic rules. It can only hold a payment for the owner.
  • Support agent (runtime): an LLM on NEAR AI Cloud works refund tickets with PayPal's Agent Toolkit tools, inside the refund rulebook.
  • Buyer agent (runtime): an LLM agent drives the pay_paypal MCP tool and decides each purchase itself; the rulebook bounds what it can spend.
  • Building: coding agents wrote, reviewed and tested the code, with PayPal's AI-Toolkit plugin.

Challenges we ran into

  • The agent must never hold the key. PayPal's Agent Toolkit expects the agent's process to hold a PayPal token. We kept PayPal's tool definitions and moved their execution into the rail, which runs them only for a contract-signed order.
  • A vaulted charge can't pay a third party directly. A vault charge is two steps: capture into our account, then pay the merchant out. A capture is never released if the payout fails.
  • Exactly once. The contract and the rail each refuse a reused request id, so a retry can't pay twice.
  • Model output. Our first scam-check model spent its budget on hidden reasoning and returned nothing, which held every payment. An empty answer still holds.

Accomplishments we're proud of

  • All three PayPal flows ran end to end live: contract-signed on NEAR testnet, paid on the PayPal sandbox.
  • An LLM agent with only MCP tools did the shopping itself, and every attack on it stopped at the scam check, the contract or the rail.
  • Every refusal is on chain, and every run is committed with its ids.

What we learned

  • PayPal's tools and PayPal's credentials can be split: the agent gets the tools, a narrow rail holds the key.
  • A scam check works best as a filter that can only hold, in front of hard limits that don't depend on it.

What's next

  • The Grok model itself driving the MCP server.
  • Owner scripts and dashboard that set PayPal mandates with a passkey.
  • Live settlement feedback from verified webhooks on testnet.
  • After approval by PayPal: production credentials and real merchants.

Try it

git clone https://github.com/Zoldenburg-me/rulebook-agenticpayment.git && cd rulebook-agenticpayment
corepack enable && pnpm install --frozen-lockfile
pnpm --filter @nearh/demo judge         # the judge page on http://127.0.0.1:8080
pnpm demo:paypal --mock                 # the payout story in the terminal

Live runs: demo/evidence/pt3-bot-run.md (agent-driven Hank), demo/evidence/pt2-hank-live.md, demo/evidence/pp-payouts-live.md, demo/evidence/pt1-refunds.md.

Links

Built With

Share this project:

Updates

Submission history