Test your x402 client against a real endpoint.
Every refusal here tells you what was actually wrong: which field differs from what was advertised, which schemes and networks the route offers, whether the amount or the validity window is the problem. Refusals are free, because an error status cancels settlement. You pay only when it works, and then it costs $0.001.
1. Get a challenge
Any paid route answers one. This is the cheapest: pure computation, no upstream.
curl -sD - -X POST https://agent402.tools/api/hash \
-H 'content-type: application/json' \
-d '{"text":"hello"}'
The terms are in the PAYMENT-REQUIRED response header as base64 JSON, which is where the x402 v2 spec puts them; the body is {} by design. MPP clients get WWW-Authenticate: Payment challenges on the same response.
2. Pay it, and read the refusal
Retry with your client's PAYMENT-SIGNATURE header. If it is wrong, the 402 body carries a reason, a hint in words, and a retry telling you what kind of change is needed. Here is a real one:
{
"error": "Payment rejected",
"reason": "unsupported-scheme",
"hint": "Scheme \"lightning\" is not offered on this route. Offered: exact, upto.",
"retry": "choose-offered-option"
}
Field names are echoed so you can compare them; values never are. A payment header is a credential.
Every reason this server emits
| malformed-header | The PAYMENT-SIGNATURE header is not decodable base64 JSON. Usually a hand-built header, or a base64 variant the decoder did not expect. |
| version-mismatch | The payload declares one x402Version and the route serves another. An x402 v1 client against a v2 resource is the common case. |
| malformed-payload | It decoded, but names no scheme or network. Copy both verbatim from one accepts entry. |
| unsupported-scheme | The scheme is not one this route offers. The refusal names the schemes that are. |
| unsupported-network | The network is not one this route offers. The refusal names the networks that are. |
| missing-accepted | No echoed `accepted` object. Verification deep-equals what you echo against what was advertised, so it has to be there. |
| requirements-mismatch | The echoed accepts entry differs from the advertised one. The refusal names WHICH fields differ, which is usually a client that rebuilt the object instead of echoing it. |
| amount-below-price | The authorized amount is under the price this route quoted. |
| wrong-recipient | The authorization pays an address this route did not advertise. |
| authorization-expired | validBefore has already passed. Signing well ahead of sending, or a clock adrift, will do it. |
| unclassified | It decoded and still matched nothing, in a way this server has no name for. The refusal lists the field NAMES received so you can compare them yourself, and we would like to hear about it: an unclassified refusal is as likely to be our defect as yours. |
3. When it works
You get a 200, the tool's answer, and a PAYMENT-RESPONSE receipt naming the settlement transaction, verifiable on the chain you paid on without asking us. At that point your client is integrated with the whole catalog: the same credential pays for 500+ tools, five model tiers on three wires, embeddings, images, speech and finished reports.
If the refusal looks wrong, it may be ours.
A refusal we cannot classify is as likely to be a defect on this server as a fault in your client, and we would rather hear about it than have you work around it. Two of the classes in the table above exist because someone outside told us their client was being refused for a reason that turned out to be ours.