REST API for corporate BTC, ETH & SOL treasuries
Same data that powers the dashboard. SEC filings parsed in minutes, holdings reconciled nightly against bitbo.io, JSON + CSV bulk export. Keep your dashboards, spreadsheets, and models fed.
Quick start
Authenticate with the x-api-key header:
curl https://www.corpstacking.com/api/v1/stats \
-H "x-api-key: cs_live_YOUR_KEY"All responses are JSON with a content-type: application/json header. CSV export available at /export?format=csv.
Rate limits by plan
| Plan | API access | Req/min | Req/month |
|---|---|---|---|
| Free | — | — | — |
| Pro ($9/mo) | ✓ | 60 | 1,000 |
| Pro+ ($19/mo) | ✓ | 300 | 10,000 |
| API Pro ($499/mo) | ✓ | 2,000 | 500,000 |
| Team (Contact sales) | ✓ | 3,000 | 1,000,000 |
Rate-limit headers returned on every response: x-ratelimit-limit, x-ratelimit-remaining, x-ratelimit-reset.
Endpoints
/api/v1/statsProTotal BTC held, total USD value at current price, entity count, and unrealized PnL across the tracked universe (companies, ETFs, and governments combined).
tokenquerystringToken to roll up. Defaults to bitcoin. Non-bitcoin values require Pro+.{
"token": "bitcoin",
"total_amount": 3830257,
"total_usd": 306420560000,
"entity_count": 248,
"unrealized_pnl_usd": 78900000000,
"purchase_count": 7086
}/api/v1/treasuriesProFull list of tracked entities (public companies, private companies, ETFs, and governments) with holdings and cost basis. Sorted by holdings descending. Use entity_type to pull a single segment (e.g. just ETFs or just governments).
tokenquerystringFilter to entities whose primary treasury asset is this token. Defaults to bitcoin. Non-bitcoin values require Pro+.entity_typequerystringLimit to one segment. Omit (or pass all) to return every segment.limitqueryintegerMax rows to return. Default 100, max 200.offsetqueryintegerRow offset for pagination. Default 0.[
{
"ticker": "MSTR",
"name": "Strategy",
"slug": "microstrategy",
"country": "US",
"flag_emoji": "🇺🇸",
"logo_domain": "strategy.com",
"logo_initial": "S",
"btc_holdings": 818869,
"avg_price_usd": 75577,
"total_cost_usd": 59013000000,
"last_purchase": "2026-04-13"
}
]/api/v1/treasuries/{slug}ProEntity metadata + its last 20 treasury events (buys + sells). Replace {slug} in the path with the slug from /treasuries.
slugpathstringrequiredTreasury slug (e.g. microstrategy).{
"ticker": "MSTR",
"name": "Strategy",
"btc_holdings": 818869,
"purchases": [
{ "date": "2026-04-13", "btc_amount": 13927, "usd_amount": 1001000000, "filing_url": "https://sec.gov/..." }
]
}/api/v1/activityProGlobal feed of recent treasury events across every tracked entity. Includes both buys (positive amount) and sells (negative amount, e.g. ETF daily outflows). Each row is a discrete, citable disclosure (an SEC filing, a fund-administrator daily flow, an on-chain transfer, etc.). Note: governments report their holdings as official headline figures, not as individual dated transactions, so filtering this feed to a government returns an empty list — that is by design, not a gap. The current government position is on /treasuries/{slug}.
tokenquerystringFilter to a specific token. Defaults to bitcoin. Non-bitcoin values require Pro+.companyquerystringFilter to a single entity by its treasury slug.entity_typequerystringLimit to one segment. Governments have no per-event activity (see note above).sincequerystringISO date — only include events on or after this date.orderquerystringSort direction by event date. Default desc (newest first).limitqueryintegerPage size. Default 50, max 100.offsetqueryintegerRow offset for pagination. Default 0.{
"data": [
{
"id": "abc-123",
"token_id": "bitcoin",
"amount": 13927,
"btc_amount": 13927,
"usd_amount": 1001000000,
"price_per_btc": 71870,
"purchase_date": "2026-04-13",
"source": "sec_edgar",
"sec_accession": "0000950170-26-000123",
"filing_url": "https://sec.gov/...",
"company": {
"ticker": "MSTR",
"name": "Strategy",
"slug": "microstrategy",
"country": "US",
"flag_emoji": "🇺🇸",
"logo_domain": "strategy.com",
"logo_initial": "S"
}
}
],
"meta": { "total": 3450, "limit": 50, "offset": 0, "token": "bitcoin", "entity_type": "all" }
}/api/v1/marketProLatest prices for 12 tracked tokens, plus global market cap, 24h volume, BTC/ETH dominance, and Fear & Greed index.
{
"tokens": [ { "id": "bitcoin", "symbol": "BTC", "price_usd": 83512.44, "change_24h": -1.23 } ],
"stats": { "total_market_cap": 3200000000000, "btc_dominance": 58.2, "fear_greed_value": 62 }
}/api/v1/tokensProList of tokens that have tracked treasury holdings. Pro+ unlocks non-bitcoin tokens.
[
{ "id": "bitcoin", "symbol": "BTC", "name": "Bitcoin", "entity_count": 248 },
{ "id": "ethereum", "symbol": "ETH", "name": "Ethereum", "entity_count": 41 },
{ "id": "solana", "symbol": "SOL", "name": "Solana", "entity_count": 32 }
]/api/v1/exportProCSV or JSON bulk export of discrete treasury events (one row per disclosed buy/sell, with its per-(entity, token) data-confidence tier). Pro+ includes non-BTC tokens. Governments have no per-event rows here (their holdings are headline figures — use /treasuries).
formatquerystringrequiredExport format.tokenquerystringFilter to a specific token. Defaults to bitcoin. Non-bitcoin values require Pro+.entity_typequerystringLimit to one segment.companyquerystringFilter to a single entity by its treasury slug.sincequerystringISO date — only include events on or after this date.limitqueryintegerMax rows. Default 10,000, max 50,000.company,ticker,country,token_id,amount,usd_amount,price_per_unit,purchase_date,total_holdings_after,source,data_confidence_tier,data_confidence_sources
Strategy,MSTR,US,bitcoin,13927,1001000000,71870,2026-04-13,818869,sec_edgar,verified,sec_edgar
BlackRock iShares Bitcoin Trust,IBIT,US,bitcoin,5859,.../api/v1/usageProLive counts for the calling API key — requests this minute, requests this month, and the ceilings your plan enforces.
{
"plan": "pro_plus",
"minute": { "used": 3, "limit": 60 },
"monthly": { "used": 412, "limit": 10000 }
}Live playground
Stored in your browser session only. Never logged or transmitted beyond the request itself.
GET /api/v1/statsMCP server (AI agents)
For Claude Desktop, Claude Code, Cursor, ChatGPT custom GPTs, and any other client that speaks the Model Context Protocol, we host an MCP server at https://www.corpstacking.com/api/mcp/mcp. Same API key, same plan, same monthly quota — eight read-only tools wrapped around this same /v1 surface. Full reference and copy-paste configs for the popular clients at /mcp.
Embed widgets (free, no key)
Drop a live treasury widget on any page with a single <iframe>. No API key, no sign-up — the widget reads the same verified holdings shown on the site and refreshes on its own. Point it at any company by its page name:
<iframe src="https://www.corpstacking.com/api/embed/widget?company=strategy" width="420" height="180" frameborder="0" title="Strategy bitcoin treasury — CorpStacking"></iframe>
Options: company(the company's page name, e.g. strategy), theme (light or dark), variant, and layout for size. Signed-in users get a point-and-click builder with a live preview at /widgets.
Webhooks (API Pro)
API Pro subscribers can receive signed HTTP callbacks whenever a qualifying event fires. Three event types today: purchase.detected, holding.updated, and price.threshold. Delivery is at-least-once; each envelope carries a stable id you can use to dedupe.
curl -X POST https://www.corpstacking.com/api/v1/webhooks \
-H "x-api-key: cs_live_YOUR_KEY" \
-H "content-type: application/json" \
-d '{
"url": "https://your-app.example/corpstacking-webhook",
"events": ["purchase.detected", "holding.updated"],
"description": "prod pipeline"
}'Response returns a secret field (prefix whsec_cs_). Store it now — subsequent GET /webhooks only shows the masked preview.
POST https://your-app.example/corpstacking-webhook
content-type: application/json
user-agent: CorpStacking-Webhooks/1.0
x-corpstacking-event: purchase.detected
x-corpstacking-event-id: 9f0c…e2a1
x-corpstacking-timestamp: 1745078400
x-corpstacking-signature: t=1745078400,v1=5a8b…c9d0
{
"id": "9f0c…e2a1",
"type": "purchase.detected",
"created_at": "2026-04-19T14:00:00Z",
"data": {
"company": { "id": "uuid", "ticker": "MSTR" },
"token_id": "bitcoin",
"amount": 1250,
"usd_amount": 82500000,
"total_holdings_after": 214046,
"purchase_date": "2026-04-19",
"sec_accession": "0001104659-26-000...",
"filing_url": "https://sec.gov/..."
}
}import { createHmac, timingSafeEqual } from 'crypto'
function verify(secret, rawBody, header) {
const parts = Object.fromEntries(header.split(',').map(p => p.split('=', 2)))
const t = parts.t, v1 = parts.v1
if (!t || !v1) return false
const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex')
const a = Buffer.from(v1, 'hex'), b = Buffer.from(expected, 'hex')
return a.length === b.length && timingSafeEqual(a, b)
}
// Express handler — rawBody must be the unparsed request body bytes.
app.post('/corpstacking-webhook', express.raw({ type: '*/*' }), (req, res) => {
const ok = verify(process.env.CORPSTACKING_SECRET, req.body.toString(), req.header('x-corpstacking-signature'))
if (!ok) return res.sendStatus(400)
const event = JSON.parse(req.body.toString())
// ... dedupe on event.id, then process
res.sendStatus(200)
})Reject requests where the timestamp is more than 5 minutes old to prevent replay attacks. We retry on 5xx/network with exponential backoff up to 24h; 4xx is treated as permanent failure.
curl "https://www.corpstacking.com/api/v1/webhooks/events?subscription_id=SUB_ID&status=failed" \
-H "x-api-key: cs_live_YOUR_KEY"After 20 consecutive failures (~24h under the backoff curve), the subscription is auto-paused with paused_reason: too_many_failures. DELETE and recreate the subscription, or contact support to resume.
Errors
Errors are JSON with a stable code field. Treat codes as the source of truth; messages are human-readable and may change.
401 unauthorized — missing or invalid API key402 upgrade_required — endpoint requires a higher plan403 token_gated — token requires Pro+429 rate_limited — check x-ratelimit-reset429 quota_exceeded — monthly cap hit500 server_error — logged + auto-reported