Public API

Free, read-only JSON endpoints. No API key needed. Terminals and bots can use them to find the official coin for a ticker.

Devnet test. Data comes from devnet for now, and every response includes cluster. There's no uptime guarantee yet, and the API may change before mainnet. We'll document changes here. Please don't poll more than once every 5–10 seconds.

Base URL: this site. Every endpoint returns JSON, allows cross-origin requests (Access-Control-Allow-Origin: *) and returns errors as { "error": "...", "code": "..." } with an HTTP 4xx or 5xx status.

GET /api/ticker/{SYMBOL}

Status of a single ticker. SYMBOL is normalized ( $ and spaces removed, uppercase) and must then be 1–10 letters or numbers. Exact match only.

GET /api/ticker/CAT

200 OK
{
  "symbol": "CAT",
  "status": "launched",          // free | owned | launched | graduated | protected | reserved (legacy)
  "owner": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU",
  "expiresAt": null,              // ISO date while "reserved", else null
  "mint": "9fQp…",                // official mint once launched, else null
  "reservationId": 42,
  "reservedAt": "2026-09-28T14:02:11.000Z",
  "launchedAt": "2026-09-28T18:40:03.000Z",
  "tokenName": "Cat Coin",        // launched tokens only
  "imageUri": "https://ipfs.io/ipfs/…",
  "launchSignature": "5h…",       // creation transaction, verified on-chain
  "feeSharing": "active",         // active | pending | mismatch | off (creator-fee split)
  "cluster": "devnet"
}

A free ticker:

{ "symbol": "PEPE", "status": "free", "owner": null, "expiresAt": null, "mint": null,
  "reservationId": null, "reservedAt": null, "launchedAt": null, "cluster": "devnet" }

Errors: 400 INVALID_TICKER (unsupported characters or too long).

An owned ticker: owner is the current on-chain holder of its NFT.

{ "symbol": "DOGE", "status": "owned", "owner": "7xKX…gAsU", "mint": null,
  "title": {
    "asset": "Fq3…",                  // Metaplex Core NFT of the One Ticker collection
    "owner": "7xKX…gAsU",
    "boughtAt": "2026-09-30T12:00:00.000Z",
    "listing": { "id": 12, "priceSol": 1.5, "seller": "7xKX…gAsU", "listedAt": "…" },   // null if not for sale
    "lastSale": { "priceSol": 1, "at": "…" }                                             // null if never resold
  }, "cluster": "devnet" }

GET /api/market

Listed tickers. Only listings that are still valid on-chain (the seller holds the NFT and approved the listing). Query: q (ticker prefix), sort = recent (default) | price_asc | price_desc, limit 1–50 (default 24), cursor (from nextCursor).

GET /api/market?sort=price_asc&limit=2

{ "items": [
    { "symbol": "DOGE", "asset": "Fq3…", "listingId": 12, "priceSol": 1.5, "lastSaleSol": 1,
      "seller": "7xKX…gAsU", "listedAt": "2026-09-30T12:10:00.000Z" }
  ],
  "total": 1, "nextCursor": null, "sort": "price_asc", "cluster": "devnet" }

GET /api/market/sales

Sales, newest first. Query: symbol (one ticker), kind = primary (free ticker bought from One Ticker) | resale, limit 1–50.

{ "sales": [ { "symbol": "DOGE", "kind": "resale", "priceSol": 1, "feeSol": 0.05,
    "seller": "7xKX…gAsU", "buyer": "3pQr…9fQp", "signature": "5h…", "at": "…" } ], "cluster": "devnet" }

GET /api/market/stats

{ "owned": 120, "listed": 14, "titlesSold": 131, "resales": 22, "volumeSol": 48.5, "volume24hSol": 6,
  "floorSol": 0.2, "lastSale": { "symbol": "DOGE", "priceSol": 1, "at": "…" },
  "titlePriceSol": 0.05, "feeBps": 500, "enabled": true, "collection": "…", "cluster": "devnet", "updatedAt": "…" }

Marketplace actions (used by the site)

These endpoints prepare transactions that the user signs in their own wallet; the server then verifies them on-chain. One Ticker never takes custody of funds. Each takes { "action": "prepare" | "confirm", ... }.

  • POST /api/market/title: buy a free ticker (payment and NFT mint in one transaction).
  • POST /api/market/list: list a ticker or edit the listing (owner only).
  • POST /api/market/delist: cancel the listing (revokes the approval on-chain).
  • POST /api/market/buy: buy a listed ticker (seller payment, fee and NFT in one transaction).
  • POST /api/market/transfer: send the NFT to another wallet.
  • POST /api/market/refresh { "action": "refresh", "symbol" }: check the owner on-chain again (for example, after a sale on another marketplace).
  • GET /api/title/{SYMBOL}: metadata JSON for the ticker NFT.

GET /api/profile/{addressOrHandle}

A wallet's public profile, by address or username (not case-sensitive). Any valid address returns a profile (empty if it was never edited). An unknown username returns a 404.

GET /api/profile/cat_dev

{ "profile": { "wallet": "7xKX…gAsU", "handle": "cat_dev", "bio": "gm", "twitter": "https://x.com/catdev",
               "telegram": null, "website": null, "avatarUrl": "/api/profile/avatar/7xKX…-a1b2c3d4e5f6.webp", "updatedAt": "…" },
  "stats": { "owned": 2, "listed": 1, "launched": 1, "soldVolumeSol": 1.5, "boughtVolumeSol": 0.1, "trades": 3 },
  "titles": [ { "symbol": "DOGE", "boughtAt": "…", "priceSol": 1.5, "listingId": 12, "lastSaleSol": null } ],
  "launches": [ { "symbol": "CAT", "mint": "9fQp…", "launchedAt": "…", "tokenName": "Cat Coin", "imageUri": "…", "status": "launched" } ],
  "sales": [ { "symbol": "DOGE", "kind": "resale", "side": "sold", "priceSol": 1.5, "counterparty": "3pQr…",
               "counterpartyProfile": { "handle": "bob", "avatarUrl": null }, "signature": "5h…", "at": "…" } ],
  "cluster": "devnet" }

Lists that show a wallet (/api/recent, /api/tickers, /api/market, /api/market/sales) include its profile ({ handle, avatarUrl } or null) next to the short address.

Editing (used by the site): POST /api/profile and POST /api/profile/avatar (multipart, PNG/JPG/WebP ≤ 1 MB, re-encoded to a 256×256 WebP without metadata). Both require a signed wallet message (free, no transaction) with the wallet, a SHA-256 of the exact data, a one-time nonce and the time (valid for 10 minutes). Usernames: 3–20 characters [a-z0-9_], unique, some names reserved. Rate-limited like the other write endpoints.

GET /api/stats

Live counters, computed from our database.

GET /api/stats

200 OK
{
  "reservedNow": 12,            // active, non-expired reservations
  "launched": 3,                // tickers with status "launched"
  "graduated": 0,               // tickers with status "graduated"
  "creators": 9,                // distinct wallets with at least one valid reservation
  "reservationsAllTime": 20,    // legacy 48 h reservations (replaced on Sept 30, 2026)
  "ownedNow": 120,              // tickers owned right now (marketplace titles)
  "listedNow": 14,              // tickers for sale right now
  "titlesSold": 131,            // free tickers bought from One Ticker, all-time
  "cluster": "devnet",
  "updatedAt": "2026-09-28T16:20:00.000Z"
}

Cached for up to 10 seconds (s-maxage=10, stale-while-revalidate=30).

GET /api/recent

Latest activity, newest first.

QueryValues
limit1–50, default 20 (values above 50 are capped)
typeoptional: reserved, launched, graduated, released
GET /api/recent?limit=3

200 OK
{
  "events": [
    { "type": "launched", "symbol": "MOON",  "wallet": "7xKX…gAsU", "mint": "9fQp…", "at": "2026-09-28T18:40:03.000Z", "expiresAt": null },
    { "type": "reserved", "symbol": "CAT",   "wallet": "4aTq…Zz1P", "mint": null,    "at": "2026-09-28T18:12:45.000Z", "expiresAt": "2026-09-30T18:12:45.000Z" },
    { "type": "released", "symbol": "WAGMI", "wallet": "Hn3c…b8Qe", "mint": null,    "at": "2026-09-28T17:00:00.000Z", "expiresAt": null }
  ],
  "cluster": "devnet"
}
  • wallet is always shortened (7xKX…gAsU).
  • expiresAt is set on reserved events (to show the time left), null otherwise.
  • released means a reservation expired without a launch.
  • Cached for up to 5 seconds.

Errors: 400 BAD_LIMIT, 400 BAD_TYPE.

GET /api/launches

Every coin launched on One Ticker (never outside copies). This is what the Launches page uses. Market data is read on-chain from the pump.fun bonding curve and cached by the server for about 20 seconds. market is null when the data isn't available.

QueryValues
taball (default) · curve (on the bonding curve) · graduated · pending (90/10 split not set yet, before its deadline)
sortnew (default) · old · mcap · progress (closest to graduation; coins without data last)
qticker, coin name, dev username or wallet, CA (contains)
creatordev wallet or username
cursor, limitpagination: nextCursor of the previous page; 1–60 (default 30)
GET /api/launches?limit=1
{
  "items": [{
    "symbol": "CAT", "name": "Cat Coin", "imageUri": "https://ipfs.io/ipfs/…", "mint": "AbCd…pump",
    "launchedAt": "2026-10-02T12:00:00.000Z",
    "creator": { "wallet": "7xKX…", "walletShort": "7xKX…9fQp", "handle": "alice", "avatarUrl": null },
    "status": "launched", "feeSharing": "active", "feeShareDeadline": null, "viaTitle": false,
    "market": { "mcapSol": 84.2, "mcapUsd": 12400, "progressPct": 64.1, "complete": false,
                "updatedAt": "2026-10-02T12:05:10.000Z" }
  }],
  "total": 12, "nextCursor": "1",
  "counts": { "all": 12, "curve": 10, "graduated": 1, "pending": 1 },
  "creators": 9, "marketUpdatedAt": "2026-10-02T12:05:10.000Z", "cluster": "mainnet-beta"
}
  • mcapUsd is null when the SOL price is unknown. Graduated coins have market: null (their bonding curve is closed).
  • Open CORS (*), cached for up to 5 seconds.

GET /api/tickers

Owned, reserved and launched tickers, paginated. This is what the Tickers page uses.

QueryValues
statusreserved (active reservations), launched (launched and graduated), all (default)
qoptional ticker prefix, normalized like a search ($cat → CAT, matches CAT, CATS…)
sortrecent (default, newest first) or expiring (soonest expiry first, only with status=reserved)
limit1–50, default 20
cursoropaque value from the previous response's nextCursor
GET /api/tickers?status=reserved&sort=expiring&limit=2

200 OK
{
  "items": [
    { "symbol": "CAT", "status": "reserved", "wallet": "4aTq…Zz1P", "reservedAt": "2026-09-28T18:12:45.000Z",
      "expiresAt": "2026-09-30T18:12:45.000Z", "mint": null, "launchedAt": null },
    { "symbol": "DOG", "status": "reserved", "wallet": "7xKX…gAsU", "reservedAt": "2026-09-28T19:03:10.000Z",
      "expiresAt": "2026-09-30T19:03:10.000Z", "mint": null, "launchedAt": null }
  ],
  "total": 12,
  "nextCursor": "WyIyMDI2LTA5LTMwVDE5OjAzOjEwLjAwMFoiLCJET0ciXQ",
  "status": "reserved",
  "sort": "expiring",
  "cluster": "devnet"
}

Pass nextCursor back as cursor to get the next page. It's null on the last page. total counts every matching ticker. Errors: 400 BAD_STATUS, 400 BAD_SORT, 400 BAD_QUERY, 400 BAD_CURSOR, 400 BAD_LIMIT.

GET /api/reserved

Active reservations, newest first. limit: 1–50, default 20.

GET /api/reserved?limit=2

200 OK
{
  "reservations": [
    { "symbol": "CAT", "wallet": "4aTq…Zz1P", "reservedAt": "2026-09-28T18:12:45.000Z", "expiresAt": "2026-09-30T18:12:45.000Z" },
    { "symbol": "DOG", "wallet": "7xKX…gAsU", "reservedAt": "2026-09-28T16:03:10.000Z", "expiresAt": "2026-09-30T16:03:10.000Z" }
  ],
  "cluster": "devnet"
}

Errors: 400 BAD_LIMIT. Cached for up to 5 seconds.

POST /api/launch/precheck

Can this wallet launch this ticker on One Ticker? A free ticker can be launched by any wallet (launch fee); an owned ticker only by the current on-chain holder of its NFT (no launch fee). The launch runs the same check again right before signing and at confirmation.

POST /api/launch/precheck
Content-Type: application/json

{ "symbol": "CAT", "wallet": "<wallet address>" }

200 OK
{ "symbol": "CAT", "canLaunch": true, "viaReservation": false, "viaTitle": true, "launchFeeSol": 0,
  "platformFeeShareBps": 1000, "launchEnabled": true }

Errors: 400 INVALID_TICKER, 400 INVALID_WALLET, 409 OWNED (owned by another wallet), 409 RESERVED (another wallet's old reservation), 409 PROTECTED, 409 UNAVAILABLE (already launched), 503 RPC_ERROR (couldn't check the owner).