API Reference
Complete documentation for Blocky402 facilitator API endpoints. The wire
format is x402 v2 (x402Version: 2); the facilitator does not accept
v1 envelopes.
Base URLs
- Testnet:
https://api.testnet.blocky402.com(orhttp://localhost:3002for local development) - Mainnet:
https://api.blocky402.com/v1(coming soon)
Authentication
- Testnet: No authentication required (open access)
- Mainnet: API key required in
X-Api-Keyheader (format:b402_<64_character_hex_string>)
Endpoints
GET /supported
Returns supported payment schemes and networks for the current environment.
Request:
GET /supported
Response:
{
"kinds": [
{ "scheme": "exact", "network": "eip155:80002", "x402Version": 2 },
{
"scheme": "exact",
"network": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
"x402Version": 2,
"extra": { "feePayer": "7B6Q2MvcJvNcy1A13wHmAzmmdo3L8DVriaXML7bvkojm" }
},
{
"scheme": "exact",
"network": "hedera:testnet",
"x402Version": 2,
"extra": { "feePayer": "0.0.7162784" }
}
],
"extensions": [],
"signers": {
"eip155:*": ["0xDCF7D72C2eE049DE4269ac6AAf925F33efdA18de"],
"solana:*": ["7B6Q2MvcJvNcy1A13wHmAzmmdo3L8DVriaXML7bvkojm"],
"hedera:*": ["0.0.7162784"]
}
}
Solana and Hedera entries carry extra.feePayer — the account the facilitator co-signs as. Clients must place the same value into paymentRequirements.extra.feePayer when building the payment payload, or the client SDK will throw before signing.
Status Codes:
200 OK: Success401 Unauthorized: Invalid or missing API key (mainnet only)429 Too Many Requests: Rate limit exceeded
POST /verify
Verifies a payment payload against the x402 protocol. Three input formats
are accepted; the canonical form is paymentPayload (object) in the body,
matching @x402/[email protected] httpFacilitatorClient.
Request (canonical — paymentPayload object, Hedera example):
The same HTTP envelope works for EVM and SVM — only the payload shape inside paymentPayload differs (see Payload shapes by scheme below). Hedera additionally requires extra.feePayer and must match the fee-payer the facilitator advertises in GET /supported.
POST /verify
Content-Type: application/json
{
"x402Version": 2,
"paymentPayload": {
"x402Version": 2,
"scheme": "exact",
"network": "hedera:testnet",
"accepted": {
"scheme": "exact",
"network": "hedera:testnet",
"amount": "100000",
"payTo": "0.0.8011510",
"maxTimeoutSeconds": 300,
"asset": "0.0.0",
"extra": { "feePayer": "0.0.7162784" }
},
"payload": {
"transaction": "<base64-encoded TransferTransaction bytes>"
}
},
"paymentRequirements": {
"scheme": "exact",
"network": "hedera:testnet",
"amount": "100000",
"payTo": "0.0.8011510",
"maxTimeoutSeconds": 300,
"asset": "0.0.0",
"extra": { "feePayer": "0.0.7162784" }
}
}
Request (x402 spec — X-PAYMENT header): the same paymentPayload
object, base64-encoded, sent in the X-PAYMENT header. The body then
only carries paymentRequirements.
POST /verify
X-PAYMENT: <base64(JSON(paymentPayload))>
Content-Type: application/json
{ "paymentRequirements": { /* same shape as above */ } }
Request (legacy — base64 paymentHeader in body): equivalent to the
X-PAYMENT header form but with the base64 string in the body. Accepted
for backwards-compatibility with pre-2.12 clients.
{
"x402Version": 2,
"paymentHeader": "<base64(JSON(paymentPayload))>",
"paymentRequirements": { /* same shape as above */ }
}
Response (valid):
{
"isValid": true,
"payer": "0.0.7326075"
}
Response (invalid):
{
"isValid": false,
"invalidReason": "InvalidSignature",
"invalidMessage": "Signature recovery did not match the expected payer"
}
Optional response fields: extensions, extra (scheme-specific blobs).
Status Codes:
200 OK: Verification completed (checkisValid)400 Bad Request: Invalid request format, unknown scheme, or unsupported network401 Unauthorized: Invalid or missing API key (mainnet only)429 Too Many Requests: Rate limit exceeded
POST /settle
Settles a payment by broadcasting the transaction. Same three input
formats as /verify; the body shape is identical (you can reuse the
same paymentPayload + paymentRequirements pair).
Request: identical to /verify. POST to /settle instead.
Response (success):
{
"success": true,
"transaction": "[email protected]",
"network": "hedera:testnet",
"payer": "0.0.7326075"
}
The transaction field is network-native: 0.0.<feePayer>@<seconds>.<nanos> for Hedera, a 0x… hash for EVM, base58 signature for SVM.
Response (error):
{
"success": false,
"errorReason": "transaction_failed",
"errorMessage": "TOKEN_NOT_ASSOCIATED_TO_ACCOUNT",
"transaction": "",
"network": "hedera:testnet"
}
Optional response fields: amount (for schemes that allow partial
settlement, e.g. upto), extensions, extra.
Status Codes:
200 OK: Settlement attempt completed (checksuccess)400 Bad Request: Invalid request format, unknown scheme, or unsupported network401 Unauthorized: Invalid or missing API key (mainnet only)429 Too Many Requests: Rate limit exceeded
GET /health
Health check endpoint for monitoring API status.
Request:
GET /health
Response:
{
"status": "ok",
"timestamp": "2026-05-17T10:30:00Z",
"version": "1.0.0"
}
Status Codes:
200 OK: Service is healthy
Payload shapes by scheme
The paymentPayload.payload field is scheme-specific. The facilitator
detects the shape automatically.
Hedera exact (and SVM exact)
{ "transaction": "<base64-encoded transaction bytes>" }
For Hedera this is a partially-signed TransferTransaction produced by @x402/hedera’s ExactHederaScheme.createPaymentPayload(...). The facilitator’s fee-payer co-signs at settlement time.
EVM exact — EIP-3009 (default)
{
"signature": "0x...",
"authorization": {
"from": "0x...", "to": "0x...", "value": "1000000",
"validAfter": "0", "validBefore": "9999999999",
"nonce": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
}
EVM exact — Permit2
{
"signature": "0x...",
"permit2Authorization": {
"from": "0x...", "spender": "0x...",
"nonce": "0", "deadline": "9999999999",
"permitted": { "token": "0x...", "amount": "1000000" },
"witness": { "facilitator": "0x...", "to": "0x...", "validAfter": "0" }
}
}
Rate Limiting
Testnet
- Type: Per-IP
- Limit: 100 requests per minute
- Burst: 10 requests
Mainnet (Coming Soon)
- Type: Per-API-Key
- Limit: 10 requests per second
- Daily Quota: 10,000 settlements per day per key
Error Responses
NestJS-style error bodies on 4xx:
{
"statusCode": 400,
"message": "Network unsupported-network is not supported",
"error": "Bad Request"
}
For validation failures, message is a comma-joined list of constraint
violations, e.g. "Validation failed: amount must be a string, extra should not be null or undefined".
Common Error Messages
| HTTP Status | Trigger |
|---|---|
400 | DTO validation, unknown scheme/network, missing x402Version, malformed base64 |
401 | Mainnet only — missing or invalid X-Api-Key |
429 | Rate limit exceeded |
500 | Unexpected facilitator error |
Payment Flow
- Discover capabilities:
GET /supported - Sign a v2 PaymentPayload using
@x402/hedera,@x402/evm, or@x402/svm - Verify the payment:
POST /verify(checkisValid) - Settle the payment:
POST /settle(checksuccess, readtransaction)
For complete examples, see the Code Examples page.