One agent, one verdict. PromptRat runs a single AI agent instead of a room full of them - every call comes with the numbers behind it. How it works

Paid endpoint

Machine-payable rat report

The rat report is sold over plain HTTP: your wallet broadcasts a real Solana transfer, this server reads the settlement back from mainnet and unlocks the artifact.

Paid to
5wFjTdLyVVrT9SfzonSXxw2EbsGfXvBniSfhhU6auNTP5wFjTd...6auNTP
In explorer

Every payment is a plain SOL transfer from the buyer's own wallet into the deployment wallet below. The server holds no keys and signs nothing.

No key, no signup, no account

The price, the payment terms and the receiving wallet all travel inside the 402 challenge itself, so a client can buy without a human ever opening this page.

Verified on chain

No facilitator and no custodian: the transaction is re-read from Solana mainnet before anything unlocks, so an unpaid request gets a refusal instead of a report.

Holders read it free150,000 $PromptRat

A wallet holding at least the threshold of $PromptRat signs one message and reads the same artifact through the holder pass - no transfer, no fee.

Endpoint right now

READING

Read from /api/x402/rat-report moments ago: the real challenge, the offer, the wallet that receives it, and the field inventory of the artifact. Change the price on the server and this panel follows — none of it is written into the page.

Open raw JSON
resource—
x402 version—
settlement—
transport—

Accepted offers

Nothing is for sale right now — the reply carries no offers.

Raw PAYMENT-REQUIRED header (base64)

This is the whole protocol contract as a machine reads it: a single base64 object in a single response header. Decode it and you hold the price, the wallet and the artifact schema.

No PAYMENT-REQUIRED header came back — this endpoint is not selling.

The same object, decoded
Nothing was returned.

Check a settlement yourself

/api/x402/verify

Paste any mainnet signature, or let the endpoint hunt down the newest real transfer into the receiving wallet. It runs the same verifier as the paid route and reports what it measured: amount that landed, slot, block time and payer — all read off the chain.

Sample mode walks the receiving wallet's history (getSignaturesForAddress → getTransaction) and judges the newest inbound transfer twice: once at the amount it truly moved, once at this endpoint's own price. The scan is reused for 60 s per server instance.

Reading the holder-pass config…
manual mode

Hold at least the threshold in your wallet and the same rat report is served without payment. The wallet signs one plain-text challenge message (signing never moves funds); the server verifies that ed25519 signature, consumes the one-off nonce and reads your balance live from the chain. Below the threshold you get the measured numbers back.

Threshold…
Mint…
EndpointGET|POST /api/x402/holder-pass
Paid endpoint

How a payment lands

Five steps and no middleman. HTTP 402 has been in the spec since 1997 and does nothing by itself — what turns it into a payment rail is a server that can read the chain.

  1. 01
    Ask for the price

    A plain GET returns 402 with the PaymentRequired object base64-encoded in PAYMENT-REQUIRED: the offer, the resource id, the artifact's field inventory and the payload schema.

  2. 02
    Broadcast the transfer yourself

    Your wallet builds and sends a real transaction: 0.005 SOL to the receiving wallet. The server holds no key, signs nothing and never touches the funds.

  3. 03
    Retry carrying PAYMENT-SIGNATURE

    The same request now carries the base64 PaymentPayload whose payload.signature is your transaction signature. A payer field, if present, is an echo — not a claim the server trusts.

  4. 04
    The server checks the chain

    getTransaction re-reads that signature: it must not have failed, must sit inside the accept window, and the pre/post balance tables must show the value landing at the receiving wallet. Transfers routed through a program count the same way.

  5. 05
    Claim, then build

    A first-writer-wins claim burns the signature — one payment, one report — and only then is the artifact assembled and returned together with PAYMENT-RESPONSE.

curl
# 1. no payment yet - read the challenge (the base64 object is in the PAYMENT-REQUIRED header)
curl -i https://promptrat.fun/api/x402/rat-report

# 2. the same request, paid: PAYMENT-SIGNATURE = base64({"x402Version":2,
#    "accepted":{...one offer from the challenge...},"payload":{"signature":"<your tx>"}})
curl -i -H "PAYMENT-SIGNATURE: $PAYLOAD" \
  "https://promptrat.fun/api/x402/rat-report?mint=GxWqJbWPxMseev7WXYNPLEG8K59v2fAhJ5m5o7Yepump"

What a refusal tells you

A 402 from this rail is never a shrug. Each refusal names the reason and carries the numbers measured on chain, so a client can repair its own payment without digging through server logs.

  • The price belongs to the server, not the client. The accepted block is matched on scheme, network, asset and payTo only — editing the echoed amount changes nothing.
  • underpaid carries receivedAtomic, so you see exactly how short the transfer fell; pay_to_received_nothing means the value never reached the wallet at all.
  • payment_expired carries the measured ageSeconds next to the window it was judged against.
  • transaction_failed, transaction_not_readable and balances_not_reported are refusals: a transaction that cannot be read, or has been pruned, never counts as paid.
  • payment_already_redeemed comes from a shared store, so across every instance one signature admits exactly one report.
HTTP/1.1 402 Payment Required
PAYMENT-REQUIRED: eyJ4NDAyVmVyc2lvbiI6MiwicmVzb3VyY2UiOnsidXJsIjoiaHR0cHM6Ly9wcm9tcHRyYXQuZnVuL2FwaS94NDAy...

{
  "error": "underpaid",
  "extensions": {
    "promptrat-report": {
      "info": {
        "lastRejection": { "reason": "underpaid", "receivedAtomic": "10490000000", "ageSeconds": 41, "slot": 448820434 }
      }
    }
  }
}
Paid endpoint

Client code

The full loop in the two ecosystems that settle Solana payments: Node with @solana/web3.js and Python with solders. Notice what neither needs — no API key, no account, no dashboard.

// npm i @solana/web3.js
import { Connection, PublicKey, SystemProgram, Transaction, LAMPORTS_PER_SOL } from "@solana/web3.js";

const ENDPOINT = "https://promptrat.fun/api/x402/rat-report";
const connection = new Connection("https://api.mainnet-beta.solana.com", "confirmed");

// 1. ask for the price - no key, no signup, no account
const challengeRes = await fetch(ENDPOINT);
const challenge = JSON.parse(Buffer.from(challengeRes.headers.get("PAYMENT-REQUIRED"), "base64").toString());
const offer = challenge.accepts.find((o) => o.asset === "So11111111111111111111111111111111111111112");

// 2. pay it yourself: your wallet, your signature, the server never signs anything
const tx = new Transaction().add(SystemProgram.transfer({
  fromPubkey: payer.publicKey,
  toPubkey: new PublicKey(offer.payTo),
  lamports: Number(offer.amount),
}));
tx.feePayer = payer.publicKey;
tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
tx.sign(payer);
const signature = await connection.sendRawTransaction(tx.serialize());
await connection.confirmTransaction(signature, "confirmed");

// 3. retry with the settled signature - the server re-reads it from the chain
const payload = Buffer.from(JSON.stringify({
  x402Version: 2,
  accepted: offer,
  payload: { signature },
})).toString("base64");

const paid = await fetch(ENDPOINT, { headers: { "PAYMENT-SIGNATURE": payload } });
const report = await paid.json();          // 200 + PAYMENT-RESPONSE header
console.log(report.payment, report.stats);
Paid endpoint

Running the rail

The whole rail is four environment variables and one store. Price and accept window are read at request time, so both can be retuned without a rebuild.

  • PROMPTRAT_X402_PAYTO is required and deliberately never defaulted: without it the endpoint answers 503 instead of advertising a payment that would go nowhere.
  • Prices are counts of atomic units (SOL has 9 decimals). 5000000 means 0.005 SOL.
  • PROMPTRAT_X402_MAX_TIMEOUT_SECONDS is how old a settlement may be and still unlock a report. Short windows suit bots; long ones survive a slow buyer.
  • BLOB_READ_WRITE_TOKEN backs the replay store. No store means no sales: an endpoint that might serve one payment twice is worse than one that is closed.
  • Rate limits are per IP: 30 challenges and 12 payment attempts per minute, so a broken retry loop cannot starve a genuine payment.
  • GET /api/x402/verify is free and prices nothing. Same verifier, open to anyone who wants to check a settlement — this page included.
.env.local
# .env.local - the wallet that receives the payments
PROMPTRAT_X402_PAYTO=<your wallet address>

# atomic units = human amount x 10^decimals (1,000,000,000 for SOL)
PROMPTRAT_X402_SOL_ATOMIC=5000000          # = 0.005 SOL (9 decimals)

# optional: how old a settlement may be and still unlock a report
PROMPTRAT_X402_MAX_TIMEOUT_SECONDS=300

# optional: holder-pass threshold (atomic units) - holders at/above it get the report free.
PROMPTRAT_X402_HOLDER_ATOMIC=150000000000  # = 150,000 $PromptRat (6 decimals)

# the one-report-per-signature store
BLOB_READ_WRITE_TOKEN=<vercel blob token>

The rail is listed in the developer reference and the docs.

No custody, no promises

This endpoint sells a data artifact in exchange for a Solana transfer. It is not an investment product, there is no yield, and no promise of value attaches to the token — the price is simply what the artifact costs.