Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/tiagosiebler/coinbase-api/llms.txt

Use this file to discover all available pages before exploring further.

Coinbase’s institutional-grade APIs — Exchange, International (INTX), and Prime — each expose their own WebSocket feed. All three use the same WebsocketClient and the same event model as Advanced Trade. The main difference is the WsKey you pass to subscribe(), and the credentials your client is initialised with.
internationalMarketData and primeMarketData always require valid API credentials. There is no public (unauthenticated) access to these feeds. The SDK will throw if credentials are missing when you attempt to subscribe.

WsKey reference

WsKeyAuth requiredURL
exchangeMarketDataNowss://ws-feed.exchange.coinbase.com
exchangeDirectMarketDataYeswss://ws-direct.exchange.coinbase.com
internationalMarketDataAlwayswss://ws-md.international.coinbase.com
primeMarketDataAlwayswss://ws-feed.prime.coinbase.com
Sandbox URLs are available for Exchange and International — pass useSandbox: true when constructing the client.

Authentication differences

Authentication for these products uses HMAC signing with an API passphrase, not JWT. Pass all three credentials to the constructor:
import { WebsocketClient } from 'coinbase-api';

const client = new WebsocketClient({
  apiKey: process.env.API_KEY,
  apiSecret: process.env.API_SECRET,
  // The passphrase you set when creating the API key — NOT your account password
  apiPassphrase: process.env.API_PASSPHRASE,
});
The SDK signs each subscribe request automatically using the appropriate algorithm for the target feed:
  • Exchange — HMAC-SHA256 of timestamp + "GET" + "/users/self/verify"
  • International — HMAC-SHA256 of timestamp + apiKey + "CBINTLMD" + passphrase
  • Prime — HMAC-SHA256 of the channel name, access key, service account ID, timestamp, portfolio ID, and product IDs
No manual signing is required.

Coinbase Exchange

Exchange offers two feeds on different WsKey values. Use exchangeMarketData for unauthenticated market data, and exchangeDirectMarketData for authenticated channels that require direct server access.

Public feed (exchangeMarketData)

import { WebsocketClient } from 'coinbase-api';

const client = new WebsocketClient(); // no credentials needed

client.on('open',        (data) => console.log('open:',      data?.wsKey));
client.on('update',      (data) => console.info('data:',     JSON.stringify(data)));
client.on('reconnect',   (data) => console.log('reconnect:', data));
client.on('reconnected', (data) => console.log('reconnected:', data));
client.on('close',       (data) => console.error('close:',   data));
client.on('response',    (data) => console.info('response:', JSON.stringify(data, null, 2)));
client.on('exception',   (data) => console.error('exception:', data));

// Subscribe to multiple public Exchange channels at once
client.subscribe(
  [
    // Heartbeat — confirm connection is alive per product
    { topic: 'heartbeat',    payload: { product_ids: ['ETH-EUR'] } },
    // Trading status for all products
    'status',
    // Open order book and auction data
    { topic: 'auctionfeed',  payload: { product_ids: ['LTC-USD'] } },
    // Trade matches (executions)
    { topic: 'matches',      payload: { product_ids: ['BTC-USD'] } },
    // RFQ matches — no product filter required
    { topic: 'rfq_matches',  payload: {} },
    // Best bid/ask per product
    { topic: 'ticker',       payload: { product_ids: ['ETH-USD', 'BTC-USD'] } },
    // Batched ticker updates
    { topic: 'ticker_batch', payload: { product_ids: ['ETH-USD', 'BTC-USD'] } },
    // Level-2 order book (batch updates)
    { topic: 'level2_batch', payload: { product_ids: ['ETH-USD', 'BTC-USD'] } },
  ],
  'exchangeMarketData',
);

Authenticated direct feed (exchangeDirectMarketData)

import { WebsocketClient } from 'coinbase-api';

const client = new WebsocketClient({
  apiKey: 'yourAPIKeyHere',
  apiSecret: 'yourAPISecretHere',
  apiPassphrase: 'yourAPIPassPhraseHere',
  // Optional — connect to the sandbox environment
  // useSandbox: true,
});

client.on('open',      (data) => console.log('open:',      data?.wsKey));
client.on('update',    (data) => console.info('data:',     JSON.stringify(data)));
client.on('response',  (data) => console.info('response:', JSON.stringify(data, null, 2)));
client.on('exception', (data) => console.error('exception:', data));

// The full channel streams every order lifecycle event
client.subscribe(
  { topic: 'full', payload: { product_ids: ['BTC-USD'] } },
  'exchangeDirectMarketData',
);

// The balance channel streams account balance updates
client.subscribe(
  {
    topic: 'balance',
    payload: {
      account_ids: [
        'd50ec984-77a8-460a-b958-66f114b0de9b',
        'd50ec984-77a8-460a-b958-66f114b0de9a',
      ],
    },
  },
  'exchangeDirectMarketData',
);

// Subscribe to multiple authenticated channels at once
client.subscribe(
  [
    { topic: 'full',    payload: { product_ids: ['BTC-USD'] } },
    { topic: 'user',    payload: { product_ids: ['BTC-USD'] } },
    { topic: 'level2',  payload: { product_ids: ['BTC-USD'] } },
    {
      topic: 'balance',
      payload: {
        account_ids: [
          'd50ec984-77a8-460a-b958-66f114b0de9b',
          'd50ec984-77a8-460a-b958-66f114b0de9a',
        ],
      },
    },
  ],
  'exchangeDirectMarketData',
);

Exchange channel reference

ChannelFeedDescription
heartbeatPublicPer-product heartbeat to confirm the connection
statusPublicTrading status for all listed products
tickerPublicBest bid/ask and last trade price
ticker_batchPublicBatched ticker updates
matchesPublicTrade executions (matches)
rfq_matchesPublicRFQ trade matches
auctionfeedPublicOpen order book and auction data
level2_batchPublicBatched level-2 order book updates
fullAuthFull order lifecycle events
level2AuthLevel-2 order book (direct feed)
userAuthAuthenticated user’s orders
balanceAuthAccount balance updates

Coinbase International (INTX)

The International feed always requires authentication. Attempting to subscribe without credentials will throw an error.
import { WebsocketClient, WsTopicRequest } from 'coinbase-api';

const client = new WebsocketClient({
  apiKey:        process.env.CB_INTX_API_KEY,
  apiSecret:     process.env.CB_INTX_API_SECRET,
  apiPassphrase: process.env.CB_INTX_API_PASSPHRASE,
});

client.on('open',        (data) => console.log('open:',      data?.wsKey));
client.on('update',      (data) => console.info('data:',     JSON.stringify(data)));
client.on('reconnect',   (data) => console.log('reconnect:', data));
client.on('reconnected', (data) => console.log('reconnected:', data));
client.on('close',       (data) => console.error('close:',   data));
client.on('response',    (data) => console.info('response:', JSON.stringify(data, null, 2)));
client.on('exception',   (data) => console.error('exception:', data));

// Subscribe to level-1 order book for BTC perpetuals
const orderbookRequest: WsTopicRequest = {
  topic: 'LEVEL1',
  payload: {
    product_ids: ['BTC-PERP'],
  },
};

client.subscribe(orderbookRequest, 'internationalMarketData');
As of September 2024, the INTX WebSocket does not support nested parameters inside the channels array. The SDK works around this by sending one subscription request per topic — this is handled automatically and requires no changes to your code.

Coinbase Prime

The Prime feed always requires authentication. All credentials — apiKey, apiSecret, and apiPassphrase — are mandatory.
Prime authentication signs each request using the channel name, access key, service account ID, timestamp, portfolio ID, and an optional list of product IDs. The SDK generates and attaches this signature for every subscription request.
import { WebsocketClient } from 'coinbase-api';

const client = new WebsocketClient({
  apiKey:        process.env.CB_PRIME_API_KEY,
  apiSecret:     process.env.CB_PRIME_API_SECRET,
  apiPassphrase: process.env.CB_PRIME_API_PASSPHRASE,
});

client.on('open',        (data) => console.log('open:',      data?.wsKey));
client.on('update',      (data) => console.info('data:',     JSON.stringify(data)));
client.on('reconnect',   (data) => console.log('reconnect:', data));
client.on('reconnected', (data) => console.log('reconnected:', data));
client.on('close',       (data) => console.error('close:',   data));
client.on('response',    (data) => console.info('response:', JSON.stringify(data, null, 2)));
client.on('exception',   (data) => console.error('exception:', data));

client.subscribe(
  {
    topic: 'market_trades',
    payload: {
      product_ids: ['BTC-USD'],
    },
  },
  'primeMarketData',
);

Shared event handling

The event model is identical across all feeds. The update event fires whenever a message arrives from any channel; use the wsKey field in the payload to distinguish sources if you share one client across multiple feeds.
client.on('update', (data) => {
  switch (data.wsKey) {
    case 'exchangeMarketData':
      // Exchange public data — data.type identifies the channel
      break;
    case 'exchangeDirectMarketData':
      // Exchange authenticated data
      break;
    case 'internationalMarketData':
      // INTX data
      break;
    case 'primeMarketData':
      // Prime data
      break;
  }
});

Sandbox support

Exchange and International support a sandbox environment. Pass useSandbox: true to redirect all connections to the sandbox URLs automatically:
const client = new WebsocketClient({
  apiKey:        process.env.API_KEY,
  apiSecret:     process.env.API_SECRET,
  apiPassphrase: process.env.API_PASSPHRASE,
  useSandbox:    true,
});
FeedSandbox URL
Exchange publicwss://ws-feed-public.sandbox.exchange.coinbase.com
Exchange directwss://ws-direct.sandbox.exchange.coinbase.com
Internationalwss://ws-md.n5e2.coinbase.com

Build docs developers (and LLMs) love