halvd
BTC …Supply / coin 21,000,000On curve …Graduated …$HALVD burned …Solana
Developers · API v1

Build on halvd

Everything the site does, over plain HTTP: list and read coins, quote a trade, get a buy, a sell, a launch or a holder claim back as an unsigned transaction, and follow new coins, epochs, graduations, trades and burns as they happen.

List coins in a wallet app, run a trading bot, chart a curve, ping a chat when a coin graduates. halvd builds each transaction and stops there: the person using your app signs it in their own wallet.

Endpoints28JSON, plus one SSE stream
API keyNoneopen CORS, per-IP limits
SigningYoursunsigned transactions out
ClusterMainnetX-Cluster on every reply
01 / What it's for#overview

One API, the whole launchpad

Every halvd coin is a Meteora pool anyone can read. The API saves you the indexing, the curve math and the transaction building.

Base URL
https://halvd.fun/api/v1
Format
JSON in and out (one multipart upload). Big integers such as atom amounts are strings; everything else is a plain number.
Access
No key, no sign-up. Any website may call it straight from the browser: CORS allows all origins.
Network
Every response carries X-Cluster: mainnet or fork (a local test copy of mainnet). Compare it with the RPC your app sends through: a transaction built against the fork can never land on mainnet, and the reverse. This server says mainnet.
Transactions
Builders return unsigned transactions with the user as fee payer. halvd never holds or asks for a user's key. Real cbBTC moves on mainnet.
Spec
/api/v1/openapi.json (OpenAPI 3.1) for client generators, Postman or Insomnia. The index at /api/v1 lists tiers, configs, fees and thresholds for this cluster.
02 / Quick start#quickstart

From zero to a signed buy

Pick a coin, see what a buy returns, then let the user's wallet sign the transaction the API builds.

1 · Choose a coin

Curve coins closest to graduation first. Each coin carries its price in sats, its epoch (1 to 4) and its progress to the target.

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

2 · Price the trade

What 0.001 BTC buys right now. outUi is the expected coins, minOutUi the floor your slippage allows, feeBps the live fee (higher in a coin's first seconds).

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

3 · Build, sign, send

Post the same numbers to /tx/buy and you get the transaction. Decode it, hand it to the wallet, wait for confirmation. The swap carries your floor: if the price runs past it, the program rejects the swap and the user is out only the network fee.

curl
curl -X POST https://halvd.fun/api/v1/tx/buy \
  -H "content-type: application/json" \
  -d '{"wallet":"<your wallet>","mint":"<mint>","amount":"0.001","slippageBps":200}'
TypeScript · @solana/web3.js + wallet adapter
import { Transaction, VersionedTransaction } from "@solana/web3.js";
import { useConnection, useWallet } from "@solana/wallet-adapter-react";

const API = "https://halvd.fun/api/v1";

/** base64 → the transaction class its `version` says */
function decode(b64: string, version: "legacy" | 0) {
  const bytes = Uint8Array.from(atob(b64), (ch) => ch.charCodeAt(0));
  return version === 0 ? VersionedTransaction.deserialize(bytes) : Transaction.from(bytes);
}

export function useBuy() {
  const { publicKey, sendTransaction } = useWallet();
  const { connection } = useConnection();

  return async function buy(mint: string, btc: string) {
    if (!publicKey) throw new Error("Connect a wallet first");
    const res = await fetch(`${API}/tx/buy`, {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({ wallet: publicKey.toBase58(), mint, amount: btc, slippageBps: 200 }),
    });
    const built = await res.json();
    if (!res.ok) throw new Error(built.error); // says what to fix

    // the wallet is the only signer, so a fresh blockhash is fine and buys signing time
    const tx = decode(built.transaction, built.version);
    const latest = await connection.getLatestBlockhash();
    if (tx instanceof Transaction) tx.recentBlockhash = latest.blockhash;
    else tx.message.recentBlockhash = latest.blockhash;

    const signature = await sendTransaction(tx, connection);
    await connection.confirmTransaction({ signature, ...latest }, "confirmed");
    return { signature, coinsAtLeast: built.quote.minOutUi };
  };
}
03 / Units#units

Sats first

Prices are sats per whole coin. Field names say the unit: Sats, Btc, Usd, Ui or atoms.

FieldWhat it holdsExample
amountWhat you send: BTC or SOL to spend on a buy, coins on a sell, as a decimal string"0.001"
amountAtomsThe same in the smallest unit: sats (8 decimals), lamports (9) or coin atoms (6)"100000"
…SatsWhole sats as integers; 100,000,000 make 1 BTC12500000
priceSatsSats for one whole coin; a float, usually under 1 early on0.23
fdvBtc, mcapBtcWhole BTC: priceSats × 21,000,000 (or × coins out) ÷ 10^80.0492
inAmount, outAmount, minOutAtom counts as strings, since they can exceed 2^53; minOut is the floor the transaction checks"402069365110"
inUi, outUi, minOutUiThe same three as decimals, for showing people402069.36511
createdAt, ts, atUnix seconds1792193381
Coins
Every coin has 21,000,000 supply and 6 decimals. A balance of 1000000 atoms is one coin.
BTC
cbBTC, Coinbase's wrapped bitcoin, with 8 decimals: its smallest unit is exactly one sat. Mint cbbtcf3aa214zXHbiAZQwf4122FBYbraNdFqgw4iMij.
Dollars
Only as a convenience (priceUsd, /btc-usd). They come from BTC/USD at read time and can be null.
04 / Launch to pool#lifecycle

Launch, four epochs, a pool

What happens to a coin, and how each step shows up in the API.

Launch
The creator picks a tier (spark 0.125 BTC · block 0.25 BTC · vault 0.5 BTC · whole 1 BTC) and a mode (creator, holders, longhold, btc, hash). Each pair is its own DBC config, so both are fixed on chain. The launch transaction can carry the creator's own first buy, which pays the normal 1%. Anyone buying in the following 3 seconds pays a falling fee, 49.99%, then 33.66%, then 17.33%, before it settles at 1%. Read the live figure from a quote's feeBps.
Epochs
The price doubles from one epoch to the next and each epoch raises a quarter of the target. On Spark the curve starts at 0.23 sats and epoch 4 ends at 3.75 sats. A coin's epoch reads 1 to 4, toNextHalving counts the coins left before the next step, and the stream sends coin.epoch the first time a buy crosses one. /curves has every boundary.
Sold out
When epoch 4 fills, the curve stops trading. A buy that would overshoot fills to the end and refunds the rest (refundSats in its quote). Until the pool opens, quotes and builders answer 409 for a few seconds.
Graduation
Meteora moves the raised BTC and the unsold coins into a DAMM v2 pool whose liquidity is locked for good. The coin then reads graduated: true with its dammPool filled in, and stream listeners get coin.graduated. Keep calling the same endpoints: the server trades on the pool from then on, and a quote's venue turns from curve to dammV2.
Fees
1% of every trade in cbBTC, on the curve and in the pool. Who gets the 60% fee share depends on the mode; claims and payouts have their own endpoints below.
05 / Signing#signing

Your users sign

Builders return a transaction, never a signature. What to do with it depends on what it is.

Decoding
The bytes arrive base64-encoded. Look at version first: "legacy" goes through Transaction.from, 0 through VersionedTransaction.deserialize. You'll see 0 whenever SOL is involved, because the Jupiter leg needs address lookup tables.
Fee payer
The wallet you named, listed first in signers. It pays the network fee and any token account rent (a first cbBTC or coin account).
Blockhash
The network accepts a blockhash for roughly 150 blocks, about a minute. A user who takes longer needs a rebuilt transaction. For trades and boosts the wallet is the only signer, so your app may drop in a newer blockhash itself right before signing, as the sample above does.
Simulation
Trade and boost builders simulate first: a trade that would fail (no balance, slippage) comes back as a 400 with the reason instead of a transaction.
Launches
Two signers: the wallet and a keypair you generate for the mint (its public key goes in mintPubkey). Never reuse a mint keypair. Then post the signature to /launch/record.
Holder claims
halvd's distributor key signs the claim before you see it, over these exact bytes. Call signTransaction and post the result to /holders/claim/submit; halvd broadcasts it and settles the books. Some wallets slip a compute-budget instruction in while signing, which alters the bytes: that claim comes back 422, and you prepare a new one. A prepared claim reserves the owed sats for 2 minutes.
TypeScript · a launch, two signers
const mint = Keypair.generate(); // becomes the coin's address; keep it until the tx lands
const built = await post("/tx/launch", {
  wallet: publicKey.toBase58(),
  mintPubkey: mint.publicKey.toBase58(),
  tier: "spark", mode: "creator", name: "Sat Stacker", symbol: "STACK", uri,
});
const tx = decode(built.transaction, built.version);
// the wallet signs as fee payer, the mint keypair as the new mint
const signature = await sendTransaction(tx, connection, { signers: [mint] });
await post("/launch/record", { signature }); // optional: indexes it now instead of in a few seconds
TypeScript · a holder claim, signed unchanged
const prep = await post("/holders/claim/prepare", { wallet: publicKey.toBase58() });
const tx = Transaction.from(Uint8Array.from(atob(prep.transaction), (ch) => ch.charCodeAt(0)));
const signed = await signTransaction(tx); // signTransaction, not sendTransaction: halvd broadcasts it
const signedTx = btoa(String.fromCharCode(...signed.serialize()));
const done = await post("/holders/claim/submit", { claimId: prep.claimId, signedTx });
// done.status === "confirmed", done.sig is the transaction
06 / Errors & limits#limits

Plain errors, fair limits

A failed call answers with a status from the list below and a JSON body holding one sentence, such as { "error": "sort must be one of new, boost, mcap, progress, fdv, volume, hashrate" }.

200 / 201
Done. 201 means something was created (metadata, a recorded launch).
400
The request breaks a rule, or a transaction failed its simulation. The message names the field or the reason.
404
No such coin, claim or endpoint on this cluster. A coin that launched seconds ago can 404 on routes that read the index; /coins/{mint} doesn't.
405
Wrong method: the builders are POST only.
409
A state conflict: a mint already in use, a claim already open, or a curve that sold out a moment ago and hasn't migrated yet.
410 / 422
Claims only: the two-minute lock lapsed (410), or the signed transaction isn't the one prepared (422).
413 / 415
Uploads only: over 1 MB (413), or not multipart / not an image (415). POST bodies must be JSON (415).
429
Over a rate limit or the stream cap. The body has retryAfterSecs; Retry-After says the same.
500
Something failed on halvd's side. The message keeps a short reason.
502
An upstream failed: Jupiter had no route, or the RPC didn't answer a chain check.
503
Trading or launches are paused, the RPC is busy, or the event stream is full. Safe to retry.

Rate limits

Counted per IP address, in buckets. Every endpoint in a bucket draws on one allowance, which you can spend in a burst; it then refills at an even pace across the window. These numbers come from the same table the server enforces.

read
240 per minute. Reads answered from halvd's index.GET /GET /openapi.jsonGET /coinsGET /coins/{mint}/candlesGET /curvesGET /burnsGET /btc-usdGET /btc-address/checkGET /coins/{mint}/holdersGET /coins/{mint}/holders/{wallet}GET /wallets/{wallet}/sharesGET /coins/{mint}/payoutsGET /coins/{mint}/rigGET /rigsGET /blocks
live
90 per minute. Reads that go to the chain first.GET /coins/{mint}GET /coins/{mint}/checkGET /quoteGET /holders/claim/status
build
30 per minute. Trade and boost transactions.POST /tx/buyPOST /tx/sellPOST /tx/boost
claim
12 per minute. Holder claims.POST /holders/claim/preparePOST /holders/claim/submit
launch
10 per 10 minutes. Launch transactions.POST /tx/launch
record
30 per 10 minutes. Recording a landed launch.POST /launch/record
metadata
10 per 10 minutes. Image and metadata uploads.POST /metadata
stream
12 per minute. Opening the event stream.GET /events
Event stream
At most 4 open streams per IP (the next answers 429) and 100 on the server (then 503 with Retry-After).
Spending less
Each read sends a Cache-Control lifetime; a CDN or a small in-memory cache answers repeats for free. For new coins and trades, one stream replaces any amount of polling.
07 / Endpoints#basics

Index and spec

GET/api/v1

The index

Cluster, coin rules, tiers with their config per mode, fees, anti-snipe schedule, off-chain thresholds, public addresses and this endpoint list.

  • Fetch it when your app boots: it carries this cluster's config addresses and thresholds, so nothing needs hard-coding.
read bucket: 240 per minute per IP · cached 60 s
Request
curl "https://halvd.fun/api/v1"
Response 200 · captured on the fork, arrays shortened
{
  "name": "halvd API",
  "version": "1",
  "cluster": "fork",
  "docs": "/developers",
  "openapi": "/api/v1/openapi.json",
  "token": {
    "supply": 21000000,
    "decimals": 6,
    "mintAuthority": null,
    "freezeAuthority": null,
    "metadata": "immutable"
  },
  "btc": {
    "symbol": "cbBTC",
    "mint": "cbbtcf3aa214zXHbiAZQwf4122FBYbraNdFqgw4iMij",
    "decimals": 8
  },
  "tiers": [
    {
      "id": "spark",
      "name": "Spark",
      "targetBtc": 0.125,
      "targetSats": 12500000,
      "startSats": 0.23452125193542817,
      "graduationSats": 3.75234003096685,
      "configs": {
        "creator": "7p7GuuTzNsQumkFPWxPGNX2Hyj1M23aroc7BkpCSu3SW",
        "holders": "26yVFHMfzRBTJV7GcQonc6Lj1PbEGcNNBgny3PMrpFfp",
        "longhold": "BEmJTmLwDKvVDc2yuNEJWLAARESN1XAS7DFjqHqcN51Q",
        "btc": "2tXdcQhK7HhKLyDYhmf7vJ8S4bEFpHGEmeuL8NAWfUHV",
        "hash": "EqHJ9tADga9F1SzD4CoNQPxgVL75ruqeCzkKHcTQJdtD"
      }
    }
  ],
  "modes": [
    {
      "id": "creator",
      "name": "Creator",
      "claimer": "creator",
      "summary": "The fee share is yours, paid in BTC. Claim it any time from Wallet."
    }
  ],
  "epochs": [
    {
      "epoch": 1,
      "subsidyBtc": "50",
      "priceMultipleAtStart": 1
    }
  ],
  "antiSnipe": {
    "scheduleBps": [
      4999
    ],
    "stepSeconds": 1,
    "afterBps": 100,
    "firstBuyInLaunchTxBps": 100
  },
  "fees": {
    "tradeFeeBps": 100,
    "paidIn": "cbBTC",
    "meteoraShare": 0.2,
    "feeShareOfRest": 0.75,
    "split": {
      "feeShare": 0.6,
      "burn": 0.15,
      "treasury": 0.05,
      "meteora": 0.2
    },
    "afterGraduation": {
      "poolFeeBps": 100,
      "lockedLiquidityPct": 100,
      "creatorMode": {
        "creatorPct": 80,
        "platformPct": 20
      },
      "otherModes": {
        "claimerPct": 100
      }
    }
  },
  "offchain": {
    "snapshotFastSecs": 60,
    "snapshotFastForSecs": 3600,
    "snapshotSlowSecs": 600,
    "minHoldingUsd": 10,
    "minClaimSats": 500,
    "payoutSats": 12000,
    "payoutMaxFee": 0.1,
    "payoutStaleDays": 90,
    "payoutStaleSats": 6000,
    "payoutStaleMaxFee": 0.2,
    "hashFundSats": 11000,
    "hashFundMaxFee": 0.1,
    "hashBidSats": 10000,
    "hashFinderShare": 0.1,
    "hashBurnShare": 0.05,
    "hashConfirmations": 100,
    "claimMinSats": 2000
  },
  "longholdSteps": [
    {
      "afterHours": 0,
      "weight": 1
    }
  ],
  "boosts": {
    "minBurn": 1000,
    "fadeSeconds": 86400
  },
  "memos": {
    "btcPayout": "halvd payout v1 ",
    "hash": "halvd hash v1 ",
    "boost": "halvd boost v1 ",
    "burn": "halvd burn",
    "treasury": "halvd treasury",
    "platform": "halvd platform share",
    "claim": "halvd claim"
  },
  "addresses": {
    "programs": {
      "dbc": "dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN",
      "dammV2": "cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG"
    },
    "keeper": "BdcxkPEKvPJ74vX6gKRXhCgV4ZUAkCaCnkXuUES3nMSY",
    "distributor": "7Jzj13Kn8Q7B9esBHxGRYtuSmuM4zVuH3Pk8vk88FJKV",
    "miner": "93aTDkTC48wH56S1NEB9X3FSPzV7uPqqYv3M7eUcxMnF",
    "sender": "DMZjK5wdTSUaukUK8p856oNFsNRXYPVCMcu3fie5VZ46",
    "treasury": "5Bf6vRccSczDFcxVvdHJ9FfV2EXL1AyZ1N9fX1hxJyAs",
    "houseMint": "2sNyqhYwx9TQ6BrMCscPowKnpYn3oWiQ4bHjyu5iXy4G",
    "configsReady": true
  },
  "stream": {
    "open": 0,
    "maxOpen": 100,
    "maxOpenPerIp": 4,
    "polling": false,
    "pollMs": 2000,
    "heartbeatS": 15,
    "types": [
      "coin.created"
    ]
  },
  "limits": {
    "read": {
      "limit": 240,
      "windowSecs": 60
    },
    "live": {
      "limit": 90,
      "windowSecs": 60
    },
    "build": {
      "limit": 30,
      "windowSecs": 60
    },
    "claim": {
      "limit": 12,
      "windowSecs": 60
    },
    "launch": {
      "limit": 10,
      "windowSecs": 600
    },
    "record": {
      "limit": 30,
      "windowSecs": 600
    },
    "metadata": {
      "limit": 10,
      "windowSecs": 600
    },
    "stream": {
      "limit": 12,
      "windowSecs": 60
    }
  },
  "endpoints": [
    {
      "method": "GET",
      "path": "/api/v1",
      "summary": "Cluster, coin rules, tiers with their config per mode, fees, anti-snipe schedule, off-chain thresholds, public addresses and this endpoint list.",
      "bucket": "read"
    },
    {
      "method": "GET",
      "path": "/api/v1/openapi.json",
      "summary": "An OpenAPI 3.1 description of every v1 route, with schemas for the main objects.",
      "bucket": "read"
    },
    {
      "method": "GET",
      "path": "/api/v1/coins",
      "summary": "Coins from halvd's index, sorted and filtered, a page at a time.",
      "bucket": "read"
    }
  ]
}
Errors
  • 429Over the rate limit; see retryAfterSecs.
GET/api/v1/openapi.json

OpenAPI document

An OpenAPI 3.1 description of every v1 route, with schemas for the main objects.

  • OpenAPI 3.1, JSON. Load it into Postman, Insomnia or a client generator.
read bucket: 240 per minute per IP · cached 300 s
Request
curl "https://halvd.fun/api/v1/openapi.json"
Response 200 · captured on the fork, arrays shortened
{
  "openapi": "3.1.0",
  "info": {
    "title": "halvd API",
    "version": "1",
    "description": "Read halvd coins and build their transactions over HTTP. JSON, open CORS, no key. Transactions come back unsigned: the user's wallet signs and sends them. Every response carries X-Cluster (mainnet or fork). Guide: /developers."
  },
  "paths": "28 paths",
  "components": {
    "schemas": "32 schemas"
  }
}
Errors
  • 429Over the rate limit; see retryAfterSecs.
08 / Endpoints#market

Coins and market data

GET/api/v1/coins

Browse coins

Coins from halvd's index, sorted and filtered, a page at a time.

read bucket: 240 per minute per IP · cached 5 s
sort
stringquery
new: newest first · boost: coins with boost left, most first · mcap / fdv / volume: largest first · progress: closest to graduation, curve coins only · hashrate: Hashrate mode coins only.newboostmcapprogressfdvvolumehashrate
limit
integerquery
Page size, 1 to 100.Default 24.
offset
integerquery
Coins to skip.Default 0.
mode
stringquery
Only coins in this mode.creatorholderslongholdbtchash
creator
stringquery
Only coins launched by this wallet.
graduated
booleanquery
true: only coins on DAMM v2 · false: only coins still on the curve.
q
stringquery
Search names and tickers, or match an exact mint. Up to 64 characters.
Request
curl "https://halvd.fun/api/v1/coins?sort=progress&graduated=false&limit=2"
Response 200 · captured on the fork, arrays shortened
{
  "total": 101,
  "limit": 2,
  "offset": 0,
  "sort": "progress",
  "btcUsd": 81541.875,
  "coins": [
    {
      "mint": "ABa4BRS5CfGrEuGVrHhWVa5niZJqvbV8HmrmiYiGhuD9",
      "pool": "3BPgdBGNVjfGC67bQjC9WGqyVu12Y6UHAFLcJhfEkWqh",
      "config": "7p7GuuTzNsQumkFPWxPGNX2Hyj1M23aroc7BkpCSu3SW",
      "tier": "spark",
      "mode": "creator",
      "creator": "5q1JUAkPmWVTyVDuYjVqTrRj3aeTJHMaP8hwJk1Aw2tJ",
      "name": "Halving Test",
      "symbol": "HTEST",
      "image": null,
      "description": "",
      "xUrl": null,
      "website": null,
      "createdAt": 1792184933,
      "createSig": "5hsQmJNLy9TTa5EWBXAR6jMQ896Cd1DReFfvoZydoATbxBsNMiKZ6uczgJzbkNg9GEzDq14HBzGJCqd2mkhNRvfa",
      "priceSats": 2.9896370107075807,
      "priceUsd": 0.002437806074224912,
      "fdvBtc": 0.627823772248592,
      "mcapBtc": 0.5179405228298422,
      "epoch": 4,
      "graduated": false,
      "raisedSats": 11354135,
      "targetSats": 12500000,
      "progress": 0.9083308,
      "soldCoins": 17324528.729568314,
      "toNextHalving": 342116.6674795151,
      "dammPool": null,
      "graduatedAt": null,
      "volumeSats": 11354135,
      "trades": 1,
      "boost": 0,
      "btcAddress": null,
      "hashDest": null,
      "hashRig": null
    }
  ]
}
Errors
  • 400A parameter is missing or malformed; the message names it.
  • 429Over the rate limit; see retryAfterSecs.
GET/api/v1/coins/{mint}

One coin

A coin with its price re-read from its pool when the index copy is more than a few seconds old, plus its recent boosts.

  • A coin the indexer hasn't recorded yet is built from chain (source: chain), so this works seconds after a launch.
live bucket: 90 per minute per IP · cached 2 s
mint
stringpathrequired
The coin's mint address.
Request
curl "https://halvd.fun/api/v1/coins/<mint>"
Response 200 · captured on the fork, arrays shortened
{
  "coin": {
    "mint": "ABa4BRS5CfGrEuGVrHhWVa5niZJqvbV8HmrmiYiGhuD9",
    "pool": "3BPgdBGNVjfGC67bQjC9WGqyVu12Y6UHAFLcJhfEkWqh",
    "config": "7p7GuuTzNsQumkFPWxPGNX2Hyj1M23aroc7BkpCSu3SW",
    "tier": "spark",
    "mode": "creator",
    "creator": "5q1JUAkPmWVTyVDuYjVqTrRj3aeTJHMaP8hwJk1Aw2tJ",
    "name": "Halving Test",
    "symbol": "HTEST",
    "image": null,
    "description": "",
    "xUrl": null,
    "website": null,
    "createdAt": 1792184933,
    "createSig": "5hsQmJNLy9TTa5EWBXAR6jMQ896Cd1DReFfvoZydoATbxBsNMiKZ6uczgJzbkNg9GEzDq14HBzGJCqd2mkhNRvfa",
    "priceSats": 2.9896370107075807,
    "priceUsd": 0.002437806074224912,
    "fdvBtc": 0.627823772248592,
    "mcapBtc": 0.5179405228298422,
    "epoch": 4,
    "graduated": false,
    "raisedSats": 11354135,
    "targetSats": 12500000,
    "progress": 0.9083308,
    "soldCoins": 17324528.729568314,
    "toNextHalving": 342116.6674795151,
    "dammPool": null,
    "graduatedAt": null,
    "volumeSats": 11354135,
    "trades": 1,
    "boost": 0,
    "btcAddress": null,
    "hashDest": null,
    "hashRig": null
  },
  "source": "db",
  "readAt": 1792194011,
  "boosts": [],
  "boostToLead": 4816
}
Errors
  • 400A parameter is missing or malformed; the message names it.
  • 404No halvd coin with this mint on this cluster.
  • 429Over the rate limit; see retryAfterSecs.
GET/api/v1/coins/{mint}/candles

Price candles

OHLC candles in sats per coin, built from every pool change the indexer saw. Quiet buckets are filled flat.

read bucket: 240 per minute per IP · cached 5 s
mint
stringpathrequired
The coin's mint address.
interval
stringquery
Seconds per candle. auto picks the smallest that fits the coin's history in about limit candles.auto6030090036001440086400
limit
integerquery
Candles, 10 to 500.Default 120.
Request
curl "https://halvd.fun/api/v1/coins/<mint>/candles?interval=60&limit=3"
Response 200 · captured on the fork, arrays shortened
{
  "mint": "ABa4BRS5CfGrEuGVrHhWVa5niZJqvbV8HmrmiYiGhuD9",
  "interval": 60,
  "intervals": [
    60,
    300
  ],
  "count": 1,
  "last": 2.9896370107075807,
  "candles": [
    {
      "t": 1792193460,
      "o": 2.9896370107075807,
      "h": 2.9896370107075807,
      "l": 2.9896370107075807,
      "c": 2.9896370107075807,
      "v": 0,
      "n": 0
    },
    {
      "t": 1792193520,
      "o": 2.9896370107075807,
      "h": 2.9896370107075807,
      "l": 2.9896370107075807,
      "c": 2.9896370107075807,
      "v": 0,
      "n": 0
    }
  ]
}
Errors
  • 400A parameter is missing or malformed; the message names it.
  • 404No indexed coin with this mint.
  • 429Over the rate limit; see retryAfterSecs.
GET/api/v1/coins/{mint}/check

Chain check

Four properties read straight from the mint and pool: the coin count, no mint key, no freeze key, and a cbBTC pairing on a halvd config.

live bucket: 90 per minute per IP · cached 30 s
mint
stringpathrequired
The coin's mint address.
Request
curl "https://halvd.fun/api/v1/coins/<mint>/check"
Response 200 · captured on the fork, arrays shortened
{
  "mint": "ABa4BRS5CfGrEuGVrHhWVa5niZJqvbV8HmrmiYiGhuD9",
  "ok": true,
  "checks": [
    {
      "id": "supply",
      "ok": true,
      "label": "Exactly 21,000,000 coins exist",
      "detail": "mint account: 21000000000000 base units, 6 decimals"
    },
    {
      "id": "mint",
      "ok": true,
      "label": "Nobody holds the mint key",
      "detail": "mint authority: none, so the count can't grow"
    }
  ],
  "checkedAt": 1792194011
}
Errors
  • 400A parameter is missing or malformed; the message names it.
  • 404No halvd coin with this mint on this cluster.
  • 429Over the rate limit; see retryAfterSecs.
  • 502The RPC didn't answer. Retry.
GET/api/v1/curves

Curve shapes

Every tier's halving curve: epoch boundaries, prices in sats, coins per epoch, pool seed and FDV at start and at graduation.

  • A tier's numbers never change, so one fetch is enough.
read bucket: 240 per minute per IP · cached 1 h
Request
curl "https://halvd.fun/api/v1/curves"
Response 200 · captured on the fork, arrays shortened
{
  "supply": 21000000,
  "note": "Ideal curve. The on-chain configs round a few atoms.",
  "tiers": [
    {
      "tier": "spark",
      "name": "Spark",
      "targetBtc": 0.125,
      "targetSats": 12500000,
      "startSats": 0.23452125193542817,
      "graduationSats": 3.75234003096685,
      "startFdvBtc": 0.04924946290643991,
      "graduationFdvBtc": 0.7879914065030386,
      "soldCoins": 17666645.397047833,
      "poolCoins": 3331254.602952168,
      "leftoverCoins": 2099.9999999995343,
      "epochs": [
        {
          "epoch": 1,
          "subsidyBtc": "50",
          "startSats": 0.23452125193542817,
          "endSats": 0.4690425038708563,
          "coins": 9422210.87842551,
          "raisesSats": 3125000,
          "fromSupplyShare": 0,
          "toSupplyShare": 0.44867670849645286
        }
      ],
      "points": [
        {
          "coins": 0,
          "sats": 0.23452125193542817,
          "epoch": 1
        }
      ]
    }
  ]
}
Errors
  • 429Over the rate limit; see retryAfterSecs.
GET/api/v1/burns

Burn ledger

$HALVD burned so far, the treasury balance and the burn ledger (buybacks, curve dust, boosts, block burns), ten rows a page.

read bucket: 240 per minute per IP · cached 15 s
page
integerquery
Page, from 1. Ten rows a page, newest first.Default 1.
kind
stringquery
Only this kind of burn.buybackleftoverboostblock
Request
curl "https://halvd.fun/api/v1/burns?kind=buyback"
Response 200 · captured on the fork, arrays shortened
{
  "totals": {
    "houseMint": "2sNyqhYwx9TQ6BrMCscPowKnpYn3oWiQ4bHjyu5iXy4G",
    "burned": 10750870.351181,
    "burnedShare": 0.5119462071990952,
    "circulating": 10249129.648819,
    "source": "chain",
    "transactions": 27,
    "btcSpent": 0.05666465
  },
  "keeper": "BdcxkPEKvPJ74vX6gKRXhCgV4ZUAkCaCnkXuUES3nMSY",
  "treasury": {
    "address": "5Bf6vRccSczDFcxVvdHJ9FfV2EXL1AyZ1N9fX1hxJyAs",
    "btc": 0.01242347
  },
  "rows": [
    {
      "sig": "2oNRjurPzSeYLnNdoFwvXfpadoz1JB4RjVCR2rEmJMiuqmkrDBQgJVs2epEw2wqVX1VqQFagZJSJkf3HmXZEv6Wn",
      "ix": 3,
      "ts": 1792193266,
      "kind": "leftover",
      "mint": "AL6sL2cgQiZSSKmp65stYgmVAxdFrNorXnDpbLHyapeb",
      "amount": 2100.000005,
      "btcSpent": 0,
      "target": "",
      "wallet": "BdcxkPEKvPJ74vX6gKRXhCgV4ZUAkCaCnkXuUES3nMSY",
      "coin": "AL6sL2cgQiZSSKmp65stYgmVAxdFrNorXnDpbLHyapeb",
      "coinSymbol": "KTA",
      "coinName": "Keeper Test KTA"
    },
    {
      "sig": "2Lk4jeyRPZW21Cm9AbzUtmU7bRFtN3RdGtdmUebnYQB6ojsQAuoRsLN22BbakJH7qNLszDXZLNT1K1PMjsoVV2xF",
      "ix": 3,
      "ts": 1792193265,
      "kind": "leftover",
      "mint": "HB6EW46PBHsGHzfJrx74nWzLGqUMKMPfzZ7vm9gehsQ6",
      "amount": 2100.000008,
      "btcSpent": 0,
      "target": "",
      "wallet": "BdcxkPEKvPJ74vX6gKRXhCgV4ZUAkCaCnkXuUES3nMSY",
      "coin": "HB6EW46PBHsGHzfJrx74nWzLGqUMKMPfzZ7vm9gehsQ6",
      "coinSymbol": "TTEST",
      "coinName": "Trade Test"
    }
  ],
  "page": 1,
  "pages": 3,
  "total": 27,
  "kind": ""
}
Errors
  • 400A parameter is missing or malformed; the message names it.
  • 429Over the rate limit; see retryAfterSecs.
GET/api/v1/btc-usd

BTC price

The BTC/USD price halvd uses for dollar figures, or null when no source answers.

read bucket: 240 per minute per IP · cached 30 s
Request
curl "https://halvd.fun/api/v1/btc-usd"
Response 200 · captured on the fork, arrays shortened
{
  "usd": 81541.875,
  "usdPerSat": 0.00081541875,
  "at": 1792194011
}
Errors
  • 429Over the rate limit; see retryAfterSecs.
09 / Endpoints#trading

Trades and boosts

GET/api/v1/quote

Price a trade

What a buy or sell returns right now, on the curve or the DAMM v2 pool, with the live fee (anti-snipe included) and price impact.

live bucket: 90 per minute per IP · cached 2 s
mint
stringqueryrequired
The coin.
side
stringquery
buy coins, or sell them.buysell
asset
stringquery
buy: what you pay with · sell: what you're paid in. SOL is swapped through Jupiter in the same transaction.btcsol
amount
stringquery
Decimal. buy: BTC or SOL to spend · sell: coins to sell. Required unless amountAtoms is sent.
amountAtoms
stringquery
The same amount as an integer of atoms (sats, lamports or coin atoms).
slippageBps
integerquery
Sets minOut, 0 to 5000.Default 200.
Request
curl "https://halvd.fun/api/v1/quote?mint=<mint>&side=buy&amount=0.001"
Response 200 · captured on the fork, arrays shortened
{
  "mint": "ABa4BRS5CfGrEuGVrHhWVa5niZJqvbV8HmrmiYiGhuD9",
  "venue": "curve",
  "side": "buy",
  "asset": "btc",
  "inAmount": "100000",
  "outAmount": "32773696138",
  "minOut": "32118222215",
  "feeBps": 100,
  "priceImpact": 0.01039528397135614,
  "inUi": 0.001,
  "outUi": 32773.696138,
  "minOutUi": 32118.222215,
  "inSymbol": "cbBTC",
  "outSymbol": "coin",
  "spotSats": 2.9896370107075807,
  "avgSats": 3.051227410510265,
  "poolSats": "100000",
  "refundSats": "0",
  "graduates": false,
  "ageSeconds": 9027,
  "slippageBps": 200
}
Errors
  • 400A parameter is missing or malformed; the message names it.
  • 404No halvd coin with this mint on this cluster.
  • 409Epoch 4 sold out and the DAMM v2 pool isn't open yet. Retry in a moment.
  • 429Over the rate limit; see retryAfterSecs.
  • 502SOL only: Jupiter has no route right now.
  • 503The RPC was busy. Safe to retry.
POST/api/v1/tx/buy

Buy transaction

An unsigned buy, paid in cbBTC (legacy transaction) or SOL routed through Jupiter (v0). Simulated before it's returned.

  • On the curve buys fill up to graduation and refund the rest (quote.refundSats).
build bucket: 30 per minute per IP · not cached
wallet
stringJSON bodyrequired
The buyer. Signs and pays the network fee.
mint
stringJSON bodyrequired
The coin.
amount
stringJSON body
BTC (asset btc) or SOL (asset sol) to spend, as a decimal string. Or send amountAtoms.
amountAtoms
stringJSON body
The amount in sats or lamports.
asset
stringJSON body
btc: one legacy transaction · sol: Jupiter SOL→cbBTC and the buy in one v0 transaction.btcsol
slippageBps
integerJSON body
0 to 5000.Default 200.
simulate
booleanJSON body
Simulate before returning, so a trade that would fail comes back as a 400 with the reason.Default true.
Request
curl -X POST https://halvd.fun/api/v1/tx/buy \
  -H "content-type: application/json" \
  -d '{"wallet":"<your wallet>","mint":"<mint>","amount":"0.001","asset":"btc","slippageBps":200}'
Response 200 · captured on the fork, arrays shortened
{
  "transaction": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA…",
  "version": "legacy",
  "bytes": 720,
  "signers": [
    "6GNru4XLq44kSQcfCnqYgcwv2e8M33g9rPyRUgvmFrcw"
  ],
  "mint": "9FsMyTkjg1vrp8S6nv2Vb9GLBrpkpZdQyKqNHGZ3NBiY",
  "quote": {
    "venue": "curve",
    "side": "buy",
    "asset": "btc",
    "inAmount": "100000",
    "outAmount": "414504500114",
    "minOut": "402069365110",
    "feeBps": 100,
    "priceImpact": 0.013087936928250388,
    "inUi": 0.001,
    "outUi": 414504.500114,
    "minOutUi": 402069.36511,
    "inSymbol": "cbBTC",
    "outSymbol": "coin",
    "spotSats": 0.2357538537048299,
    "avgSats": 0.2412519043158694,
    "poolSats": "100000",
    "refundSats": "0",
    "graduates": false,
    "ageSeconds": 5,
    "slippageBps": 300
  }
}
Errors
  • 400Bad input, or the simulation failed (balance, slippage); the message says which.
  • 404No halvd coin with this mint on this cluster.
  • 409The curve just sold out; the pool opens shortly.
  • 429Over the rate limit; see retryAfterSecs.
  • 502SOL only: no Jupiter route.
  • 503Trading is paused, or the RPC is busy.
POST/api/v1/tx/sell

Sell transaction

An unsigned sell, paid out in cbBTC (legacy) or SOL (v0). Simulated before it's returned.

build bucket: 30 per minute per IP · not cached
wallet
stringJSON bodyrequired
The seller. Signs and pays the network fee.
mint
stringJSON bodyrequired
The coin.
amount
stringJSON body
Coins to sell, as a decimal string (6 decimals at most). Or send amountAtoms.
amountAtoms
stringJSON body
Coin atoms to sell.
asset
stringJSON body
Be paid in cbBTC (legacy tx) or SOL (v0 tx through Jupiter).btcsol
slippageBps
integerJSON body
0 to 5000.Default 200.
simulate
booleanJSON body
Simulate before returning.Default true.
Request
curl -X POST https://halvd.fun/api/v1/tx/sell \
  -H "content-type: application/json" \
  -d '{"wallet":"<your wallet>","mint":"<mint>","amount":"1000","asset":"btc"}'
Response 200 · captured on the fork, arrays shortened
{
  "transaction": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA…",
  "version": "legacy",
  "bytes": 720,
  "signers": [
    "6GNru4XLq44kSQcfCnqYgcwv2e8M33g9rPyRUgvmFrcw"
  ],
  "mint": "9FsMyTkjg1vrp8S6nv2Vb9GLBrpkpZdQyKqNHGZ3NBiY",
  "quote": {
    "venue": "curve",
    "side": "sell",
    "asset": "btc",
    "inAmount": "124677704821",
    "outAmount": "29748",
    "minOut": "29153",
    "feeBps": 100,
    "priceImpact": 0.003951030340377248,
    "inUi": 124677.704821,
    "outUi": 0.00029748,
    "minOutUi": 0.00029153,
    "inSymbol": "coin",
    "outSymbol": "cbBTC",
    "spotSats": 0.24196530008234407,
    "avgSats": 0.23859919496199625,
    "poolSats": "29748",
    "refundSats": "0",
    "graduates": false,
    "ageSeconds": 8,
    "slippageBps": 200
  }
}
Errors
  • 400Bad input, or the simulation failed (not enough coins, slippage).
  • 404No halvd coin with this mint on this cluster.
  • 409The curve just sold out; the pool opens shortly.
  • 429Over the rate limit; see retryAfterSecs.
  • 502SOL only: no Jupiter route.
  • 503Trading is paused, or the RPC is busy.
POST/api/v1/tx/boost

Boost transaction

An unsigned burn of $HALVD with the boost memo naming a coin.

build bucket: 30 per minute per IP · not cached
wallet
stringJSON bodyrequired
Holds the $HALVD, signs the burn and the memo.
mint
stringJSON bodyrequired
The coin to boost.
amount
stringJSON bodyrequired
Whole $HALVD to burn, 1,000 or more.
Request
curl -X POST https://halvd.fun/api/v1/tx/boost \
  -H "content-type: application/json" \
  -d '{"wallet":"<your wallet>","mint":"<mint>","amount":"1000"}'
Response 200 · captured on the fork, arrays shortened
{
  "transaction": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA…",
  "version": "legacy",
  "bytes": 393,
  "signers": [
    "6GNru4XLq44kSQcfCnqYgcwv2e8M33g9rPyRUgvmFrcw"
  ],
  "mint": "9FsMyTkjg1vrp8S6nv2Vb9GLBrpkpZdQyKqNHGZ3NBiY",
  "amount": 1000,
  "memo": "halvd boost v1 9FsMyTkjg1vrp8S6nv2Vb9GLBrpkpZdQyKqNHGZ3NBiY"
}
Errors
  • 400Under 1,000, more than the wallet holds, or the simulation failed.
  • 404No halvd coin with this mint on this cluster.
  • 409$HALVD hasn't launched on this cluster.
  • 429Over the rate limit; see retryAfterSecs.
10 / Endpoints#launching

Launching a coin

POST/api/v1/metadata

Store coin metadata

Stores the coin's image and details and returns the metadata uri to put on chain.

  • The metadata is hosted by halvd under /api/meta/{id}; the uri is what goes on chain, and on-chain metadata can't be edited later.
metadata bucket: 10 per 10 minutes per IP · not cached
name
stringform fieldrequired
Up to 32 characters.
symbol
stringform fieldrequired
1 to 10 of A–Z and 0–9; a leading $ is dropped, letters are uppercased.
image
fileform fieldrequired
PNG, JPG, GIF or WebP, at most 1 MB (checked by its bytes, not its name).
description
stringform field
Up to 280 characters.
x
stringform field
An X handle or an x.com / twitter.com link.
website
stringform field
An http(s) link.
Request
curl -X POST https://halvd.fun/api/v1/metadata \
  -F name="Sat Stacker" \
  -F symbol="STACK" \
  -F image=@stack.png \
  -F website="https://example.com"
Response 201 · captured on the fork, arrays shortened
{
  "id": "LOEl69iWayBy",
  "uri": "http://localhost:3112/api/meta/LOEl69iWayBy",
  "image": "http://localhost:3112/api/img/LOEl69iWayBy"
}
Errors
  • 400A field breaks a rule; the message names it.
  • 413The image is over 1 MB.
  • 415Not multipart/form-data, or the file isn't PNG, JPG, GIF or WebP.
  • 429Over the rate limit; see retryAfterSecs.
POST/api/v1/tx/launch

Launch transaction

An unsigned create-pool transaction on the tier and mode you pick, with an optional first buy in the same transaction.

launch bucket: 10 per 10 minutes per IP · not cached
wallet
stringJSON bodyrequired
The creator: signs, pays rent and fees (about 0.03 SOL), and is the pool creator.
mintPubkey
stringJSON bodyrequired
Public key of a keypair you just generated. It becomes the coin's mint and must sign too.
tier
stringJSON bodyrequired
Graduation target: 0.125, 0.25, 0.5 or 1 BTC. Permanent.sparkblockvaultwhole
mode
stringJSON bodyrequired
Who gets the 60% fee share. Permanent.creatorholderslongholdbtchash
name
stringJSON bodyrequired
Up to 32 characters (and bytes).
symbol
stringJSON bodyrequired
1 to 10 of A–Z and 0–9.
uri
stringJSON bodyrequired
Metadata JSON URL, http(s), at most 200 bytes. Use /metadata to get one.
btcAddress
stringJSON body
btc mode, required: the mainnet bc1 address the fee share is paid to. Bound for good by a memo the wallet signs.
hashDest
stringJSON body
hash mode, required: where found blocks go.holdersburn
hashRig
stringJSON body
hash mode, required: mine with the shared pool rig or alone.poolsolo
firstBuy
objectJSON body
Optional { amount, payWith: btc | sol }: whole BTC (from 1,000 sats, at most 90% of the target) or whole SOL (from 0.001). Lands in the launch transaction at the 1% fee.
Request
curl -X POST https://halvd.fun/api/v1/tx/launch \
  -H "content-type: application/json" \
  -d '{"wallet":"<your wallet>","mintPubkey":"<new mint public key>","tier":"spark","mode":"holders","name":"Sat Stacker","symbol":"STACK","uri":"<uri from /metadata>","firstBuy":{"amount":0.0001,"payWith":"btc"}}'
Response 200 · captured on the fork, arrays shortened
{
  "transaction": "AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA…",
  "version": "legacy",
  "mint": "9FsMyTkjg1vrp8S6nv2Vb9GLBrpkpZdQyKqNHGZ3NBiY",
  "pool": "9UVU8pMz1E8BqgBRTS4GCayrXvafFV2bQnWoQfyqwWhL",
  "config": "26yVFHMfzRBTJV7GcQonc6Lj1PbEGcNNBgny3PMrpFfp",
  "tier": "spark",
  "mode": "holders",
  "memo": null,
  "bytes": 943,
  "firstBuy": {
    "payWith": "btc",
    "spend": "20000",
    "btcIn": "20000",
    "coinsOut": 84206.32077816188,
    "minCoinsOut": 79996.00473925378
  },
  "blockhash": "SURFNETxSAFEHASHxxxxxxxxxxxxxxxxxxxxxxx5c7c",
  "lastValidBlockHeight": 23827,
  "signers": [
    "6GNru4XLq44kSQcfCnqYgcwv2e8M33g9rPyRUgvmFrcw",
    "9FsMyTkjg1vrp8S6nv2Vb9GLBrpkpZdQyKqNHGZ3NBiY"
  ]
}
Errors
  • 400A field breaks a rule, or the wallet can't cover rent, fees or the first buy.
  • 409That mint is already in use; generate a new keypair.
  • 429Over the rate limit; see retryAfterSecs.
  • 502SOL first buy: Jupiter has no route.
  • 503Launches are paused, or configs aren't set up on this cluster.
POST/api/v1/launch/record

Record a launch

After the launch lands: verifies the transaction and indexes the coin right away.

  • Optional: the indexer finds every launch on its own. Recording makes the coin page and /coins/{mint} complete immediately.
record bucket: 30 per 10 minutes per IP · not cached
signature
stringJSON bodyrequired
The launch transaction's signature.
Request
curl -X POST https://halvd.fun/api/v1/launch/record \
  -H "content-type: application/json" \
  -d '{"signature":"<launch signature>"}'
Response 201 · captured on the fork, arrays shortened
{
  "ok": true,
  "mint": "9FsMyTkjg1vrp8S6nv2Vb9GLBrpkpZdQyKqNHGZ3NBiY",
  "pool": "9UVU8pMz1E8BqgBRTS4GCayrXvafFV2bQnWoQfyqwWhL",
  "config": "26yVFHMfzRBTJV7GcQonc6Lj1PbEGcNNBgny3PMrpFfp",
  "tier": "spark",
  "mode": "holders",
  "creator": "6GNru4XLq44kSQcfCnqYgcwv2e8M33g9rPyRUgvmFrcw",
  "name": "API Stack",
  "symbol": "STACK",
  "uri": "http://localhost:3112/api/meta/LOEl69iWayBy",
  "memo": null,
  "btcAddress": "",
  "hashDest": "",
  "hashRig": "",
  "inserted": true
}
Errors
  • 400Not a signature, the tx failed, or it didn't create a pool on a halvd config.
  • 404Not visible yet. Retry in a few seconds.
  • 429Over the rate limit; see retryAfterSecs.
GET/api/v1/btc-address/check

Validate a Bitcoin address

Whether a Bitcoin address can be bound to a BTC address coin: mainnet bc1 only.

  • Native segwit (bc1q) and taproot (bc1p) on mainnet only. An invalid address is a 200 with valid: false and a reason.
read bucket: 240 per minute per IP · cached 1 h
address
stringqueryrequired
The Bitcoin address to check.
Request
curl "https://halvd.fun/api/v1/btc-address/check?address=bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq"
Response 200 · captured on the fork, arrays shortened
{
  "valid": true,
  "type": "p2wpkh",
  "normalized": "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq"
}
Errors
  • 400address missing or longer than 120 characters.
  • 429Over the rate limit; see retryAfterSecs.
11 / Endpoints#holders

Holder shares and claims

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

A coin's holder pot

What came into the coin's holder pot, what snapshots credited, what's been claimed, and the last snapshot.

read bucket: 240 per minute per IP · cached 10 s
mint
stringpathrequired
The coin's mint address.
Request
curl "https://halvd.fun/api/v1/coins/<mint>/holders"
Response 200 · captured on the fork, arrays shortened
{
  "mint": "9FsMyTkjg1vrp8S6nv2Vb9GLBrpkpZdQyKqNHGZ3NBiY",
  "symbol": "STACK",
  "mode": "holders",
  "potSats": 0,
  "inSats": 1500,
  "creditedSats": 1500,
  "claimedSats": 0,
  "owedSats": 1500,
  "walletsCredited": 1,
  "holdersCounted": 1,
  "snapshots": 1,
  "lastSnapshot": {
    "ts": 1792194228,
    "counted": 1,
    "creditedSats": 1500,
    "skipped": null
  }
}
Errors
  • 400A parameter is missing or malformed; the message names it.
  • 404No indexed coin with this mint.
  • 429Over the rate limit; see retryAfterSecs.
GET/api/v1/coins/{mint}/holders/{wallet}

Holder balance on one coin

What one wallet is owed by one coin, has claimed, and (Long hold) its current weight.

read bucket: 240 per minute per IP · cached 5 s
mint
stringpathrequired
The coin's mint address.
wallet
stringpathrequired
A wallet address.
Request
curl "https://halvd.fun/api/v1/coins/<mint>/holders/<wallet>"
Response 200 · captured on the fork, arrays shortened
{
  "wallet": "6GNru4XLq44kSQcfCnqYgcwv2e8M33g9rPyRUgvmFrcw",
  "mint": "9FsMyTkjg1vrp8S6nv2Vb9GLBrpkpZdQyKqNHGZ3NBiY",
  "symbol": "STACK",
  "name": "API Stack",
  "mode": "holders",
  "owedSats": 1500,
  "claimedSats": 0,
  "creditedSats": 1500,
  "pendingSats": 0,
  "balance": "498710819286"
}
Errors
  • 400A parameter is missing or malformed; the message names it.
  • 404No indexed coin with this mint.
  • 429Over the rate limit; see retryAfterSecs.
GET/api/v1/wallets/{wallet}/shares

All shares of a wallet

Every coin that owes or has paid this wallet a holder share.

read bucket: 240 per minute per IP · cached 5 s
wallet
stringpathrequired
A wallet address.
Request
curl "https://halvd.fun/api/v1/wallets/<wallet>/shares"
Response 200 · captured on the fork, arrays shortened
{
  "wallet": "6GNru4XLq44kSQcfCnqYgcwv2e8M33g9rPyRUgvmFrcw",
  "owedSats": 1500,
  "minClaimSats": 500,
  "claimable": true,
  "shares": [
    {
      "mint": "9FsMyTkjg1vrp8S6nv2Vb9GLBrpkpZdQyKqNHGZ3NBiY",
      "symbol": "STACK",
      "name": "API Stack",
      "mode": "holders",
      "owedSats": 1500,
      "claimedSats": 0,
      "creditedSats": 1500,
      "pendingSats": 0,
      "balance": "498710819286"
    }
  ]
}
Errors
  • 400A parameter is missing or malformed; the message names it.
  • 429Over the rate limit; see retryAfterSecs.
POST/api/v1/holders/claim/prepare

Start a claim

One transaction paying the wallet everything it's owed in cbBTC. The distributor has signed already; the wallet signs it unchanged.

claim bucket: 12 per minute per IP · not cached
wallet
stringJSON bodyrequired
The holder. Must be a regular (on-curve) key: it signs and pays the network fee.
mints
string[]JSON body
Claim only these coins (up to 50). Default: everything owed.
Request
curl -X POST https://halvd.fun/api/v1/holders/claim/prepare \
  -H "content-type: application/json" \
  -d '{"wallet":"<your wallet>"}'
Response 200 · captured on the fork, arrays shortened
{
  "claimId": "2011254774982b6ad7ea8555",
  "transaction": "AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA…",
  "version": "legacy",
  "totalSats": 1500,
  "items": [
    {
      "mint": "9FsMyTkjg1vrp8S6nv2Vb9GLBrpkpZdQyKqNHGZ3NBiY",
      "sats": 1500
    }
  ],
  "expiresAt": 1792194348,
  "signers": [
    "6GNru4XLq44kSQcfCnqYgcwv2e8M33g9rPyRUgvmFrcw"
  ]
}
Errors
  • 400Nothing owed, or under the 500-sat minimum.
  • 409Another claim for this wallet is in progress (locks last two minutes).
  • 429Over the rate limit; see retryAfterSecs.
  • 503The distributor is between top-ups. Retry in a few minutes.
POST/api/v1/holders/claim/submit

Hand in a signed claim

Checks the signed claim is byte-for-byte the prepared one, sends it and settles the books.

  • The wallet signs with signTransaction and your app posts the result here; halvd broadcasts it, waits for confirmation and only then marks the sats claimed. If the wallet inserted anything while signing, the bytes no longer match and the answer is 422.
claim bucket: 12 per minute per IP · not cached
claimId
stringJSON bodyrequired
From prepare.
signedTx
stringJSON bodyrequired
The prepared transaction after the wallet signed it, base64.
Request
curl -X POST https://halvd.fun/api/v1/holders/claim/submit \
  -H "content-type: application/json" \
  -d '{"claimId":"<claimId>","signedTx":"<base64 signed by the wallet>"}'
Response 200 · captured on the fork, arrays shortened
{
  "claimId": "2011254774982b6ad7ea8555",
  "status": "confirmed",
  "sig": "32UG99ab2YjN7VEKphKVuYNbhLT8S8Y53R47CySUJmnra4z8w5CKowaD81qg9CuzNTTubP7B5ZAYMysM6AHcAg1w",
  "totalSats": 1500
}
Errors
  • 400A parameter is missing or malformed; the message names it.
  • 404Unknown claimId.
  • 409Already sent, or no longer pending.
  • 410The two-minute lock lapsed. Prepare again.
  • 422The transaction was changed, or the wallet's signature is missing or invalid.
  • 429Over the rate limit; see retryAfterSecs.
  • 502Sending failed; status says whether it can still land.
GET/api/v1/holders/claim/status

Follow a claim

Where a claim stands: pending, sending, confirmed, failed or expired.

live bucket: 90 per minute per IP · not cached
id
stringqueryrequired
The claimId.
Request
curl "https://halvd.fun/api/v1/holders/claim/status?id=<claimId>"
Response 200 · captured on the fork, arrays shortened
{
  "id": "2011254774982b6ad7ea8555",
  "wallet": "6GNru4XLq44kSQcfCnqYgcwv2e8M33g9rPyRUgvmFrcw",
  "status": "confirmed",
  "totalSats": 1500,
  "items": [
    {
      "mint": "9FsMyTkjg1vrp8S6nv2Vb9GLBrpkpZdQyKqNHGZ3NBiY",
      "sats": 1500
    }
  ],
  "sig": "32UG99ab2YjN7VEKphKVuYNbhLT8S8Y53R47CySUJmnra4z8w5CKowaD81qg9CuzNTTubP7B5ZAYMysM6AHcAg1w",
  "error": null,
  "createdAt": 1792194228,
  "expiresAt": 1792194348
}
Errors
  • 400A parameter is missing or malformed; the message names it.
  • 404Unknown claim.
  • 429Over the rate limit; see retryAfterSecs.
12 / Endpoints#payouts

BTC payouts and hashrate

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

Payout ledger

A BTC address coin's bound address, what's owed, the payout rule in force, and every payout with its receipts.

read bucket: 240 per minute per IP · cached 10 s
mint
stringpathrequired
The coin's mint address.
Request
curl "https://halvd.fun/api/v1/coins/<mint>/payouts"
Response 200 · captured on the fork, arrays shortened
{
  "mint": "2Q9AxwQkre8RxvgC9AdhLwCrXFbN8NLV8BvQSmGTLry3",
  "mode": "btc",
  "address": "bc1p5d7rjq7g6rdk2yhzks9smlaqtedr4dekq08ge8ztwac72sfr9rusxg3297",
  "addressValid": true,
  "addressType": "p2tr",
  "owedSats": 0,
  "paidSats": 0,
  "inSats": 0,
  "lastPayoutAt": null,
  "rule": {
    "minSats": 12000,
    "maxFeePct": 10,
    "relaxed": false
  },
  "lastCheck": null,
  "payouts": []
}
Errors
  • 400A parameter is missing or malformed; the message names it.
  • 404Not indexed, or not a btc mode coin.
  • 429Over the rate limit; see retryAfterSecs.
GET/api/v1/coins/{mint}/rig

Rig detail

A Hashrate coin's rig: state, hash bought, claims, fundings, bids and the blocks it took part in.

read bucket: 240 per minute per IP · cached 15 s
mint
stringpathrequired
The coin's mint address.
Request
curl "https://halvd.fun/api/v1/coins/<mint>/rig"
Response 200 · captured on the fork, arrays shortened
{
  "rig": {
    "mint": "2gwc5BPrwEDnbh27WGMsB9hkovpeeAm6iPe4M5Patr3J",
    "name": "Keeper Test KTD",
    "symbol": "KTD",
    "image": "http://127.0.0.1:54404/img/KTD.png",
    "rig": "solo",
    "dest": "burn",
    "address": "bc1qq58ftdp7sv8gr0qyjp45vmkagkathjanz09dru",
    "worker": "2gwc5BPrwEDn",
    "state": "idle",
    "speedPh": 0,
    "sharesM": 0,
    "phHours": 0,
    "spentSats": 0,
    "potSats": 0,
    "fundedSats": 0,
    "budgetSats": 0,
    "claimedSats": 0,
    "nextPoolShare": null,
    "blocks": 0
  },
  "config": {
    "connected": false,
    "missing": [
      "BRAIINS_TOKEN",
      "BRAIINS_DEPOSIT"
    ],
    "poolAddress": "bc1qlye2k5652vs2ymdfth8j4n90dezr34lvln9crm",
    "stratum": "stratum+tcp://solo.ckpool.org:3333",
    "fundMinSats": 11000,
    "bidMinSats": 10000,
    "maxBridgeFee": 0.1,
    "platformShare": 0.25,
    "keeperBlockShare": 0.05,
    "finderShare": 0.1,
    "maturity": 100
  },
  "fundings": [],
  "bids": [],
  "blocks": [],
  "claims": []
}
Errors
  • 400A parameter is missing or malformed; the message names it.
  • 404Not a Hashrate coin.
  • 429Over the rate limit; see retryAfterSecs.
GET/api/v1/rigs

All rigs

All Hashrate coins' rigs with totals, and whether the operator's hashrate account is connected.

read bucket: 240 per minute per IP · cached 15 s
Request
curl "https://halvd.fun/api/v1/rigs"
Response 200 · captured on the fork, arrays shortened
{
  "stats": {
    "speedPh": 0,
    "mining": 0,
    "hashCoins": 31,
    "phHours": 0,
    "spentSats": 0,
    "blocks": 0,
    "poolBlocks": 0,
    "soloBlocks": 0,
    "rewardSats": 0,
    "creditedSats": 0
  },
  "rigs": [
    {
      "mint": "9MQtLqtxG2zVzrxHMFqYfJN4nRXoGpB2ZnaotXg3tc9o",
      "name": "Halving Test Coin",
      "symbol": "HTEST",
      "image": "http://localhost:3112/api/img/X-0_swH18Yhq",
      "rig": "solo",
      "dest": "burn",
      "address": "bc1q330xltq2kndhyqdl2u2gmk4na7ems027mwl3tq",
      "worker": "9MQtLqtxG2zV",
      "state": "idle",
      "speedPh": 0,
      "sharesM": 0,
      "phHours": 0,
      "spentSats": 0,
      "potSats": 0,
      "fundedSats": 0,
      "budgetSats": 0,
      "claimedSats": 0,
      "nextPoolShare": null,
      "blocks": 0
    },
    {
      "mint": "spGwBAnMnWtrB3LrNkY2X5TzUhKpH9psktmX4wWPCvH",
      "name": "Keeper Test KTD",
      "symbol": "KTD",
      "image": "http://127.0.0.1:62740/img/KTD.png",
      "rig": "solo",
      "dest": "burn",
      "address": "bc1q5cvl4lf58ydz4ql053gczaw9cfl6wz02rk9zas",
      "worker": "spGwBAnMnWtr",
      "state": "idle",
      "speedPh": 0,
      "sharesM": 0,
      "phHours": 0,
      "spentSats": 0,
      "potSats": 0,
      "fundedSats": 0,
      "budgetSats": 0,
      "claimedSats": 0,
      "nextPoolShare": null,
      "blocks": 0
    }
  ],
  "config": {
    "connected": false,
    "missing": [
      "BRAIINS_TOKEN",
      "BRAIINS_DEPOSIT"
    ],
    "poolAddress": "bc1qlye2k5652vs2ymdfth8j4n90dezr34lvln9crm",
    "stratum": "stratum+tcp://solo.ckpool.org:3333",
    "fundMinSats": 11000,
    "bidMinSats": 10000,
    "maxBridgeFee": 0.1,
    "platformShare": 0.25,
    "keeperBlockShare": 0.05,
    "finderShare": 0.1,
    "maturity": 100
  },
  "updatedAt": 1792194011
}
Errors
  • 429Over the rate limit; see retryAfterSecs.
GET/api/v1/blocks

Blocks found

Bitcoin blocks halvd's rigs found, newest first, with how each splits and where it stands.

read bucket: 240 per minute per IP · cached 15 s
limit
integerquery
Blocks, 1 to 200.Default 50.
Request
curl "https://halvd.fun/api/v1/blocks?limit=10"
Response 200 · captured on the fork, arrays shortened
{
  "stats": {
    "speedPh": 0,
    "mining": 0,
    "hashCoins": 31,
    "phHours": 0,
    "spentSats": 0,
    "blocks": 0,
    "poolBlocks": 0,
    "soloBlocks": 0,
    "rewardSats": 0,
    "creditedSats": 0
  },
  "blocks": []
}
Errors
  • 400A parameter is missing or malformed; the message names it.
  • 429Over the rate limit; see retryAfterSecs.
13 / Endpoints#stream

Event stream

Format
Server-Sent Events: event: is the type, data: one line of JSON, id: where the stream stands. Every payload has at, the unix second of the change.
Delay
Events come from halvd's index, which reads pools every few seconds; the stream checks it every 2 s. Expect events seconds after the chain, not milliseconds.
On connect
A hello event with the current id. Then live events, and a comment line every 15 s so proxies keep the connection open.
Resuming
An id is a position in halvd's tables, so a client that drops off can pick up exactly where it stopped, even after hours: pass the last id in a Last-Event-ID header (a browser EventSource sends it on its own when it reconnects) or as ?since=. Up to 1,000 missed events are replayed before the live ones; beyond that you get a single gap event and should catch up through the REST endpoints.
GET/api/v1/events

Live events

Server-Sent Events for new coins, epochs, graduations, trades, burns and boosts. Resumable with Last-Event-ID.

stream bucket: 12 per minute per IP · a stream, not cached
since
stringquery
Resume after this event id (same as the Last-Event-ID header).
Last-Event-ID
stringheader
Sent by EventSource on reconnect. Replays what happened after that id, up to 1,000 events.
Request
curl -N https://halvd.fun/api/v1/events

# resume after the last id you saw
curl -N -H "Last-Event-ID: <id>" https://halvd.fun/api/v1/events
Stream · captured on the fork
retry: 3000

id: 114-151-27
event: hello
data: {"cluster":"fork","cursor":"114-151-27","pollMs":2000,"heartbeatS":15,"types":["coin.created","coin.epoch","coin.graduated","trade","burn","boost"]}

id: 114-0-0
event: coin.created
data: {"mint":"9FsMyTkjg1vrp8S6nv2Vb9GLBrpkpZdQyKqNHGZ3NBiY","name":"API Stack","symbol":"STACK","tier":"spark","mode":"holders","creator":"6GNru4XLq44kSQcfCnqYgcwv2e8M33g9rPyRUgvmFrcw","pool":"9UVU8pMz1E8BqgBRTS4GCayrXvafFV2bQnWoQfyqwWhL","image":"http://localhost:3112/api/img/LOEl69iWayBy","createdAt":1792194168,"at":1792194168}

id: 114-151-0
event: trade
data: {"mint":"9FsMyTkjg1vrp8S6nv2Vb9GLBrpkpZdQyKqNHGZ3NBiY","symbol":"STACK","tier":"spark","at":1792194225,"venue":"curve","side":"buy","btcSats":99000,"priceSats":0.24196530008234407,"reserveSats":118800}

: beat 1792234888
Errors
  • 400since isn't an event id.
  • 429Over the connection rate, or 4 streams already open from this IP.
  • 503The server's stream capacity is full. Retry after Retry-After.

Event types

coin.created

A coin entered halvd's index: recorded right after its launch, or found by the indexer.

mint, name, symbol, tier, mode, creator, pool, image, createdAt, at

id: 114-0-0
event: coin.created
data: {
  "mint": "9FsMyTkjg1vrp8S6nv2Vb9GLBrpkpZdQyKqNHGZ3NBiY",
  "name": "API Stack",
  "symbol": "STACK",
  "tier": "spark",
  "mode": "holders",
  "creator": "6GNru4XLq44kSQcfCnqYgcwv2e8M33g9rPyRUgvmFrcw",
  "pool": "9UVU8pMz1E8BqgBRTS4GCayrXvafFV2bQnWoQfyqwWhL",
  "image": "http://localhost:3112/api/img/LOEl69iWayBy",
  "createdAt": 1792194168,
  "at": 1792194168
}
coin.epoch

A buy took a coin's curve price into an epoch it had never reached before. Selling back under a boundary and buying again doesn't repeat it.

mint, symbol, tier, from, to (both 1 to 4), priceSats, at

id: 114-150-0
event: coin.epoch
data: {
  "mint": "FEJEf6fubFKfdgfA3G76MMc32ZoRu9EebcQ7ZA8BwVjs",
  "symbol": "KTA",
  "tier": "spark",
  "at": 1792194225,
  "from": 1,
  "to": 4,
  "priceSats": 3.7523401025205874
}
coin.graduated

The indexer saw the sold-out curve migrate to its DAMM v2 pool. Quotes and trades move there from now on.

mint, symbol, name, tier, dammPool, priceSats, graduatedAt, at

id: 114-143-0
event: coin.graduated
data: {
  "mint": "AL6sL2cgQiZSSKmp65stYgmVAxdFrNorXnDpbLHyapeb",
  "symbol": "KTA",
  "tier": "spark",
  "at": 1792193000,
  "name": "Keeper Test KTA",
  "dammPool": "Cd8JRpEVmKYUY6ssTzTVwfSGH2nQSSu8U175Gt3GqhJi",
  "priceSats": 3.7523401025205874,
  "graduatedAt": 1792192954
}
trade

A pool changed and BTC moved. Side comes from the direction of the BTC reserve; trades that land between two reads arrive as one with the net change.

mint, symbol, tier, venue (curve | dammV2), side, btcSats, priceSats, reserveSats, at

id: 114-151-0
event: trade
data: {
  "mint": "9FsMyTkjg1vrp8S6nv2Vb9GLBrpkpZdQyKqNHGZ3NBiY",
  "symbol": "STACK",
  "tier": "spark",
  "at": 1792194225,
  "venue": "curve",
  "side": "buy",
  "btcSats": 99000,
  "priceSats": 0.24196530008234407,
  "reserveSats": 118800
}
burn

A burn reached the ledger: the keeper's $HALVD buyback, a graduated curve's dust, or a mined block's burn share.

sig, kind (buyback | leftover | block), mint, amount, btcSpent, wallet, at

id: 114-151-27
event: burn
data: {
  "sig": "2oNRjurPzSeYLnNdoFwvXfpadoz1JB4RjVCR2rEmJMiuqmkrDBQgJVs2epEw2wqVX1VqQFagZJSJkf3HmXZEv6Wn",
  "kind": "leftover",
  "mint": "AL6sL2cgQiZSSKmp65stYgmVAxdFrNorXnDpbLHyapeb",
  "amount": 2100.000005,
  "btcSpent": 0,
  "wallet": "BdcxkPEKvPJ74vX6gKRXhCgV4ZUAkCaCnkXuUES3nMSY",
  "at": 1792193266
}
boost

Someone burned $HALVD to boost a coin.

sig, mint (the boosted coin), burnedMint, wallet, amount, at

id: 114-151-23
event: boost
data: {
  "sig": "JVqC1BmYS7iTbwnsAUAw726pqubVAnUhJ24b57yTsZraLdzWwwoGScxW9byPRSyLm2cBusEYdTC2dT5BRaCCiKo",
  "mint": "F1m1eZZMvVzwEwWRGuMVKQqhhPKQf6yzv28CDZgRkFAy",
  "burnedMint": "2sNyqhYwx9TQ6BrMCscPowKnpYn3oWiQ4bHjyu5iXy4G",
  "wallet": "3p88wLtDR5knZiktNStvhZd1iuPewGUYAccA1oUgVPmn",
  "amount": 1500,
  "at": 1792190907
}
JavaScript · browser
const stream = new EventSource("https://halvd.fun/api/v1/events");

stream.addEventListener("coin.epoch", (e) => {
  const x = JSON.parse(e.data);
  console.log(`$${x.symbol} reached epoch ${x.to} at ${x.priceSats.toFixed(3)} sats`);
});
stream.addEventListener("trade", (e) => {
  const t = JSON.parse(e.data);
  if (t.btcSats >= 1_000_000) console.log(`big ${t.side}: ${t.btcSats / 1e8} BTC of $${t.symbol}`);
});
// EventSource reconnects by itself and sends Last-Event-ID, so nothing is missed
JavaScript · Node
// Node 20+: no library needed
let last = ""; // keep the last id to resume after a restart

async function listen() {
  const res = await fetch("https://halvd.fun/api/v1/events", { headers: last ? { "Last-Event-ID": last } : {} });
  if (!res.ok) throw new Error((await res.json()).error);
  let pending = "";
  for await (const chunk of res.body.pipeThrough(new TextDecoderStream())) {
    pending += chunk;
    const frames = pending.split("\n\n");
    pending = frames.pop();
    for (const frame of frames) {
      const field = (k) => frame.match(new RegExp(`^${k}: (.*)$`, "m"))?.[1];
      if (field("id")) last = field("id");
      if (field("event") === "coin.graduated") console.log("graduated", JSON.parse(field("data")).symbol);
    }
  }
}
14 / Objects#objects

The shapes you'll see most

Field by field. Every other response is described in the OpenAPI document.

Coin/coins, /coins/{mint}
mint
string
The coin's mint (base58 address).
pool
string
Its Meteora DBC pool.
config
string
The DBC config it launched on: one per tier and mode.
tier
string
Graduation target tier. (spark, block, vault, whole)
mode
string
Who receives the 60% fee share. (creator, holders, longhold, btc, hash)
creator
string
The wallet that launched it.
name
string
Name from its metadata (can be empty for a moment after launch).
symbol
string
Ticker, without the $.
image
string | null
Image URL from its metadata.
description
string
Description from its metadata.
xUrl
string | null
X link from its metadata.
website
string | null
Website from its metadata.
createdAt
integer
Unix seconds the pool opened.
createSig
string | null
The launch transaction's signature, once known.
priceSats
number
Sats per coin now: from the curve, or from the DAMM v2 pool after graduation.
priceUsd
number | null
Dollars per coin at the current BTC/USD (null if no price source answered).
fdvBtc
number
priceSats × 21,000,000 ÷ 10^8.
mcapBtc
number
priceSats × coins in circulation ÷ 10^8. On the curve that's coins sold; after graduation the whole supply.
epoch
integer
1 to 4: the curve epoch the price sits in. A graduated coin reads 4.
graduated
boolean
True once the curve sold out and the coin moved to its DAMM v2 pool.
raisedSats
integer
cbBTC on the curve, in sats (the target once graduated).
targetSats
integer
The tier's graduation target, in sats.
progress
number
raisedSats ÷ targetSats, 0 to 1.
soldCoins
number
Coins bought off the curve so far.
toNextHalving
number
Coins left in the current epoch before the price step (epoch 4: before graduation).
dammPool
string | null
The DAMM v2 pool once graduated.
graduatedAt
integer | null
Unix seconds it graduated.
volumeSats
integer
All-time BTC volume the indexer saw, in sats.
trades
integer
Pool changes the indexer saw (about one per trade).
boost
number
Boost left now, in whole $HALVD. Each boost burn fades to zero over 24 hours.
btcAddress
string | null
btc mode: the Bitcoin address bound at launch.
hashDest
string | null
hash mode: where found blocks go. (holders, burn)
hashRig
string | null
hash mode: pool or solo mining. (pool, solo)
Quote/quote, and inside every trade
mint
string
The coin.
venue
string
curve before graduation, dammV2 after. (curve, dammV2)
side
string
buy or sell. (buy, sell)
asset
string
What a buy pays with, or what a sell pays out in. (btc, sol)
inAmount
string
Atoms going in.
outAmount
string
Atoms expected out.
minOut
string
The floor after slippage. The transaction fails below it.
feeBps
integer
The pool fee on this trade, live: up to 4999 in a coin's first seconds, then 100.
priceImpact
number
How much worse than spot, fee excluded: 0.012 = 1.2%.
inUi
number
inAmount as a decimal.
outUi
number
outAmount as a decimal.
minOutUi
number
minOut as a decimal.
inSymbol
string
cbBTC, SOL or coin.
outSymbol
string
cbBTC, SOL or coin.
spotSats
number
Sats per coin before the trade.
avgSats
number
Sats per coin this trade averages, fee included.
poolSats
string
Sats that reach (buy) or leave (sell) the pool.
refundSats
string
Curve buys: sats handed back because the curve ends first.
graduates
boolean
This buy fills the curve: the coin graduates.
ageSeconds
integer
Seconds since the pool opened, by chain time.
slippageBps
integer
Slippage used for minOut.
jup
object · optional
SOL trades: the Jupiter leg.
Transaction/tx/buy, /tx/sell, /tx/boost
transaction
string
The serialized transaction, base64.
version
string | integer
legacy → Transaction.from(bytes); 0 → VersionedTransaction.deserialize(bytes). (legacy, 0)
bytes
integer
Serialized size (at most 1232).
signers
string[]
Public keys that must sign, fee payer first.
mint
string · optional
The coin.
quote
Quote · optional
amount
number · optional
Boost: whole $HALVD burned.
memo
string · optional
Boost: the memo the transaction carries.
15 / From the chain#chain

Skip the API entirely

Nothing here needs halvd's servers. The coins are ordinary Meteora DBC pools; what marks one as halvd's is its config, and there are 20 of them, listed at the bottom of this section.

Programs
Meteora DBC dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN for the curve and Meteora DAMM v2 cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG after graduation. Trade them with @meteora-ag/dynamic-bonding-curve-sdk and @meteora-ag/cp-amm-sdk.
Finding coins
List the DBC pools whose config is one of the 20 (a memcmp on the config field), or read the configs from /api/v1 and /api/addresses.
Buys
Use DBC's swap2 with partial fill on the curve: an exact-in buy larger than what's left would fail, partial fill stops at the end and refunds.
TypeScript · deriving the pools
import { PublicKey } from "@solana/web3.js";
import { DAMM_V2_MIGRATION_FEE_ADDRESS, deriveDammV2PoolAddress, deriveDbcPoolAddress } from "@meteora-ag/dynamic-bonding-curve-sdk";

const CBBTC = new PublicKey("cbbtcf3aa214zXHbiAZQwf4122FBYbraNdFqgw4iMij");

// the curve: one pool per (quote mint, coin mint, config)
const curve = deriveDbcPoolAddress(CBBTC, mint, config); // config: one of the 20 below

// after graduation: the DAMM v2 pool DBC migrates into
const pool = deriveDammV2PoolAddress(DAMM_V2_MIGRATION_FEE_ADDRESS[6], mint, CBBTC);

Memos

Plain SPL Memo instructions. The launch memos are signed by the creator inside the launch transaction; anything else (no memo, two memos, an unsigned one) binds nothing.

BTC address launchhalvd payout v1 <bc1 address>
Hashrate launchhalvd hash v1 <holders|burn> <pool|solo>
Boost burnhalvd boost v1 <coin mint>
Keeper burnhalvd burn
Treasury transferhalvd treasury
Platform sharehalvd platform share
Holder claimhalvd claim

Addresses on this cluster

Reading addresses…
16 / Versioning#versioning

v1 only grows

What you build against today keeps working.

Growth only
v1 may get new endpoints, new optional parameters and new fields in its answers. Write clients that skip keys they don't recognise and they'll keep working.
Breaking changes
They wait for a v2 path, and v1 keeps answering next to it for a deprecation period announced here.
Private routes
Paths under /api/ without v1 exist for halvd's own pages. Their shapes follow the site's needs from one release to the next, so don't depend on them.
Rules
Off-chain thresholds (holder minimum $10, claims from 500 sats, payouts from 12,000 sats) can be tuned; read them from the index rather than hard-coding them. On-chain rules (supply, curve, fees) are fixed by the configs. See the rules.

Examples on this page were captured from a local copy of mainnet and shortened. Nothing here is a promise about price or returns; burns of $HALVD reduce its supply and that is all.