Launch a token
Your server prepares the launch, your user's own wallet signs it last. relayfor.si never holds its keys or money.
A launch creates a pump.fun token with its fee route locked in the same transaction. The token's creator is the wallet that signs it and pays for it: your user, or you. relayfor.si builds the transaction, checks it by simulation and signs it with the new mint, but never holds the creator's keys or money.
- 01PrepareYour server
POST /launches/prepare - 02SignThe creator's wallet
The wallet signs last - 03SendYou, or relayfor.si
POST /launches/{id}/submit - 04ConfirmSolana
launch.confirmed
What a launch costs
The creator's wallet pays, all inside the launch transaction:
| Part | About | What for |
|---|---|---|
| pump.fun's accounts | 0.03 SOL | The token, its bonding curve and its fee route |
| relayfor.si's fee | 0.02 SOL | Our launch fee |
| The token's vault | 0.0009 SOL | Opens the vault the AI's share is paid to |
| An opening buy | Optional | The creator buys first, up to 100 SOL |
Each route wallet that holds nothing yet is opened the same way, for about 0.0009 SOL: pump.fun can't pay an empty wallet less than that.
Step by step
Prepare
Your server calls POST /launches/prepare with the creator's wallet and the token's details. The image is a base64 data URI, up to 2 MB.
const launch = await fetch("https://relayfor.si/api/project/v1/launches/prepare", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RELAYFOR_SECRET_KEY}`,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({
creator: userWallet,
name: "Nova",
symbol: "NOVA",
description: "The agent that reads Solana for you.",
image: imageDataUri,
}),
}).then((response) => response.json());The answer is the launch in state prepared, with its mint, its route and the transaction to sign. Ask for "transaction_version": 0 when the creator's wallet can't sign version 1 (see the next step).
Sign in the browser
The creator's wallet signs last. Every Solana wallet in the browser (Phantom, Solflare, Backpack and others) offers the Wallet Standard's solana:signTransaction, which takes the transaction's bytes as they are:
npm i @wallet-standard/app @wallet-standard/features @solana/wallet-standard-featuresimport { SolanaSignTransaction, type SolanaSignTransactionFeature } from "@solana/wallet-standard-features";
import { getWallets } from "@wallet-standard/app";
import { StandardConnect, type StandardConnectFeature } from "@wallet-standard/features";
// The Solana wallets in this browser that can connect and sign.
const wallets = getWallets()
.get()
.filter((wallet) => SolanaSignTransaction in wallet.features && StandardConnect in wallet.features);
// Connect the one your user picks, and read its address.
const wallet = wallets[0]!;
const connect = (wallet.features as StandardConnectFeature)[StandardConnect];
const { accounts } = await connect.connect();
const account = accounts[0]!;
const signing = (wallet.features as SolanaSignTransactionFeature)[SolanaSignTransaction];
// A wallet that can't sign version 1 transactions yet gets a version 0 launch.
const transactionVersion = signing.supportedTransactionVersions.includes(1) ? 1 : 0;
// Your server prepares the launch for this wallet (step 1)...
const launch = await prepareOnYourServer({ creator: account.address, transactionVersion });
// ...the wallet signs it...
const [signed] = await signing.signTransaction({
account,
transaction: Uint8Array.from(atob(launch.transaction.base64), (char) => char.charCodeAt(0)),
chain: "solana:mainnet",
});
// ...and your server sends it (step 3).
await submitOnYourServer(launch.id, btoa(String.fromCharCode(...signed!.signedTransaction)));prepareOnYourServer and submitOnYourServer are your own server's routes: the secret key never reaches the browser.
Send
Post the signed transaction to POST /launches/{id}/submit and relayfor.si sends it, or send it to Solana yourself. Do it within about a minute of preparing: the transaction expires with its blockhash.
await fetch(`https://relayfor.si/api/project/v1/launches/${launchId}/submit`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RELAYFOR_SECRET_KEY}`,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({ transaction: signedBase64 }),
});Confirm
Poll GET /launches/{id} until state is confirmed, or listen for the launch.confirmed webhook. The token then has a credit account and a proof page.
| State | Means |
|---|---|
prepared | Built and waiting for the creator's wallet |
sent | Sent to Solana, not confirmed yet |
confirmed | On chain with its route. The token is live |
failed | It did not land: error says why |
expired | Never sent in time: prepare it again |
The token's route
The route comes from your fee strategy. Three fields shape it:
preset: the strategy to use (fps_...). Your default when left out.split: the creator's pick of the AI's and the creator's shares, in basis points of your part, within the strategy'screator_choice. The strategy's own split when left out.creator_fees_to: where the creator's share goes. The creator's own wallet when left out.
{ "split": { "ai_share": 7000, "creator_share": 1000 } }Here the AI takes 70% of your part and the creator 10%, and Standard's wallet keeps its 20%. A launch is refused before anything is signed when a route wallet can't be paid, such as a program's address or relayfor.si's own. The answer's route lists every shareholder with its roles, in basis points of the whole fee, relayfor.si's 20% among them.
Quote tokens
A token trades against SOL unless you name a quote_mint: USDC, or a token on pump.fun's quote-control list. It then trades, pays its creator fees and pays its route in that token. relayfor.si credits USDC at $1, and sells any other quote token for USDC before crediting it.
Its opening buy is opening_buy_amount, in the quote token's base units: 5000000 is 5 USDC, paid from the creator's own account for it. Every amount in the API is base units, as on chain. A Token-2022 quote with a scaled UI amount (an xStock) or interest reads differently in wallets: turn a typed amount into base units with Token-2022's UiAmountToAmount.
Older wallets
Launches are version 1 transactions, Solana's newer format. A wallet that can't sign version 1 yet says so in supportedTransactionVersions; ask for "transaction_version": 0 for it: a version 0 transaction that loads shared accounts from relayfor.si's lookup table. A version 0 launch carries no opening buy.
Without a server
A project with no developer launches from the dashboard's Launch page. It builds the same launch with your strategy and route preview, and signs with the Solana wallet connected in your browser.