Skip to main content

Advanced Trade API Authentication Overview

This guide explains how to authenticate requests to the Advanced REST API endpoints and WebSocket server channels. Most Advanced API calls require authentication.

Authentication Schemes

Coinbase has multiple authentication schemes available for different APIs. The following table shows schemes relevant to the Advanced APIs and adjacent Sign in with Coinbase (SIWC) APIs.

SchemeWho Should UseWhen to Use
Cloud API Trading keysIndividuals or applications for individual use

If you have security keys enabled on your account
  • With all Advanced REST APIs & WebSocket channels
  • With new Advanced API features like Portfolios
  • Cannot be used on SIWC APIs
OAuthApplications serving many users
  • Can be used with Advanced REST API
  • Can be used with SIWC APIs
Legacy API keysIndividuals or applications for individual use
  • Required with SIWC APIs
  • Can be used with Advanced REST APIs & WebSocket channels (except new features)

Cloud API Trading Keys

Coinbase Cloud supports two API key types, "Trading" keys and "General" keys. The Advanced API is only compatible with Cloud API Trading keys.


Cloud API Trading keys are new and may not be supported by all third-party applications.

Creating Trading Keys

  1. Log into Coinbase Cloud.
  2. Navigate to Access => API keys.
  3. Click Create API key, select Trading key, and click Next.
  4. In the Create trading API key dialog, configure:
    • API key nickname.
    • Portfolio (e.g., Default).
    • Permission level (View, Trade, Transfer).
    • Allowlist IPs.
  5. Click Create & Download.
  6. Click Complete 2-factor authentication and enter your Coinbase Cloud 2FA code. The key automatically downloads as a JSON file.
  7. In the final popup, you can optionally copy the API Key Name and Private Key (which are also in the JSON download). Read the warning and click Got it to finish.
Click to enlarge
Image of

Making Requests

Cloud API keys are used to generate a JSON Web Token (JWT) for an API. Once you've generated a JWT, set it as a Authorization Bearer header to make an authenticated request.

# Example request to get account
curl -H "Authorization: Bearer $JWT" ''

Generating a JWT

Regardless of which code snippet you use, follow these steps:

  1. Replace key name and key secret with your key name and private key. key secret is a multi-line key and newlines must be preserved to properly parse the key. Do this on one line with \n escaped newlines, or with a multi-line string.

  2. Replace the request method and the path you want to test. If the URI has a UUID in the path you should include that UUID here, e.g., api/v3/brokerage/accounts/f603f97c-37d7-4e58-b264-c27e9e393dd9.

  3. Run the generation script that prints the command export JWT=....

  4. Run the generated command to save your JWT.


    Your JWT expires after 2 minutes, after which all requests are unauthenticated.


    You must generate a different JWT for each unique API request.

Code Samples

The easiest way to generate a JWT is to use the built-in functions in our Python SDK as described below.

Otherwise, use the code samples below to generate/export a JWT and make an authenticated request.

  1. Install the SDK.

    pip3 install coinbase-advanced-py
  2. In the console, run: python (or whatever your file name is).

  3. Set the JWT to that output, or export the JWT to the environment with eval $(python

  4. Make your request, example curl -H "Authorization: Bearer $JWT" ''

from coinbase import jwt_generator

api_key = "organizations/{org_id}/apiKeys/{key_id}"
api_secret = "-----BEGIN EC PRIVATE KEY-----\nYOUR PRIVATE KEY\n-----END EC PRIVATE KEY-----\n"

request_method = "GET"
request_path = "/api/v3/brokerage/accounts"

def main():
jwt_uri = jwt_generator.format_jwt_uri(request_method, request_path)
jwt_token = jwt_generator.build_rest_jwt(jwt_uri, api_key, api_secret)
print(f"export JWT={jwt_token}")

if __name__ == "__main__":


Use OAuth authentication if you're building an application for many users on top of the Advanced Trade APIs. See Sign in with Coinbase OAuth2 Integration to get a client set up and make authenticated calls.

Legacy API Keys

Use legacy API key authentication if you need access to both the Advanced Trade and Sign in with Coinbase APIs.

Creating Legacy Keys

Generate an API key on and copy the API key string and API secret to create a signature.

  1. Login and navigate to
  2. Select New API Key and enter you 2FA code.
  3. Configure the following key details:
    • Accounts
    • Permissions
    • Notifications
    • Allowlist IPs
  4. Securely store the values of your new API key and API secret. They will not be shown again.

Signing Requests

All Advanced Trade REST API requests with legacy API keys must contain the following headers:

CB-ACCESS-KEYAPI key as a string (that you create on
CB-ACCESS-SIGNEncoded signature using API secret
CB-ACCESS-TIMESTAMPTimestamp for your request

Advanced Trade does not require a PASSPHRASE as did Coinbase Pro.

Creating a Signature

  1. Create a signature string by concatenating the values of these query parameters with the + operator: timestamp + method + requestPath + body.

    • timestamp is the same as the CB-ACCESS-TIMESTAMP header (+/-30 seconds)
    • method should be UPPER CASE
    • requestPath is the full path (minus the base URL and query parameters), for example:
      • /api/v3/brokerage/orders/historical/fills
      • /api/v3/brokerage/products/BTC-USD/ticker
    • body is the request body string -- it is omitted if there is no request body (typically for GET requests)
  2. Create a sha256 HMAC object with your API secret on the signature string.

  3. Get the hexadecimal string representation of the sha256 HMAC object and pass that in as the CB-ACCESS-SIGN header.

lowercase signature

A signature must be in lowercase letters or the program throws a 401 error.

Signature Code Samples

The following examples demonstrate how to generate a signature in Python, Ruby, and JavaScript:

import json, hmac, hashlib, time, base64
#timestamp = str(int(time.time()))
#request.method = GET or POST
#request.path_url.split('?')[0] = /api/v3/brokerage/orders/historical/batch
message = timestamp + request.method + request.path_url.split('?')[0] + str(request.body or '')
signature ='utf-8'), message.encode('utf-8'), digestmod=hashlib.sha256).digest()
print(signature.hex(), ts)

The Advanced Trade requestPath should only include the path of the API endpoint in the string for hashing. It should not include the base URL (protocol and domain) nor any query parameters. By contrast, the SIWC requestPath does include query parameters.

APIrequestPathValid Example
Advanced (v3)API endpoint/api/v3/brokerage/products/BTC-USD/ticker
SIWC (v2)API endpoint + query params/v2/exchange-rates?currency=USD

Making Requests

All private API requests must include CB-ACCESS-* headers:

  1. Set a timestamp for the CB-ACCESS-TIMESTAMP header.
  2. Create an encoded signature as the CB-ACCESS-SIGN header (with the API secret).
  3. Set your legacy API key for the CB-ACCESS-KEY header.
  4. Apply the headers to the request. You are ready to send.

Example Request

curl \
--header "CB-ACCESS-KEY: <your api key>" \
--header "CB-ACCESS-SIGN: <the user generated message signature>" \
--header "CB-ACCESS-TIMESTAMP: <a timestamp for your request>"

All requests should have content type application/json and the body must be valid JSON.

// Ruby code sample of a GET Request to product ticker

require 'uri'
require 'net/http'
require 'openssl'

url = URI("")
request_path= "/api/v3/brokerage/products/BTC-USD/ticker"
body = ""
method = "GET"

timestamp =
payload = "#{timestamp}#{method}#{request_path}#{body}"
# create a sha256 hmac with the secret
signature = OpenSSL::HMAC.hexdigest('sha256', $SECRET_KEY, payload)

http =, url.port)
http.use_ssl = true

request =
request["accept"] = 'application/json'
request["CB-ACCESS-SIGN"] = signature
request["CB-ACCESS-TIMESTAMP"] = timestamp

response = http.request(request)
puts response.read_body

Was this helpful?