JetForge
Trade Solana fair-launch tokens on JetForge: list active markets, get live bonding-curve quotes, check wallet balances and build unsigned buy or sell transactions for your own wallet to sign. No API key; no tool can move funds.
Hosted MCP Server
npx add-mcp 'https://jetforge.io/api/mcp'Installs into Claude Code, Codex, Cursor and more
Documentation
Public REST API v1
Integrate JetForge bonding curve markets into your app, trading bot, or aggregator. Fetch live market data, get real-time quotes, and prepare unsigned Solana transactions. No API key or authentication required, and it can be called from any website. AI agents can connect through MCP; tools can read the OpenAPI spec.
● Live Report an issue →
Base URL
Auth
None required
Rate limit
300 req / min per IP
Returns the API status, current Solana slot, on-chain program ID, and network (devnet / mainnet). Use this to verify connectivity before making trade calls.
curl https://jetforge.io/api/v1/health
{
"status": "ok",
"version": "1.0.0",
"network": "mainnet",
"programId": "JetvDoU56t5vU6vo4RCkYmFUCatnQpLeXNWsuzxA4Cj",
"slot": 312847651,
"docs": "https://jetforge.io/docs/api"
}
List all active (non-graduated) JetForge markets with live on-chain bonding curve state — price, reserves, and graduation progress. Suitable for building market screeners or aggregator feeds.
Query Parameters
limitnumberoptionalNumber of markets to return. Default 50, max 200.
sortstringoptionalSort order: new (by creation time), trending (by volume), or graduating (closest to 85 SOL graduation).
curl "https://jetforge.io/api/v1/markets?limit=5&sort=trending"
{
"markets": [
{
"marketId": "EKpQ...cjm",
"name": "WIF",
"baseSymbol": "WIF",
"quoteSymbol": "SOL",
"baseMint": "EKpQ...cjm",
"bondingCurveAddress": "7xQ1...pda",
"creator": "9xDe...xyz",
"decimals": 6,
"price": 0.00000003,
"priceSOL": 0.00000003,
"virtualSolReserves": "30000000000",
"virtualTokenReserves": "947058823529412",
"realSolReserves": "1294200000",
"realTokenReserves": "42731050000000",
"graduated": false,
"progress": 1.5,
"imageUrl": "https://...",
"createdAt": "2026-05-24T10:00:00Z"
}
],
"count": 1,
"network": "mainnet"
}
Get a real-time trade quote directly from the on-chain bonding curve state. Returns expected output, fee, price impact, and minimum output after slippage. No transaction is sent.
Query Parameters
mintstringrequiredToken mint address (base58).
sidestringrequiredTrade direction: buy or sell.
amountnumberrequiredFor buy: SOL amount in lamports (1 SOL = 1,000,000,000). For sell: token amount in base units (6 decimals).
slippageBpsnumberoptionalSlippage tolerance in basis points. Default 300 (3%).
# Buy quote: 0.1 SOL (100,000,000 lamports)
curl "https://jetforge.io/api/v1/quote?mint=Acbazrpvf9kMMcsUCVf7J6hcUwsF3jFJRQ7DsWE6qjet&side=buy&amount=100000000"
# Sell quote: 1,000 tokens (1,000,000,000 base units at 6 decimals)
curl "https://jetforge.io/api/v1/quote?mint=Acbazrpvf9kMMcsUCVf7J6hcUwsF3jFJRQ7DsWE6qjet&side=sell&amount=1000000000"
{
"quote": {
"marketId": "EKpQ...cjm",
"bondingCurveAddress": "7xQ1...pda",
"side": "buy",
"inputAmount": "100000000",
"inputAmountHuman": "0.100000 SOL",
"outputAmount": "3464437480000",
"outputAmountHuman": "3,464,437.48 tokens",
"price": 0.000000029,
"priceImpactPct": 0.655,
"estimatedFeeLamports": "1000000",
"minimumOutput": "3354163955600",
"slippageBps": 300,
"solCharged": "100000000",
"partialFill": false,
"curveState": {
"virtualSolReserves": "30000000000",
"virtualTokenReserves": "947058823529412",
"realSolReserves": "1294200000",
"realTokenReserves": "42731050000000"
}
}
}
Build a fully-formed, unsigned Solana transaction for a buy or sell on the JetForge bonding curve. The server constructs the instruction, sets the fee payer and recent blockhash, then returns the transaction as base64. You sign it with your own wallet and broadcast it — JetForge never touches your private key.
Request Body (JSON)
mintstringrequiredToken mint address.
sidestringrequired"buy" or "sell".
amountstringrequiredLamports for buy, token base units for sell. Pass as string to avoid precision loss.
walletPublicKeystringrequiredCaller's wallet public key (base58). Used as fee payer.
slippageBpsnumberoptionalSlippage tolerance in basis points. Default 300.
curl -X POST https://jetforge.io/api/v1/trade/prepare \
-H "Content-Type: application/json" \
-d '{
"mint": "Acbazrpvf9kMMcsUCVf7J6hcUwsF3jFJRQ7DsWE6qjet",
"side": "buy",
"amount": "100000000",
"walletPublicKey": "YOUR_WALLET_PUBLIC_KEY",
"slippageBps": 300
}'
{
"transaction": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADe...base64==",
"message": "Sign and broadcast this transaction to buy on JetForge",
"quote": {
"marketId": "EKpQ...cjm",
"side": "buy",
"inputAmount": "100000000",
"outputAmount": "3464437480000",
"fee": "1000000",
"minimumOutput": "3354163955600",
"slippageBps": 300,
"solCharged": "100000000",
"partialFill": false,
"blockhash": "8ZyJ...",
"lastValidBlockHeight": 312847751
},
"instructions": {
"description": "Sign with your wallet and sendRawTransaction",
"code": [
"const tx = Transaction.from(Buffer.from(response.transaction, 'base64'));",
"const signed = await wallet.signTransaction(tx);",
"const sig = await connection.sendRawTransaction(signed.serialize());",
"await connection.confirmTransaction(sig, 'confirmed');"
]
}
}
Get the SOL balance and all SPL token positions for any Solana wallet. Optionally filter to specific mints. Useful for building portfolio views or checking a bot wallet's holdings before trading.
Query Parameters
mintsstringoptionalComma-separated list of mint addresses to filter. Omit to return all token accounts.
# All positions
curl "https://jetforge.io/api/v1/wallet/YOUR_WALLET_ADDRESS"
# Filter to specific tokens
curl "https://jetforge.io/api/v1/wallet/YOUR_WALLET_ADDRESS?mints=Acbazrpvf9kMMcsUCVf7J6hcUwsF3jFJRQ7DsWE6qjet"
{
"wallet": "9xDe...xyz",
"solBalance": "2450000000",
"solBalanceSOL": 2.45,
"tokenCount": 2,
"tokens": [
{
"mint": "EKpQ...cjm",
"balance": "3464437480000",
"balanceUi": 3464437.48,
"decimals": 6,
"ataAddress": "4rT2...ata"
}
]
}
Connect an AI Agent (MCP)
AI agents can use JetForge through its Model Context Protocol server. It uses Streamable HTTP and needs no API key.
Server URL
Claude Code
claude mcp add --transport http jetforge https://jetforge.io/api/mcp
Other MCP clients
{
"mcpServers": {
"jetforge": {
"type": "http",
"url": "https://jetforge.io/api/mcp"
}
}
}
Tools
list_markets
Active tokens with live price, reserves and graduation progress.
get_quote
Price a buy or sell from the live curve, with fee, price impact and minimum output.
prepare_trade
Build an unsigned transaction for the agent's wallet to sign and broadcast.
get_wallet
SOL and token balances of any wallet.
No tool can move funds. prepare_trade only returns an unsigned transaction, and your agent's own wallet signs and broadcasts it. Never give a private key to an MCP server, including this one. Limit how much the agent's wallet holds, and check each transaction before it's signed.
SDK Examples
Full buy flow in TypeScript: get a quote, prepare the unsigned transaction, inspect it, then sign and broadcast. The inspection checks the fee payer, that only the JetForge, compute-budget and associated-token programs appear, the token mint, the amount and the slippage floor. Never sign a transaction you haven't checked, from any API.
Website (React + wallet adapter)
// React (Next.js / Vite) — inside your <WalletProvider> + <ConnectionProvider>.
import { useCallback } from "react";
import { useConnection, useWallet } from "@solana/wallet-adapter-react";
import { ComputeBudgetProgram, PublicKey, Transaction } from "@solana/web3.js";
import { ASSOCIATED_TOKEN_PROGRAM_ID } from "@solana/spl-token";
const BASE = "https://jetforge.io/api/v1";
const JETFORGE_PROGRAM = new PublicKey("JetvDoU56t5vU6vo4RCkYmFUCatnQpLeXNWsuzxA4Cj");
const MAX_MICROLAMPORTS = 1_000_000; // refuse silly priority fees
/** fetch + JSON that throws on HTTP errors instead of passing { error } along. */
async function api<T>(path: string, init?: RequestInit): Promise<T> {
const res = await fetch(\`${BASE}${path}\`, init);
const body = await res.json().catch(() => ({}));
if (!res.ok) throw new Error(body.error ?? \`HTTP ${res.status}\`);
return body as T;
}
/**
* Check the server-built transaction BEFORE signing it: fee payer, programs,
* mint, amount and slippage floor. Never sign a transaction you haven't checked.
*/
function inspect(tx: Transaction, o: { wallet: PublicKey; mint: PublicKey; amount: bigint; minOut: bigint }) {
if (!tx.feePayer?.equals(o.wallet)) throw new Error("Fee payer is not your wallet");
const allowed = [JETFORGE_PROGRAM, ComputeBudgetProgram.programId, ASSOCIATED_TOKEN_PROGRAM_ID];
const jf = tx.instructions.filter((ix) => ix.programId.equals(JETFORGE_PROGRAM));
for (const ix of tx.instructions) {
if (!allowed.some((p) => p.equals(ix.programId))) throw new Error(\`Unexpected program ${ix.programId}\`);
if (ix.programId.equals(ComputeBudgetProgram.programId) && ix.data[0] === 3) {
const microLamports = ix.data.readBigUInt64LE(1); // SetComputeUnitPrice
if (microLamports > BigInt(MAX_MICROLAMPORTS)) throw new Error("Priority fee too high");
}
}
if (jf.length !== 1) throw new Error("Expected exactly one JetForge instruction");
const [ix] = jf;
if (!ix.keys.some((k) => k.pubkey.equals(o.mint))) throw new Error("Instruction is for a different token");
// data = 8-byte discriminator | amount (u64 LE) | minimum output (u64 LE)
if (ix.data.readBigUInt64LE(8) !== o.amount) throw new Error("Amount differs from your request");
if (ix.data.readBigUInt64LE(16) < o.minOut) throw new Error("Slippage protection is weaker than quoted");
}
export function useJetForgeBuy() {
const { connection } = useConnection();
const { publicKey, signTransaction } = useWallet();
return useCallback(async (mint: string, lamports: bigint, slippageBps = 300) => {
if (!publicKey || !signTransaction) throw new Error("Connect a wallet first");
// 1. Quote
const { quote } = await api<any>(\`/quote?mint=${mint}&side=buy&amount=${lamports}\`);
const expectedOut = BigInt(quote.outputAmount);
const minOut = (expectedOut * BigInt(10_000 - slippageBps)) / 10_000n;
// 2. Unsigned transaction, built by the server
const prepared = await api<any>("/trade/prepare", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
mint,
side: "buy",
amount: lamports.toString(),
walletPublicKey: publicKey.toBase58(),
slippageBps,
}),
});
const tx = Transaction.from(Buffer.from(prepared.transaction, "base64"));
// 3. Inspect, then sign and send
// (the price can move between the quote and this call; allow 1% drift on top of the slippage)
inspect(tx, { wallet: publicKey, mint: new PublicKey(mint), amount: lamports, minOut: (minOut * 99n) / 100n });
const signed = await signTransaction(tx);
const sig = await connection.sendRawTransaction(signed.serialize());
await connection.confirmTransaction(
{ signature: sig, blockhash: tx.recentBlockhash!, lastValidBlockHeight: prepared.quote.lastValidBlockHeight },
"confirmed"
);
return sig;
}, [connection, publicKey, signTransaction]);
}
// In a component:
// const buy = useJetForgeBuy();
// const sig = await buy("Acbazrpvf9kMMcsUCVf7J6hcUwsF3jFJRQ7DsWE6qjet", 100_000_000n); // 0.1 SOL
Bot (Node.js + keypair)
// Node.js bot — signs with a local keypair file. Keep that key on the bot's
// machine only, fund it with what the bot may spend, and never commit it.
import { readFileSync } from "node:fs";
import { ComputeBudgetProgram, Connection, Keypair, PublicKey, Transaction } from "@solana/web3.js";
import { ASSOCIATED_TOKEN_PROGRAM_ID } from "@solana/spl-token";
const BASE = "https://jetforge.io/api/v1";
const JETFORGE_PROGRAM = new PublicKey("JetvDoU56t5vU6vo4RCkYmFUCatnQpLeXNWsuzxA4Cj");
const connection = new Connection(process.env.RPC_URL ?? "https://api.mainnet-beta.solana.com", "confirmed");
const wallet = Keypair.fromSecretKey(Uint8Array.from(JSON.parse(readFileSync(process.env.KEYPAIR_PATH!, "utf8"))));
async function api(path: string, init?: RequestInit) {
const res = await fetch(\`${BASE}${path}\`, init);
const body = await res.json().catch(() => ({}));
if (!res.ok) throw new Error(body.error ?? \`HTTP ${res.status}\`);
return body;
}
async function buy(mint: string, lamports: bigint, slippageBps = 300) {
const { quote } = await api(\`/quote?mint=${mint}&side=buy&amount=${lamports}\`);
const minOut = (BigInt(quote.outputAmount) * BigInt(10_000 - slippageBps)) / 10_000n;
const prepared = await api("/trade/prepare", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ mint, side: "buy", amount: lamports.toString(), walletPublicKey: wallet.publicKey.toBase58(), slippageBps }),
});
const tx = Transaction.from(Buffer.from(prepared.transaction, "base64"));
// Inspect before signing (same checks as the React example)
if (!tx.feePayer?.equals(wallet.publicKey)) throw new Error("Fee payer is not this wallet");
const allowed = [JETFORGE_PROGRAM, ComputeBudgetProgram.programId, ASSOCIATED_TOKEN_PROGRAM_ID];
if (tx.instructions.some((ix) => !allowed.some((p) => p.equals(ix.programId)))) throw new Error("Unexpected program");
const jf = tx.instructions.filter((ix) => ix.programId.equals(JETFORGE_PROGRAM));
if (jf.length !== 1 || !jf[0].keys.some((k) => k.pubkey.equals(new PublicKey(mint)))) throw new Error("Bad JetForge instruction");
if (jf[0].data.readBigUInt64LE(8) !== lamports) throw new Error("Amount differs");
if (jf[0].data.readBigUInt64LE(16) < (minOut * 99n) / 100n) throw new Error("Slippage protection too weak");
tx.sign(wallet);
const sig = await connection.sendRawTransaction(tx.serialize());
await connection.confirmTransaction(
{ signature: sig, blockhash: tx.recentBlockhash!, lastValidBlockHeight: prepared.quote.lastValidBlockHeight },
"confirmed"
);
return sig;
}
buy("Acbazrpvf9kMMcsUCVf7J6hcUwsF3jFJRQ7DsWE6qjet", 100_000_000n) // 0.1 SOL
.then((sig) => console.log("TX:", sig))
.catch((e) => { console.error("Trade failed:", e.message); process.exit(1); });
Error Responses
400
Bad Request
Missing or invalid parameters.
404
Not Found
Mint not found on JetForge.
429
Too Many Requests
Over 300 requests/min from your IP. Wait and retry; see the RateLimit-* headers.
500
Server Error
RPC or internal error. Retry with backoff.
{ "error": "Human-readable error message" }
On-Chain Details
Program ID
JetvDoU56t5vU6vo4RCkYmFUCatnQpLeXNWsuzxA4Cj
Treasury
FpRb8wNaSg1zcezV3gm7L2rFAv8mNw7HH6Vhuauxkd6K
Fee
1% per trade — split: 40% creator / 40% treasury / 20% buyback
Graduation
85 SOL real reserves → auto-migrate to Raydium
AMM
Constant-product bonding curve (k = virtualSol × virtualTokens)