x402 has two protocol versions. Version 2 is preferred for new integrations. Faremeter supports both versions simultaneously, and the middleware can serve v1 and v2 clients at the same time.
At a glance
| v1 | v2 |
|---|
| Client header | X-PAYMENT | PAYMENT-SIGNATURE |
| Server requirement header | (in response body only) | PAYMENT-REQUIRED |
| Server response header | X-PAYMENT-RESPONSE | PAYMENT-RESPONSE |
| Payload location | Base64-encoded JSON in header | Base64-encoded JSON in header |
Payload includes accepted | No | Yes — echoes the requirement the client chose |
| Status | Supported | Preferred |
Version 1
In v1, the server returns payment requirements in the 402 response body as JSON:
{
"x402Version": 1,
"accepts": [
{
"scheme": "exact",
"network": "solana-devnet",
"asset": "USDC",
"maxAmountRequired": "10000",
"payTo": "7xKX..."
}
]
}
The client sends its payment proof in the X-PAYMENT header:
X-PAYMENT: eyJ4NDAyVmVyc2lvbiI6MSwi...
The decoded payload contains:
{
"x402Version": 1,
"scheme": "exact",
"network": "solana-devnet",
"payload": { /* scheme-specific proof */ }
}
Version 2
v2 uses dedicated HTTP headers for the payment protocol, separating payment data from the response body.
The server returns requirements in both the response body and the PAYMENT-REQUIRED header. On successful payment, it includes a PAYMENT-RESPONSE header with the settlement result.
The client sends its payment proof in the PAYMENT-SIGNATURE header. The v2 payload includes the accepted requirement the client chose, plus resource information:
{
"x402Version": 2,
"payload": { /* scheme-specific proof */ },
"resource": { "url": "https://api.example.com/data", "method": "GET" },
"accepted": {
"scheme": "exact",
"network": "solana-devnet",
"asset": "USDC",
"maxAmountRequired": "10000",
"payTo": "7xKX..."
}
}
Including the accepted requirement in the payload lets the facilitator verify that the client is paying for the correct requirement without relying on the server to re-send it.
Configuring version support
The middleware uses resolveSupportedVersions() to determine which protocol versions to serve. By default, v1 is enabled and v2 is disabled.
import { resolveSupportedVersions } from "@faremeter/middleware/common"
// Default: v1 enabled, v2 disabled
const versions = resolveSupportedVersions()
// Enable both
const versions = resolveSupportedVersions({ x402v1: true, x402v2: true })
// v2 only
const versions = resolveSupportedVersions({ x402v1: false, x402v2: true })
Pass this to createMiddleware or handleMiddlewareRequest:
With createMiddleware (Express)
import { createMiddleware } from "@faremeter/middleware/express"
app.use(
"/api/protected",
await createMiddleware({
facilitatorURL: "https://facilitator.corbits.dev",
accepts,
supportedVersions: resolveSupportedVersions({ x402v1: true, x402v2: true }),
}),
)
With handleMiddlewareRequest
import { handleMiddlewareRequest, resolveSupportedVersions } from "@faremeter/middleware/common"
await handleMiddlewareRequest({
facilitatorURL: "https://facilitator.corbits.dev",
accepts,
supportedVersions: resolveSupportedVersions({ x402v2: true }),
resource: req.url,
// ... other options
})
Migrating from v1 to v2
- Enable both versions during the transition so existing v1 clients continue to work:
resolveSupportedVersions({ x402v1: true, x402v2: true })
- Update clients to use the latest
@faremeter/rides or @faremeter/fetch, which automatically negotiate the highest supported version.
- Disable v1 once all clients have migrated:
resolveSupportedVersions({ x402v1: false, x402v2: true })
Version adapters
If you are running your own facilitator and need to convert between v1 and v2 formats, use the adapter functions from @faremeter/types/x402-adapters:
| Function | Direction |
|---|
adaptPayloadV1ToV2() | v1 payment payload to v2 |
adaptPaymentRequiredResponseV1ToV2() | v1 requirements response to v2 |
adaptSettleResponseV1ToV2() | v1 settle response to v2 |
adaptSettleResponseV2ToV1() | v2 settle response to v1 |
adaptSettleResponseV2ToV1Legacy is deprecated. Use adaptSettleResponseV2ToV1 for spec-compliant v1 output.
Further reading