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.
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 BPI | Demo 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.
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.
?mock_delay=3000 for the loading spinner, ?mock_status=503 for the error path, ?mock_seq=503,503,200 to prove your retry logic recovers.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):
| Source | Endpoint | Note |
|---|---|---|
| Coinbase | api.coinbase.com/v2/prices/spot?currency=USD | closest in spirit: tiny JSON, one price |
| CoinGecko | api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd,eur,gbp | multi-currency in one call; public tier is rate-limited (it 429'd on our 4th call β guide) |
| blockchain.info | blockchain.info/ticker | ~25 currencies, BPI-like per-currency objects |
| Kraken | api.kraken.com/0/public/Ticker?pair=XBTUSD | exchange data: bid/ask/volume too |
| CoinDesk (new) | developers.coindesk.com | the 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).
| api.coindesk.com | Real 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 / signup | none | none (public tiers) | none |
| Deterministic for tests | β | β | β |
| Error/latency simulation | β | β | β mock_delay/mock_status/mock_seq |
| Who keeps it alive | nobody (that's the point) | each vendor | your project, bounded free limits (10k req/day) |
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.