← All guides
Agent payments · Zambo

Human-approved x402 Day Pass payments for agents

Zambo x402 returns a machine-readable HTTP 402 challenge for the $0.99, 24-hour USDC-on-Base Day Pass. A challenge is a payment request, not consent. Get explicit human approval for the exact amount before invoking any client that can sign and retry automatically. The Day Pass is time-based, not per-call.

Try the Zambo demo · Explore Zambo

How Zambo does it

Zambo publishes its payment contract at /.well-known/x402. Request GET /api/x402/day-pass without payment to receive the live x402 challenge for $0.99 USDC on Base. Only after human approval, use an official client to sign the EIP-3009 authorization and retry POST /api/x402/day-pass. The server verifies settlement before activating the 24-hour pass. The separate discovery resource is available at GET /api/x402/discovery.

Official TypeScript client

Verified package versions on October 4, 2026: @x402/core, @x402/fetch, and @x402/evm 2.28.0. The client automatically handles the challenge after you invoke it. The example requires a person to type an exact approval phrase, then enforces the Base USDC asset and 0.99 USDC amount in the x402 hook. This submits a real payment on Base; do not run it without the person's approval. Keep the wallet key in a secret store.

npm install @x402/core@2.28.0 @x402/fetch@2.28.0 @x402/evm@2.28.0 viem

import { wrapFetchWithPayment, x402HTTPClient } from "@x402/fetch";
import { x402Client } from "@x402/core/client";
import { ExactEvmScheme } from "@x402/evm/exact/client";
import { privateKeyToAccount } from "viem/accounts";
import { createInterface } from "node:readline/promises";

const key = process.env.EVM_PRIVATE_KEY;
if (!key || !/^0x[a-fA-F0-9]{64}$/.test(key)) throw new Error("Load the wallet key from a secret store.");
const signer = privateKeyToAccount(key as \`0x${string}\`);
const approvalInput = createInterface({ input: process.stdin, output: process.stdout });
const approval = await approvalInput.question('Type PAY $0.99 to approve one Day Pass payment: ');
approvalInput.close();
if (approval !== "PAY $0.99") throw new Error("Payment not approved.");

const client = new x402Client();
client.register("eip155:8453", new ExactEvmScheme(signer));
client.onBeforePaymentCreation(async ({ selectedRequirements }) => {
  const correctUsdc = selectedRequirements.asset.toLowerCase() === "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913";
  if (selectedRequirements.network !== "eip155:8453" || !correctUsdc || String(selectedRequirements.amount) !== "990000") {
    return { abort: true, reason: "Only the approved 0.99 USDC Base Day Pass is allowed." };
  }
});
const fetchWithPayment = wrapFetchWithPayment(fetch, client);
const httpClient = new x402HTTPClient(client);
const response = await fetchWithPayment("https://zambo.dev/api/x402/day-pass", { method: "POST" });
const result = await httpClient.processResponse(response);

if (result.paymentStatus !== "settled" || !response.ok) {
  console.error("Payment or activation was refused; inspect the refusal receipt and do not retry blindly.");
  process.exitCode = 1;
} else {
  const payload = result.body && typeof result.body === "object" ? result.body as Record<string, unknown> : {};
  const accessKey = payload.access_key;
  if (typeof accessKey !== "string" || !accessKey) throw new Error("Activation did not return a key.");
  // Keep accessKey in memory or a secret store. Never print it or put it in a URL.
}

Official Python client

The official PyPI package was x402 2.25.0 when checked on October 4, 2026. Its HTTP wrapper handles the challenge and retry. This submits a real payment on Base; do not run it without the person's approval. The example asks for typed confirmation, then checks the exact asset, network, and amount in the official client hook.

pip install "x402[httpx,evm]==2.25.0"

import argparse
import asyncio
import os
from eth_account import Account
from x402 import AbortResult, x402Client
from x402.http.clients import x402HttpxClient
from x402.mechanisms.evm import EthAccountSigner
from x402.mechanisms.evm.exact.register import register_exact_evm_client

async def main():
    approval = input("Type PAY $0.99 to approve one Day Pass payment: ")
    if approval != "PAY $0.99":
        raise SystemExit("Payment not approved.")

    client = x402Client()
    account = Account.from_key(os.environ["EVM_PRIVATE_KEY"])
    register_exact_evm_client(client, EthAccountSigner(account))
    async def enforce_approved_payment(context):
        requirements = context.selected_requirements
        correct_usdc = requirements.asset.lower() == "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913"
        if requirements.network != "eip155:8453" or not correct_usdc or int(requirements.amount) != 990000:
            return AbortResult(reason="Only the approved 0.99 USDC Base Day Pass is allowed.")
    client.on_before_payment_creation(enforce_approved_payment)
    async with x402HttpxClient(client) as http:
        response = await http.post("https://zambo.dev/api/x402/day-pass")
        await response.aread()
        if response.status_code != 200:
            print("Payment or activation was refused; inspect the refusal receipt and do not retry blindly.")
            return
        result = response.json()
        access_key = result.get("access_key")
        if not isinstance(access_key, str) or not access_key:
            raise RuntimeError("Activation did not return a key.")
        # Keep access_key in memory or a secret store. Never print it or put it in a URL.

asyncio.run(main())

Human Pay $0.99 with PayPal. checkout from chat

Ask the person whether they want a PayPal checkout link. Only after they explicitly agree, call day_pass_checkout_link with human_approved=true. The 30-minute URL creates no order or charge; the person must open it and approve payment. Then check with day_pass_status in the same MCP session. Status exposes activation and expiry, never the raw access key. Do not send an agent to the human checkout page.

Spend receipt after settlement

After confirmed settlement, the success response returns spend_receipt next to the 24-hour activation. It contains the exact challenged resource, chain, asset, payTo, and maxAmount; a recomputable signedPayloadHash; the actual on-chain settlementId; the activation expiry; and an auditUrl that resolves to a public HTML page showing the receipt. The receipt does not expose the bearer access_key; keep that capability value with the retrying agent.

To verify a retry without relying on chat history, compare the receipt fields with the original 402 challenge, inspect settlementId on Base, confirm expiry is the returned 24-hour pass boundary, and open auditUrl. The JSON projection is also available at /api/x402/spend-receipt/<receiptId>.

When a payment is refused

A payment attempt with an X-Payment header that cannot be accepted returns HTTP 402 with a top-level refusal receipt and a fresh challenge. The receipt is verifiable at verifier_url and contains an attempt_hash, not the raw payment payload. Correct the request only when retryable is true; stop when it is false.

The fixed policy_reason enum is malformed_payload, wrong_amount, wrong_asset, wrong_network, challenge_expired, duplicate_payment, or policy_blocked. quoted_max_amount and settlement_window come from the live challenge response.

{
  "receipt_id": "<UUID>",
  "type": "refusal",
  "policy_reason": "<enum value>",
  "retryable": true,
  "quoted_max_amount": "<challenge.accepts[0].amount>",
  "settlement_window": {"opens_at": "<ISO timestamp>", "closes_at": "<ISO timestamp>"},
  "verifier_url": "https://zambo.dev/api/x402/refusal-receipt/<UUID>/audit",
  "attempt_hash": "sha256:<canonical submitted payload hash>"
}

Human checkout from an MCP chat

If the person prefers Pay $0.99 with PayPal. , ask first. After they explicitly agree, call day_pass_checkout_link with human_approved=true. The 30-minute link creates no order or charge; the person must open the link and approve payment. Check status with day_pass_status in that same MCP session. It returns activation status and expiry, never the raw access key. Do not send an agent to the human checkout page.

Retrying a gated MCP call

A quota response is a real HTTP 402, not a successful tool result. Keep the returned request_id, payment challenge, session ID, and original arguments together. After access is verified, retry the same tool with the same arguments and session ID. If activation returns an opaque capability key, send it in the X-Zambo-Key header; MCP clients that cannot add headers may send it as the protocol argument _zambo_key. An email address is a receipt or activation lookup value, not proof of ownership by itself.

Recovery checklist
  1. Confirm the payment settled or the Day Pass status is active.
  2. Preserve the exact job/session and do not start a duplicate request.
  3. Retry with X-Zambo-Key: <access_key> or _zambo_key.
  4. Expect a receipt after the verified retry. If the payment settled but access is still unavailable, email brennanzambo@zambo.dev with the request ID and transaction hash - never send a private key, seed phrase, password, or card number.
Connect the MCP endpoint
{"mcpServers":{"zambo":{"url":"https://zambo.dev/mcp"}}}
https://zambo.dev/mcp

FAQ

What is x402?

x402 is a payment convention built around HTTP 402. The server explains the exact payment needed, and the client retries after payment.

Which chain?

Base, using USDC.

How much is a day pass?

$0.99 USDC for 24 hours.

Do I need an account?

No account is required. The x402 route uses a signed EIP-3009 authorization, but an agent must get explicit human approval before invoking an auto-paying client. Pay $0.99 with PayPal. checkout is a separate human-only flow.

Further reading

Framework integration tutorials: LangChain verifiable receipt integration and CrewAI verifiable receipt integration.

Read the install guide → · Read the cross-AI continuity guide →

What the HTTP 402 challenge means

An HTTP 402 response is a request for payment, not a successful tool result. Treat it as a structured pause in the workflow. The client should preserve the original method, URL, request body, session reference, and arguments before deciding whether to pay. It should then read the current challenge rather than relying on a copied amount or an old example. A challenge can state the asset, network, destination, amount, resource, and validity window. Those fields define what the payer is being asked to authorize.

The challenge and the later execution are separate records. Payment authorizes access to a resource for a stated period. It does not prove that a later call returned a correct answer or that an outside system accepted an action. Keep the payment reference, access expiry, request reference, and execution receipt linked in your own audit record. This separation makes a dispute easier to investigate because it shows whether the problem was a payment, entitlement, request, or result problem.

Before signing any authorization

A wallet agent should apply local checks before it signs. Confirm that the resource is the endpoint the workflow intended to call. Compare the requested amount with the current challenge and reject an amount above the configured spending limit. Confirm the chain identifier and token contract, then check that the destination is the expected service destination. Check the validity window and nonce rules. If any field is missing, surprising, or inconsistent with the task, stop and request a fresh challenge.

Do not treat a displayed label as enough evidence of what will be paid. The signed authorization has structured fields, and the wallet or signing library should show the values that matter. A spending policy can allow a small day pass while rejecting an unbounded amount, an unknown destination, or a long validity interval. The policy should also limit which resources the agent may pay for. An agent that can pay should still be constrained by an owner-defined budget and an explicit recovery path.

Safe retry behavior

Retry the same request only after the payment response confirms that the entitlement is active. Preserve the original arguments and session identifier so the retry does not accidentally become a new task. A client should make duplicate handling explicit. If a request timed out after submission, first query the payment or entitlement status before sending another authorization. A second payment can create an avoidable charge even when the first payment eventually settles.

Use a bounded retry count for transport errors and do not retry a non-retryable refusal. A refusal reason should be recorded with its timestamp and the new challenge, if one is supplied. A malformed envelope needs a client correction. A wrong amount or asset needs a policy decision. An expired challenge needs a fresh request. A duplicate payment needs status lookup. These cases are operationally different, so one generic retry rule is unsafe.

What to record after access is granted

Record the payment resource, network, asset, amount, settlement reference, activation time, expiry time, and access capability reference. Do not put a private key, seed phrase, or bearer capability into a public log. Store sensitive values in the wallet or secret store that owns them. The public receipt can establish the integrity of the published payment record while a private access value remains limited to the client that needs it.

For the first paid tool call, record the request identifier and the execution receipt returned by the service. Inspect the receipt through its verifier and compare the recorded tool, arguments commitment, timestamp, and observed result with the request that the agent sent. A receipt is evidence of what the execution layer recorded. It is not a guarantee that an external recipient accepted the result. If the tool reports a failure, retain that failure rather than describing the paid request as successful.

Handling the free allowance and the Day Pass

The free MCP allowance and the agent-native Day Pass answer different usage patterns. The free route is useful for low-volume testing within the published limit. The Day Pass is a time-limited entitlement bought for $0.99 USDC on Base for 24 hours. It is not a per-call price. Keep those categories separate in a cost report. A free call is not evidence that a paid entitlement exists, and a settled Day Pass is not evidence that every call during its window succeeded.

When the pass expires, request a new challenge and check the current terms before paying again. Do not assume that an old access key remains valid. If the payment settled but the entitlement is not available, keep the settlement reference and request identifier, stop repeated payments, and use the published support route. Never send wallet secrets while diagnosing an access problem. A support request should contain only the safe identifiers needed to locate the event.

Human checkout and safe recovery

The MCP quota response can include a session-bound short PayPal link for the human. It does not create an order or charge. The human must open it and approve payment. If no link is present, ask first and call day_pass_checkout_link with human_approved=true. Use day_pass_status in the same MCP session to check activation and expiry; the status tool never returns the raw access key.

For x402, do not repeat a payment after a timeout or refusal. Inspect the current refusal receipt and retryability, then check settlement or entitlement status before signing another authorization. Keep access keys out of URLs and logs.

Review checklist for operators

  1. Capture the original request and the fresh challenge.
  2. Check amount, asset, network, destination, resource, validity, and spending policy.
  3. Sign only the structured authorization that passed local checks.
  4. Confirm settlement or entitlement status before retrying the resource.
  5. Retry the same request with the same session and arguments.
  6. Save the payment and execution references separately.
  7. Verify the execution receipt and check any important outside state with its owning system.
  8. Record refusal, timeout, duplicate, and expiry states without converting them into success.

This workflow keeps machine payment useful without making payment carry claims it cannot support. It also gives a reviewer a clear path from the 402 challenge to the authorization, from the authorization to the entitlement, and from the entitlement to the recorded execution. The final question remains specific: what did the execution layer observe, and what independent evidence confirms anything beyond that observation?

For developers and agents

Zambo gives AI work a receipt you can check. For people: add Zambo to your AI app and ask for a job. These technical links are for developers and AI agents. One hosted MCP at https://zambo.dev/mcp. Check the proof for recorded tool calls (verify a receipt). Agents: 24-hour Day Pass, $0.99 USDC on Base via x402, not per call. People: Zambo Pass $29/mo or $290/yr; holder pass $19/mo for verified $ZAMBO holders.

Start here: For AI agents · Add Zambo · Check a receipt · Answers · Guides · What a receipt is · Open receipt format (draft) · All tools · Pricing · Day Pass: $0.99 · Agent Day Pass · Switch AIs without losing your work · Connect your AI · Founder · Source code
Brennan on X · Zambo on X