# Flap Trading API > Trade and launch tokens on Flap, on BNB Chain --- # Flap API for Trading Bots on BNB Chain > Build bots that trade and launch tokens on Flap and PancakeSwap on BNB Chain through one free, keyless API. Buy, sell, stream every launch live, create tokens with a tax, collect creator revenue. # Flap Trading API The simplest way to trade and launch tokens on Flap - the launchpad on BNB Chain - through an API. Buy and sell any Flap token, on its bonding curve or in the PancakeSwap pool it graduates to; launch new ones, with or without a tax. shrine.trade is a Flap API for executing buys and sells, streaming every launch and graduation the moment it happens, creating tokens with a dev buy, reading curve and tax state, and collecting creator revenue - across both venues a Flap token passes through. Start with [Buy & Sell](/local-trade), watch the [live feed](/live-launches), or [launch a token](/create-token). ## One API, both Flap venues Flap tokens on their bonding curve and Flap tokens in their PancakeSwap pool after graduation. Pass a token address and the API routes it - the request is the same before and after graduation. Tokens priced in USD1, or in a tokenised stock like NVDAB, TSLAB or SPYB, are bought with plain BNB; Flap swaps on the way in, as part of the transaction. ## Why shrine.trade - **Nothing to sign up for.** No account, no API key, no rate plan. Send the request. - **Non-custodial by construction.** The API hands back an unsigned transaction; your wallet signs it and hands the signed bytes back to be broadcast. We never see a key and never touch funds - and you never need an RPC. - **Everything in BNB.** Buy any token with BNB, whatever it is priced in. Sell back to BNB by default. - **Tax tokens, handled.** Flap's tax tokens - the most common kind on BNB - quote correctly on every side, on the curve and after graduation. - **FREE live feed.** Every launch and graduation over WebSocket, within a second of the block. - **Fast.** Quotes come from Flap's own Portal, simulated as your wallet, with every other chain read done in parallel - a few hundred milliseconds end to end. - **Checked before you sign.** Funds, balances, approvals, buy quotas and slippage are verified up front, so what you get back lands. - **Front-run protected.** - **Scripts, not SDKs.** Each page carries a complete Node.js and Python script. Edit the constants at the top and run it; there is nothing to install beyond ethers or web3. - **Built for bots.** Stable error codes, consistent nonces, BNB-denominated amounts, and the [sniper tutorial](/tutorials/snipe-flap-launches) to start from. ``` Base URL: https://api.shrine.trade/bnb ``` ## Endpoints | Endpoint | What it does | |---|---| | `POST /api/local-trade` | Buy or sell any Flap token, curve or PancakeSwap → [Buy & Sell](/local-trade) | | `POST /api/send` | Broadcast a transaction you signed - no RPC of your own needed → [Sending](/local-trade#sending) | | `WS /api/launches/ws` | Live feed of launches and graduations → [Live Launches](/live-launches) | | `POST /api/create-token` | Launch a token on Flap, standard or tax, with an optional dev buy → [Create Token](/create-token) | | `GET /api/token/{address}` | Curve state, progress, tax, buy quota, quote asset → [Token Info](/token-info) | | `GET /api/fees/{wallet}` · `POST /api/claim-fees` | What your launches earned, and the transactions that pay it out → [Creator Revenue](/creator-fees) | ## Questions? Read the [FAQ](/faq) for supported venues, fees, amounts, slippage, private-key safety and the live feed. Or follow a [tutorial](/tutorials) - sniping launches, trading tax tokens, and what gas costs on BNB Chain. ## Stay updated Releases are announced on [X, @shrinetrade](https://x.com/shrinetrade). For help, the [Telegram group](https://t.me/+nEqAowTK8BZhZjFk) is where the team answers. If you build with an AI coding tool, point it at [llms-full.txt](/llms-full.txt): the whole of this site as one plain-text file. *shrine.trade is a Flap and PancakeSwap API for BNB Chain developers and traders. It is an independent integration, not affiliated with Flap or Binance; Flap's contracts and its protocol fees belong to Flap. Built by traders, for traders.* --- # Create a Token on Flap (BNB Chain) > Launch a token on the Flap bonding curve on BNB Chain with one signed transaction - metadata, image, an optional buy and sell tax, a dev buy, and BNB, USD1 or a tokenised stock such as NVDAB or TSLAB as the quote. # Create Token ``` POST https://api.shrine.trade/bnb/api/create-token ``` Builds the Flap launch transaction for you: metadata pinned through Flap's IPFS gateway, the vanity address Flap requires, the tax setup if you want one, and - if you want one - a dev buy in the same transaction. You sign and send it; the token and its bonding curve exist as soon as it confirms. shrine.trade takes **no fee** on creation, and neither does Flap: the only cost is gas. The transaction value is your dev buy, if any. Every launch goes on the Flap bonding curve and graduates to PancakeSwap on its own once 800M tokens are sold. Two kinds of token: - **Standard** - no tax. Graduates to a PancakeSwap Infinity pool whose LP fees are paid to holders as a dividend. - **Tax token** - you set a tax on buys and sells, charged on every trade. Flap's tax system decides where it goes: to you, burned, paid to holders as dividends, added to liquidity, or any mix. Graduates to PancakeSwap v2. This is what most Flap launches are. > **About the private key field.** **The key never leaves your machine.** It signs locally; only the signed transaction is handed to `/api/send` to broadcast. The key itself is never sent to shrine.trade. Pinning happens first: **Build waits for the image and metadata to finish pinning to IPFS**, so the token shows up on flap.sh with its image the moment it launches. ## Example **JavaScript** ```js const { readFileSync } = require("node:fs"); const { Wallet } = require("ethers"); // ─── your token ─────────────────────────────────────── const PRIVATE_KEY = "0xYOUR_PRIVATE_KEY"; const NAME = "Grene"; const SYMBOL = "GRENE"; const IMAGE = "./logo.png"; // image file, next to this script const DESCRIPTION = "the greenest coin on BNB Chain"; // ─── links — all optional, "" to leave one out ──────── const TWITTER = "https://x.com/grene"; const TELEGRAM = ""; const WEBSITE = "https://grene.example"; // ─── economics ──────────────────────────────────────── const PAIR_TOKEN = "BNB"; // what the curve holds: BNB, USD1, a stock ticker like NVDAB or TSLAB, or an address const DEV_BUY = ""; // your own opening buy, in PAIR_TOKEN. "" = none const BUY_TAX = 0; // % of every buy. 0 on both = standard token const SELL_TAX = 0; // % of every sell const BENEFICIARY = ""; // where your share of the tax goes. "" = the launching wallet // how the tax splits, % of the tax, must add up to 100: const TO_YOU = 100; // to BENEFICIARY, in the quote asset const BURNED = 0; const TO_HOLDERS = 0; // as dividends, in DIVIDEND_TOKEN const TO_LIQUIDITY = 0; const DIVIDEND_TOKEN = "quote"; // "quote", "self", or an ERC-20 address // ────────────────────────────────────────────────────── async function main() { const wallet = new Wallet(PRIVATE_KEY); // signs only; no node needed // 1. Pin the image + metadata through Flap's IPFS gateway. const form = new FormData(); form.append("file", new Blob([readFileSync(IMAGE)], { type: "image/png" }), "logo.png"); form.append("description", DESCRIPTION); form.append("twitter", TWITTER); form.append("telegram", TELEGRAM); form.append("website", WEBSITE); const up = await fetch("https://api.shrine.trade/bnb/api/upload-image", { method: "POST", body: form, }); const uploaded = await up.json(); if (uploaded.error) throw new Error(`${uploaded.error}: ${uploaded.message}`); console.log("metadata pinned:", uploaded.meta); // 2. Ask shrine.trade to build the launch transaction. const res = await fetch("https://api.shrine.trade/bnb/api/create-token", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ name: NAME, symbol: SYMBOL, meta: uploaded.meta, pairToken: PAIR_TOKEN, buyTaxBps: BUY_TAX * 100, sellTaxBps: SELL_TAX * 100, // Left out entirely when empty - the API picks sane defaults. ...(DEV_BUY ? { initialBuy: DEV_BUY } : {}), ...(BENEFICIARY ? { beneficiary: BENEFICIARY } : {}), ...(BUY_TAX || SELL_TAX ? { marketingBps: TO_YOU * 100, deflationBps: BURNED * 100, dividendBps: TO_HOLDERS * 100, lpBps: TO_LIQUIDITY * 100, dividendToken: DIVIDEND_TOKEN, } : {}), from: wallet.address, }), }); const body = await res.json(); if (body.error) throw new Error(`${body.error}: ${body.message}`); console.log("token will be", body.token, "-", body.tokenType); // 3. Sign locally - your private key never leaves this script. // 4. Hand each signed transaction to the API to broadcast, in order (a dev // buy in USD1 needs an approval first). No RPC of your own needed. let explorer; for (const tx of body.txs) { const signed = await wallet.signTransaction({ to: tx.to, data: tx.data, value: BigInt(tx.value), gasLimit: BigInt(tx.gas), maxFeePerGas: BigInt(tx.maxFeePerGas), maxPriorityFeePerGas: BigInt(tx.maxPriorityFeePerGas), nonce: tx.nonce, chainId: tx.chainId, type: 2, }); const sent = await (await fetch("https://api.shrine.trade/bnb/api/send", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ signedTx: signed }), })).json(); if (sent.error) throw new Error(`${sent.error}: ${sent.message}`); if (sent.status !== "landed") throw new Error(`${tx.description} ${sent.status}: ${sent.explorer}`); explorer = sent.explorer; } // 5. The address was known before sending: Flap deploys with CREATE2. console.log("token launched:", body.token); console.log("tx:", explorer); console.log("page:", "https://flap.sh/token/" + body.token); } main(); ``` Save it as `launch.js`, put your image next to it as `logo.png`, then: ```bash npm install ethers node launch.js ``` **Python** ```python import requests from eth_account import Account # ─── your token ─────────────────────────────────────── PRIVATE_KEY = "0xYOUR_PRIVATE_KEY" NAME = "Grene" SYMBOL = "GRENE" IMAGE = "./logo.png" # image file, next to this script DESCRIPTION = "the greenest coin on BNB Chain" # ─── links - all optional, "" to leave one out ──────── TWITTER = "https://x.com/grene" TELEGRAM = "" WEBSITE = "https://grene.example" # ─── economics ──────────────────────────────────────── PAIR_TOKEN = "BNB" # what the curve holds: BNB, USD1, a stock ticker like NVDAB or TSLAB, or an address DEV_BUY = "" # your own opening buy, in PAIR_TOKEN. "" = none BUY_TAX = 0 # % of every buy. 0 on both = standard token SELL_TAX = 0 # % of every sell BENEFICIARY = "" # where your share of the tax goes. "" = the launching wallet # how the tax splits, % of the tax, must add up to 100: TO_YOU = 100 # to BENEFICIARY, in the quote asset BURNED = 0 TO_HOLDERS = 0 # as dividends, in DIVIDEND_TOKEN TO_LIQUIDITY = 0 DIVIDEND_TOKEN = "quote" # "quote", "self", or an ERC-20 address # ────────────────────────────────────────────────────── account = Account.from_key(PRIVATE_KEY) # signs only; no node needed # 1. Pin the image + metadata through Flap's IPFS gateway. with open(IMAGE, "rb") as f: up = requests.post( "https://api.shrine.trade/bnb/api/upload-image", files={"file": ("logo.png", f, "image/png")}, data={"description": DESCRIPTION, "twitter": TWITTER, "telegram": TELEGRAM, "website": WEBSITE}, ).json() if "error" in up: raise SystemExit(f"{up['error']}: {up['message']}") print("metadata pinned:", up["meta"]) # 2. Build the launch transaction. payload = { "name": NAME, "symbol": SYMBOL, "meta": up["meta"], "pairToken": PAIR_TOKEN, "buyTaxBps": BUY_TAX * 100, "sellTaxBps": SELL_TAX * 100, "from": account.address, } if DEV_BUY: payload["initialBuy"] = DEV_BUY if BENEFICIARY: payload["beneficiary"] = BENEFICIARY if BUY_TAX or SELL_TAX: payload.update({"marketingBps": TO_YOU * 100, "deflationBps": BURNED * 100, "dividendBps": TO_HOLDERS * 100, "lpBps": TO_LIQUIDITY * 100, "dividendToken": DIVIDEND_TOKEN}) body = requests.post("https://api.shrine.trade/bnb/api/create-token", json=payload).json() if "error" in body: raise SystemExit(f"{body['error']}: {body['message']}") print("token will be", body["token"], "-", body["tokenType"]) # 3. Sign locally and hand each signed transaction to the API to broadcast. for tx in body["txs"]: signed = Account.sign_transaction( { "to": tx["to"], "data": tx["data"], "value": int(tx["value"]), "gas": tx["gas"], "maxFeePerGas": int(tx["maxFeePerGas"]), "maxPriorityFeePerGas": int(tx["maxPriorityFeePerGas"]), "nonce": tx["nonce"], "chainId": tx["chainId"], }, account.key, ) sent = requests.post("https://api.shrine.trade/bnb/api/send", json={"signedTx": "0x" + signed.raw_transaction.hex().removeprefix("0x")}).json() if "error" in sent: raise SystemExit(f"{sent['error']}: {sent['message']}") if sent["status"] != "landed": raise SystemExit(f"{tx['description']} {sent['status']}: {sent['explorer']}") print(tx["description"] + ":", sent["explorer"]) print("token launched:", body["token"]) print("page:", "https://flap.sh/token/" + body["token"]) ``` Save it as `launch.py`, put your image next to it as `logo.png`, then: ```bash pip install eth-account requests python launch.py ``` ## Supported quote assets A Flap token can be priced in BNB, in a stablecoin or major, or in one of Binance's tokenised stocks and ETFs on BNB Chain - a meme that trades directly against NVIDIA, Tesla, SpaceX, the S&P 500 or gold. Flap also accepts other Flap tokens as quotes ("child" launches). Pass `"BNB"`, a ticker from the tables (any case), or an address as `pairToken`; an asset Flap hasn't enabled returns `pair_token_not_approved`. Whatever you pick is fixed at launch and is what the curve holds. Buyers still pay in plain BNB: for every asset below, Flap swaps BNB into the quote inside the buy, and sells come back as BNB by default. A tax on a stock-priced token is collected in that stock, so `marketingBps` pays you in NVDAB, and `dividendBps` pays holders in it (the default `dividendToken` is the quote). ### Crypto | Ticker | Asset | Decimals | Address | |---|---|---|---| | `BNB` | BNB | 18 | native BNB - no address | | `USDT` | Tether USD | 18 | `0x55d398326f99059fF775485246999027B3197955` | | `USD1` | USD1 | 18 | `0x8d0D000Ee44948FC98c9B98A4FA4921476f08B0d` | | `U` | United Stables | 18 | `0xcE24439F2D9C6a2289F741120FE202248B666666` | | `lisUSD` | Lista USD | 18 | `0x0782b6d8c4551B9760e74c0545a9bCD90bdc41E5` | | `BTCB` | Bitcoin (BTCB) | 18 | `0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c` | | `ETH` | Ethereum | 18 | `0x2170Ed0880ac9A755fd29B2688956BD959F933F8` | | `SOL` | Solana | 18 | `0x570A5D26f7765Ecb712C0924E4De545B89fD43dF` | ### Stocks, ETFs and gold Binance-issued tokenised equities. Each tracks one share of the underlying; one `NVDAB` is one NVIDIA share, so a `0.01` dev buy in a NVDAB launch is a hundredth of a share. | Ticker | Asset | Decimals | Address | |---|---|---|---| | `XAUT` | Tether Gold | 6 | `0x21cAef8A43163Eea865baeE23b9C2E327696A3bf` | | `SPYB` | SPY (S&P 500 ETF) | 18 | `0x7138b48df7D98D7e3cc221BfE7192D0a178182D8` | | `QQQB` | Invesco QQQ Trust | 18 | `0x205812CdBed920aFf76C6580abD681a46D11efc7` | | `NVDAB` | NVIDIA | 18 | `0x02Fca66C1D1aFB4E2A7884261eB00F63598a7436` | | `AAPLB` | Apple | 18 | `0x431a3BEE82E2ca41e49895CbECE5bB0F76A89b7A` | | `TSLAB` | Tesla | 18 | `0x5b1910eAaD6450E50f816082Aa078C41F10C292f` | | `MSFTB` | Microsoft | 18 | `0x80106cb3EAD06659A5ad19DF39D9b4733863B9b0` | | `GOOGLB` | Alphabet | 18 | `0x3F53De71c126BdaBAe20f9cD64848d317f6C3238` | | `SPCXB` | SpaceX | 18 | `0xbe9D156892E55e7154BcD3cB0FEA677F9D3103E1` | | `SKHYB` | SK Hynix | 18 | `0xCA750eF65f295BBECd685Abf54e82CAf297BDB61` | | `HOODB` | Robinhood | 18 | `0xA394dCEa3fd3847fD793afBFd163E2e3858B7c65` | | `BABAB` | Alibaba | 18 | `0x4eF9d3062c7F6ebA4AAE4990c5036598C6eff4ec` | | `GMEB` | GameStop | 18 | `0x46cEeFDa28Dd7207059ed19B0acdc026955bb15C` | | `NFLXB` | Netflix | 18 | `0xD6829Ea836b6FA224d099D40E54B31262f874631` | | `MSTRB` | Strategy (MicroStrategy) | 18 | `0xE87afb3076AeB0f9B14E368DE8145ae6a2826A14` | | `DJTB` | Trump Media & Technology Group | 18 | `0xF2ec508422174Ee564de98187db9359D318AFB6b` | | `MRNAB` | Moderna | 18 | `0x5fd86da9B05abE396fe9d02a4A213A7c00556503` | | `FLNCB` | Fluence Energy | 18 | `0x4af1D41cd9dD950dcA43984b43aaA2A8702714Ac` | | `SOXLB` | Direxion Semiconductor Bull 3X ETF | 18 | `0xd97d097a89113fa59b76c572E5b2Eb647E8eefaf` | | `SOXSB` | Direxion Semiconductor Bear 3X ETF | 18 | `0xE28Cd11C99AF2df76bb8aDA4Cd0ef3904378280F` | This is the list as of September 2026. When Binance issues a new stock and Flap enables it, its address works as `pairToken` straight away; the ticker follows in the next release. Every curve graduates at the same point - 800M of the 1B supply sold - whatever it is priced in. That is the only graduation point Flap's Portal accepts on BNB Chain. ## The tax system A tax token's tax is split four ways, in basis points that sum to 10000: | Share | Goes to | |---|---| | `marketingBps` | `beneficiary`, in the quote asset, automatically. This is the creator's revenue. | | `deflationBps` | Burned. | | `dividendBps` | Holders of at least `minimumShareBalance` tokens, in `dividendToken`: the quote asset, the token itself, or another ERC-20. They claim it through [Creator Revenue](/creator-fees). | | `lpBps` | Added to the token's PancakeSwap liquidity. | The default is all to the beneficiary. A buy tax and a sell tax can differ (`buyTaxBps: 300, sellTaxBps: 1000` is a common shape); the tax runs for `taxDays` after graduation and, for `antiFarmerHours` after graduation, on every pool rather than just the main one. On the curve the tax is charged as an extra fee on every trade and goes the same way. Before it reaches any of those, Flap keeps up to 0.3% of taxed volume. shrine.trade takes nothing from it. Everything here is fixed at launch. ## Request | Field | Type | Description | |---|---|---| | `name` | string | Token name. Not unique - always identify tokens by address. | | `symbol` | string | Ticker. | | `logo` | string | Image URL, or a base64 `data:` URL. The API fetches it and pins image + metadata through Flap's gateway. Either this or `meta`. | | `meta` | string | A metadata CID you already pinned with `POST /api/upload-image` (what the scripts above do). Skips the pinning step; `description` and `socials` are then ignored. | | `description` | string, optional | Project description, pinned with the image. | | `socials` | object, optional | `{ twitter, telegram, website }` - any may be `""`. | | `pairToken` | string, optional | What the curve is priced in. `"BNB"` (default), a ticker from [Supported quote assets](#supported-quote-assets) such as `"USD1"` or `"NVDAB"`, or the address of any quote asset Flap has enabled. | | `initialBuy` | decimal string, optional | Your own opening buy, in the same transaction, in the quote asset (BNB for a BNB launch). Runs inside the transaction that creates the curve, so nobody can trade ahead of it. A USD1 dev buy puts an `approve_quote` transaction in front. | | `buyTaxBps` / `sellTaxBps` | number, optional | Tax on every buy / sell, in basis points (100 = 1%). Either above 0 makes this a tax token; they can differ. Immutable after launch. Default `0`. | | `taxDays` | number, optional | Tax tokens: how long the tax runs after graduation, in days. Default `365`. | | `antiFarmerHours` | number, optional | Tax tokens: for this many hours after graduation the tax also applies to every other pool, so LP farmers can't route around it. At most 8760. Default `0`. | | `beneficiary` | address, optional | Tax tokens: where the marketing share of the tax goes. Defaults to `from`. | | `marketingBps` / `deflationBps` / `dividendBps` / `lpBps` | number, optional | Tax tokens: how the tax splits, in bps of the tax - to the beneficiary, burned, paid to holders as a dividend, added to the token's liquidity. Must sum to 10000; anything not named is 0. Default: all to the beneficiary. | | `dividendToken` | string, optional | With `dividendBps`: what holders are paid in. `"quote"` (default) for the quote asset (the stock itself on a stock-priced launch), `"self"` for the token itself, or an ERC-20 address Flap can swap into. | | `minimumShareBalance` | decimal string, optional | With dividends (tax tokens with `dividendBps`, and every standard token): the token balance a holder needs to receive them. Flap's floor is 10000, which is the default. | | `slippage` | number, optional | Percent, for the dev buy. Default `5`. | | `from` | address | Your wallet (creator). | ### What a launch costs Flap charges no creation fee, so a launch costs gas and nothing else - about **0.0004 BNB** for a tax token and less for a standard one at BNB Chain's usual 0.05 gwei, plus your dev buy. Because a node reserves `gasLimit x maxFeePerGas` before running the transaction, and both figures are padded (20% on the limit, a 1.25x ceiling on the price), the wallet must hold a little more than is actually spent; the difference comes back in the same block. **Budget 0.001 BNB** for a plain launch and you will never be short. Flap does apply a **rate limit per creator wallet** - one launch every so often - and returns `launch_rate_limited` when you are inside it. ## Response A real one, for a 3%/3% tax token with a 0.001 BNB dev buy: ```json { "txs": [ { "to": "0xe2cE6ab80874Fa9Fa2aAE65D277Dd6B8e65C9De0", "data": "0x…", "value": "1000000000000000", "gas": 7230661, "maxFeePerGas": "62500000", "maxPriorityFeePerGas": "50000000", "nonce": 12, "chainId": 56, "type": 2, "description": "create" } ], "token": "0x32e00b9c8eb2ff2462b61b692475d7670ea07777", "salt": "0xe37d685461db060f32606abcd0af9c18d4bc275244d46edbf0123869d1367347", "tokenType": "tax_v3", "launchFee": "0", "launchFeeFormatted": "0", "pairToken": "BNB", "pairTokenSymbol": "BNB", "pairTokenDecimals": 18, "graduationSupply": "800000000000000000000000000", "graduationSupplyFormatted": "800000000", "meta": "bafkreieraixgnucog5qpve3qqqapghudod7ogi5ztlorgavbjszahk3lga", "metaUri": "https://ipfs.io/ipfs/bafkreieraixgnucog5qpve3qqqapghudod7ogi5ztlorgavbjszahk3lga", "beneficiary": "0x8894E0a0c962CB723c1976a4421c95949bE2D4E3", "buyTaxBps": 300, "sellTaxBps": 300, "tax": { "taxDays": 365, "antiFarmerHours": 0, "marketingBps": 10000, "deflationBps": 0, "dividendBps": 0, "lpBps": 0, "dividendToken": "quote", "minimumShareBalance": "0" }, "initialBuy": "1000000000000000", "initialBuyFormatted": "0.001", "expectedTokensOut": "173060121205804955576978", "expectedTokensOutFormatted": "173060.121205804955576978", "expectedEconomics": "Flap tax token: 3.00% tax on buys and 3.00% on sells for 365 days after graduation …" } ``` - `txs` - sign and send in order. Usually one, `create`. A dev buy in an ERC-20 quote puts `approve_quote` in front. - `token` - the token's address, known before you send: Flap deploys with CREATE2 and the `salt` we searched for. Tax tokens end in `7777`, standard ones in `8888` - Flap requires it. - `tokenType` - `standard_v3` or `tax_v3`. - `launchFee` - always `0`: Flap charges nothing to create. The transaction's `value` is the dev buy. - `meta` / `metaUri` - the pinned metadata, as a CID and through a gateway. - `beneficiary`, `buyTaxBps`, `sellTaxBps`, `tax` - echo what the launch will use: the tax duration and anti-farmer window, the split, the dividend token and holder floor. `lpFeesTo` on a standard token is always `holders`. - `initialBuy`, `expectedTokensOut` - the dev buy in the quote asset's base units and what it returns, simulated against the real launch. Only with an `initialBuy`. - `expectedEconomics` - a plain-English summary of the token's terms. --- # Flap Creator Revenue > See what your Flap tax tokens have earned on BNB Chain and push anything waiting to your wallet. Tax is paid automatically; two endpoints cover the rest. # Creator Revenue If you launched a **tax token**, every trade on it earns you the tax - and Flap pays it to your wallet by itself. On the curve the tax is charged as part of each trade; after graduation it accumulates in the token and Flap liquidates it into the quote asset and sends it on. There is nothing to claim in the usual sense, but three pots can still be waiting: - **Pending tax** - liquidated but not yet pushed to you. Anyone may trigger the payout. - **LP fees** - once graduated, the beneficiary's share of the PancakeSwap pool's fees. - **Dividends** - if the token pays holders a dividend (a tax token with `dividendBps`, or any standard token, whose LP fees are the dividend), your own unclaimed share. Two endpoints, free and keyless. They work for any wallet, not only the creator: a holder claims their dividend the same way. ## What's waiting ``` GET https://api.shrine.trade/bnb/api/fees/{wallet}?token={yourToken} ``` ```json { "wallet": "0xF31b8fcD326e0aD7837af0aefed60cC71Db82595", "token": "0x2f1952E00F6BA7655993120B8c41E5ab511e7777", "asset": "BNB", "decimals": 18, "beneficiary": "0xF31b8fcD326e0aD7837af0aefed60cC71Db82595", "isBeneficiary": true, "totalPaid": "27083340900000001", "totalPaidFormatted": "0.027083340900000001", "pendingTax": "0", "pendingTaxFormatted": "0", "lpFees": "0", "lpFeesFormatted": "0", "dividend": "0", "dividendFormatted": "0", "claimable": "0", "claimableFormatted": "0", "hasClaimable": false } ``` `totalPaid` is what Flap has already sent the beneficiary - automatically, no claim needed. `claimable` is what a claim from `wallet` would move right now: the pending tax (if `wallet` is the beneficiary), the LP fee share and your dividend. `hasClaimable: false` means don't bother - you'd only pay gas. ## Claim it ``` POST https://api.shrine.trade/bnb/api/claim-fees ``` Send `{ "from": "0x…", "token": "0x…" }` - your wallet and your launched token - and you get back the transactions that move everything that is waiting: up to three, send them in order. **JavaScript** ```js const { Wallet } = require("ethers"); // ─── change these ───────────────────────────────────── const PRIVATE_KEY = "0xYOUR_PRIVATE_KEY"; const TOKEN = "0xYOUR_LAUNCHED_TOKEN"; // ────────────────────────────────────────────────────── async function main() { const wallet = new Wallet(PRIVATE_KEY); // signs only; no node needed // 1. Ask shrine.trade to build the claim. const res = await fetch("https://api.shrine.trade/bnb/api/claim-fees", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ from: wallet.address, token: TOKEN }), }); const data = await res.json(); if (data.error) throw new Error(`${data.error}: ${data.message}`); console.log("claiming", data.claimingFormatted, data.asset); // 2. Sign locally and send, in order - the key never leaves this script. for (const tx of data.txs) { const signed = await wallet.signTransaction({ to: tx.to, data: tx.data, value: BigInt(tx.value), gasLimit: BigInt(tx.gas), maxFeePerGas: BigInt(tx.maxFeePerGas), maxPriorityFeePerGas: BigInt(tx.maxPriorityFeePerGas), nonce: tx.nonce, chainId: tx.chainId, type: 2, }); const sent = await (await fetch("https://api.shrine.trade/bnb/api/send", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ signedTx: signed }), })).json(); if (sent.error) throw new Error(`${sent.error}: ${sent.message}`); if (sent.status !== "landed") throw new Error(`${tx.description} ${sent.status}: ${sent.explorer}`); console.log(tx.description + ": " + sent.explorer); } } main(); ``` Save it as `claim.js`, then: ```bash npm install ethers node claim.js ``` **Python** ```python import requests from eth_account import Account # ─── change these ───────────────────────────────────── PRIVATE_KEY = "0xYOUR_PRIVATE_KEY" TOKEN = "0xYOUR_LAUNCHED_TOKEN" # ────────────────────────────────────────────────────── account = Account.from_key(PRIVATE_KEY) # signs only; no node needed # 1. Ask shrine.trade to build the claim. data = requests.post( "https://api.shrine.trade/bnb/api/claim-fees", json={"from": account.address, "token": TOKEN}, ).json() if "error" in data: raise SystemExit(f"{data['error']}: {data['message']}") print("claiming", data["claimingFormatted"], data["asset"]) # 2. Sign locally and hand each signed transaction to the API to broadcast - the # key never leaves this script, and you need no RPC of your own. for tx in data["txs"]: signed = Account.sign_transaction( { "to": tx["to"], "data": tx["data"], "value": int(tx["value"]), "gas": tx["gas"], "maxFeePerGas": int(tx["maxFeePerGas"]), "maxPriorityFeePerGas": int(tx["maxPriorityFeePerGas"]), "nonce": tx["nonce"], "chainId": tx["chainId"], }, account.key, ) sent = requests.post("https://api.shrine.trade/bnb/api/send", json={"signedTx": "0x" + signed.raw_transaction.hex().removeprefix("0x")}).json() if "error" in sent: raise SystemExit(f"{sent['error']}: {sent['message']}") if sent["status"] != "landed": raise SystemExit(f"{tx['description']} {sent['status']}: {sent['explorer']}") print(tx["description"] + ":", sent["explorer"]) ``` Save it as `claim.py`, then: ```bash pip install eth-account requests python claim.py ``` ## Notes - **The tax goes to the `beneficiary`** - your wallet unless you set another at launch. `/api/token/{address}` shows which. A `dispatch_tax` transaction can be sent by anyone; the money still goes to the beneficiary. - **Launches priced in USD1 or another ERC-20** pay out in that asset. Pass the launched token and the API works out the rest. - **LP fees** exist only after graduation and only for the beneficiary; `claim_lp_fees` fails with `not_beneficiary` for anyone else. - These are Flap's payments to you as a creator. Flap keeps its protocol fee on curve trades and up to 0.3% of taxed volume - see [Fees](/fees). Our 0.5% on trades is separate and never touches any of this; creating a token costs you nothing beyond gas. --- # API Errors > Every error code the Flap Trading API returns, grouped by endpoint, with what to do about each. # Errors Every failure is a JSON object carrying a machine-readable `error` code, which never changes meaning, and a `message` written for people. Branch on the code; log or display the message. ```json { "error": "insufficient_balance", "message": "wallet holds 0 tokens" } ``` ## Your request | Code | HTTP | Meaning | |---|---|---| | `invalid_request` | 400 | Something required is absent, or a field has the wrong shape. | | `invalid_address` | 400 | An address field (`token`, `from`, `beneficiary`, …) does not parse as one. | | `invalid_amount` | 400 | `amount` is zero, negative or not numeric, or a percentage was given on a buy. | | `invalid_action` | 400 | Only `"buy"` and `"sell"` are accepted. | | `token_not_found` | 404 | The address is not a Flap token on BNB Chain. Check you copied the token, not a pool. | ## Trading | Code | HTTP | Meaning | |---|---|---| | `insufficient_funds` | 400 | Not enough BNB in `from` for the trade plus gas. The message states the balance and the requirement side by side. It has to be **BNB on BNB Chain** - a balance of USD1 or another asset does not pay for gas. | | `insufficient_balance` | 400 | Selling more tokens than the wallet holds, or paying with a quote asset you don't hold enough of. `"100%"` sells everything. | | `slippage_exceeded` | 400 | Between quoting and building, the price moved past what `slippage` allows. Re-request; on a volatile token, allow more. | | `quote_asset_required` | 400 | The token is priced in an asset Flap cannot swap BNB into (or out of). Hold the asset and buy with `payWithQuote: true`; sells pay out in the asset. | | `buy_quota_exhausted` | 400 | The token caps curve buys per wallet and this wallet has used its cap. | | `amount_too_small` | 400 | So little that the trade would return nothing. Increase `amount`. | | `not_tradable` | 409 | The token is not in a tradeable state right now (mid-migration, or blocked by Flap). Retry in a minute. | | `insufficient_allowance` | 400 | The spender lacks an allowance the trade relies on. Request again and an `approve` transaction is prepended. | ## Sending | Code | HTTP | Meaning | |---|---|---| | `not_ours` | 400 | `/api/send` only broadcasts transactions this API built: Flap trades, launches, approvals to our router or Flap's Portal, and claims. Anything else is refused before it reaches the chain. | | `wrong_chain` | 400 | The signed transaction is for another chain id; this API relays BNB Chain (56). | ## Creating a token | Code | HTTP | Meaning | |---|---|---| | `invalid_pair_token` | 400 | `pairToken` is not an address and not one of the known tickers (listed in the message). | | `pair_token_not_approved` | 400 | Flap doesn't accept that asset as a quote. Use BNB or one of the [enabled assets](/create-token#supported-quote-assets). | | `invalid_tax` | 400 | `buyTaxBps` / `sellTaxBps` is above 10000. | | `invalid_logo` | 400 | `logo` is not a fetchable image URL or a valid base64 `data:` URL. | | `launch_rate_limited` | 400 | Flap limits how often one wallet may launch. Wait and retry. | | `launcher_blocked` | 400 | Flap has blocked `from` from launching. | | `metadata_already_used` | 400 | Another token already uses this metadata CID. Pin fresh metadata. | | `name_blacklisted` | 400 | Flap rejects this name or symbol. | | `flap_disabled` | 400 | Flap has paused launching or trading. Try later. | | `missing_file` | 400 | The multipart upload contained no `file` part. | | `not_an_image` | 400 | The file's content type is not `image/*`. | | `file_too_large` | 400 | Images are capped at 5 MB. | | `invalid_upload` | 400 | The multipart body could not be parsed. | ## Creator revenue | Code | HTTP | Meaning | |---|---|---| | `nothing_to_claim` | 400 | No tax, LP fees or dividend is pending for this wallet on this token. The message notes how much Flap has already paid out on its own. | | `not_beneficiary` | 400 | Only the token's beneficiary can claim its LP fee share. | | `not_graduated` | 400 | LP fees exist only once the token has graduated to PancakeSwap. | ## Limits | Code | HTTP | Meaning | |---|---|---| | `rate_limited` | 429 | Over 3 calls a second to a single endpoint from one IP. `Retry-After: 1` says when to try again. | | `too_many_connections` | 429 | One launch-feed socket per IP is the cap; this would have been the second. | ## Everything else | Code | HTTP | Meaning | |---|---|---| | `revert` | 400 | Simulation shows the transaction failing for a reason without its own code; `message` carries the decoded contract error. | | `rpc_error` | 502 | BNB Chain (or Flap's IPFS gateway) could not be reached. Retry. | Passing every check here does not guarantee a landed trade: the price can still move past `minOut` before your transaction is mined, in which case it reverts and only gas is spent. --- # Frequently Asked Questions > Answers about supported venues, fees, private-key safety, amounts, slippage, tax tokens, the live feed and rate limits for the Flap Trading API. # Frequently asked questions ### Which platforms are supported? Every Flap token on BNB Chain - on its bonding curve and, after graduation, in the PancakeSwap pool Flap migrated it to. You never say which; the API reads the token's status from Flap and picks the venue. Launching is on Flap, standard or tax token. ### Do I need an API key or an account? No. Every endpoint is open. Two limits apply per IP address: 3 requests a second on any one endpoint, and one open launch-feed socket. ### Is my private key safe? It never leaves your machine. Every response is an unsigned transaction. Signing happens in your script, with your key; only the signed bytes are posted to `/api/send`, which broadcasts them and can do nothing else with them. Nothing about the key ever reaches shrine.trade, and there is no custody of any kind. ### What does it cost? A 0.5% fee on buys and on sells, charged in the settlement asset. Everything else - token info, the launch feed, creating a token - costs nothing. Flap's own curve fee and the token's tax apply on top, and gas is a fraction of a cent. See [Fees](/fees). ### Which currency is `amount` in? On a buy, BNB, whatever the token is priced in - Flap swaps into USD1 or whichever asset the token uses on the way. On a sell, tokens, or a percentage of your balance like `"50%"`; proceeds come back as BNB. Only when Flap cannot convert does the quote asset itself come into play (`payWithQuote`, `receiveQuote`). ### What is a tax token? A Flap token whose creator takes a percentage of every buy and sell. Most launches are. The tax is inside every quote (`creatorTaxBps` is the rate on your side), so `expectedOut` is what you actually get. [Token Info](/token-info) shows both rates before you trade. ### Why did my buy fill for less than I asked? The token caps how much one wallet may buy on the curve and you reached it. Flap fills up to the cap and refunds the rest in the same transaction. The quote already knows your remaining allowance, and `buy_quota_exhausted` tells you when there is none left. ### Are trades front-run protected? The on-chain minimum (`minOut`, from your slippage) is enforced by Flap's contracts, so a trade that would fill worse than quoted fails instead of filling badly. A dev buy on a launch runs inside the transaction that creates the curve, so it cannot be sniped. BNB Chain does have a public mempool, but you never touch it: signed transactions go through `/api/send`, which broadcasts them over our private endpoint rather than a public node. ### How does slippage work here? `slippage` is the percentage the fill may fall short of the quote before the transaction refuses to execute; the API turns it into an on-chain `minOut`. The default of 5 suits most curve tokens. A busy launch may need more, a quiet graduated token can take less. `slippage_exceeded` means the floor was hit. ### The wallet holds enough for the trade, so why `insufficient_funds`? A BNB Chain node sets aside `gasLimit x maxFeePerGas` before it executes anything, and only refunds the unused part afterwards. The API applies the same check up front and states the exact balance required. Keep 0.002 BNB extra and this never comes up. Details in [gas and fees](/tutorials/bnb-chain-gas-and-fees). ### When can I buy a new launch? Immediately. Flap has no opening snipe tax; what it has instead are optional per-wallet buy caps and the token's own tax, both visible in the quote. The [sniper tutorial](/tutorials/snipe-flap-launches) shows a bot that reads the launch event, checks the tax, and buys. ### Is the live feed really free? Yes. `wss://api.shrine.trade/bnb/api/launches/ws` streams every Flap launch and graduation. No key, one connection per IP. It is a stream, not a database: no history endpoint exists. ### Where is my creator revenue? Flap pays a tax token's tax to its beneficiary automatically. `/api/fees/{wallet}?token=YOUR_TOKEN` shows what has been paid and what is waiting, and `/api/claim-fees` builds the transactions for anything that is. See [Creator Revenue](/creator-fees). ### Can AI coding tools read these docs? Yes. Two files are kept for that: [llms.txt](/llms.txt), an index with one line per page, and [llms-full.txt](/llms-full.txt), the entire site as plain text. Both are rebuilt with every release. ### Where do I get help? Ask in the [Telegram group](https://t.me/+nEqAowTK8BZhZjFk). New versions are posted on [X](https://x.com/shrinetrade). --- # Fees > shrine.trade charges 0.5% per trade on Flap tokens on BNB Chain, on the curve and on PancakeSwap; launching and reading are free. Flap's curve fee and a token's own tax apply on top. # Fees ## shrine.trade | Action | Fee | |---|---| | Buy | **0.5%** | | Sell | **0.5%** | | Create token | **Free** | | Token info, live feed | Free | ## Lower fees **The 0.5% is negotiable.** Trading real size, building a bot or app on top of this, or need an endpoint that isn't here yet? Message me on [Telegram](https://t.me/+nEqAowTK8BZhZjFk) and we'll sort out a rate that works. --- # Live Flap Launches on BNB Chain > WebSocket feed of every new Flap launch and every graduation to PancakeSwap on BNB Chain, the moment it happens. Free and keyless. # Live Launches & Graduations The whole token lifecycle on Flap, pushed the moment it happens. Two things arrive on this one socket: - **Launches** - a token appears on the Flap bonding curve. Several hundred a day. - **Graduations** - a curve sells out and the token moves to its permanent PancakeSwap pool. Free, no key, no account. ``` wss://api.shrine.trade/bnb/api/launches/ws ``` ## Copy this Click Flap or PancakeSwap to choose what the script receives - the URL updates. **JavaScript** (Node 22+, no packages): ```js // Add ?protocols=FLAP for launches only, or ?protocols=PANCAKESWAP for // graduations only. No query = everything. const ws = new WebSocket("wss://api.shrine.trade/bnb/api/launches/ws"); ws.onmessage = (e) => { const t = JSON.parse(e.data); // t.type: new_launch or graduated console.log(JSON.stringify(t, null, 2)); }; ``` **Python** (`pip install websockets`): ```python import json from websockets.sync.client import connect with connect("wss://api.shrine.trade/bnb/api/launches/ws") as ws: for raw in ws: t = json.loads(raw) # t["type"]: new_launch or graduated print(json.dumps(t, indent=2)) ``` ## What you get The first message after connecting is a replay of the **most recent event**, so a fresh client has something to show. After that, every message is new. A message is classified by two fields, `type` and `protocol`: | `type` | `protocol` | Means | |---|---|---| | `new_launch` | `FLAP` | A token launched on the Flap curve - tradeable immediately. | | `graduated` | `PANCAKESWAP` | A Flap curve sold out; the token moved to its PancakeSwap pool. | Filter with `?protocols=FLAP` or `?protocols=PANCAKESWAP` (omit it for both), or use the picker above. Optional fields are omitted rather than sent as null, so branch on `type` before reading anything else. ```json { "type": "new_launch", "protocol": "FLAP", "token": "0x2f1952E00F6BA7655993120B8c41E5ab511e7777", "name": "星际巨舰", "symbol": "星际巨舰", "creator": "0xF31b8fcD326e0aD7837af0aefed60cC71Db82595", "quoteToken": "BNB", "tokenType": "tax_v3", "buyTaxBps": 1000, "sellTaxBps": 1000, "graduationSupply": "800000000000000000000000000", "meta": "bafkreidrm6a6ieclmputpy2iw5wxqkpcttpapxidcxpl5z5lj…", "metaUri": "https://ipfs.io/ipfs/bafkreidrm6a6ieclmputpy2iw5wxqkpcttpapxidcxpl5z5lj…", "blockNumber": 120101041, "txHash": "0x…", "timestamp": 1788610321 } ``` **`tokenType`, the tax and the quote asset come from Flap's Portal** at the moment of the event, so a sniper can decide on a launch without another request: skip 10% sell taxes, take only BNB-priced tokens, only stock-priced ones, whatever the rule is. `quoteToken` is a ticker (`BNB`, `USD1`, `NVDAB`, `TSLAB`...) for every asset in [Supported quote assets](/create-token#supported-quote-assets), and an address for a quote the API has no name for, such as another Flap token. `meta` is the IPFS CID of the creator's metadata JSON (image, description, socials); `metaUri` is the same thing through a gateway. A `graduated` event carries `pool` (the PancakeSwap pool), `liquidityTokens` and `liquidityQuote` (what Flap put in it) instead. > **Buy quotas and taxes.** Some launches cap what one wallet may buy on the curve, and most carry a tax. Both are in [Token Info](/token-info) and in every quote from [Buy & Sell](/local-trade), so a sniper that reads the quote before sending never overpays. ## Notes - **Reconnect on drop.** Long-lived sockets die; reconnect and you're re-seeded with the most recent launch, so you won't miss much. - **One socket per IP.** A second is turned away with `too_many_connections`. An unfiltered socket already carries every event, so one is enough. --- # Buy & Sell Flap Tokens on BNB Chain > Buy or sell any Flap token on BNB Chain with one script, on the bonding curve or on PancakeSwap after graduation. Pay in BNB; tax tokens and USD1-priced tokens are handled for you. # Buy & Sell One request, one unsigned transaction back, signed and sent by your own script. The snippet below is complete: set the key, the token and the amount, and run it. One endpoint for every Flap token on BNB Chain, wherever it lives: - **On the bonding curve** - from launch until 800M tokens are sold. - **On PancakeSwap** - after graduation, in the pool Flap migrated it to. You send the token address; the API reads its state from Flap's Portal and routes accordingly, reporting the venue as `flap_curve` or `pancakeswap`. Tax tokens need no special handling - their tax is already inside the quote. ## What you need - **Node.js** or **Python**. - A wallet private key with some **BNB on BNB Chain**. - A token address. Take one from [any Flap token page](https://flap.sh) or the [live launches feed](/live-launches). ## Example **JavaScript** ```js const { Wallet } = require("ethers"); // ─── change these three ─────────────────────────────── const PRIVATE_KEY = "0xYOUR_PRIVATE_KEY"; const TOKEN = "0xTHE_TOKEN_ADDRESS"; const AMOUNT = "0.01"; // to buy: BNB to spend. To sell: "1000" tokens, or "100%" const ACTION = "buy"; // "buy" or "sell" const SLIPPAGE = 5; // %, how far the price may move against you // ────────────────────────────────────────────────────── async function main() { const wallet = new Wallet(PRIVATE_KEY); // signs only; no node needed const res = await fetch("https://api.shrine.trade/bnb/api/local-trade", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ action: ACTION, token: TOKEN, amount: AMOUNT, slippage: SLIPPAGE, from: wallet.address, }), }); const data = await res.json(); if (data.error) throw new Error(`${data.error}: ${data.message}`); console.log("you should get about", data.quote.expectedOutFormatted, ACTION === "buy" ? "tokens" : data.receive); // Sign locally and hand the signed bytes to the API to broadcast - the key // never leaves this script, and you need no RPC of your own. for (const tx of data.txs) { const signed = await wallet.signTransaction({ to: tx.to, data: tx.data, value: BigInt(tx.value), gasLimit: BigInt(tx.gas), maxFeePerGas: BigInt(tx.maxFeePerGas), maxPriorityFeePerGas: BigInt(tx.maxPriorityFeePerGas), nonce: tx.nonce, chainId: tx.chainId, type: 2, }); const sent = await (await fetch("https://api.shrine.trade/bnb/api/send", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ signedTx: signed }), })).json(); if (sent.error) throw new Error(`${sent.error}: ${sent.message}`); if (sent.status !== "landed") throw new Error(`${tx.description} ${sent.status}: ${sent.explorer}`); console.log(tx.description + ": " + sent.explorer); } if (ACTION === "buy") { console.log(`bought ${data.name} (${data.symbol}) ${data.token} for ${data.amountInFormatted} ${data.payWith}`); } else { console.log(`sold ${data.amountInFormatted} ${data.name} (${data.symbol}) ${data.token} for ${data.quote.expectedOutFormatted} ${data.receive}`); } } main(); ``` Save it as `trade.js`, then: ```bash npm install ethers node trade.js ``` **Python** ```python import requests from eth_account import Account # ─── change these three ─────────────────────────────── PRIVATE_KEY = "0xYOUR_PRIVATE_KEY" TOKEN = "0xTHE_TOKEN_ADDRESS" AMOUNT = "0.01" # to buy: BNB to spend. To sell: "1000" tokens, or "100%" ACTION = "buy" # "buy" or "sell" SLIPPAGE = 5 # %, how far the price may move against you # ────────────────────────────────────────────────────── account = Account.from_key(PRIVATE_KEY) # signs only; no node needed res = requests.post( "https://api.shrine.trade/bnb/api/local-trade", json={"action": ACTION, "token": TOKEN, "amount": AMOUNT, "slippage": SLIPPAGE, "from": account.address}, ) data = res.json() if "error" in data: raise SystemExit(f"{data['error']}: {data['message']}") unit = "tokens" if ACTION == "buy" else data["receive"] print("you should get about", data["quote"]["expectedOutFormatted"], unit) for tx in data["txs"]: signed = Account.sign_transaction( { "to": tx["to"], "data": tx["data"], "value": int(tx["value"]), "gas": tx["gas"], "maxFeePerGas": int(tx["maxFeePerGas"]), "maxPriorityFeePerGas": int(tx["maxPriorityFeePerGas"]), "nonce": tx["nonce"], "chainId": tx["chainId"], }, account.key, ) sent = requests.post("https://api.shrine.trade/bnb/api/send", json={"signedTx": "0x" + signed.raw_transaction.hex().removeprefix("0x")}).json() if "error" in sent: raise SystemExit(f"{sent['error']}: {sent['message']}") if sent["status"] != "landed": raise SystemExit(f"{tx['description']} {sent['status']}: {sent['explorer']}") print(tx["description"] + ":", sent["explorer"]) if ACTION == "buy": print(f"bought {data['name']} ({data['symbol']}) {data['token']} for {data['amountInFormatted']} {data['payWith']}") else: print(f"sold {data['amountInFormatted']} {data['name']} ({data['symbol']}) {data['token']} for {data['quote']['expectedOutFormatted']} {data['receive']}") ``` Save it as `trade.py`, then: ```bash pip install eth-account requests python trade.py ``` Whatever the API returns, the script sends in sequence. A buy is a single transaction. The first sell of a given token is two: a one-time approval, then the sell itself. Trades are front-run protected: the on-chain `minOut` guarantees the fill is never worse than your slippage allows, and the signed transaction is broadcast through our own endpoint via `/api/send`, not a public node, so you need no RPC of your own. > **Buy quotas.** Some Flap tokens cap how much one wallet may buy on the curve. Your quote already reflects your remaining allowance; a buy past it is filled up to the cap and the rest of your BNB is refunded in the same transaction. [Token Info](/token-info) shows the cap and what you have left. ## Selling Switch `ACTION` to `"sell"`. For the amount, give either a token count or a percentage of the wallet's balance: | `AMOUNT` | Sells | |---|---| | `"1000"` | 1000 tokens | | `"50%"` | half your balance | | `"100%"` | everything | Proceeds arrive in BNB, whatever the token is priced in, whenever Flap can convert on the way out. `receive` in the response says which asset you end up with. ## Tax tokens Most Flap launches are tax tokens: the creator takes a percentage of every buy and sell. The tax is applied inside the quote, so `expectedOut` is what you actually receive - on the curve it is an extra fee on the trade, after graduation it is taken from the tokens as they move through the pool. `creatorTaxBps` in the response is the rate on your side of the trade. Nothing changes in the script. ## Tokens priced in USD1, stocks or other assets Flap lets a launch be priced in USD1, a tokenised stock (NVDAB, TSLAB, SPYB, XAUT and more - see [Supported quote assets](/create-token#supported-quote-assets)), or another Flap token instead of BNB. Nothing changes in the script: `AMOUNT` on a buy is always BNB, and Flap swaps it into the quote asset inside the transaction. `quoteAsset` says what the token is priced in and `payWith` what left your wallet. Where Flap cannot swap on the way in (`quoteAssetRequired`), buy with the asset itself: hold it and send `payWithQuote: true` with `amount` in that asset. Selling such a token pays out the quote asset; send `receiveQuote: true` to insist on it for any token. ## If it doesn't work | Error | What to do | |---|---| | `insufficient_funds` | Add BNB to the wallet - the amount plus a little for gas. | | `insufficient_balance` | The sell is bigger than the balance. `"100%"` always fits. | | `token_not_found` | Flap's Portal has never heard of this address. Make sure it is the token contract, not the PancakeSwap pool. | | `slippage_exceeded` | The price ran away between quote and send. Retry, with a higher `SLIPPAGE` on a busy token. | | `buy_quota_exhausted` | This wallet has bought all it may of this token on the curve. | | `quote_asset_required` | The token is priced in an asset Flap can't swap BNB into. Hold it and set `payWithQuote`. | Full list on [Errors](/errors). ## Sending `POST https://api.shrine.trade/bnb/api/send` takes one signed transaction and broadcasts it through our BNB Chain endpoint, so the scripts need no RPC at all. It only forwards transactions this API built - Flap trades, launches, approvals and claims - and refuses anything else with `not_ours`. | Field | | | |---|---|---| | `signedTx` | 0x-hex | The signed transaction, as `wallet.signTransaction` returns it. | | `wait` | boolean, optional | Default `true`: wait for the receipt. `false` returns the hash as soon as the node accepts it. | ```json { "hash": "0x…", "status": "landed", "blockNumber": 120162431, "gasUsed": 514058, "explorer": "https://bscscan.com/tx/0x…" } ``` `status` is `landed`, `reverted`, or `pending` (not waited for, or not mined within 45 seconds - stuck on nonce or gas). ### Request and response `POST https://api.shrine.trade/bnb/api/local-trade` **Request** | Field | | | |---|---|---| | `action` | `"buy"` or `"sell"` | | | `token` | address | The Flap token. | | `amount` | decimal string | On a buy, the BNB to spend regardless of the token's quote asset. On a sell, a token count such as `"1000"`, or a percentage of the balance such as `"50%"` or `"100%"`. | | `from` | address | Your wallet. | | `slippage` | number, optional | In percent. `5` when omitted. | | `payWithQuote` | boolean, optional | Buy only, tokens priced in an ERC-20: pay with that asset; `amount` is then in it. | | `receiveQuote` | boolean, optional | Sell only, tokens priced in an ERC-20: receive that asset instead of BNB. | **Response** - a real one, a buy of a tax token for 0.001 BNB on its curve: ```json { "action": "buy", "protocol": "FLAP", "token": "0x2f1952E00F6BA7655993120B8c41E5ab511e7777", "name": "星际巨舰", "symbol": "星际巨舰", "status": "Tradable", "venue": "flap_curve", "amountIn": "1000000000000000", "amountInFormatted": "0.001", "quoteAsset": { "address": "0x0000000000000000000000000000000000000000", "symbol": "BNB", "decimals": 18, "isNative": true }, "payWith": "BNB", "receive": "TOKEN", "quote": { "expectedOut": "160442982903129676642962", "expectedOutFormatted": "160442.982903129676642962", "minOut": "152420833757973192810813", "curveFeeBps": 125, "creatorTaxBps": 1000, "shrineFeeBps": 50, "slippagePct": 5.0 }, "txs": [ { "to": "0x799924b88883cD9436C8B0dfc51660147C8Bcd7C", "data": "0x…", "value": "1000000000000000", "gas": 521904, "maxFeePerGas": "62500000", "maxPriorityFeePerGas": "50000000", "nonce": 5, "chainId": 56, "type": 2, "description": "buy" } ] } ``` - `txs` - the transactions to sign and broadcast, in this order. The three wei-denominated fields (`value`, `maxFeePerGas`, `maxPriorityFeePerGas`) are decimal strings so they survive JSON; everything else is a plain number. `description` labels each: `buy`, `sell`, or a one-time `approve` / `approve_quote`. - `name` / `symbol` - read from the token contract, for logging what was traded. - `status` - Flap's: `Tradable` on the curve, `DEX` after graduation. `venue` - `flap_curve` or `pancakeswap`. The request is the same in both cases. - `quoteAsset` - what the token is priced in: BNB, or an ERC-20. `payWith` / `receive` - what actually left or reached your wallet (`BNB`, the quote symbol, or `TOKEN`). - `amountIn` - what you spend, base units: wei of BNB on a buy, tokens on a sell. - `quote.expectedOut` - the amount you should end up with once Flap's fee, the token's tax and ours are all taken. `minOut` is that figure less your slippage, and it is the floor the contract enforces. Both are base units; use the `*Formatted` twins for display. - `quote` fees - `curveFeeBps` is Flap's fee on the curve (0 once graduated - PancakeSwap's LP fee applies instead), `creatorTaxBps` the token's tax on this side, `shrineFeeBps` ours (50 = 0.5%). --- # Flap Token Info API > Read any Flap token on BNB Chain: curve progress, quote asset, buy and sell tax, per-wallet buy quota, PancakeSwap pool, and what the creator has earned. # Token Info Free, keyless reads. Use them to decide what to trade and to size a buy before you call `local-trade`. Amounts are raw base-unit strings (wei for BNB, 18-decimal units for tokens); fields ending in `Formatted` are the human-readable decimal. ## Token ``` GET https://api.shrine.trade/bnb/api/token/{address} GET https://api.shrine.trade/bnb/api/token/{address}?wallet=0x… ``` **JavaScript** ```js const TOKEN = "0x2f1952E00F6BA7655993120B8c41E5ab511e7777"; async function main() { const res = await fetch(`https://api.shrine.trade/bnb/api/token/${TOKEN}`); const t = await res.json(); if (t.error) throw new Error(`${t.error}: ${t.message}`); console.log(t.symbol, t.status, "| venue:", t.venue, "| progress:", t.progressPct.toFixed(1) + "%"); console.log("priced in", t.quoteAsset.symbol, "| tax:", t.buyTaxBps, "/", t.sellTaxBps, "bps"); if (t.tax) console.log("creator has earned", t.tax.totalPaidToBeneficiary, t.quoteAsset.symbol); } main(); ``` Save it as `token.js` and run `node token.js` - no packages needed. **Python** ```python import requests TOKEN = "0x2f1952E00F6BA7655993120B8c41E5ab511e7777" t = requests.get(f"https://api.shrine.trade/bnb/api/token/{TOKEN}").json() if "error" in t: raise SystemExit(f"{t['error']}: {t['message']}") print(t["symbol"], t["status"], "| venue:", t["venue"], "| progress:", f"{t['progressPct']:.1f}%") print("priced in", t["quoteAsset"]["symbol"], "| tax:", t["buyTaxBps"], "/", t["sellTaxBps"], "bps") if t.get("tax"): print("creator has earned", t["tax"]["totalPaidToBeneficiary"], t["quoteAsset"]["symbol"]) ``` Save it as `token.py`, `pip install requests`, then `python token.py`. Add `?wallet=0x…` to get `buyQuotaRemaining` for that wallet. A real response: ```json { "protocol": "FLAP", "token": "0x2f1952E00F6BA7655993120B8c41E5ab511e7777", "name": "星际巨舰", "symbol": "星际巨舰", "tokenType": "tax_v3", "isTaxToken": true, "status": "Tradable", "graduated": false, "venue": "flap_curve", "quoteAsset": { "address": "0x0000000000000000000000000000000000000000", "symbol": "BNB", "decimals": 18, "isNative": true }, "pairToken": "BNB", "bnbBuysAccepted": true, "quoteReserve": "7232115677198697", "quoteReserveFormatted": "0.007232115677198697", "circulatingSupply": "1058452331420000000000000", "circulatingSupplyFormatted": "1058452.33142", "graduationSupply": "800000000000000000000000000", "graduationSupplyFormatted": "800000000", "progressPct": 0.13, "price": "5556337995", "curveFeeBps": 125, "shrineFeeBps": 50, "buyTaxBps": 1000, "sellTaxBps": 1000, "tax": { "buyTaxBps": 1000, "sellTaxBps": 1000, "beneficiary": "0xF31b8fcD326e0aD7837af0aefed60cC71Db82595", "beneficiaryIsVault": false, "marketingBps": 10000, "deflationBps": 0, "dividendBps": 0, "lpBps": 0, "totalPaidToBeneficiary": "0.027083340900000001", "pendingForBeneficiary": "0", "taxProcessor": "0xaa0093AC156cDd7FE16af7C0a8cEAF3C4b38F38e" }, "curve": { "r": "6140000000000000000", "h": "107036752000000000000000000", "k": "6797205657280000000000000000" } } ``` | Field | Meaning | |---|---| | `tokenType` / `isTaxToken` | `standard` or `tax_v3` (older launches: `tax_v1`, `tax_v2`, `legacy`). A tax token charges `buyTaxBps` / `sellTaxBps` on every trade and pays it to `tax.beneficiary`. | | `status` / `graduated` / `venue` | Flap's `Tradable` while on the curve, `DEX` once graduated. `venue` is where a trade goes right now: `flap_curve` or `pancakeswap`. | | `quoteAsset` / `pairToken` | What the token is priced in: BNB, or an ERC-20 (USD1, a tokenised stock like NVDAB or TSLAB, another Flap token). `decimals` is not always 18 - XAUT has 6. The full list is in [Supported quote assets](/create-token#supported-quote-assets). | | `bnbBuysAccepted` | `true` when a BNB buy works for this token - always for BNB-priced tokens, and for ERC-20-priced ones where Flap swaps BNB in on the way. If `false`, hold the quote asset and use `payWithQuote`. | | `quoteReserve` / `circulatingSupply` | How much quote the curve holds and how many tokens it has sold. | | `graduationSupply` / `progressPct` | The curve graduates to PancakeSwap once `circulatingSupply` reaches `graduationSupply` (800M on BNB Chain). `progressPct` is how far along it is; 100 once graduated. | | `price` | Quote per token, 18-decimal fixed point, as Flap's Portal reports it. | | `curveFeeBps` / `shrineFeeBps` | Flap's fee on curve trades (0 after graduation) and ours (0.5%). | | `pool` | The PancakeSwap pool, once graduated. | | `maxBuyPerWallet` / `buyQuotaRemaining` | Present when the token caps curve buys per wallet. `buyQuotaRemaining` needs `?wallet=`. A buy past the cap is filled up to it and the rest refunded. | | `tax` | Only for tax tokens: how the tax splits (to the beneficiary, burned, paid to holders, added to liquidity), what has been paid out so far and what is waiting. See [Creator Revenue](/creator-fees). | | `curve` | Flap's constant-product parameters `(x + h)(y + r) = k`, for anyone quoting off-chain. Immutable per token. | --- # BNB Chain Gas and Fees Explained > What BNB on BNB Chain pays for, what a trade or a launch actually costs, and why the wallet needs a little more than the trade amount. # BNB Chain gas and fees explained BNB Chain (BSC) is chain id 56. Gas is paid in BNB, blocks are about 0.75 s apart, and the going gas price is 0.05 gwei - a transaction costs a fraction of a cent. ## Getting BNB BNB from any exchange withdraws straight to BNB Chain (pick the "BSC" or "BEP20" network). Holding USD1 or another asset does not pay for gas; the API's `insufficient_funds` error spells this out because it is the most common first-run problem. ## What a trade costs | | Typical gas | At 0.05 gwei | |---|---|---| | Buy on the curve, BNB-priced | ~500k | ~0.000025 BNB | | Buy on the curve, USD1-priced (Flap swaps for you) | ~1.1M | ~0.000055 BNB | | Buy on PancakeSwap after graduation | ~900k | ~0.000045 BNB | | One-time approval | ~50k | ~0.0000025 BNB | Flap's contracts do a lot per trade (tax accounting, liquidation checks, mirror pairs for indexers), so the gas figures are high for what they are - and still cost well under a cent each. ## What a launch costs Flap charges nothing to create a token. A tax-token launch is about 7 million gas, around 0.00035 BNB; a standard token is lighter. Plus your dev buy, if any. ## Why the wallet needs more than the trade amount A node reserves `gasLimit x maxFeePerGas` before running a transaction and refunds what is unused. The API pads the gas limit by 20% and sets the fee ceiling at 1.25x the current gas price, so the reservation is about one and a half times what is actually spent. A wallet holding exactly the trade amount plus the expected gas is rejected. The API checks this before you sign, sums the whole batch when there is an approval in front, and tells you the figure to hold. A practical rule: keep 0.002 BNB in a trading wallet on top of what you trade with. At BNB Chain's prices that covers hundreds of trades. ## Where the fees go - **Gas** to the validators. - **Flap's curve fee** to Flap; **the tax** to the token's creator - see [Creator Revenue](/creator-fees). - **PancakeSwap's LP fee** to the pool, on graduated tokens. - **0.5%** to shrine.trade. Full list on [Fees](/fees). --- # How to Snipe Flap Launches on BNB Chain > A complete Node.js bot that watches the Flap launch feed, filters on tax and quote asset, buys new tokens with BNB and sells at a target or a stop. # How to snipe Flap launches The whole loop in one script: watch every new Flap launch, skip the ones you don't want, buy with a fixed amount of BNB, and sell when the position hits a take-profit or a stop-loss. ## What you need - Node.js 22+ (it ships a WebSocket client) with ethers installed: `npm install ethers`. - A wallet private key with some BNB on BNB Chain - see [gas and fees](/tutorials/bnb-chain-gas-and-fees). - Ten minutes. ## What to filter on Flap has no opening snipe tax, so there is nothing to wait out - but two things decide whether a launch is worth buying, and both arrive in the launch event itself: - **The tax.** Most launches are tax tokens. A 10% sell tax means you need a 10% move just to break even on the way out. `buyTaxBps` and `sellTaxBps` are on every event. - **The quote asset.** `quoteToken` is `BNB`, a ticker like `USD1` or `NVDAB`, or an address for a quote the API has no name for. BNB-priced tokens need one transaction; the rest need Flap to swap on the way in, which works for every listed asset but costs more gas. Some tokens also cap how much one wallet may buy on the curve. The quote already reflects your allowance, so the script never overpays; it just buys less. ## The script ```js const { Wallet } = require("ethers"); // ─── change these ───────────────────────────────────── const PRIVATE_KEY = "0xYOUR_PRIVATE_KEY"; const BUY_BNB = "0.01"; // BNB per launch const TAKE_PROFIT = 2.0; // sell when the position is worth 2x what you paid const STOP_LOSS = 0.5; // ... or half const MAX_POSITIONS = 3; const MAX_SELL_TAX = 500; // skip tokens taxing sells above 5% (bps) const ONLY_BNB_PRICED = true; // skip tokens priced in USD1 or another asset const DRY_RUN = true; // quote and log, never send // ────────────────────────────────────────────────────── const API = "https://api.shrine.trade/bnb"; const wallet = new Wallet(PRIVATE_KEY); // signs only; no node needed const positions = new Map(); // token -> { paidBnb, symbol } const post = async (path, body) => (await fetch(`${API}${path}`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body) })).json(); async function send(txs) { for (const tx of txs) { if (DRY_RUN) { console.log(" dry-run:", tx.description); continue; } const signed = await wallet.signTransaction({ to: tx.to, data: tx.data, value: BigInt(tx.value), gasLimit: BigInt(tx.gas), maxFeePerGas: BigInt(tx.maxFeePerGas), maxPriorityFeePerGas: BigInt(tx.maxPriorityFeePerGas), nonce: tx.nonce, chainId: tx.chainId, type: 2, }); const sent = await (await fetch("https://api.shrine.trade/bnb/api/send", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ signedTx: signed }), })).json(); if (sent.error) throw new Error(`${sent.error}: ${sent.message}`); if (sent.status !== "landed") throw new Error(`${tx.description} ${sent.status}: ${sent.explorer}`); console.log(" " + tx.description + ": " + sent.explorer); } } async function onLaunch(t) { if (positions.size >= MAX_POSITIONS || positions.has(t.token)) return; if (ONLY_BNB_PRICED && t.quoteToken !== "BNB") return; if ((t.sellTaxBps ?? 0) > MAX_SELL_TAX) return; console.log(`launch ${t.symbol} ${t.token} tax ${t.buyTaxBps}/${t.sellTaxBps} bps, priced in ${t.quoteToken}`); const q = await post("/api/local-trade", { action: "buy", token: t.token, amount: BUY_BNB, from: wallet.address }); if (q.error) { console.log(" skip:", q.error, q.message); return; } console.log(` buying ${BUY_BNB} BNB -> ~${q.quote.expectedOutFormatted} ${q.symbol}`); await send(q.txs); positions.set(t.token, { paidBnb: Number(BUY_BNB), symbol: q.symbol }); } async function checkPositions() { for (const [token, pos] of positions) { const q = await post("/api/local-trade", { action: "sell", token, amount: "100%", from: wallet.address }); if (q.error) continue; // insufficient_balance right after a dry-run buy is expected const worth = Number(q.quote.expectedOutFormatted); // BNB, after tax and fees const ratio = worth / pos.paidBnb; if (ratio >= TAKE_PROFIT || ratio <= STOP_LOSS) { console.log(`selling ${pos.symbol}: worth ${worth.toFixed(5)} BNB, ${ratio.toFixed(2)}x`); await send(q.txs); positions.delete(token); } } } const ws = new WebSocket(`${API.replace("https", "wss")}/api/launches/ws?protocols=FLAP`); ws.onmessage = (e) => { const t = JSON.parse(e.data); if (t.type === "new_launch") onLaunch(t).catch((err) => console.log(" error:", err.message)); }; ws.onclose = () => { console.log("feed closed"); process.exit(1); }; setInterval(() => checkPositions().catch(() => {}), 10_000); console.log("watching launches as", wallet.address, DRY_RUN ? "(dry run)" : ""); ``` Run it with `node sniper.js`. Keep `DRY_RUN` true until the output looks right: in that mode the bot logs the launches it would take and the transactions it would sign, and sends nothing. ## What each part does - **The feed** delivers every launch within a second of the block - several hundred a day. `?protocols=FLAP` keeps graduation events out. - **Filters** are yours to extend. The event carries `name`, `symbol`, `creator`, `tokenType`, the tax and `metaUri` (the creator's image, description and links as JSON), so "only tokens with a website" or a creator blocklist is a few lines. - **The buy** is in BNB. The quote is Flap's own, simulated as your wallet, so the tax, the curve fee and any buy cap are already in `expectedOut`. - **Position checks** run every ten seconds: the bot asks for a full-exit quote and compares the BNB it would get, after the sell tax, with the BNB it spent. - **State lives in memory.** Kill the process and it forgets what it holds; persist `positions` to disk before trusting it with real size. --- # Trade Flap Tax Tokens Without Getting Burned > How Flap tax tokens work on the curve and after graduation, what the buy and sell tax do to your fill, and how to read the numbers before you trade. # Trade Flap tax tokens without getting burned Most tokens on Flap are tax tokens: the creator takes a percentage of every buy and sell. That is not a scam flag on BNB Chain - it is the standard way a launch funds itself - but it changes the arithmetic of a trade, and a bot that ignores it loses money on tokens that "went up". ## What the tax is Two rates, set at launch and immutable: `buyTaxBps` and `sellTaxBps` (100 = 1%). They can differ; 3% in / 10% out is a common shape. The tax goes to the creator's beneficiary, automatically, in the quote asset. Where it is charged depends on where the token is: - **On the curve** - as an extra fee on the trade, on top of Flap's own curve fee. Buy 1 BNB of a 3%-tax token and about 0.9575 BNB reaches the curve (1.25% Flap fee, 3% tax). - **After graduation** - on the tokens as they move through the PancakeSwap pool. Buy and 3% of the tokens are kept back; sell and 10% of the tokens you sell go to the tax before the pool prices the rest. Either way, the API's quote already includes it. `expectedOut` is what you actually receive. ## Read it before you trade ```js const t = await (await fetch(`https://api.shrine.trade/bnb/api/token/${TOKEN}`)).json(); console.log(t.isTaxToken, t.buyTaxBps, t.sellTaxBps, t.venue); ``` `isTaxToken` and the two rates tell you the shape. `venue` tells you whether it is still on the curve. The `tax` block shows where the revenue goes and how much has been paid out - a token whose creator has already collected a lot of BNB is a token with a lot of volume. ## What a round trip really costs Buy 0.1 BNB of a 3%/10% token on the curve, sell it back straight away at the same price: | | | |---|---| | Flap curve fee, in and out | 1.25% + 1.25% | | Tax, in and out | 3% + 10% | | shrine.trade, in and out | 0.5% + 0.5% | | **Round trip** | **about 17.5%** | So the token has to gain 17.5% before you are level. The [sniper tutorial](/tutorials/snipe-flap-launches) skips sell taxes above a threshold for exactly this reason - `MAX_SELL_TAX` is the knob. ## The sell quote is the truth Never estimate a position's value from the buy price. Quote a full exit: ```js const q = await post("/api/local-trade", { action: "sell", token: TOKEN, amount: "100%", from: wallet.address }); console.log("worth", q.quote.expectedOutFormatted, q.receive); // after tax, Flap's fee and ours ``` `expectedOut` is BNB after everything. Compare that with what you paid and you have the real return. ## Graduation changes nothing in your script When the curve sells out, Flap moves the token and its BNB to a PancakeSwap pool. The same `local-trade` request keeps working; `venue` flips from `flap_curve` to `pancakeswap`, `curveFeeBps` drops to 0 and the tax carries on for the period the creator set (`taxDays` at launch, 365 by default).