# TokenRouter — full reference for agents > Non-custodial launch router. One API to launch tokens on launchpads across Solana, Robinhood Chain, Base, BNB Chain. TokenRouter prepares unsigned transactions; the creator's own wallet signs and sends them. Private keys never leave the creator's machine. Base URL: https://tokenrouter.fun ## Authentication - API key: `Authorization: Bearer tr_live_…`. Keys are created by a signed-in user (Developers page or `POST /api/v1/keys` from a browser session) and are bound to that user's wallet. The plaintext key is shown once; TokenRouter stores only its SHA-256 hash. - Browser session: the `tr_session` cookie from wallet sign-in. State-changing calls with a session must come from the TokenRouter origin. - Rule: `creator` in every launch request must equal the authenticated wallet, and the launchpad's chain family must match it (a Solana wallet launches on Solana pads, an EVM wallet on EVM pads). Otherwise: 403 `creator_mismatch`. - No key yet? Sign in programmatically: `POST /api/auth/nonce` {address, family} → sign the returned message (Solana signMessage, EVM personal_sign) → `POST /api/auth/verify` {address, family, message, signature} sets the session cookie → `POST /api/v1/keys` {name}. Send `Origin: https://tokenrouter.fun` on these requests. ## Endpoints - `GET /api/v1/pads` (pads) - `POST /api/v1/uploads` (upload) - `POST /api/v1/launch/challenge` (challenge) - `POST /api/v1/launch/quote` (quote) - `POST /api/v1/launch/prepare` (prepare) - `POST /api/v1/launch/submit` (submitSigned) - `POST /api/v1/launch/confirm` (confirm) - `GET /api/v1/launches/:id` (launch) - `GET /api/v1/launches` (myLaunches) - `GET /api/v1/feed` (feed) - `GET /api/v1/keys` (keys) - `POST /api/v1/keys` (createKey) - `DELETE /api/v1/keys/:id` (revokeKey) - `GET /api/v1/openapi.json` (openapi) ## Launchpads - `pumpfun` — pump.fun on Solana (Solana wallet). Kinds: meme, agent, fund. Biggest trader crowd; graduates to PumpSwap. - `paid` — Paid on Solana (Solana wallet). Kinds: creator. Creator fees paid to your X handle; graduates to PumpSwap. - `bonkfun` — bonk.fun on Solana (Solana wallet). Kinds: meme, fund. LaunchLab curve, BONK community; graduates to Raydium. - `stonkfun` — Stonk Fun on Solana (Solana wallet). Kinds: stonk. Paired with tokenized stocks; graduates to Raydium. - `pons` — Pons on Robinhood Chain (EVM wallet). Kinds: meme, stonk. Robinhood Chain native; graduates to Uniswap v4. - `clanker` — Clanker on Base (EVM wallet). Kinds: agent, app, meme. One transaction, agent-native; graduates to Uniswap v4. - `zora` — Zora on Base (EVM wallet). Kinds: creator, app. Creator coins on Base; graduates to Uniswap v4. - `fourmeme` — four.meme on BNB Chain (EVM wallet). Kinds: meme. BNB Chain meme crowd; graduates to PancakeSwap. Needs `challenge` first. - `flap` — Flap on BNB Chain (EVM wallet). Kinds: meme, fund. Tax tokens with a beneficiary; graduates to PancakeSwap. Check `GET /api/v1/pads` for live availability (`available`) and `needsChallenge`. ## Launch flow 1. Upload the image: `POST /api/v1/uploads` with the raw bytes and `Content-Type: image/png` (or image/jpeg, image/webp, image/gif), max 5 MB. Browsers may use multipart/form-data with the field `file`. Response: `{ "url": "https://…" }` → use as `card.imageUrl`. 2. Only if the pad has `needsChallenge: true`: `POST /api/v1/launch/challenge` {pad, creator} → sign `message` with the creator wallet → pass `padAuth: { message, signature }` in quote and prepare. 3. Optional: `POST /api/v1/launch/quote` with the launch body → fee breakdown in the native currency. 4. `POST /api/v1/launch/prepare` with the launch body and an `Idempotency-Key` header. Response: `launchId`, ordered `steps` (each with an unsigned `tx`), `expectedToken`, `fees`, `expiresAt`. 5. For each step in order: - Solana (`tx.chain = "solana"`): base64-decode `tx.transaction` into a VersionedTransaction, sign it with the creator keypair (it may already carry the single-use mint signature — keep it), send it, wait for confirmation. - EVM: send `{ to, data, value (wei, decimal string), gas? }` on `chainId` from the creator account, wait for the receipt. - Steps with `submitVia: "pad"`: sign only and post the base64 signed transaction to `POST /api/v1/launch/submit`. No current launchpad uses this. 6. `POST /api/v1/launch/confirm` {launchId, txIds} → the launch record with `token`, `explorerUrl`, `padUrl`. Safe to retry if a transaction is not visible yet. Launch body: ```json { "pad": "pumpfun", "kind": "meme", "creator": "", "card": { "name": "Router Cat", "symbol": "RCAT", "description": "optional, up to 1000 chars", "imageUrl": "", "links": { "website": "https://…", "x": "@handle", "telegram": "@group" } }, "options": { "devBuy": "0.1" } } ``` `devBuy` is a decimal string in the chain's native unit (SOL, ETH, BNB). Unknown fields are rejected. ## Socials and pad fields `card.links` takes `website` (Website: any https site), `x` (X: x.com, twitter.com, mobile.twitter.com, mobile.x.com; "@name" works), `telegram` (Telegram: t.me, telegram.me, telegram.dog; "@name" works), `discord` (Discord: discord.gg, discord.com, discordapp.com), `farcaster` (Farcaster: farcaster.xyz, warpcast.com; "@name" works). Every link is normalised to a canonical https URL (`@name` → `https://x.com/name`); http, other hosts and malformed links are rejected with `invalid_request`. Each launchpad forwards only the platforms it shows; others are left out and named in the quote `notes`. `GET /api/v1/pads` returns the same spec as `fields`. - `pumpfun`: links: website, x, telegram; description ≤ 1000 chars. - `paid`: links: website, x, telegram; description ≤ 256 chars. Paid adds a "Fees to @handle via UsePaid" line; 256 characters in total. - `bonkfun`: links: website, x, telegram; description ≤ 512 chars. - `stonkfun`: links: website, x, telegram; description ≤ 1000 chars. - `pons`: links: website, x, telegram, discord, farcaster; description ≤ 256 chars. Pons hides descriptions that contain links, so put links in the link fields. - `clanker`: links: website, x, telegram, farcaster; description ≤ 1000 chars. - `zora`: links: ; description ≤ 1000 chars. Zora coins carry no links; Zora shows the links of your Zora profile. - `fourmeme`: links: website, x, telegram; description ≤ 800 chars; `options.extra.label` (Category): Meme | AI | Defi | Games | Infra | DeSci | Social | Depin | Charity | Others, default Meme. - `flap`: links: website, x, telegram; description ≤ 1000 chars. ## Errors All errors are `application/problem+json`: `{ type, title, status, code, detail }`. Launchpad error codes: `missing_env` 503, `invalid_request` 400, `insufficient_funds` 402, `upstream_error` 502, `unsupported` 422, `expired` 410. Others: `unauthorized` / `invalid_api_key` 401, `creator_mismatch` / `tx_mismatch` / `session_required` / `cross_site` 403, `not_found` 404, `already_confirmed` / `invalid_state` / `too_many_keys` 409, `idempotency_key_reused` 422, `rate_limited` 429 (honour `Retry-After`). ## Other endpoints - `GET /api/v1/launches` and `GET /api/v1/launches/{id}`: your own launches. - `GET /api/v1/feed?chain=&pad=&graduated=&limit=&before=`: public live feed of new tokens, newest first, `limit` ≤ 100, paginate with `nextBefore`. ## Safety - Never send a private key or seed phrase to TokenRouter or anyone else. Sign locally. - Check every transaction before signing (for Solana: the fee payer is your wallet; simulate it). - A launch spends real funds. Get your principal's approval before sending.