Waiting for the first launch or trade…

Public API

Launch and read Runitup tokens on any supported chain, from a bot, an agent, or your own app.

Runitup has a public API so you can launch a token from a script, a trading bot, an AI agent, or your own front-end. A token launched this way is identical to one launched on the website: same factory contract, same 75/25 fee split, same permanently locked liquidity.

No API key. No sign-up. Nothing here moves money or exposes anything private, so there is nothing to gate.

We never touch your keys

The API builds your transaction. It does not send it. You sign with a key Runitup never sees and broadcast it yourself. There is no endpoint that launches a token for you, and there never will be — that would mean holding your private key, which would turn one break-in into everyone's loss.

Chains

The API answers for every chain the platform runs on. Name one with chain, using either the slug from token URLs or the numeric id — ?chain=robinhood and ?chain=4663 are the same request.

ChainSlugIdPools quoted inVenues
Robinhood Chainrobinhood4663ETH, USDG, or one of 30 tokenized equitiesuniswap-v3, sushi-v3, uniswap-v4

Omit chain and you get Robinhood, which is what the API has always defaulted to.

Don't hardcode this table. GET /api/v1/config returns it live, including which quote assets each venue accepts, and it will be right when this page is not. This page named a testnet for longer than it should have, which is the argument for reading the endpoint rather than the docs.

Tokenized equities pair on Uniswap V4 only

An equity-quoted launch must pass venue: "uniswap-v4". This is enforced by the contracts, not by the interface: the V3 adapters refuse the equities, so the same launch on uniswap-v3 or sushi-v3 reverts. Equity pools are also quoted in an ERC-20, so a dev buy against one is pulled from your wallet and needs an approval first — the API builds it for you, see two transactions below.

These are third-party instruments whose issuer excludes US persons from holding them. That restriction applies however the token was acquired, and Runitup cannot enforce it.

Using it from an AI agent

There's a ready-made skill file — drop it into Claude Code, OpenCode, Hermes, OpenClaw or anything else that loads markdown skills, and the agent knows the whole flow without you explaining it:

https://runitup.gg/skills/runitup/SKILL.md

For Claude Code, save it as .claude/skills/runitup/SKILL.md in your project (or ~/.claude/skills/ to have it everywhere). Most other frameworks take the raw URL directly. There's a full walkthrough on the Agent Skill page.

There's also an llms.txt at the root, which is what agents look for when they want to find their way around a site on their own.

The flow

  1. POST /api/v1/launch/prepare with your token's details and the chain
  2. Sign and send the approval transaction it returns, if it isn't null
  3. Sign and send the launch transaction
  4. Read the token address from the TokenLaunched event in the receipt
  5. Optionally POST an image and description to the metadata endpoint

Get the current rules

curl https://runitup.gg/api/v1/config
curl https://runitup.gg/api/v1/config?chain=arc

Without chain you get a chains array covering all of them, with the default chain's fields also flattened at the top level so older callers keep working. With chain, you get that one.

Per chain you get the contract addresses, the venues actually deployed there, what each venue can pair against, and the live launch rules — the fee, the supply bounds, the starting market cap. These are read from the contract on every request and can change, so read them rather than pinning them.

Two things worth reading rather than assuming:

  • quoteAssets is keyed by venue, and the lists differ. Tokenized equities appear under uniswap-v4 and nowhere else; the V3 venues carry ETH and USDG. That is enforced by the contracts, so a launch submitted with an equity on a V3 venue reverts. Assets carrying "isRwa": true are the equities.
  • startingMcapQuoteWei is denominated in ETH, not converted from a dollar figure. It reads 1.5 ETH today. There is a startingMcapUsd alongside it for the assets that price through dollars, but for an ETH-quoted launch the wei figure is the authority.
{
  "defaultChainId": 4663,
  "chains": [
    {
      "chain": { "chainId": 4663, "slug": "robinhood", "name": "Robinhood Chain",
                 "nativeCurrency": { "symbol": "ETH", "decimals": 18 } },
      "quoteAsset": { "symbol": "ETH", "decimals": 18, "isWrappedNative": true, "isUsdStable": false },
      "contracts": { "tokenFactory": "0x3677…", "launchConfig": "0x…" },
      "launchRules": {
        "launchFeeWei": "500000000000000",
        "startingMcapQuoteWei": "1500000000000000000",
        "venues": ["uniswap-v3", "sushi-v3", "uniswap-v4"],
        "quoteAssets": {
          "uniswap-v3": [{ "symbol": "ETH", "isNative": true, "decimals": 18, "isRwa": false }, ],
          "uniswap-v4": [{ "symbol": "NVDA", "isNative": false, "decimals": 18, "isRwa": true }, ]
        }
      }
    },
  ]
}

A chain whose RPC is unreachable is left out of chains rather than failing the whole response.

Prepare a launch

curl -X POST https://runitup.gg/api/v1/launch/prepare \
  -H 'Content-Type: application/json' \
  -d '{
    "chain": "arc",
    "name": "My Coin",
    "symbol": "MYC",
    "totalSupply": "1000000000",
    "creatorAddress": "0xYourWallet",
    "devBuy": "10",
    "venue": "uniswap-v3"
  }'
FieldRequiredNotes
nameyesUp to 64 characters
symbolyesUp to 16 characters
totalSupplyyesWhole tokens, as a string. "1000000000" is one billion
creatorAddressyesThe wallet that will sign
chainnoSlug or id. Defaults to robinhood
devBuynoHow much of your own token to buy at launch, in whatever the pool is quoted in — ETH on an ETH pool, USDG on a USDG pool, shares on an equity pool
quoteTokennoThe pool's other side. Defaults to ETH. Read the options from /api/v1/config
feeRecipientnoDefaults to creatorAddress
venuenouniswap-v3 (default), sushi-v3, or uniswap-v4 where deployed

Amounts in are decimal strings, not raw integers — write "10" for ten USDC, not "10000000". Values coming back are raw integers as strings, because a JSON number would silently round a supply of 1e21.

devBuyUsdc is the old name for devBuy

devBuyUsdc still works and means the same thing. It used to be parsed as six decimals while being spent as eighteen, so a dev buy of "25" bought about 25 millionths of a millionth of an ETH. Both names now read as the quote asset's own units. If you were working around that bug by multiplying, stop.

One transaction, or two

It depends on what the pool is quoted in, and the response tells you which you got.

A pool quoted in the chain's native asset — ETH on Robinhood — takes the fee and the dev buy as msg.value. There is nothing to approve, transactions.approval is null, and you send one transaction.

A pool quoted in an ERC-20 — USDG or any of the tokenized equities — has no native leg, so the factory pulls the dev buy with transferFrom. That needs an allowance first, so transactions.approval is a real transaction and you send two. The launch still carries the fee as msg.value; only the dev buy moves as a token.

approval is also null when your allowance already covers the dev buy, so a repeat launch doesn't pay gas to approve what is already approved.

You get back:

{
  "chainId": 4663,
  "chain": { "chainId": 4663, "slug": "robinhood", "name": "Robinhood Chain" },
  "quote": { "symbol": "USDC", "address": "0x3600…0000", "decimals": 6, "isNative": false },
  "venue": "uniswap-v3",
  "transactions": {
    "approval": { "to": "0x3600…0000", "data": "0x095ea7b3…", "value": "0" },
    "launch":   { "to": "0x9Ec9…D19f", "data": "0x1f6a5b96…", "value": "500000000000000" }
  },
  "cost": {
    "launchFeeWei": "500000000000000",
    "devBuyWei": "0",
    "devBuyQuoteAmount": "10000000",
    "totalValueRequired": "500000000000000",
    "currentBalance": "29057017849920000000",
    "sufficientBalance": true,
    "quoteBalance": "29057017",
    "sufficientQuoteBalance": true
  }
}

totalValueRequired is what the launch transaction must carry as msg.value — already set on transactions.launch.value, so you can send it as-is.

devBuyWei is the dev buy when it rides as native value; devBuyQuoteAmount is the same buy when it moves as an ERC-20. Exactly one of them is non-zero.

sufficientBalance covers the native side and sufficientQuoteBalance the token side. Both are reported, not enforced — if either is false the transaction is still built, on the assumption you're about to fund the wallet.

Send it

import { createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";

const account = privateKeyToAccount(process.env.PRIVATE_KEY);
const wallet = createWalletClient({ account, transport: http(RPC_URL) });

const { transactions } = await fetch(".../api/v1/launch/prepare", { ... }).then(r => r.json());

// Only present for an ERC-20-quoted pool, and only when the allowance is short.
if (transactions.approval) {
  const hash = await wallet.sendTransaction(transactions.approval);
  await publicClient.waitForTransactionReceipt({ hash });
}

const hash = await wallet.sendTransaction(transactions.launch);
const receipt = await publicClient.waitForTransactionReceipt({ hash });
// TokenLaunched in the receipt logs carries your new token's address

Wait for the approval's receipt, not just its hash. Sending the launch while the approval is still pending reverts with ERC20: transfer amount exceeds allowance, which does not obviously mean "you went too early".

Add an image and description

These aren't on-chain, so they're a separate call after the launch confirms:

curl -X POST https://runitup.gg/api/tokens/0xYourToken/metadata \
  -H 'Content-Type: application/json' \
  -d '{ "name":"My Coin", "ticker":"MYC", "totalSupply":"1000000000000000000000000000",
        "creatorAddress":"0xYourWallet", "imageUrl":"https://…", "description":"…",
        "ammVenue":"uniswap-v3", "launchType":"quick", "chainId":4663 }'

Do this straight after launching. It makes your token appear on the site immediately rather than waiting for the indexer, and sets the venue so the first buys route correctly.

Note totalSupply here is in raw units (18 decimals) — the opposite convention to the prepare call, because this endpoint mirrors what the indexer stores.

Reading data

These are open too, and need nothing. All of them take ?chain= to narrow to one chain; without it they answer across every chain.

EndpointReturns
GET /api/tokensEvery live token with price, market cap, volume
GET /api/tokens/{address}One token, plus holders and recent trades
GET /api/tokens/{address}/candles?interval=1hOHLC price history
GET /api/activityRecent launches and trades across the platform
GET /api/statisticsPlatform totals
GET /api/wallet/{address}/portfolioA wallet's holdings, across all chains

An address is not unique across chains

Every chain runs the same factory deployed from the same wallet, so two chains can mint tokens at the same address. When you look a token up by address, pass ?chain= if you know which one you mean — otherwise you may get its namesake on another network. Every token returned carries chainId, and every token page URL includes the chain: /token/arc/0x….

Reading amounts

Every amount on a token — market cap, volume, trade sizes — is denominated in that token's pool's quote asset, not in ETH and not in dollars. Tokens carry quoteToken, quoteDecimals and quoteSymbol to say which; all three are null for an ETH-quoted token, and null there means ETH rather than missing data.

Getting this wrong is the single most expensive mistake against this API. A USDG-quoted token reports six-decimal amounts that are already dollars; reading them as eighteen-decimal ETH and then applying an ETH rate is wrong by about a trillion, and produces a plausible-looking number rather than an error.

Errors

Validation failures return 400 with the offending field named:

{ "error": "invalid_request", "field": "venue",
  "message": "venue must be one of: uniswap-v3, sushi-v3, uniswap-v4 on Robinhood Chain." }

An unknown chain returns 404 and lists the ones that exist:

{ "error": "unknown_chain", "message": "No such chain: solana.",
  "available": [{ "chainId": 4663, "slug": "robinhood" }] }

Parameters are checked against the live contract rules on the chain you named, so a request that returns 200 should not revert for a reason we could have caught. Gas, balance and network conditions are still yours to handle.