Create Token
Launch a pump.fun coin with one call: send the coin's name, symbol, image and links, and the API pins the metadata on IPFS, picks a mint address ending in pump, and returns the create transaction with an optional dev buy in it. Only your wallet signs. Your keys never leave your machine.
Everything is optional beyond that: bring your own metadata uri, or your own mint keypair, and the API uses those instead. An optional initialBuy puts your dev buy in the same transaction so nobody can front-run the launch.
POST https://sol.shrine.trade/api/create-token
Request
| Field | Type | Notes |
|---|---|---|
publicKey | string | Creator wallet. Fee payer, first signer, receives creator fees later. |
mint | string | Optional. Leave it out for an address ending in pump, signed for you (see below). Or the public key of a keypair you generated; it then signs as well. |
name | string | Up to 32 bytes. |
symbol | string | Up to 13 bytes. |
uri | string | Optional. A metadata JSON URL you already host. Leave it out and pass the details below instead; the metadata is pinned on IPFS for you and the uri comes back in the answer. |
imageUrl | string | The coin's image, fetched by the API (up to 8 MB). Or imageBase64 with the bytes. Required when uri is not given. |
description | string | Optional. |
twitter, telegram, website | string | Optional links. |
initialBuy | number | Optional dev buy in SOL, in the same transaction. |
slippage | number | Percent, for the dev buy. Default 10. |
creatorFeeAddress | string | Optional. The wallet that collects the creator's share of trading fees. Defaults to publicKey. |
quoteMint | string | Optional. Price the coin in USDC or any mint on pump.fun's quote-control list instead of SOL. initialBuy is then in that quote, and so is the fee. |
mayhemMode | boolean | pump.fun mayhem mode for the coin. |
holderReward | boolean | A holder rewards coin: the creator fee of every trade is set aside for the coin's holders and paid out by pump.fun. Permanent; there is nothing for the creator to claim afterwards, and creatorFeeAddress is not used as the recipient. |
creatorFeeBps | number | Custom pairs only (a quote other than SOL or USDC): the coin's own creator fee, up to pump.fun's current cap (300 today). SOL- and USDC-paired coins always use the standard schedule. |
priorityFee | number | SOL. |
jitoTip | number | SOL. |
Every launch uses pump.fun's create_v2: the coin is a Token-2022 mint. With quoteMint set, the dev buy and every later trade settle in that quote, and the response carries quoteMint and feeMint. Allowed quotes are USDC and the mints on pump.fun's custom pairs list; anything else is refused before a transaction is built, as are cashback coins, which pump.fun no longer creates.
To launch and have other wallets buy in the same block, put the create in the first transaction of a bundle and the buys in the next ones, referring to the new coin by mintRef. A dev buy plus one more buy also fits in one multi-action transaction, on SOL and on a custom quote alike.
Vanity address ending in pump
Leave mint out and the coin gets an address ending in pump, like launches from pump.fun's own site. We keep a pool of pre-generated mint keypairs: the returned tx is already signed by the mint, so only your wallet signs, and mintSecretKey carries the mint's secret for libraries that rebuild the signature list themselves. Each address is handed out once. The mint key only matters for signing the create; once the coin exists, pump.fun's program owns the mint, so nobody (us included) can do anything with that key afterwards.
const res = await fetch("https://sol.shrine.trade/api/create-token", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
publicKey: wallet.publicKey.toBase58(),
name: "My Coin",
symbol: "MINE",
uri: "https://ipfs.io/ipfs/<metadata json>",
initialBuy: 0.5,
}),
});
const { tx, mint, vanity } = await res.json(); // mint ends in "pump" when vanity is true
const transaction = VersionedTransaction.deserialize(Buffer.from(tx, "base64"));
transaction.sign([wallet]); // the mint's signature is already in place
In Python (solders), build the signed transaction from both keys: VersionedTransaction(tx.message, [wallet, Keypair.from_base58_string(mintSecretKey)]). If the pool is ever empty the launch still goes through with a random address and vanity: false.
Upload metadata separately
You do not need this: create-token pins the metadata itself when you give it the details. POST https://sol.shrine.trade/api/upload-metadata is the same step on its own, for when you want the uri first (to reuse it, or to launch later). Free.
{
"name": "My Coin",
"symbol": "COIN",
"description": "…",
"imageUrl": "https://…/logo.png",
"twitter": "https://x.com/…",
"telegram": "https://t.me/…",
"website": "https://…"
}
imageUrl is fetched by us (up to 8 MB); pass imageBase64 instead to send the bytes directly. The answer is { "uri": "https://ipfs.io/ipfs/…", "image": "https://ipfs.io/ipfs/…", "metadata": { … } }.
Example
import { Keypair, VersionedTransaction } from "@solana/web3.js";
import bs58 from "bs58";
const wallet = Keypair.fromSecretKey(bs58.decode("<your wallet private key, base58>"));
const mint = Keypair.generate(); // keep this: it is the token's identity
const res = await fetch("https://sol.shrine.trade/api/create-token", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
publicKey: wallet.publicKey.toBase58(),
mint: mint.publicKey.toBase58(),
name: "My Coin",
symbol: "MINE",
uri: "https://ipfs.io/ipfs/<metadata json>",
initialBuy: 0.5,
slippage: 10,
priorityFee: 0.0005,
}),
});
const { tx } = await res.json();
const transaction = VersionedTransaction.deserialize(Buffer.from(tx, "base64"));
transaction.sign([wallet, mint]); // both signers, wallet first
// Send through the shrine.trade relay (no RPC needed); it waits for confirmation.
const sent = await (await fetch("https://sol.shrine.trade/api/send", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ signedTx: Buffer.from(transaction.serialize()).toString("base64") }),
})).json();
console.log(sent.status, `https://solscan.io/tx/${sent.signature}`);
Response
{
"tx": "<base64 unsigned transaction>",
"blockhash": "…",
"mint": "…",
"bondingCurve": "…",
"feeLamports": 1250000,
"signers": ["<wallet>", "<mint>"]
}
uri is the metadata the coin was created with, and image its pinned image when the API did the pinning. Without mint in the request, the answer also carries mintSecretKey (base58) and vanity (true for an address ending in pump), and tx already holds the mint's signature.
When the launch and its dev buy do not fit one transaction (long metadata, a wallet's first pump.fun buy), the answer carries two: tx is the launch alone, signed by the wallet and the mint, and buyTx is the dev buy, signed by the wallet, on the same blockhash. Send tx then buyTx, or both as one bundle; note says so.
Fees
Creation itself is free apart from network rent. The dev buy pays the normal 0.25% trade fee, included in the transaction.
Try it
Paste your wallet private key, fill in the coin, and press Sign & send. The API only ever receives your public key and returns an unsigned transaction; your browser generates the mint keypair, signs with both keys, and posts the signed bytes to /api/send (or your own RPC). The mint's private key is printed in the output: keep it. This launches a real coin on mainnet.