Docs menu

Getting started

Quickstart

Three steps: see a price, pay it, parse the JSON. Any x402-capable client does the middle step for you — the examples below use the official SDK and the pay CLI.

0 · A wallet with USDC#

Payments are USDC on Solana mainnet. The keypair needs USDC only — the x402 facilitator pays the network fee, so a balance of 0 SOL is fine. A few dollars covers hundreds of calls. No wallet yet? Fund your agent walks through both ways — sign in with Google or email, or fund a keypair yourself; new to crypto entirely, start at Paying, plainly.

Nothing to sign up for with us

There is no Citable account and no key. The wallet is the identity; the 402 header is the invoice; the on-chain transfer is the receipt.

1 · Read the price (free)#

Every paid route answers an unauthenticated request with 402 and a base64 PAYMENT-REQUIRED header. Decode it to see the amount in USDC base units, the mint and the pay-to address.

terminal
$ curl -i https://citable.run/v1/keyword-suggest?seed=seo+api
HTTP/2 402
payment-required: eyJ4NDAyVmVyc2lvbiI6MiwiZXJyb3IiOiJQYXltZW50IHJlcXVpcmVkIiwi…

$ curl -s https://citable.run/v1/keyword-suggest?seed=seo+api -D - -o /dev/null | grep -i payment-required | cut -d' ' -f2 | base64 -d | jq .accepts[0]
{
  "scheme": "exact",
  "network": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
  "amount": "1000",                                         // USDC base units → $0.001
  "asset": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",  // USDC mint
  "payTo": "6nWrWRTqrqpqbu5MsMW8mPDpZjKLwPb9Wf8BdMwNMWzK",
  "maxTimeoutSeconds": 300
}

2 · Pay with the x402 SDK#

wrapFetchWithPayment turns fetch into a client that reads the 402, signs a USDC transfer for the quoted amount, and retries. The settlement transaction comes back in PAYMENT-RESPONSE.

typescript
// bun add @x402/fetch @x402/svm @solana/kit
import { wrapFetchWithPayment, decodePaymentResponseHeader, x402Client } from "@x402/fetch";
import { registerExactSvmScheme } from "@x402/svm/exact/client";
import { toClientSvmSigner } from "@x402/svm";
import { createKeyPairSignerFromBytes } from "@solana/kit";

const keypair = await createKeyPairSignerFromBytes(secretKey); // a wallet holding USDC
const client = registerExactSvmScheme(new x402Client(), { signer: toClientSvmSigner(keypair) });
const paidFetch = wrapFetchWithPayment(fetch, client);

const res = await paidFetch("https://citable.run/v1/onpage-audit?url=https://example.com");
const data = await res.json();
const settlement = decodePaymentResponseHeader(res.headers.get("PAYMENT-RESPONSE")!);
console.log(data.score, settlement.transaction); // 92, 5AS7BF…

Two things the server does on purpose

The 402 carries no recentBlockhash — the client fetches its own, so the challenge can be retried. And payTo is a USDC token account that already exists; no account-creation rent is ever passed to you.

Or: the pay CLI#

Any x402 client works the same way. With pay.sh installed and funded:

terminal
$ pay curl https://citable.run/v1/keyword-metrics?keywords=seo+api
{ "keywords": [ { "keyword": "seo api", "volume": 390, "cpc": 20.98, … } ], … }

3 · Errors are free#

Only a delivered result is settled. A 400 for bad params, a 502 because a data source did not answer, a 503 because an endpoint is not configured — none of them charge anything. Each endpoint page lists its codes.

StatusMeaningCharged
200Result deliveredyes — the quoted price
402No valid payment on the request; the header carries the priceno
4xxBad parameters — the message says whichno
502 / 503Source unavailable, or not configured on this deploymentno

Next#