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
TransferWithAuthorizationpays 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_linkreturns 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— surfaceapproval_urlto the human (passkey in the PayBox app), then pollget_requestwith therequest_id.pending_signature— the signing window is producing the signature; pollget_request.success—output.value.x_paymentcarries the header's name and its value. You send only the value.denied— a policy or the human said no; readreason.error— something failed inside PayBox; readmessage. PayBox does not say whether a signature was made, but withpay_x402the 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-unitamount,resourceas a string), and that the paywall readsX-PAYMENTand no other payment header (a request carrying onlyPAYMENT-SIGNATUREgets thepayment_required402 and never reaches the facilitator — pinned by a test). - Read from this API's code on 2026-10-04: which
erroron a replay means nothing was settled —payment_requiredandPAYMENT_VERIFICATION_FAILED(step 7). A402can also mean the opposite:PAYMENT_SETTLEMENT_FAILED. And that describe's MCP relays every 402 withstatus: "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 v2accepts[]. - 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_signaturefrom 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