Start Using CoinAPI in 15 Minutes: Setup, First Calls & Common Errors

We’ve created this quickstart to help you get started with CoinAPI. If you’re using REST or WebSocket, you’ll be set up and making your first successful call in minutes.

This quickstart helps you avoid day-one friction by walking you through working examples, error handling, and the right setup for your dev environment.

  • How to create and secure your API key
  • Make your first REST API call (e.g., OHLCV or trades)
  • Authenticate and subscribe to a WebSocket stream
  • Fix common errors: 401, TLS, rate limits, handshake issues
  • Check health, usage, and debugging tools
  • SDK quickstart snippets in Python and JavaScript
  • A CoinAPI account and API key (Get $25 in free credits when you verify a payment method!)
  • Development environment with:
    • curl, or
    • Python 3.8+ with requests + websocket-client, or
    • Node.js 18+ with fetch and ws
  • Internet access with WebSocket (wss://) support

→ Want to understand what your free API key gives you? Check out What You Get with a Free Crypto API from CoinAPI ($25 Credits) - it breaks down what’s included in the free plan and how to make the most of your credits while staying within limits.

  1. Log into the Console.
  2. Go to the API Keys section.
  3. Click Create API Key.
  1. Choose your key type (Standard Key or JWT Key)
  • Standard Key - recommended for most use cases, including REST and WebSocket calls.
  • JWT Key - for advanced integrations requiring signed tokens (e.g., sharing limited-access credentials with your customers or applications).

5. Copy your API key securely and don’t share it publicly.

We'll fetch 10 hourly OHLCV candles for BTC/USD on Bitstamp.

OHLCV = Open, High, Low, Close, Volume (standard candlestick price data).

Endpoint:

https://rest.coinapi.io/v1/ohlcv/BITSTAMP_SPOT_BTC_USD/history

1curl -H "X-CoinAPI-Key: $COINAPI_KEY" \\
2"<https://rest.coinapi.io/v1/ohlcv/BITSTAMP_SPOT_BTC_USD/history?period_id=1HRS&time_start=2025-01-01T00:00:00&limit=10>"
1import os, requests
2
3key = os.environ["COINAPI_KEY"]
4url = "<https://rest.coinapi.io/v1/ohlcv/BITSTAMP_SPOT_BTC_USD/history>"
5params = { "period_id": "1HRS", "time_start": "2025-01-01T00:00:00", "limit": 10 }
6headers = { "X-CoinAPI-Key": key }
7
8res = requests.get(url, headers=headers, params=params)
9print(res.json())
1const key = process.env.COINAPI_KEY;
2const url = "<https://rest.coinapi.io/v1/ohlcv/BITSTAMP_SPOT_BTC_USD/history?period_id=1HRS&time_start=2025-01-01T00:00:00&limit=10>";
3const res = await fetch(url, { headers: { "X-CoinAPI-Key": key } });
4const data = await res.json();
5console.log(data);

If you omit period_id or set it as an empty string, you will get:

1{ "error": "The parameter period_id can not be null or empty string." }

Always specify a valid period_id!

Common values are:

  • 1MIN (1 minute)
  • 1HRS (1 hour)
  • 1DAY (1 day)

See the full list of supported periods here.

1[
2    {
3        "time_period_start": "2025-01-01T00:00:00.0000000Z",
4        "time_period_end": "2025-01-01T01:00:00.0000000Z",
5        "time_open": "2025-01-01T00:00:06.5530000Z",
6        "time_close": "2025-01-01T00:59:50.7480000Z",
7        "price_open": 93347,
8        "price_high": 94272,
9        "price_low": 93318,
10        "price_close": 94211,
11        "volume_traded": 63.60429212999999,
12        "trades_count": 390
13    },
14    {
15        "time_period_start": "2025-01-01T01:00:00.0000000Z",
16        "time_period_end": "2025-01-01T02:00:00.0000000Z",
17        "time_open": "2025-01-01T01:00:13.2220000Z",
18        "time_close": "2025-01-01T01:59:53.0660000Z",
19        "price_open": 94188,
20        "price_high": 94188,
21        "price_low": 93416,
22        "price_close": 93421,
23        "volume_traded": 14.544311170000002,
24        "trades_count": 171
25    },
26    {
27        "time_period_start": "2025-01-01T02:00:00.0000000Z",
28        "time_period_end": "2025-01-01T03:00:00.0000000Z",
29        "time_open": "2025-01-01T02:00:01.3840000Z",
30        "time_close": "2025-01-01T02:58:15.9490000Z",
31        "price_open": 93421,
32        "price_high": 93893,
33        "price_low": 93416,
34        "price_close": 93858,
35        "volume_traded": 8.502786899999998,
36        "trades_count": 128
37    },
38]

If you see data like this, your API call worked!

📘 Not sure what OHLCV means or why it matters? Read Understanding OHLCV in Market Data Analysis for a beginner-friendly explanation of this essential trading data format used across most crypto and stock charts.

CoinAPI uses a canonical symbol identifier, e.g. BITSTAMP_SPOT_BTC_USD which follows a structured naming convention.

  • Exchange ID: e.g. BITSTAMP
  • Market Type: e.g. SPOT, PERP, FTS (futures), OPTION, INDEX
  • Base Asset: e.g. BTC
  • Quote Asset: e.g. USD

For derivatives, more fields may appear (expiry dates, strike price, etc.).

Use the symbols endpoint to discover valid symbols for your exchange or asset.

Endpoint:

1GET <https://rest.coinapi.io/v1/symbols>

Optionally, you can filter results via query parameters:

  • filter_exchange_id=BINANCE
  • filter_asset_id=ETH
  • filter_symbol_id=BINANCE_SPOT_ You can combine them to narrow down.

Example usage:

1GET /v1/symbols?filter_exchange_id=BINANCE&filter_asset_id=BTC

This returns only symbols on Binance where the base or quote asset is BTC.

WebSocket URL:

wss://ws.coinapi.io/v1/

We’ll subscribe to real-time trades for BTC/USD.

1pip install websocket-client
1import os, json, time, random, websocket
2
3API_KEY = os.environ["COINAPI_KEY"]
4WS_URL = "wss://ws.coinapi.io/v1/"
5
6def on_open(ws):
7    hello = {
8        "type": "hello",
9        "apikey": API_KEY,
10        "heartbeat": False,
11        "subscribe_data_type": ["trade"],
12        "subscribe_filter_symbol_id": ["BITSTAMP_SPOT_BTC_USD$"]
13    }
14    ws.send(json.dumps(hello))
15
16def run():
17    backoff = 1
18    while True:
19        ws = websocket.WebSocketApp(
20            WS_URL,
21            on_open=on_open,
22            on_message=lambda ws, msg: print(msg),
23            on_error=lambda ws, err: print("WS error:", err),
24            on_close=lambda ws, code, reason: print("Closed:", code, reason)
25        )
26        ws.run_forever(ping_interval=20, ping_timeout=10)
27        time.sleep(backoff + random.random())
28        backoff = min(backoff * 2, 30)
29
30run()
31
32
1npm install ws
1import WebSocket from "ws";
2
3const API_KEY = process.env.COINAPI_KEY;
4const WS_URL = "wss://ws.coinapi.io/v1/";
5
6function connect() {
7  const ws = new WebSocket(WS_URL);
8
9  ws.on("open", () => {
10    ws.send(JSON.stringify({
11      type: "hello",
12      apikey: API_KEY,
13      heartbeat: false,
14      subscribe_data_type: ["trade"],
15      subscribe_filter_symbol_id: ["BITSTAMP_SPOT_BTC_USD$"]
16    }));
17  });
18
19  ws.on("message", (msg) => console.log(msg.toString()));
20  ws.on("error", (err) => console.error("WS Error:", err.message));
21  ws.on("close", (code, reason) => {
22    console.warn("WS Closed:", code, reason.toString());
23    setTimeout(connect, 1000 + Math.random() * 2000); // backoff
24  });
25}
26
27connect();
28
29
1{
2  "type": "hello",
3  "apikey": "YOUR_API_KEY",
4  "heartbeat": false,
5  "subscribe_data_type": ["trade"],
6  "subscribe_filter_symbol_id": ["BITSTAMP_SPOT_BTC_USD$"]
7}
1{
2    "time_exchange": "2025-09-30T12:37:40.3730000Z",
3    "time_coinapi": "2025-09-30T12:37:40.4230979Z",
4    "uuid": "52bb6fa3-d507-481e-b7ac-70c89cb17f92",
5    "price": 113202,
6    "size": 0.00067136,
7    "taker_side": "BUY",
8    "symbol_id": "BITSTAMP_SPOT_BTC_USD",
9    "sequence": 1254021,
10    "type": "trade"
11}

🟢 If you see messages like this, your WebSocket is live!

IssueFix or Cause
401 Unauthorized (REST)Missing or invalid API key. Check the X-CoinAPI-Key header
401 Unauthorized (WebSocket)API key missing or malformed in the hello payload
400 Bad RequestInvalid symbol_id, period_id, or bad date format
403 ForbiddenYour plan doesn't support this endpoint. Check Console
429 Too Many RequestsYou’ve hit rate limits. Throttle and upgrade if needed
Bad handshake (WS)Use wss:// and ensure no firewall/proxy is interfering
TLS/certificate errorsUpdate your root certs; avoid MITM proxies
  • Use exponential backoff with jitter (1s → 2s → 4s … up to 30s)
  • Resend hello and subscriptions after reconnect
  • Log disconnects and handle ping/pong or enable heartbeat
  • Don’t loop reconnects aggressively, this can trigger rate limits
  • Check CoinAPI Status Page
  • Verify API key in the Console
  • Try a minimal working REST/WebSocket example
  • Send full request/response logs (with timestamps & symbol_id) when contacting support
  • Subscribe to multiple symbols
  • Explore /v1/symbols to discover markets
  • Build your first trading dashboard or market analytics tool

→ Why do we normalize symbol IDs and trade data? Different exchanges use different formats. Learn how CoinAPI solves this with Why is it Critical to Normalize Cryptocurrency Trade Data?. A must-read if you're integrating across multiple data sources.

You’ve made your first authenticated REST and WebSocket calls. You're now equipped to build apps, dashboards, bots, or anything powered by real-time market data.