Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion docs/api-reference/chat-completions.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,14 +172,16 @@ WWW-Authenticate: X402 requirements="<same value>"

```json
{
"x402Version": 2,
"accepts": [{"scheme": "exact", "network": "eip155:8453", "amount": "25685", "asset": "0x8335…", "payTo": "0x…", "maxTimeoutSeconds": 300}],
"error": "Payment Required",
"message": "This endpoint requires x402 payment",
"price": {"amount": "0.025685", "currency": "USD"},
"paymentInfo": {"network": "base", "asset": "USDC", "x402Version": 2}
}
```

`price.amount` is the exact amount the header signs, transaction fee included. Decoded, the header is:
`price.amount` is the exact amount the header signs, transaction fee included. `x402Version`/`accepts` at the top level mirror the header's challenge in the body, for clients that only parse the body. Decoded, the header is:

```json
{
Expand Down
5 changes: 4 additions & 1 deletion docs/api-reference/defillama.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,13 @@ DefiLlama does not know is simply absent from `coins` — the call still returns
A request without a payment header returns `402`. The signed requirements are
in the `X-Payment-Required` / `PAYMENT-REQUIRED` headers (and
`WWW-Authenticate: X402 requirements="…"`), and the JSON body restates the
price for humans:
price for humans and mirrors the challenge itself (`x402Version`, `accepts`)
for clients that only read the body:

```json
{
"x402Version": 2,
"accepts": [{ "scheme": "exact", "network": "eip155:8453", "amount": "2000", "asset": "0x8335…", "payTo": "0x…", "maxTimeoutSeconds": 300 }],
"error": "Payment Required",
"message": "This endpoint requires x402 payment",
"endpoint": "/api/v1/defillama/prices/coingecko:bitcoin",
Expand Down
4 changes: 3 additions & 1 deletion docs/api-reference/errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,14 +93,16 @@ An unknown model is a plain-string error that suggests live IDs:

```json
{
"x402Version": 2,
"accepts": [{"scheme": "exact", "network": "eip155:8453", "amount": "25685", "asset": "0x8335…", "payTo": "0x…", "maxTimeoutSeconds": 300}],
"error": "Payment Required",
"message": "This endpoint requires x402 payment",
"price": {"amount": "0.025685", "currency": "USD"},
"paymentInfo": {"network": "base", "asset": "USDC", "x402Version": 2}
}
```

The signed requirements travel in the `X-Payment-Required` / `PAYMENT-REQUIRED` headers (and `WWW-Authenticate: X402 requirements="…"`). `price.amount` equals the signed amount, including the flat $0.001 transaction fee.
The signed requirements travel in the `X-Payment-Required` / `PAYMENT-REQUIRED` headers (and `WWW-Authenticate: X402 requirements="…"`), and — since 2026-08-30 — are mirrored at the top level of the JSON body too (`x402Version`, `accepts`), byte-identical to the decoded header. This is for v1-era x402 clients (early `x402-fetch`/`x402-axios` and third-party wrappers) that only parse the body and silently fail to auto-pay when there's no top-level `accepts`. `price.amount` equals the signed amount, including the flat $0.001 transaction fee.

:::info{title="402 is not an error"}
A `402 Payment Required` is part of the normal x402 flow — the gateway is quoting a price. Sign and retry with payment and the SDKs handle this round-trip automatically.
Expand Down
4 changes: 3 additions & 1 deletion docs/api-reference/exa-search.md
Original file line number Diff line number Diff line change
Expand Up @@ -326,10 +326,12 @@ Every price above already includes the flat $0.001 per-transaction fee (base $0.

### The 402 response

An unpaid request returns `402` with the exact charge in the body and the signable x402 v2 requirements in the `X-Payment-Required` / `PAYMENT-REQUIRED` headers (base64 JSON; also mirrored in `WWW-Authenticate`). For `/contents` the body is read first, so `price.amount` reflects `urls.length`:
An unpaid request returns `402` with the exact charge in the body and the signable x402 v2 requirements in the `X-Payment-Required` / `PAYMENT-REQUIRED` headers (base64 JSON; also mirrored in `WWW-Authenticate`), plus the same challenge mirrored into the body as `x402Version`/`accepts`. For `/contents` the body is read first, so `price.amount` reflects `urls.length`:

```json
{
"x402Version": 2,
"accepts": [{ "scheme": "exact", "network": "eip155:8453", "amount": "5000", "asset": "0x8335…", "payTo": "0x…", "maxTimeoutSeconds": 300 }],
"error": "Payment Required",
"message": "This endpoint requires x402 payment",
"endpoint": "/api/v1/exa/contents",
Expand Down
4 changes: 3 additions & 1 deletion docs/api-reference/image-generation.md
Original file line number Diff line number Diff line change
Expand Up @@ -337,10 +337,12 @@ billed = catalog rate for the size × n × 1.05 (5% platform margin on media)

### 402 responses

The unpaid `402` is a normal x402 challenge: the signable requirements live in the `X-Payment-Required` / `PAYMENT-REQUIRED` / `WWW-Authenticate` headers (base64 JSON, `x402Version: 2`, `maxTimeoutSeconds: 600`); the body is informational.
The unpaid `402` is a normal x402 challenge: the signable requirements live in the `X-Payment-Required` / `PAYMENT-REQUIRED` / `WWW-Authenticate` headers (base64 JSON, `x402Version: 2`, `maxTimeoutSeconds: 600`), mirrored at the top of the body (`x402Version`, `accepts`) for clients that only read the body; the rest of the body is informational.

```json
{
"x402Version": 2,
"accepts": [{ "scheme": "exact", "network": "eip155:8453", "amount": "53500", "asset": "0x8335…", "payTo": "0x…", "maxTimeoutSeconds": 600 }],
"error": "Payment Required",
"message": "This endpoint requires x402 payment",
"price": { "amount": "0.053500", "currency": "USD", "pricePerImage": 0.05, "totalImages": 1 },
Expand Down
5 changes: 4 additions & 1 deletion docs/api-reference/modal-sandbox.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,10 +177,13 @@ curl -X POST https://blockrun.ai/api/v1/modal/sandbox/create \

The signed requirements are in the `X-Payment-Required` / `PAYMENT-REQUIRED`
headers (and `WWW-Authenticate: X402 requirements="…"`); the body restates the
price:
price and mirrors the challenge itself (`x402Version`, `accepts`) for clients
that only read the body:

```json
{
"x402Version": 2,
"accepts": [{ "scheme": "exact", "network": "eip155:8453", "amount": "11000", "asset": "0x8335…", "payTo": "0x…", "maxTimeoutSeconds": 300 }],
"error": "Payment Required",
"message": "This endpoint requires x402 payment",
"endpoint": "/api/v1/modal/sandbox/create",
Expand Down
2 changes: 2 additions & 0 deletions docs/api-reference/polymarket-funding.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ curl -X POST https://blockrun.ai/api/v1/polymarket/fund

```json
{
"x402Version": 2,
"accepts": [{ "scheme": "exact", "network": "eip155:8453", "amount": "11000", "asset": "0x8335…", "payTo": "0x…", "maxTimeoutSeconds": 300 }],
"error": "Payment Required",
"message": "This endpoint requires an x402 fee payment ($0.0110). Include the signed deposit authorization in the body.",
"endpoint": "/api/v1/polymarket/fund",
Expand Down
2 changes: 1 addition & 1 deletion docs/api-reference/realface.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ POST https://blockrun.ai/api/v1/realface/enroll

Same two-step pattern as other paid BlockRun endpoints:

1. First call without `X-Payment` → server returns `402 Payment Required` with x402 challenge headers (`X-Payment-Required` / `PAYMENT-REQUIRED` base64, plus `WWW-Authenticate: X402 requirements="…"`) and a body of `{ "error": "Payment Required", "message": "Enrolling a RealFace asset costs $0.0110 USDC. …", "price": { "amount": "0.0110", "currency": "USD" }, "paymentInfo": { "network": "base", "asset": "USDC", "x402Version": 2 } }`
1. First call without `X-Payment` → server returns `402 Payment Required` with x402 challenge headers (`X-Payment-Required` / `PAYMENT-REQUIRED` base64, plus `WWW-Authenticate: X402 requirements="…"`) and a body of `{ "x402Version": 2, "accepts": [{ "scheme": "exact", "network": "eip155:8453", "amount": "11000", "payTo": "0x…", "maxTimeoutSeconds": 300 }], "error": "Payment Required", "message": "Enrolling a RealFace asset costs $0.0110 USDC. …", "price": { "amount": "0.0110", "currency": "USD" }, "paymentInfo": { "network": "base", "asset": "USDC", "x402Version": 2 } }` — `x402Version`/`accepts` mirror the header's challenge for clients that only read the body
2. Sign the EIP-3009 transfer authorization for **$0.011 USDC on Base** (`$0.01` enrolment + `$0.001` transaction fee — the requirements say `11000` micro-USDC)
3. Retry the same request with `X-Payment: <base64>` (`Payment-Signature` is accepted too)

Expand Down
4 changes: 3 additions & 1 deletion docs/api-reference/responses.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,15 @@ The quote is estimated input tokens plus **10% of `max_output_tokens`** at the m

```json
{
"x402Version": 2,
"accepts": [{"scheme": "exact", "network": "eip155:8453", "amount": "24685", "asset": "0x8335…", "payTo": "0x…", "maxTimeoutSeconds": 300}],
"error": {"message": "This endpoint requires x402 payment", "type": "payment_required", "param": null, "code": null},
"price": {"amount": "0.024685", "currency": "USD"},
"paymentInfo": {"network": "base", "asset": "USDC", "x402Version": 2}
}
```

The signed requirements are in the `X-Payment-Required` / `PAYMENT-REQUIRED` / `WWW-Authenticate` headers; the header amount is authoritative and includes the transaction fee, and the body `price.amount` quotes the same fee-inclusive number. A payment that fails verification is a `402` in the same OpenAI envelope — `"Payment verification failed: …"` — and a reused authorization is `402` `"Payment authorization already used — sign a fresh authorization for each request."`; this endpoint keeps OpenAI's error schema rather than the `code` field the native BlockRun endpoints carry. Nothing is charged on either.
The signed requirements are in the `X-Payment-Required` / `PAYMENT-REQUIRED` / `WWW-Authenticate` headers; the header amount is authoritative and includes the transaction fee, and the body `price.amount` quotes the same fee-inclusive number. `x402Version`/`accepts` at the top of the body mirror that header challenge for clients that only read the body — they sit alongside the OpenAI-shaped `error` object, not inside it. A payment that fails verification is a `402` in the same OpenAI envelope — `"Payment verification failed: …"` — and a reused authorization is `402` `"Payment authorization already used — sign a fresh authorization for each request."`; this endpoint keeps OpenAI's error schema rather than the `code` field the native BlockRun endpoints carry. Nothing is charged on either.

## Examples

Expand Down
11 changes: 10 additions & 1 deletion docs/api-reference/search.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,15 @@ When you first make a request without payment, you'll receive:

```json
{
"x402Version": 2,
"accepts": [{
"scheme": "exact",
"network": "eip155:8453",
"amount": "263500",
"asset": "0x8335…",
"payTo": "0x…",
"maxTimeoutSeconds": 300
}],
"error": "Payment Required",
"message": "This endpoint requires x402 payment",
"price": {
Expand All @@ -90,7 +99,7 @@ When you first make a request without payment, you'll receive:
}
```

The full x402 v2 payment requirements are in the `X-Payment-Required` and `PAYMENT-REQUIRED` headers (base64 JSON, identical content) and in `WWW-Authenticate: X402 requirements="..."`. Sign against the header, not the body: `price.amount` in the body is the per-source cost plus margin **before** the flat $0.001 transaction fee, while `accepts[0].amount` in the header is the exact USDC (6-decimal) amount you will be charged — for the default 10 sources that is `263500`, i.e. $0.2635. Payment authorizations are valid for `maxTimeoutSeconds: 300`.
The full x402 v2 payment requirements are in the `X-Payment-Required` and `PAYMENT-REQUIRED` headers (base64 JSON, identical content) and in `WWW-Authenticate: X402 requirements="..."`, and are now also mirrored at the top of the JSON body as `x402Version`/`accepts` (for clients that only read the body). Sign against `accepts[0].amount` (header or body, they're identical), not `price.amount`: `price.amount` is the per-source cost plus margin **before** the flat $0.001 transaction fee, while `accepts[0].amount` is the exact USDC (6-decimal) amount you will be charged — for the default 10 sources that is `263500`, i.e. $0.2635. Payment authorizations are valid for `maxTimeoutSeconds: 300`.

A `GET` to the same URL returns a 402 quoting the default price (10 sources) — useful for discovery.

Expand Down
4 changes: 3 additions & 1 deletion docs/api-reference/text-to-speech.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,12 @@ Differences from the ElevenLabs models:

### The 402 challenge

An unpaid POST returns `402` with the x402 requirement in the `X-Payment-Required` / `PAYMENT-REQUIRED` / `WWW-Authenticate` headers and an informational body:
An unpaid POST returns `402` with the x402 requirement in the `X-Payment-Required` / `PAYMENT-REQUIRED` / `WWW-Authenticate` headers, mirrored at the top of the body as `x402Version`/`accepts`; the rest of the body is informational:

```json
{
"x402Version": 2,
"accepts": [{ "scheme": "exact", "network": "eip155:8453", "amount": "53500", "asset": "0x8335…", "payTo": "0x…", "maxTimeoutSeconds": 300 }],
"error": "Payment Required",
"message": "This endpoint requires x402 payment",
"price": { "amount": "0.053500", "currency": "USD" },
Expand Down
6 changes: 4 additions & 2 deletions docs/api-reference/video-generation.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,10 +175,12 @@ All prices below are the amounts quoted in the `402` challenge and actually bill

## The 402 challenge

An unpaid POST returns `402` with the x402 requirement in three equivalent headers — `X-Payment-Required`, `PAYMENT-REQUIRED` (base64 JSON) and `WWW-Authenticate: X402 requirements="…"` — plus an informational JSON body:
An unpaid POST returns `402` with the x402 requirement in three equivalent headers — `X-Payment-Required`, `PAYMENT-REQUIRED` (base64 JSON) and `WWW-Authenticate: X402 requirements="…"` — mirrored at the top of the body as `x402Version`/`accepts`; the rest of the JSON body is informational:

```json
{
"x402Version": 2,
"accepts": [{ "scheme": "exact", "network": "eip155:8453", "amount": "1122000", "asset": "0x8335…", "payTo": "0x…", "maxTimeoutSeconds": 300 }],
"error": "Payment Required",
"message": "This endpoint requires x402 payment",
"price": {
Expand All @@ -199,7 +201,7 @@ An unpaid POST returns `402` with the x402 requirement in three equivalent heade
}
```

`price.amount` is the full amount you will be charged (media price + $0.001 fee). On the Grok SKUs `pricePerSecond` states the rate of the **tier actually billed** and `resolution` / `perGenerationFee` are present so the arithmetic reconciles; on Sora and Seedance `pricePerSecond` is the model's flat display rate. The decoded requirement's `accepts[0].amount` is the same figure in USDC base units (6 decimals).
`price.amount` is the full amount you will be charged (media price + $0.001 fee). On the Grok SKUs `pricePerSecond` states the rate of the **tier actually billed** and `resolution` / `perGenerationFee` are present so the arithmetic reconciles; on Sora and Seedance `pricePerSecond` is the model's flat display rate. The decoded requirement's `accepts[0].amount` is the same figure in USDC base units (6 decimals) — and now identical to the body's own `accepts[0].amount`.

Sign that requirement and re-send the POST with the signature in `X-Payment` (also accepted: `Payment-Signature`). A verification failure returns `402` with a machine-readable `code`:

Expand Down
2 changes: 1 addition & 1 deletion docs/api-reference/virtual-portrait.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Images that fail the upstream content filter (NSFW, recognizable real-celebrity

Standard BlockRun two-step:

1. **First request without `X-Payment`** → server returns `402 Payment Required` with x402 challenge headers (`X-Payment-Required` / `PAYMENT-REQUIRED` base64, plus `WWW-Authenticate: X402 requirements="…"`) and a body of `{ "error": "Payment Required", "message": "Enrolling a Virtual Portrait costs $0.0110 USDC. …", "price": { "amount": "0.0110", "currency": "USD" }, "paymentInfo": { "network": "base", "asset": "USDC", "x402Version": 2 } }`
1. **First request without `X-Payment`** → server returns `402 Payment Required` with x402 challenge headers (`X-Payment-Required` / `PAYMENT-REQUIRED` base64, plus `WWW-Authenticate: X402 requirements="…"`) and a body of `{ "x402Version": 2, "accepts": [{ "scheme": "exact", "network": "eip155:8453", "amount": "11000", "payTo": "0x…", "maxTimeoutSeconds": 300 }], "error": "Payment Required", "message": "Enrolling a Virtual Portrait costs $0.0110 USDC. …", "price": { "amount": "0.0110", "currency": "USD" }, "paymentInfo": { "network": "base", "asset": "USDC", "x402Version": 2 } }` — `x402Version`/`accepts` mirror the header's challenge for clients that only read the body
2. Sign the EIP-3009 transfer authorization for **$0.011 USDC on Base** (`$0.01` enrolment + `$0.001` transaction fee — the requirements say `11000` micro-USDC)
3. **Retry the same request with `X-Payment: <base64>`** (`Payment-Signature` is accepted too) → server verifies, rejects a reused authorization (`402`, `code: "PAYMENT_REPLAY"`), registers the portrait, settles the payment after registration succeeds, returns the `ta_xxx`

Expand Down
2 changes: 2 additions & 0 deletions docs/products/creation/music-generation.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ Same x402 flow as all BlockRun endpoints:
```json
// 402 response body
{
"x402Version": 2,
"accepts": [{ "scheme": "exact", "network": "eip155:8453", "amount": "157500", "asset": "0x8335…", "payTo": "0x…", "maxTimeoutSeconds": 300 }],
"error": "Payment Required",
"price": { "amount": "0.158500", "currency": "USD" },
"generation_info": {
Expand Down
8 changes: 8 additions & 0 deletions docs/resources/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ description: All notable changes to BlockRun — gateway endpoints, model lineup

All notable changes to BlockRun, newest first — gateway endpoints, model lineup, pricing, and SDK releases.

## [2026-08-30]

### Fixed — 402 responses now carry the payment challenge in the body, not just the headers
- Every `402 Payment Required` body now spreads `x402Version` and `accepts` at the top level, mirroring the signed challenge that has always lived in the `PAYMENT-REQUIRED` / `X-Payment-Required` / `WWW-Authenticate` headers. Pre-v2-era x402 clients (early `x402-fetch`/`x402-axios`, and some third-party wrappers) only ever parsed the body; finding no top-level `accepts` there, they silently gave up instead of auto-paying — invisible in our logs, indistinguishable from organic non-conversion.
- Applies across every paid endpoint — chat completions, responses, messages, images, video, music, speech, search, market data, RPC, Modal sandboxes, RealFace, Virtual Portrait, and Polymarket funding. A route's own fields still win on any key collision with the mirrored ones. ([BlockRunAI/blockrun#446](https://github.com/BlockRunAI/blockrun/pull/446))

---

## [2026-08-29]

### Removed — OpenAI GPT-5.3
Expand Down
2 changes: 1 addition & 1 deletion docs/x402/how-it-works.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ When you make a request without payment, the server returns HTTP 402 with:
- **Network** - Which blockchain (`eip155:8453` on Base, `solana:…` on the Solana gateway)
- **Validity** - `maxTimeoutSeconds` (300 on most endpoints; longer on async media jobs)

The requirements are base64-encoded in three equivalent headers — `PAYMENT-REQUIRED` (x402 v2), `X-Payment-Required`, and `WWW-Authenticate: X402 requirements="…"` — and the JSON body repeats the price as `price.amount` in USD.
The requirements are base64-encoded in three equivalent headers — `PAYMENT-REQUIRED` (x402 v2), `X-Payment-Required`, and `WWW-Authenticate: X402 requirements="…"` — and the JSON body repeats the price as `price.amount` in USD, plus the challenge itself (`x402Version`, `accepts`) mirrored at the top level for clients that only read the body.

On BlockRun the price for chat is the model's list rate — estimated input tokens plus 10% of `max_tokens` output — with no platform margin, plus a flat **$0.001 transaction fee** per paid call. Media generation (image, video, music, speech) and Live Search carry a 5% margin on top of their list rate, plus the same fee.

Expand Down
Loading
Loading