Developer docs

Everything about the ponsapi, in one place.

Base URL https://api.ponsapi.dev. Every example below runs against it — pick your language once and the whole page follows.

Quickstart

From wallet to first call

Keys are wallet-linked. Ask for a nonce, sign it with personal_sign, and swap the signature for a key. No email, no dashboard round-trip needed.

# 1. ask for a nonce
curl -s -X POST https://api.ponsapi.dev/v1/auth/nonce \
  -H "content-type: application/json" \
  -d '{"wallet":"0xYourWallet"}'
# -> { "nonce": "a1b2...", "message": "ponsapi wants you to sign in..." }

# 2. personal_sign that exact message with the wallet

# 3. trade the signature for a key
curl -s -X POST https://api.ponsapi.dev/v1/auth/verify \
  -H "content-type: application/json" \
  -d '{"wallet":"0xYourWallet","signature":"0x...","nonce":"a1b2..."}'
# -> { "apiKey": "pons_..." }   shown once — store it

Then call anything with the key in the header:

auth via:
curl -s https://api.ponsapi.dev/v1/tokens?sort=mcap&limit=10 \
  -H "x-api-key: $PONS_KEY"
Authentication

Hold the gate token, keep the key

Access is tied to holding at least the gate minimum (currently 1 $PONSAPI). Keys are re-checked periodically; drop below and the key suspends until you top up. Check your own status any time:

auth via:
curl -s https://api.ponsapi.dev/v1/me \
  -H "x-api-key: $PONS_KEY"

Two ways to send the key

Every authenticated endpoint accepts either, on any method — GET, POST, or the WebSocket upgrade. Flip auth via on any code block above and the whole page rewrites itself to match.

x-api-key: pons_…Header. The default, and the one to use server-side.
authorization: Bearer pons_…Header. For clients that only speak Bearer.
?api-key=pons_…Query parameter. Also accepted as ?apikey=, ?api_key= and ?key=.

The query parameter exists because headers are awkward in a browser fetch from a static page, in an EventSource, in a WebSocket handshake, or when you are pasting a URL into a browser to eyeball a response. It is the same key with the same rate limits — just remember that URLs end up in server logs and browser history, so prefer the header wherever you control the request.

Data API

Read the chain, normalized

Every token launched through pons is self-describing onchain. ponsapi reads metadata, pool state, graduation and fee splits directly from the contracts and caches them. Trade history and holders are backfilled lazily on first request and kept warm from then on.

auth via:
curl -s https://api.ponsapi.dev/v1/tokens/0x39dBED3a2bd333467115dE45665cC57F813C4571 \
  -H "x-api-key: $PONS_KEY"
response
{
  "token": "0x39dbed3a2bd333467115de45665cc57f813c4571",
  "name": "Pons",
  "symbol": "PONS",
  "priceEth": 0.0002972,
  "priceUsd": 0.7110,
  "mcapUsd": 496329581,
  "graduated": true,
  "creatorSharePercent": 90,
  "pool": "0x10cc6bd38112cac182db90b6a71d8bb5939526ba",
  "pairedToken": "0x...",
  "poolFee": 10000
}

Creator fees are computed from the locked V3 position — exact, never estimated:

auth via:
curl -s https://api.ponsapi.dev/v1/tokens/0x39dBED3a2bd333467115dE45665cC57F813C4571/fees \
  -H "x-api-key: $PONS_KEY"
response
{
  "creatorSharePercent": 70,
  "creatorPayout": "0x...",
  "pending": {
    "weth":  { "total": 12.4, "creator": 8.68, "protocol": 3.72, "usd": 41000 },
    "token": { "total": 920000, "creator": 644000, "protocol": 276000 }
  }
}
Reference

Every endpoint

GET
/v1/tokens
List known launches — sort: new, mcap, vol
GET
/v1/tokens/{token}
Full state: metadata, price, graduation, fee split
GET
/v1/tokens/{token}/price
Price, market cap, FDV — public, no key
GET
/v1/tokens/{token}/trades
Trade history, lazily backfilled, cursor paged
GET
/v1/tokens/{token}/holders
Holder balances rebuilt from Transfer logs
GET
/v1/tokens/{token}/fees
Exact pending creator + protocol fees (V3 math)
POST
/v1/trade/quote
Quote through Quoter V2
POST
/v1/trade/build
Unsigned exactInputSingle transaction
POST
/v1/trade/launch/build
Unsigned launchToken transaction
POST
/v1/trade/fees/claim/build
Unsigned locker.collectFees transaction
POST
/v1/wallets
Create a lightning wallet
GET
/v1/wallets
List your lightning wallets and balances
POST
/v1/wallets/{id}/trade
Execute a buy or sell server-side
POST
/v1/wallets/{id}/launch
Launch a token from the wallet
POST
/v1/wallets/{id}/claim
Claim creator fees
POST
/v1/wallets/{id}/withdraw
Withdraw ETH or tokens out
GET
/v1/auth/gate
Gate token address and minimum — public
POST
/v1/auth/nonce
Start the sign-in flow — public
POST
/v1/auth/verify
Exchange a signature for a key — public
GET
/v1/me
Key status and current gate balance
WS
/v1/ws
Launch, trade and price streams
WebSocket

Real-time streams

Connect to wss://api.ponsapi.dev/v1/ws?api-key=… and send subscribe messages. One connection per key — add and remove subscriptions on the same socket.

subscribeNewToken
every pons launch, both factories
subscribeTokenTrade
trades for specific tokens
subscribeAccountTrade
trades by specific wallets
unsubscribe*
same shape, unsubscribe prefix
const ws = new WebSocket("wss://api.ponsapi.dev/v1/ws?api-key=" + process.env.PONS_KEY);

ws.onopen = () => {
  ws.send(JSON.stringify({ method: "subscribeNewToken" }));
  ws.send(JSON.stringify({
    method: "subscribeTokenTrade",
    keys: ["0x39dBED3a2bd333467115dE45665cC57F813C4571"],
  }));
};

ws.onmessage = (raw) => {
  const msg = JSON.parse(raw.data);
  if (msg.event === "tokenTrade") {
    console.log(msg.data.side, msg.data.amountEth, "ETH", msg.data.token);
  }
  if (msg.event === "newToken") console.log("launched:", msg.data.token);
};
event
{
  "event": "tokenTrade",
  "data": {
    "token": "0x39dbed3a2bd333467115de45665cc57f813c4571",
    "side": "buy",
    "amountEth": "0.42",
    "amountToken": "1412.5",
    "priceEth": 0.000297,
    "trader": "0xabc...",
    "txHash": "0x...",
    "ts": "2026-09-09T12:00:00Z"
  }
}
Trade API

Build transactions locally

Non-custodial by default: ponsapi quotes through Quoter V2 and returns an unsigned SwapRouter02 transaction. You sign and broadcast with your own wallet and RPC. Send value as-is; the router wraps ETH for you.

auth via:
curl -s -X POST https://api.ponsapi.dev/v1/trade/build \
  -H "x-api-key: $PONS_KEY" \
  -H "content-type: application/json" \
  -d '{
       "token": "0x39dBED3a2bd333467115dE45665cC57F813C4571",
       "side": "buy",
       "amountEth": "0.01",
       "slippageBps": 100
     }'
response
{
  "swap": {
    "to": "0xCaf6...5cb2",
    "data": "0x04e45aaf...",
    "value": "10000000000000000"
  },
  "quote": {
    "expectedOut": "33.412...",
    "minOut": "33.078..."
  }
}
Lightning

Or let the API execute

For bots and automation, create server-side lightning wallets. Keys are encrypted at rest and funds can be withdrawn to your own wallet at any time. Trade, launch tokens and claim creator fees straight through the API.

auth via:
curl -s -X POST https://api.ponsapi.dev/v1/wallets \
  -H "x-api-key: $PONS_KEY" \
  -H "content-type: application/json" \
  -d '{
       "label": "my-bot"
     }'

Fund the returned address with ETH, then execute — the response carries the tx hash:

auth via:
curl -s -X POST https://api.ponsapi.dev/v1/wallets/{id}/trade \
  -H "x-api-key: $PONS_KEY" \
  -H "content-type: application/json" \
  -d '{
       "token": "0x39dBED3a2bd333467115dE45665cC57F813C4571",
       "side": "buy",
       "amountEth": "0.05"
     }'
Errors & limits

Fair use

Free for gate-token holders: 10 requests/second per key, 2 websocket connections, 25 subscriptions. Historical backfill is bounded per request — repeated calls keep advancing the cursor. Data and streams are never metered; the only charge anywhere is 0.25% on trades the API builds or executes, which funds $PONSAPI buybacks — see pricing.

errors
{ "error": "missing api key" }          // 401 — no key sent
{ "error": "key suspended" }            // 403 — gate balance dropped
{ "error": "rate limit exceeded" }      // 429 — slow down
{ "error": "token and side required" }  // 400 — bad payload