---
title: "Node.js SDK for Coinbase Advanced Trade: Integration Guide"
description: "Explore the Node.js SDK for Coinbase Advanced Trade. Reduce signing and auth boilerplate with coinbase-api while maintaining custom pacing and safe controls."
canonical: "https://siebly.io/blog/nodejs-sdk-for-coinbase-advanced-trade-integration-guide"
---

# Node.js SDK for Coinbase Advanced Trade: Integration Guide

Explore the Node.js SDK for Coinbase Advanced Trade. Reduce signing and auth boilerplate with coinbase-api while maintaining custom pacing and safe controls.

## Technical Disclaimer

These articles are software engineering references for exchange API integrations. They are not financial, investment, legal, tax, compliance, or trading advice. Use public data, demo, testnet, or paper workflows first. Keep API credentials out of frontend code and disable withdrawal permissions for automation keys.

## Overview {#overview}

[coinbase-api](/sdk/coinbase/javascript) is the Node.js package for Coinbase REST and WebSockets. Advanced Trade is one client in that package, `CBAdvancedTradeClient`, plus a shared `WebsocketClient` for the market and user streams. The client builds the JWT, signs the request, and exposes typed methods. Your application still decides how fast to call Coinbase, what to do when a call fails, and which key permissions are safe to grant.

The package docs explain how those endpoints show up as methods. The same npm package also includes clients for the Coinbase App, Exchange, International Exchange, Prime, and Commerce APIs. This guide stays on Advanced Trade.

## Key Takeaways {#key-takeaways}

- Install [coinbase-api](/sdk/coinbase/javascript) and use `CBAdvancedTradeClient` for Advanced Trade REST. Use `WebsocketClient` for Advanced Trade market and user streams.
- Advanced Trade auth is a JWT. Pass an ECDSA or ED25519 key as `apiKey` and `apiSecret`, or pass the downloaded CDP key JSON as `cdpApiKey`. The client detects the key type.
- Public product calls need no API key. Account and order calls do.
- Place and cancel orders with REST methods such as `submitOrder` and `cancelOrders`. The WebSocket client subscribes to channels. It does not place orders.
- The client does not throttle requests and does not retry REST calls. WebSocket reconnect and resubscribe are handled by `WebsocketClient`.
- `useSandbox: true` switches the Exchange and International clients. It does not point Advanced Trade at Coinbase's static sandbox.



## When this SDK fits {#when-this-sdk-fits}

Raw Advanced Trade calls repeat the same work: JWT signing, timestamps, request bodies, response parsing, and WebSocket connect, heartbeat, and resubscribe logic. [coinbase-api](/sdk/coinbase/javascript) already does that for the endpoints it implements.

Check the method list against the calls your app actually makes. The Advanced Trade client covers accounts, products, orders, fills, portfolios, futures, perpetuals, converts, payment methods, and the public market routes. The endpoint map lives in the package docs and in [endpointFunctionList.md](https://github.com/tiagosiebler/coinbase-api/blob/master/docs/endpointFunctionList.md). If a route you need is missing there, do not assume a similarly named method exists.

TypeScript projects get request and response types with the package. JavaScript projects use the same methods. The build ships both ESM (`import`) and CommonJS (`require`).

## What the client handles {#what-the-client-handles}

The SDK handles request plumbing. For Advanced Trade that means JWT auth, key-type detection, timestamps, typed REST methods, and WebSocket connection tracking. `WebsocketClient` opens the socket it needs, sends heartbeats, reconnects after a drop, and resubscribes to the topics you already registered. Listen for `open`, `update`, `reconnect`, `reconnected`, `close`, `response`, and `exception` in your own code so you can log and react.

Your application handles safety. Store secrets outside the repo. Limit key permissions. Turn withdrawals off for automation keys. Pace requests yourself. Decide which errors are safe to retry. A dropped REST call is not retried by the client. Retrying `submitOrder` on a timeout can create a second order if the first one actually landed.

Coinbase defines the API. Accepted fields, product rules, auth requirements, and rate limits come from Coinbase. The SDK does not change them, and it does not slow calls down to stay under those limits.

### Authentication {#authentication}

Advanced Trade and the Coinbase App API use the same JWT flow. Create a key in [Coinbase API key management](https://www.coinbase.com/settings/api), then pass either the key name and private key, or the exported `cdp_api_key.json` object.

ECDSA secrets are PEM text, including the `BEGIN EC PRIVATE KEY` and `END EC PRIVATE KEY` lines. ED25519 secrets are the base64 private key string. You do not pass an API passphrase for Advanced Trade. Exchange, International, and Prime do use `apiPassphrase`, so do not reuse this constructor for those clients.

Load the values at runtime. The examples in the repo read `API_KEY_NAME` and `API_PRIVATE_KEY`.

```js title="Imported example"
import { CBAdvancedTradeClient } from "coinbase-api";

const client = new CBAdvancedTradeClient({
  apiKey: process.env.API_KEY_NAME,
  apiSecret: process.env.API_PRIVATE_KEY,
});
```

The same values can be passed as one object:

```js title="Imported example"
const client = new CBAdvancedTradeClient({
  cdpApiKey: {
name: process.env.API_KEY_NAME,
privateKey: process.env.API_PRIVATE_KEY,
  },
});
```

### Rate limits and retries {#rate-limits-and-retries}

Nothing in `CBAdvancedTradeClient` queues, delays, or drops calls to respect a rate limit. If Coinbase returns a limit error, your code sees the exception and has to decide what to do. Check the current Advanced Trade limit docs and put pacing in the application, around the client, so you can test it on its own.

REST methods are single attempts. There is no retry wrapper in the REST client. WebSocket reconnect is a separate path: the socket client will try to reconnect and then resubscribe. That does not replay a REST order.

`submitOrder` validates `client_order_id`. If you omit it, the client fills one in. Generated ids start with the prefix `cbnode`. If you pass your own id, use `client.generateNewOrderId()`, or the client will prepend that prefix and log a warning.

## How to choose an integration approach {#how-to-choose-an-integration-approach}

Pick the approach from the calls you need, then read how that library maps onto Coinbase's docs.

- Endpoint coverage. `CBAdvancedTradeClient` methods line up with Advanced Trade REST, including `submitOrder` (`POST /api/v3/brokerage/orders`) and `getAccounts`. `WebsocketClient` covers the public market feed (`advTradeMarketData`) and the private user feed (`advTradeUserData`).
- Docs. Trace a method to the Coinbase page for that route before you depend on a response field.
- Language. The package is JavaScript with TypeScript types, for Node. It also documents a webpack bundle for browser use. That bundle has smaller differences from the Node build, and the browser notes in the README are still thin, so treat browser use as something you verify yourself.
- Auth. Advanced Trade is JWT with ECDSA or ED25519, as shown above.
- Ownership. The library signs and sends. You own secrets, pacing, retries, and what a reconnect means for your order state.

Calling REST yourself means you maintain signing and request shapes. Coinbase's own samples and SDKs are worth reading against the same checklist. [coinbase-api](/sdk/coinbase/javascript) is the Siebly package that already implements the Advanced Trade clients described here. Other Siebly exchange packages (Binance, Bybit, OKX, and the rest) are separate npm modules with their own clients. They are listed on the [SDK directory](/sdk).



## Build an Advanced Trade integration {#build-an-advanced-trade-integration}

Install the current package, then run one public call before you add keys.

```bash title="Imported example"
npm install coinbase-api
```

### Read public market data {#read-public-market-data}

Public routes do not need a key. This follows `examples/AdvancedTrade/Public/advanced-public-rest-all.ts`.

```js title="Imported example"
import { CBAdvancedTradeClient } from "coinbase-api";
// const { CBAdvancedTradeClient } = require('coinbase-api');

const client = new CBAdvancedTradeClient();

async function publicCalls() {
  try {
const serverTime = await client.getServerTime();
console.log("Server Time: ", serverTime);

const publicProduct = await client.getPublicProduct({
product_id: "BTC-USD",
});
console.log("Public Product: ", publicProduct);

const productBook = await client.getPublicProductBook({
product_id: "BTC-USD",
limit: 10,
});
console.log("Public Product Book: ", productBook);
  } catch (e) {
console.error("Error: ", e);
  }
}

publicCalls();
```

The same file also calls `getPublicProducts`, `getPublicProductCandles`, and `getPublicMarketTrades`. Start with one of these and check the parsed object before you move on.

### Read accounts {#read-accounts}

`getAccounts` is private. It needs the key from the authentication section. This follows `examples/AdvancedTrade/Private/getAccounts.ts`.

```js title="Imported example"
import { CBAdvancedTradeClient } from "coinbase-api";

const client = new CBAdvancedTradeClient({
  apiKey: process.env.API_KEY_NAME,
  apiSecret: process.env.API_PRIVATE_KEY,
});

async function getAccounts() {
  try {
const accounts = await client.getAccounts({ limit: 10 });
console.log("Accounts: ", accounts);

if (accounts.accounts.length > 0) {
const accountId = accounts.accounts[0].uuid;
const accountDetails = await client.getAccount({ account_id: accountId });
console.log("Account Details: ", accountDetails);
}
  } catch (e) {
console.error("Get accounts error: ", e);
  }
}

getAccounts();
```

`getOrders` and `getOrder` follow the same pattern in `examples/AdvancedTrade/Private/getOrders.ts`.

### Submit an order {#submit-an-order}

`submitOrder` is a live REST call to `POST /api/v3/brokerage/orders`. Run it only when you mean to trade, with a key that cannot withdraw, and with a size you are willing to send. This follows `examples/AdvancedTrade/Private/submitOrderSpot.ts`.

```js title="Imported example"
import { CBAdvancedTradeClient } from "coinbase-api";

const client = new CBAdvancedTradeClient({
  apiKey: process.env.API_KEY_NAME,
  apiSecret: process.env.API_PRIVATE_KEY,
});

async function submitLimitOrder() {
  try {
const limitOrder = await client.submitOrder({
product_id: "BTC-USDT",
order_configuration: {
limit_limit_gtc: {
base_size: "0.001",
limit_price: "50000.00",
},
},
side: "BUY",
client_order_id: client.generateNewOrderId(),
});
console.log("Limit Order Result: ", limitOrder);
  } catch (e) {
console.error("Submit limit order error: ", e);
  }
}

submitLimitOrder();
```

A market order uses the same method with `order_configuration: { market_market_ioc: { base_size: '0.001' } }`. Confirm the product id against `getPublicProduct` first. `BTC-USD` and `BTC-USDT` are different products, and the sample above uses the product id from the repo example.

There is no Advanced Trade WebSocket method for placing an order in this package. User-order updates arrive on the user stream after the REST call.

### Subscribe to the market WebSocket {#subscribe-to-the-market-websocket}

Public market data uses the ws key `advTradeMarketData`. No API key is required. The client connects to `wss://advanced-trade-ws.coinbase.com` when you subscribe. This follows `examples/AdvancedTrade/WebSockets/publicWs.ts`.

```js title="Imported example"
import { WebsocketClient } from "coinbase-api";

const client = new WebsocketClient();

client.on("open", (data) => {
  console.log("open: ", data?.wsKey);
});

client.on("update", (data) => {
  console.info(new Date(), "data received: ", 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("exception", (data) => {
  console.error("exception: ", data);
});

client.subscribe(
  {
topic: "ticker",
payload: {
product_ids: ["ETH-USD", "BTC-USD"],
},
  },
  "advTradeMarketData",
);
```

Other public topics in that example include `heartbeats`, `candles`, `market_trades`, `status`, `ticker_batch`, and `level2`. Pass a string, one object, or an array of objects as the first argument. The second argument is the ws key that selects the feed.

Private user streams use `advTradeUserData` and `wss://advanced-trade-ws-user.coinbase.com`. Put the same `apiKey` and `apiSecret` on `WebsocketClient`. Subscriptions on that ws key are signed with those credentials. The repo example subscribes to `user` and `futures_balance_summary` in `examples/AdvancedTrade/WebSockets/privateWs.ts`.

`useSandbox` does not give these Advanced Trade sockets a test host. The testnet entries in the client are `NotAvailable`.

### About the Advanced Trade sandbox {#about-the-advanced-trade-sandbox}

Responses are fixed mocks in the production JSON shape. The published list is accounts, orders, and a handful of portfolio and perpetuals routes. A few error cases need an `X-Sandbox` request header.

`useSandbox: true` does not select that host for `CBAdvancedTradeClient`. In this package the Advanced Trade sandbox URL is the placeholder `NoSandboxAvailable`. Setting the flag sends traffic at that placeholder. The flag does work for `CBExchangeClient` (Exchange sandbox) and `CBInternationalClient`.

`RestClientOptions` also accepts `baseUrl`. Use the result to check response shape only. It will not show live matching, partial fills, or rate limits.

For a first integration check, the public product calls above are the path the examples actually use.

## Keep the integration safe {#keep-the-integration-safe}

Keep test keys and production keys in different runtime config. Prefer public product calls while you are wiring the client. Do not treat a sandbox mock, or a successful `getPublicProduct`, as proof that a live `submitOrder` will behave the same way.

Keep secrets out of source control, logs, screenshots, and chat transcripts. Grant only the permissions that workflow needs, and disable withdrawals on keys that place orders.

On the WebSocket side, the client owns the socket lifecycle. Your code should still handle `exception` and `close`, and it should rebuild any local order book from a fresh snapshot after `reconnected`. Do not keep applying deltas across a gap.

Before you widen the workflow:

- Secrets come from the environment or a secret manager, and the automation key cannot withdraw.
- The REST methods and WebSocket topics you call are in the current package and match the current Coinbase docs.
- Request pacing lives in your code and follows Coinbase's current limits.
- You have tests for bad input, auth failure, REST errors, and a socket drop followed by `reconnected`.

The [Coinbase JavaScript SDK page](/sdk/coinbase/javascript) and the package [README](https://github.com/tiagosiebler/coinbase-api#readme) are the setup references. [Explore Siebly.io](/) for the other exchange packages.

## Build on the methods the package actually ships {#build-on-the-methods-the-package-actually-ships}

Confirm the REST methods and WebSocket topics you need, then install [coinbase-api](/sdk/coinbase/javascript) and call them as the examples do. Use `CBAdvancedTradeClient` for REST and `WebsocketClient` for streams. Keep Coinbase's docs next to you for field rules and limits. Pace requests in your own code, and keep order retries explicit.

[Explore the Siebly Coinbase SDK](/sdk/coinbase/javascript).

## Frequently Asked Questions {#frequently-asked-questions}

### Does a Node.js SDK support Coinbase Advanced Trade? {#does-a-node-js-sdk-support-coinbase-advanced-trade}

Yes. The npm package is [coinbase-api](/sdk/coinbase/javascript). Advanced Trade REST goes through `CBAdvancedTradeClient`. Streams go through `WebsocketClient` with the ws keys `advTradeMarketData` and `advTradeUserData`. Compare the method you want with Coinbase's Advanced Trade docs before you depend on a field.

### How do I install it? {#how-do-i-install-it}

```bash title="Imported example"
npm install coinbase-api
```

Import `CBAdvancedTradeClient` or `WebsocketClient` from `coinbase-api`. CommonJS can `require` the same names. Types ship with the package. Avoid copying constructors from the Exchange or International examples. Those clients expect an API passphrase and, when you want it, `useSandbox`.

### Does the Siebly Coinbase SDK handle rate limits for me? {#does-the-siebly-coinbase-sdk-handle-rate-limits-for-me}

No. `coinbase-api` does not delay or queue requests. Your application paces calls and handles limit errors. Coinbase's current docs are the reference for those limits. The same is true of the other Siebly exchange SDKs: they do not throttle for you. Some of them can surface rate-limit fields the exchange already returned. That is not the same as holding requests back.

### Can I use WebSockets? {#can-i-use-websockets}

Yes, for streams. Construct `WebsocketClient`, subscribe with a topic and a ws key, and listen for `update`. Public market data uses `advTradeMarketData`. Private user data uses `advTradeUserData` and your API key. The client reconnects and resubscribes. Order placement stays on REST (`submitOrder`).

### How should I store Coinbase API credentials? {#how-should-i-store-coinbase-api-credentials}

Put `API_KEY_NAME` and `API_PRIVATE_KEY` in a secret manager or protected environment config. Keep them out of git, logs, and support tickets. Use a key that can only do what that process needs, with withdrawals disabled. ECDSA private keys include the PEM header and footer. ED25519 keys are the base64 secret. The client accepts either.

### Is an SDK better than calling the API directly? {#is-an-sdk-better-than-calling-the-api-directly}

Use the SDK when you want the JWT signing, typed methods, and WebSocket reconnect that `coinbase-api` already implements, and when those methods cover your routes. Call the API yourself when you want to own every header and you already have that client code. Either way, Coinbase's docs define the API.

### How can I test without placing a live order? {#how-can-i-test-without-placing-a-live-order}

Call public methods such as `getPublicProduct` and `getServerTime` with `new CBAdvancedTradeClient()`. Subscribe to `advTradeMarketData` the same way, with no key. Coinbase's static sandbox is a separate host for mocked account and order JSON. `useSandbox` on this client does not select it. Exchange and International are the Coinbase products where that flag is wired up. Read the sandbox page before you point `baseUrl` anywhere, and do not treat mocks as live trading behavior.

Ready to try the client? [Explore the Siebly Coinbase SDK](/sdk/coinbase/javascript) and match it against the endpoints you need.

## Related articles

- [Integrating Coinbase Advanced Trade API with Node.js: A 2026 Engineering Guide](/blog/integrating-coinbase-advanced-trade-api-with-nodejs-a-2026-engineering-guide)
- [Coinbase Pro to Advanced Trade Migration Guide](/blog/coinbase-pro-to-advanced-trade-migration-guide)
- [Coinbase Advanced Trade Node.js Library: Production-Ready Implementation Guide](/blog/coinbase-advanced-trade-nodejs-library-production-ready-implementation-guide)


## Related Siebly Resources

- [Binance JavaScript SDK](/sdk/binance/javascript)
- [Bybit JavaScript SDK](/sdk/bybit/javascript)
- [OKX JavaScript SDK](/sdk/okx/javascript)
- [Siebly SDK directory](/sdk)
- [Exchange State Management](/ai/exchange-state)
