Partner API
Launch coins on Emerald from your own product: a Telegram bot, a trading terminal, a script. Two HTTP calls to prepare, one on-chain transaction to launch. The chain itself is permissionless; the API only gates our pinning bandwidth.
Base URL
https://emeraldfi.fun/api/v1. Partner keys are issued by the Emerald team. Ask in the Emerald Telegram with a one-line description of your integration.
1. Pin metadata
POST /api/v1/metadata with header X-API-Key: emk_…. Accepts multipart/form-data (image file + fields) or application/json (image as a base64 data URI or an https URL we download). Returns the ipfs:// URI you pass to launch().
Request (JSON)
curl -X POST https://emeraldfi.fun/api/v1/metadata \
-H "X-API-Key: emk_xxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"name": "Wen Lambo",
"symbol": "WEN",
"description": "Priced in Lamborghinis.",
"image": "https://example.com/wen.png",
"telegram": "https://t.me/wenlambo"
}'Response 200
{
"metadataUri": "ipfs://<jsonCID>", // pass THIS to launch()
"imageUri": "ipfs://<imageCID>",
"gateway": {
"metadata": "https://emerald-finance.myfilebase.com/ipfs/<jsonCID>",
"image": "https://emerald-finance.myfilebase.com/ipfs/<imageCID>"
}
}Errors are plain English: 400 bad input (with the reason), 401 bad key, 429 rate limit (30 per minute, 500 per day, Retry-After header set).
2. Read live launch parameters
GET /api/v1/launch-info. Public, cacheable for 30 seconds. Every value is read live from chain: never hardcode the fee.
Response 200
{
"chainId": 4663,
"rpc": "https://rpc.mainnet.chain.robinhood.com",
"launcher": "0x3bA3415217bFb083508F26e955fd61f6C95AbF79",
"launchFeeWei": "…", // launchFee() live
"pairs": [
{ "unit": "0xD56ac21dd0F3Ee62c8fe2b3473bb967D40fCe0D1", "symbol": "ROLEX", "usdPrice": 12500, "devBuyDecimals": 18 },
{ "unit": "0x886C830987fB5249339A7Cfc2a5422f31fcbA197", "symbol": "LAMBO", "usdPrice": 300000, "devBuyDecimals": 18 },
{ "unit": "0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168", "symbol": "USDG", "usdPrice": 1, "devBuyDecimals": 6 },
{ "unit": "0x0000000000000000000000000000000000000000", "symbol": "ETH", "usdPrice": …, "devBuyDecimals": 18,
"note": "devBuyAmount rides in msg.value ON TOP of launchFee" }
],
"launchParamsAbi": "(string name, string symbol, string metadataUri, address unit, uint24 poolFeePips, int24 rangeWidthTicks, uint256 devBuyAmount, bool feesToHolders)",
"poolFeePipsRange": [100, 50000],
"recommendedRangeWidthTicks": 20000,
"permit2": "0x000000000022D473030F116dDEE9F6B43aC78BA3",
"locker": "0x69b363A212dED9b83045369CAd33Aa756167dEC5"
}3. Send the launch transaction
Call launch(p) on the launcher with a single tuple argument of 8 fields, feesToHolders last. msg.value = launchFeeWei, plus devBuyAmount when the unit is ETH.
viem
import { createWalletClient, http, parseAbi } from "viem";
const info = await fetch("https://emeraldfi.fun/api/v1/launch-info").then(r => r.json());
const abi = parseAbi([
"function launch((string name,string symbol,string metadataUri,address unit,uint24 poolFeePips,int24 rangeWidthTicks,uint256 devBuyAmount,bool feesToHolders) p) payable returns (address token, bytes32 poolId)",
"event Launched(address indexed token,address indexed creator,address indexed unit,bytes32 poolId,string metadataUri,uint256 totalSupply,uint256 lpSupply)",
]);
const eth = info.pairs.find(p => p.symbol === "ETH");
const devBuy = 0n; // simplest for bots: ETH pair or devBuyAmount 0
const hash = await wallet.writeContract({
address: info.launcher, abi, functionName: "launch",
args: [{ name: "Wen Lambo", symbol: "WEN", metadataUri, unit: eth.unit,
poolFeePips: 10000, rangeWidthTicks: info.recommendedRangeWidthTicks,
devBuyAmount: devBuy, feesToHolders: true }],
value: BigInt(info.launchFeeWei) + devBuy,
});ERC-20 pairs and dev buys
A dev buy in ROLEX, LAMBO or USDG needs the wallet to hold the unit and two Permit2 approvals first: unit.approve(permit2, amount) then permit2.approve(unit, launcher, amount, deadline). If you do not need a dev buy, pass devBuyAmount = 0 and skip both.
4. Read the result from the receipt
- The coin address is
tokenin the launcher'sLaunchedevent. - The LP position id is
tokenIdin the locker'sRegistered(token, tokenId)event. Never derive it fromnextTokenId. - The coin appears on emeraldfi.fun automatically: the indexer picks up the event and renders name, symbol and image from the
ipfs://URI you pinned in step 1.
Limits and guardrails
Contract addresses live on the contracts page. Questions: the Emerald Telegram.