HomeExploreLaunchBurnsRewardsStatsAvatarDocs
Launch
·Let’s make something fun.DocsStatsRewardsBurnsXTerms of UsePrivacy Policy
  • Explore
  • Rewards
  • Burns
  • Stats
  • Docs
  • Overview
  • Before you start
  • 1. Register
  • 2. Build
  • 3. Check, sign, send
  • 4. List
  • Dev Launches
  • Pair assets
  • Full example
  • The launcher script
  • What is enforced

Launch API

How to launch a token on Lesgo from your own code: a Burn + Rewards launch or a Dev Launch on the Meteora curve, paired with GO or any accepted pair asset. Four HTTP calls and two signed transactions; any language that can sign an ed25519 message and a Solana transaction. Nothing here needs a key from Lesgo.

Overview

The site does the part that must be right, building the curve, and you do the part that must be yours, signing. In order:

  1. POST /api/upload: register the token. Image, name, ticker, links, pair asset, kind, and a proof the wallet is yours. Creates the token row and stores image and metadata permanently.
  2. POST /api/launch/build: get the unsigned launch transactions, built from that registration alone.
  3. Check, sign and send them with the wallet, the mint key and the config key.
  4. PATCH /api/tokens/<CA>: ask the site to list the token. It reads the pool and config from the chain and lists only when everything matches.

A token listed this way is a Lesgo launch in every respect: the burn program is the fee claimer, the launch fee against sniper bots applies (50% at launch falling to 2% over the first 150 slots, your own buys included), holders earn the pair-asset side of every sell, and the worker settles it like every other token.

Before you start

ItemDetail
Base URLhttps://www.lesgo.fun (mainnet). GET /api/health answers { ok, cluster } and needs nothing.
WalletA keypair you control, holding about 0.06 SOL for the config and pool rent plus fees. This wallet becomes the token creator on chain.
KeypairsTwo fresh keypairs per launch: the token mint (its public key is the CA) and the Meteora config account. Generate them, register their public keys, sign with them once, then they are not needed again.
Session cookieEvery /api call except /api/launch/build and /api/health needs the cookie any page load sets: GET /explore, take the lesgo_s value from Set-Cookie, send it as Cookie on later calls. It lasts seven days.
Rate limitsRegistration: 10 per network address per hour, 5 per wallet per hour, and a daily launch capacity. Builder: 30 per address per minute. Listing: 30 per address per minute. A 429 answers with a message.
ErrorsEvery error is JSON, { error: "message" } with a 4xx or 5xx status. The pair resolver answers { ok: false, reason } with 200 instead.

1. Register: POST /api/upload

multipart/form-data. Creates the token row bound to your wallet, the CA and the config address, stores the image and the metadata JSON, and answers with their permanent URLs. Nothing is on chain yet; an unlaunched registration is dropped after a while.

FieldValue
imageRequired. PNG, JPEG or WebP, up to 2 MB, at least 128 by 128 pixels, no more than 1.25:1. Re-encoded and stripped of metadata on our side.
mintThe CA: the public key of the mint keypair you generated.
name2 to 32 characters.
symbol2 to 10 letters or numbers; stored upper-case.
descriptionUp to 500 characters. Optional.
website, twitter, telegramhttp(s) URLs. Optional.
kindburn for Burn + Rewards, dev for a Dev Launch.
feeBpsburn: 100 (a fixed value; the curve charges the launch fee then 2%). dev: the Dev Launch fee, 100 to 500 in steps of 100 (1% to 5%).
burnBasedev only: 1 to burn the token side of fees (default), 0 to take every fee in the pair asset.
creatorYour wallet public key.
quoteMintThe pair asset CA. GO is D1YZZg9dBZ7AbfknZVbaeVLto36eySwoFYEVhZrD4F4n.
backendmeteora
meteoraConfigThe public key of the config keypair you generated.
tsUnix time in seconds, within five minutes of the server clock.
signatureBase58 ed25519 signature by the creator wallet over the UTF-8 message below. Each (wallet, CA, ts) signature works once.
lesgo:v1:mainnet:launch:<CA>:<ts>

Response 200: { imageUrl, metadataUrl }. Errors: 400 with the field problem (bad ticker, image too small, pair asset not a token or not one the curve accepts), 401 signature expired, already used or not by that wallet, 409 the CA is already registered, 429 rate limited, 503 capacity or storage unavailable (nothing was registered).

2. Build: POST /api/launch/build

application/json. No cookie needed. Body { "mint": "<CA>" }. The site reads the registration (creator, pair asset, kind, fee, name, ticker, metadata) and returns the transactions for the canonical Lesgo config and the pool, priced like the launch form, with a fresh blockhash and a compute budget already in place. You cannot pass any launch parameter here: only the CA.

{
  "mint": "<CA>", "config": "<config address>", "pool": "<pool address>", "creator": "<wallet>",
  "pair": { "mint": "<pair CA>", "decimals": 6, "usd": 0.0028, "liquidityUsd": 344000 },
  "target": { "thresholdUi": 3589273.7, "standardUi": 3589273.7, "lowered": null },
  "transactions": [
    { "label": "launch", "transaction": "<base64>", "signers": ["<wallet>", "<config address>", "<CA>"], "bytes": 1116 }
  ],
  "next": null,
  "blockhash": { "blockhash": "...", "lastValidBlockHeight": 123456 },
  "preview": false
}
FieldMeaning
transactions[].transactionThe unsigned transaction, base64, legacy format (web3.js Transaction.from). Fee payer is your wallet; the blockhash is set.
transactions[].signersThe public keys whose signatures the transaction needs: your wallet, and the config and mint keys as required.
transactions[].labellaunch (config and pool together), config, or pool.
nextnull when the transactions above complete the launch. "pool" when the config and pool did not fit in one transaction (a long name or metadata URL), or when you asked for two steps: send the config transaction, then call the builder again with the same body and it returns the pool transaction.
targetThe graduation target in the pair asset's units: the value of 85 SOL, lowered for a pair with under $25,000 of liquidity (lowered: "liquidity") or for the most a Meteora curve can hold (lowered: "curve").
blockhashValid for about a minute. If you sign later than that, call the builder again for fresh transactions.

Options: { "mint": "<CA>", "twoStep": true } always returns the config first and the pool on a second call, for tools that prefer two smaller transactions. A preview, { "preview": true, "creator", "quoteMint", "kind", "feeBps", "burnBase", "name", "symbol" }, prices the curve and builds the transactions for a launch that is not registered: use it for a dry run (the answer carries "preview": true and is not signable for a real launch).

Errors: 400 not a curve launch, no metadata yet, pair asset refused, or the config address already holds something that is not this launch's canonical config; 404 no registration for this CA; 409 already launched, or the pool already exists (go to step 4); 503 no live price for the pair asset right now.

3. Check, sign, send

Deserialize each transaction and, before signing, check it is a launch and nothing else. A launch transaction has these properties and no others; refuse anything that differs, whatever the reason.

  • The fee payer is your wallet.
  • Every instruction goes to one of three programs: the compute budget program (ComputeBudget111111111111111111111111111111), Meteora's Dynamic Bonding Curve (dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN), or, for a Dev Launch only, Lesgo's burn program (H6Gdk44WWcA59Qtq9hmWuUv48oXox7y7KvEAtfbePm5S), which records you as the creator. No system transfers, no token approvals, nothing else.
  • The signatures required are exactly the ones named in signers: your wallet, the config key, the mint key.

Then sign with those keys, send with sendRawTransaction (preflight on), and confirm against the returned blockhash. The last transaction's signature (the one that creates the pool) is the launch signature for step 4. If next was "pool", call the builder again once the config has confirmed and repeat.

4. List: PATCH /api/tokens/<CA>

application/json, cookie needed. Body { "launchSig": "<signature of the pool transaction>" }. The site finds the pool from the registered CA, pair asset and config address, then checks on chain that the pool was created by your wallet, on that config, and that the config is canonical for the registered kind: the burn program as fee claimer, the launch fee schedule, the fee mode, the migration settings, no vesting, no dynamic fee, nothing else. For a Dev Launch it also checks the creator record. Response 200: { ok: true, verified: true }, and the token is live on the site.

Errors: 400 No Lesgo pool for this CA yet (the RPC has not seen it; retry for a few seconds), Pool creator does not match, Not a Lesgo config (the launch was not built from the builder's transaction, or was altered; it will never be listed), 404 nothing to verify (unknown CA, or already listed). If this call does not go through for a transient reason, the worker verifies every registration from the chain within a minute and lists it the same way.

Dev Launches

Register with kind=dev, feeBps 100 to 500 and burnBase. The builder's pool transaction then carries one more instruction, the burn program's register_dev_launch, which records your wallet as the creator who receives the creator share of fees; the listing check requires that record. A Dev Launch has no launch fee: its curve charges the flat fee you chose from the first trade.

Pair assets

GET /api/pairs/resolve?mint=<CA> (cookie needed) tells you whether a token can be a pair asset and how the site sees it: { ok, symbol, name, decimals, program, via, liquidityUsd, usdPrice, warning } or { ok: false, reason }. Only via: "meteora" pairs launch through this API (a plain SPL token, or a Token-2022 token with nothing but metadata). A token with a transfer fee pairs as a direct launch on the site, which this API does not build. Registration and the builder run the same check, so a pair the resolver refuses cannot be registered.

Full example

Node 20 or newer, @solana/web3.js and bs58; save it as launch.mjs next to wallet.json and logo.png. The same flow in any language: an ed25519 signature over the message, a multipart POST, a JSON POST, a transaction signed with three keys, a JSON PATCH.

// launch.mjs: node launch.mjs   (Node 20+, npm install @solana/web3.js bs58)
import { Connection, Keypair, Transaction } from '@solana/web3.js';
import { createPrivateKey, sign } from 'node:crypto';
import bs58 from 'bs58';
import fs from 'node:fs';

const SITE = 'https://www.lesgo.fun';
const wallet = Keypair.fromSecretKey(Uint8Array.from(JSON.parse(fs.readFileSync('wallet.json', 'utf8'))));
const mintKp = Keypair.generate(), configKp = Keypair.generate();
const conn = new Connection('https://api.mainnet-beta.solana.com', 'confirmed');
const ALLOWED = new Set(['ComputeBudget111111111111111111111111111111', 'dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN', 'H6Gdk44WWcA59Qtq9hmWuUv48oXox7y7KvEAtfbePm5S']);

// The session cookie any page load sets.
const page = await fetch(SITE + '/explore', { redirect: 'manual' });
const cookie = page.headers.getSetCookie().map(c => c.split(';')[0]).find(c => c.startsWith('lesgo_s='));

// 1. Register, with the wallet's signature over lesgo:v1:mainnet:launch:<CA>:<ts>.
const mint = mintKp.publicKey.toBase58(), ts = Math.floor(Date.now() / 1000);
const seed = Buffer.from(wallet.secretKey.subarray(0, 32));
const key = createPrivateKey({ key: Buffer.concat([Buffer.from('302e020100300506032b657004220420', 'hex'), seed]), format: 'der', type: 'pkcs8' });
const signature = bs58.encode(sign(null, Buffer.from('lesgo:v1:mainnet:launch:' + mint + ':' + ts), key));
const fd = new FormData();
for (const [k, v] of Object.entries({ mint, name: 'My Token', symbol: 'MYT', description: '', website: '', twitter: '', telegram: '',
  kind: 'burn', feeBps: '100', creator: wallet.publicKey.toBase58(), quoteMint: 'D1YZZg9dBZ7AbfknZVbaeVLto36eySwoFYEVhZrD4F4n',
  backend: 'meteora', meteoraConfig: configKp.publicKey.toBase58(), ts: String(ts), signature })) fd.set(k, v);
fd.set('image', new File([fs.readFileSync('logo.png')], 'logo.png', { type: 'image/png' }));
const reg = await fetch(SITE + '/api/upload', { method: 'POST', headers: { cookie }, body: fd }).then(r => r.json());
if (reg.error) throw new Error(reg.error);

// 2 and 3. Build, check, sign, send; again if the pool comes in a second transaction.
const keys = { [wallet.publicKey.toBase58()]: wallet, [mint]: mintKp, [configKp.publicKey.toBase58()]: configKp };
let launchSig, b;
do {
  b = await fetch(SITE + '/api/launch/build', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ mint }) }).then(r => r.json());
  if (b.error) throw new Error(b.error);
  for (const t of b.transactions) {
    const tx = Transaction.from(Buffer.from(t.transaction, 'base64'));
    if (!tx.feePayer.equals(wallet.publicKey)) throw new Error('not my wallet paying');
    for (const ix of tx.instructions) if (!ALLOWED.has(ix.programId.toBase58())) throw new Error('unexpected program ' + ix.programId);
    tx.sign(...t.signers.map(k => keys[k] ?? (() => { throw new Error('unexpected signer ' + k); })()));
    launchSig = await conn.sendRawTransaction(tx.serialize());
    await conn.confirmTransaction({ signature: launchSig, ...b.blockhash }, 'confirmed');
  }
} while (b.next === 'pool');

// 4. List.
const listed = await fetch(SITE + '/api/tokens/' + mint, { method: 'PATCH', headers: { 'content-type': 'application/json', cookie }, body: JSON.stringify({ launchSig }) }).then(r => r.json());
console.log(listed.verified ? SITE + '/token/' + mint : listed.error);

In Python the same signature is nacl.signing.SigningKey(seed).sign(message).signature (PyNaCl) encoded with base58, and the transaction is solders.transaction.Transaction.from_bytes signed with the three keypairs.

The launcher script

The repository ships cranks/scripts/launch.js, which does all of the above from a keypair file: node scripts/launch.js --keypair wallet.json --name "My Token" --symbol MYT --image logo.png, with --dev 3, --dev-no-burn, --pair <CA>, --two-step, --json, and --dry-run (prices and builds without registering or sending). It runs the transaction checks above before signing anything, and needs only @solana/web3.js and bs58.

What is enforced, and by whom

PropertyEnforced by
The token is yoursThe registration signature (your wallet) and the pool creator on chain (your wallet), checked at listing.
The curve is Lesgo'sThe builder makes it from the registration alone; the listing check reads the config from the chain and compares every parameter. An altered or foreign config is never listed.
The launch feeOn chain, by Meteora's program, from the config: 50% falling to 2% over 150 slots for Burn + Rewards. The listing check refuses configs without it.
Fees go to the burn programThe config names the burn program as fee claimer; the worker settles it: token side burned, pair-asset side to holders and the platform (or to the creator for a Dev Launch).
No config reuseEvery launch has its own config; a registration naming an existing address gets a pool built only if that config is canonical for this launch and pair.
Your wallet is safe from usYour client checks each transaction before signing: fee payer, the three programs, the named signers. Do not skip it.

Back to the docs