build on visionary.
A free, open JSON API with everything visionary knows, and everything a wallet can do: start a coin, take a spot, buy and sell, set take home. Write calls hand back an unsigned transaction for your own wallet to sign, so visionary never sees a key. No API key, no sign up. Every read below is live, so press Send and you get real data.
- Base
- /api/v1
- JSON over HTTPS
- Methods
- GET, POST
- read and build
- Key
- none
- CORS open
- Times
- unix ms
- header x-visionary-api: 1
basics.
https://usevisionary.fun/api/v1x-visionary-api: 1.endpoints, live.
Ids, mints and wallets are prefilled from the live API, so every Send works as is.
list coins
cached 5s/api/v1/coinsEvery coin, newest first. Filter by status to watch circles filling or coins going live. Drafts that never paid the start fee aren't listed.
Returns{ coins: Coin[], count, updatedAt }
/api/v1/coinscurl -s "https://usevisionary.fun/api/v1/coins"
get a coin
cached 3s/api/v1/coins/{id}One coin with every detail list: the circle (every wallet, what it paid, accepted, refunded, tokens, delivery tx, linked), each payday with the milestone that set it off and its claim, swap and transfer transactions, every take home send, every burn, every payment and the top 50 holders.
ReturnsCoin plus buyers, linkedPairs, paydays, takeHome, burns, joins, holderList
/api/v1/coins/coin%20idcurl -s "https://usevisionary.fun/api/v1/coins/coin%20id"
look up a mint
cached 3s/api/v1/coins/mint/{mint}Is this token a visionary coin? Returns the full coin with isVisionary: true, or a 404 with isVisionary: false. Made for terminals and bots that see a token address first.
Returns{ isVisionary: true, ...Coin with detail lists } or 404 { error, isVisionary: false }
/api/v1/coins/mint/token%20mintcurl -s "https://usevisionary.fun/api/v1/coins/mint/token%20mint"
look up a wallet
cached 10s/api/v1/wallets/{address}Every coin a wallet started, joined or holds: what it put in, what was accepted and refunded, its tokens, whether it held at the last payday, its hold streak and its starter lock, next to each coin's totals. Unknown wallets come back with empty lists, not a 404.
Returns{ wallet, totals: { coinsStarted, coinsJoined, solIn, solAccepted, solRefunded }, coins: [...], updatedAt }
/api/v1/wallets/wallet%20addresscurl -s "https://usevisionary.fun/api/v1/wallets/wallet%20address"
leaderboard
cached 30s/api/v1/leaderboardThree lists of up to 20 rows: live coins ranked by fees returned (paid to holders plus bought back and burned), the biggest circles, and the starters with the most coins live.
/api/v1/leaderboardcurl -s "https://usevisionary.fun/api/v1/leaderboard"
stats
cached 15s/api/v1/statsTotals across visionary: coins by status, SOL that went into live coins' pots, wallets that bought in at go live, and creator fees paid to holders.
/api/v1/statscurl -s "https://usevisionary.fun/api/v1/stats"
rules
cached 5m/api/v1/rulesThe constants every coin runs on (spots, spot price, payday milestone limits, fees, payout thresholds, pay coins, curve) and the Meteora program and visionary config addresses. Read from the same file the server enforces.
ReturnsSee the rules object below.
/api/v1/rulescurl -s "https://usevisionary.fun/api/v1/rules"
take home, read only
cached never/api/homeWhere a wallet's Zcash payouts go and what is waiting for it on every Zcash coin. Same origin, not versioned and not cached. To set the address from code, use the take home endpoints under launch and trade.
Returns{ wallet, to (Zcash address or null), since, coins: [{ id, ticker, waitingSol, carriedSol, sent: [{ at, sol, zecOut, tx, to, status }] }] }
/api/homecurl -s "https://usevisionary.fun/api/home"
launch and trade.
Everything the site does with a wallet, over HTTP. Build, sign locally, send. Same rules and limits as the start page.
| Endpoint | Body | Returns |
|---|---|---|
| POST | starter, name, ticker, description?, image (data URL or https URL), start (instant | circle), payCoin (zec | xmr), feeMode?, mcapGoalUsd?, mcapStep?, openingBuySol? (instant, 0 to 0.5), spotPriceSol (circle), takeSpot? (circle), starterLock?, scheduledFor? (circle, unix ms), links? { website, twitter, telegram, tweet }, priorityMicroLamports? | 201 { id, pot, amountSol, breakdown { startFeeSol, buySol, deliverySol }, transaction, lastValidBlockHeight }. The starter signs transaction (it pays the pot). |
| POST | signedTransaction (we send it) or signature (you sent it) | { signature, coin }. Instant coins come back live with their mint; circles come back open (or scheduled). |
| POST | wallet, priorityMicroLamports? | { amountSol, breakdown { spotSol, deliverySol }, transaction }: one spot in an open circle, one per wallet. |
| POST | signedTransaction or signature | { signature, seated, rejected, departing, status, mint }. rejected says why (linked, late, full); refused payments are refunded. |
| POST | wallet, coin (id) or mint, side (buy | sell), amount (buy: SOL; sell: tokens or a percent like "100%"), slippageBps? (default 300), priorityMicroLamports? | { venue (curve | damm_v2), amountIn, expectedOut, minimumOut, outUnit, transaction }: a swap on the coin's Meteora curve, or its DAMM v2 pool after graduation. |
| POST | signedTransaction (base64 or base58, legacy or v0) | { signature, landed: true } once it's confirmed (up to about 45 s), or 422 with the chain's error. |
| GET | to: a Zcash address (leave it out to switch take home off) | { to, since, sign { to, time, message, validForSeconds } }: the exact message the wallet signs. |
| POST | to, time, signature (base58 ed25519 over sign.message) | { wallet, to }. Only the wallet's own signature changes where its Zcash payouts go. Nothing moves funds. |
Flow: call a build endpoint, sign the returned transaction (base64, legacy) with the wallet it names as fee payer, then either pass signedTransaction to the confirm step (we send it and wait) or send it through your own RPC and pass its signature. A transaction is good for about a minute (lastValidBlockHeight); build a fresh one if it expires. Trades go straight to Meteora, so a coin trades the same here as on Jupiter or any terminal.
launch and trade, code.
Node with @solana/web3.js. The same calls work from Python, Rust or a browser wallet.
// Launch an instant coin from a script. You sign locally; visionary never sees your key.
import { Keypair, Transaction } from "@solana/web3.js";
const wallet = Keypair.fromSecretKey(/* your key */);
const api = (path, body) => fetch("https://usevisionary.fun" + path, {
method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body),
}).then((r) => r.json());
const sign = (b64) => { const tx = Transaction.from(Buffer.from(b64, "base64")); tx.partialSign(wallet); return tx.serialize().toString("base64"); };
const draft = await api("/api/v1/coins", {
starter: wallet.publicKey.toBase58(),
name: "hush", ticker: "HUSH", description: "a quiet coin",
image: "https://example.com/hush.png", // or a data URL
start: "instant", payCoin: "zec",
openingBuySol: 0.1, mcapGoalUsd: 25000, mcapStep: 2,
});
if (draft.error) throw new Error(draft.error);
const { coin } = await api(`/api/v1/coins/${draft.id}/start`, { signedTransaction: sign(draft.transaction) });
console.log("live:", coin.url, "mint", coin.mint);// Buy 0.5 SOL of a coin, then sell all of it (same api and sign helpers as above)
const buy = await api("/api/v1/trade", { wallet: wallet.publicKey.toBase58(), coin: "{id}", side: "buy", amount: 0.5, slippageBps: 300 });
console.log(buy.venue, "expect", buy.expectedOut, "tokens, at least", buy.minimumOut);
console.log(await api("/api/v1/send", { signedTransaction: sign(buy.transaction) }));
const sell = await api("/api/v1/trade", { wallet: wallet.publicKey.toBase58(), coin: "{id}", side: "sell", amount: "100%" });
console.log(await api("/api/v1/send", { signedTransaction: sign(sell.transaction) }));// Take a spot in an open circle
const spot = await api(`/api/v1/coins/${id}/spot`, { wallet: wallet.publicKey.toBase58() });
const r = await api(`/api/v1/coins/${id}/spot/confirm`, { signedTransaction: sign(spot.transaction) });
console.log(r.seated ? "in" : `refused: ${r.rejected}`, r.departing ? "(that was the last spot, going live)" : "");// Point a wallet's Zcash payouts at a Zcash address (one signed message, no funds move)
import nacl from "tweetnacl"; import bs58 from "bs58";
const me = wallet.publicKey.toBase58();
const { sign: s } = await fetch(`https://usevisionary.fun/api/v1/wallets/${me}/take-home?to=${zcashAddress}`).then((r) => r.json());
const signature = bs58.encode(nacl.sign.detached(new TextEncoder().encode(s.message), wallet.secretKey));
console.log(await api(`/api/v1/wallets/${me}/take-home`, { to: s.to, time: s.time, signature }));the coin object.
What /coins returns per coin. Single coin and mint lookups add the detail lists below.
| Field | Type | Meaning |
|---|---|---|
| id, url | string | Coin id and its coin page. |
| name, ticker, description | string | As set by the starter. Ticker is uppercase, 2 to 10 characters. |
| image | string | Absolute URL to the coin image. |
| links | object | website, twitter, telegram and tweet, each a URL or null. |
| status | string | See the lifecycle below. |
| starter | address | Wallet that started the coin. |
| pot | address | The coin's pot address. Circle payments go here, it creates the pool on chain, claims the fee, pays holders and keeps the burn vault. |
| mint, pool | address | null | Null until the coin goes live. The mint is never revealed early. |
| createdAt, opensAt, closesAt, launchedAt, scheduledFor | unix ms | null | Drafted, circle opened, circle deadline, went live, and the requested start of a scheduled coin. |
| start | string | circle or instant. |
| spotPriceSol | number | null | SOL per spot. Null on instant coins. |
| spotsTaken, spotsTotal | number | null | Spots taken out of 20. Null on instant coins. |
| potSol | number | SOL in the pot. Live while the circle fills, then the amount that bought. |
| wallets | number | Wallets in the pot (the circle, or the starter on an instant coin). |
| entryPriceSol | number | null | SOL per token everyone in the pot paid. |
| tokensBought | string | null | Raw token amount the pot bought (6 decimals). |
| launchTx | signature | null | The block zero transaction that created the pool and bought. |
| failReason, lookalikeOf | string | null | Why a coin refunded; the ticker of an earlier coin this one looks like. |
| feeMode | string | holders, burn or split. |
| payCoin | object | { key, symbol, name, mint, decimals, takeHome }: zec or xmr, its SPL mint on Solana, and whether take home is possible. |
| paidCoin | string | Raw pay coin units that reached holders, all paydays (use payCoin.decimals). |
| feesPaidSol | number | Creator fee SOL routed to holders across all paydays (swapped, sent home or carried). |
| carriedSol | number | SOL waiting in the pot for holders whose shares were too small to send yet. |
| takeHomeWaitingSol, takeHomeSentSol | number | Take home SOL still collecting, and SOL already sent through NEAR Intents. |
| holders | number | null | Wallets holding the coin at the last payday. |
| burnVaultSol, burnSavedTargetSol | number | SOL saved toward the next burn, and the burn target. |
| burnedSol, burnedTokens | number, string | SOL spent on buybacks, and raw tokens burned. |
| goals | object | The coin's market cap milestones and how close it is to the next one. See payday milestones below. |
| starterLock | object | null | { until: "bond", totalTokens, releasedTokens, releaseSig } when the starter locked their tokens until the coin bonds. releasedTokens equals totalTokens once it bonded. |
| market | object | null | Live Meteora curve (or its DAMM v2 pool after graduation): priceSol, marketCapSol, raisedSol, goalSol, progress (0 to 1), graduated. |
payday milestones.
Every coin carries goals: its market cap milestones. A payday runs each time the market cap reaches the next milestone, and at no other time.
| Field | Type | Meaning |
|---|---|---|
| firstMcapUsd, mcapStep | number | First market cap milestone in USD, and the step: each milestone is the last one times this (1.5, 2 or 3). |
| nextMcapUsd | number | The next milestone still to reach. A payday runs when marketCapUsd reaches it. Each milestone pays once. |
| marketCapUsd | number | null | Market cap in USD at the last check. Null before the first check or when the price couldn't be read. |
| feesCollectedSol | number | null | Fee waiting for the next milestone at the last check (unclaimed creator fee plus anything held over). Paid out when the milestone is reached. Null before the first check. |
| checkedAt | unix ms | null | When the market cap was last read from the chain. Live coins are checked once per 60 seconds. |
| milestonesReached[] | array | { at, usd, marketCapUsd }: each milestone reached, when, and the market cap at the time. |
The starter picks the first milestone and the step when starting the coin, within the limits in paydayGoals on /rules, and both are locked at start. Coins started before milestones existed report the defaults. If the market cap never reaches nextMcapUsd there is no payday and the fee keeps waiting on Meteora, so read marketCapUsd against nextMcapUsd as progress, not as a time.
detail lists.
Only on /coins/{id} and /coins/mint/{mint}.
status lifecycle.
scheduled then open then settling then launched, or refunded. A circle goes live the moment all 20 spots are taken; read spotsTaken, spotsTotal and spotPriceSol on each coin.
the rules object.
What /rules returns. The same numbers as the rules page.
recipes.
// Alert on every circle filling (poll every 10s)
const seen = new Map();
setInterval(async () => {
const { coins } = await fetch("https://usevisionary.fun/api/v1/coins?status=open").then((r) => r.json());
for (const c of coins) {
if (seen.get(c.id) === c.spotsTaken) continue;
seen.set(c.id, c.spotsTaken);
console.log(`$${c.ticker}: ${c.spotsTaken}/${c.spotsTotal} spots at ${c.spotPriceSol} SOL, pays ${c.payCoin.symbol} ${c.url}`);
}
}, 10_000);// Label visionary coins in a terminal or bot
async function psstInfo(mint) {
const r = await fetch(`https://usevisionary.fun/api/v1/coins/mint/${mint}`);
if (r.status === 404) return null; // not a visionary coin
const c = await r.json();
return {
devIsPot: c.pot, // the "dev" wallet is the pot, not a person
circle: c.buyers.length, // the wallets terminals call bundle or insiders
linked: c.buyers.filter((w) => w.linked).length,
entryPriceSol: c.entryPriceSol,
paysIn: c.payCoin.symbol, // ZEC or XMR
holders: c.holders,
};
}Why this matters: on a visionary coin the creator wallet is the pot, and its block zero buy is the whole circle buying together. The guide explains how that reads on terminals.
// Each payday of a coin, the milestone that set it off, and its transactions
const c = await fetch("https://usevisionary.fun/api/v1/coins/{id}").then((r) => r.json());
const d = 10 ** c.payCoin.decimals;
for (const p of c.paydays) {
const why = p.reason === "mcap" ? `market cap hit $${p.milestoneUsd}` : "payday"; // older rows: "fees" or null
console.log(new Date(p.at).toISOString(), why, p.sol, "SOL claimed,",
Number(p.coinSent ?? 0) / d, c.payCoin.symbol, "to", p.recipients, "holders,",
p.carriedSol, "SOL carried, claim", p.claimTx, "swap", p.swapTx, "transfers", p.payTxs);
}// How close a coin is to its next payday: market cap against the next milestone
const { ticker, goals: g } = await fetch("https://usevisionary.fun/api/v1/coins/{id}").then((r) => r.json());
if (g.marketCapUsd == null) console.log(`$${ticker}: market cap not checked yet`);
else {
const pct = Math.min(100, Math.round((g.marketCapUsd / g.nextMcapUsd) * 100));
console.log(`$${ticker}: $${g.marketCapUsd} of $${g.nextMcapUsd} (${pct}%), then x${g.mcapStep}`);
}errors and limits.
{ "error": "..." } with status 400 (bad input), 404 (not found), 409 (wrong state, like a full circle), 422 (a transaction failed on chain), 429 (slow down) or 500.