Developers · API v1

Build on Piconero

Read every Piconero coin and build its transactions over HTTP. Put them in a bot, a wallet, a dashboard or your own trading front end, without learning Meteora's SDKs. Each coin has 18,446,744.073709551 supply (Monero's M), trades against wXMR on a Meteora bonding curve shaped like Monero's emission, and graduates to a Meteora DAMM v2 pool.

  • No API key. JSON over HTTPS, open to every origin (CORS).
  • Your users keep their keys. Trades and launches come back as unsigned transactions; the user's wallet signs and sends them.
  • Curve or pool, handled. Buys and sells route to the bonding curve or, after graduation, the DAMM v2 pool. Buys can pay in SOL.
  • Live events. One stream for new coins, era changes, graduations and burns.
Base URLhttps://piconero.fun/api/v1
NetworkSolana: real wXMR is at stake
OpenAPI/api/v1/openapi.json
StatusThe v1 contract is stable; the service has no uptime guarantee.

Start in three calls

Find a coin, quote it, sign the buy.

1. Find a coin

curl "https://piconero.fun/api/v1/coins?sort=progress&graduated=false&limit=5"

2. Quote it

curl "https://piconero.fun/api/v1/quote?mint=<mint>&side=buy&amount=0.01"

3. Build the transaction, sign it in the wallet, send it

TypeScript · @solana/web3.js + wallet adapter
import { Transaction, VersionedTransaction } from "@solana/web3.js";

const res = await fetch("https://piconero.fun/api/v1/tx/buy", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ wallet: wallet.publicKey.toBase58(), mint, xmr: 0.01, slippageBps: 200 }),
}).then((r) => r.json());
if (res.error) throw new Error(res.error);

const bytes = Uint8Array.from(atob(res.transaction), (c) => c.charCodeAt(0));
const tx = res.version === 0 ? VersionedTransaction.deserialize(bytes) : Transaction.from(bytes);
const signature = await wallet.sendTransaction(tx, connection);

Learn the concepts

Units

QuantityUnit in the APIOn chain
XMR amountsXMR (wXMR), a decimal number12 decimals (1 XMR = 10^12 atoms, piconero)
Ledger amounts (…Sats fields)Quote atoms (piconero), an integer÷ 10^12 for XMR
Coin amountsWhole coins, a decimal number9 decimals, 18,446,744.073709551 supply per coin
PricesXMR per coin (priceXmr); the site shows µXMR (× 10^6)Read from the pool's sqrt price
Fully diluted valueXMR (fdvXmr)priceXmr × 18,446,744.073709551
Market capXMR (mcapXmr)priceXmr × coins in circulation (coinsSold until graduation)
TimesUnix seconds (event timestamps at: Unix ms)—

Numbers are JSON floats, fine for display and quotes. The transactions themselves use exact integer amounts, and out.min is what the chain enforces.

A coin's life

  1. Launch. Every coin launches on one curve: standard (Monero curve, 13 XMR), so tier is optional. Supply, eras and fees are the same for every coin. The creator picks a mode, which decides where the creator share (60% of every fee) goes: creator (to the creator, claimable in wXMR), stealth (Stealth payout: paid out as native XMR to a Monero address bound at launch, in payouts of 0.1 XMR or more, less the bridge's 0.1%), burn (Tail burn: it buys the coin back and burns it).
  2. Binding a Stealth payout address. A stealth launch carries exactly one Memo v2 instruction with the text moneropad xmr payout: v1 <address>, listing the creator (the pool creator and fee payer) as a signer key, in the pool-creation transaction. tx/launch with xmrAddress adds it for you. The keeper reads it back from the creation transaction; no memo, two memos, an address for another network or a memo the creator didn't sign leave the coin unbound, and its creator share goes to the platform. The address can never be changed.
  3. Anti-snipe. On the current configs the fee starts high and drops each second after launch (49.99% / 33.66% / 17.33% / 1%); feeBpsNow on a coin and feeBps on a quote show the live value. The bundled firstBuyXmr in tx/launch pays 1%.
  4. Bonding curve, 16 eras. Emission 1 to Emission 15, then the Tail. Each emission segment raises the same XMR and sells a constant factor fewer coins than the last, so the price rises smoothly (16× from the first coin to graduation); the tail is near-flat. Entering the next era moves era.index up and fires a coin.era event. Each trade pays a 1% fee in wXMR.
  5. Graduation. When xmrRaised reaches graduationXmr, the coin moves to a Meteora DAMM v2 pool (migrated: true, dammPool set, a coin.graduated event). Trading continues there; the API routes to it automatically and quotes show venue: "dammV2".

Which network

This deployment serves Solana. Every response carries an X-Cluster header (mainnet-beta), and GET /api/v1 returns cluster. Check it before asking a user to sign, and send the transaction to an RPC on the same network.

Sign transactions

  • transaction is base64. Decode it, then Transaction.from(bytes) when version is "legacy", or VersionedTransaction.deserialize(bytes) when it is 0 (buys paid in SOL).
  • The fee payer is wallet. Nothing is signed on our side. Launches also need the new mint keypair's signature (see the launch recipe).
  • The transaction has a recent blockhash: sign and send within about 60 seconds, or build a new one.
  • Slippage protection is on chain: if the price moves past slippageBps, the transaction fails and nothing is spent but the network fee.
  • Simulate before sending if you want an early error (insufficient wXMR, for example); wallets usually do this for you.

Handle errors and limits

Errors are JSON: { "error": "slippageBps: an integer from 0 to 5000" }. The message says what to fix.

StatusMeaning
400Bad input: a parameter is missing or invalid.
404Not a Piconero coin on this network.
409Launch: that mint already exists.
413 / 415Metadata: the image is too big, or not PNG, JPG or GIF.
429Rate limited. retryAfterSecs says when to retry.
502A chain read or route failed upstream. Safe to retry.
503Not deployed on this network yet, or the event stream is full.

Limits per IP address:

BucketLimitEndpoints
read120 per 1 min/, /coins, /coins/{mint}, /curves, /burns, /xmr-usd, /coins/{mint}/payouts
quote60 per 1 min/quote, /xmr-address/check
tx30 per 1 min/tx/buy, /tx/sell
claimPrepare10 per 1 min
claimSubmit5 per 1 min
launch5 per 10 min/tx/launch
metadata10 per 10 min/metadata
stream10 per 1 min/events

Need more? Cache the read endpoints (their Cache-Control headers say for how long) and use the event stream instead of polling.

API reference

Market

Get the API index

GET/api/v1

The network this deployment serves, the curve (one tier) with its DBC config per launch mode, the anti-snipe schedule, the eras, the holder-claim, Stealth payout and Mining constants, the wXMR quote mint, token rules, fees, program IDs, the keeper and treasury, and the endpoint list. Read it once at startup and check cluster.

Limit 120 reads per 1 min per IP · cached 1 min

Request
curl https://piconero.fun/api/v1
Response 200
{
  "name": "Piconero API",
  "version": "1.0",
  "cluster": "mainnet-beta",
  "deployed": true,
  "token": {
    "supply": 18446744.07370955,
    "decimals": 9,
    "mintAuthority": null,
    "freezeAuthority": null
  },
  "quote": {
    "mint": "<wXMR mint>",
    "decimals": 12
  },
  "tiers": [
    {
      "id": "standard",
      "name": "Monero curve",
      "graduationXmr": 13,
      "configs": {
        "creator": "<config>",
        "stealth": "<config>",
        "burn": "<config>",
        "mine": "<config>"
      }
    }
  ],
  "modes": [
    {
      "id": "creator",
      "name": "Creator"
    },
    {
      "id": "stealth",
      "name": "Stealth payout"
    },
    {
      "id": "burn",
      "name": "Tail burn"
    },
    {
      "id": "mine",
      "name": "Mining"
    }
  ],
  "antiSnipe": {
    "startFeeBps": 4999,
    "endFeeBps": 100,
    "periods": 3,
    "seconds": 3,
    "mode": "linear"
  },
  "eras": [
    {
      "index": 0,
      "name": "Emission 1"
    },
    {
      "index": 1,
      "name": "Emission 2"
    },
    "…",
    {
      "index": 15,
      "name": "Tail"
    }
  ],
  "fees": {
    "tradingFeeBps": 100,
    "protocolShareBps": 2000,
    "creatorShareBps": 7500,
    "buybackShareOfFees": 0.15,
    "treasuryShareOfFees": 0.05,
    "modes": {
      "creator": "…",
      "stealth": "…",
      "burn": "…",
      "mine": "…"
    }
  },
  "holders": {
    "distributor": "<address>",
    "shareOfPartnerBps": 7500,
    "shareOfLpBps": 8000,
    "minUsd": 10,
    "minSatsNow": 17006802721,
    "minClaimAtoms": 1000000000,
    "…": "…"
  },
  "stealthPayout": {
    "memo": "moneropad xmr payout: v1 <address>",
    "network": "<network>",
    "minAtoms": 100000000000,
    "bridgeFeeBps": 10,
    "…": "…"
  },
  "mining": {
    "memo": "<memo> v1 <dest> <rig>",
    "default": {
      "dest": "holders",
      "rig": "pool"
    },
    "…": "…"
  },
  "programs": {
    "dbc": "<program>",
    "dammV2": "<program>"
  },
  "keeper": "<address>",
  "treasury": "<address>",
  "nativeCoin": {
    "symbol": "<symbol>",
    "mint": "<mint>"
  },
  "endpoints": {
    "GET /api/v1/coins": "…"
  }
}

List coins

GET/api/v1/coins

Every coin with its live state and metadata. The list is refreshed every few seconds; page through it with limit and offset.

Limit 120 reads per 1 min per IP · cached 3 s

Query

sortstring
Newest first, largest market cap first (price × coins in circulation), largest fully diluted value first, closest to graduation first, or Mining coins by hashrate now.One of new, mcap, fdv, progress, hashrate.Default new.
graduatedboolean
true: only coins trading on DAMM v2. false: only coins still on the bonding curve.
tierstring
Only coins on this curve tier (there is one, so every coin matches).One of standard.
modestring
Only coins in this launch mode.One of creator, stealth, burn, mine.
limitinteger
Page size, 1 to 200.Default 50.
offsetinteger
Coins to skip.Default 0.
Request
curl "https://piconero.fun/api/v1/coins?sort=progress&graduated=false&limit=10"
Response 200
{
  "total": 42,
  "offset": 0,
  "limit": 10,
  "coins": [
    {
      "mint": "<mint>",
      "pool": "<dbc pool>",
      "config": "<config>",
      "tier": "standard",
      "mode": "creator",
      "legacy": false,
      "feeBpsNow": 100,
      "antiSnipeUntil": 1791103359,
      "creator": "<wallet>",
      "activatedAt": 1791103356,
      "priceXmr": 2.6e-7,
      "fdvXmr": 4.7962,
      "mcapXmr": 0.338,
      "xmrRaised": 0.33,
      "graduationXmr": 13,
      "progress": 0.0254,
      "era": {
        "index": 0,
        "name": "Emission 1",
        "progress": 0.514,
        "coinsToNextEra": 1160000.12
      },
      "coinsSold": 1300000.5,
      "migrated": false,
      "dammPool": null,
      "partnerFeeXmrUnclaimed": 0.00066,
      "tradingFeeXmrTotal": 0.0026,
      "creatorFeeXmrUnclaimed": 0.00198,
      "creatorSurplusPending": false,
      "meta": {
        "name": "Rock Cat",
        "symbol": "RCAT",
        "uri": "https://…/metadata.json",
        "image": "https://…/image.png",
        "description": "…",
        "socials": {
          "twitter": "https://x.com/…"
        }
      },
      "isNative": false
    },
    "…"
  ]
}
  • 400 A parameter is missing or invalid; error names it.

Get a coin

GET/api/v1/coins/{mint}

One coin's live state and metadata, the same object as in the list.

Limit 120 reads per 1 min per IP · cached 2 s

Path

mintstringrequired
The coin's mint address.
Request
curl https://piconero.fun/api/v1/coins/<mint>
Response 200
{
  "mint": "<mint>",
  "pool": "<dbc pool>",
  "config": "<config>",
  "tier": "standard",
  "mode": "creator",
  "legacy": false,
  "feeBpsNow": 100,
  "antiSnipeUntil": 1791103359,
  "creator": "<wallet>",
  "activatedAt": 1791103356,
  "priceXmr": 2.6e-7,
  "fdvXmr": 4.7962,
  "mcapXmr": 0.338,
  "xmrRaised": 0.33,
  "graduationXmr": 13,
  "progress": 0.0254,
  "era": {
    "index": 0,
    "name": "Emission 1",
    "progress": 0.514,
    "coinsToNextEra": 1160000.12
  },
  "coinsSold": 1300000.5,
  "migrated": false,
  "dammPool": null,
  "partnerFeeXmrUnclaimed": 0.00066,
  "tradingFeeXmrTotal": 0.0026,
  "creatorFeeXmrUnclaimed": 0.00198,
  "creatorSurplusPending": false,
  "meta": {
    "name": "Rock Cat",
    "symbol": "RCAT",
    "uri": "https://…/metadata.json",
    "image": "https://…/image.png",
    "description": "…",
    "socials": {
      "twitter": "https://x.com/…"
    }
  },
  "isNative": false
}
  • 400 A parameter is missing or invalid; error names it.
  • 404 The mint is not a coin on any of this network's Piconero configs.

Get the emission curve

GET/api/v1/curves

The curve every coin launches on, keyed by its tier id (one tier; every launch mode shares it): its 16 eras (15 emission segments and the tail) with their XMR raised, price range (XMR per coin) and coins sold, sampled points for charting (xmr: XMR per coin, raised: cumulative XMR), and the coins that go into the DAMM v2 pool at graduation. Curves are immutable on chain, so cache this as long as you like.

Limit 120 reads per 1 min per IP · cached 60 min

Request
curl https://piconero.fun/api/v1/curves
Response 200
{
  "standard": {
    "tier": "standard",
    "graduationXmr": 13,
    "eras": [
      {
        "index": 0,
        "name": "Emission 1",
        "fromRaised": 0,
        "toRaised": 0.642,
        "fromPrice": 2.367e-7,
        "toPrice": 2.833e-7,
        "coins": 2465000.41
      },
      {
        "index": 1,
        "name": "Emission 2",
        "fromRaised": 0.642,
        "toRaised": 1.284,
        "fromPrice": 2.833e-7,
        "toPrice": 3.391e-7,
        "coins": 2060000.7
      },
      "…"
    ],
    "points": [
      {
        "coins": 0,
        "xmr": 2.367e-7,
        "raised": 0,
        "era": 0
      },
      {
        "coins": 61500.2,
        "xmr": 2.377e-7,
        "raised": 0.01458,
        "era": 0
      },
      "…"
    ],
    "lpCoins": 3433000.78
  }
}

Get buyback & burn

GET/api/v1/burns

The native coin's circulating and burned supply (18,446,744.073709551 minus the mint's supply), the treasury's wXMR balance (treasury.btc, in XMR), and the keeper's buyback & burn transactions over its whole history, newest first, 10 per page (pages in all). txCount counts every burn transaction (historyComplete is false while older history is still being read). why is buyback or leftover (a graduated coin's unsold curve remainder). Pass next as before for the next page, which returns { burns, next }.

Limit 120 reads per 1 min per IP · cached 15 s

Query

beforestring
The next cursor from the previous page: returns the burns after that transaction as { burns, next }.
Request
curl https://piconero.fun/api/v1/burns
Response 200
{
  "nativeMint": "<mint>",
  "nativeSymbol": "<symbol>",
  "keeper": "<address>",
  "burnedCoins": 21955.54,
  "supplyCoins": 18424788.53,
  "treasury": {
    "address": "<address>",
    "btc": 0.0412
  },
  "txCount": 42,
  "historyComplete": true,
  "pages": 5,
  "burns": [
    {
      "signature": "<signature>",
      "time": 1791140807,
      "mint": "<mint>",
      "coins": 10.2039,
      "why": "buyback"
    },
    "…"
  ],
  "next": "<signature>"
}
  • 400 A parameter is missing or invalid; error names it.

Get XMR/USD

GET/api/v1/xmr-usd

The XMR/USD rate the site uses for dollar figures; null when every price source is down. Multiply an XMR amount by it, or priceXmr × usd for a coin's dollar price.

Limit 120 reads per 1 min per IP · cached 30 s

Request
curl https://piconero.fun/api/v1/xmr-usd
Response 200
{
  "usd": 588.12
}

Trading

Quote a trade

GET/api/v1/quote

What a buy or sell would return right now, without building a transaction. On the bonding curve it also previews the era after the trade: whether it crosses into the next era (emission segment or the tail), or completes the curve and graduates. That preview uses the XMR raised after the 1% fee; treat it as an estimate.

Limit 60 quotes per 1 min per IP · cached 2 s

Query

mintstringrequired
The coin.
sidestring
Buy coins, or sell coins for wXMR.One of buy, sell.Default buy.
amountnumberrequired
Buys: wXMR to spend (or SOL with in=sol). Sells: coins to sell.
instring
Buys only: pay in wXMR, or in SOL swapped to wXMR in the same transaction (btc is accepted as an alias of xmr).One of xmr, sol.Default xmr.
slippageBpsinteger
Sets out.min, 0 to 5000.Default 200.
Request
curl "https://piconero.fun/api/v1/quote?mint=<mint>&side=buy&amount=0.5"
Response 200
{
  "mint": "<mint>",
  "side": "buy",
  "in": {
    "asset": "xmr",
    "amount": 0.5
  },
  "out": {
    "asset": "coin",
    "expected": 1833300.12,
    "min": 1796634.12
  },
  "viaXmr": null,
  "slippageBps": 200,
  "spotPriceXmr": 2.6e-7,
  "avgPriceXmr": 2.727e-7,
  "priceImpact": 0.049,
  "venue": "curve",
  "feeBps": 100,
  "era": {
    "before": 0,
    "after": 1,
    "crossesEra": true,
    "graduates": false
  }
}
  • 400 A parameter is missing or invalid; error names it.
  • 404 The mint is not a coin on any of this network's Piconero configs.

Build a buy

POST/api/v1/tx/buy

An unsigned transaction that buys the coin for wallet. Send exactly one of xmr or sol (btc is accepted as an alias of xmr). With sol, one v0 transaction swaps SOL to wXMR and buys with the wXMR that swap guarantees; any extra wXMR stays in the wallet. Graduated coins are bought on their DAMM v2 pool.

Limit 30 buy / sell transactions per 1 min per IP · not cached

JSON body

walletstringrequired
The buyer; signs and pays fees.
mintstringrequired
The coin.
xmrnumber
wXMR to spend, in XMR (12 decimals).
solnumber
SOL to spend instead of wXMR.
slippageBpsinteger
Maximum slippage in basis points, 0 to 5000. 200 = 2%.Default 200.
Request
curl -X POST https://piconero.fun/api/v1/tx/buy -H "Content-Type: application/json" \
  -d '{"wallet":"<wallet>","mint":"<mint>","xmr":0.01,"slippageBps":200}'
Response 200
{
  "transaction": "<base64>",
  "version": "legacy",
  "mint": "<mint>",
  "wallet": "<wallet>",
  "in": {
    "asset": "xmr",
    "amount": 0.01
  },
  "expectedCoins": 38076.92,
  "minCoins": 37315.38,
  "note": "Sign with the wallet and send within ~60 s (the blockhash expires)."
}
  • 400 A parameter is missing or invalid; error names it.
  • 404 The mint is not a coin on any of this network's Piconero configs.
  • 502 The chain read or the SOL route failed (for SOL buys: try a different amount, or pay in wXMR).

Build a sell

POST/api/v1/tx/sell

An unsigned transaction that sells coins from wallet for wXMR, on the bonding curve or the DAMM v2 pool.

Limit 30 buy / sell transactions per 1 min per IP · not cached

JSON body

walletstringrequired
The seller; signs and pays fees.
mintstringrequired
The coin.
coinsnumberrequired
Coins to sell.
slippageBpsinteger
Maximum slippage in basis points, 0 to 5000. 200 = 2%.Default 200.
Request
curl -X POST https://piconero.fun/api/v1/tx/sell -H "Content-Type: application/json" \
  -d '{"wallet":"<wallet>","mint":"<mint>","coins":1000}'
Response 200
{
  "transaction": "<base64>",
  "version": "legacy",
  "mint": "<mint>",
  "wallet": "<wallet>",
  "in": {
    "asset": "coin",
    "amount": 1000
  },
  "expectedXmr": 0.0002574,
  "minXmr": 0.00025225,
  "note": "Sign with the wallet and send within ~60 s (the blockhash expires)."
}
  • 400 A parameter is missing or invalid; error names it.
  • 404 The mint is not a coin on any of this network's Piconero configs.

Launch

Upload metadata

POST/api/v1/metadata

Stores the coin's image and a Metaplex-style metadata JSON on permanent storage and returns its uri for the launch. Send the image as a file, or link one with imageUrl.

Limit 10 metadata uploads per 10 min per IP · not cached

Form fields (multipart/form-data)

namestringrequired
Up to 32 characters.
symbolstringrequired
2 to 10 letters or digits; uppercased.
imagefile
PNG, JPG or GIF, at most 1 MB.
imageUrlstring
An http(s) image URL instead of a file.
descriptionstring
Up to 500 characters.
twitterstring
http(s) URL.
telegramstring
http(s) URL.
websitestring
http(s) URL.
Request
curl -X POST https://piconero.fun/api/v1/metadata \
  -F name="Rock Cat" -F symbol=RCAT -F image=@cat.png -F twitter=https://x.com/rockcat
Response 200
{
  "uri": "https://…/metadata.json",
  "image": "https://…/image.png",
  "provider": "…"
}
  • 400 A parameter is missing or invalid; error names it.
  • 413 The image is over 1 MB.
  • 415 The image is not a PNG, JPG or GIF.
  • 502 The storage provider failed.

Build a launch

POST/api/v1/tx/launch

A transaction that creates the coin on the emission curve in the chosen launch mode, with an optional first buy in the same transaction so nobody can buy ahead of the creator. The first buy pays the 1% fee; separate buys in the first 3 seconds pay the anti-snipe fee (49.99% / 33.66% / 17.33% / 1%). Mode btc (Stealth payout) needs xmrAddress: the transaction then ends with one Memo v2 instruction moneropad xmr payout: v1 <address> listing the wallet as a signer, which binds the address for good (a launch built elsewhere must carry exactly that one memo, or its creator share goes to the platform). The address is public in that memo. Generate a fresh keypair for the mint and send only its public key: the transaction needs the wallet's and the mint keypair's signatures. Supply (18,446,744.073709551, Monero's M), 9 decimals and the revoked mint and freeze authorities come from the config and can't be changed.

Limit 5 launch transactions per 10 min per IP · not cached

JSON body

walletstringrequired
The creator; signs and pays fees. In creator mode it receives the creator share of trading fees.
mintstringrequired
Public key of a fresh keypair you generated.
tierstring
The curve: there is one (graduates at 13 XMR raised), so this is optional.One of standard.Default standard.
modestring
Who gets the creator share (60% of every fee): creator (the creator, claimable in wXMR), stealth (Stealth payout: paid out to xmrAddress as native XMR, after the bridge's fee), burn (Tail burn: buys the coin back and burns it) or mine (rents RandomX hashrate for the coin's rig, which mines Monero at SupportXMR; see mineDest). Permanent.One of creator, stealth, burn, mine.Default creator.
xmrAddressstring
Mode stealth only, then required: the Monero address the creator share is paid to as native XMR, once 0.1 XMR or more is owed, less the bridge's fee. Checked like POST /api/v1/xmr-address/check. Bound by the launch memo: permanent, no update path.
mineDeststring
Mode mine only: where what the rig mines goes: holders (credited in wXMR to holders, claimable), creator (credited in wXMR to the creator, claimable) or burn (buys the coin back and burns it). Default holders. Bound by the launch memo: permanent.
mineRigstring
Mode mine only: pool (hashes with every pool coin; payouts split by hash delivered) or solo (hashes alone). Default pool. Bound by the launch memo: permanent.
namestringrequired
Up to 32 characters.
symbolstringrequired
2 to 10 letters or digits.
uristringrequired
The metadata JSON URL, from POST /api/v1/metadata.
firstBuyXmrnumber
wXMR the creator buys with in the launch transaction (firstBuyBtc is accepted as an alias).Default 0.
Request
curl -X POST https://piconero.fun/api/v1/tx/launch -H "Content-Type: application/json" \
  -d '{"wallet":"<wallet>","mint":"<new mint>","tier":"standard","mode":"creator","name":"Rock Cat",
       "symbol":"RCAT","uri":"https://…/metadata.json","firstBuyXmr":0.01}'
Response 200
{
  "transaction": "<base64>",
  "version": "legacy",
  "mint": "<mint>",
  "wallet": "<wallet>",
  "tier": "standard",
  "mode": "creator",
  "config": "<config>",
  "pool": "<dbc pool>",
  "firstBuyXmr": 0.01,
  "xmrAddress": "(mode stealth) <address>",
  "xmrPayoutMemo": "(mode stealth) moneropad xmr payout: v1 <address>",
  "signers": [
    "<wallet>",
    "<mint>"
  ],
  "note": "Sign with the wallet and the mint keypair, then send within ~60 s (the blockhash expires)."
}
  • 400 A parameter is missing or invalid; error names it.
  • 409 That mint already has a pool: generate a fresh keypair.
  • 422 Mode btc (Stealth payout): the bridge refuses xmrAddress (mainnet). Use another address.

Holders

Payouts

Check a payout address

POST/api/v1/xmr-address/check

Would a btc-mode (Stealth payout) launch accept this address: its checksum and network, and on mainnet a read-only quote from the bridge to it. tx/launch runs the same check.

Limit 60 quotes per 1 min per IP · not cached

JSON body

addressstringrequired
The payout address.
Request
curl -X POST https://piconero.fun/api/v1/xmr-address/check -H "Content-Type: application/json" -d '{"address":"<address>"}'
Response 200
{
  "ok": true,
  "address": "<address>",
  "type": "<type>",
  "bridge": "<bridge>"
}
  • 400 Not a valid address for this network.
  • 422 The bridge refuses this address.
  • 503 The bridge didn't answer; try again.

Get a coin's Stealth payouts

GET/api/v1/coins/{mint}/payouts

Stealth payout coins (mode stealth): 60% of every trading fee (and 80% of LP fees after graduation) is owed to the Monero address bound at launch and paid out automatically as native XMR once 0.1 XMR or more is owed: the distributor unwraps it through the wXMR bridge, which takes 0.1%. Amounts depend on trading volume and can be zero. Each payout: gross sent into the bridge, its fee, net delivered, the Monero tx (mainnet) and the Solana withdrawal. …Sats amounts are quote atoms: piconero, 10^-12 wXMR (divide by 10^12 for XMR).

Limit 120 reads per 1 min per IP · cached 5 s

Path

mintstringrequired
The coin.
Request
curl https://piconero.fun/api/v1/coins/<mint>/payouts
Response 200
{
  "mint": "<mint>",
  "status": "bound",
  "address": "<address>",
  "addressUrl": "<explorer>/address/<address>",
  "bindSignature": "<launch signature>",
  "unboundReason": null,
  "owedAtoms": 31044000000,
  "inFlightAtoms": 0,
  "paidGrossAtoms": 90744000000,
  "paidNetAtoms": 89713000000,
  "minPayoutAtoms": 100000000000,
  "history": [
    {
      "id": 1,
      "state": "btc_confirmed",
      "createdAt": "2026-10-05T17:49:51.000Z",
      "settledAt": "2026-10-05T17:51:17.000Z",
      "grossSats": 90744000000,
      "feeSats": 1031000000,
      "netSats": 89713000000,
      "btcTxid": "<txid>",
      "btcTxUrl": "<explorer>/tx/<txid>",
      "depositSignature": "<signature>",
      "refundedAtoms": null
    }
  ]
}
  • 404 Not a Stealth payout coin (or not registered yet), or no payout ledger on this server.

Mining

Events

Stream events

GET/api/v1/events

Server-sent events (text/event-stream) for new coins, era changes (the next emission segment, or the tail), graduations and burns, a few seconds after they land on chain. Each event has an id; reconnect with the Last-Event-ID header (browsers' EventSource does this for you) or ?since=<id> to receive what you missed. The server keeps the last 200 events since it started.

Limit 10 event stream connections per 1 min per IP · not cached

Query

sinceinteger
Replay buffered events after this id.
Request
curl -N https://piconero.fun/api/v1/events
Stream
event: ready
data: {"cluster":"mainnet-beta"}

id: 7
event: coin.era
data: {"mint":"<mint>","symbol":"RCAT","name":"Rock Cat","tier":"standard","fromEra":0,"toEra":1,"eraName":"Emission 2","priceXmr":0.0000002833,"at":1791147084827}

: ping
  • 503 Too many open streams on the server; retry after the Retry-After seconds.

Objects

Coin

Returned by /coins and /coins/{mint}.

mintstring
The coin's mint address.
poolstring
Its Meteora DBC pool.
configstring
The DBC config it launched on (one per launch mode).
tierstring
standard (the one curve).
modestring
creator (the creator gets the creator share of fees, in wXMR), btc (Stealth payout: it is paid out to the address bound at launch) or mine (it rents RandomX hashrate for the coin's rig).
btcPayoutobject | null
Mode btc only: address, status (bound | unbound | null), owedAtoms, paidAtoms (quote atoms). Unbound coins (no valid launch memo) credit the share to the platform.
legacyboolean
Always false (kept for the shape: no legacy configs exist).
feeBpsNowinteger
The live base fee in bps: anti-snipe in a coin's first 3 s (49.99% / 33.66% / 17.33% / 1%), then 100.
antiSnipeUntilinteger | null
Unix seconds the anti-snipe schedule ends (null: flat fee).
creatorstring
The wallet that launched it.
activatedAtinteger
Unix seconds trading opened.
priceXmrnumber
Current price in XMR per coin (the site shows µXMR: × 10^6), from the curve or, once graduated, the DAMM v2 pool.
fdvXmrnumber
Fully diluted value in XMR: priceXmr × 18,446,744.073709551.
mcapXmrnumber
Market cap in XMR: priceXmr × coins in circulation (on the curve: coinsSold; graduated: the whole supply, so it equals fdvXmr).
xmrRaisednumber
XMR (wXMR) on the bonding curve.
graduationXmrnumber
XMR raised at which the coin graduates.
progressnumber
xmrRaised ÷ graduationXmr, 0 to 1.
era.indexinteger
0 Emission 1, 1 Emission 2, … 14 Emission 15, 15 Tail
era.namestring
The era's name.
era.progressnumber
0 to 1 through the current era, by XMR raised.
era.coinsToNextEranumber
Coins left to buy before the next era (emission segment, or the tail).
coinsSoldnumber
Coins bought off the curve so far.
migratedboolean
Graduated: now trades on Meteora DAMM v2.
dammPoolstring | null
The DAMM v2 pool once graduated.
partnerFeeXmrUnclaimednumber
Partner-side fees on the curve not yet claimed, XMR (creator mode: the platform's; other modes: the mode's share and the platform's).
tradingFeeXmrTotalnumber
Creator-share and platform fees on the curve, all time, XMR (Meteora's cut excluded).
creatorFeeXmrUnclaimednumber
The creator's unclaimed fees, XMR (always 0 outside creator mode).
metaobject
name, symbol, uri, image, description and socials (twitter, telegram, website).
isNativeboolean
This is the platform's native coin, the one fees buy back and burn.

Quote

inobject
What goes in: asset (xmr, sol or coin) and amount.
out.expectednumber
Coins (buys) or wXMR (sells) out at the current state.
out.minnumber
The least the trade can return with your slippage; the transaction fails below it.
viaXmrnumber | null
SOL buys: the wXMR the SOL swap guarantees, which then buys the coin.
spotPriceXmrnumber
Price before the trade, XMR per coin.
avgPriceXmrnumber
XMR paid or received ÷ coins, XMR per coin, fee included.
priceImpactnumber
avgPriceXmr ÷ spotPriceXmr − 1: positive on buys, negative on sells.
venuestring
curve (Meteora DBC) or dammV2 (graduated).
feeBpsinteger
The base fee the quote used: up to 4999 in a new coin's first seconds (anti-snipe), else 100.
eraobject | null
Curve only: before, after (null = graduates), crossesEra, graduates.

Transaction response

transactionstring
The serialized transaction, base64.
version"legacy" | 0
Deserialize with Transaction.from (legacy) or VersionedTransaction.deserialize (0).
expectedCoins / expectedXmrnumber
What the trade should return.
minCoins / minXmrnumber
The least it can return; below that it fails and nothing is spent.
notestring
Signing reminder.

Event types

From GET /api/v1/events. Every payload has at, the Unix ms the server saw it. The stream also sends a ready event on connect and a comment ping every 15 seconds.

coin.created

A coin launched.

{
  "mint": "<mint>",
  "symbol": "RCAT",
  "name": "Rock Cat",
  "tier": "standard",
  "creator": "<wallet>",
  "pool": "<dbc pool>",
  "activatedAt": 1791147066,
  "at": 1791147073843
}

coin.era

A coin on the bonding curve entered its next era: the next emission segment (the price has risen by about 20% since the last one began, and each XMR buys that many fewer coins), or the tail.

{
  "mint": "<mint>",
  "symbol": "RCAT",
  "name": "Rock Cat",
  "tier": "standard",
  "fromEra": 0,
  "toEra": 1,
  "eraName": "Emission 2",
  "priceXmr": 2.833e-7,
  "at": 1791147084827
}

coin.graduated

A coin raised the curve's target and moved to its Meteora DAMM v2 pool.

{
  "mint": "<mint>",
  "symbol": "RCAT",
  "name": "Rock Cat",
  "tier": "standard",
  "dammPool": "<damm v2 pool>",
  "priceXmr": 0.0000037872,
  "at": 1791150000000
}

burn

A keeper buyback & burn (or a graduated coin's leftover burn) landed.

{
  "signature": "<signature>",
  "time": 1791140807,
  "mint": "<mint>",
  "coins": 10.2039,
  "why": "buyback",
  "at": 1791140812000
}

Recipes

Launch a coin from your app

TypeScript · browser
import { Keypair, Transaction } from "@solana/web3.js";

// 1. Image + metadata -> uri
const form = new FormData();
form.set("name", "Rock Cat");
form.set("symbol", "RCAT");
form.set("image", file); // a File from an <input type="file">
const meta = await fetch("https://piconero.fun/api/v1/metadata", { method: "POST", body: form }).then((r) => r.json());
if (meta.error) throw new Error(meta.error);

// 2. A fresh keypair becomes the coin's mint
const mint = Keypair.generate();
const res = await fetch("https://piconero.fun/api/v1/tx/launch", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    wallet: wallet.publicKey.toBase58(),
    mint: mint.publicKey.toBase58(),
    tier: "standard",
    name: "Rock Cat",
    symbol: "RCAT",
    uri: meta.uri,
    firstBuyXmr: 0.01,
  }),
}).then((r) => r.json());
if (res.error) throw new Error(res.error);

// 3. Wallet + mint sign; the coin page is live once it confirms
const tx = Transaction.from(Uint8Array.from(atob(res.transaction), (c) => c.charCodeAt(0)));
const signature = await wallet.sendTransaction(tx, connection, { signers: [mint] });
console.log("https://piconero.fun/c/" + res.mint);

An era alert bot

Node 22 or later, no dependencies: read the stream with fetch and post wherever you like.

JavaScript · Node
const res = await fetch("https://piconero.fun/api/v1/events");
const reader = res.body.pipeThrough(new TextDecoderStream()).getReader();
let buf = "";
for (;;) {
  const { value, done } = await reader.read();
  if (done) break; // reconnect here with ?since=<last id>
  buf += value;
  let end;
  while ((end = buf.indexOf("\n\n")) >= 0) {
    const block = buf.slice(0, end);
    buf = buf.slice(end + 2);
    const type = /^event: (.*)$/m.exec(block)?.[1];
    const data = /^data: (.*)$/m.exec(block)?.[1];
    if (type === "coin.era") {
      const e = JSON.parse(data);
      console.log(`$${e.symbol} entered ${e.eraName} at ${(e.priceXmr * 1000000).toFixed(4)} µXMR https://piconero.fun/c/${e.mint}`);
    }
  }
}

In a browser it is shorter:

JavaScript · browser
const es = new EventSource("https://piconero.fun/api/v1/events");
es.addEventListener("coin.graduated", (e) => console.log("graduated", JSON.parse(e.data).symbol));

Coins about to graduate

Python · requests
import requests

r = requests.get("https://piconero.fun/api/v1/coins", params={"sort": "progress", "graduated": "false", "limit": 10})
for c in r.json()["coins"]:
    print(f'{c["meta"]["symbol"]:>8}  {c["progress"]:6.1%}  {c["era"]["name"]:<10}  {c["priceXmr"] * 1000000:.4f} µXMR')

Price in dollars

TypeScript
const [{ usd }, coin] = await Promise.all([
  fetch("https://piconero.fun/api/v1/xmr-usd").then((r) => r.json()),
  fetch("https://piconero.fun/api/v1/coins/<mint>").then((r) => r.json()),
]);
const priceUsd = coin.priceXmr * usd; // priceXmr is XMR per coin

Read straight from the chain

There is no Piconero program. A coin belongs to Piconero exactly when its Meteora DBC pool uses one of these configs, so you can index or trade without this API using @meteora-ag/dynamic-bonding-curve-sdk and @meteora-ag/cp-amm-sdk.

WhatAddress
Monero curve config (13 XMR, creator)FHWgd6phRkeNf6UvxkJc4P3xxjo4yPYxQo1bmrSR5axp
Monero curve config (13 XMR, stealth)F8c5D6fufyZ9BVzTLfsps3MD3yFEaWLmPWsdtisH3LYg
Monero curve config (13 XMR, burn)G8ikC4gzF7Rn88MB35bx16xgh7ccC7sK2jdqHyQrXmU9
Distributor: Stealth payout configs (holder claims: holdings worth $10+)EtuPeHpgrx6GR7XDGm9aAJckH5VxqBaAwHbnpHjm7wGQ
Stealth payout bridge sender7sy5K4JZV6WG3eZtuEAJpsYsdhzZ6e6igM9EubEeovbX
wXMR quote mintWXMRyRZhsa19ety5erZhHg4N3xj3EVN92u94422teJp
DBC programdbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN
DAMM v2 programcpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG

A coin's pool is deriveDbcPoolAddress(quoteMint, mint, config). Era boundaries follow from the config's curve: 16 constant-product segments, one per era: 15 emission segments that each raise the same XMR, then the tail.

Versioning

  • Within /api/v1, responses only gain fields. Ignore fields you don't know. Removing or renaming anything means /api/v2. Version 1.0 is Piconero's first contract; it is not the API of the site this code was forked from.
  • The unversioned /api/* routes serve this site and can change without notice. Build on /api/v1.
  • Fees bought back and burned describe what the platform does with its share; nothing here is a promise about price or returns.