Coinbase API Docs: Complete Guide for Crypto Traders
A hands-on guide to Coinbase API documentation covering authentication, endpoints, Python examples, and how to build trading tools using Advanced and Prime APIs.
A hands-on guide to Coinbase API documentation covering authentication, endpoints, Python examples, and how to build trading tools using Advanced and Prime APIs.
If you've spent any time trying to automate crypto trading, you know the frustration: vague docs, inconsistent endpoints, and authentication flows that seem designed to break on purpose. Coinbase has cleaned this up significantly over the past two years, and the current Coinbase API documentation is genuinely one of the better resources in the space — if you know where to look. This guide cuts straight to what traders actually need: auth setup, key endpoints, working code, and the differences between Coinbase's several API tiers.
Coinbase doesn't have a single API — it has several, and picking the wrong one wastes hours. Here's the breakdown:
| API | Target User | Key Feature |
|---|---|---|
| Coinbase Advanced API | Retail & pro traders | Full order management, market data |
| Coinbase Prime API | Institutional clients | Portfolio management, custody, bulk ops |
| Coinbase International API | Non-US institutional | Perpetuals & derivatives trading |
| Coinbase Exchange API (legacy) | Legacy integrations | Being deprecated — migrate off this |
| Coinbase Commerce API | Merchants | Payment processing, invoices |
For most traders building bots or data pipelines, the Coinbase Advanced API docs are where you'll spend your time. The Coinbase Prime API docs are relevant only if you're operating at institutional scale — think funds, prop desks, or OTC desks. The Coinbase International API docs cover their offshore derivatives venue. The old Coinbase Exchange API docs still work but Coinbase has signaled a transition away from it, so don't build new things on top of it.
The legacy 'Coinbase Pro' API (api.pro.coinbase.com) is effectively the Coinbase Exchange API. It still functions but new features are only in the Advanced Trade API. Migrate sooner rather than later.
Coinbase Advanced API uses two auth methods: legacy API key pairs (key + secret) and the newer Cloud API Key system using JWT (JSON Web Tokens). The JWT approach is recommended for all new integrations — it's more secure and aligns with the Coinbase SDK docs. Here's a working Python authentication setup:
import jwt
import time
import secrets
import hashlib
import hmac
from cryptography.hazmat.primitives.serialization import load_pem_private_key
# Cloud API Key auth (recommended approach)
KEY_NAME = "organizations/{org_id}/apiKeys/{key_id}" # from Coinbase Developer Portal
KEY_SECRET = """-----BEGIN EC PRIVATE KEY-----
-----END EC PRIVATE KEY-----"""
def build_jwt(method: str, path: str) -> str:
private_key = load_pem_private_key(KEY_SECRET.encode(), password=None)
payload = {
"sub": KEY_NAME,
"iss": "coinbase-cloud",
"nbf": int(time.time()),
"exp": int(time.time()) + 120, # 2-minute expiry
"uri": f"{method} api.coinbase.com{path}"
}
return jwt.encode(
payload,
private_key,
algorithm="ES256",
headers={"kid": KEY_NAME, "nonce": secrets.token_hex()}
)
# Usage
token = build_jwt("GET", "/api/v3/brokerage/accounts")
headers = {"Authorization": f"Bearer {token}"}
If you're using the older HMAC-based key auth (still valid for the legacy Coinbase exchange API docs flow), the signing process is different — you hash the timestamp + method + path + body with your secret. The Coinbase API reference covers both, but the JWT path above is cleaner for new projects.
Once auth is sorted, the two things most traders need are market data and order placement. Here's a practical Python example pulling BTC-USD price data and placing a limit order — this is essentially what any trading bot on Coinbase is built around:
import requests
import json
BASE_URL = "https://api.coinbase.com"
def get_product_book(product_id: str, limit: int = 10) -> dict:
"""Fetch order book for a product"""
path = f"/api/v3/brokerage/product_book"
token = build_jwt("GET", path)
response = requests.get(
f"{BASE_URL}{path}",
headers={"Authorization": f"Bearer {token}"},
params={"product_id": product_id, "limit": limit}
)
response.raise_for_status()
return response.json()
def place_limit_order(
product_id: str,
side: str, # "BUY" or "SELL"
base_size: str,
limit_price: str,
client_order_id: str
) -> dict:
"""Place a limit order via Advanced Trade API"""
path = "/api/v3/brokerage/orders"
token = build_jwt("POST", path)
payload = {
"client_order_id": client_order_id,
"product_id": product_id,
"side": side,
"order_configuration": {
"limit_limit_gtc": {
"base_size": base_size,
"limit_price": limit_price,
"post_only": False
}
}
}
response = requests.post(
f"{BASE_URL}{path}",
headers={
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
},
json=payload
)
result = response.json()
# Error handling
if not result.get("success"):
error_response = result.get("error_response", {})
raise Exception(f"Order failed: {error_response.get('message', 'Unknown error')}")
return result["order_id"]
# Example usage
book = get_product_book("BTC-USD", limit=5)
best_bid = book["pricebook"]["bids"][0]["price"]
print(f"Best bid: ${best_bid}")
# Place limit buy $100 below best bid
import uuid
order_id = place_limit_order(
product_id="BTC-USD",
side="BUY",
base_size="0.001",
limit_price=str(float(best_bid) - 100),
client_order_id=str(uuid.uuid4())
)
print(f"Order placed: {order_id}")
Always use a unique client_order_id (UUID4 works) for every order. If your request times out and you retry, Coinbase will reject duplicate client_order_ids — which actually protects you from double-fills.
Coinbase maintains an official Python SDK (coinbase-advanced-py) and a Node.js SDK. The Coinbase SDK docs are lighter than the full API reference, but they handle JWT signing and retries for you — worth it for most use cases. Install with pip install coinbase-advanced-py.
from coinbase.rest import RESTClient
# SDK handles JWT auth automatically
client = RESTClient(
api_key="your_api_key_name",
api_secret="your_private_key_pem_string"
)
# List accounts
accounts = client.get_accounts()
for account in accounts["accounts"]:
if float(account["available_balance"]["value"]) > 0:
print(f"{account['currency']}: {account['available_balance']['value']}")
# Get candles (OHLCV data)
candles = client.get_candles(
product_id="ETH-USD",
start="1700000000",
end="1700086400",
granularity="ONE_HOUR"
)
# Parse candle data
for candle in candles["candles"]:
print(f"Open: {candle['open']}, High: {candle['high']}, "
f"Low: {candle['low']}, Close: {candle['close']}, "
f"Volume: {candle['volume']}")
The SDK is the right choice for most trading bots. Drop down to raw HTTP requests only when you need WebSocket streams (the SDK's WebSocket support is limited) or when you're hitting Prime API endpoints that the SDK doesn't cover yet. For the Coinbase International API docs, there's currently no official SDK — you'll need raw requests with JWT auth.
Compare this to how Binance handles it: the python-binance library is community-maintained and excellent, but Coinbase's official SDK being first-party means it tracks API changes faster. On Bybit and OKX, the official SDKs are similarly well-maintained, but their API structures differ enough that switching between them requires real effort. If you're running a multi-exchange bot that hits Coinbase, Binance, and Bitget simultaneously, you'll want an abstraction layer — or a platform like VoiceOfChain that aggregates signals across exchanges without you building the connectors yourself.
The REST API is fine for placing orders and checking account state, but for real-time price feeds you need WebSockets. The Coinbase Advanced API WebSocket endpoint streams live trades, order book updates, and ticker data. Authentication here uses the same JWT approach:
import asyncio
import websockets
import json
CB_WS_URL = "wss://advanced-trade-ws.coinbase.com"
async def stream_ticker(product_ids: list):
async with websockets.connect(CB_WS_URL) as ws:
# Build subscription message with JWT auth
token = build_jwt("GET", "/ws")
subscribe_msg = {
"type": "subscribe",
"product_ids": product_ids,
"channel": "ticker",
"jwt": token
}
await ws.send(json.dumps(subscribe_msg))
async for raw_msg in ws:
msg = json.loads(raw_msg)
if msg.get("channel") == "ticker":
for event in msg.get("events", []):
for ticker in event.get("tickers", []):
print(
f"{ticker['product_id']}: "
f"${ticker['price']} "
f"({ticker['price_percent_chg_24h']}% 24h)"
)
# Run it
asyncio.run(stream_ticker(["BTC-USD", "ETH-USD", "SOL-USD"]))
The JWT token on WebSocket connections expires in 2 minutes, so for long-running streams you'll need to handle reconnection and re-auth. A clean pattern is to wrap the connection in a retry loop that rebuilds the JWT on reconnect. Gate.io and KuCoin use similar WebSocket auth patterns if you're familiar with those — Coinbase's implementation is actually cleaner than most.
The Coinbase API documentation has matured into a solid resource. The shift from the old Exchange/Pro API to the Advanced Trade API brought cleaner endpoint design, proper SDK support, and JWT auth that's easier to reason about than the old HMAC approach. For traders building Python-based bots, the coinbase-advanced-py SDK gets you to first trade in under an hour.
That said, API access gives you execution capability — it doesn't tell you when to trade. For that, combining Coinbase's order infrastructure with a signal layer makes sense. Platforms like VoiceOfChain aggregate real-time signals across multiple exchanges and timeframes, so you can use the Coinbase API for execution while letting a dedicated signal engine handle the analysis side. It's a cleaner architecture than trying to build both in the same bot.
Whether you're pulling data from the International API docs to build a perps strategy, using the Prime API docs for institutional custody integration, or just running a basic DCA bot via the Advanced API — the foundation is the same: clean auth, tested endpoints, and robust error handling. Start there, and the rest follows.