Guides
- Quickstart
- Authentication and keys
- Key protection
- Models, aliases and fallbacks
- Chat completions
- Streaming
- Structured outputs and tools
- Logprobs
- Vision
- Responses, Claude and Ollama
- Embeddings, rerank, audio, images
- Files and batches
- LoRA adapters
- Project tags and costs
- Prefix caching
- Headers, rate limits and spend caps
- Errors
- Privacy and retention
- Verifiable receipts
- Pricing
- Billing
- Pay per request (x402)
- Status
- SDKs
- Integrations
- Run a node
- Architecture
- Changelog
API reference
Guide
Pay per request (x402)
No account and no API key: the request pays for itself in USDC from your wallet, and whatever it does not use stays yours as credit.
Pay per request is available when it is switched on for the deployment. Where it is off, a request without a key is refused with 401 as always, and nothing on this page applies.
What x402 is
x402 is an open protocol for paying over plain HTTP, built on the status code HTTP has always reserved for it, 402 Payment Required. The server answers an unpaid request with what it accepts (scheme, network, token, amount, recipient). The client signs a payment that matches, sends the same request again with the payment in a header, and the server settles it on chain and answers the request.
The payment is an EIP-3009 transferWithAuthorization for USDC (the exact scheme): your wallet signs an authorization to move that exact amount to Silicon Network's receive address, and a facilitator submits it, so you need USDC on Base but no ETH for gas. The signature authorizes that one transfer and nothing else, and it expires after a few minutes.
What it costs
Each paid request currently carries a deposit of $0.05 in USDC on Base. The deposit is credited to the paying wallet's account, and the request runs against that balance at the normal per-token price (see Pricing and the pricing page), the same as a request with a key.
What the request does not use stays as credit on the paying wallet's account. A short chat completion with a small model costs a small fraction of a cent, so one deposit usually leaves most of it behind.
The paying wallet's account
The first payment from a wallet opens an account for it: the same account you get by signing in with that wallet on the sign-in page (choose Wallet). Sign in there to see the balance, top up, and create API keys. Once you have a key, send it instead, and requests are billed to the balance with no payment each time.
A wallet you already bound to an organization for top-ups credits that organization instead. Sign in to it with that account's email as usual; the sign-in page refuses to open a second account for the wallet.
The exchange
Only requests that reach a model take part (chat completions, Responses, Claude Messages, embeddings and the other inference endpoints). Listing models with GET /v1/models is unchanged.
1. A request without a key answers 402
curl -si https://api.siliconnetwork.io/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model": "llama-3.2-3b", "messages": [{"role": "user", "content": "Hello"}]}'
HTTP/2 402
content-type: application/json
payment-required: eyJ4NDAyVmVyc2lvbiI6Miwi...
{"x402Version": 1, "error": "payment required", "accepts": [...],
"detail": "Send an API key (Authorization: Bearer <key>), or pay $0.05 in USDC on Base with x402 ..."}The PAYMENT-REQUIRED header is the x402 v2 answer, base64 encoded JSON. Decoded, it names the request and what pays for it:
{
"x402Version": 2,
"error": "payment required",
"resource": {
"url": "https://api.siliconnetwork.io/v1/chat/completions",
"description": "Silicon Network API request, paid with an x402 deposit charged per token; unused credit stays on the paying wallet's account",
"mimeType": "application/json"
},
"accepts": [
{
"scheme": "exact",
"network": "eip155:8453",
"amount": "50000",
"asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"payTo": "<Silicon Network's receive address on Base>",
"maxTimeoutSeconds": 120,
"extra": { "name": "USD Coin", "version": "2" }
}
]
}amount is in the token's smallest unit: USDC has 6 decimals, so 50000 is $0.05. The body carries the same requirements in the x402 v1 form (maxAmountRequired, network: "base", the resource fields inline), so clients written for either version work, plus a detail sentence for a person reading it.
2. The client pays and sends the request again
The client signs the authorization with the wallet and repeats the request with the payment, base64 encoded JSON, in PAYMENT-SIGNATURE (x402 v2) or X-PAYMENT (v1). The gateway checks it, has it settled, waits for the transfer on chain, credits the wallet's account, and runs the request.
3. The answer says what was paid
The response is the normal one, streaming included, with PAYMENT-RESPONSE (and X-PAYMENT-RESPONSE for v1 clients) added: base64 encoded JSON of the settlement.
{
"success": true,
"transaction": "0x<the transfer's hash on Base>",
"network": "eip155:8453",
"payer": "0x<your wallet>"
}A payment that does not check out (wrong amount, wrong recipient, expired, a bad signature, or a transfer that failed) answers 402 again with fresh requirements and a PAYMENT-RESPONSE whose success is false and whose errorReason says why. A payment header that is not base64 JSON answers 400.
Headers
| Header | Direction | What it carries |
|---|---|---|
| PAYMENT-REQUIRED | response | On a 402: the x402 v2 payment requirements, base64 encoded JSON. |
| PAYMENT-SIGNATURE | request | The signed payment, x402 v2, base64 encoded JSON. |
| X-PAYMENT | request | The same for x402 v1 clients. Read only when PAYMENT-SIGNATURE is absent. |
| PAYMENT-RESPONSE | response | The settlement: success, transaction, network and payer, or errorReason on failure. |
| X-PAYMENT-RESPONSE | response | The same settlement, for x402 v1 clients. |
A request that carries an API key never sees any of this: the key decides, as it always has.
With an x402 client
An x402 client library does the exchange for you: it reads the 402, signs a matching payment with your wallet, and retries. An example in TypeScript with x402-fetch and viem, for a script that holds its own wallet key:
import { decodeXPaymentResponse, wrapFetchWithPayment } from "x402-fetch";
import { privateKeyToAccount } from "viem/accounts";
// A wallet with USDC on Base. Keep its key out of source control.
const account = privateKeyToAccount(process.env.WALLET_PRIVATE_KEY as `0x${string}`);
const fetchWithPayment = wrapFetchWithPayment(fetch, account);
const res = await fetchWithPayment("https://api.siliconnetwork.io/v1/chat/completions", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
model: "llama-3.2-3b",
messages: [{ role: "user", content: "Hello" }],
}),
});
console.log((await res.json()).choices[0].message.content);
console.log(decodeXPaymentResponse(res.headers.get("x-payment-response")!));This is an example, not a Silicon Network SDK: the library and its options are its own, so check its documentation for the version you install. It caps what it will pay per request, by default above the current deposit.