Bitcoin Treasury Company Data Feed
CEBE Tracker publishes free JSON endpoints covering the tracked universe. Companies serves the latest verified balance sheet and CEBE computation per company: BTC holdings, debt, preferred stock, cash, share counts, Senior Claims %, CEBE in satoshis per share, and CEBE mNAV. Instruments serves the capital structure those figures are computed from, one object per filed instrument. Deals serves the capital events between the snapshots. No API key. CORS is enabled for any origin. Free to use with attribution to cebetracker.io, under the Terms of Use.
Endpoint
GET https://cebetracker.io/api/v1/companies.json
Try it:
curl -s https://cebetracker.io/api/v1/companies.json
# CEBE per share and Senior Claims % for every company
curl -s https://cebetracker.io/api/v1/companies.json \
| jq '.companies[] | {ticker, cebe_sats, senior_claims_pct, cebe_mnav}'
Methods: GET, HEAD, OPTIONS. The response is JSON with Access-Control-Allow-Origin: *, so browser apps can call it directly.
The two price bases
The feed serves the same construction on two explicit bases, and every price is dated.
Snapshot basis (filing-anchored)
Balance sheet figures come from each company's latest verified snapshot, sourced from primary filings (see the per-company source field). btc_price is the BTC/USD price on as_of, and senior_claims_pct, cebe_sats, and cebe_mnav are computed at that price. A dated price is not stale data; it is the price at which the filing-anchored figures were anchored.
Live basis
btc_price_live is the current BTC/USD price (CoinGecko, timestamped by btc_price_live_as_of). The senior_claims_pct_live, cebe_sats_live, and cebe_mnav_live fields recompute the identical formula at that price, so fiat claims re-convert and the whole lens moves together. Live-basis fields are null when no live BTC price is available.
The formula
Senior claims and CEBE are computed the same way on either basis. btc_price_basis is btc_price on the snapshot basis and btc_price_live on the live basis.
claims = max(0, (debt_usd + preferred_usd - cash_usd - strc_holdings_usd)
/ btc_price_basis
+ btc_claim_static) / btc_holdings # capped to [0, 1]
cebe_sats = btc_holdings * (1 - claims) / basic_shares # in satoshis
cebe_mnav = market_cap_usd / (btc_holdings * (1 - claims) * btc_price_basis)
senior_claims_pct is claims expressed as a percent, 0 to 100. The full measurement rules live on the methodology page.
Net Senior Claims carries three fiat terms, Debt plus Preferred less Cash, with strc_holdings_usd netting senior securities the issuer holds against itself. preferred_usd is carried at accrued liquidation preference, which is where declared but unpaid arrears live. dividends_payable_usd is served beside these figures as disclosure and is not summed into them.
Response shape
| Top-level field | Meaning |
|---|---|
| version | Contract version. Currently 1. |
| as_of | ISO timestamp when the response was generated. |
| license | License line: free to use with attribution to cebetracker.io. Full terms under Terms of Use. |
| terms_date | Date of the Terms of Use revision in force (YYYY-MM-DD). It changes with every revision; see Changes. Served on all three feeds. |
| methodology | URL of the methodology page. |
| btc_price_live | Current BTC/USD price, or null when unavailable. |
| btc_price_live_as_of | Timestamp of the live price. |
| notes | Machine-readable description of the bases, formula, and contract. |
| companies | Array of per-company objects, documented below. |
Per-company field dictionary
| Field | Type | Meaning |
|---|---|---|
| ticker | string | Canonical ticker used across the site. Exchange aliases resolve to this key. |
| name | string | Company display name. |
| as_of | string | Date of the latest verified balance sheet snapshot (YYYY-MM-DD). |
| pending_fields | array of strings | Required fields the snapshot row does not state, from btc_holdings, shares_outstanding and btc_price (each must be positive) and debt_usd and cash_usd (each must be stated; a stated zero is complete). Empty when the row is complete. When it is not empty the row is pending: the missing fields serve null, every computed figure on both bases serves null, and no earlier snapshot is substituted. |
| btc_holdings | number, null | BTC held as of the snapshot date. null when the row does not state it. |
| debt_usd | number, null | Debt outstanding, USD. |
| preferred_usd | number, null | Preferred stock outstanding at face, USD. |
| cash_usd | number, null | Cash and equivalents, USD. Nets against senior claims. |
| strc_holdings_usd | number, null | STRC preferred held as an asset, USD. Nets against senior claims. |
| dividends_payable_usd | number, null | Declared but unpaid preferred dividends, USD, at face. Non-netting disclosure field: this is not an input to claims. preferred_usd carries accrued liquidation preference, so these arrears already sit inside it and adding this field would double-count them. null means not reported, 0 means none stands declared and unpaid. |
| btc_claim_static | number | BTC-denominated senior claims for BTC-indexed issuers. Price independent. |
| basic_shares | number, null | Basic common shares outstanding. null when the row does not state it. |
| btc_price | number, null | BTC/USD price the snapshot figures were anchored at. null when the row does not state it, never 0. |
| btc_price_as_of | string | Date of btc_price. Equals as_of. |
| senior_claims_pct | number, null | Share of BTC holdings consumed by net senior claims at btc_price. Percent, 0 to 100. null when the row is pending. |
| cebe_sats | integer, null | Common Equity Bitcoin Exposure per share, in satoshis, snapshot basis. null when the row is pending. |
| stock_price | number, null | Last available trade or close in USD, from the same quote pipeline the site uses (Finnhub for US and OTC listings, Yahoo Finance for international venues, non-USD prices converted at fetched cross rates). Never a live tick. |
| stock_price_as_of | string, null | Timestamp of the quote. |
| stock_price_source | string, null | Which quote pipeline produced the price. |
| market_cap_usd | number, null | stock_price times basic_shares. |
| cebe_mnav | number, null | Market cap over the USD value of common equity BTC at btc_price. Accretion threshold is 1.0. |
| senior_claims_pct_live | number, null | Senior Claims % recomputed at btc_price_live. |
| cebe_sats_live | integer, null | cebe_sats recomputed at btc_price_live. |
| cebe_mnav_live | number, null | cebe_mnav recomputed at btc_price_live. |
| wrapper_annual_usd | number, null | Annual carry cost of the wrapper (interest plus preferred dividends), USD. |
| wrapper_annual_usd_verified | boolean, null | true when the wrapper figure is filing-verified, false when estimated, null when no flag is recorded. |
| source | string, null | Primary filing reference for the snapshot. |
Stock-derived fields (stock_price, market_cap_usd, cebe_mnav and its live twin) are null when no dated quote is available. The feed withholds a quote rather than serving it on a wrong currency basis.
Instruments feed
GET https://cebetracker.io/api/v1/instruments.json
GET https://cebetracker.io/api/v1/instruments.json?ticker=MSTR
Every row of the instruments record for the live fleet, grouped by company, in the record's own order. ?ticker= restricts the response to one company and accepts exchange aliases, so ?ticker=3350 and ?ticker=MTPLF reach the same company. A ticker outside the live universe returns 404 by name rather than an empty fleet.
This feed serves the capital structure, not the measurement. It computes no claim total, no Senior Claims % and no per-share figure, and a sum of face_value across these rows does not reproduce Net Senior Claims: the claim perimeter is a construction rather than a column sum, and the record deliberately carries rows outside it, including pre-active pools, retired instruments kept for history, and undrawn options recorded as instruments. Use companies.json for the measured figures.
# Active preferred and debt claims for one company
curl -s 'https://cebetracker.io/api/v1/instruments.json?ticker=MSTR' \
| jq '.companies[0].instruments[] | select(.status_active) | {inst_id, class, face_value, rate}'
Field semantics that carry a trap
Blank reads as null, never as zero. On an instrument row a blank term was never filed, which is a different fact from a filed zero, and a consumer handed a zero cannot recover the blank.
face_value is blank on every share-delivery row by construction. That obligation is denominated in shares rather than a currency amount, so there is no face to file. face_value_applicable is false on exactly those rows, so a null never has to be interpreted.
The delivery pool carries its basis. share_delivery_pool.basis reads filed where the share count states the pool, proportional where the clause states a fraction of the diluted total and the count is solved from that fraction, and unresolved where neither shape is filed. A null count means not yet verified, never zero.
conversion_price carries the exercise price on a warrant, option or stock acquisition right, and a conversion price elsewhere. conversion_price_role names which, so the role never has to be inferred from a free-text class cell. A filed strike sits on the basis in force when it was filed, and those bases differ across the roster, so a moneyness screen must settle each issuer's split history before comparing a strike to a price series.
Status resolves through one reader. status is the ratified token, status_raw is the cell as typed, status_state gives the three-way reading (active, pre_active, inactive, unrecognized), and status_active is the inclusion boolean the site's own surfaces gate on. A blank status resolves active by the standing absence rule. A value outside the ratified set is served with status_recognized: false and status_active: true, which is the inclusion the site applies, made visible rather than silent.
p_ref_immune lists the fields on that row carrying filed contractual terms: strikes, stated amounts, floors, caps and reference rates. Those terms are immune to every price, FX and basis sweep. Two live cases on this roster move in opposite directions at the same kind of corporate action, one warrant price left unadjusted at a reverse split and another raised by the split ratio, both correct as filed, which is why the flag exists rather than a rule of thumb.
Companies under review carry hold: true with a hold_reason. Their rows are served in full: a hold marks figures as under review and never blanks them.
Deals feed
GET https://cebetracker.io/api/v1/deals.json
GET https://cebetracker.io/api/v1/deals.json?ticker=MSTR
Every row of the capital events record for the live fleet, grouped by company, oldest first so the newest print is last. Purchases and sales, ATM prints, preferred and convertible issuance, repurchases, repayments and conversion triggers, each carrying the filing it came from. ?ticker= behaves as it does on the instruments feed.
Nothing is computed. Every field is the record's own cell, and this feed applies no accretion test, derives no per-share figure and totals nothing, because a total over event rows is a construction with rules of its own.
Before summing anything
Superseded rows are corrections, not events. A row whose data_quality is SUPERSEDED carries superseded: true and must be excluded from every total. It is served rather than dropped so a consumer reconciling against the filings can see what was corrected.
At least one event is recorded twice under two ids, and both rows are served. A feed that quietly drops rows cannot be reconciled against the filings. The known case is the STRC repurchase week to 26 July 2026, carried as MSTR-2026-07-26-01 and MSTR-2026-07-27-01, both marked VERIFIED, both citing 8-K accession 0001193125-26-316917, and both stating the same 288,930 shares and the same $28,893,000 of face. The companion ATM print for that week is carried twice in the same way. Summing claims_added_usd for that company without de-duplicating overstates retired face by $28,893,000. The duplicate is filed with the owning company anchor for correction at source.
Vocabulary normalization
The record carries the same fact under two spellings in three columns, and the sweep settling that at source has not landed. The normalization is applied in the reader, printed in the response's normalization field, and listed here. Every entry is a spelling pair evidenced in the record itself rather than a judgment about what two different words ought to mean.
| Field | As filed | As served |
|---|---|---|
| deal_type | pref_repurchase | preferred_repurchase |
| deal_type | atm_common | atm_equity |
| direction | issue | raise |
| data_quality | EST | ESTIMATED |
The atm_common and issue entries come from the duplicate pair above, where one 8-K is recorded once as atm_equity with direction raise and once as atm_common with direction issue, which is the record stating the equivalence in its own hand.
Every row carries the cell as filed in deal_type_raw, direction_raw and data_quality_raw, and vocabulary_normalized lists which of its fields were rewritten, so nothing is lost and the sweep can be checked against this feed afterwards.
Directions left as filed: deploy, dispose, retire, in and pledge. Those are not spellings of one word. dispose sits beside deploy on sale rows and retire beside deploy on repayment and repurchase rows, describing the cash leg and the claim leg of one event; in and pledge appear once each, on an acquisition close and a collateral pledge, with no second row to establish a mapping.
Joins and estimates
instrument_id joins to the instruments feed on inst_id, and the join is not clean on every row: the record carries both MSTR_STRC and STRC for one instrument across different weeks. The value is served exactly as filed, because rewriting an identifier to make a join succeed hides the defect rather than reporting it.
funding_group links the legs of one financing at announcement level only. Where a filing states no use of proceeds, the link is not a claim that the proceeds bought the coin.
shares_issued, net_proceeds and stock_price_at_deal each carry an _est boolean and a _note beside them, so an estimate never has to be inferred. stock_price_at_deal is the price as filed at the deal and never a live quote, because an accretion test run against today's price answers a different question from the one the print poses.
Conditional requests
The instruments and deals feeds serve a strong ETag over the exact bytes returned, excluding the generation timestamp, so an unchanged record yields an unchanged validator. Send it back as If-None-Match and an unchanged feed answers 304 with no body.
curl -s -D - -o /dev/null https://cebetracker.io/api/v1/instruments.json | grep -i etag
curl -s -o /dev/null -w '%{http_code}\n' \
-H 'If-None-Match: "PASTE_THE_ETAG_HERE"' \
https://cebetracker.io/api/v1/instruments.json
Caching and limits
Responses are CDN-cached for about five minutes (s-maxage=300, stale-while-revalidate=600). Behind the cache, requests are rate-limited to 100 per minute per IP; over-limit requests receive 429 with Retry-After: 60. Error responses are never cached. If upstream garbage rows were stripped server-side, the response carries an X-CEBE-Integrity header and caches for 60 seconds so a cleanup propagates fast.
Versioning contract
The v1 response shape is a published contract: additive changes only. Fields are never renamed or removed. New fields may appear at any time, so parse tolerantly.
Terms of Use
Dated 11 September 2026. These terms may evolve; see Changes.
The CEBE Tracker service and its content are operated by Tierney Analytics LLC.
The feed and the computed figures it serves are free to use with attribution. There is no key, no registration, and no fee.
Commercial use
Commercial use of the API is permitted under these attribution terms; CEBE Tracker reserves the right to introduce commercial licensing tiers for systematic or revenue-bearing redistribution, with existing implementers grandfathered on notice.
Attribution
Cite the source in this form:
Data via CEBE Tracker, cebetracker.io
Render cebetracker.io as a link to https://cebetracker.io wherever the medium supports links. The citation belongs on any surface that displays the data, in view alongside the figures themselves. A chart, a table, a slide, a post, or a screenshot each carries its own citation. A footnote, an endnote, a credits page, or a source list elsewhere in the document does not satisfy this.
No representation as house data
Do not present these figures as your own original or in-house research, and do not republish the dataset under another name or brand as though it were independently produced. Work derived from the feed is welcome, and the underlying figures stay attributed to CEBE Tracker.
Naming the measure
A figure computed on the CEBE construction, total bitcoin less Net Senior Claims in bitcoin as defined on the methodology page, divided by basic shares outstanding, at any dated bitcoin price, is CEBE. Label it CEBE wherever it is displayed, alongside any other name you also give it. A figure that changes any part of that construction, including the share count, the claims included, or their netting, is not CEBE. Do not label it CEBE, and state what was changed where the figure appears.
No endorsement in either direction
Use of this data does not mean CEBE Tracker endorses you, your product, or your analysis, and it does not mean you endorse CEBE Tracker. Do not describe the relationship as a partnership, an affiliation, a sponsorship, or a review, and do not use the CEBE Tracker name or wordmark in a way that suggests one.
Publishing the figures accurately
Every figure traces to a primary filing; the per-company source field carries the reference. Every CEBE figure is a function of a dated BTC price, so publish the basis (snapshot or live) and the as_of date alongside any number you take from the feed.
Changes
These terms may evolve as the feed does. Each revision changes the date at the top of this section and the terms_date field in every feed response. A revision takes effect 30 days after that date. Continuing to call the feed after a revision takes effect means accepting the revised terms, and a live product that calls the feed is continuing use. Static work published before a revision takes effect, such as a post, chart, screenshot or article, stays governed by the version in force when it was published.
2026-09-16: undocumented row-level notes fields were removed from the deals and instruments feeds. They carried internal working notes and were never part of the documented field tables. No documented field changed. The 30-day change clock applies from this date.
Access
Access to the feed is provided at CEBE Tracker's discretion. Use that does not meet these terms is outside this permission, and access for that use may be withdrawn.