Skip to main content

Overview

NanoGPT supports accountless API calls for selected endpoints. A client can send a normal request without Authorization or x-api-key, receive 402 Payment Required, pay through one of the advertised rails, then call the quoted completeUrl, replay the original endpoint with X-PAYMENT, or replay the original endpoint with Authorization: L402 <token>:<preimage> for Lightning L402. Live demo: https://nano-gpt.com/x402 Only endpoints returned by GET /api/v1/x402/endpoints should be treated as public accountless x402 endpoints. Treat broad x402 support claims as release-gated by live smoke tests against localhost and production. Streaming chat/responses and long-running video generation have implementation coverage but are not the stable public contract yet.

Endpoint Matrix

The supported endpoint matrix is machine-readable. Its schemes list reflects the payment rails enabled in the current deployment.
curl https://nano-gpt.com/api/v1/x402/endpoints
As of 2026-06-14, production advertises lightning-l402 on the public endpoints listed below. Continue to use GET /api/v1/x402/endpoints as the source of truth because enabled rails can be deployment-gated. Use ?supported=all to include beta and deferred routes:
curl "https://nano-gpt.com/api/v1/x402/endpoints?supported=all"
If x402 is disabled, payment storage is unavailable, or completion replay is not configured, the default supported list is empty. The matrix is generated from lib/x402/publicEndpointContract.ts, which is also used by the runnable smoke test examples. Current public accountless endpoints:
MethodEndpointStable accountless scopeQuote typeNotes
POST/api/v1/images/generationsJSON requestsdeterministicImage generation.
POST/api/v1/images/editsJSON requestsdeterministicMultipart uploads require normal auth before conversion.
POST/api/v1/chat/completionsnon-streaming requestsestimated with reconciliationSet stream: false or omit streaming.
POST/api/v1/responsesnon-streaming requestsestimated with reconciliationStreaming and background mode are not stable accountless contract.
POST/api/v1/data/web/searchJSON requestsdeterministicPublic v1 data path for web search.
POST/api/v1/data/url/scrapeJSON requestsdeterministicPublic v1 data path for URL scraping. Use urls: [...].
Only endpoints that return a valid 402 quote in smoke tests should be listed as supported. Do not assume other API endpoints support accountless payment until they appear as supported in the matrix and have passed live smoke tests.

Payment Schemes

Production 402 quotes currently advertise these schemes when enabled:
Public schemeNetworkAssetFlow
nanonano-mainnetXNOSend XNO to a unique Nano address, then call completeUrl.
nano-exactNano mainnet exact settlementXNOSign an exact payment payload and replay the original request with X-PAYMENT.
base-usdcBaseUSDCSend USDC on Base to a unique address, then call completeUrl.
x402-exactBaseUSDCUse an EIP-3009 authorization in X-PAYMENT, then replay the original request.
x402-solana-usdcSolana/SVMUSDCUse a Solana/SVM exact payment in X-PAYMENT, then replay the original request.
lightning-l402bitcoin-lightningsatsPay the Lightning invoice, then replay the original request with Authorization: L402 <token>:<preimage>.
Solana USDT and native SOL are not documented x402 exact rails. Do not list either as a supported accountless x402 scheme until it appears in GET /api/v1/x402/endpoints.

Working Quote Examples

All examples below intentionally omit Authorization and x-api-key.

Text Chat

curl -i https://nano-gpt.com/api/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-4.1-nano",
    "messages": [{"role": "user", "content": "Say ok"}],
    "stream": false
  }'

Image Generation

curl -i https://nano-gpt.com/api/v1/images/generations \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-image-1",
    "prompt": "a product photo of a brushed steel desk lamp",
    "size": "1024x1024",
    "n": 1
  }'
curl -i https://nano-gpt.com/api/v1/data/web/search \
  -H "Content-Type: application/json" \
  -d '{
    "query": "NanoGPT x402 accountless payments",
    "max_results": 3
  }'

URL Scrape

curl -i https://nano-gpt.com/api/v1/data/url/scrape \
  -H "Content-Type: application/json" \
  -d '{
    "urls": ["https://nano-gpt.com"]
  }'

Flow 1: Quote, Pay, Complete

Send a normal unauthenticated request:
curl -i https://nano-gpt.com/api/v1/images/generations \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-image-1",
    "prompt": "a product photo of a brushed steel desk lamp",
    "size": "1024x1024",
    "n": 1
  }'
For accountless payment challenges, key off the stable top-level payment object. The error object is kept for OpenAI-compatible error handling and may vary by endpoint. The legacy accepts, x402Version, and top-level requestHash fields may still appear for backwards compatibility and advanced protocol clients.
{
  "error": {
    "type": "insufficient_quota",
    "code": "insufficient_quota",
    "message": "Payment required to complete this request."
  },
  "payment": {
    "version": 1,
    "paymentId": "pay_...",
    "requestHash": "sha256:...",
    "expiresAt": "2026-06-09T12:00:00.000Z",
    "amountUsd": "0.0714",
    "statusUrl": "https://nano-gpt.com/api/x402/status/pay_...",
    "completeUrl": "https://nano-gpt.com/api/x402/complete/pay_...",
    "accepted": [
      {
        "scheme": "nano",
        "protocolScheme": "nano",
        "network": "nano-mainnet",
        "amount": "...",
        "amountFormatted": "0.17067988 XNO",
        "amountUsd": "0.0714",
        "payTo": "nano_...",
        "paymentId": "pay_...",
        "statusUrl": "https://nano-gpt.com/api/x402/status/pay_...",
        "completeUrl": "https://nano-gpt.com/api/x402/complete/pay_..."
      },
      {
        "scheme": "x402-solana-usdc",
        "protocolScheme": "exact",
        "network": "solana",
        "amount": "1500",
        "amountFormatted": "0.0015 USDC",
        "amountUsd": "0.0015",
        "payTo": "<solana treasury address from quote>",
        "asset": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
        "feePayer": "<solana facilitator fee payer from quote>",
        "paymentId": "pay_...",
        "expiresAt": "2026-06-09T12:00:00.000Z"
      },
      {
        "scheme": "lightning-l402",
        "protocolScheme": "lightning-l402",
        "network": "bitcoin-lightning",
        "amount": "9",
        "amountFormatted": "9 sats",
        "amountUsd": "0.0054",
        "payTo": "lnbc...",
        "invoice": "lnbc...",
        "paymentHash": "...",
        "l402Token": "...",
        "discountRate": 0.1,
        "undiscountedAmountUsd": "0.006"
      }
    ]
  },
  "x402Version": 1,
  "accepts": []
}
Treat the presence of payment as the accountless payment signal; do not depend on a single legacy error.code value. Top-level payment.statusUrl and payment.completeUrl mirror the primary advertised payment option when that option is a polling-style rail. When choosing a specific payment scheme, prefer the fields inside that option in payment.accepted[]. Exact replay options such as nano-exact, x402-exact, and x402-solana-usdc do not include statusUrl or completeUrl; successful replay settles through the X-PAYMENT response path rather than updating the original quote record. Lightning L402 options also do not use completeUrl; successful completion is the replay of the original endpoint with the Authorization: L402 <token>:<preimage> header. After paying a nano or base-usdc quote, call:
curl -i -X POST "https://nano-gpt.com/api/x402/complete/pay_..."
Completion replays the stored original request. A payment is bound to the original method, path, body hash, quoted amount, and expiration. Expired, underpaid, already processing, or already completed payments are rejected. Nano quote-and-complete rails use scheme: "nano" and a unique payTo Nano address. Base USDC quote-and-complete rails use scheme: "base-usdc" and a unique Base address. For either rail, clients should copy the option-specific amountFormatted, payTo, statusUrl, and completeUrl from payment.accepted[].

Flow 2: x402 Exact Replay

For nano-exact, x402-exact, and x402-solana-usdc, sign the advertised exact payment requirement and replay the original endpoint with:
curl -i https://nano-gpt.com/api/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "X-PAYMENT: $BASE64_PAYMENT_PAYLOAD" \
  -d '{
    "model": "gpt-4.1-nano",
    "messages": [{"role": "user", "content": "Say ok"}]
  }'
Successful exact-settlement responses include X-PAYMENT-RESPONSE when a settlement hash is available. For Solana USDC, select the x402-solana-usdc option from payment.accepted[] and use an x402 Solana/SVM-compatible client, such as @x402/svm, to create and sign the exact payment from the quote requirements. amount is in USDC atomic units with 6 decimals. asset is the Solana USDC mint, EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v. Copy payTo and feePayer from the quote; do not hardcode either value. Lower-level x402 clients can also read the top-level accepts[] protocol object. For Solana USDC exact payments, it uses the official exact shape:
{
  "scheme": "exact",
  "network": "solana",
  "asset": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
  "maxAmountRequired": "1500",
  "payTo": "<solana treasury address from quote>",
  "extra": {
    "feePayer": "<solana facilitator fee payer from quote>",
    "tokenSymbol": "USDC",
    "tokenDecimals": 6
  }
}
The exact replay request must use the same method, path, and JSON body that produced the quote:
curl -i https://nano-gpt.com/api/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "X-PAYMENT: $BASE64_PAYMENT_PAYLOAD" \
  -d '{
    "model": "gpt-4.1-nano",
    "messages": [{"role": "user", "content": "Say ok"}],
    "stream": false
  }'
NanoGPT validates exact X-PAYMENT replay against the quoted resource, amount, and expiration. Clients should replay the same request they quoted unless endpoint docs state otherwise. Example Solana USDC replay:
curl -i https://nano-gpt.com/api/v1/data/url/scrape \
  -H "Content-Type: application/json" \
  -H "X-PAYMENT: $BASE64_SOLANA_X402_PAYMENT" \
  -d '{
    "urls": ["https://nano-gpt.com"]
  }'
Successful Solana exact-settlement responses include a base64 JSON X-PAYMENT-RESPONSE header. After decoding, the shape is:
{
  "success": true,
  "hash": "<solana transaction signature>",
  "network": "solana"
}
The full live Solana USDC x402 flow was tested successfully on 2026-06-09 against POST https://nano-gpt.com/api/v1/data/url/scrape. The request paid 1500 atomic USDC, or $0.0015, via x402-solana-usdc and returned 200 with an X-PAYMENT-RESPONSE header for network: "solana". On-chain Solana signature:
5yqd8zJCNMqJBShKboJkDr4fDyFiWe8cawC6gGCuYD2zwqrbSUhQYws3w5YdEMeCL2cpyhuWG5en7zMYabjZyJRx

Flow 3: Lightning L402 Replay

NanoGPT also supports Lightning L402 for accountless API payments. Instead of signing an X-PAYMENT payload, the client pays a Lightning invoice and proves payment by replaying the original request with the invoice preimage. Send the original request without Authorization or x-api-key:
curl -i https://nano-gpt.com/api/v1/data/web/search \
  -H "Content-Type: application/json" \
  -d '{
    "query": "latest AI agent payment protocols",
    "max_results": 3
  }'
When lightning-l402 is enabled, the 402 Payment Required response includes a Lightning option in payment.accepted[] and a WWW-Authenticate: Payment ... challenge header. For most API clients, the easiest path is to read payment.accepted[].invoice or payment.accepted[].payTo, then read payment.accepted[].l402Token for the replay token. The challenge header is useful for clients that already implement L402 or HTTP auth challenge handling. Example Lightning option:
{
  "scheme": "lightning-l402",
  "protocolScheme": "lightning-l402",
  "network": "bitcoin-lightning",
  "amount": "9",
  "amountFormatted": "9 sats",
  "amountUsd": "0.0054",
  "payTo": "lnbc...",
  "invoice": "lnbc...",
  "paymentHash": "...",
  "l402Token": "...",
  "discountRate": 0.1,
  "undiscountedAmountUsd": "0.006"
}
The WWW-Authenticate challenge includes the same token in id="<token>" and a base64-encoded request value:
WWW-Authenticate: Payment id="<token>", realm="https://nano-gpt.com", method="lightning", intent="charge", request="<base64-json>", description="...", expires="..."
After decoding the request value, the JSON contains the Lightning invoice:
{
  "amount": "9",
  "currency": "sat",
  "methodDetails": {
    "invoice": "lnbc...",
    "network": "mainnet",
    "paymentHash": "..."
  }
}
Pay the advertised invoice with a Lightning wallet, node, or payment API that returns the payment preimage. Some consumer Lightning wallets do not expose the payment preimage; L402 clients need a wallet, node, or payment API that returns it after payment. Replay the exact original request with the same method, path, and JSON body, adding:
Authorization: L402 <token>:<preimage>
curl -i https://nano-gpt.com/api/v1/data/web/search \
  -H "Content-Type: application/json" \
  -H "Authorization: L402 $L402_TOKEN:$PAYMENT_PREIMAGE" \
  -d '{
    "query": "latest AI agent payment protocols",
    "max_results": 3
  }'
For chat completions, keep accountless L402 requests non-streaming:
curl -i https://nano-gpt.com/api/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: L402 $L402_TOKEN:$PAYMENT_PREIMAGE" \
  -d '{
    "model": "gpt-4.1-nano",
    "messages": [{"role": "user", "content": "Say ok"}],
    "stream": false
  }'
The L402 token is bound to the original method, path, request body hash, amount, and expiration. The token/preimage pair is single-use and expires with the quote. Lightning L402 quotes currently receive a 10% discount versus the normal accountless quote; when present, the Lightning option exposes discountRate and undiscountedAmountUsd. Minimal client logic:
const original = {
  path: '/api/v1/data/web/search',
  body: {
    query: 'latest AI agent payment protocols',
    max_results: 3,
  },
};

const quoteResponse = await fetch(`https://nano-gpt.com${original.path}`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(original.body),
});

if (quoteResponse.status !== 402) {
  throw new Error(`Expected 402, got ${quoteResponse.status}`);
}

const quote = await quoteResponse.json();
const lightning = quote.payment.accepted.find(
  (option: any) => option.scheme === 'lightning-l402'
);

if (!lightning) {
  throw new Error('Lightning L402 is not advertised for this endpoint');
}

// Pay lightning.invoice with a Lightning client that returns the preimage.
const preimage = await payLightningInvoiceAndReturnPreimage(lightning.invoice);

const paidResponse = await fetch(`https://nano-gpt.com${original.path}`, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: `L402 ${lightning.l402Token}:${preimage}`,
  },
  body: JSON.stringify(original.body),
});

const result = await paidResponse.json();
console.log(result);

Status Polling

For quote-and-complete rails such as nano and base-usdc, use the quoted statusUrl to watch payment state:
curl "https://nano-gpt.com/api/x402/status/pay_..."
Known statuses:
  • pending
  • underpaid
  • paid
  • processing
  • completed
  • failed
  • refunded
  • expired
Status responses include pollAfterSeconds, plus Retry-After and X-Poll-After headers. Async media status URLs are not documented as stable accountless x402 behavior until signed unauthenticated status and media URL behavior is smoke-tested and expiration is explicitly documented.

Reconciliation

Image and data endpoint quotes are deterministic for the submitted request parameters. Chat Completions and Responses quotes are estimates and are reconciled after the provider returns usage. If provider execution fails after direct x402 settlement, the endpoint-specific failure path attempts the documented refund or failed-fee reconciliation. For completeUrl, NanoGPT replays the stored original request, so the completed request is bound to the quoted method, path, and body. For exact X-PAYMENT replay, NanoGPT validates the payment against the quoted resource, amount, and expiration. For Lightning L402 replay, NanoGPT validates the token and preimage against the quoted method, path, request body hash, amount, and expiration. Clients should replay the same request they quoted unless endpoint docs state otherwise. Tool follow-up replay is separately constrained to trusted tool-call continuations. Do not assume every accountless x402 payment is an exact final charge.

Helper Examples And Smoke Tests

Helper examples live in examples/x402. They cover:
  • quote request
  • choosing a payment rail
  • status polling
  • completeUrl
  • exact replay with X-PAYMENT
  • Lightning L402 replay with Authorization: L402 <token>:<preimage>
  • expired, underpaid, and failed completion handling via status/complete responses
Run the smoke tests against localhost or production:
pnpm x402:smoke -- --base http://localhost:3000
pnpm x402:smoke -- --base https://nano-gpt.com
Paid smoke paths are opt-in because the payment payload is wallet-specific:
X402_PAYMENT_HEADER="$BASE64_PAYMENT_PAYLOAD" pnpm x402:smoke -- --endpoint chat-completions
X402_COMPLETE_URL="https://nano-gpt.com/api/x402/complete/pay_..." pnpm x402:smoke

Safety Notes

  • completeUrl payments are bound to the original request method, path, body hash, quote amount, and expiration.
  • Exact X-PAYMENT replay is validated against the quoted resource, amount, and expiration.
  • Lightning L402 replay is validated against the quoted method, path, request body hash, amount, and expiration.
  • Authorization: L402 <token>:<preimage> is bearer payment proof. Do not log full L402 authorization headers.
  • Expired payments cannot be completed.
  • Underpaid payments cannot be completed.
  • Completed or processing payments cannot be completed twice.
  • Store the original request only as long as needed for payment completion.
  • Do not log X-PAYMENT payloads, private keys, provider credentials, or full request bodies beyond existing request logging policy.