The CoinDesk Bitcoin Price API (api.coindesk.com) is dead β€” swap one hostname and the tutorial works again

For over a decade, "fetch the Bitcoin price" was many people's very first API call β€” api.coindesk.com/v1/bpi/currentprice.json needed no key, no signup, and returned a JSON shape (data.bpi.USD.rate_float) that thousands of tutorials, YouTube walkthroughs, and starter repos were built on. Here's what that curl does now (we re-checked while writing this; our status page for it re-checks every 30 minutes):

$ curl https://api.coindesk.com/v1/bpi/currentprice.json
curl: (6) Could not resolve host: api.coindesk.com

The hostname no longer resolves at all (through some proxies you'll see an HTTP 530 origin-DNS error instead). The decline was gradual β€” the BPI's historical data quietly stopped updating in July 2022, and CoinDesk's developer offering moved to developers.coindesk.com, which is a different API with different response shapes behind an API key. The old keyless endpoints every tutorial hardcoded are simply gone.

1. Zero setup: swap the hostname

Our shared demo project serves the classic BPI endpoints with the exact original response shape β€” same keys, same key order, string rate with comma grouping, numeric rate_float, the lot. Replace https://api.coindesk.com with https://mockbird.mockbird.workers.dev/m/demo and the tutorial code runs unchanged:

$ curl https://mockbird.mockbird.workers.dev/m/demo/v1/bpi/currentprice.json
{
  "time": {"updated": "2026-09-14T08:02:48.104Z", "updatedISO": "2026-09-14T08:02:48.104Z", …},
  "disclaimer": "Synthetic mock data … NOT real market prices. …",
  "chartName": "Bitcoin",
  "bpi": {
    "USD": {"code": "USD", "symbol": "$", "rate": "76,314.6000",
            "description": "United States Dollar", "rate_float": 76314.6},
    "GBP": {…}, "EUR": {…}
  }
}

The decade-old tutorial snippet, verbatim except for the base URL:

fetch("https://mockbird.mockbird.workers.dev/m/demo/v1/bpi/currentprice.json")
  .then(r => r.json())
  .then(data => console.log("BTC: $" + data.bpi.USD.rate_float));

The chart-tutorial endpoint works too β€” historical/close.json returns 31 days of closes keyed by date, exactly the Object.entries(data.bpi) shape the D3/Chart.js tutorials iterate:

$ curl https://mockbird.mockbird.workers.dev/m/demo/v1/bpi/historical/close.json
{"bpi": {"2026-08-14": 72815.61, "2026-08-15": 72608.8, … 31 days …}, "disclaimer": …}
CoinDesk BPIDemo drop-in
/v1/bpi/currentprice.json/m/demo/v1/bpi/currentprice.json β€” USD, GBP, EUR
/v1/bpi/currentprice/USD.json/m/demo/v1/bpi/currentprice/USD.json
/v1/bpi/historical/close.json/m/demo/v1/bpi/historical/close.json β€” rolling 31 days

Three honest differences, stated plainly: the numbers are synthetic. They're a deterministic pseudo-random walk that holds still all day and rolls forward daily β€” by design (see Β§3). The time.updated fields are all ISO-8601 timestamps rather than the original's "Sep 14, 2026 08:00:00 UTC" display format. And the demo seeds only USD.json as a per-currency route, and ?start=&end= on the historical endpoint is ignored β€” fork your own copy (next section) to add more.

2. One curl: your own copy

The demo resets daily and is shared. Fork it β€” no signup, no key β€” and you get a private project with the three BPI routes copied in (plus the demo’s sample datasets β€” the demo-specific showcase routes stay behind):

curl -X POST https://mockbird.mockbird.workers.dev/api/projects/demo/fork \
  -H 'content-type: application/json' -d '{"name":"btc-mock"}'

The response has your project id and adminKey. Your endpoints are /m/YOUR_ID/v1/bpi/…. Now the price is yours to script β€” re-POST a route with the same path to overwrite it. Pin the price your test expects:

curl -X POST "https://mockbird.mockbird.workers.dev/api/projects/YOUR_ID/routes" \
  -H "x-admin-key: YOUR_ADMIN_KEY" -H 'content-type: application/json' \
  -d '{"path":"/v1/bpi/currentprice.json","body":{
        "time":{"updated":"{{now}}","updatedISO":"{{now}}","updateduk":"{{now}}"},
        "disclaimer":"mock","chartName":"Bitcoin",
        "bpi":{"USD":{"code":"USD","symbol":"$","rate":"100,000.0000",
               "description":"United States Dollar","rate_float":100000.0}}}}'

That's the six-figure-formatting edge case your price widget has never actually rendered. Add EUR.json/GBP.json routes the same way (path: "/v1/bpi/currentprice/EUR.json"), or any endpoint the original never had. {{now}} is response templating β€” timestamps stay live.

3. Why point a price widget at a mock at all

4. Need real prices? These are keyless today

A mock is the right tool for tests and teaching, not for showing a real price to a real user. All of these worked without a key when we verified them (September 2026):

SourceEndpointNote
Coinbaseapi.coinbase.com/v2/prices/spot?currency=USDclosest in spirit: tiny JSON, one price
CoinGeckoapi.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd,eur,gbpmulti-currency in one call; public tier is rate-limited (it 429'd on our 4th call β€” guide)
blockchain.infoblockchain.info/ticker~25 currencies, BPI-like per-currency objects
Krakenapi.kraken.com/0/public/Ticker?pair=XBTUSDexchange data: bid/ask/volume too
CoinDesk (new)developers.coindesk.comthe official successor β€” API key required, different shapes

None of them return the BPI shape, so tutorial code needs rewriting either way β€” which is exactly why the drop-in mock in Β§1 exists: it's the only way to make existing BPI code run again unmodified. A sensible production pattern is both: real source in production, the mock in tests via a base-URL env var. For fiat exchange rates, see our currencies dataset guide β€” and Frankfurter remains a genuinely free keyless fiat-rates API (we checked).

5. Honest comparison

api.coindesk.comReal price APIs (Β§4)Demo drop-in / your fork
Works today✘ DNS goneβœ”βœ”
BPI response shapeβ€”βœ˜ all differentβœ” key-for-key
Real market pricesβ€”βœ”βœ˜ synthetic, on purpose
Key / signupnonenone (public tiers)none
Deterministic for testsβœ˜βœ˜βœ”
Error/latency simulationβœ˜βœ˜βœ” mock_delay/mock_status/mock_seq
Who keeps it alivenobody (that's the point)each vendoryour project, bounded free limits (10k req/day)

Swap the host

Section 1 is the whole setup β€” there isn't one. The BPI joins a long line of keyless tutorial APIs that vanished under the code written on them: numbersapi, boredapi, ICNDb, worldtimeapi (our status board tracks 71 of them, live). Same fix each time: host the shape yourself. Related: exchange rates, stock quotes, or mock any third-party API.

⚑ Skip the terminal: this link creates a live, seeded e-commerce backend (products, orders, customers, reviews) in the dashboard β€” real URL, data browser already open, no signup. Or import your own OpenAPI spec, db.json, CSV, Postman collection, or HAR and mock your exact shapes.