# TrenchyTools API > Build, sign locally and send trades and launches on pump.fun, PumpSwap (Solana) and pons (Robinhood chain). Jito bundles, lookup tables, creator fees, quotes, balances and a live websocket feed from our own node. Base URL: https://api.trenchytools.lol --- # Introduction Source: https://trenchytools-docs-production.up.railway.app/docs Transaction building, sending, bundles, quotes, balances, creator fees and live market data for pump.fun, PumpSwap and pons. A trading and launch API for **Solana** (pump.fun, PumpSwap) and **Robinhood chain** (pons). You send a JSON request; the API resolves the venue from the token address, reads live curve or pool state, builds the transaction with slippage and priority fee, and returns it **unsigned**. You sign locally and submit through `send` (our RPC + Jito lanes) or your own node. Keys never leave your process. **Building with an AI assistant?** Give it [AGENTS.md](https://trenchytools-docs-production.up.railway.app/AGENTS.md), [openapi.json](https://trenchytools-docs-production.up.railway.app/openapi.json) and [llms-full.txt](https://trenchytools-docs-production.up.railway.app/llms-full.txt), or paste a ready prompt from [Build with AI](/docs/build-with-ai). ## What you can build `trade-local` → sign → `send`. Curve or AMM resolved per token; `pool` overrides. `create` with metadata URI and dev buy in one transaction; mint keypair co-signs. Creates, migrations, per-token and per-wallet trades over one websocket, straight from our node. Create + up to 16 buyers in one Jito bundle via launch lookup tables. ## Chains and launchpads One prefix per chain, the venue resolved from the token address (`pool` forces one). Lit marks are live; dim ones are on the roadmap, in this order. ## Request flow `POST /api/{chain}/trade-local` returns an unsigned transaction (Solana: one v0 tx; EVM: an ordered `transactions[]`), priced from current on-chain state with your `slippage` and `priorityFee` applied. Sign with your own key (web3.js / viem / ethers). The API never receives it. `POST /api/{chain}/send` submits through our RPC and Jito lanes and returns the signature; or send through any node yourself. Bundles go to `POST /api/sol/bundle`. `GET /tx/:signature`, `GET /bundle/:id`, and the `/data` websocket for creates, migrations and trades. ## Chain prefixes One prefix per chain, same verbs on each. Account endpoints (`create-api-key`, `me`, `ipfs`, `health`) are shared. | | Solana | Robinhood chain | | --- | --- | --- | | Launchpads | pump.fun bonding curve, PumpSwap after graduation | pons bonding curve, Uniswap V4 after graduation | | Prefix | `/api/sol` | `/api/rh` | | Fields | `publicKey`, `mint`, `denominatedInSol` | `wallet`, `token`, `denominatedInEth` | | `trade-local` returns | one unsigned v0 transaction (raw bytes, or JSON with `?format=json`) | ordered `transactions[]` with `label`, `to`, `data`, `value`, `gas` | | Send | `/api/sol/send`, `/api/sol/bundle` (Jito) | `/api/rh/send`, or any RPC | --- # Quickstart Source: https://trenchytools-docs-production.up.railway.app/docs/quickstart Key → quote → build → sign → send. Node 18+ or Python 3.9+, a funded wallet, and an API key. Create one at [API keys](/docs/api-keys). Shown once; pass it as `?api-key=` or the `x-api-key` header. No wallet required. ```bash title="cURL" curl "https://api.trenchytools.lol/api/sol/quote?mint=MINT_ADDRESS&action=buy&amount=0.1&api-key=YOUR_API_KEY" ``` ```bash title="cURL" curl "https://api.trenchytools.lol/api/rh/quote?token=TOKEN_ADDRESS&action=buy&amount=0.01&api-key=YOUR_API_KEY" ``` Solana uses `@solana/web3.js` to sign. Robinhood uses `viem`. ```bash title="Terminal" npm install @solana/web3.js bs58 ``` ```bash title="Terminal" npm install viem ``` Copy the full example from the trade page and replace the placeholders. --- # Build with AI Source: https://trenchytools-docs-production.up.railway.app/docs/build-with-ai Paste one prompt into Claude Code, Cursor or Codex; the assistant builds against the real API from machine-readable docs. The API ships three files for coding agents. A prompt that points the assistant at them is enough to get a working bot without reading these docs yourself. **Backups are a rule, not advice.** Every prompt here makes the assistant write each generated wallet to disk before funding it, and refuse to fund one that is not saved. Most lost wallets are keys that only ever existed in memory or a terminal. See [Wallet backups](/docs/wallets/backups). | File | What it is | | --- | --- | | [AGENTS.md](https://trenchytools-docs-production.up.railway.app/AGENTS.md) | The rules: keys stay local, only real endpoints, simulate first, handle errors by `code`. | | [openapi.json](https://trenchytools-docs-production.up.railway.app/openapi.json) | Every endpoint, field, response and error, generated from these docs and checked against the routes. | | [llms-full.txt](https://trenchytools-docs-production.up.railway.app/llms-full.txt) | All pages as plain text, for the assistant to read in one go. | | `GET https://api.trenchytools.lol/api/chains` | Live capability discovery: chains, launchpads, operations, what is live. | Every error the API returns carries `code`, `hint` and a `docs` link, so an assistant can fix its own mistakes without guessing. ## Prompts Copy one, edit the numbers, paste it into your assistant. Each starts with the same rules block. ```text title="Sniper bot" Build a Solana sniper bot on the TrenchyTools API. Before writing any code, read these three documents completely: - https://trenchytools-docs-production.up.railway.app/AGENTS.md rules for building on this API - https://trenchytools-docs-production.up.railway.app/openapi.json every endpoint, field, response and error code - https://trenchytools-docs-production.up.railway.app/llms-full.txt the full documentation as text Rules you must follow: - Use only endpoints and fields that appear in openapi.json. Never invent an endpoint, field or response key. If something is missing, say so. - Private keys never leave this machine. Build with trade-local, sign locally, submit with send. Never use the Lightning (trade) endpoints. - Every wallet the app generates (trading, funding, bundle wallets, vanity mint keys) must be written to disk BEFORE it is funded: a wallets/ folder next to the project (one JSON per wallet: address, secret, createdAt, label) or .env, and print the absolute path. Refuse to fund a wallet that is not on disk. Never keep keys only in memory or a log. - Secrets come from .env (TRENCHY_API_KEY, SOL_PRIVATE_KEY). Never hard-code or print them. Write a .env.example. - Create the API key with GET https://api.trenchytools.lol/api/create-api-key?label= and tell me to put it in .env. - Simulate with POST /api/sol/simulate before the first real send. Default to DRY_RUN=1 and tiny sizes (0.005 SOL). - Handle every API error by its "code" and show me its "hint" and "docs" link. Never retry a send without checking /tx first. - Deliverable: a TypeScript Node 20 project with README, .env.example, npm start, a dry-run mode, and clear logs. What it must do: - Connect to wss://…/api/sol/data and subscribe to subscribeNewToken. - For every new pump.fun coin that passes my filters (name/symbol keywords, dev buy ≥ X SOL, no more than Y holders in the first Z seconds), build a buy with POST /api/sol/trade-local (pool "pump", slippage 25, priorityFee from GET /api/sol/priority-fee "high"), sign it, send it with POST /api/sol/send, confirm with GET /api/sol/tx/:signature. - Subscribe to subscribeTokenTrade for each position and sell 100% when price is +X% or −Y% from entry, or after N minutes. - Keep positions in a JSON file so a restart does not lose them. Log every decision. ``` ```text title="Token launcher with bundle" Build a pump.fun token launcher with a bundled first buy on the TrenchyTools API. Before writing any code, read these three documents completely: - https://trenchytools-docs-production.up.railway.app/AGENTS.md rules for building on this API - https://trenchytools-docs-production.up.railway.app/openapi.json every endpoint, field, response and error code - https://trenchytools-docs-production.up.railway.app/llms-full.txt the full documentation as text Rules you must follow: - Use only endpoints and fields that appear in openapi.json. Never invent an endpoint, field or response key. If something is missing, say so. - Private keys never leave this machine. Build with trade-local, sign locally, submit with send. Never use the Lightning (trade) endpoints. - Every wallet the app generates (trading, funding, bundle wallets, vanity mint keys) must be written to disk BEFORE it is funded: a wallets/ folder next to the project (one JSON per wallet: address, secret, createdAt, label) or .env, and print the absolute path. Refuse to fund a wallet that is not on disk. Never keep keys only in memory or a log. - Secrets come from .env (TRENCHY_API_KEY, SOL_PRIVATE_KEY). Never hard-code or print them. Write a .env.example. - Create the API key with GET https://api.trenchytools.lol/api/create-api-key?label= and tell me to put it in .env. - Simulate with POST /api/sol/simulate before the first real send. Default to DRY_RUN=1 and tiny sizes (0.005 SOL). - Handle every API error by its "code" and show me its "hint" and "docs" link. Never retry a send without checking /tx first. - Deliverable: a TypeScript Node 20 project with README, .env.example, npm start, a dry-run mode, and clear logs. What it must do: - Take name, symbol, description, image path, twitter/telegram/website, dev buy amount and a list of buyer wallets (private keys from .env, up to 16) as config. - Upload the image and metadata with POST /api/ipfs to get metadataUri. - Generate the mint keypair locally. If there are more than 4 buyers, create a lookup table with POST /api/sol/lut first and wait until it is ready. - Build the bundle: array body to POST /api/sol/trade-local — the create (with dev buy) first, then buys (use buyers[] entries with the lookup table). The first object's priorityFee is the Jito tip (read GET /api/sol/priority-fee for the current tip floor). - Sign each transaction with its wallet (the create also with the mint keypair), send with POST /api/sol/bundle, poll GET /api/sol/bundle/:id, then confirm with GET /api/sol/tx/:signature. - Print the mint address, each wallet's expected tokens (perBuyer from ?format=json), and what landed. ``` ```text title="Take-profit / stop-loss bot" Build a take-profit and stop-loss bot for coins I already hold on Solana, on the TrenchyTools API. Before writing any code, read these three documents completely: - https://trenchytools-docs-production.up.railway.app/AGENTS.md rules for building on this API - https://trenchytools-docs-production.up.railway.app/openapi.json every endpoint, field, response and error code - https://trenchytools-docs-production.up.railway.app/llms-full.txt the full documentation as text Rules you must follow: - Use only endpoints and fields that appear in openapi.json. Never invent an endpoint, field or response key. If something is missing, say so. - Private keys never leave this machine. Build with trade-local, sign locally, submit with send. Never use the Lightning (trade) endpoints. - Every wallet the app generates (trading, funding, bundle wallets, vanity mint keys) must be written to disk BEFORE it is funded: a wallets/ folder next to the project (one JSON per wallet: address, secret, createdAt, label) or .env, and print the absolute path. Refuse to fund a wallet that is not on disk. Never keep keys only in memory or a log. - Secrets come from .env (TRENCHY_API_KEY, SOL_PRIVATE_KEY). Never hard-code or print them. Write a .env.example. - Create the API key with GET https://api.trenchytools.lol/api/create-api-key?label= and tell me to put it in .env. - Simulate with POST /api/sol/simulate before the first real send. Default to DRY_RUN=1 and tiny sizes (0.005 SOL). - Handle every API error by its "code" and show me its "hint" and "docs" link. Never retry a send without checking /tx first. - Deliverable: a TypeScript Node 20 project with README, .env.example, npm start, a dry-run mode, and clear logs. What it must do: - Read my wallet from .env and my positions from a config file (mint, entry price in SOL, take-profit %, stop-loss %, trailing %). - Subscribe to subscribeTokenTrade for each mint on wss://…/api/sol/data and keep the latest price from the trades; also poll GET /api/sol/quote every 15 s as a fallback. - When a rule triggers, sell with POST /api/sol/trade-local (action sell, amount "100%" or the configured share, pool "auto"), sign, send, confirm. - Never sell twice: mark the position done the moment a send succeeds and only reopen it if /tx says the transaction failed. - Send me a one-line summary per action (Telegram webhook URL from .env, optional). ``` ```text title="Copy-trader" Build a copy-trading bot on the TrenchyTools API. Before writing any code, read these three documents completely: - https://trenchytools-docs-production.up.railway.app/AGENTS.md rules for building on this API - https://trenchytools-docs-production.up.railway.app/openapi.json every endpoint, field, response and error code - https://trenchytools-docs-production.up.railway.app/llms-full.txt the full documentation as text Rules you must follow: - Use only endpoints and fields that appear in openapi.json. Never invent an endpoint, field or response key. If something is missing, say so. - Private keys never leave this machine. Build with trade-local, sign locally, submit with send. Never use the Lightning (trade) endpoints. - Every wallet the app generates (trading, funding, bundle wallets, vanity mint keys) must be written to disk BEFORE it is funded: a wallets/ folder next to the project (one JSON per wallet: address, secret, createdAt, label) or .env, and print the absolute path. Refuse to fund a wallet that is not on disk. Never keep keys only in memory or a log. - Secrets come from .env (TRENCHY_API_KEY, SOL_PRIVATE_KEY). Never hard-code or print them. Write a .env.example. - Create the API key with GET https://api.trenchytools.lol/api/create-api-key?label= and tell me to put it in .env. - Simulate with POST /api/sol/simulate before the first real send. Default to DRY_RUN=1 and tiny sizes (0.005 SOL). - Handle every API error by its "code" and show me its "hint" and "docs" link. Never retry a send without checking /tx first. - Deliverable: a TypeScript Node 20 project with README, .env.example, npm start, a dry-run mode, and clear logs. What it must do: - Watch a list of wallets with subscribeAccountTrade on wss://…/api/sol/data. - When a watched wallet buys a pump.fun coin, buy the same coin with a fixed SOL size (config), slippage 20, pool "auto"; when it sells, sell the same share of my position. - Ignore coins older than N minutes (GET /api/sol/token/:mint) and skip if my balance is below a floor (GET /api/sol/balances). - Keep a ledger of copied trades with the leader's signature and mine; expose a tiny status page on localhost. ``` ```text title="Robinhood chain (pons) bot" Build a trading bot for pons coins on Robinhood chain on the TrenchyTools API. Before writing any code, read these three documents completely: - https://trenchytools-docs-production.up.railway.app/AGENTS.md rules for building on this API - https://trenchytools-docs-production.up.railway.app/openapi.json every endpoint, field, response and error code - https://trenchytools-docs-production.up.railway.app/llms-full.txt the full documentation as text Rules you must follow: - Use only endpoints and fields that appear in openapi.json. Never invent an endpoint, field or response key. If something is missing, say so. - Private keys never leave this machine. Build with trade-local, sign locally, submit with send. Never use the Lightning (trade) endpoints. - Every wallet the app generates (trading, funding, bundle wallets, vanity mint keys) must be written to disk BEFORE it is funded: a wallets/ folder next to the project (one JSON per wallet: address, secret, createdAt, label) or .env, and print the absolute path. Refuse to fund a wallet that is not on disk. Never keep keys only in memory or a log. - Secrets come from .env (TRENCHY_API_KEY, SOL_PRIVATE_KEY). Never hard-code or print them. Write a .env.example. - Create the API key with GET https://api.trenchytools.lol/api/create-api-key?label= and tell me to put it in .env. - Simulate with POST /api/sol/simulate before the first real send. Default to DRY_RUN=1 and tiny sizes (0.005 SOL). - Handle every API error by its "code" and show me its "hint" and "docs" link. Never retry a send without checking /tx first. - Deliverable: a TypeScript Node 20 project with README, .env.example, npm start, a dry-run mode, and clear logs. What it must do: - Use the /api/rh routes: trade-local returns an ordered transactions[] (approve → sell, graduate → buy); send them in order with viem and wait for the approve receipt before the sell. - Watch wss://…/api/rh/data subscribeNewToken for launches and buy with a fixed ETH size in the first N seconds (slippage 10), then sell on +X% using GET /api/rh/quote with my wallet as holder. - Everything else as in the rules above (dry-run, simulate with POST /api/rh/simulate, error codes). ``` ## Before you trust it Run with `DRY_RUN=1`: it should build and simulate (`POST /api/{chain}/simulate`) and send nothing. First real run with 0.005 SOL and one coin. Check `GET /api/sol/tx/:signature` and your wallet. Every `code` is listed on [Errors](/docs/errors) with what to change. Paste the error back to the assistant with its `docs` link. Generated code is a draft until it has run against real transactions at small size. Nothing here guarantees a landing or a profit. --- # Example repos Source: https://trenchytools-docs-production.up.railway.app/docs/examples Working projects on this API to clone, run and hand to your assistant as the pattern to follow. Every example is TypeScript, runs with `npm start`, reads its secrets from `.env` (template in `.env.example`), has a `DRY_RUN=1` mode that builds and simulates without sending, and logs every API error `code`. An assistant that reads one of them produces the same shape. | Repo | What it does | Status | | --- | --- | --- | | **pumpfun-launcher** | Full launcher UI: wallets, metadata upload, create + up to 16 bundled buyers via lookup tables, live trades, sells, creator fees. Backend talks only to this API. | Working; in this repository under `demos/pumpfun-launcher`. Public GitHub repo being prepared. | | **sniper-bot** | Watches `subscribeNewToken`, filters, buys, takes profit / stops out, persists positions. | Coming. Until then: the [Build with AI](/docs/build-with-ai) sniper prompt produces it. | | **take-profit-bot** | Take-profit, stop-loss and trailing rules for coins you already hold. | Coming (prompt available). | | **copy-trader** | Mirrors buys and sells of watched wallets with `subscribeAccountTrade`. | Coming (prompt available). | | **pons-bot** | Robinhood chain: launches and trades on pons through the ordered-transaction flow. | Coming (prompt available). | | **sdk** | `@trenchytools/sdk`: typed client generated from `openapi.json`, retries, 429 handling, websocket helper. | In this repository under `packages/sdk` (0.1, not yet published). | GitHub links land here as each repo is published. Until then, the prompts on [Build with AI](/docs/build-with-ai) plus [openapi.json](https://trenchytools-docs-production.up.railway.app/openapi.json) are enough for an assistant to generate any of them. ## What an example must have - TypeScript, Node 20+, `npm start` - `README.md` with setup in five steps - `.env.example` with every variable; no secret anywhere else - `DRY_RUN=1`: build + simulate, never send - One place that maps API error `code` → what the bot does next - No private key ever leaves the process; no Lightning (custodial) endpoints --- # Get an API key Source: https://trenchytools-docs-production.up.railway.app/docs/api-keys Create your own API key in one click, see your usage, or revoke a key. Every request needs an API key. It tells us who is calling, so we can show you your usage and keep the service fast for everyone. Keys are free to create. ## Using your key Add it to the URL as `?api-key=YOUR_API_KEY`, or send it in an `x-api-key` header. Both work on every endpoint, including the websockets. **Treat your key like a password.** Anyone with it can spend your request limits, and with a linked wallet, trade that wallet's funds. Never paste it into a public repo or a frontend that ships to users. ## Key only, or key with wallets? | Option | Best for | Who signs | | --- | --- | --- | | **Key only** (recommended) | Bots that already have their own wallets | You sign every transaction with your own key | | **Key + new wallets** | Getting started fast, or one wallet per user | You, with the wallet keys we show you once. If Lightning is enabled, we can also sign for you | **Key + new wallets** shows the wallet secrets once. Download the .txt, store it in a password manager or an offline copy, and only then fund the wallets. The API keeps nothing it could give back. [Wallet backups](/docs/wallets/backups). --- # Core concepts Source: https://trenchytools-docs-production.up.railway.app/docs/concepts Terms as this API uses them. **Local** (`trade-local`): the API builds, you sign and send. **Lightning** (`trade`): the API builds, signs with a wallet bound to your key, and sends. Fees: 0.5 % local, 1 % lightning, on the SOL/ETH side of the trade. Venue selector. Solana: `pump` (curve, default), `pump-amm` (PumpSwap), `auto` (resolved from on-chain state per request). Robinhood: resolved per request, no field needed. `denominatedInSol: true` → `amount` is SOL (ETH on EVM); `false` → `amount` is tokens. Sells accept `"100%"` or any `"N%"` of the wallet balance, read at build time. Percent. Applied to the quote the API computes from live reserves when building; the on-chain guard is the resulting min-out / max-in. Over-tight slippage surfaces as pump.fun errors 6002/6003. In SOL. Converted to a compute-unit price against the tx's unit limit; `GET /api/sol/priority-fee` returns current percentiles. On Jito bundles it also sets the tip. Curve → AMM move: PumpSwap on Solana (the websocket emits `migration` with the pool), Uniswap v4 MemeHook on Robinhood (a `graduate` entry may precede your trade). `POST /api/sol/bundle`: ≤5 transactions, atomic, same slot, ordered. Multi-buyer entries pack ~4 buyers per tx via a lookup table (`POST /api/sol/lut`) → up to 16 buyers plus the create. The creator's buy inside the `create` transaction (`amount` on the create entry). Priced against the fresh curve; the API simulates the curve forward for subsequent buyers in the same bundle. pump.fun / PumpSwap creator revenue. `GET /api/sol/creator-fees?wallet=` reports what is claimable; `action: "collectCreatorFee"` builds the claim. Launch-window tax on pons buys, decaying to zero over the first blocks. Addresses in the create call's exempt list skip it. --- # Solana overview Source: https://trenchytools-docs-production.up.railway.app/docs/sol/overview pump.fun curve and PumpSwap AMM: routing, pools, trade flow. pump.fun bonding-curve coins and graduated coins on PumpSwap. `pool`: `pump` (curve), `pump-amm` (PumpSwap), `auto` (resolved from chain state). | You want to… | Use | | --- | --- | | Buy or sell | [POST /api/sol/trade-local](/docs/sol/trade) | | Launch a coin | [Create a token](/docs/sol/create) | | Launch and buy from several wallets at once | [Jito bundles](/docs/sol/bundles) | | Send a signed transaction fast | [POST /api/sol/send](/docs/sol/send) | | See a price before trading | [GET /api/sol/quote](/docs/sol/quote) | | Watch new coins and trades live | [Websocket](/docs/sol/websocket) | Root aliases: `/api/trade-local`, `/api/trade`, `/api/data` resolve to the Solana routes. --- # Buy & sell Source: https://trenchytools-docs-production.up.railway.app/docs/sol/trade Get an unsigned buy or sell transaction for your wallet, then sign and send it. Builds a transaction that buys or sells a coin from **your** wallet. We never see your private key: you sign the transaction yourself, then send it with [/api/sol/send](/docs/sol/send). ## Request fields Your wallet address (base58). `buy` or `sell`. The coin's address. How much. SOL if `denominatedInSol` is `"true"`, tokens if `"false"`. Sells also accept a share of your balance, like `"100%"` or `"50%"`. Whether `amount` is in SOL (`"true"`) or in tokens (`"false"`). Worst price you accept, in percent. Default 10. Use 15–25 for coins in their first minutes. Extra SOL to land faster. Default 0.00005. `pump` (bonding curve), `pump-amm` (PumpSwap) or `auto` (we pick). Default `pump`; `auto` resolves curve vs. AMM from chain state. ## Full example ```javascript import { Keypair, VersionedTransaction } from '@solana/web3.js' import bs58 from 'bs58' const BASE = 'https://api.trenchytools.lol' const API_KEY = 'YOUR_API_KEY' const wallet = Keypair.fromSecretKey(bs58.decode(process.env.SOL_PRIVATE_KEY)) // 1. Ask for the transaction const res = await fetch(`${BASE}/api/sol/trade-local?api-key=${API_KEY}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ publicKey: wallet.publicKey.toBase58(), action: 'buy', mint: 'MINT_ADDRESS', amount: 0.01, // 0.01 SOL denominatedInSol: 'true', slippage: 15, priorityFee: 0.0001, pool: 'auto', }), }) if (!res.ok) throw new Error((await res.json()).error) // 2. Sign it with your own key const tx = VersionedTransaction.deserialize(new Uint8Array(await res.arrayBuffer())) tx.sign([wallet]) // 3. Send it through every fast lane const sent = await fetch(`${BASE}/api/sol/send?api-key=${API_KEY}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ transaction: Buffer.from(tx.serialize()).toString('base64') }), }).then((r) => r.json()) console.log('https://solscan.io/tx/' + sent.signature) ``` ```python import base64, os, requests from solders.keypair import Keypair from solders.transaction import VersionedTransaction BASE = 'https://api.trenchytools.lol' API_KEY = 'YOUR_API_KEY' wallet = Keypair.from_base58_string(os.environ['SOL_PRIVATE_KEY']) # 1. Ask for the transaction res = requests.post(f'{BASE}/api/sol/trade-local', params={'api-key': API_KEY}, json={ 'publicKey': str(wallet.pubkey()), 'action': 'buy', 'mint': 'MINT_ADDRESS', 'amount': 0.01, 'denominatedInSol': 'true', 'slippage': 15, 'priorityFee': 0.0001, 'pool': 'auto', }) res.raise_for_status() # 2. Sign it with your own key tx = VersionedTransaction(VersionedTransaction.from_bytes(res.content).message, [wallet]) # 3. Send it through every fast lane sent = requests.post(f'{BASE}/api/sol/send', params={'api-key': API_KEY}, json={'transaction': base64.b64encode(bytes(tx)).decode()}).json() print('https://solscan.io/tx/' + sent['signature']) ``` ```bash curl -X POST "https://api.trenchytools.lol/api/sol/trade-local?api-key=YOUR_API_KEY&format=json" \ -H "Content-Type: application/json" \ -d '{ "publicKey": "YOUR_WALLET", "action": "buy", "mint": "MINT_ADDRESS", "amount": 0.01, "denominatedInSol": "true", "slippage": 15, "priorityFee": 0.0001, "pool": "auto" }' ``` ## Response By default the body is the **raw transaction bytes** (`application/octet-stream`). Add `?format=json` to get JSON instead: ```json title="Response" { "transaction": "AQAAAAAAAAAAAAAA…", // base64, unsigned "encoding": "base64", "expected": { "tokens": 291577.94, "sol": 0.01 }, "feeSol": 0.00005, "mint": "MINT_ADDRESS" } ``` ## Selling everything ```json title="Response" { "publicKey": "YOUR_WALLET", "action": "sell", "mint": "MINT_ADDRESS", "amount": "100%", "denominatedInSol": "false", "slippage": 15, "pool": "auto" } ``` Got error `6002` or `6003` when the transaction ran? The price moved more than your slippage while it was on its way. Raise `slippage`, or trade a little later when the coin has calmed down. --- # Create a token Source: https://trenchytools-docs-production.up.railway.app/docs/sol/create Launch a pump.fun coin with its image, links and a first buy, in one transaction. Three calls: `POST /api/ipfs` for the metadata URI, a fresh mint keypair (generated locally, it co-signs), then `trade-local` with `action: "create"`. The create and the dev buy are one transaction. Send them to [POST /api/ipfs](/docs/ipfs). You get back a `metadataUri`. A brand-new keypair that becomes the coin's address. It must sign the create too. Use `action: "create"` with `tokenMetadata` and the mint's public key. ## Request fields Your wallet (the creator). `create`. The **public key** of the new mint keypair. `{ name, symbol, uri }`: `uri` is the `metadataUri` from [/api/ipfs](/docs/ipfs). Name up to 32 characters, symbol up to 10. Your dev buy, in SOL. 0 for no buy. Keep `"true"`. For the dev buy. Default 10. SOL. Default 0.00005. ## Full example ```javascript import fs from 'node:fs' import { Keypair, VersionedTransaction } from '@solana/web3.js' import bs58 from 'bs58' const BASE = 'https://api.trenchytools.lol', API_KEY = 'YOUR_API_KEY' const wallet = Keypair.fromSecretKey(bs58.decode(process.env.SOL_PRIVATE_KEY)) // 1. Upload image + details const form = new FormData() form.append('file', new Blob([fs.readFileSync('./logo.png')], { type: 'image/png' }), 'logo.png') form.append('name', 'My Coin') form.append('symbol', 'MYC') form.append('description', 'The best coin') form.append('twitter', 'https://x.com/mycoin') form.append('website', 'https://mycoin.fun') const { metadataUri } = await fetch(`${BASE}/api/ipfs?api-key=${API_KEY}`, { method: 'POST', body: form }).then((r) => r.json()) // 2. A new mint keypair (this becomes the coin's address) const mint = Keypair.generate() // 3. Create + dev buy in one transaction const res = await fetch(`${BASE}/api/sol/trade-local?api-key=${API_KEY}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ publicKey: wallet.publicKey.toBase58(), action: 'create', mint: mint.publicKey.toBase58(), tokenMetadata: { name: 'My Coin', symbol: 'MYC', uri: metadataUri }, amount: 0.1, // dev buy: 0.1 SOL denominatedInSol: 'true', slippage: 10, priorityFee: 0.0005, }), }) const tx = VersionedTransaction.deserialize(new Uint8Array(await res.arrayBuffer())) tx.sign([wallet, mint]) // both must sign const sent = await fetch(`${BASE}/api/sol/send?api-key=${API_KEY}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ transaction: Buffer.from(tx.serialize()).toString('base64') }), }).then((r) => r.json()) console.log('https://pump.fun/coin/' + mint.publicKey.toBase58(), sent.signature) ``` ```python import base64, os, requests from solders.keypair import Keypair from solders.transaction import VersionedTransaction BASE, API_KEY = 'https://api.trenchytools.lol', 'YOUR_API_KEY' wallet = Keypair.from_base58_string(os.environ['SOL_PRIVATE_KEY']) # 1. Upload image + details with open('logo.png', 'rb') as f: meta = requests.post(f'{BASE}/api/ipfs', params={'api-key': API_KEY}, files={'file': ('logo.png', f, 'image/png')}, data={'name': 'My Coin', 'symbol': 'MYC', 'description': 'The best coin'}).json() # 2. A new mint keypair mint = Keypair() # 3. Create + dev buy res = requests.post(f'{BASE}/api/sol/trade-local', params={'api-key': API_KEY}, json={ 'publicKey': str(wallet.pubkey()), 'action': 'create', 'mint': str(mint.pubkey()), 'tokenMetadata': {'name': 'My Coin', 'symbol': 'MYC', 'uri': meta['metadataUri']}, 'amount': 0.1, 'denominatedInSol': 'true', 'slippage': 10, 'priorityFee': 0.0005, }) tx = VersionedTransaction(VersionedTransaction.from_bytes(res.content).message, [wallet, mint]) sent = requests.post(f'{BASE}/api/sol/send', params={'api-key': API_KEY}, json={'transaction': base64.b64encode(bytes(tx)).decode()}).json() print('https://pump.fun/coin/' + str(mint.pubkey()), sent['signature']) ``` Coins are created as Token-2022 with the dev buy folded in, the same shape the pump.fun website makes. --- # Jito bundles Source: https://trenchytools-docs-production.up.railway.app/docs/sol/bundles Up to 5 transactions that land together, all or nothing; up to 16 buyers with lookup tables. Send an **array** of up to 5 trade objects instead of one. You get back a list of transactions, one per object, in the same order. Sign each with its wallet, then send them together with [POST /api/sol/bundle](/docs/sol/send-bundle). They land in the same block, in order, or not at all. The **first** object's `priorityFee` is paid as the Jito tip (that is what makes a bundle land). Priority fees on the other objects are ignored. Launching with buyers? Put the `create` first and the buys of the **same mint** after it. Each buy is priced on the curve exactly as it will be at that point in the bundle (after the dev buy and the buys before it), so the amounts match what lands. A bundle is the create plus up to 4 buyers. Add `?format=json` to get `{ transactions: [{ transaction, expected: { tokens, sol }, feeSol, mint, action }] }` instead of a bare list: handy for showing each wallet how many tokens it will get. Need more than 4 buyers in the block? See [Lookup tables](/docs/sol/lut): a `buyers` entry puts several wallets in one transaction, for about 16 per bundle. ## Example: launch + 2 buyers ```javascript title="JavaScript" const txs = await fetch(`${BASE}/api/sol/trade-local?api-key=${API_KEY}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify([ { publicKey: dev.publicKey.toBase58(), action: 'create', mint: mint.publicKey.toBase58(), tokenMetadata: { name: 'My Coin', symbol: 'MYC', uri: metadataUri }, amount: 0.5, denominatedInSol: 'true', slippage: 10, priorityFee: 0.002, pool: 'pump' }, { publicKey: buyer1.publicKey.toBase58(), action: 'buy', mint: mint.publicKey.toBase58(), amount: 0.3, denominatedInSol: 'true', slippage: 25, priorityFee: 0, pool: 'pump' }, { publicKey: buyer2.publicKey.toBase58(), action: 'buy', mint: mint.publicKey.toBase58(), amount: 0.3, denominatedInSol: 'true', slippage: 25, priorityFee: 0, pool: 'pump' }, ]), }).then((r) => r.json()) // [base58, base58, base58] const signed = txs.map((b58, i) => { const tx = VersionedTransaction.deserialize(bs58.decode(b58)) tx.sign(i === 0 ? [dev, mint] : [[buyer1, buyer2][i - 1]]) return bs58.encode(tx.serialize()) }) const { bundleId } = await fetch(`${BASE}/api/sol/bundle?api-key=${API_KEY}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ transactions: signed }), }).then((r) => r.json()) console.log('bundle', bundleId) ``` ## Response ```json title="Response" ["4hX9…base58…", "2kPq…base58…", "9wLm…base58…"] ``` --- # Lookup tables Source: https://trenchytools-docs-production.up.railway.app/docs/sol/lut Launch with up to 16 buyers in one block: a lookup table lets several wallets buy in one transaction. A Jito bundle holds 5 transactions, so a plain launch bundle is the create plus 4 buyers. An **address lookup table** lists the accounts a coin's buys touch (its curve accounts, each wallet's token account), so one transaction can carry **about 4 buyers** instead of one, and a bundle about **16**. The table lives on chain under your wallet; its rent (about 0.002 SOL plus 32 bytes per address) comes back when you close it after the launch. Order of events: create the table and wait until it is **ready** (one slot after the last extend, about a second) → build the bundle with `buyers` entries that name the table → send the bundle → later, deactivate and close the table to get the rent back. ## 1. Create the table The wallet that owns the table and pays its rent (the dev wallet is a good choice). The coin (it may not exist yet: pass the new mint's public key). Every wallet that will buy (up to 60). The coin's creator (defaults to `authority`); needed when the coin does not exist yet. You get the table's address and one or more unsigned transactions: the first creates the table and adds the first addresses, the others add more. Sign each with `authority` and send them **in order** with [/api/sol/send](/docs/sol/send), waiting for the first to confirm. ```javascript const { lookupTable, transactions, rentSol } = await fetch(`${BASE}/api/sol/lut?api-key=${API_KEY}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ authority: dev.publicKey.toBase58(), mint: mint.publicKey.toBase58(), wallets: buyers.map((b) => b.publicKey.toBase58()) }), }).then((r) => r.json()) for (const b64 of transactions) { const tx = VersionedTransaction.deserialize(Buffer.from(b64, 'base64')) tx.sign([dev]) const { signature } = await fetch(`${BASE}/api/sol/send?api-key=${API_KEY}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ transaction: Buffer.from(tx.serialize()).toString('base64') }), }).then((r) => r.json()) // wait for it: GET /api/sol/tx/:signature until confirmed } // then poll GET /api/sol/lut/:lookupTable until ready === true ``` ```bash curl -X POST "https://api.trenchytools.lol/api/sol/lut?api-key=YOUR_API_KEY" -H "Content-Type: application/json" -d '{"authority":"DEV_WALLET","mint":"NEW_MINT","wallets":["WALLET_1","WALLET_2","WALLET_3"]}' ``` ```json title="Response" { "lookupTable": "…", "addresses": 14, "rentSol": 0.0043, "transactions": ["base64…"], "encoding": "base64" } ``` ## 2. Check it is ready ```bash title="cURL" curl "https://api.trenchytools.lol/api/sol/lut/LOOKUP_TABLE?api-key=YOUR_API_KEY" ``` ```json title="Response" { "lookupTable": "…", "authority": "…", "addresses": ["…"], "lastExtendedSlot": 3812, "ready": true, "deactivated": false } ``` ## 3. Build the bundle with buyers entries In [/api/sol/trade-local](/docs/sol/bundles) a bundle entry may carry `buyers: [{ publicKey, amount }, …]` plus `lookupTable` instead of a single `publicKey`. Up to 6 buyers per entry are accepted; about 4 fit in 1232 bytes (every signer still costs an address and a signature). Each buyer signs; the first one pays the network fee. Buyers are priced in order on the same curve. ```javascript title="JavaScript" const txs = await fetch(`${BASE}/api/sol/trade-local?format=json&api-key=${API_KEY}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify([ { publicKey: dev.publicKey.toBase58(), action: 'create', mint: mint.publicKey.toBase58(), tokenMetadata: { name: 'My Coin', symbol: 'MYC', uri: metadataUri }, amount: 0.5, denominatedInSol: 'true', slippage: 10, priorityFee: 0.002 }, { action: 'buy', mint: mint.publicKey.toBase58(), lookupTable, denominatedInSol: 'true', slippage: 25, buyers: buyers.slice(0, 4).map((b) => ({ publicKey: b.publicKey.toBase58(), amount: 0.2 })) }, { action: 'buy', mint: mint.publicKey.toBase58(), lookupTable, denominatedInSol: 'true', slippage: 25, buyers: buyers.slice(4, 8).map((b) => ({ publicKey: b.publicKey.toBase58(), amount: 0.2 })) }, ]), }).then((r) => r.json()) // { transactions: [{ transaction, expected, perBuyer: [{ publicKey, tokens, sol }] }, …] } const signed = txs.transactions.map((t, i) => { const tx = VersionedTransaction.deserialize(bs58.decode(t.transaction)) tx.sign(i === 0 ? [dev, mint] : buyers.slice((i - 1) * 4, i * 4)) return bs58.encode(tx.serialize()) }) // POST /api/sol/bundle { transactions: signed } ``` ## 4. Get the rent back `POST /api/sol/lut/:address/deactivate { authority }` returns a transaction to sign and send. About four minutes later (513 slots), `POST /api/sol/lut/:address/close { authority, recipient? }` returns the one that closes the table and refunds the rent. Too early gets `409 cooling_down` with the seconds left. --- # Vanity mint Source: https://trenchytools-docs-production.up.railway.app/docs/sol/vanity A mint that ends in `pump` (or another short pattern): instant from our warm pool, a bounded job for other patterns, or the SDK grinder on your own CPU. pump.fun coins conventionally end in `pump`, letsbonk coins in `bonk`. The address is the mint keypair's public key, so a pattern means grinding keypairs until one matches (a 4-character suffix averages 11 million tries). Three tiers: **warm pool** — we keep a few `…pump` and `…bonk` keys ready, so the common request answers at once; **job** — other patterns up to 4 characters are ground on our workers (up to 10 minutes); **local** — the SDK grinder on your own CPU, no limits, the key never exists anywhere else (the recommended default for anything custom). A job's keypair is handed out **once** and never stored or logged. Use it promptly as the `mint` of your own `create`: anyone who sees the secret first could create a token at that address. Save the keypair to disk the moment you get it (the `wallets/` pattern on [Wallet backups](/docs/wallets/backups)); a mint key that only lives in memory is a launch you cannot repeat. ## Start a job Base58 characters the address must end with, e.g. `pump`. Case-sensitive by default. Base58 characters it must start with. `suffix` + `prefix` together ≤ 4 characters on our workers; longer patterns → `vanity_too_long`, grind locally. Default `true` (pump.fun shows the exact case). `false` matches letters in either case and is ~30 % faster per character. ```bash curl -X POST "https://api.trenchytools.lol/api/sol/vanity?api-key=YOUR_API_KEY" \ -H "content-type: application/json" \ -d '{"suffix":"pump"}' ``` ```javascript const start = await fetch(`${BASE}/api/sol/vanity?api-key=${API_KEY}`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ suffix: 'pump' }), }).then((r) => r.json()) // pooled suffixes come back status "done" immediately; otherwise poll (a job may take minutes) let job do { await new Promise((r) => setTimeout(r, 5000)) job = await fetch(`${BASE}${start.poll}?api-key=${API_KEY}`).then((r) => r.json()) } while (job.status === 'running') if (job.status !== 'done') throw new Error(job.reason) const mint = Keypair.fromSecretKey(bs58.decode(job.secretKey)) // use it as the mint of your create, now ``` ```json title="Response (202 · pooled key: status \"done\" straight away, poll once to collect it)" { "jobId": "k3Jt…", "status": "running", "suffix": "pump", "caseSensitive": true, "expectedAttempts": 11316496, "limits": { "maxChars": 4, "workersPerJob": 3, "timeoutS": 600, "maxJobs": 2, "pool": { "ready": { "pump": 5, "bonk": 3 } } }, "poll": "/api/sol/vanity/k3Jt…" } ``` ## Poll a job `GET /api/sol/vanity/:jobId` → `status` `running` (with `attempts`, `elapsedMs`), `failed` (with `reason`, e.g. the 10-minute limit), or `done` with `publicKey` and `secretKey` — once. `pooled: true` marks a key that came from the warm pool. A second read says `collected: true`. Results are kept 10 minutes. One running job per key; when the workers are busy you get `429 vanity_busy`: retry in a minute or grind locally. ```json title="Response (done)" { "jobId": "k3Jt…", "status": "done", "attempts": 9412377, "elapsedMs": 171204, "publicKey": "7gH…pump", "secretKey": "", "warning": "Shown once; we keep nothing. Use it only as the mint of your own create, promptly." } ``` ## Grind locally (recommended) Same search on your own CPU, no limits, the key never leaves the process. The SDK ships it; any example repo has the worker. ```javascript title="JavaScript" import { grindVanity } from '@trenchytools/sdk/vanity' const { keypair, attempts } = await grindVanity({ suffix: 'pump', workers: 8 }) // ~1–2 min on 8 cores // keypair.publicKey.toBase58() ends in "pump"; pass it as `mint` and sign the create with it ``` ## What each launchpad expects | Launchpad | Address pattern | Who makes it | | --- | --- | --- | | pump.fun | `…pump` (convention, optional) | You: vanity mint keypair | | letsbonk (LaunchLab) | `…bonk` (convention, optional) | You: vanity mint keypair | | StonkFun (LaunchLab) | none | — | | four.meme (BNB) | `…4444` always | The launchpad (CREATE2 salt), nothing to do | | Flap (BNB) | none known | — | | pons (Robinhood) | derived from form + salt | Salt search; not exposed yet | `GET /api/chains` carries the same `address` info per launchpad so an assistant knows when to grind and when not to. --- # Creator fees Source: https://trenchytools-docs-production.up.railway.app/docs/sol/creator-fees See and claim the creator fees your coins earned. Every pump.fun coin pays its creator a share of each trade, on the bonding curve and after it moves to PumpSwap. Check what a creator wallet can claim, then claim it all in one transaction. The creator (dev) wallet. ```bash title="cURL" curl "https://api.trenchytools.lol/api/sol/creator-fees?wallet=DEV_WALLET&api-key=YOUR_API_KEY" ``` ```json title="Response" { "wallet": "…", "lamports": "18250000", "sol": 0.01825 } ``` ## Claim them Ask [/api/sol/trade-local](/docs/sol/trade) for `action: "collectCreatorFee"`. No mint needed: one transaction claims every coin's fees. Sign it with the creator wallet and send it. There is no API fee on claims. ```javascript title="JavaScript" const res = await fetch(`${BASE}/api/sol/trade-local?api-key=${API_KEY}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ publicKey: dev.publicKey.toBase58(), action: 'collectCreatorFee', priorityFee: 0.0001 }), }) const tx = VersionedTransaction.deserialize(new Uint8Array(await res.arrayBuffer())) tx.sign([dev]) // then POST it to /api/sol/send ``` A wallet with nothing to claim gets `409 nothing_to_collect`. --- # Lightning trade Source: https://trenchytools-docs-production.up.railway.app/docs/sol/lightning We build, sign with the wallet linked to your key, and send. One request, no signing code. Lightning is **not enabled yet** on this server. Use [Buy & sell](/docs/sol/trade) (you sign) in the meantime. Same fields as [Buy & sell](/docs/sol/trade), but no `publicKey`: we use the Solana wallet linked to your API key (create one with **Key + new wallets** on [Get an API key](/docs/api-keys)) and send the transaction for you. Fee: 1% instead of 0.5%. ```bash title="cURL" curl -X POST "https://api.trenchytools.lol/api/sol/trade?api-key=YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "action": "buy", "mint": "MINT_ADDRESS", "amount": 0.01, "denominatedInSol": "true", "slippage": 15, "priorityFee": 0.0001, "pool": "auto" }' ``` ```json title="Response" { "signature": "5Uf…", "lanes": ["rpc", "jito:mainnet"], "expected": { "tokens": 291577.9, "sol": 0.01 } } ``` --- # Send a transaction Source: https://trenchytools-docs-production.up.railway.app/docs/sol/send Send a signed transaction through our RPC and every Jito region at once. Takes a **signed** transaction and pushes it through our premium Solana node and all Jito regions at the same time, so it lands as fast as possible. Works for any Solana transaction, not just ours. The signed transaction, base64 or base58. Default `false`: we simulate first and refuse a transaction that would fail. `true` sends without checking (faster). Send only through Jito. ```javascript const sent = await fetch(`${BASE}/api/sol/send?api-key=${API_KEY}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ transaction: Buffer.from(signedTx.serialize()).toString('base64') }), }).then((r) => r.json()) ``` ```bash curl -X POST "https://api.trenchytools.lol/api/sol/send?api-key=YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "transaction": "BASE64_SIGNED_TX" }' ``` ```json title="Response" { "signature": "5Uf…", "lanes": ["rpc", "jito:mainnet", "jito:ny", "jito:frankfurt"] } ``` Trades are relayed exactly as `trade-local` built them. A pump.fun or PumpSwap buy, sell or create whose fee transfer was removed gets `400 fee_missing`; the fee is 0.5 % of the SOL side and is already in the `feeSol` the build reports. --- # Blockhash Source: https://trenchytools-docs-production.up.railway.app/docs/sol/blockhash A recent blockhash, for transactions you build yourself. Most transactions come ready-made from [/api/sol/trade-local](/docs/sol/trade). For the ones you build yourself (moving SOL between your wallets, closing empty token accounts) you need a recent blockhash: get it here, build and sign the transaction, then send it with [/api/sol/send](/docs/sol/send). No RPC of your own needed. ```javascript import { SystemProgram, TransactionMessage, VersionedTransaction } from '@solana/web3.js' const { blockhash } = await (await fetch(`${BASE}/api/sol/blockhash?api-key=${API_KEY}`)).json() const tx = new VersionedTransaction(new TransactionMessage({ payerKey: from.publicKey, recentBlockhash: blockhash, instructions: [SystemProgram.transfer({ fromPubkey: from.publicKey, toPubkey: to, lamports: 10_000_000 })], }).compileToV0Message()) tx.sign([from]) await fetch(`${BASE}/api/sol/send?api-key=${API_KEY}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ transaction: Buffer.from(tx.serialize()).toString('base64') }), }) ``` ```bash curl "https://api.trenchytools.lol/api/sol/blockhash?api-key=YOUR_API_KEY" ``` ```json title="Response" { "blockhash": "5tt5pLPN…", "lastValidBlockHeight": 438211042 } ``` --- # Send a bundle Source: https://trenchytools-docs-production.up.railway.app/docs/sol/send-bundle Submit 1–5 signed transactions as one Jito bundle. 1 to 5 signed transactions (base58 or base64). One must pay a Jito tip account; bundles from [trade-local](/docs/sol/bundles) already do. ```json title="Response" { "bundleId": "a1b2…", "signatures": ["…", "…"], "region": "ny" } ``` ## Check if it landed ```bash title="cURL" curl "https://api.trenchytools.lol/api/sol/bundle/BUNDLE_ID?api-key=YOUR_API_KEY" ``` ```json title="Response" { "bundleId": "a1b2…", "status": "Landed", "landedSlot": 459926401 } // Pending | Landed | Failed | Invalid ``` Trades are relayed exactly as `trade-local` built them. A pump.fun or PumpSwap buy, sell or create whose fee transfer was removed gets `400 fee_missing`; the fee is 0.5 % of the SOL side and is already in the `feeSol` the build reports. --- # Transaction status Source: https://trenchytools-docs-production.up.railway.app/docs/sol/tx Is my transaction confirmed? ```bash title="cURL" curl "https://api.trenchytools.lol/api/sol/tx/SIGNATURE?api-key=YOUR_API_KEY" ``` ```json title="Response" { "signature": "5Uf…", "slot": 459926401, "confirmationStatus": "confirmed", "err": null } ``` --- # Priority fee Source: https://trenchytools-docs-production.up.railway.app/docs/sol/priority-fee Live suggestions for priorityFee and Jito tips. Read this before trading to pick a `priorityFee` that lands. `suggestedPriorityFeeSol` plugs straight into the `priorityFee` field. ```json title="Response" { "suggestedPriorityFeeSol": { "low": 0.000006, "medium": 0.000018, "high": 0.000024, "veryHigh": 0.000252 }, "jitoTipSol": { "p25": 0.000001, "p50": 0.000012, "p75": 0.000077, "p95": 0.00055 } } ``` Jito tip accounts (for building your own bundles): `GET /api/sol/jito/tip-accounts`. --- # Quote Source: https://trenchytools-docs-production.up.railway.app/docs/sol/quote See what a trade would give you before you make it. The coin's address. `buy` or `sell`. SOL for a buy, tokens for a sell (by default). Override the unit. `auto` (default), `pump` or `pump-amm`. ```bash title="cURL" curl "https://api.trenchytools.lol/api/sol/quote?mint=MINT_ADDRESS&action=buy&amount=0.1&api-key=YOUR_API_KEY" ``` ```json title="Response" { "pool": "pump", "action": "buy", "solIn": 0.1, "tokensOut": 2915779.4, "avgPriceSol": 3.4e-8, "spotPriceSol": 3.36e-8, "priceImpactPct": 1.27, "marketCapSol": 33.6, "bondingProgressPct": 4.7, "complete": false } ``` --- # Token info Source: https://trenchytools-docs-production.up.railway.app/docs/sol/token Name, image link, price, market cap and how close the coin is to graduating. ```bash title="cURL" curl "https://api.trenchytools.lol/api/sol/token/MINT_ADDRESS?api-key=YOUR_API_KEY" ``` ```json title="Response" { "mint": "Cpu7…pump", "name": "MoonGoat", "symbol": "MGOAT", "uri": "https://ipfs.io/ipfs/…", "venue": "pump", // pump | pump-amm "curve": { "complete": false, "creator": "8cgW…", "marketCapSol": 33.6, "priceSol": 3.36e-8, "bondingProgressPct": 4.7 } } ``` --- # Balances Source: https://trenchytools-docs-production.up.railway.app/docs/sol/balances SOL and token balances of one wallet, or of up to 100 wallets in one call. ## One wallet Any Solana address. Comma-separated coin addresses. Leave out to list every non-zero token (slow for wallets with thousands of tokens). Also list token accounts holding 0, e.g. to close them and get the rent back. ```bash title="cURL" curl "https://api.trenchytools.lol/api/sol/balances?wallet=WALLET&mints=MINT_ADDRESS&api-key=YOUR_API_KEY" ``` ```json title="Response" { "wallet": "…", "sol": 1.25, "tokens": [ { "mint": "…", "balance": 291577.94, "raw": "291577940000", "account": "…", "program": "TokenzQd…" } ] } ``` ## Many wallets A bundler checking its dev, bundle and holder wallets: pass `wallets` instead of `wallet` and get every SOL balance (and one coin's balance with `mint`) in a single request. Up to 100 comma-separated addresses. One coin address: each row then carries that coin's balance too. ```bash title="cURL" curl "https://api.trenchytools.lol/api/sol/balances?wallets=WALLET_1,WALLET_2,WALLET_3&mint=MINT_ADDRESS&api-key=YOUR_API_KEY" ``` ```json title="Response" { "wallets": [ { "wallet": "…", "sol": 0.52, "token": { "mint": "…", "balance": 1200000, "raw": "1200000000000", "account": "…", "program": "TokenzQd…" } } ] } ``` --- # Live data (websocket) Source: https://trenchytools-docs-production.up.railway.app/docs/sol/websocket New coins, graduations and trades the moment they happen. Open **one** websocket and subscribe to what you need. | Send | You receive | | --- | --- | | `{"method":"subscribeNewToken"}` | Every new pump.fun coin | | `{"method":"subscribeMigration"}` | Every coin that graduates to PumpSwap | | `{"method":"subscribeTokenTrade","keys":["MINT"]}` | Every trade on these coins | | `{"method":"subscribeAccountTrade","keys":["WALLET"]}` | Every trade by these wallets (copy-trading) | To stop, send the same message with `unsubscribe…` instead of `subscribe…`. ```javascript const ws = new WebSocket('wss://api.trenchytools.lol/api/sol/data?api-key=YOUR_API_KEY') ws.onopen = () => { ws.send(JSON.stringify({ method: 'subscribeNewToken' })) } ws.onmessage = (msg) => { const e = JSON.parse(msg.data) if (e.txType === 'create') { console.log('new coin', e.symbol, e.mint, 'dev bought', e.solAmount, 'SOL') // follow its trades too ws.send(JSON.stringify({ method: 'subscribeTokenTrade', keys: [e.mint] })) } else if (e.txType === 'buy' || e.txType === 'sell') { console.log(e.txType, e.solAmount, 'SOL by', e.traderPublicKey) } } ``` ```python import asyncio, json, websockets async def main(): async with websockets.connect('wss://api.trenchytools.lol/api/sol/data?api-key=YOUR_API_KEY') as ws: await ws.send(json.dumps({'method': 'subscribeNewToken'})) async for raw in ws: e = json.loads(raw) if e.get('txType') == 'create': print('new coin', e['symbol'], e['mint']) asyncio.run(main()) ``` ## Event examples ```json title="Response" // new coin { "txType": "create", "signature": "…", "mint": "…pump", "traderPublicKey": "…", "name": "MoonGoat", "symbol": "MGOAT", "uri": "https://ipfs.io/ipfs/…", "pool": "pump", "initialBuy": 2560000, "solAmount": 0.077, "marketCapSol": 28.1 } // trade { "txType": "buy", "signature": "…", "mint": "…pump", "traderPublicKey": "…", "tokenAmount": 291577.9, "solAmount": 0.01, "marketCapSol": 33.6, "pool": "pump" } ``` New coins and graduations are free. Trade streams need your API key in the URL. ## Migration events `subscribeMigration` delivers two moments per coin: `txType: "complete"` when the bonding curve fills (trading on the curve stops), then `txType: "migrate"` when pump.fun creates the PumpSwap pool, with `poolAddress`. Trade on PumpSwap (`pool: "pump-amm"` or `"auto"`) from the second one on. ```json title="Migration" { "txType": "migrate", "signature": "…", "mint": "…", "pool": "pump-amm", "poolAddress": "…", "slot": 3812, "ts": 1760000000000 } ``` Our feed subscribes upstream to exactly what connected clients ask for (creates, migrations, the mints and wallets you watch), straight from our own node. Subscribe to what you need; nothing is sampled or throttled. --- # Robinhood overview Source: https://trenchytools-docs-production.up.railway.app/docs/rh/overview pons on Robinhood chain: curve, Uniswap v4 after graduation, ordered EVM transactions. pons coins on their bonding curve, then on the Uniswap v4 pool (MemeHook) after graduation. EVM chain 4663; sign with viem, ethers or web3.py. `trade-local` returns an ordered `transactions[]` (an `approve` may precede a sell, a `graduate` may precede a trade). Submit in order; each entry carries `label`, `to`, `data`, `value`, `gas`. | You want to… | Use | | --- | --- | | Buy or sell | [POST /api/rh/trade-local](/docs/rh/trade) | | Launch a coin | [Create a token](/docs/rh/create) | | Send a signed transaction | [POST /api/rh/send](/docs/rh/send) | | See a price before trading | [GET /api/rh/quote](/docs/rh/quote) | | Watch new coins and trades live | [Websocket](/docs/rh/websocket) | Chain ID **4663** · native ETH · EVM field names: `wallet`, `token`, `denominatedInEth`. --- # Buy & sell Source: https://trenchytools-docs-production.up.railway.app/docs/rh/trade Get the ordered transactions for a pons buy or sell, then send them in order. Returns the transactions your wallet needs, in order, **unsigned**. Sign and send them one after another with your own wallet. If a transaction is labeled `approve`, wait for it to confirm before sending the next one. Every buy and sell carries a min-out derived from the quote and your `slippage`, on the curve and on the v4 pool alike. ## Request fields Your 0x address. `buy` or `sell`. The coin's 0x address. Buys: ETH. Sells: tokens, or a share of your balance like `"100%"`. Percent. Default 5. ## Full example ```javascript import { createWalletClient, createPublicClient, http, defineChain } from 'viem' import { privateKeyToAccount } from 'viem/accounts' const BASE = 'https://api.trenchytools.lol', API_KEY = 'YOUR_API_KEY' const robinhood = defineChain({ id: 4663, name: 'Robinhood Chain', nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 }, rpcUrls: { default: { http: ['https://rpc.mainnet.chain.robinhood.com'] } } }) const account = privateKeyToAccount(process.env.EVM_PRIVATE_KEY) const wallet = createWalletClient({ account, chain: robinhood, transport: http() }) const chain = createPublicClient({ chain: robinhood, transport: http() }) // 1. Ask for the transactions const { transactions, expected } = await fetch(`${BASE}/api/rh/trade-local?api-key=${API_KEY}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ wallet: account.address, action: 'buy', token: 'TOKEN_ADDRESS', amount: 0.01, slippage: 5 }), }).then((r) => r.json()) console.log('you should get about', expected.tokens, 'tokens') // 2. Sign and send each one, in order for (const tx of transactions) { const hash = await wallet.sendTransaction({ to: tx.to, data: tx.data, value: BigInt(tx.value) }) console.log(tx.label, hash) if (tx.label === 'approve' || tx.label === 'graduate') await chain.waitForTransactionReceipt({ hash }) } ``` ```python import os, requests from web3 import Web3 BASE, API_KEY = 'https://api.trenchytools.lol', 'YOUR_API_KEY' w3 = Web3(Web3.HTTPProvider('https://rpc.mainnet.chain.robinhood.com')) acct = w3.eth.account.from_key(os.environ['EVM_PRIVATE_KEY']) r = requests.post(f'{BASE}/api/rh/trade-local', params={'api-key': API_KEY}, json={ 'wallet': acct.address, 'action': 'buy', 'token': 'TOKEN_ADDRESS', 'amount': 0.01, 'slippage': 5, }).json() for tx in r['transactions']: signed = acct.sign_transaction({ 'to': tx['to'], 'data': tx['data'], 'value': int(tx['value']), 'chainId': 4663, 'nonce': w3.eth.get_transaction_count(acct.address), 'gas': int(tx.get('gas') or 500000), 'gasPrice': w3.eth.gas_price, }) h = w3.eth.send_raw_transaction(signed.raw_transaction) print(tx['label'], h.hex()) if tx['label'] in ('approve', 'graduate'): w3.eth.wait_for_transaction_receipt(h) ``` ## Response ```json title="Response" { "chainId": 4663, "transactions": [ { "label": "approve", "to": "0x…token", "data": "0x…", "value": "0", "gas": "55971" }, { "label": "sell", "to": "0x…curve", "data": "0x…", "value": "0" }, { "label": "fee", "to": "0x…", "data": "0x", "value": "162873307575", "valueEth": "0.000000162873307575" } ], "expected": { "tokens": 19761.65, "eth": 0.0000326 }, "venue": "curve" // curve | v4 } ``` | label | What it is | | --- | --- | | `approve` | ERC-20 approve to the curve/pool. Emitted once per token, ahead of the first sell. | | `graduate` | Finishes a coin's move to its V4 pool when it is stuck halfway. Rare. | | `buy` / `sell` | The trade itself. | | `fee` | Our 0.5% service fee, in ETH. | --- # Create a token Source: https://trenchytools-docs-production.up.railway.app/docs/rh/create Launch a pons coin with a first buy in one transaction, and know its address before you sign. Send it to [POST /api/ipfs](/docs/ipfs) and take `metadata.image` from the answer. `action: "create"` with `tokenMetadata` and your dev buy in ETH. The answer already contains the coin's **future address** (`predicted.token`). Your 0x address (the creator). `create`. `{ name, symbol, image, description?, twitter?, telegram?, website? }`. Dev buy in ETH. Minimum 0.0001. Up to 31 wallets that skip the launch-window snipe tax (your other buyers). Percent. Default 5. ```javascript title="JavaScript" const r = await fetch(`${BASE}/api/rh/trade-local?api-key=${API_KEY}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ wallet: account.address, action: 'create', tokenMetadata: { name: 'My Coin', symbol: 'MYC', image: imageUrl, twitter: 'https://x.com/mycoin' }, amount: 0.01, // dev buy: 0.01 ETH slippage: 5, }), }).then((r) => r.json()) console.log('your coin will be', r.predicted.token, '· pons launch fee', r.launchFeeEth, 'ETH') for (const tx of r.transactions) { const hash = await wallet.sendTransaction({ to: tx.to, data: tx.data, value: BigInt(tx.value) }) if (tx.label === 'create') await chain.waitForTransactionReceipt({ hash }) } ``` ```json title="Response" { "chainId": 4663, "transactions": [ { "label": "create", "to": "0x…router", "value": "10500000000000000", … }, { "label": "fee", … } ], "predicted": { "token": "0x9a21…", "curve": "0x…" }, "launchFeeEth": 0.0005, "expected": { "tokens": 5823000, "eth": 0.01 } } ``` --- # Lightning trade Source: https://trenchytools-docs-production.up.railway.app/docs/rh/lightning We sign with the Robinhood wallet linked to your key and send everything in order. Lightning is **not enabled yet** on this server. Use [Buy & sell](/docs/rh/trade) in the meantime. Same fields as [Buy & sell](/docs/rh/trade) without `wallet`. Answer: `{ hash, hashes }`. Fee: 1%. --- # Send a transaction Source: https://trenchytools-docs-production.up.railway.app/docs/rh/send Broadcast a signed Robinhood transaction through our node. The signed raw transaction, `0x…`. ```bash title="cURL" curl -X POST "https://api.trenchytools.lol/api/rh/send?api-key=YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "transaction": "0xSIGNED_RAW_TX" }' ``` ```json title="Response" { "hash": "0x…" } ``` --- # Transaction status Source: https://trenchytools-docs-production.up.railway.app/docs/rh/tx Did my transaction go through? ```bash title="cURL" curl "https://api.trenchytools.lol/api/rh/tx/0xHASH?api-key=YOUR_API_KEY" ``` ```json title="Response" { "hash": "0x…", "status": "success", "block": 94883891, "gasUsed": "113544" } ``` --- # Quote Source: https://trenchytools-docs-production.up.railway.app/docs/rh/quote An exact quote, simulated as your wallet. pons charges a launch-window snipe tax that depends on **who** buys, so the quote is simulated as your wallet. Pass `wallet` for the exact number. Graduated coins are quoted on their Uniswap v4 pool by simulating the swap (`venue: "v4"`); pass `holder` for sells. The coin's 0x address. `buy` (amount in ETH) or `sell` (amount in tokens). How much. Your address. Required for an exact sell quote (it must hold the tokens). ```bash title="cURL" curl "https://api.trenchytools.lol/api/rh/quote?token=TOKEN_ADDRESS&action=buy&amount=0.01&wallet=0xYOU&api-key=YOUR_API_KEY" ``` ```json title="Response" { "venue": "curve", "action": "buy", "ethIn": 0.01, "tokensOut": 5822825.4, "snipeTaxBps": 0, "bondingProgressPct": 5.88 } ``` --- # Token info Source: https://trenchytools-docs-production.up.railway.app/docs/rh/token The coin's curve, phase, price and graduation progress. ```bash title="cURL" curl "https://api.trenchytools.lol/api/rh/token/TOKEN_ADDRESS?api-key=YOUR_API_KEY" ``` ```json title="Response" { "token": "0x6Fbc…", "name": "Pheal", "symbol": "PHEAL", "venue": "pons-curve", // pons-curve | uniswap-v4 "curve": "0x…", "graduated": false, "creator": "0x…", "curveState": { "realEth": 0.29, "graduationThresholdEth": 5, "bondingProgressPct": 5.88, "snipeTaxBps": 0, "priceEth": 2.2e-9 } } ``` --- # Balances Source: https://trenchytools-docs-production.up.railway.app/docs/rh/balances ETH and token balances of any wallet. Any 0x address. Comma-separated token addresses. ```bash title="cURL" curl "https://api.trenchytools.lol/api/rh/balances?wallet=0xYOU&tokens=TOKEN_ADDRESS&api-key=YOUR_API_KEY" ``` ```json title="Response" { "wallet": "0x…", "eth": "0.0683", "tokens": [ { "token": "0x…", "balance": "1889822.68" } ] } ``` --- # Live data (websocket) Source: https://trenchytools-docs-production.up.railway.app/docs/rh/websocket New pons coins, graduations and trades as they happen. Same messages as the Solana websocket (`subscribeNewToken`, `subscribeMigration`, `subscribeTokenTrade`, `subscribeAccountTrade`). Events use EVM names. ```javascript title="JavaScript" const ws = new WebSocket('wss://api.trenchytools.lol/api/rh/data?api-key=YOUR_API_KEY') ws.onopen = () => ws.send(JSON.stringify({ method: 'subscribeNewToken' })) ws.onmessage = (msg) => { const e = JSON.parse(msg.data) if (e.txType === 'create') console.log('new pons coin', e.symbol, e.token) else if (e.txType === 'buy' || e.txType === 'sell') console.log(e.txType, e.ethAmount, 'ETH by', e.trader) } ``` ```json title="Events" { "txType": "create", "token": "0x…", "creator": "0x…", "name": "…", "symbol": "…", "image": "…", "curve": "0x…", "hash": "0x…", "block": 94883891 } { "txType": "buy", "token": "0x…", "trader": "0x…", "ethAmount": 0.01, "tokenAmount": 5823, "priceEth": 1.7e-6, "hash": "0x…" } { "txType": "migrate", "token": "0x…", "venue": "uniswap-v4", "hash": "0x…" } ``` --- # Wallet transfers Source: https://trenchytools-docs-production.up.railway.app/docs/wallets/overview Move value between your wallets and across chains: directly, through a centralized-exchange hop at the best available rate, through one named venue, or through a privacy-coin leg. Non-custodial throughout. Funding a set of fresh wallets, sweeping them back, moving SOL to Robinhood chain or BNB Chain: `/api/transfer` does all of it with one request shape. You pick a **route** (where the coins travel) and a **mode** (how the exchange executes). You sign exactly one thing: a deposit from your wallet. We never hold the coins. ## Routes | Route | What happens | When to use it | | --- | --- | --- | | `direct` | One signed transfer on the same chain, wallet → wallet. Nothing in between. | Moving money between wallets you are happy to see linked on chain. Same chain only. | | `exchange` · `venue: "auto"` | **Smart routing.** The order goes to the provider with the best price, speed and reliability at that moment, drawn from centralized-exchange liquidity. The destination is paid by the exchange, not by your wallet. | Default. Best rate, no on-chain link between the two wallets. | | `exchange` · `venue: ""` — **break wallet cluster** | Execution is forced through the exchange you name (bybit, kucoin, htx, mexc, …), so the destination is paid out by **that** exchange's hot wallet, not by the default route's. On-chain, the new wallet's funder is a different exchange from the one that funded your other wallets. `GET /api/transfer/venues` says which are open; a closed one is refused with `transfer_route_off`. The answer carries `venueHonoured`. Non-default venues cost about 1 % more (their withdrawal fee). | Fresh wallets that must not share a funder with your existing ones. | | `exchange` · `venue: "random"` | A venue rolled per transfer (small amounts favour the cheapest route; larger ones mix venues). | Batches: fan-outs whose destinations should look independently funded. | | cross-chain | Any exchange route with a different destination chain: SOL → ETH on Robinhood chain, SOL → BNB, ETH → SOL. The exchange does the conversion. | Moving between chains without a bridge contract or a wrapped asset. | ## Which routes are open The exchange switches venues off from time to time. `GET /api/transfer/venues` probes every route every two minutes **without creating anything** and reports `open` / `closed` / `unknown` per venue, plus the state of the default route. `routes` includes the same status on each venue entry, `venue: "random"` only rolls open venues, and a transfer to a closed venue is refused up front rather than silently rerouted. ```json title="GET /api/transfer/venues" { "exchange": "on", "checkedAt": "2026-10-22T23:52:10.000Z", "venues": { "binance": { "status": "open", "default": true }, "bybit": { "status": "open" }, "kucoin": { "status": "closed", "reason": "the exchange refuses this route for our account" }, "htx": { "status": "closed", "reason": "switched off at the exchange right now" }, "mexc": { "status": "closed", "reason": "switched off at the exchange right now" }, "bitget": { "status": "closed", "reason": "switched off at the exchange right now" }, "gate": { "status": "closed", "reason": "switched off at the exchange right now" } } } ``` ## Modes | Mode | Execution | Fee | Timing | | --- | --- | --- | --- | | `float` (default) | Market rate at execution; output may vary slightly. | ~0.1–0.4 % | Fastest: usually under a few minutes. | | `fixed` | Rate locked when the order is created; exact output guaranteed. | 0.8 % | Same once the deposit confirms; the deposit must land within ~15 minutes or the order expires. | | `private` | Routed through a **Monero or Zcash leg** before paying out: the exchange converts in, hops through the privacy coin, converts out. | 1 % + network fees | Typically 5 minutes or more. | What the private mode does: it breaks the direct on-chain path between your deposit and the destination, so a block explorer cannot walk from one to the other. What it does **not** do: make you anonymous. The exchange route sees both sides and applies its own policies. Say "reduces on-chain linkability", never "untraceable". ## Chains | Chain | As source (`from`) | As destination (`to`) | Native unit | | --- | --- | --- | --- | | Solana `sol` | yes — unsigned v0 deposit transaction | yes | SOL | | Robinhood chain `rh` | yes — `{to, value, gas}` deposit transaction | yes | ETH | | Ethereum `eth` | not yet | yes | ETH | | BNB Chain `bnb` | not yet | yes | BNB | | Arc, Base | not yet | not yet (bridge route planned) | — | ## How a transfer runs `GET /api/transfer/routes?from=sol&to=rh&amount=0.5` → every route and mode available now, with receive amount, fee, minimum and ETA. Respect `min`. `POST /api/transfer` → the exchange opens an order; you get a **one-time deposit address** and an **unsigned deposit transaction** from `from.wallet` for exactly the deposit amount. Sign that transaction with your wallet and submit it (`POST /api/sol/send`, or your own node). Promptly: the address is single-use and fixed orders expire. `GET /api/transfer/:id` → `awaiting_deposit` → `exchanging` → `completed` with `payoutHash` on the destination chain. Failed or slow orders carry a `help` block with the receipt link and support contacts. Budget: about 10 exchange orders a minute shared by every key (`429 transfer_busy`), 5 creations a minute per key, 25 legs per batch. The provider behind the exchange route is ours to run; you need no account with it. `GET /api/transfer/routes` — what is possible for a pair and amount. `POST /api/transfer` — deposit address + unsigned deposit transaction. `POST /api/transfer/batch` — fan-out and consolidate. `GET /api/transfer/:id` — status, receipt, help. --- # Quotes Source: https://trenchytools-docs-production.up.railway.app/docs/wallets/routes Everything available for a pair and amount right now: direct, best-rate exchange, fixed, private — with receive amount, fee, minimum and ETA. Call this before creating a transfer. The exchange minimum changes with the pair and the market; a create below it fails with `transfer_min_amount`. Source chain: `sol` or `rh`. Destination chain: `sol`, `rh`, `eth`, `bnb`. In the source chain's native unit. ```bash title="cURL" curl "https://api.trenchytools.lol/api/transfer/routes?from=sol&to=rh&amount=0.5&api-key=YOUR_API_KEY" ``` ```json title="Response" { "from": "sol", "to": "rh", "amount": 0.5, "routes": [ { "route": "exchange", "mode": "float", "venue": "auto", "receive": 0.02156, "fee": 0.000054, "networkFee": 0.00005, "etaS": 40, "min": 0.087, "max": 200300 }, { "route": "exchange", "mode": "fixed", "venue": "auto", "receive": 0.02145, "fee": 0.00255, "networkFee": 0.00005, "etaS": 40, "min": 0.087 }, { "route": "exchange", "mode": "float", "venue": "bybit", "status": "open", "receive": 0.02134, "fee": 0.00505, "etaS": 40, "min": 0.087, "note": "funds the destination from this exchange (breaks the wallet cluster); ~1 % extra" }, { "route": "exchange", "mode": "float", "venue": "htx", "status": "closed", "note": "switched off at the exchange right now" }, { "route": "exchange", "mode": "private", "venue": "auto", "receive": 0.02134, "fee": 0.00505, "networkFee": 0.00005, "etaS": 300, "min": 0.087 } ], "venues": ["auto", "random", "binance", "bybit", "kucoin", "htx", "mexc", "bitget", "gate"], "chains": { "sol": { "source": true, "destination": true }, "rh": { "source": true, "destination": true }, "eth": { "source": false, "destination": true }, "bnb": { "source": false, "destination": true } }, "exchange": "on" } ``` A same-chain pair also lists `{ "route": "direct", "fee": 0 }`. `exchange: "off"` means the server has no exchange route configured; `direct` still works. The per-venue entries are the break-wallet-cluster option: one line per exchange with its live `status`. Pass that `venue` to `POST /api/transfer`. --- # Create a transfer Source: https://trenchytools-docs-production.up.railway.app/docs/wallets/transfer Open a transfer and get the deposit address plus the unsigned deposit transaction from your wallet. One request: where from, where to, how much, which route and mode (see [Wallet transfers](/docs/wallets/overview) for what each means). The answer is a one-time deposit address and an unsigned deposit transaction from `from.wallet`; sign it, send it, then [track it](/docs/wallets/status). Exchange routing reduces on-chain linkability between the two wallets; it is **not** anonymity, and the exchange route applies its own policies. `mode: "private"` adds a privacy-coin leg (slower, ~1 %). Never describe this to users as untraceable. ## Create a transfer `{ chain, wallet }` — the wallet that will sign the deposit. `sol` or `rh`. `{ chain, address }` — where the coins end up. Any supported chain; validated for that chain. In the source chain's native coin (SOL on `sol`, ETH on `rh`). `auto` (default: exchange when enabled), `direct` (same chain, one signed transfer), `exchange`. `float` (default, market rate, ~0.1–0.4 %), `fixed` (locked output, 0.8 %, deposit within ~15 min), `private` (privacy-coin leg, 1 %, 5+ min). `auto` (best execution, default), `random` (an open venue rolled per transfer), or a named exchange (`bybit`, `kucoin`, `htx`, `mexc`, `bitget`, `gate`, `binance`) to force who pays the destination — the break-wallet-cluster option. Closed venues are refused (`transfer_route_off`); the answer says `venueHonoured`. Where a failed order is refunded. Default: `from.wallet`. ```javascript const t = await fetch(`${BASE}/api/transfer?api-key=${API_KEY}`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ from: { chain: 'sol', wallet: wallet.publicKey.toBase58() }, to: { chain: 'sol', address: 'DEST…' }, amount: 0.5, mode: 'float', venue: 'auto' }), }).then((r) => r.json()) // t.deposit.address is a one-time address for this transfer; t.transaction is the unsigned deposit from your wallet const tx = VersionedTransaction.deserialize(Buffer.from(t.transaction.transaction, 'base64')) tx.sign([wallet]) await fetch(`${BASE}/api/sol/send?api-key=${API_KEY}`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ transaction: Buffer.from(tx.serialize()).toString('base64') }) }) // then poll t.poll until status is "completed" (payoutHash) or a final failure ``` ```bash curl -X POST "https://api.trenchytools.lol/api/transfer?api-key=YOUR_API_KEY" -H "content-type: application/json" \ -d '{"from":{"chain":"sol","wallet":"YOUR_WALLET"},"to":{"chain":"rh","address":"0xDEST"},"amount":0.5,"mode":"float"}' ``` ```json title="Response (202)" { "transferId": "k9f3…", "status": "awaiting_deposit", "route": "exchange", "mode": "float", "venue": "binance", "from": { "chain": "sol", "wallet": "…" }, "to": { "chain": "rh", "address": "0x…" }, "amount": 0.5, "deposit": { "chain": "sol", "address": "", "amount": 0.5, "deadline": "2026-10-22T23:40:00Z" }, "transaction": { "chain": "sol", "encoding": "base64", "transaction": "" }, "poll": "/api/transfer/k9f3…" } ``` On Robinhood chain the deposit is `transaction.evm` (`{chainId, from, to, value, gas}`): sign and send it with viem like any `trade-local` transaction. A `direct` transfer answers `200` with the same shape and no `deposit` deadline. --- # Many wallets Source: https://trenchytools-docs-production.up.railway.app/docs/wallets/batch Fan one wallet out to many, or sweep many wallets back into one — one order and one unsigned deposit per leg. The same transfer, repeated per leg, in one call. Legs are independent: a leg that fails (minimum, venue off, budget) is reported inline and the others proceed. Up to 25 legs. ## Fan-out: one source, many destinations ```javascript title="JavaScript" const r = await fetch(`${BASE}/api/transfer/batch?api-key=${API_KEY}`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ from: { chain: 'sol', wallet: funding.publicKey.toBase58() }, to: wallets.map((w) => ({ chain: 'sol', address: w.publicKey.toBase58(), amount: 0.3 })), mode: 'float', venue: 'random', // a venue per leg: the wallets are not all paid by the same exchange }), }).then((r) => r.json()) // r.legs[i].transaction is the unsigned deposit for leg i: sign each with the funding wallet and send for (const leg of r.legs) if (!leg.error) { /* sign leg.transaction.transaction, POST /api/sol/send, remember leg.transferId */ } ``` ## Consolidate: many sources, one destination ```json title="Request" { "from": [ { "chain": "sol", "wallet": "WALLET_1", "amount": 0.25 }, { "chain": "sol", "wallet": "WALLET_2", "amount": 0.25 } ], "to": { "chain": "sol", "address": "TREASURY" }, "mode": "float", "venue": "auto" } ``` Each source gets its own order and its own unsigned deposit (signed by that wallet). `route: "direct"` makes every leg a plain transfer instead. ```json title="Response (202)" { "batchId": "b_m2x…", "legs": [ { "transferId": "k9f3…", "status": "awaiting_deposit", "venue": "binance", "deposit": { "chain": "sol", "address": "…", "amount": 0.3 }, "transaction": { "chain": "sol", "encoding": "base64", "transaction": "…" }, "poll": "/api/transfer/k9f3…" }, { "error": "the amount is below the exchange minimum for this pair", "code": "transfer_min_amount", "leg": { "to": { "address": "…" }, "amount": 0.01 } } ] } ``` Keep the batch within the budget: ~10 exchange orders a minute shared by every key. A 25-leg fan-out takes two to three minutes of orders; legs refused with `transfer_busy` can be re-sent. --- # Track and support Source: https://trenchytools-docs-production.up.railway.app/docs/wallets/status Where a transfer is, its receipt page, and what to do when one fails or stalls. | status | Meaning | | --- | --- | | `awaiting_deposit` | Order open; waiting for your signed deposit to confirm. | | `exchanging` | Deposit seen (`depositHash`); the exchange is executing. | | `completed` | Paid out: `payoutHash` on the destination chain, `expectedReceive` final. | | `failed` / `expired` / `refunded` / `cancelled` | Terminal. `reason` carries the exchange's wording; a refund goes to `refundAddress` (your wallet by default). | | `awaiting_send` → `sent` | Direct transfers: tell us the signature with `POST /api/transfer/:id/sent {hash}`. | ```json title="Response" { "transferId": "k9f3…", "status": "exchanging", "route": "exchange", "mode": "float", "venue": "binance", "from": { "chain": "sol", "wallet": "…" }, "to": { "chain": "rh", "address": "0x…" }, "amount": 0.5, "expectedReceive": 0.02156, "deposit": { "chain": "sol", "address": "…" }, "depositHash": "5Kx…", "payoutHash": null, "orderId": "…", "receipt": "https://…/normal-exchange/…", "createdAt": 1792700000000, "updatedAt": 1792700300000 } ``` ## If it fails or stalls When the status is terminal, or the order has not completed 30 minutes after the deposit confirmed, the answer adds `help`: what happened, what to do, our support ([t.me/trenchytools](https://t.me/trenchytools)) and the exchange route's own support (Telegram bot and email), with the exact details to include — `orderId`, `depositHash`, the deposit address, the time, the destination. The provider's name appears only here and in `receipt`. ```json title="help" { "orderId": "…", "receipt": "https://…", "why": "the deposit confirmed more than 30 minutes ago and the order has not completed", "whatToDo": "In rare cases an order needs a manual nudge at the exchange route. Open the receipt page first; if it shows no progress, contact support with the details below.", "support": { "trenchytools": "https://t.me/trenchytools", "exchangeRoute": { "telegram": "https://t.me/HusherOfficialBot", "email": "support@husher.io" }, "include": ["this orderId", "your deposit transaction hash (depositHash)", "the deposit address", "the approximate time", "the destination address"] }, "warning": "Never send funds, private keys or seed phrases to anyone claiming to be support." } ``` `GET /api/transfer` lists your last 50 transfers. --- # Wallet backups Source: https://trenchytools-docs-production.up.railway.app/docs/wallets/backups The rule every app on this API follows: a wallet is written to disk, in a place you can find, before it holds anything. The API never sees your keys, which means it can never give one back. Bots create wallets constantly — funding wallets, bundle wallets, per-coin wallets, vanity mints — and the most common way money is lost is a key that only ever existed in memory, in a log line, or in a terminal that was closed. So this is a rule, enforced in [AGENTS.md](/docs/build-with-ai) and in every prompt we publish, not a tip. **Before a wallet is funded, its secret is on disk, and the path has been printed.** An app that cannot show where a key is saved must not send to that wallet. ## The pattern `wallets/