Pay for things safely from your agent — gasless USDC on Base plus JIT single-use virtual cards via the Z-Zero MCP server. Card data never enters the model context, and no payment executes without explicit human approval.
---
name: z-zero-payments
description: Pay for things safely from your agent — gasless USDC on Base plus JIT single-use virtual cards via the Z-Zero MCP server. Card data never enters the model context, and no payment executes without explicit human approval.
homepage: https://z-zero.xyz
user-invocable: true
metadata:
{
"openclaw":
{
"requires": { "bins": ["npx"], "env": ["Z_ZERO_API_KEY"] },
"primaryEnv": "Z_ZERO_API_KEY",
"emoji": "💳",
},
}
---
# Z-Zero Payments
Give this agent the ability to buy things — SaaS subscriptions, API credits, physical goods — without ever seeing a card number.
Z-Zero is a payment MCP server with two rails behind one interface:
- **Gasless USDC on Base** for crypto-native checkouts (sponsored by Coinbase Paymaster — the wallet holds only USDC, no ETH, no gas UX).
- **JIT single-use virtual cards** for the 99% of the web that only takes cards: issued for one amount, one merchant, 1-hour TTL, burned after a single use.
## The security model (read this first)
This skill is deliberately boring about money. Three properties are structural, not policy:
1. **The model never sees card data.** No PAN, no CVV, no expiry ever enters your context. You only ever handle single-use *tokens*; the real card details are injected into the merchant's checkout form by a local Playwright process and wiped from RAM. If you ever think you need a card number, you are off the rails — stop.
2. **Humans approve money movement.** Before any payment executes, call `request_human_approval` with the exact final total and wait for confirmation. A purchase your operator didn't approve is a failed purchase, even if the checkout would have succeeded.
3. **Blast radius is capped by design.** Tokens are amount-locked and merchant-locked. A prompt-injected or hallucinating agent holding a Z-Zero token can lose at most that token's amount — not a wallet, not a card limit.
4. **Keys rotate on connect (v1.5.0+).** Any Passport Key that was pasted into a conversation is treated as burned: on first connect the server swaps it for a fresh key stored only in `~/.z-zero/credentials` (0600) — the live key never exists in any LLM context. One key = one machine; all agents on the machine share it, and a connect from a different machine disconnects this one (built-in intrusion alarm).
## One-time setup
1. Your operator gets a Passport Key (starts with `zk_live_`) at **[z-zero.xyz/dashboard/agents](https://z-zero.xyz/dashboard/agents)** and funds the wallet by sending USDC on Base to the deposit address shown there.
2. Export it as `Z_ZERO_API_KEY` in the agent environment. (This is only a bootstrap: on first connect the key auto-rotates and the live key moves to `~/.z-zero/credentials` — the exported value goes stale by design.)
3. Register the MCP server (OpenClaw runs MCP via mcporter). Add to `~/.openclaw/openclaw.json`:
```json
{
"mcpServers": {
"z-zero": {
"command": "npx",
"args": ["-y", "z-zero-mcp-server@latest"],
"env": { "Z_ZERO_API_KEY": "${Z_ZERO_API_KEY}" }
}
}
}
```
4. Verify: list the server's tools (e.g. `mcporter list`). You should see 12 tools including `list_cards`, `auto_pay_checkout`, and `request_human_approval`, plus the `safe_checkout` prompt.
## Hard rules (non-negotiable)
- **Always read the SOP resource first** (`mcp://resources/sop`) before your first payment in a session. It is the authoritative flow; this skill is the summary.
- **Never call the REST endpoint `/api/tokens/resolve`.** It exists for the server-side injection process only. An agent calling it defeats the entire security model.
- **Never proceed past a missing approval.** No `request_human_approval` confirmation → no payment. Do not interpret silence as consent.
- **Respect the budget.** If the operator set a cap and the final total (including shipping) exceeds it, abort and report — do not negotiate with yourself.
- **Report honestly.** "Filled the form" is not "paid". Read the result `status` and relay it verbatim, including failures.
- **Prove, don't claim.** A confirmed payment returns a signed receipt with a public `verify_url`. Give it to the operator instead of asserting from memory that the order went through.
## Buying something (the flow)
1. Read `mcp://resources/sop` (once per session).
2. `get_merchant_hints` for the target platform (Shopify, Etsy, WooCommerce…) and follow its `pre_steps`.
3. Navigate the checkout until the **final total including shipping** is visible.
4. **Compare the page with what was actually asked for** — same items, quantity, variant, destination. If anything differs, stop here: no token has been issued, so a mismatch caught now costs nothing.
5. `request_human_approval` with item, merchant, and exact total. Wait.
6. On approval: `auto_pay_checkout` (it auto-detects crypto vs card checkout and routes — an EIP-681 crypto checkout settles as a gasless USDC transfer on Base; a card checkout uses a JIT single-use virtual card). For the manual path, pass `cart` and `ship_to` to `request_payment_token` so the card is bound to a **signed intent** — proof of what it was authorized to buy, not just how much it could spend.
7. Relay the result status and the receipt: `signed_receipt.diff` shows what the merchant actually did versus what was authorized (charged more, swapped an item). `verify_receipt(receipt_id)` re-checks it any time.
8. If a checkout failed for a *technical* reason, call `report_checkout_fail(url, failure_class, step, error_message)`. `failure_class` is a fixed enum — `card_declined_issuer`, `card_declined_bin_block`, `avs_mismatch`, `3ds_required`, `bot_detected`, `form_changed`, `price_changed`, `out_of_stock`, `shipping_unsupported`, `login_required`, `timeout`, `outcome_unconfirmed`, `intent_mismatch`, `unknown` — so each failure becomes evidence the next agent can use, not a log line.
## Wallet operations (read-only, no approval needed)
- `list_cards` — card aliases and balances
- `check_balance` — spendable USD for an alias
- `get_deposit_addresses` — the Base USDC deposit address for top-ups
## Troubleshooting
- `Z_ZERO_API_KEY is missing` → key not exported or agent not restarted after config change.
- `401 Invalid API Key` → key truncated on copy; re-copy the full `zk_live_…` value.
- Cloudflare-protected merchants may block the headless browser → tell the operator instead of retrying blindly.
## Links
- Source: [github.com/Dempty-glitch/Z-Zero-mcp](https://github.com/Dempty-glitch/Z-Zero-mcp) (MIT)
- npm: [`z-zero-mcp-server`](https://www.npmjs.com/package/z-zero-mcp-server)
- Official MCP Registry: `io.github.Dempty-glitch/z-zero-mcp`
- Proof of a real gasless USDC transfer on Base mainnet: [`0xdfd1f2f8…5d7a`](https://basescan.org/tx/0xdfd1f2f824e1232c3e03c52485332570ff01fbb0340c5571f699ed1218735d7a)
don't have the plugin yet? install it then click "run inline in claude" again.
extracted and formalized implicit security model, decision logic, edge cases (auth expiry, key rotation, budget caps, timeout handling, receipt mismatches), and wallet operations; added explicit output contracts and outcome signals; clarified hard rules as non-negotiable decision branches; mapped all MCP tools to procedure steps.
enable agents to purchase items (SaaS subscriptions, API credits, physical goods) without ever handling card data. z-zero routes payments through two rails: gasless USDC on Base (sponsored by Coinbase Paymaster, no ETH or gas UX) for crypto-native checkouts, and just-in-time single-use virtual cards (one amount, one merchant, 1-hour TTL, auto-burned) for traditional web merchants. the model context never sees PAN, CVV, or expiry; only single-use tokens are handled. every payment requires explicit human approval before execution, and token blast radius is capped by amount and merchant lock. use this skill when an agent needs to buy something and the operator wants full transparency, control, and zero card data leakage.
environment variables:
Z_ZERO_API_KEY (required): Passport Key starting with zk_live_. obtained from z-zero.xyz/dashboard/agents. bootstrap value only; auto-rotates on first connect and moves to ~/.z-zero/credentials (mode 0600). if you paste the key into a conversation, it's considered burned and will be replaced on next server connect.setup requirements:
npx binary available in PATH.~/.openclaw/openclaw.json under mcpServers.z-zero:{
"mcpServers": {
"z-zero": {
"command": "npx",
"args": ["-y", "z-zero-mcp-server@latest"],
"env": { "Z_ZERO_API_KEY": "${Z_ZERO_API_KEY}" }
}
}
}
external MCP resources:
mcp://resources/sop: authoritative payment flow SOP. must be read once per session before any payment.operator context:
bootstrap session: call mcp://resources/sop resource and read the full SOP once. this is the authoritative flow; do not deviate.
gather merchant hints: call get_merchant_hints with the target checkout platform name (e.g. "Shopify", "Etsy", "WooCommerce"). receive structured pre_steps (login flow, form IDs, variant selectors, known blocker patterns).
execute pre-steps: follow the merchant's pre_steps exactly (login, add to cart, navigate to checkout page). do not skip or reorder these steps.
reach final checkout page: navigate until the final total (subtotal + tax + shipping) is visible and unambiguous on the page. pause here.
audit cart vs. intent: compare the live checkout page item-by-item with what the operator originally asked for: same SKU, same quantity, same variant, same ship-to address. if any detail differs, stop immediately. no token issued yet, so a mismatch caught here costs nothing.
request human approval: call request_human_approval with exact parameters: merchant name, item description, quantity, unit price, shipping cost (or "calculated at checkout"), tax (if visible), final total, and destination. include a short URL or screenshot of the cart if possible. wait for operator confirmation. do not proceed without explicit approval or a confirmation message from the operator.
execute payment: on approval, call auto_pay_checkout. the server auto-detects checkout type (EIP-681 crypto link vs. card form) and routes accordingly. for crypto checkouts, it settles as a gasless USDC transfer on Base; for card checkouts, it issues a JIT virtual card bound to a signed intent (proof of what was authorized). do not call any endpoint directly; use auto_pay_checkout only.
verify and relay result: receive response with status (e.g. "completed", "declined", "timeout", "form_changed"). read signed_receipt field. call verify_receipt(receipt_id) to re-confirm. relay to operator: the exact status, merchant's verify_url (if present), and any differences in signed_receipt.diff (e.g. "charged $5 more than authorized", "item quantity changed"). do not assert from memory; quote the signed receipt.
handle technical failures: if checkout failed for a technical reason (not operator cancellation), call report_checkout_fail(url, failure_class, step, error_message). failure_class must be one of: card_declined_issuer, card_declined_bin_block, avs_mismatch, 3ds_required, bot_detected, form_changed, price_changed, out_of_stock, shipping_unsupported, login_required, timeout, outcome_unconfirmed, intent_mismatch, unknown. this feeds evidence for the next agent.
wallet operations (optional): for read-only balance checks between payments, call list_cards (aliases and balances), check_balance(alias) (spendable USD), or get_deposit_addresses (Base USDC deposit address). these require no approval.
if Z_ZERO_API_KEY is missing or empty: abort with error message. do not guess or fabricate a key. operator must export Z_ZERO_API_KEY and restart the agent.
if MCP server does not register (e.g., mcporter list shows no z-zero tools): abort with setup instructions. do not attempt to call tools that don't exist.
if get_merchant_hints returns an unknown or unsupported platform: proceed with generic checkout steps, but inform operator that merchant-specific logic is unavailable and checkout may require manual fallback (e.g. Cloudflare blocks headless browser, or form structure is non-standard).
if cart audit (step 5) detects a mismatch: stop immediately. do not request approval. inform operator of the discrepancy (e.g. "you asked for 2x item A, but cart shows 1x item A and 1x item B") and ask them to fix and restart.
if request_human_approval receives no response within a reasonable timeout (e.g., 5 minutes) or operator explicitly declines: abort payment. do not call auto_pay_checkout. do not interpret silence, delays, or vague responses ("sounds good") as confirmation. confirmation must be explicit and unambiguous.
if operator budget cap is set and final total (including shipping and tax) exceeds it: abort payment. do not request approval. report the overage to operator. do not attempt to negotiate (e.g. removing items) without explicit re-request from operator.
if auto_pay_checkout returns status declined with failure_class like card_declined_issuer or 3ds_required: inform operator of the specific failure. do not retry automatically. operator may choose to retry, use a different payment method, or cancel.
if auto_pay_checkout returns outcome_unconfirmed or timeout: call verify_receipt(receipt_id) to check if the charge actually went through (sometimes the response is lost but the merchant processed it). relay the verification result, not a guess.
if /api/tokens/resolve endpoint exists and you think you need to call it: do not. this endpoint is for server-side token injection only. calling it defeats the security model. if you think you need raw card data, you are off the rails; stop and report to operator.
if merchant is Cloudflare-protected and checkout fails with bot_detected: inform operator instead of retrying. headless Playwright cannot easily bypass Cloudflare; operator may need to manually complete the purchase or use a different merchant.
if signed_receipt.diff shows a mismatch (e.g. charged $5 more than authorized): relay the diff verbatim to operator. this is evidence of potential fraud or misconfiguration. do not assume it's okay.
successful payment flow returns:
status: "completed" (string).signed_receipt: object containing:receipt_id: unique identifier for this transaction.merchant: name of merchant.amount_charged_usd: final amount charged (number, in USD).payment_method: "usdc_base" or "virtual_card" (string).timestamp: ISO 8601 UTC timestamp.verify_url: public URL where operator can verify the transaction with the merchant.diff: object with any discrepancies vs. authorization (e.g. {"charged_amount_vs_authorized": "+5.00", "item_qty_vs_authorized": "changed"}, or empty {} if match).proof: for USDC transfers, includes Base mainnet transaction hash; for card, includes last 4 of virtual card and issuer confirmation.failed payment returns:
status: "declined" | "timeout" | "form_changed" | "outcome_unconfirmed" | (other failure_class enum).failure_reason: human-readable reason.failure_class: one of the fixed enums (card_declined_issuer, bot_detected, etc.).retry_eligible: boolean (true if operator can safely retry; false if permanent).wallet read operations return:
list_cards: array of objects with alias, balance_usd, card_type ("virtual" or "stored"), created_at.check_balance: object with alias, balance_usd, currency ("USD").get_deposit_addresses: object with base_usdc_address (string, 0x...), network ("base"), qr_code_url (optional).human approval request does NOT return until operator confirms or declines. operator confirmation is a synchronous message, not a background event.
receipt verification via verify_receipt(receipt_id) returns:
verified: boolean (true if receipt is cryptographically valid and merchant confirms the charge).current_status: current status of the transaction at the merchant (e.g. "completed", "refunded", "chargebacked").amount_confirmed_usd: merchant-confirmed amount.proof_link: merchant's order tracking or confirmation link.payment succeeded when:
auto_pay_checkout returns status: "completed".signed_receipt is present and contains a valid receipt_id and verify_url.verify_receipt(receipt_id) returns verified: true.verify_url).payment failed when:
auto_pay_checkout returns any status other than "completed".verify_receipt returns verified: false or a mismatch in current_status.for wallet operations:
check_balance returns a balance_usd value and operator sees it matches their expected funding.get_deposit_addresses returns a valid Base mainnet address (0x...) and operator can copy it for USDC transfer.operator knows it worked when:
verify_url from the signed receipt and the merchant confirms the charge.credits: original skill by z-zero team (github.com/Dempty-glitch/Z-Zero-mcp, MIT license). enriched per Implexa quality standards.