# Pons Trading API > Trade and launch tokens on Pons, on Robinhood Chain --- # Pons Trading API for Robinhood Chain > Free, keyless REST and WebSocket API to buy, sell and launch tokens on Pons v2 and Uniswap v4 on Robinhood Chain. Unsigned transactions you sign locally - your private key never leaves your machine. # Pons Trading API The simplest way to trade and launch tokens on **Pons** - the launchpad on **Robinhood Chain** - through an API. Buy and sell any Pons token, **v2** (bonding curve, then Uniswap v4) or **v1** (Uniswap V3 from launch); launch new ones on Pons v2. - **Keyless.** No account, no API key, no sign-up. Just call it. - **Local only.** Every endpoint returns **unsigned transactions**. You sign them with your own wallet. Your private key never leaves your machine. - **Everything in ETH.** Buy with ETH whatever a token is priced in - USDG, NVDA, TSLA and the other tokenised assets are converted for you on the way in, and optionally back to ETH on the way out. - **Copy-paste scripts.** Every page has a plain JavaScript and Python script: change three lines, run it. ``` Base URL: https://api.shrine.trade/evm ``` ## Endpoints | Endpoint | What it does | |---|---| | `POST /api/local-trade` | Buy or sell any Pons v2 or v1 token, on its curve or on Uniswap → [Buy & Sell](/local-trade) | | `WS /api/launches/ws` | Live feed of Pons launches, graduations and new Uniswap v4 pools → [Live Launches](/live-launches) | | `POST /api/create-token` | Launch a new token on Pons v2, with an optional dev buy → [Create Token](/create-token) | | `GET /api/token/{address}` | Curve state, phase, reserves, snipe tax, unswept creator fees → [Token Info](/token-info) | | `GET /api/fees/{wallet}` `POST /api/claim-fees` | What your launches have earned, and the transactions that pay it out → [Claim Creator Fees](/creator-fees) | *shrine.trade is an independent integration. We are not affiliated with Pons or Robinhood Markets, Inc.; Pons's contracts and its launch fees belong to Pons.* --- # Create a Token on Pons (Robinhood Chain) > Launch a token on the Pons v2 bonding curve on Robinhood Chain with one signed transaction - metadata, image, creator tax, dev buy and any quote asset from ETH to NVDA. # Create Token ``` POST https://api.shrine.trade/evm/api/create-token ``` Builds the Pons launch transaction for you: metadata, launch config, the pinned economics hash, and — if you want one — a dev buy in the same transaction. You sign and send it; the token and its bonding curve exist as soon as it confirms. shrine.trade takes **no fee** on creation. The transaction value covers Pons's own launch fee (plus your dev buy, if any). Launching is **Pons v2 only**: the bonding curve, graduating to Uniswap v4 on its own once it sells out. Pons v1 launches are not offered (v1 is superseded), though v1 tokens still [buy and sell](/local-trade) here. > **About the private key field.** **The key never leaves your machine.** It signs locally and the signed transaction goes straight to the RPC you included in the api request; it is never sent to shrine.trade. Uploading happens first: **Build waits for the image to finish pinning to IPFS**, so the token's `logo` is set the moment it launches rather than being patched in afterwards. ## Example **JavaScript** ```js const { readFileSync } = require("node:fs"); const { JsonRpcProvider, Wallet, id, getAddress, dataSlice } = require("ethers"); // ─── your token ─────────────────────────────────────── const PRIVATE_KEY = "0xYOUR_PRIVATE_KEY"; const NAME = "Grene"; const SYMBOL = "GRENE"; const IMAGE = "./logo.png"; // image file, next to this script const DESCRIPTION = "the greenest coin on Robinhood Chain"; // ─── links — all optional, "" to leave one out ──────── const TWITTER = "https://x.com/grene"; const TELEGRAM = ""; const DISCORD = ""; const WEBSITE = "https://grene.example"; const FARCASTER = ""; // ─── economics ──────────────────────────────────────── const PAIR_TOKEN = "ETH"; // what buyers pay with: ETH, USDG, NVDA, MSTR, … const DEV_BUY = ""; // your own opening buy, in ETH. "" = none const CREATOR_TAX = 0; // % of every trade you earn, 0–10. Fixed at launch const FEE_RECIPIENT = ""; // where your fees go. "" = the launching wallet const EXEMPTIONS = []; // wallets that skip the opening snipe tax. // Max 32, or 31 when you take a dev buy const BUYBACK = false; // route creator fees into buybacks // ────────────────────────────────────────────────────── async function main() { const provider = new JsonRpcProvider("https://rpc.mainnet.chain.robinhood.com", 4663); const wallet = new Wallet(PRIVATE_KEY, provider); // 1. Upload the image. We pin it to IPFS and hand back a hosted URL. const form = new FormData(); form.append("file", new Blob([readFileSync(IMAGE)], { type: "image/png" }), "logo.png"); form.append("name", NAME); form.append("symbol", SYMBOL); form.append("description", DESCRIPTION); const up = await fetch("https://api.shrine.trade/evm/api/upload-image", { method: "POST", body: form, }); const uploaded = await up.json(); if (uploaded.error) throw new Error(`${uploaded.error}: ${uploaded.message}`); console.log("image pinned:", uploaded.image); // 2. Ask shrine.trade to build the launch transaction. const res = await fetch("https://api.shrine.trade/evm/api/create-token", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ name: NAME, symbol: SYMBOL, description: DESCRIPTION, logo: uploaded.image, socials: { twitter: TWITTER, telegram: TELEGRAM, discord: DISCORD, website: WEBSITE, farcaster: FARCASTER }, pairToken: PAIR_TOKEN, creatorTaxBps: CREATOR_TAX * 100, buybackEnabled: BUYBACK, // Left out entirely when empty - the API picks sane defaults. ...(DEV_BUY ? { initialBuy: DEV_BUY } : {}), ...(EXEMPTIONS.length ? { snipeTaxExemptions: EXEMPTIONS } : {}), ...(FEE_RECIPIENT ? { creatorFeeRecipient: FEE_RECIPIENT } : {}), from: wallet.address, }), }); const body = await res.json(); if (body.error) throw new Error(`${body.error}: ${body.message}`); console.log("launch fee", body.launchFeeFormatted, "ETH"); // 3. Sign locally - your private key never leaves this script. // 4. Submit through your own RPC. A dev buy in an ERC-20 needs an approval // first, so send whatever comes back, in order. let receipt, hash; for (const tx of body.txs) { const sent = await wallet.sendTransaction({ to: tx.to, data: tx.data, value: BigInt(tx.value), // launch fee (+ dev buy) in wei gasLimit: BigInt(tx.gas), maxFeePerGas: BigInt(tx.maxFeePerGas), maxPriorityFeePerGas: BigInt(tx.maxPriorityFeePerGas), nonce: tx.nonce, chainId: tx.chainId, type: tx.type, }); hash = sent.hash; receipt = await sent.wait(); } // 5. Read the new addresses out of the TokenLaunched event. const topic0 = id("TokenLaunched(address,address,address,address,uint256,uint256)"); const log = receipt.logs.find((l) => l.topics[0] === topic0); console.log("token launched:", getAddress(dataSlice(log.topics[1], 12))); console.log("curve:", getAddress(dataSlice(log.topics[2], 12))); console.log("tx:", "https://robinscan.io/tx/" + hash); } main(); ``` Save it as `launch.js`, put your image next to it as `logo.png`, then: ```bash npm install ethers node launch.js ``` **Python** ```python import requests from web3 import Web3 # ─── your token ─────────────────────────────────────── PRIVATE_KEY = "0xYOUR_PRIVATE_KEY" NAME = "Grene" SYMBOL = "GRENE" IMAGE = "./logo.png" # image file, next to this script DESCRIPTION = "the greenest coin on Robinhood Chain" # ─── links - all optional, "" to leave one out ──────── TWITTER = "https://x.com/grene" TELEGRAM = "" DISCORD = "" WEBSITE = "https://grene.example" FARCASTER = "" # ─── economics ──────────────────────────────────────── PAIR_TOKEN = "ETH" # what buyers pay with: ETH, USDG, NVDA, MSTR, … DEV_BUY = "" # your own opening buy, in ETH. "" = none CREATOR_TAX = 0 # % of every trade you earn, 0-10. Fixed at launch FEE_RECIPIENT = "" # where your fees go. "" = the launching wallet EXEMPTIONS = [] # wallets that skip the opening snipe tax. # Max 32, or 31 when you take a dev buy BUYBACK = False # route creator fees into buybacks # ────────────────────────────────────────────────────── w3 = Web3(Web3.HTTPProvider("https://rpc.mainnet.chain.robinhood.com")) account = w3.eth.account.from_key(PRIVATE_KEY) # 1. Upload the image. We pin it to IPFS and hand back a hosted URL. with open(IMAGE, "rb") as fh: up = requests.post( "https://api.shrine.trade/evm/api/upload-image", files={"file": ("logo.png", fh, "image/png")}, data={"name": NAME, "symbol": SYMBOL, "description": DESCRIPTION}, ).json() if "error" in up: raise SystemExit(f"{up['error']}: {up['message']}") print("image pinned:", up["image"]) # 2. Ask shrine.trade to build the launch transaction. res = requests.post( "https://api.shrine.trade/evm/api/create-token", json={ "name": NAME, "symbol": SYMBOL, "description": DESCRIPTION, "logo": up["image"], "socials": {"twitter": TWITTER, "telegram": TELEGRAM, "discord": DISCORD, "website": WEBSITE, "farcaster": FARCASTER}, "pairToken": PAIR_TOKEN, "creatorTaxBps": CREATOR_TAX * 100, "buybackEnabled": BUYBACK, # Left out entirely when empty - the API picks sane defaults. **({"initialBuy": DEV_BUY} if DEV_BUY else {}), **({"snipeTaxExemptions": EXEMPTIONS} if EXEMPTIONS else {}), **({"creatorFeeRecipient": FEE_RECIPIENT} if FEE_RECIPIENT else {}), "from": account.address, }, ) body = res.json() if "error" in body: raise SystemExit(f"{body['error']}: {body['message']}") print("launch fee", body["launchFeeFormatted"], "ETH") # 3. Sign locally - your private key never leaves this script. # 4. Submit through your own RPC. A dev buy in an ERC-20 needs an approval # first, so send whatever comes back, in order. for tx in body["txs"]: signed = w3.eth.account.sign_transaction( { "to": tx["to"], "data": tx["data"], "value": int(tx["value"]), # launch fee (+ dev buy) in wei "gas": tx["gas"], "maxFeePerGas": int(tx["maxFeePerGas"]), "maxPriorityFeePerGas": int(tx["maxPriorityFeePerGas"]), "nonce": tx["nonce"], "chainId": tx["chainId"], "type": tx["type"], }, account.key, ) h = w3.eth.send_raw_transaction(signed.raw_transaction) # web3.py v6: signed.rawTransaction receipt = w3.eth.wait_for_transaction_receipt(h) # 5. Read the new addresses out of the TokenLaunched event. topic0 = w3.keccak(text="TokenLaunched(address,address,address,address,uint256,uint256)") log = next(l for l in receipt["logs"] if l["topics"] and l["topics"][0] == topic0) print("token launched:", w3.to_checksum_address(log["topics"][1][-20:])) print("curve:", w3.to_checksum_address(log["topics"][2][-20:])) print("tx:", f"https://robinscan.io/tx/0x{h.hex().removeprefix('0x')}") ``` Save it as `launch.py`, put your image next to it as `logo.png`, then: ```bash pip install web3 requests python launch.py ``` ## Supported quote assets A Pons token can be priced in ETH or in one of Robinhood Chain's tokenised assets. Pass the **ticker** as `pairToken` - `"MSTR"`, `"USDG"`, `"NVDA"` - or the address if you prefer; both work, and tickers are case-insensitive. Whatever you pick is fixed at launch and is what buyers pay with. The launch fee itself is always ETH. | Ticker | Decimals | Address | |---|---|---| | `ETH` | 18 | native ETH — no address | | `USDG` | 6 | `0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168` | | `SPCX` | 18 | `0x4a0E65A3EcceC6dBe60AE065F2e7bb85Fae35eEa` | | `NVDA` | 18 | `0xd0601CE157Db5bdC3162BbaC2a2C8aF5320D9EEC` | | `RDDT` | 18 | `0x05b37Fb53A299a1b874A619e1c4C404D52C36F4C` | | `AMZN` | 18 | `0x12f190a9F9d7D37a250758b26824B97CE941bF54` | | `DJT` | 18 | `0x1D11f0496982706C5e14A514D4E79F2e6BdE4516` | | `TTWO` | 18 | `0x5e81213613b6B86EaB4c6c50d718d34359459786` | | `GME` | 18 | `0x1b0E319c6A659F002271B69dB8A7df2F911c153E` | | `SPY` | 18 | `0x117cc2133c37B721F49dE2A7a74833232B3B4C0C` | | `AAPL` | 18 | `0xaF3D76f1834A1d425780943C99Ea8A608f8a93f9` | | `MSFT` | 18 | `0xe93237C50D904957Cf27E7B1133b510C669c2e74` | | `COIN` | 18 | `0x6330D8C3178a418788dF01a47479c0ce7CCF450b` | | `TSLA` | 18 | `0x322F0929c4625eD5bAd873c95208D54E1c003b2d` | | `QQQ` | 18 | `0xD5f3879160bc7c32ebb4dC785F8a4F505888de68` | | `PLTR` | 18 | `0x894E1EC2D74FFE5AEF8Dc8A9e84686acCB964F2A` | | `cbBTC` | 8 | `0xCEC185eB182c47d1bA1EFc84e6959e18cd620Be4` | | `GOOGL` | 18 | `0x2e0847E8910a9732eB3fb1bb4b70a580ADAD4FE3` | | `GLD` | 18 | `0xC9a981FEE1F9DEc688bb123ccDeCc63D0deBFC4e` | | `META` | 18 | `0xc0D6457C16Cc70d6790Dd43521C899C87ce02f35` | | `CRCL` | 18 | `0xdF0992E440dD0be65BD8439b609d6D4366bf1CB5` | | `COST` | 18 | `0x4EA005168D7F09a7A0Ba9D1DEf21a479950E44C2` | | `MSTR` | 18 | `0xec262a75e413fAfD0dF80480274532C79D42da09` | | `AMD` | 18 | `0x86923f96303D656E4aa86D9d42D1e57ad2023fdC` | | `SNDK` | 18 | `0xB90A19fF0Af67f7779afF50A882A9CfF42446400` | | `BB` | 18 | `0x48E39E56aCdbA37b09020C0b734A613C9a2f100A` | | `MU` | 18 | `0xfF080c8ce2E5feadaCa0Da81314Ae59D232d4afD` | | `HIMS` | 18 | `0xCceE82fE024c36fA15E1005edE3E9e4787e23D09` | Pons scales each curve's economics into its quote asset, so the graduation threshold differs per asset - 4.2 ETH, 8090 USDG, 41.6 NVDA. `create-token` returns the one that applies as `graduationThreshold`. ## Request | Field | Type | Description | |---|---|---| | `name` | string | Token name. Not unique — always identify tokens by address. | | `symbol` | string | Ticker. | | `description` | string | Project description. | | `socials` | object | `{ twitter, telegram, discord, website, farcaster }` — any may be `""`. | | `logo` | string, optional | Hosted image URL. The scripts above pin your image file to IPFS and fill this in for you. | | `creatorFeeRecipient` | address, optional | Where creator fees are paid. Defaults to `from`. | | `snipeTaxExemptions` | string[], optional | Up to **32** wallets that skip the opening snipe tax (**31** with an `initialBuy` - the dev-buy wallet takes one slot on-chain). In the form above, separate them with commas (spaces and new lines work too). Your own sniper, a partner, whoever. Fixed at launch and never changeable. | | `creatorTaxBps` | number, optional | Extra creator tax on every trade, in basis points. Capped by Pons at 10%; immutable after launch. Default `0`. | | `buybackEnabled` | boolean, optional | Route the creator's fee share into token buybacks (vested). Default `false`. | | `launchConfigId` | number, optional | Which Pons launch config to use. Only config `0` exists today and it is the default, so leave it out. | | `pairToken` | string, optional | What the curve is priced in. `"ETH"` (default) or the address of an approved quote asset — USDG, NVDA, SPCX, GME, cbBTC and the rest of Robinhood Chain's tokenised assets. An asset Pons hasn't approved returns `pair_token_not_approved`. | | `initialBuy` | decimal string, optional | Your own opening buy, in the same transaction, **in ETH** whatever the token is priced in. On a USDG or NVDA launch the API works out how much of that asset the ETH buys (`initialBuy` in the response, `initialBuyEth` echoes your figure); your wallet's own holding of the asset is used first and only the shortfall is swapped, with a `buy_quote_with_eth` transaction in front. Your wallet is exempt from the snipe tax on this buy, and there is no slippage to set on the buy itself: it runs inside the transaction that creates the curve, so nobody can trade ahead of it. | | `salt` | 32-byte hex, optional | CREATE2 salt. Lets you know the token address before launching. Random if omitted. | | `from` | address | Your wallet (deployer). | ### What a launch costs Two numbers matter, and they are not the same: | | plain launch | + 0.001 dev buy | |---|---|---| | **ETH you must hold** | ~0.0026 | ~0.0036 | | **ETH actually spent** | ~0.0019 | ~0.0029 | The gap is not a fee. A node reserves `gasLimit x maxFeePerGas` for the whole transaction before it runs, and neither figure is what gets used: the limit is padded 20% above the estimate, and the price is a ceiling set at 1.25x the current base fee, not the rate. Unused gas is never taken - you get the difference back in the same block. So **budget around 0.003 ETH on Robinhood Chain** for a plain launch, plus your dev buy. A wallet holding exactly the launch fee plus the expected gas will be rejected, which is not a bug. The ceiling is deliberately tight: if the base fee climbs more than 25% between quoting and sending, the node rejects the transaction and you request a fresh one. Of what is spent, `0.0005` is Pons's launch fee and the rest is gas. shrine.trade takes nothing on creation. ## Response A real one, for a launch with a 0.001 ETH dev buy: ```json { "txs": [ { "to": "0xe33E9E479dF8802cb0866d5d05258bEc4cF62948", "data": "0x\u2026", "value": "1500000000000000", "gas": 4600821, "maxFeePerGas": "581672501", "maxPriorityFeePerGas": "1", "nonce": 5, "chainId": 4663, "type": 2, "description": "launch_and_buy" } ], "launchFee": "500000000000000", "launchFeeFormatted": "0.0005", "expectedEconomics": "0xa9fc75d4203a33fe660e8fa32c74c3aa41c1fda4bf23d3a39b6bc22a1f8b1ca7", "launchConfigId": 0, "pairToken": "ETH", "pairTokenSymbol": "ETH", "pairTokenDecimals": 18, "graduationThreshold": "4200000000000000000", "graduationThresholdFormatted": "4.2", "salt": "0x\u2026", "creatorFeeRecipient": "0x7b444D22f099Fd238210161791dE26d16c3cEdf2", "creatorTaxBps": 100, "snipeTaxExemptions": [], "initialBuy": "1000000000000000", "expectedTokensOut": "582993253935204464062630", "minTokensOut": "553843591238444240859498" } ``` - `txs` - sign and send in order. Usually one: `launch` (plain) or `launch_and_buy` (with a dev buy). A dev buy in an ERC-20 pair token can put `buy_quote_with_eth` (if the wallet is short of it) and `approve_quote` in front. - `launchFee` - Pons's fee, always ETH, read from the factory at request time. The transaction's `value` is this plus an ETH dev buy. - `pairToken`, `pairTokenSymbol`, `pairTokenDecimals` - what the curve is priced in. `graduationThreshold` is how much of it the curve must take in before it graduates; Pons scales it per asset. - `expectedEconomics` - the launch config's economics hash, pinned into the transaction so the terms can't change between quote and landing. - `salt` - yours, or the random one we picked. `creatorFeeRecipient`, `creatorTaxBps`, `snipeTaxExemptions` echo what the launch will use. - `initialBuy`, `expectedTokensOut`, `minTokensOut` - the dev buy in the pair token's base units and what it returns. Only with an `initialBuy`. On an ERC-20-priced launch `initialBuyEth` is the ETH you gave and `initialBuy` what it became. - `quoteSwap` - only when an ERC-20 dev buy needed a swap in front: what it buys, the ETH quoted and carried, and the pools. --- # Claim Pons Creator Fees > See what your Pons launches have earned on Robinhood Chain and claim it to your wallet in two calls. # Claim Creator Fees If you launched a token, every trade on it earns you a share: what's left of the trading fee after Pons's 30%, plus all of your creator tax. It isn't sent to you automatically - you claim it. Two endpoints, free and keyless. ## What's waiting ``` GET https://api.shrine.trade/evm/api/fees/{wallet}?token={yourToken} ``` ```json { "wallet": "0xfc1FFd8b43631Ba04a347FAF930fA1Dc547BFcb2", "escrow": "0xd3AFEB2a57f70eF218Aa82451c51B2fb0416Ac9e", "asset": "USDG", "decimals": 6, "claimable": "39388954", "claimableFormatted": "39.388954", "unswept": "1935146", "unsweptFormatted": "1.935146", "total": "41324100", "totalFormatted": "41.3241", "hasClaimable": true } ``` `total` is what a claim pays out right now, in the launch's quote asset (`asset`). `claimable` is already in Pons's escrow; `unswept` is still on the token's curve and gets collected as part of the claim. `hasClaimable: false` means don't bother - you'd only pay gas. Leave `token` out to see just the ETH escrow balance. ## Claim it ``` POST https://api.shrine.trade/evm/api/claim-fees ``` Send `{ "from": "0x…", "token": "0x…" }` - your wallet and your launched token - and you get back the transactions that pay everything out to your wallet: one or two, send them in order. **JavaScript** ```js const { JsonRpcProvider, Wallet } = require("ethers"); // ─── change these ───────────────────────────────────── const PRIVATE_KEY = "0xYOUR_PRIVATE_KEY"; const TOKEN = "0xYOUR_LAUNCHED_TOKEN"; // ────────────────────────────────────────────────────── async function main() { const wallet = new Wallet( PRIVATE_KEY, new JsonRpcProvider("https://rpc.mainnet.chain.robinhood.com", 4663), ); // 1. Ask shrine.trade to build the claim. const res = await fetch("https://api.shrine.trade/evm/api/claim-fees", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ from: wallet.address, token: TOKEN }), }); const data = await res.json(); if (data.error) throw new Error(`${data.error}: ${data.message}`); console.log("claiming", data.claimingFormatted, data.asset); // 2. Sign locally and send, in order - the key never leaves this script. for (const tx of data.txs) { const sent = await wallet.sendTransaction({ to: tx.to, data: tx.data, value: BigInt(tx.value), gasLimit: BigInt(tx.gas), maxFeePerGas: BigInt(tx.maxFeePerGas), maxPriorityFeePerGas: BigInt(tx.maxPriorityFeePerGas), nonce: tx.nonce, }); await sent.wait(); console.log(tx.description + ": https://robinscan.io/tx/" + sent.hash); } } main(); ``` Save it as `claim.js`, then: ```bash npm install ethers node claim.js ``` **Python** ```python import requests from web3 import Web3 # ─── change these ───────────────────────────────────── PRIVATE_KEY = "0xYOUR_PRIVATE_KEY" TOKEN = "0xYOUR_LAUNCHED_TOKEN" # ────────────────────────────────────────────────────── w3 = Web3(Web3.HTTPProvider("https://rpc.mainnet.chain.robinhood.com")) account = w3.eth.account.from_key(PRIVATE_KEY) # 1. Ask shrine.trade to build the claim. data = requests.post( "https://api.shrine.trade/evm/api/claim-fees", json={"from": account.address, "token": TOKEN}, ).json() if "error" in data: raise SystemExit(f"{data['error']}: {data['message']}") print("claiming", data["claimingFormatted"], data["asset"]) # 2. Sign locally and send, in order - the key never leaves this script. for tx in data["txs"]: signed = w3.eth.account.sign_transaction( { "to": tx["to"], "data": tx["data"], "value": int(tx["value"]), "gas": tx["gas"], "maxFeePerGas": int(tx["maxFeePerGas"]), "maxPriorityFeePerGas": int(tx["maxPriorityFeePerGas"]), "nonce": tx["nonce"], "chainId": tx["chainId"], }, account.key, ) h = w3.eth.send_raw_transaction(signed.raw_transaction) w3.eth.wait_for_transaction_receipt(h) print(tx["description"] + ":", f"https://robinscan.io/tx/0x{h.hex().removeprefix('0x')}") ``` Save it as `claim.py`, then: ```bash pip install web3 requests python claim.py ``` ## Notes - **Only the `creatorFeeRecipient` can claim** - your wallet unless you set another at launch. `/api/token/{address}` shows which. - **Launches priced in an ERC-20** (USDG, NVDA, …) pay out in that asset. Pass the launched token and the API works out the rest. - **Launched with buybacks on?** Then Pons collects the curve's fees for you on its own schedule, and the claim covers what has arrived in the escrow so far. `nothing_to_claim` tells you when the rest is still on the curve. - These are Pons's fees to you as a creator. Our 1% is separate and never touches this escrow. --- # API Errors > Every error code the Pons Trading API returns, grouped by endpoint, with what to do about each. # Errors Errors are JSON with a stable `error` code and a plain-language `message`. Check the code in your script and show the message to a human. ```json { "error": "insufficient_balance", "message": "wallet holds 0 tokens, tried to sell 1000" } ``` ## Your request | Code | HTTP | Meaning | |---|---|---| | `invalid_request` | 400 | A required field is missing or malformed. | | `invalid_address` | 400 | `token`, `from` or another address field is not a valid address. | | `invalid_amount` | 400 | `amount` is zero, negative, not a number, or a percentage on a buy. | | `invalid_action` | 400 | `action` is not `"buy"` or `"sell"`. | | `token_not_found` | 404 | The address is not a Pons token on Robinhood Chain, v2 or v1. Check you copied the token, not a pool or a curve. | ## Trading | Code | HTTP | Meaning | |---|---|---| | `insufficient_funds` | 400 | Not enough ETH in `from` for the trade plus gas. The message says what the wallet holds and what it needs. It has to be **ETH on Robinhood Chain** - ETH on Ethereum mainnet or another L2 must be bridged first, and holding USDG, NVDA or another asset does not pay for gas. | | `insufficient_balance` | 400 | Selling more tokens than the wallet holds. `"100%"` sells everything. | | `slippage_exceeded` | 400 | The price moved between the quote and now by more than `slippage`. Retry, or raise `slippage` on a fast-moving token. | | `no_route` | 400 | The token is priced in an asset your wallet doesn't hold enough of, and no Uniswap pool can buy that asset with ETH. Acquire it yourself, then retry. With `toEth`: no pool can turn the proceeds into ETH - sell without it and keep the asset. | | `amount_too_small` | 400 | So little that the swap would return nothing. Increase `amount`. | | `graduating` | 409 | The token is moving from its curve to its Uniswap pool right now. Retry in a minute; it then trades on Uniswap automatically. | | `graduated` | 400 | The curve closed while your trade was being built. Retry; the trade now routes to Uniswap. | | `curve_closed` | 409 | The curve has sold out and is about to graduate; sells reopen once the Uniswap pool exists. | | `deadline_passed` | 400 | A Uniswap transaction is only valid for 10 minutes after it is built. Request a fresh one. | | `insufficient_allowance` | 400 | An approval the trade needs is missing. Retry; the response will include it. | ## Creating a token | Code | HTTP | Meaning | |---|---|---| | `invalid_pair_token` | 400 | `pairToken` is neither an address nor a ticker we know. The message lists the tickers. | | `pair_token_not_approved` | 400 | Pons doesn't accept that asset as a quote. Use ETH or one of the [approved assets](/create-token#supported-quote-assets). | | `too_many_exemptions` | 400 | More than 32 `snipeTaxExemptions` (31 with an `initialBuy`). | | `creator_tax_too_high` | 400 | `creatorTaxBps` is above the maximum Pons allows (10%). | | `invalid_salt` | 400 | `salt` is not 32 bytes of hex. | | `launch_config_disabled` | 400 | The requested `launchConfigId` is not available. Leave it out. | | `launcher_not_permitted` | 403 | Pons currently only lets allow-listed wallets launch, and `from` isn't one. | | `launch_disabled` | 503 | Pons has paused launching. Try later. | | `missing_file` | 400 | The image upload had no `file` field. | | `not_an_image` | 400 | The uploaded file is not an image. | | `file_too_large` | 400 | The image is over 5 MB. | | `invalid_upload` | 400 | The upload could not be read. | ## Creator fees | Code | HTTP | Meaning | |---|---|---| | `nothing_to_claim` | 400 | Nothing is waiting for this wallet. If the message names an amount, that much has been earned but is still being collected by Pons; check back later. | | `sweep_requires_operator` | 400 | This launch's fees are collected by Pons on its own schedule, not by you. Nothing to do - claim again once they arrive. | ## Limits | Code | HTTP | Meaning | |---|---|---| | `rate_limited` | 429 | More than 5 requests per second from your IP to one endpoint. Wait a second and retry (`Retry-After: 1`). | | `too_many_connections` | 429 | A third launch-feed WebSocket from your IP. Two per IP; close one first. | ## Everything else | Code | HTTP | Meaning | |---|---|---| | `revert` | 400 | The transaction would fail on-chain for a reason not listed above; `message` says what the contract reported. | | `rpc_error` | 502 | Robinhood Chain could not be reached. Retry. | A transaction can still fail after you send it if the price moves past your slippage. `minOut` is your protection; a failed trade costs only gas. --- # Fees > shrine.trade charges 1% per trade on Pons and Uniswap v4 tokens on Robinhood Chain; launching and reading are free. Pons fees and the opening snipe tax apply on top. # Fees ## shrine.trade | Action | Fee | |---|---| | Buy | **1%** | | Sell | **1%** | | Create token | **Free** (Pons's launch fee applies — see below) | | Token info | Free | The 1% is taken in the asset the trade settles in - ETH on an ETH-priced token, USDG on a USDG-priced one, and so on - on the curve and on Uniswap alike. It excludes Pons's own trading fee, creator tax and opening snipe tax, and Uniswap pool fees. ## Network Robinhood Chain gas is paid in ETH and is small (100 ms blocks, cheap L2 execution). The API fills `gas` and the EIP-1559 fee fields for you. --- # Live Pons Launches on Robinhood Chain > WebSocket feed of every new Pons launch, every graduation and every new Uniswap v4 pool on Robinhood Chain, the moment it happens. Free and keyless. # Live Launches & Graduations The whole token lifecycle on Robinhood Chain, pushed the moment it happens. Three things arrive on this one socket: - **Launches** - a token appears on the Pons bonding curve. - **Graduations** - a curve sells out and the token moves to its permanent Uniswap v4 pool. - **New Uniswap v4 pools** - including tokens launched straight on Uniswap, without a curve. Free, no key, no account. ``` wss://api.shrine.trade/evm/api/launches/ws ``` ## Copy this Click Pons or Uniswap v4 to choose what the script receives - the URL updates. **JavaScript** (Node 22+, no packages): ```js // Add ?protocols=PONS for launches only, or ?protocols=UNISWAP_V4 for // graduations and new pools only. No query = everything. const ws = new WebSocket("wss://api.shrine.trade/evm/api/launches/ws"); ws.onmessage = (e) => { const t = JSON.parse(e.data); // t.type: new_launch, graduated or new_pool console.log(JSON.stringify(t, null, 2)); }; ``` **Python** (`pip install websockets`): ```python import json from websockets.sync.client import connect with connect("wss://api.shrine.trade/evm/api/launches/ws") as ws: for raw in ws: t = json.loads(raw) # t["type"]: new_launch, graduated or new_pool print(json.dumps(t, indent=2)) ``` ## What you get On connect you're sent the **single most recent event** so the screen isn't blank, then everything new as it happens. Each message has a `type` and a `protocol`: | `type` | `protocol` | Means | |---|---|---| | `new_launch` | `PONS` | A token launched on the Pons curve - tradeable immediately. | | `graduated` | `UNISWAP_V4` | A Pons curve sold out; the token moved to its Uniswap v4 pool. | | `new_pool` | `UNISWAP_V4` | A Uniswap v4 pool was created. Includes Pons graduations **and** tokens launched directly on Uniswap. | Filter with `?protocols=PONS` or `?protocols=UNISWAP_V4` (omit it for both), or use the picker above. Fields that don't apply to an event are simply absent, so check `type` first. ```json { "type": "new_launch", "protocol": "PONS", "token": "0x84BD8478c0…", "curve": "0x2ffCc8d7…", "deployer": "0x1a2b3c…", "name": "Tollbooth", "symbol": "TOLLBOOTH", "pairToken": "ETH", "launchConfigId": 0, "graduationThreshold": "4200000000000000000", "uri": "ipfs://bafy…", "description": "the greenest coin on Robinhood Chain", "socials": { "twitter": "https://x.com/grene", "telegram": "", "discord": "", "website": "", "farcaster": "" }, "blockNumber": 50952986, "txHash": "0x…", "timestamp": 1756654321 } ``` **`uri`, `description` and `socials` come off the token contract itself** - Pons stores them on-chain, so the creator's image URI and links arrive with the event and there's nothing extra to fetch. A `new_pool` event carries `poolId`, `currency0`, `currency1`, `fee`, `tickSpacing` and `hooks` instead. A `hooks` of `0x0000…0000` means a plain Uniswap pool with no Pons hook - i.e. someone launched directly on Uniswap rather than through a curve. > **Don't buy the instant you see a launch.** Pons has sniper protection and taxes buys for about **3 seconds** after a launch, starting near **99%** and decaying to zero. Buying the moment a launch appears in this feed hands over almost your entire order as tax. ## Notes - **Reconnect on drop.** Long-lived sockets die; reconnect and you're re-seeded with the recent launches, so you won't miss much. - **Two subscriptions per IP.** A third connection from the same address is refused with `too_many_connections`. One socket with no filter carries everything, so you rarely need more. - **Nothing is stored.** This is a live feed, not an archive - there's no history endpoint and no backfill. --- # Buy & Sell Pons Tokens on Robinhood Chain > Buy or sell any Pons v2 token on Robinhood Chain with one script, on the bonding curve or on Uniswap v4. Pay in ETH; tokens priced in USDG, NVDA or TSLA are converted for you. # Buy & Sell Copy the script, change three lines, run it. We build the transaction, your script signs and sends it - your private key never leaves your machine. One endpoint for every Pons token on Robinhood Chain, whichever generation launched it and wherever it lives: - **Pons v2** - on its bonding curve, then in its Uniswap v4 pool after graduation. - **Pons v1** - in the Uniswap V3 pool it launched into. Pass the token address and we work out which. The response says so in `protocol` (`PONS_V2` / `PONS_V1`) and `venue` (`pons_curve`, `uniswap_v4`, `uniswap_v3`). ## What you need - **Node.js** or **Python**. - A wallet private key with some **ETH on Robinhood Chain**. - A token address. Take one from [any Pons token page](https://www.ponsfamily.com) or the [live launches feed](/live-launches). ## Example **JavaScript** ```js const { JsonRpcProvider, Wallet } = require("ethers"); // ─── change these three ─────────────────────────────── const PRIVATE_KEY = "0xYOUR_PRIVATE_KEY"; const TOKEN = "0xTHE_TOKEN_ADDRESS"; const AMOUNT = "0.01"; // to buy: ETH to spend. To sell: "1000" tokens, or "100%" const ACTION = "buy"; // "buy" or "sell" const TO_ETH = true; // selling a token priced in USDG/NVDA/…: also // convert the proceeds to ETH const SLIPPAGE = 5; // %, how far the price may move against you // ────────────────────────────────────────────────────── async function main() { const wallet = new Wallet( PRIVATE_KEY, new JsonRpcProvider("https://rpc.mainnet.chain.robinhood.com", 4663), ); const res = await fetch("https://api.shrine.trade/evm/api/local-trade", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ action: ACTION, token: TOKEN, amount: AMOUNT, toEth: TO_ETH, slippage: SLIPPAGE, from: wallet.address, }), }); const data = await res.json(); if (data.error) throw new Error(`${data.error}: ${data.message}`); console.log("you should get about", data.quote.expectedOutFormatted, ACTION === "buy" ? "tokens" : data.quoteAsset.symbol); if (data.quoteSwap) { console.log("buying", data.quoteSwap.quoteOutFormatted, data.quoteAsset.symbol, "with", data.quoteSwap.ethInMaxFormatted, "ETH first"); } // Sign locally and send, in order - the key never leaves this script. for (const tx of data.txs) { const sent = await wallet.sendTransaction({ to: tx.to, data: tx.data, value: BigInt(tx.value), gasLimit: BigInt(tx.gas), maxFeePerGas: BigInt(tx.maxFeePerGas), maxPriorityFeePerGas: BigInt(tx.maxPriorityFeePerGas), nonce: tx.nonce, }); await sent.wait(); console.log(tx.description + ": https://robinscan.io/tx/" + sent.hash); } if (ACTION === "buy") { console.log(`bought ${data.name} (${data.symbol}) ${data.token} for ${data.ethInFormatted ?? data.amountInFormatted} ETH`); } else if (data.toEth) { console.log(`sold ${data.amountInFormatted} ${data.name} (${data.symbol}) ${data.token} for ${data.toEth.ethOutFormatted} ETH`); } else { console.log(`sold ${data.amountInFormatted} ${data.name} (${data.symbol}) ${data.token} for ${data.quote.expectedOutFormatted} ${data.quoteAsset.symbol}`); } } main(); ``` Save it as `trade.js`, then: ```bash npm install ethers node trade.js ``` **Python** ```python import requests from web3 import Web3 # ─── change these three ─────────────────────────────── PRIVATE_KEY = "0xYOUR_PRIVATE_KEY" TOKEN = "0xTHE_TOKEN_ADDRESS" AMOUNT = "0.01" # to buy: ETH to spend. To sell: "1000" tokens, or "100%" ACTION = "buy" # "buy" or "sell" TO_ETH = True # selling a token priced in USDG/NVDA/…: also convert the proceeds to ETH SLIPPAGE = 5 # %, how far the price may move against you # ────────────────────────────────────────────────────── w3 = Web3(Web3.HTTPProvider("https://rpc.mainnet.chain.robinhood.com")) account = w3.eth.account.from_key(PRIVATE_KEY) res = requests.post( "https://api.shrine.trade/evm/api/local-trade", json={"action": ACTION, "token": TOKEN, "amount": AMOUNT, "toEth": TO_ETH, "slippage": SLIPPAGE, "from": account.address}, ) data = res.json() if "error" in data: raise SystemExit(f"{data['error']}: {data['message']}") unit = "tokens" if ACTION == "buy" else data["quoteAsset"]["symbol"] print("you should get about", data["quote"]["expectedOutFormatted"], unit) for tx in data["txs"]: signed = w3.eth.account.sign_transaction( { "to": tx["to"], "data": tx["data"], "value": int(tx["value"]), "gas": tx["gas"], "maxFeePerGas": int(tx["maxFeePerGas"]), "maxPriorityFeePerGas": int(tx["maxPriorityFeePerGas"]), "nonce": tx["nonce"], "chainId": tx["chainId"], }, account.key, ) h = w3.eth.send_raw_transaction(signed.raw_transaction) w3.eth.wait_for_transaction_receipt(h) print(tx["description"] + ":", f"https://robinscan.io/tx/0x{h.hex().removeprefix('0x')}") if ACTION == "buy": print(f"bought {data['name']} ({data['symbol']}) {data['token']} for {data.get('ethInFormatted', data['amountInFormatted'])} ETH") elif data.get("toEth"): print(f"sold {data['amountInFormatted']} {data['name']} ({data['symbol']}) {data['token']} for {data['toEth']['ethOutFormatted']} ETH") else: print(f"sold {data['amountInFormatted']} {data['name']} ({data['symbol']}) {data['token']} for {data['quote']['expectedOutFormatted']} {data['quoteAsset']['symbol']}") ``` Save it as `trade.py`, then: ```bash pip install web3 requests python trade.py ``` The script sends whatever comes back, in order. Usually that is one transaction; a first sell, or a buy on a token priced in USDG, NVDA or another asset, may need a one-time approval in front of it. > **Don't buy a launch in its first seconds.** Pons has sniper protection and taxes buys for about 3 seconds after a launch. ## Selling Set `ACTION = "sell"`. `AMOUNT` is a number of tokens or a share of what you hold: | `AMOUNT` | Sells | |---|---| | `"1000"` | 1000 tokens | | `"50%"` | half your balance | | `"100%"` | everything | ## Tokens priced in USDG, NVDA, … A lot of Pons launches are priced in one of Robinhood Chain's tokenised assets instead of ETH. Nothing changes in the script: `AMOUNT` on a buy is always ETH. For a token priced in USDG, `"0.001"` means "spend 0.001 ETH", and the API works out how much USDG that is (`amountIn`, in `quoteAsset`) and hands the curve or pool that. If your wallet already holds that much USDG it is used as is; otherwise the transactions start with a swap that buys the missing amount with ETH, and `quoteSwap` says what that costs. `ethIn` in the response is the ETH you asked to spend. Selling pays out in that asset. With `toEth: true` (the scripts' `TO_ETH`) the proceeds are converted to ETH as well: on a graduated token it happens inside the same transaction, on a curve token it is a follow-up swap of the guaranteed minimum. `toEth` in the response says how much ETH you end up with and through which pools. The full list is on [Create Token](/create-token#supported-quote-assets). ## If it doesn't work | Error | What to do | |---|---| | `insufficient_funds` | Add ETH to the wallet - the amount plus a little for gas. | | `insufficient_balance` | You're selling more than you hold. Try `"100%"`. | | `token_not_found` | Not a Pons token. Check you copied the token, not the pool. | | `slippage_exceeded` | The price moved. Raise `SLIPPAGE` (percent, default `5`) and retry. | | `graduating` | The token is moving to its Uniswap pool. Wait a minute and retry. | Full list on [Errors](/pons/errors). ### Request and response `POST https://api.shrine.trade/evm/api/local-trade` **Request** | Field | | | |---|---|---| | `action` | `"buy"` or `"sell"` | | | `token` | address | The Pons token. | | `amount` | decimal string | Buy: ETH to spend, whatever the token is priced in. Sell: tokens (`"1000"`) or a share of your balance (`"50%"`, `"100%"`). | | `from` | address | Your wallet. | | `slippage` | number, optional | Percent, default `5`. | | `toEth` | boolean, optional | Sell only, tokens priced in an ERC-20: also convert the proceeds to ETH. | **Response** - a real one, a buy of an RDDT-priced token for 0.001 ETH: ```json { "action": "buy", "token": "0x77df8B452670deb3DA51B367CD58044422dcE4b0", "name": "Honest Work", "symbol": "HONEST", "curve": "0x07365E838a3f62675b81b3438137824F4B03457e", "phase": "NotGraduated", "venue": "pons_curve", "amountIn": "14171692423151839", "amountInFormatted": "0.014171692423151839", "quoteAsset": { "address": "0x05b37Fb53A299a1b874A619e1c4C404D52C36F4C", "symbol": "RDDT", "decimals": 18, "isNative": false }, "quote": { "expectedOut": "819167564794497226305697", "expectedOutFormatted": "819167.564794497226305697", "minOut": "778209186554772364990412", "curveFeeBps": 100, "creatorTaxBps": 0, "snipeTaxBps": 0, "shrineFeeBps": 100, "slippagePct": 5.0 }, "ethIn": "1000000000000000", "ethInFormatted": "0.001", "txs": [ { "to": "0x05b37Fb53A299a1b874A619e1c4C404D52C36F4C", "data": "0x\u2026", "value": "0", "gas": 80000, "maxFeePerGas": "580242501", "maxPriorityFeePerGas": "1", "nonce": 5, "chainId": 4663, "type": 2, "description": "approve_quote" }, { "to": "0xEc20E594D28a17511264dc73a84cd4AA957B0ABc", "data": "0x\u2026", "value": "0", "gas": 400000, "maxFeePerGas": "580242501", "maxPriorityFeePerGas": "1", "nonce": 6, "chainId": 4663, "type": 2, "description": "buy" } ] } ``` - `txs` - sign and send in order. `value`, `maxFeePerGas`, `maxPriorityFeePerGas` are decimal strings in wei; the rest are numbers. `description` says what each one is: `buy`, `sell`, a one-time `approve` / `approve_quote` (curve) or `approve_permit2` / `approve_router` (Uniswap), `buy_quote_with_eth` (a swap in front of a buy), `convert_to_eth` (a swap after a curve sell). - `name` / `symbol` - the token's own, so your script can say what it traded. - `protocol` - `PONS_V2` or `PONS_V1`. `venue` - `pons_curve` while a v2 token is on its bonding curve, `uniswap_v4` after graduation, `uniswap_v3` for every v1 token. The request is the same in all cases. v1 tokens are always priced in ETH, so `toEth` and the quote-asset conversion don't apply. - `quoteAsset` - what the trade is settled in: ETH, or the tokenised asset the token is priced in. `decimals` is not always 18. - `amountIn` - what the curve or pool receives, in `quoteAsset`. On a buy of an ERC-20-priced token, `ethIn` is the ETH you asked for and `amountIn` is what that ETH buys of the asset. - `quote.expectedOut` - what you should receive; `minOut` has your slippage applied and is enforced on-chain. Base units; the `*Formatted` fields are the human numbers. - `quote` fees - `curveFeeBps` and `creatorTaxBps` are Pons's, `shrineFeeBps` is ours (100 = 1%), `snipeTaxBps` is Pons's opening tax for your wallet right now. - `quoteSwap` - only when your wallet is short of the quote asset and a swap was added in front: `quoteOut` bought, `ethIn` quoted, `ethInMax` carried (refunded if unused), `route` the pools, found on-chain. - `toEth` - only on a sell with `toEth: true`: `ethOut` after our fee, `ethOutMin` enforced on-chain, `route` the pools. Graduated tokens do it in the same transaction; curve tokens add a `convert_to_eth` transaction. --- # Pons Token Info API > Read any Pons token on Robinhood Chain: curve reserves, graduation phase, snipe tax for your wallet and unswept creator fees. # Token Info Free, keyless reads. Use them to decide what to trade and to size a buy before you call `local-trade`. Amounts are raw base-unit strings (wei for ETH, 18-decimal units for tokens); fields ending in `Formatted` are the human-readable decimal. ## Token ``` GET https://api.shrine.trade/evm/api/token/{address} GET https://api.shrine.trade/evm/api/token/{address}?recipient=0x… ``` **JavaScript** ```js const TOKEN = "0xEad55618651062963DeE22728EFb1F3275DA7393"; async function main() { const res = await fetch(`https://api.shrine.trade/evm/api/token/${TOKEN}`); const t = await res.json(); if (t.error) throw new Error(`${t.error}: ${t.message}`); console.log(t.phase, "| sellable:", t.sellableTokensFormatted, "| curve fee:", t.curveFeeBps, "bps"); console.log("reserves:", t.quoteReserve, "wei /", t.tokenReserve, "tokens"); console.log("unswept creator fees:", t.unsweptFees.creatorShareEstimateFormatted); } main(); ``` Save it as `token.js` and run `node token.js` - no packages needed. **Python** ```python import requests TOKEN = "0xEad55618651062963DeE22728EFb1F3275DA7393" t = requests.get(f"https://api.shrine.trade/evm/api/token/{TOKEN}").json() if "error" in t: raise SystemExit(f"{t['error']}: {t['message']}") print(t["phase"], "| sellable:", t["sellableTokensFormatted"], "| curve fee:", t["curveFeeBps"], "bps") print("reserves:", t["quoteReserve"], "wei /", t["tokenReserve"], "tokens") print("unswept creator fees:", t["unsweptFees"]["creatorShareEstimateFormatted"]) ``` Save it as `token.py`, `pip install requests`, then `python token.py`. Add `?recipient=0x…` to get `snipeTaxBps` for that wallet. Example response: ```json { "token": "0x1111111111111111111111111111111111111111", "curve": "0x2222222222222222222222222222222222222222", "deployer": "0x3333333333333333333333333333333333333333", "creatorFeeRecipient": "0x3333333333333333333333333333333333333333", "pairToken": "ETH", "phase": "NotGraduated", "graduated": false, "readyToGraduate": false, "graduationThreshold": "4200000000000000000", "quoteReserve": "1712522872270353145", "tokenReserve": "981008795387803266283543676", "sellableTokens": "695294509673517551997829391", "sellableTokensFormatted": "695294509.673517551997829391", "curveFeeBps": 100, "creatorTaxBps": 0, "buybackEnabled": false, "poolFee": 0, "tickSpacing": 200, "snipeTaxBps": 0, "unsweptFees": { "heldBy": "curve", "tradingFee": "747321571942453", "tradingFeeFormatted": "0.000747321571942453", "creatorTax": "682955361004953", "creatorTaxFormatted": "0.000682955361004953", "creatorShareEstimate": "944517911184812", "creatorShareEstimateFormatted": "0.000944517911184812", "protocolShareBps": 3000, "buybackShareBps": 5000, "buybackEnabled": true, "creatorCanSweep": false, "hasUnswept": true } } ``` | Field | Meaning | |---|---| | `protocol` | `PONS_V2` or `PONS_V1`. For v1 tokens `curve` is the Uniswap V3 pool, `phase` is always `PoolCreated`, `quoteReserve` / `tokenReserve` are the pool's balances, and the fee and creator-fee fields are zero - v1 has no curve, no creator tax and no escrow. | | `curve` | The bonding-curve contract — where trades go while `phase` is `NotGraduated`. | | `pairToken` | The quote asset. `"ETH"` for native-ETH launches (the only kind this API trades). | | `phase` / `graduated` | `NotGraduated` (curve live) · `Swept` · `PoolCreated` (trading on Uniswap v4) · `Rescued`. `graduated` is `true` for anything but `NotGraduated`. | | `readyToGraduate` | `true` once nothing is left to sell; sells revert from here on. | | `graduationThreshold` | Quote (wei) the curve must collect before it graduates. | | `quoteReserve` / `tokenReserve` | Current curve reserves — the price is their ratio. | | `sellableTokens` | Tokens still purchasable on the curve. `0` means it's about to graduate. | | `curveFeeBps` / `creatorTaxBps` | Pons's base curve fee and the launcher's creator tax (basis points, on the quote asset). | | `poolFee` / `tickSpacing` | The Uniswap v4 pool parameters this token graduates into. | | `snipeTaxBps` | Only meaningful with `?recipient=` — the opening tax *that wallet* would pay on a buy right now. | | `unsweptFees` | Fees this launch has earned that are still sitting on the curve (`heldBy: "curve"`) or the pool hook after graduation (`heldBy: "hook"`), in the quote asset. `creatorShareEstimate` is what the creator gets of them, and [`/api/claim-fees`](/creator-fees) collects it together with the escrow balance; `creatorCanSweep` is `false` for launches with buybacks on, where Pons collects on its own schedule. |