POST /v1/probe
Read a paid endpoint's 402 offer. Never pays it.
POST https://api.x402spend.dev/v1/probe
Content-Type: application/json
An x402 seller answers an unpaid request with 402 Payment Required and a body describing what it would cost. That body is public by construction — it is an offer, addressed to anyone — so reading it needs no key, no account and no wallet.
Request
| Field | Type | Required | Notes |
|---|---|---|---|
url | string | yes | Absolute http or https URL, max 2048 chars |
{ "url": "https://api.onesource.io/api/chain/block-number" }
Response
{
"ok": true,
"url": "https://api.onesource.io/api/chain/block-number",
"status": 402,
"paid": true,
"x402Version": 2,
"resource": {
"url": "https://api.onesource.io/api/chain/block-number",
"description": "Latest Ethereum block height",
"mimeType": "application/json"
},
"offers": [
{
"scheme": "exact",
"network": "eip155:8453",
"asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"amount": "1000",
"payTo": "0x52E29e0d2Aa49bfBfC548C0A9F2196F4aa51f3ea",
"maxTimeoutSeconds": 3600,
"extra": { "name": "USD Coin", "version": "2" }
}
]
}
| Field | Notes |
|---|---|
url | The URL actually read, after any redirect |
status | The HTTP status the endpoint returned |
paid | true exactly when status is 402 |
x402Version | As published by the endpoint |
resource | Discovery metadata, when the endpoint publishes it |
offers | Every entry in accepts[], capped at 20 |
note | Present when the body could not be read as x402 |
amount is read from amount (x402 v2) or maxAmountRequired (v1), so both generations parse. Amounts stay in atomic units: how many decimals that is belongs to the asset contract, which a probe does not read.
An endpoint that is not paid is reported as it answered rather than as an error — status: 200, paid: false — because "this URL is not behind a paywall" is a useful answer.
Refusals
A URL that will not be fetched comes back 200 with ok: false:
{ "ok": false, "reason": "refusing to probe a private or loopback address" }
| Reason | |
|---|---|
only http and https URLs can be probed | A file: or other scheme |
refusing to probe a private or loopback address | Loopback, link-local, RFC 1918, or the metadata address |
refusing to probe a URL carrying credentials | Credentials embedded in the URL |
redirect <reason> | A redirect pointed somewhere refused for one of the above |
more than 1 redirect followed | Too many hops |
could not reach <host>: <message> | Transport failure or timeout |
A malformed url is 422 before any of this.
What it will not do
This route takes a URL from an unauthenticated caller and fetches it, which makes it a request forwarder and it is treated as one:
- It never pays. One unauthenticated
GET, no payment header, no signer, and no code path that could construct a payment. - It refuses private space — loopback, link-local, RFC 1918 and the cloud metadata address — by name, rather than leaving it to whatever the runtime happens not to route.
- It re-checks redirects against the same rule. A redirect is the obvious way to walk a probe from a public host onto a private one.
- It follows one hop, then stops.
- It reads 64 KiB and then stops, so a large body cannot exhaust the isolate.
- It stores nothing.