Skip to main content

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​

FieldTypeNotes
publicKeystringCreator wallet. Fee payer, first signer, receives creator fees later.
mintstringOptional. 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.
namestringUp to 32 bytes.
symbolstringUp to 13 bytes.
uristringOptional. 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.
imageUrlstringThe coin's image, fetched by the API (up to 8 MB). Or imageBase64 with the bytes. Required when uri is not given.
descriptionstringOptional.
twitter, telegram, websitestringOptional links.
initialBuynumberOptional dev buy in SOL, in the same transaction.
slippagenumberPercent, for the dev buy. Default 10.
creatorFeeAddressstringOptional. The wallet that collects the creator's share of trading fees. Defaults to publicKey.
quoteMintstringOptional. 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.
mayhemModebooleanpump.fun mayhem mode for the coin.
holderRewardbooleanA 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.
creatorFeeBpsnumberCustom 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.
priorityFeenumberSOL.
jitoTipnumberSOL.

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.