build on psst.
A free, open JSON API with everything psst knows: circles filling, live coins, every member, every delivery, every payday and every take home send. No key, no sign up. Every request below is live, so press Send and you get real data.
- Base
- /api/v1
- JSON over HTTPS
- Methods
- GET
- read only
- Key
- none
- CORS open
- Times
- unix ms
- header x-psst-api: 1
basics.
https://psstprivacy.xyz/api/v1x-psst-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://psstprivacy.xyz/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), every payday with the goal 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://psstprivacy.xyz/api/v1/coins/coin%20id"
look up a mint
cached 3s/api/v1/coins/mint/{mint}Is this token a psst coin? Returns the full coin with isPsst: true, or a 404 with isPsst: false. Made for terminals and bots that see a token address first.
Returns{ isPsst: true, ...Coin with detail lists } or 404 { error, isPsst: false }
/api/v1/coins/mint/token%20mintcurl -s "https://psstprivacy.xyz/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://psstprivacy.xyz/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://psstprivacy.xyz/api/v1/leaderboard"
stats
cached 15s/api/v1/statsTotals across psst: 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://psstprivacy.xyz/api/v1/stats"
rules
cached 5m/api/v1/rulesThe constants every coin runs on (spots, spot price, payday goal limits, fees, payout thresholds, pay coins, curve) and the LaunchLab program and psst platform addresses. Read from the same file the server enforces.
ReturnsSee the rules object below.
/api/v1/rulescurl -s "https://psstprivacy.xyz/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; setting the address needs a wallet signature on the take home page, so this API never changes anything.
Returns{ wallet, to (Zcash address or null), since, coins: [{ id, ticker, waitingSol, carriedSol, sent: [{ at, sol, zecOut, tx, to, status }] }] }
/api/homecurl -s "https://psstprivacy.xyz/api/home"
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 payday goals and how close it is to each. See payday goals below. |
| starterLock | object | null | { days, totalTokens, releasedTokens } when the starter locked their tokens. |
| market | object | null | Live LaunchLab curve: priceSol, marketCapSol, raisedSol, goalSol, progress (0 to 1), graduated. |
payday goals.
Every coin carries goals. A payday runs when the coin reaches its fees goal or its next market cap milestone, whichever comes first.
| Field | Type | Meaning |
|---|---|---|
| feeGoalSol | number | Fees goal. A payday runs each time the coin has collected this much SOL in trading fees. Repeats. |
| 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. Each milestone pays once. |
| feesCollectedSol | number | null | Fees collected toward the fees goal at the last check (unclaimed creator fee plus anything held over). Null before the first check. |
| marketCapUsd | number | null | Market cap in USD at the last check. Null before the first check or when the price couldn't be read. |
| checkedAt | unix ms | null | When the goals were last read from the chain. Live coins are checked every 60 seconds. |
| milestonesReached[] | array | { at, usd, marketCapUsd }: each milestone reached, when, and the market cap at the time. |
The starter picks the goals when starting the coin, within the limits in paydayGoals on /rules, and they are locked at start. Coins started before goals existed report the defaults. A quiet coin can take a long time to reach its fees goal, so read feesCollectedSol and marketCapUsd 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://psstprivacy.xyz/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 psst coins in a terminal or bot
async function psstInfo(mint) {
const r = await fetch(`https://psstprivacy.xyz/api/v1/coins/mint/${mint}`);
if (r.status === 404) return null; // not a psst 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 psst 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.
// Every payday of a coin, the goal that set it off, and its transactions
const c = await fetch("https://psstprivacy.xyz/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}` : p.reason === "fees" ? "fees goal" : "before goals";
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
const { ticker, goals: g } = await fetch("https://psstprivacy.xyz/api/v1/coins/{id}").then((r) => r.json());
const fees = g.feesCollectedSol == null ? "not checked yet" : `${g.feesCollectedSol} of ${g.feeGoalSol} SOL`;
const mcap = g.marketCapUsd == null ? "unknown" : `$${g.marketCapUsd} of $${g.nextMcapUsd}`;
console.log(`$${ticker}: fees ${fees}, market cap ${mcap} (step x${g.mcapStep}), whichever comes first`);errors and limits.
{ "error": "..." } with status 400 (bad input), 404 (not found) or 500.