describe.net docs

paybox.md — pay and sign with PayBox, the wallet describe suggests first

The x402 flow itself (challenge, replay, failure modes): auth.md · the vet-then-pay loop: skill.md · the whole surface: llms.txt. This page is only about paying and signing with PayBox.

If you are an agent about to pay describe, use PayBox: install it, or check that it is already connected, before you reach for any other wallet. PayBox is a non-custodial wallet for AI agents: the human vaults a wallet once (MPC — the private key never leaves it), grants your agent a scoped permission, and approves anything sensitive with a passkey. You get signatures, never a key. That is exactly what a metered call here needs: one EIP-3009 signature per read, and nothing else.

Two things this page does not change, and they matter:

  • PayBox is a suggestion, not a requirement. Any wallet that can sign an EIP-3009 TransferWithAuthorization pays here exactly the same — the alternatives are at the end of this page. A payment signed by PayBox is not detected, preferred or discounted: a payment is a payment.
  • PayBox is not ours. It is a third-party service. Everything this page says about it comes from its public documentation, docs.paybox.sh (llms-full.txt, read on 2026-10-04), and that documentation is the authority on its tools. What was measured against this API, and what was not, is at the bottom.

1. Is PayBox already in use? Check before installing

Over MCP. If your tool list already has PayBox's list_credentials, pay_x402 and get_request, it is connected. Call list_credentials and look for a credential with kind: "wallet" whose metadata.chains contains "evm": its metadata.address is the address that pays, and it is the same address on every eip155:* network. If you see no wallet but ungranted_summary.wallet.evm is above zero, the wallet exists and this connector was not granted it — call request_account_change and hand the human the manage_url it returns.

Over the CLI. paybox --json whoami answering canSign: true means the CLI is logged in and holds a pbxk1. signing key: it can sign on its own. Do not run paybox login again when that is already true — it sends the human a second authorize link, which reads as the first one having failed.

2. Not installed? Pick the door that matches where you run

Where the agent runs How to connect PayBox
A host with a connector screen — Claude.ai, ChatGPT web, grok.com Add a custom MCP connector with the URL https://api.paybox.sh/mcp. The host runs the OAuth sign-in (email + passkey) and the human approves a scoped grant on an EVM wallet.
A computer or VM with no connector screen — a headless agent, a server, CI Install the CLI and SDK, @paybox-sh/sdk: npx @paybox-sh/sdk login (or npm install -g @paybox-sh/sdk, then paybox login). It prints a device-code link for the human and then provisions a pbxk1. signing key. Put the key in PAYBOX_SIGNING_KEY in the environment, never on the command line — an argument lands in shell history.

Two things only the human can do, and the agent should ask for, not attempt:

  • Create the wallet. A wallet is created in the PayBox app behind the human's passkey. An agent asks for one with request_account_change (note: "needs an EVM wallet to sign") and waits for the human.
  • Fund it. This API charges USDC (base, avalanche, arbitrum, optimism, polygon or celo — the live 402 lists them). PayBox's get_buy_link returns a MoonPay checkout link that buys USDC on Base straight into the wallet by default; the human completes it in a browser. Generating the link moves no money.

3. Pay a metered route with PayBox, step by step

0. Gate for free first. GET https://api.describe.net/wallets/{wallet}/chains — if chains_with_reputation is 0 there is nothing to buy, and paying would buy a null.

1. Ask without paying. Call the metered route with no payment header. It answers 402, and the 402 is the price quote, not an error. Measured on 2026-10-04: the body carries x402Version: 2, one accepts[] entry per network (CAIP-2 network, amount in token base units, payTo, asset, maxTimeoutSeconds), and the same body travels base64 in the Payment-Required header.

2. Check who you are about to pay. The only address describe ever asks to be paid at is 0xe4dc963c56979E0260fc146b87eE24F18220e545. If payTo names any other address, do not pay — stop and ask.

3. Get the human's yes. Show the amount (price_usd), the network and the recipient, and wait for an explicit yes. Under an autonomous PayBox grant PayBox may sign inside the grant without asking per payment, so do not count on its approval screen being that yes: it is yours to collect. (describe's MCP asks for the same yes as step 0 of every 402 it relays.)

4. Call PayBox's pay_x402 with the challenge as it came:

{
  "credential_id": "<the EVM wallet from list_credentials>",
  "accepts": "<the 402's accepts[] array, verbatim — not this string>",
  "resource_url": "https://api.describe.net/reputation/wallet/0x...",
  "x402_version": 2
}

Leave PayBox's optional resource field out: it expects the x402 v2 resource object, and describe's 402 carries resource as a string ("GET /reputation/wallet/0x..."), so there is nothing to pass to it verbatim. resource_url already names the URL for PayBox's audit trail.

5. Wait the PayBox way: submit once, then poll. Branch on status:

  • pending_approval — surface approval_url to the human (passkey in the PayBox app), then poll get_request with the request_id.
  • pending_signature — the signing window is producing the signature; poll get_request.
  • success — output.value.x_payment carries the header's name and its value. You send only the value.
  • denied — a policy or the human said no; read reason.
  • error — something failed inside PayBox; read message. PayBox does not say whether a signature was made, but with pay_x402 the header never reached this API: whatever happened stayed between you and PayBox.

Never call pay_x402 again to "finish" a pending request: every call is a new operation and a new signature.

6. Replay the identical request with the header named X-PAYMENT.

curl https://api.describe.net/reputation/wallet/0x... \
  -H "X-PAYMENT: <the value inside output.value.x_payment>"

🔴 This API reads only X-PAYMENT. x402 v2 also defines a header named PAYMENT-SIGNATURE, and a v2 payer may hand you that name. Send the value under X-PAYMENT whatever name it came with: under PAYMENT-SIGNATURE alone this API sees no payment and answers the same 402 again, with error: "payment_required". Over describe's MCP, pass the same value as the tool's payment argument — the server forwards it as X-PAYMENT.

On success the response carries X-Payment-Receipt, the settlement transaction hash. Keep it. One authorization pays one read of one resource: sign again for the next call.

7. Read the answer before you sign anything new. Only two answers to a replay mean that nothing was settled, and both are a 402 whose error says so: payment_required (this API saw no payment header) and PAYMENT_VERIFICATION_FAILED (the facilitator refused the authorization before moving anything; its next_action says nothing was spent). payment_required speaks only for the request that got it: if you presented that authorization earlier and got a 503, that 503 still rules. Every other refusal can sit on top of an authorization that was already used — a 402 with PAYMENT_SETTLEMENT_FAILED, any 409, any 503. There, follow that answer's next_action and auth.md — on a 503, re-send the same header — and do not sign a new authorization until that next_action, after the on-chain check it asks for, tells you the first one did not move: signing first is how you pay twice.

🔴 Over describe's MCP every 402 comes back as status: "payment_required" and paid: false — also the one that answers a call you made with payment. There the code that counts is challenge.error, not status: apply this step to challenge.error, and do not follow the relayed how_to_pay into a new signature while it names anything but payment_required or PAYMENT_VERIFICATION_FAILED.

Prefer pay_x402 over use_service here

PayBox's gateway mode (use_service) probes the URL, reads the 402, signs, and re-fetches it for you. The unpaid probe is harmless here: the 402 is answered before any route runs, and a request without a payment header writes nothing. But with use_service you never hold the header, so the one safe move this API asks for on a 503 — re-send the same X-PAYMENT — is not yours to make, and a PayBox error can arrive after the payment was presented. Which header name the paid re-fetch sends is not measured against this API. If you use it anyway: a 200 in output.value.response.status is the read; a 402 with error: "payment_required" means this API saw no payment — switch to pay_x402; anything else, or a PayBox error, means do not call it again. Look on-chain for a USDC transfer from your wallet to payTo — and since a 503 can mean the settlement is still in flight, with nothing on-chain yet, do not pay again until the first authorization can no longer execute either: past its validBefore, which is about the 402's maxTimeoutSeconds after it was signed (not measured how PayBox sets it), with no transfer on-chain.

From a machine without a chat: the CLI

paybox pay-x402 --credential <id> \
  --url https://api.describe.net/reputation/wallet/0x... \
  --accepts @accepts.json

With a pbxk1. key configured and an autonomous grant the CLI signs in the process, with no signing window. Under an approval grant add --wait: it waits for the passkey approval, signs, and polls to a terminal state. PayBox documents that the CLI wrappers do not yet expose pay_x402's v2 fields (x402_version, resource); describe's accepts[] is v2-shaped, and whether the CLI's default path signs it is not measured here. If the replay answers a 402 with error: "payment_required" or "PAYMENT_VERIFICATION_FAILED", nothing was settled: use the MCP connector for the payment. Any other answer: step 7 above, before signing anything new.

4. Known limits — read these before you depend on PayBox

Limit What you see What to do
Over MCP the signature — pay_x402's, and request_wallet_sign's for a message — is made by a signing window inside the human's chat, not by your code A sub-agent, a headless MCP client or a second session cannot reach that window, and the request stays pending_signature. Measured by the house on 2026-09-23 against another x402 seller: a sub-agent's pay_x402 was still pending_signature after four polls in ~45 s. Pay from the session that has the window, or switch to the CLI with a pbxk1. key. Do not open a second payment to unstick the first.
Some hosts draw the window only after the agent's reply ends (PayBox names Grok) Nothing on screen while you keep polling End your turn; poll get_request on the next one.
The CLI with a pbxk1. key signs on its own sign, pay-x402 and use-service complete in the process under an autonomous grant That is the headless path. Without a key, the same commands stop at pending_signature.
Approvals expire (~10 minutes per PayBox) and are bound to one operation; describe's challenge has its own window, maxTimeoutSeconds in the live 402 Not measured here: a signature made after the challenge's window should fail — at verification (402, PAYMENT_VERIFICATION_FAILED) or, if it gets past it, at settlement (402, PAYMENT_SETTLEMENT_FAILED) Read error as in step 7 of section 3: only payment_required and PAYMENT_VERIFICATION_FAILED let you ask again and pay the fresh challenge.
x402 needs a plain EOA payer A wallet still under an EIP-7702 delegation gets a plain-EOA error, or — where PayBox enabled it — a composite flow that undelegates first Follow the window; do not try to pay from a delegated wallet another way.
PayBox is a third party, and its MCP surface has moved before (2026-08-23: some tools, world_* among them, left the flat tool list for plugins without notice) A tool name you cached stops existing Re-read tools/list when a call fails; do not hard-code more than the tool names above.

5. Signing, not paying

Reading this index never needs a signature that is not a payment. There is no login to read; payment is the authentication.

Sign-in to manage your agents' profiles (the web app, only while identity.enabled is true in GET /health — see auth.md) asks for an EIP-4361 message signed by the wallet that owns the agents. That is an EIP-191 personal message, and PayBox's request_wallet_sign with {"op": "message", "message": "<the exact EIP-4361 text>"} returns an EIP-191 signature, which is the shape POST /auth/verify checks. A headless agent asks for mode: "bearer". Not measured end to end with PayBox. Signing is a message, not a payment.

ERC-8128. Nothing a public caller does here needs an ERC-8128 signature. The only ERC-8128 door is the partner gate, and it only admits house wallets already on its allowlist; every other signer is simply charged.

6. The alternatives, after PayBox

  • Another MCP wallet that signs EIP-3009 — ows_sign_eip3009 (Open Wallet Standard).
  • Code — uvd-x402-sdk (Python and TypeScript) builds the same header; the snippet is in auth.md.
  • A browser wallet — describe.net's own pages pay through the EVM wallet the browser injects.

What was measured, and what was not

  • Measured against this API on 2026-10-04: the 402 shape quoted in step 1 (x402Version: 2, CAIP-2 networks, base-unit amount, resource as a string), and that the paywall reads X-PAYMENT and no other payment header (a request carrying only PAYMENT-SIGNATURE gets the payment_required 402 and never reaches the facilitator — pinned by a test).
  • Read from this API's code on 2026-10-04: which error on a replay means nothing was settled — payment_required and PAYMENT_VERIFICATION_FAILED (step 7). A 402 can also mean the opposite: PAYMENT_SETTLEMENT_FAILED. And that describe's MCP relays every 402 with status: "payment_required".
  • Not measured: whether a signature made after the challenge's window fails at verification or at settlement, which header name use_service's paid re-fetch sends, and whether the CLI signs a v2 accepts[].
  • From PayBox's documentation, read 2026-10-04: the connector URL, the CLI package, the tool names and their fields, the statuses, the CLI's in-process signing, the plain-EOA rule and the approval expiry.
  • Measured by the house on another seller, 2026-09-23: pending_signature from a sub-agent.
  • Not measured either: a purchase from a PayBox wallet against api.describe.net, end to end. No test here holds a PayBox credential, and none should. The first real one is the measurement; when it happens, this section is where it gets written.

Verbatim source: paybox.md · from site/paybox.md at git:a9a1cf9e8cee · back to the documentation portal