Developer docs

Build against the oracle

A price oracle that machines pay per request over x402. No API keys, no accounts. Trigger a real 402 in one command, decode the terms, and pay from code. Everything here is verified against the live API.

Base URL
https://keeta-oracle-bounty-2mz3sjj2zq-ue.a.run.app

Quickstart: your first machine paywall

About 60 seconds, and free. No signup and no key: one command triggers a real refusal from the live API.

Step 1. Trigger a real 402.

No signup, no key.

curl -si "https://keeta-oracle-bounty-2mz3sjj2zq-ue.a.run.app/api/getPrice?pair=BTC-USD" | grep -i payment-required

You get one long base64 string. That is not an error; that is the price tag. Machines decode it automatically. To peek inside it yourself:

Step 2. Decode the terms.

curl -s -D - -o /dev/null "https://keeta-oracle-bounty-2mz3sjj2zq-ue.a.run.app/api/getPrice?pair=BTC-USD" \
  | tr -d '\r' | awk 'tolower($1)=="payment-required:"{print $2}' \
  | python3 -c "import sys,base64,json; print(json.dumps(json.loads(base64.b64decode(sys.stdin.read().strip())), indent=2))"

You will see plain JSON: the scheme (exact), the network (Solana devnet), the asset (USDC), the amount (5000 base units = $0.005 at USDC's six decimals), where to pay, and the fee sponsor. This is the x402 v2 protocol: the entire price negotiation fits in one response header.

Step 3. Pay it from code.

See Pay from code below for a complete runnable buyer. The short version: an x402 client library reads those terms, signs a USDC transfer, retries the request with a PAYMENT-SIGNATURE header, and gets the data. Fees are sponsored, so the buying wallet needs only the USDC it spends, zero SOL.

API reference

All error responses:

{ "error": { "code": "STRING_CODE", "message": "text" } }
GET/api/healthfree
200 { "ok": true, "pairs": ["KTA-USD","BTC-USD","ETH-USD","SOL-USD","USDC-USD"] }
GET/api/getPrice?pair=BTC-USDpaid, $0.005
200 { "pair", "price", "sourceTimestamp", "fetchedAt", "cached" }
GET/api/getPriceHistory?pair=BTC-USD&days=7paid, $0.005
200 { "pair", "days", "points": [{ "timestamp", "usd" }], "fetchedAt" }
  • days: 1 to 90.
POST/api/subscribepaid, $0.005
201 { "id", "endpoint", "pairs" }
  • Body: { "endpoint": "https://your-server.example/hook", "pairs": ["BTC-USD"] }
  • Your endpoint then receives POST { "subscriptionId", "updates": [{ "pair", "price", "sourceTimestamp", "fetchedAt" }] } on a roughly 30-second tick.
  • Consumers that fail delivery three times in a row are detached.
  • Endpoint rules: http/https only, and hosts that resolve to private, loopback, or link-local addresses are refused (400 INVALID_ENDPOINT).
POST/api/demo/runfree, rate-limited
Full step timeline, including the fresh devnet settlement signature.
  • Body: { "pair": "BTC-USD" }. The server's own agent buys one price from the oracle and returns the run.
  • Limits: 3 runs per minute per caller, capped daily (429 RATE_LIMITED / 429 DAILY_CAP).
  • Built for the demo, fun to script against, but the paid endpoints are the product.

Freshness semantics

  • sourceTimestamp is the upstream source's own last-updated claim (epoch ms). fetchedAt is when this oracle fetched it (epoch ms). An oracle that hides its latency is lying; this one shows both.
  • Prices are cached for at most 15 seconds and never served beyond that window. When upstream is unavailable, you get an explicit 503 UPSTREAM_UNAVAILABLE, never a stale price dressed as current.

Error codes

402 + payment-required headerUnpaid request; terms in the header (x402 v2)
404 UNKNOWN_PAIRPair not served
400 BAD_REQUESTMalformed parameters
400 INVALID_ENDPOINTSubscribe endpoint failed the address rules
429 RATE_LIMITED / 429 DAILY_CAPDemo runner limits
503 UPSTREAM_UNAVAILABLEUpstream data source down; nothing stale served

The refund-free guarantee

Payment settles only after a successful response. Any 4xx cancels the payment; you are never charged for an answer you didn't get. Mechanically: the middleware verifies the payment, runs the request, and only submits settlement when the final status is below 400.

Paying programmatically

Node 20+. A real x402 v2 client against this API on Solana devnet.

Install
mkdir oracle-buyer && cd oracle-buyer && npm init -y
npm install @x402/fetch@2.18.0 @x402/core@2.18.0 @x402/svm@2.18.0 @solana/kit @scure/base

Fund a devnet wallet with USDC, free: generate a keypair (the code below prints the address on first run), then send it devnet USDC from Circle's faucet at faucet.circle.com (choose Solana devnet). No SOL needed.

buy-price.mjs
// buy-price.mjs  (run: node buy-price.mjs)
import { createKeyPairSignerFromPrivateKeyBytes } from '@solana/kit';
import { base58 } from '@scure/base';
import { wrapFetchWithPayment } from '@x402/fetch';
import { x402Client } from '@x402/core/client';
import { ExactSvmScheme } from '@x402/svm/exact/client';
import { readFileSync, writeFileSync, existsSync } from 'node:fs';

// One-time key setup, persisted locally. Fund the printed address with
// devnet USDC from faucet.circle.com, then run again.
let seed;
if (existsSync('devnet-key.txt')) {
  seed = base58.decode(readFileSync('devnet-key.txt', 'utf8').trim());
} else {
  seed = crypto.getRandomValues(new Uint8Array(32));
  writeFileSync('devnet-key.txt', base58.encode(seed));
}
const signer = await createKeyPairSignerFromPrivateKeyBytes(seed, true);
console.log('buyer wallet:', signer.address);

const client = new x402Client();
client.register('solana:*', new ExactSvmScheme(signer));
const fetchWithPay = wrapFetchWithPayment(fetch, client);

const res = await fetchWithPay(
  'https://keeta-oracle-bounty-2mz3sjj2zq-ue.a.run.app/api/getPrice?pair=BTC-USD',
  { headers: { accept: 'application/json' } }
);
console.log('status:', res.status);
console.log('data:', await res.json());
console.log('settlement receipt:', res.headers.get('payment-response'));

What happens on that one fetchWithPay call

The library makes the request, receives the 402, reads the terms from the header, signs a USDC TransferChecked with the facilitator as fee payer, retries with the PAYMENT-SIGNATURE header, and hands you the 200. The payment-response header is base64 JSON containing the on-chain transaction signature; look it up on any Solana explorer (devnet cluster).

How x402 works here

  1. 1

    Client requests a paid resource with no payment. Server answers 402 and puts machine-readable terms in the payment-required response header (base64 JSON; v2 of the protocol).

  2. 2

    Client picks acceptable terms, constructs a payment (on Solana: a partially signed USDC transfer where the facilitator pays the network fee), and retries with the PAYMENT-SIGNATURE request header.

  3. 3

    A facilitator verifies the payment, the server serves the response, and settlement is submitted on-chain only after success. The receipt travels back in the payment-response header.

Properties worth naming: no accounts, no API keys, no subscriptions, no stored payment methods; price discovery is in-band; refusals are free; buyers need only the stablecoin they spend. This instance settles on Solana devnet so anyone can try it with faucet funds. The same stack has settled on Solana mainnet with real USDC; receipts are on the main page.

The FX anchor

The same project includes an FX anchor on Keeta testnet built on the anchor SDK: it holds a float, quotes KTA to USD conversions, and settled real exchanges end to end, with its endpoints discovered through on-chain resolver metadata rather than any registry. The oracle's own service record is published the same way under the same account. This is what "anchor" means in the Keeta ecosystem: a service whose existence, endpoints, and offerings are readable from the chain itself.

FAQ

Is this devnet or real money?

The public instance settles on Solana devnet so trying it is free. The identical stack has settled real USDC on Solana mainnet; the receipts on the main page link to the mainnet transactions.

See the mainnet receipts

Why does my wallet need zero SOL?

The facilitator sponsors network fees in the exact-payment scheme; open any settlement on an explorer and you will see the fee paid by the sponsor's account, not the buyer's.

What if I pay and the request fails?

You don't pay. Settlement only happens after a successful response; any refusal cancels the payment.

Where does the price data come from?

CoinGecko. The oracle also demonstrates buying its upstream data over x402 (the same protocol it sells with), paid per request.

Who runs this?

Web3Pizza, Dodona Labs. Built on x402, Keeta, and Solana; not endorsed by or affiliated with any of them.

Can I rely on this for production?

It's a live demonstration and bounty build: a testnet-anchored oracle with mainnet payment demos. Talk to us before depending on it.