NAV
python shell

Introduction

Gemini offers two WebSocket APIs for streaming data:

  1. a private Order Events API
  2. a public Market Data API

Advantages include:

For example, to keep track of your orders, you might be requesting the Get Active Orders endpoint every five seconds:

  1. request /v1/orders
  2. bring back HTTP header data and a response body
  3. parse the JSON in the response body
  4. compare the latest response against the previous response to see what has changed

Using the private Order Events API, you would subscribe once and receive real time notifications of all order activity.

For general information about how the WebSocket protocol works, refer to:

Survey

Please complete our API Use Survey to help us improve your experience using the Gemini APIs.

Sandbox

Gemini's sandbox site is an instance of the Gemini Exchange that offers full exchange functionality using test funds.

Sandbox URLs

Website
https://exchange.sandbox.gemini.com

REST API
https://api.sandbox.gemini.com

WebSocket Feed
wss://api.sandbox.gemini.com

Documentation
https://docs.sandbox.gemini.com

Create your account

Go to the sandbox site to register for a test account to begin trading.

Your account will automatically be credited with USD, BTC, ETH, ZEC, BCH, LTC, OXT, LINK, BAT and DAI. You may use these funds to trade, both through the web site and through the API.

Gemini's sandbox site does not support either depositing or withdrawing your test funds, which can only be used to trade on the sandbox exchange.

Sandbox does not support email notifications. If you need this as part of your testing plan, please contact trading@gemini.com.

If you have any issues, or if you need to adjust your balances (to test insufficient funds handling, for example), contact trading@gemini.com.

Two Factor Authentication

Two factor authentication ("2FA") is enabled by default for all sandbox accounts. To disable 2FA for automated testing, please do the following:

  1. At the Authy 2FA entry screen, set a cookie or an HTTP header with the name GEMINI-SANDBOX-2FA. The value doesn’t matter.
  2. Enter 9999999 as your 2FA code

Rate Limits

To prevent abuse, Gemini imposes rate limits on incoming requests as described in the Gemini API Agreement.

For public WebSocket APIs, we recommend that you do not exceed 1 request per symbol per minute.

Requests

Both public and private WebSocket API requests begin with a GET request that includes headers asking for an upgrade to the WebSocket protocol.

However, the private API WebSocket request also includes the standard private API headers.

The Sec-WebSocket-Key and Sec-WebSocket-Version headers shown in the examples wll be added by your WebSocket client. See the WebSocket RFC for more detail.

Public API request headers

GET wss://api.gemini.com/v1/marketdata/BTCUSD
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Key: uRovscZjNol/umbTt5uKmw==
Sec-WebSocket-Version: 13

Private request headers

GET wss://api.gemini.com/v1/order/events
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Key: uRovscZjNol/umbTt5uKmw==
Sec-WebSocket-Version: 13
X-GEMINI-APIKEY: qOfnZJDZTTBsxdM3bVRP
X-GEMINI-PAYLOAD: eyJyZXF1ZXN0IjoiL3YxL29yZGVyL2V2ZW50cyIsIm5vbmNlIjoxNDc3OTYzMjQwNzQxMDgzMzA3fQ==
X-GEMINI-SIGNATURE: 88cd6f391d8f920a76a2060d613b519a8e8b4b3fb5bff089ea826d49ac73888bd479c0c2e2062ba60ba7afbe273132e3

Private API invocation

To walk through the process of generating a private API invocation, we start with the request json itself

{
    "request": "/v1/order/events",
    "nonce": <nonce>
}

Whitespace is ignored by the server, and may be included if desired. The hashes are always taken on the base64 string directly, with no normalization, so whatever is sent in the payload is what should be hashed, and what the server will verify.

~$ base64 << EOF
> {
>     "request": "/v1/order/events",
>     "nonce": <nonce>
> }
> EOF
ewogICAgInJlcXVlc3QiOiAiL3YxL29yZGVyL3N0YXR1cyIsCiAgICAibm9uY2UiOiAxMjM0NTYs
CgogICAgIm9yZGVyX2lkIjogMTg4MzQKfQo=
import ssl
import websocket
import json
import base64
import hmac
import hashlib
import time

def on_message(ws, message):
    print(message)

def on_error(ws, error):
    print(error)

def on_close(ws):
    print("### closed ###")

gemini_api_key = "mykey"
gemini_api_secret = "1234abcd".encode()

payload = {"request": "/v1/order/events","nonce": time.time()}
encoded_payload = json.dumps(payload).encode()
b64 = base64.b64encode(encoded_payload)
signature = hmac.new(gemini_api_secret, b64, hashlib.sha384).hexdigest()


ws = websocket.WebSocketApp("wss://api.sandbox.gemini.com/v1/order/events",
                            on_message=on_message,
                            header={
                                'X-GEMINI-PAYLOAD': b64.decode(),
                                'X-GEMINI-APIKEY': gemini_api_key,
                                'X-GEMINI-SIGNATURE': signature
                            })
ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE})

In this example, the api_secret is 1234abcd

echo -n 'ewogICAgInJlcXVlc3QiOiAiL3YxL29yZGVyL3N0YXR1cyIsCiAgICAibm9uY2UiOiAxMjM0NTYsCgogICAgIm9yZGVyX2lkIjogMTg4MzQKfQo=' | openssl sha384 -hmac "1234abcd"
(stdin)= 337cc8b4ea692cfe65b4a85fcc9f042b2e3f702ac956fd098d600ab15705775017beae402be773ceee10719ff70d710f
hmac.new("1234abcd", b64, hashlib.sha384).hexdigest()
'337cc8b4ea692cfe65b4a85fcc9f042b2e3f702ac956fd098d600ab15705775017beae402be773ceee10719ff70d710f'

The final request will look like this. The linebreaks are added for clarity, your http library may or may not put them in.

POST /v1/order/events
Content-Type: text/plain
Content-Length: 0
X-GEMINI-APIKEY: mykey
X-GEMINI-PAYLOAD:ewogICAgInJlcXVlc3QiOiAiL3YxL29yZGVyL3N
    0YXR1cyIsCiAgICAibm9uY2UiOiAxMjM0NTYsCgogICAgIm9yZGV
    yX2lkIjogMTg4MzQKfQo=
X-GEMINI-SIGNATURE: 337cc8b4ea692cfe65b4a85fcc9f042b2e3f
    702ac956fd098d600ab15705775017beae402be773ceee10719f
    f70d710f

Authentication

Gemini uses API keys to allow access to private APIs. You can obtain these by logging on and creating a key in Settings/API. This will give you both an "API Key" that will serve as your user name, and an "API Secret" that you will use to sign messages.

All requests must contain a nonce, a number that will never be repeated and must increase between requests. This is to prevent an attacker who has captured a previous request from simply replaying that request. We recommend using a timestamp at millisecond or higher precision. The nonce need only be increasing with respect to the session that the message is on.

Payload

The payload of the requests will be a JSON object, which will be described in the documentation below. Rather than being sent as the body of the POST request, it will be base-64 encoded and stored as a header in the request.

All of them will include the request name and the nonce associated with the request. The nonce must be increasing with each request to prevent replay attacks.

Header Value
Content-Length 0
Content-Type text/plain
X-GEMINI-APIKEY Your Gemini API key
X-GEMINI-PAYLOAD The base64-encoded JSON payload
X-GEMINI-SIGNATURE hex(HMAC_SHA384(base64(payload), key=api_secret))
Cache-Control no-cache

Roles

Example of error response due to API key missing a role

{
   "result":"error",
   "reason":"MissingRole",
   "message":"To access this endpoint, you need to log in to the website and go to the settings page to assign one of these roles [FundManager] to API key wujB3szN54gtJ4QDhqRJ which currently has roles [Trader]"
}

Gemini uses a role-based system for private API endpoints so that you can separate privileges for your API keys.

By assigning different roles to different API keys, you can create

  1. one API key that can trade, and
  2. another API key that can withdraw digital assets, or
  3. an API key to have access to read-only endpoints

You can configure which roles are assigned to your API keys by logging in to the Gemini Exchange website and going to API Settings to configure your API keys.

If you try to access an endpoint that requires a role you did not assign to your API key, you will get back a response with:

See Error Codes for more information about API error responses.

Trader

Assigning the Trader role to an API key allows this API key to:

Fund Manager

Gemini does not offer any WebSocket APIs for the Fund Manager role right now.

Instead, this role is used for REST API endpoints:

Auditor

Assigning the Auditor role to an API key allows this API key to:

Endpoint summary

Here's a summary of which role you need to assign to your API key to use each endpoint in the API:

Endpoint URI Trader can access? Fund Manager can access? Auditor can access?
Order Events /v1/order/events

Responses

If successful, API requests will return an HTTP 101 Switching Protocols code in the response headers:

HTTP/1.1 101 Switching Protocols
Connection: upgrade
Upgrade: websocket
Sec-WebSocket-Accept: wEV5o5orKGO27qATSTLczquY3EH=

Then the HTTP connection will be replaced by a WebSocket connection. All API responses, both public and private, will be sent over the WebSocket connection.

Client Order ID

Order Event subscription Accepted event showing client_order_id

[ {
  "type" : "accepted",
  "order_id" : "372456298",
  "event_id" : "372456299",
  "client_order_id": "20170208_example", 
  "api_session" : "AeRLptFXoYEqLaNiRwv8",
  "symbol" : "btcusd",
  "side" : "buy",
  "order_type" : "exchange limit",
  "timestamp" : "1478203017",
  "timestampms" : 1478203017455,
  "is_live" : true,
  "is_cancelled" : false,
  "is_hidden" : false,
  "avg_execution_price" : "0", 
  "original_amount" : "14.0296",
  "price" : "1059.54"
} ]

Order Status endpoint for the same order, showing client_order_id

{
    "avg_execution_price": "0.00",
    "client_order_id": "20170208_example",
    "exchange": "gemini",
    "executed_amount": "0",
    "id": "372456298",
    "is_cancelled": false,
    "is_hidden": false,
    "is_live": true,
    "order_id": "372456298",
    "original_amount": "14.0296",
    "price": "1059.54",
    "remaining_amount": "14.0296",
    "side": "buy",
    "symbol": "btcusd",
    "timestamp": "1478203017",
    "timestampms": 1478203017455,
    "type": "exchange limit",
    "was_forced": false
}

Client order ID is a client-supplied order identifier that Gemini will echo back to you in all subsequent messages about that order.

Although this identifier is optional, Gemini strongly recommends supplying client_order_id when placing orders using the New Order endpoint.

This makes it easy to track the Order Events: Accepted and Order Events: Booked responses in your Order Events WebSocket subscription.

Visibility

Your client order ids are only visible to the Gemini exchange and you. They are never visible on any public API endpoints.

Uniqueness

Gemini recommends that your client order IDs should be unique per trading session.

Allowed characters

Your client order ids should match against this PCRE regular expression: [:\-_\.#a-zA-Z0-9]{1,100}.

Characters Description ASCII Codes (Dec)
A-Z Uppercase A-Z 65 - 90
a-z Lowercase a-z 97 - 122
0-9 Digits 48 - 57
# Hash, octothorpe, number sign 35
- Hyphen 45
. Period 46
: Colon 58
_ Underscore 95

Data Types

The protocol description below will contain references to various types, which are collected here for reference

Type Description
string A simple quoted string, following standard JSON rules; see the JSON spec for details.
decimal A decimal value, encoded in a JSON string. The contents will be a series of digits, followed by an optional decimal point and additional digits.
timestamp The number of seconds since 1970-01-01 UTC. This is usually provided for compatibility; implementors should use the more precise timestampms when available. When used as an input, either the millisecond or second precision is usable; this is unambiguous for dates past 1/29/1970
timestampms The number of milliseconds since 1970-01-01 UTC. The begin date is the standard UNIX epoch, so this will be 1000 times the UNIX timestamp in seconds. This will be transmitted as a JSON number, not a string.
integer An whole number, transmitted as a JSON number.
boolean A JSON boolean, the literal string true or false
array a JSON array. Each element contains a payload that will be described.

Timestamps

The timestamp data type describes a date and time as a whole number in Unix Time format, as the number of seconds or milliseconds since 1970-01-01 UTC.

Requests

When timestamp is supplied as a request parameter, the following two values are supported in order of preference:

  1. The number of milliseconds since 1970-01-01 UTC
  2. The number of seconds since 1970-01-01 UTC (unix epoch)

For your convenience, a POST request may supply the timestamp parameter in a JSON payload as a string instead of a number.

Timestamp format example Supported request type
whole number (seconds) 1495127793 GET, POST
string (seconds) "1495127793" POST only
whole number (milliseconds) 1495127793000 GET, POST
string (milliseconds) "1495127793000" POST only

Behavior

If the timestamp parameter is not present, the default behavior is to return the most recent items in the list. For example, the public Trade History endpoint will return the most recent trades without a timestamp parameter.

The first trade on Gemini occurred at 1444311607801 milliseconds. Any request for a timestamp value before this is the same as requesting the very first item in the list.

You may choose to supply a timestamp of 0 to get the first trade in the list when retrieving trades historically.

If unable to parse your timestamp value, the exchange will return an InvalidTimestampInPayload error.

Responses

In a JSON response, the key

For backwards compatibility, some but not all timestamp values will be supplied in seconds.

Basis Point

We calculate fees as a fraction of the notional value of each trade (i.e., price × amount). We use units of basis points (“bps”), which represent 1/100th of a percent of notional value. For example, a fee of 25 bps means that 0.25% of the denominated value of the trade will be kept by our exchange, either deducted from the gross proceeds of a trade or charged to the account at the time a trade is executed. Any fees will be applied at the time an order is placed. For partially filled orders, only the executed portion is subject to trading fees.

For more information see Fee Calculation.

Symbols and minimums

Symbols are formatted as CCY1CCY2 where prices are in CCY2 and quantities are in CCY1. CCY1 is in the Currency column and CCY2 is in the respective CCY2 Price Increment column:

Symbol Minimum Order Size Tick Size Quote Currency Price Increment
btcusd 0.00001 BTC (1e-5) 0.00000001 BTC (1e-8) 0.01 USD
btceur 0.00001 BTC (1e-5) 0.00000001 BTC (1e-8) 0.01 EUR
btcgbp 0.00001 BTC (1e-5) 0.00000001 BTC (1e-8) 0.01 GBP
btcsgd 0.00001 BTC (1e-5) 0.00000001 BTC (1e-8) 0.01 SGD
ethbtc 0.001 ETH (1e-3) 0.000001 ETH (1e-6) 0.00001 BTC (1e-5)
ethusd 0.001 ETH (1e-3) 0.000001 ETH (1e-6) 0.01 USD
etheur 0.001 ETH (1e-3) 0.000001 ETH (1e-6) 0.01 EUR
ethgbp 0.001 ETH (1e-3) 0.000001 ETH (1e-6) 0.01 GBP
ethsgd 0.001 ETH (1e-3) 0.000001 ETH (1e-6) 0.01 SGD
zecusd 0.001 ZEC (1e-3) 0.000001 ZEC (1e-6) 0.01 USD
zecbtc 0.001 ZEC (1e-3) 0.000001 ZEC (1e-6) 0.0000001 BTC (1e-7)
zeceth 0.001 ZEC (1e-3) 0.000001 ZEC (1e-6) 0.00001 ETH (1e-5)
zecbch 0.001 ZEC (1e-3) 0.000001 ZEC (1e-6) 0.0001 BCH (1e-4)
zecltc 0.001 ZEC (1e-3) 0.000001 ZEC (1e-6) 0.001 LTC (1e-3)
bchusd 0.001 BCH (1e-3) 0.000001 BCH (1e-6) 0.01 USD
bchbtc 0.001 BCH (1e-3) 0.000001 BCH (1e-6) 0.00001 BTC (1e-5)
bcheth 0.001 BCH (1e-3) 0.000001 BCH (1e-6) 0.0001 ETH (1e-4)
ltcusd 0.01 LTC (1e-2) 0.00001 LTC (1e-5) 0.01 USD
ltcbtc 0.01 LTC (1e-2) 0.00001 LTC (1e-5) 0.0000001 BTC (1e-7)
ltceth 0.01 LTC (1e-2) 0.00001 LTC (1e-5) 0.00001 ETH (1e-5)
ltcbch 0.01 LTC (1e-2) 0.00001 LTC (1e-5) 0.0001 BCH (1e-4)
batusd 1.0 BAT (1e0) 0.000001 BAT (1e-6) 0.00001 USD (1e-5)
daiusd 0.1 DAI (1e-1) 0.000001 DAI (1e-6) 0.00001 USD (1e-5)
linkusd 0.1 LINK (1e-1) 0.000001 LINK (1e-6) 0.00001 USD (1e-5)
oxtusd 1.0 OXT (1e0) 0.000001 OXT (1e-6) 0.00001 USD (1e-5)
batbtc 1.0 BAT (1e0) 0.000001 BAT (1e-6) 0.00000001 BTC (1e-8)
linkbtc 0.1 LINK (1e-1) 0.000001 LINK (1e-6) 0.00000001 BTC (1e-8)
oxtbtc 1.0 OXT (1e0) 0.000001 OXT (1e-6) 0.00000001 BTC (1e-8)
bateth 1.0 BAT (1e0) 0.000001 BAT (1e-6) 0.0000001 ETH (1e-7)
linketh 0.1 LINK (1e-1) 0.000001 LINK (1e-6) 0.0000001 ETH (1e-7)
oxteth 1.0 OXT (1e0) 0.000001 OXT (1e-6) 0.0000001 ETH (1e-7)
ampusd 10.0 AMP (1e1) 0.000001 AMP (1e-6) 0.00001 USD (1e-5)
compusd 0.001 COMP (1e-3) 0.000001 COMP (1e-6) 0.01 USD
paxgusd 0.0001 PAXG (1e-4) 0.00000001 PAXG (1e-8) 0.01 USD
mkrusd 0.001 MKR (1e-3) 0.000001 MKR (1e-6) 0.01 USD
zrxusd 0.1 ZRX (1e-1) 0.000001 ZRX (1e-6) 0.00001 USD (1e-5)
manausd 1.0 MANA (1e0) 0.000001 MANA (1e-6) 0.00001 USD (1e-5)
storjusd 0.1 STORJ (1e-1) 0.000001 STORJ (1e-6) 0.00001 USD (1e-5)
snxusd 0.01 SNX (1e-2) 0.000001 SNX (1e-6) 0.0001 USD (1e-4)
crvusd 0.1 CRV (1e-1) 0.000001 CRV (1e-6) 0.0001 USD (1e-4)
uniusd 0.01 UNI (1e-2) 0.000001 UNI (1e-6) 0.0001 USD (1e-4)
renusd 0.01 REN (1e-2) 0.000001 REN (1e-6) 0.00001 USD (1e-5)
umausd 0.01 UMA (1e-2) 0.000001 UMA (1e-6) 0.0001 USD (1e-4)
yfiusd 0.00001 YFI (1e-5) 0.000001 YFI (1e-6) 0.01 USD
btcdai 0.00001 BTC (1e-5) 0.00000001 BTC (1e-8) 0.01 DAI
ethdai 0.001 ETH (1e-3) 0.000001 ETH (1e-6) 0.01 DAI
aaveusd 0.001 AAVE (1e-3) 0.000001 AAVE (1e-6) 0.0001 USD (1e-4)
filusd 0.1 FIL (1e-1) 0.000001 FIL (1e-6) 0.0001 USD (1e-4)
sklusd 0.1 SKL (1e-1) 0.000001 SKL (1e-6) 0.00001 USD (1e-5)
grtusd 0.1 GRT (1e-1) 0.000001 GRT (1e-6) 0.0001 USD (1e-4)
lrcusd 0.1 LRC (1e-1) 0.000001 LRC (1e-6) 0.00001 USD (1e-5)
sandusd 0.1 SAND (1e-1) 0.000001 SAND (1e-6) 0.00001 USD (1e-5)
cubeusd 0.01 CUBE (1e-2) 0.000001 CUBE (1e-6) 0.0001 USD (1e-4)
lptusd 0.001 LPT (1e-3) 0.000001 LPT (1e-6) 0.0001 USD (1e-4)
maticusd 0.1 MATIC (1e-1) 0.000001 MATIC (1e-6) 0.00001 USD (1e-5)
injusd 0.01 INJ (1e-2) 0.000001 INJ (1e-6) 0.0001 USD (1e-4)
sushiusd 0.01 SUSHI (1e-2) 0.000001 SUSHI (1e-6) 0.0001 USD (1e-4)
dogeusd 0.1 DOGE (1e-1) 0.000001 DOGE (1e-6) 0.00001 USD (1e-5)
ftmusd 0.03 FTM (3e-2) 0.000001 FTM (1e-6) 0.0001 USD (1e-4)
ankrusd 0.1 ANKR (1e-1) 0.000001 ANKR (1e-6) 0.00001 USD (1e-5)
btcgusd 0.00001 BTC (1e-5) 0.00000001 BTC (1e-8) 0.01 GUSD
ethgusd 0.001 ETH (1e-3) 0.000001 ETH (1e-6) 0.01 GUSD
ctxusd 0.002 CTX (2e-3) 0.000001 CTX (1e-6) 0.0001 USD (1e-4)
xtzusd 0.02 XTZ (2e-2) 0.000001 XTZ (1e-6) 0.0001 USD (1e-4)
axsusd 0.003 AXS (3e-3) 0.000001 AXS (1e-6) 0.01 USD (1e-2)
lunausd 1 LUNA (1e0) 0.000001 LUNA (1e-6) 0.00000001 USD (1e-8)
dogebtc 1.0 DOGE (1e0) 0.00000001 DOGE (1e-8) 0.000000001 BTC (1e-9)
dogeeth 1.0 DOGE (1e0) 0.00000001 DOGE (1e-8) 0.00000001 ETH (1e-8)
rareusd 0.1 RARE (1e-1) 0.000001 RARE (1e-6) 0.001 USD (1e-3)
qntusd 0.0004 QNT (4e-4) 0.000001 QNT (1e-6) 0.01 USD (1e-2)
maskusd 0.01 MASK (1e-2) 0.000001 MASK (1e-6) 0.001 USD (1e-3)
fetusd 0.1 FET (1e-1) 0.000001 FET (1e-6) 0.00001 USD (1e-5)
api3usd 0.03 API3 (3e-2) 0.000001 API3 (1e-6) 0.001 USD (1e-3)
usdcusd 0.1 USDC (1e-1) 0.000001 USDC (1e-6) 0.00001 USD (1e-5)
shibusd 1000.0 SHIB (1e3) 0.000001 SHIB (1e-6) 0.000000001 USD (1e-9)
rndrusd 0.02 RNDR (2e-2) 0.000001 RNDR (1e-6) 0.001 USD (1e-3)
galausd 0.4 GALA (4e-1) 0.000001 GALA (1e-6) 0.00001 USD (1e-5)
ensusd 0.002 ENS (2e-3) 0.000001 ENS (1e-6) 0.001 USD (1e-3)
tokeusd 0.002 TOKE (2e-3) 0.000001 TOKE (1e-6) 0.001 USD (1e-3)
ldousd 0.02 LDO (2e-2) 0.000001 LDO (1e-6) 0.001 USD (1e-3)
rlyusd 0.2 RLY (2e-1) 0.000001 RLY (1e-6) 0.00001 USD (1e-5)
solusd 0.001 SOL (1e-3) 0.000001 SOL (1e-6) 0.001 USD (1e-3)
apeusd 0.02 APE (2e-2) 0.000001 APE (1e-6) 0.001 USD (1e-3)
gusdsgd 0.1 GUSD 0.000001 GUSD (1e-6) 0.001 SGD (1e-3)
qrdousd 0.04 QRDO (4e-2) 0.000001 QRDO (1e-6) 0.00001 USD (1e-5)
zbcusd 3.0 ZBC (3e0) 0.000001 ZBC (1e-6) 0.00001 USD (1e-5)
chzusd 0.5 CHZ (5e-1) 0.000001 CHZ (1e-6) 0.00001 USD (1e-5)
jamusd 10.0 JAM (1e1) 0.000001 JAM (1e-6) 0.0000001 USD (1e-7)
gmtusd 0.1 GMT (1e-1) 0.000001 GMT (1e-6) 0.00001 USD (1e-5)
aliusd 2.0 ALI (2e0) 0.000001 ALI (1e-6) 0.000001 USD (1e-6)
gusdgbp 0.1 GUSD 0.0001 GUSD (1e-4) 0.001 GBP (1e-3)
dotusd 0.01 DOT (1e-2) 0.000001 DOT (1e-6) 0.0001 USD (1e-4)
ernusd 0.05 ERN (5e-2) 0.000001 ERN (1e-6) 0.0001 USD (1e-4)
galusd 0.04 GAL (4e-2) 0.000001 GAL (1e-6) 0.0001 USD (1e-4)
samousd 10.0 SAMO (1e+1) 0.000001 SAMO (1e-6) 0.0000001 USD (1e-7)
imxusd 0.1 IMX (1e-1) 0.000001 IMX (1e-6) 0.00001 USD (1e-5)
iotxusd 3.0 IOTX (3e+0) 0.000001 IOTX (1e-6) 0.000001 USD (1e-6)
avaxusd 0.005 AVAX (5e-3) 0.000001 AVAX (1e-6) 0.001 USD (1e-3)
atomusd 0.01 ATOM (1e-2) 0.000001 ATOM (1e-6) 0.001 USD (1e-3)
usdtusd 0.1 USDT (1e-1) 0.000001 USDT (1e-6) 0.0001 USD (1e-4)
btcusdt 0.00001 BTC (1e-5) 0.00000001 BTC (1e-8) 0.01 USDT (1e-2)
ethusdt 0.001 ETH (1e-3) 0.000001 ETH (1e-6) 0.01 USDT (1e-2)
pepeusd 1000 PEPE (1e3) 0.000001 PEPE (1e-6) 0.000000001 USD (1e-9)
xrpusd 0.1 XRP (1e-1) 0.000001 XRP (1e-6) 0.00001 USD (1e-5)
hntusd 0.04 HNT (1e-1) 0.000001 HNT (1e-6) 0.0001 USD (1e-4)

All Supported Symbols

btcusd ethbtc ethusd zecusd zecbtc zeceth zecbch zecltc bchusd bchbtc bcheth ltcusd ltcbtc ltceth ltcbch batusd daiusd linkusd oxtusd batbtc linkbtc oxtbtc bateth linketh oxteth ampusd compusd paxgusd mkrusd zrxusd manausd storjusd snxusd crvusd uniusd renusd umausd yfiusd btcdai ethdai aaveusd filusd btceur btcgbp etheur ethgbp btcsgd ethsgd sklusd grtusd lrcusd sandusd cubeusd lptusd maticusd injusd sushiusd dogeusd ftmusd ankrusd btcgusd ethgusd ctxusd xtzusd axsusd lunausd dogebtc dogeeth rareusd qntusd maskusd fetusd api3usd usdcusd shibusd rndrusd galausd ensusd elonusd tokeusd ldousd rlyusd solusd apeusd gusdsgd qrdousd zbcusd chzusd jamusd gmtusd aliusd gusdgbp dotusd ernusd galusd samousd imxusd iotxusd avaxusd atomusd usdtusd btcusdt ethusdt pepeusd xrpusd hntusd

Sequence numbers

So you can easily ensure that you are receiving all of your WebSocket messages in the expected order without any gaps, events and heartbeats contain a special sequence number.

  1. WebSocket connection is established
  2. Optional: subscription acknowledgement, such as Order Events: Subscription Acknowledgement
  3. Your subscription begins - you receive your first event with socket_sequence set to a value of 0
  4. For all further messages, each message - whether a heartbeat or an event - should increase this sequence number by one.
    • If you see a gap in this sequence number, then you should disconnect and reconnect.

Please note:

Order Events

Order events is a private API that gives you information about your orders in real time.

When you connect, you get a book of your active orders. Then in real time you'll get information about order events like:

and more.

You can use optional subscription filters to tailor your WebSocket feed to suit your individual needs. You can even create multiple WebSocket feeds for multiple purposes.

Event Types

Workflow

  1. Client submits order to Gemini exchange
  2. Is the order accepted?
    • Yes, order is accepted
      1. Gemini sends an accepted order event
      2. Gemini sends zero or more initial fill events
      3. Does the order have non-zero remaining quantity?
        • Yes, the order has non-zero remaining quantity
          • Gemini sends a booked event
          • the order rests until
            • client sends a cancel request
              • Is the order cancelled?
                1. Yes, the order is cancelled
                  • Gemini sends a cancelled event followed by a closed event
                  • No further order events about this order
                2. No, the cancel request could not be fulfilled
                  • Gemini sends a cancel_rejected event explaining why the order cancel request could not be fulfilled.
                  • The order continues to rest on the books
            • a trade executes, partially or completely filling the order
              • Gemini sends a fill event with details about the trade, including remaining quantity
              • Is the order completely filled?
                1. Yes, the order is completely filled
                  • Gemini sends a closed event
                  • No further order events about this order
                2. No, the order has remaining quantity
                  • The order continues to rest on the books
        • No, the order has been completely filled
          • Gemini sends a closed event
          • No further order events about this order
    • No, order is rejected
      • Gemini responds with a rejected order event explaining why the order was rejected
      • No further order events about this order

Keeping track of your orders

When you place an order using the New Order endpoint, supply your identifier in the client_order_id field.

The Order Events API will then echo it back to you in every single message about this order.

See Client Order ID for more information.

You can use the account_name field, if using a Master scoped API key.

How Filtering Works

Filtering is completely optional. If you don't specify any filters when you connect, you'll see all your order events: for every symbol, every API session and the UI, every event type.

If you want to filter, it's simple. Filtering works by whitelisting. You can filter on any combination of the following criteria:

  1. one or more supported symbols
  2. one or more of your API session keys
    • use UI as the session key for orders placed through the website
  3. one or more order event types
    • if you don't specify initial, you will not receive your active orders at the beginning of the subscription

You may create multiple connections, filtered any way you like.

To provide a list of arguments, repeat the parameter once for each argument you want to provide:

wss://api.gemini.com/v1/order/events?symbolFilter=btcusd&symbolFilter=ethbtc&eventTypeFilter=initial&eventTypeFilter=fill&eventTypeFilter=closed

For example, if you wanted to see all BTCUSD order event types for both API session key t14phVqvAAJlK4YiXmBM and your web users, you would subscribe to order events using this WebSocket URL:

wss://api.gemini.com/v1/order/events?apiSessionFilter=t14phVqvAAJlK4YiXmBM&&apiSessionFilter=UI&symbolFilter=btcusd

You would neither see orders for a different currency nor orders placed by a different API session key than the ones you specified.

If you wanted to create a dropcopy-like event feed, to see order fills for all orders associated with your account on all symbols, connect using:

wss://api.gemini.com/v1/order/events?eventTypeFilter=fill

To see your active orders, fills, and cancels:

wss://api.gemini.com/v1/order/events?eventTypeFilter=initial&eventTypeFilter=fill&eventTypeFilter=canceled

In general, if you create a custom event type filter, Gemini recommends always including initial: otherwise, you won't see your active orders when you connect.

WebSocket Request

npm install -g wscat
wscat -H X-GEMINI-PAYLOAD:your-payload \
 -H X-GEMINI-APIKEY:your-api-key \
 -H X-GEMINI-SIGNATURE:your-signature \
 --connect wss://api.gemini.com/v1/order/events
import ssl
import websocket
import json
import base64
import hmac
import hashlib
import time

def on_message(ws, message):
    print(message)

def on_error(ws, error):
    print(error)

def on_close(ws):
    print("### closed ###")

gemini_api_key = "mykey"
gemini_api_secret = "1234abcd".encode()

payload = {"request": "/v1/order/events","nonce": time.time()}
encoded_payload = json.dumps(payload).encode()
b64 = base64.b64encode(encoded_payload)
signature = hmac.new(gemini_api_secret, b64, hashlib.sha384).hexdigest()


ws = websocket.WebSocketApp("wss://api.gemini.com/v1/order/events?symbolFilter=btcusd&eventTypeFilter=fill&eventTypeFilter=closed&apiSessionFilter=UI&heartbeat=true",
                            on_message=on_message,
                            header={
                                'X-GEMINI-PAYLOAD': b64.decode(),
                                'X-GEMINI-APIKEY': gemini_api_key,
                                'X-GEMINI-SIGNATURE': signature
                            })
ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE})

wss://api.gemini.com/v1/order/events

Roles

The API key you use to access this endpoint must have the Trader or Auditor role assigned. See Roles for more information.

NOTE: Using a Master scoped API key receives event data for all accounts in the group.

Headers

Your WebSocket request needs to include these three headers:

Header Value
X-GEMINI-APIKEY Your Gemini API session key
X-GEMINI-PAYLOAD Before base64-encoding, the JSON payload for the X-GEMINI-PAYLOAD header looks like this, where 123456 is a valid nonce value for your account.

{
"request": "/v1/order/events",
"nonce": 123456
}
X-GEMINI-SIGNATURE See Private API Invocation for an explanation of how to create the signature hash.

URL Parameters

Parameter Type Required? Description
symbolFilter string N Optional symbol filter for order event subscription
apiSessionFilter string N Optional API session key filter for order event subscription
eventTypeFilter string N Optional order event type filter for order event subscription
heartbeat boolean N Optional filter to stream heartbeats. The default for this parameter is false.

Response

Limit Order accepted

[{
    "type": "accepted",
    "order_id": "109535951",
    "event_id": "109535952",
    "account_name": "primary",
    "api_session": "UI",
    "symbol": "btcusd",
    "side": "buy",
    "order_type": "exchange limit",
    "timestamp": "1547742904",
    "timestampms": 1547742904989,
    "is_live": true,
    "is_cancelled": false,
    "is_hidden": false,
    "original_amount": "1",
    "price": "3592.00",
    "socket_sequence": 13
}]

Market Buy accepted

[{
    "type": "accepted",
    "order_id": "109964529",
    "event_id": "109964530",
    "account_name": "primary",
    "api_session": "UI",
    "symbol": "bchusd",
    "side": "buy",
    "order_type": "market buy",
    "timestamp": "1547756076",
    "timestampms": 1547756076644,
    "is_live": false,
    "is_cancelled": false,
    "is_hidden": false,
    "total_spend": "200.00",
    "socket_sequence": 29
}]

Market Sell accepted

[{
    "type": "accepted",
    "order_id": "109964616",
    "event_id": "109964617",
    "account_name": "primary",
    "api_session": "UI",
    "symbol": "ethusd",
    "side": "sell",
    "order_type": "market sell",
    "timestamp": "1547756893",
    "timestampms": 1547756893937,
    "is_live": true,
    "is_cancelled": false,
    "is_hidden": false,
    "original_amount": "25",
    "socket_sequence": 26
}]

Maker-or-cancel limit order accepted

[{
    "type": "accepted",
    "order_id": "109964647",
    "event_id": "109964648",
    "account_name": "primary",
    "api_session": "UI",
    "symbol": "ethusd",
    "side": "sell",
    "order_type": "exchange limit",
    "timestamp": "1547757139",
    "timestampms": 1547757139783,
    "is_live": true,
    "is_cancelled": false,
    "is_hidden": false,
    "original_amount": "5",
    "price": "122.30",
    "behavior": "maker-or-cancel",
    "socket_sequence": 16
}]

Immediate-or-cancel limit order accepted, then immediately filled and closed

[{
  "type" : "accepted",
  "order_id" : "652164",
  "event_id" : "652165",
  "account_name": "primary",
  "api_session" : "UI",
  "symbol" : "btcusd",
  "side" : "buy",
  "order_type" : "exchange limit",
  "timestamp" : "1478790127",
  "timestampms" : 1478790127297,
  "is_live" : true,
  "is_cancelled" : false,
  "is_hidden" : false,
  "original_amount" : "2",
  "price" : "714.01",
  "behavior" : "immediate-or-cancel", 
  "socket_sequence" : 131419
}]
    ...
[{
  "type" : "fill",
  "order_id" : "652164",
  "account_name": "primary",
  "api_session" : "UI",
  "symbol" : "btcusd",
  "side" : "buy",
  "order_type" : "exchange limit",
  "timestamp" : "1478790127",
  "timestampms" : 1478790127297,
  "is_live" : false,
  "is_cancelled" : false,
  "is_hidden" : false,
  "avg_execution_price" : "714.00",
  "executed_amount" : "2",
  "remaining_amount" : "0",
  "original_amount" : "2",
  "price" : "714.01",
  "fill" : {
    "trade_id" : "652166",
    "liquidity" : "Taker",
    "price" : "714.00",
    "amount" : "2",
    "fee" : "3.57",
    "fee_currency" : "USD"
  }, 
  "socket_sequence" : 131420
}, {
  "type" : "closed",
  "order_id" : "652164",
  "event_id" : "652168",
  "account_name": "primary",
  "api_session" : "UI",
  "symbol" : "btcusd",
  "side" : "buy",
  "order_type" : "exchange limit",
  "timestamp" : "1478790127",
  "timestampms" : 1478790127297,
  "is_live" : false,
  "is_cancelled" : false,
  "is_hidden" : false,
  "avg_execution_price" : "714.00",
  "executed_amount" : "2",
  "remaining_amount" : "0",
  "original_amount" : "2",
  "price" : "714.01", 
  "socket_sequence" : 131421
}]

Once your WebSocket session is established, you will receive:

  1. a subscription acknowledgement
  2. a list of your active orders, if you supply either
    • no eventTypeFilter, or
    • an explicit eventTypeFilter=initial argument as part of one or more eventTypeFilter arguments in your WebSocket request
  3. ongoing order events interspersed with heartbeats every five seconds
    • A response is a JSON array containing one or more order event objects
    • Order events will arrive in real time, in the sequence that they happened on the exchange
    • Each order event pertains to a single order but a batch of order events may contain order events pertaining to multiple orders.
    • Use the order_id field in the initial order to keep track of what's happening to each order
    • Heartbeats are never batched with other order events

Common fields

These fields are common to all order events except subscription_ack and heartbeat.

Subscription acknowledgement

Subscription acknowledgement response:

{
  "type": "subscription_ack",
  "accountId": 5365,
  "subscriptionId": "ws-order-events-5365-b8bk32clqeb13g9tk8p0",
  "symbolFilter": [
    "btcusd"
  ],
  "apiSessionFilter": [
    "UI"
  ],
  "eventTypeFilter": [
    "fill",
    "closed"
  ]
}

The first message you receive acknowledges your subscription.

Compare the filters to the ones you requested to make sure your request was parsed as you expected.

Field Type Required? Description
type order event type Y subscription_ack
accountId integer Y The account id associated with the API session key you supplied in your X-GEMINI-APIKEY header. When using a master API key, it will be the account group id associated with the API session key. See Private API Invocation for more details.
subscriptionId string Y The id associated with this websocket subscription; the component after the last dash is a request trace id that will be echoed back in the heartbeat traceId field.
symbolFilter string array Y An array of zero or more supported symbols. An empty array means your subscription is not filtered by symbol.
apiSessionFilter string array Y An array of zero or more API session keys associated with your account. The string "UI" means you want to see orders placed by your website users. An empty array means you want to see all orders on your account, regardless of whether they were placed via the API or the website.
eventTypeFilter string array Y An array of zero or more order event types. An empty array means your subscription is not filtered by event type.

Heartbeats

Heartbeat response

{
  "type": "heartbeat",
  "timestampms": 1547742998508,
  "sequence": 31,
  "trace_id": "b8biknoqppr32kc7gfgg",
  "socket_sequence": 37
}

Gemini will send a heartbeat every five seconds so you'll know your WebSocket connection is active.

Gemini recommends logging and retaining all heartbeat messages. If your WebSocket connection is unreliable, please contact Gemini support with this log.

Field Type Required? Description
type order event type N heartbeat. This can be set to true in the [heartbeat URL parameter]((#order-events). Defaults to true
timestampms timestampms Y Gemini adds a timestamp so if you get disconnected, you may contact Gemini support with the timestamp of the last heartbeat you received.
sequence integer Y Gemini adds a monotonically incrementing sequence to make it easy to tell if you've missed a heartbeat. Not the same as socket_sequence!
socket_sequence integer Y zero-indexed monotonic increasing sequence number attached to each message sent - if there is a gap in this sequence, you have missed a message. See Sequence Numbers for more information.
trace_id string Y Gemini adds a trace id to each WebSocket request that our networking team can use to trace your request in our logs.

Active Orders

Your active orders

[ {
  "type": "initial",
  "order_id": "109939984",
  "account_name": "primary",
  "api_session": "myapikey",
  "symbol": "btcusd",
  "side": "sell",
  "order_type": "exchange limit",
  "timestamp": "1547754474",
  "timestampms": 1547754474438,
  "is_live": true,
  "is_cancelled": false,
  "is_hidden": false,
  "avg_execution_price": "0.00",
  "executed_amount": "0",
  "remaining_amount": "1",
  "original_amount": "1",
  "price": "3631.23",
  "socket_sequence": 0
}, {
  "type": "initial",
  "order_id": "109940168",
  "api_session": "UI",
  "symbol": "zecusd",
  "side": "buy",
  "order_type": "exchange limit",
  "timestamp": "1547754480",
  "timestampms": 1547754480759,
  "is_live": true,
  "is_cancelled": false,
  "is_hidden": false,
  "avg_execution_price": "0.00",
  "executed_amount": "0",
  "remaining_amount": "1",
  "original_amount": "1",
  "price": "53.83",
  "socket_sequence": 1
} ]

The next group of messages you receive shows all your current active orders at the time you subscribed. (Unless you've chosen to filter out the initial order event type, in which case you will not receive these messages.)

Field Type Required? Description
type order event type Y initial

Accepted

When you place an order on the exchange, Gemini acknowledges that your order has been accepted for initial processing by sending you an accepted event.

Your order is now live on the exchange. Possible outcomes are:

Field Type Required? Description
type order event type Y accepted

Rejected

This order was rejected because its price does not conform to the market price tick specified in Symbols and minimums.

[ {
  "type" : "rejected",
  "order_id" : "104246",
  "event_id" : "104247",
  "reason" : "InvalidPrice",
  "account_name": "primary",
  "api_session" : "UI",
  "symbol" : "btcusd",
  "side" : "buy",
  "order_type" : "exchange limit",
  "timestamp" : "1478205545",
  "timestampms" : 1478205545047,
  "is_live" : false,
  "original_amount" : "5",
  "price" : "703.14444444", 
  "socket_sequence" : 310311
} ]

If your order cannot be accepted by the exchange, you will receive a single rejected event.

Note that the is_live field of a rejected order event is always false but so is the is_cancelled field: is_cancelled is reserved for orders that are actually cancelled, and rejected orders are not live but they are also not cancelled.

Field Type Required? Description
type order event type Y rejected
reason string The reason your order was rejected. Contact trading@gemini.com for clarification.

Booked

Order booked

[{
  "type": "booked",
  "order_id": "109535955",
  "event_id": "109535957",
  "account_name": "primary",
  "api_session": "UI",
  "symbol": "btcusd",
  "side": "sell",
  "order_type": "exchange limit",
  "timestamp": "1547742952",
  "timestampms": 1547742952725,
  "is_live": true,
  "is_cancelled": false,
  "is_hidden": false,
  "avg_execution_price": "0.00",
  "executed_amount": "0",
  "remaining_amount": "1",
  "original_amount": "1",
  "price": "3592.23",
  "socket_sequence": 25
}]

When limit orders are booked, they have a non-zero quantity visible on the exchange. These orders remain on the exchange until they are completed filled or cancelled.

Market orders are never booked: they are accepted, filled, and then closed.

Field Type Required? Description
type order event type Y booked

Filled

Complete fill on a limit order

[{
  "type": "fill",
  "order_id": "109535955",
  "api_session": "UI",
  "symbol": "btcusd",
  "side": "sell",
  "order_type": "exchange limit",
  "timestamp": "1547743216",
  "timestampms": 1547743216580,
  "is_live": false,
  "is_cancelled": false,
  "is_hidden": false,
  "avg_execution_price": "3592.23",
  "executed_amount": "1",
  "remaining_amount": "0",
  "original_amount": "1",
  "price": "3592.23",
  "fill": {
    "trade_id": "109535970",
    "liquidity": "Maker",
    "price": "3592.23",
    "amount": "1",
    "fee": "8.980575",
    "fee_currency": "USD"
  },
  "socket_sequence": 81
}]

Partial fill on a limit order

[{
  "type" : "fill",
  "order_id" : 556309,
  "account_name": "primary",
  "api_session" : "UI",
  "symbol" : "ethbtc",
  "side" : "sell",
  "order_type" : "exchange limit",
  "timestamp" : "1478729284",
  "timestampMs" : 1478729284169,
  "is_live" : true,
  "is_cancelled" : false,
  "is_hidden" : false,
  "avg_execution_price" : "0.01514",
  "total_executed_amount" : "481.95988631",
  "remaining_amount" : "303.06099969",
  "original_amount" : "785.020886",
  "original_price" : "0.01514",
  "fill" : {
    "trade_id" : "557315",
    "liquidity" : "Maker",
    "price" : "0.01514",
    "amount" : "481.95988631",
    "fee" : "0.0182421816968335",
    "fee_currency" : "BTC"
  }, 
  "socket_sequence" : 471177
}]

A fill event indicates a partial or a complete fill. A complete fill is distinguished by a remaining_amount of 0.

Note that here executed_amount is the total amount of the order that has been filled. The quantity filled by this specific trade is fill.amount.

Similarly, price is an optional field that denotes the original price of a limit order (absent for market buys and sells), while fill.price is the execution price of the trade (always present).

Field Type Required? Description
type order event type Y fill
fill.trade_id string Y the event id the order was filled at
fill.liquidity string Y whether this side of the trade represents Maker or Taker liquidity
fill.price decimal Y the price the trade filled at
fill.amount decimal Y the amount of the trade fill
fill.fee decimal Y the fee associated with this side of the trade
fill.fee_currency string Y the three-letter code of the currency associated with the fee

Cancelled

Continuous book order cancelled

[{
  "type": "cancelled",
  "order_id": "109944118",
  "event_id": "109964524",
  "cancel_command_id": "109964523",
  "reason": "Requested",
  "account_name": "primary",
  "api_session": "myapikey",
  "symbol": "bchusd",
  "side": "buy",
  "order_type": "exchange limit",
  "timestamp": "1547756060",
  "timestampms": 1547756060142,
  "is_live": false,
  "is_cancelled": true,
  "is_hidden": false,
  "avg_execution_price": "0.00",
  "executed_amount": "0",
  "remaining_amount": "1",
  "original_amount": "1",
  "price": "128.72",
  "socket_sequence": 22
}]

When one of your active orders is cancelled, you will receive a notification via a cancelled event.

Your order could be cancelled because:

Field Type Required? Description
type order event type Y fill
cancel_command_id string N The event id of the command to cancel your order.
reason string N When possible, Gemini will supply the reason your order was cancelled.

Cancel Rejected

Cancel Rejected

[ {
  "type" : "cancel_rejected",
  "order_id" : "6425",
  "event_id" : "6434",
  "cancel_command_id" : "6433",
  "reason" : "OrderNotFound",
  "account_name": "primary",
  "api_session" : "UI",
  "symbol" : "btcusd",
  "side" : "buy",
  "order_type" : "limit",
  "timestamp" : "1478204773",
  "timestampms" : 1478204773113,
  "is_live" : true,
  "is_cancelled" : false,
  "is_hidden" : true,
  "avg_execution_price" : "0.00",
  "executed_amount" : "0",
  "remaining_amount" : "5",
  "original_amount" : "5",
  "price" : "721.24", 
  "socket_sequence" : 312300
} ]

When Gemini cannot fulfil your request to cancel an order, you'll receive a cancel_rejected notification.

Reasons this might happen include:

Field Type Required? Description
type order event type Y cancel_rejected
cancel_command_id string Y The event id of the command to cancel your order.
reason string Y The reason Gemini could not fulfil your request to cancel your order.

Closed

Limit Sell closed

[{
    "type": "closed",
    "order_id": "109535955",
    "event_id": "109535971",
    "api_session": "UI",
    "symbol": "btcusd",
    "side": "sell",
    "order_type": "exchange limit",
    "timestamp": "1547743216",
    "timestampms": 1547743216580,
    "is_live": false,
    "is_cancelled": false,
    "is_hidden": false,
    "avg_execution_price": "3592.23",
    "executed_amount": "1",
    "remaining_amount": "0",
    "original_amount": "1",
    "price": "3592.23",
    "socket_sequence": 82
}]

The closed event is the last event in the workflow of any order that has been accepted on the exchange. When you receive this event, you will know that your order has been removed from the book.

Field Type Required? Description
type order event type Y closed

Market Data

Market data is a public API that streams all the market data on a given symbol.

BTC Market Data Feed

import ssl
import websocket

def on_message(ws, message):
    print(message)

ws = websocket.WebSocketApp(
    "wss://api.gemini.com/v1/marketdata/BTCUSD",
    on_message=on_message)
ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE})
npm install -g wscat
wscat --connect wss://api.gemini.com/v1/marketdata/btcusd

Example: Offers only, top of book

import ssl
import websocket

def on_message(ws, message):
    print(message)

ws = websocket.WebSocketApp(
    "wss://api.gemini.com/v1/marketdata/btcusd?top_of_book=true&bids=false",
    on_message=on_message)
ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE})
$ wscat --connect=wss://api.gemini.com/v1/marketdata/btcusd?top_of_book=true\&bids=false
connected (press CTRL+C to quit)
< {"type":"update","eventId":35015,"socket_sequence":0,"events":[{"type":"change","reason":"initial","price":"6629.89","delta":"13.928195144","remaining":"13.928195144","side":"ask"}]}
< {"type":"update","eventId":35051,"timestamp":1528247534,"timestampms":1528247534252,"socket_sequence":1,"events":[{"type":"top-of-book","side":"ask","price":"6631.44","remaining":"33.96746891"}]}
< {"type":"update","eventId":35053,"timestamp":1528247534,"timestampms":1528247534252,"socket_sequence":2,"events":[{"type":"top-of-book","side":"ask","price":"6631.44","remaining":"28.267969234"}]}
< {"type":"update","eventId":35117,"timestamp":1528247538,"timestampms":1528247538541,"socket_sequence":3,"events":[{"type":"top-of-book","side":"ask","price":"6633.04","remaining":"23.53504107"}]}
< {"type":"update","eventId":35122,"timestamp":1528247538,"timestampms":1528247538745,"socket_sequence":4,"events":[{"type":"top-of-book","side":"ask","price":"6633.87","remaining":"19.15815988"}]}

Example: Trades only

import ssl
import websocket

def on_message(ws, message):
    print(message)

ws = websocket.WebSocketApp(
    "wss://api.gemini.com/v1/marketdata/btcusd?trades=true",
    on_message=on_message)
ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE})
$ wscat --connect=wss://api.gemini.com/v1/marketdata/btcusd?trades=true
connected (press CTRL+C to quit)
< {"type":"update","eventId":62653,"socket_sequence":0,"events":[]}
< {"type":"update","eventId":62711,"timestamp":1528249346,"timestampms":1528249346783,"socket_sequence":1,"events":[{"type":"trade","tid":62711,"price":"6619.37","amount":"7.8662471812","makerSide":"ask"}]}
< {"type":"update","eventId":62713,"timestamp":1528249346,"timestampms":1528249346783,"socket_sequence":2,"events":[{"type":"trade","tid":62713,"price":"6619.46","amount":"13.9673234988","makerSide":"ask"}]}
< {"type":"update","eventId":62795,"timestamp":1528249351,"timestampms":1528249351276,"socket_sequence":3,"events":[{"type":"trade","tid":62795,"price":"6619.46","amount":"16.7321435012","makerSide":"ask"}]}
< {"type":"update","eventId":62797,"timestamp":1528249351,"timestampms":1528249351276,"socket_sequence":4,"events":[{"type":"trade","tid":62797,"price":"6619.70","amount":"2.3054248088","makerSide":"ask"}]}
< {"type":"update","eventId":62823,"timestamp":1528249352,"timestampms":1528249352909,"socket_sequence":5,"events":[{"type":"trade","tid":62823,"price":"6619.70","amount":"0.0002606894","makerSide":"ask"}]}
< {"type":"update","eventId":62830,"timestamp":1528249353,"timestampms":1528249353316,"socket_sequence":6,"events":[{"type":"trade","tid":62830,"price":"6610.15","amount":"0.00273253","makerSide":"bid"}]}

Example: Full depth, bids and offers only

import ssl
import websocket

def on_message(ws, message):
    print(message)

ws = websocket.WebSocketApp(
    "wss://api.gemini.com/v1/marketdata/btcusd?bids=true&offers=true",
    on_message=on_message)
ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE})
$ wscat --connect=wss://api.gemini.com/v1/marketdata/btcusd?bids=true&offers=true
connected (press CTRL+C to quit)
< {"type":"update","eventId":64575,"socket_sequence":0,"events":[{"type":"change","reason":"initial","price":"6511.13","delta":"26.93362206","remaining":"26.93362206","side":"bid"},{"type":"change","reason":"initial","price":"6823.47","delta":"34.526471","remaining":"34.526471","side":"ask"}]}
< {"type":"update","eventId":64609,"timestamp":1528249465,"timestampms":1528249465320,"socket_sequence":1,"events":[{"type":"change","side":"ask","price":"6622.84","remaining":"16.49742094","delta":"16.49742094","reason":"place"}]}
< {"type":"update","eventId":64634,"timestamp":1528249466,"timestampms":1528249466750,"socket_sequence":2,"events":[{"type":"change","side":"bid","price":"6592.30","remaining":"18.97068216","delta":"18.97068216","reason":"place"}]}
< {"type":"update","eventId":64651,"timestamp":1528249467,"timestampms":1528249467565,"socket_sequence":3,"events":[{"type":"change","side":"ask","price":"6636.75","remaining":"16.10859393","delta":"16.10859393","reason":"place"}]}
< {"type":"update","eventId":64656,"timestamp":1528249467,"timestampms":1528249467975,"socket_sequence":4,"events":[{"type":"change","side":"ask","price":"6642.91","remaining":"23.553287","delta":"23.553287","reason":"place"}]}
< {"type":"update","eventId":64663,"timestamp":1528249468,"timestampms":1528249468587,"socket_sequence":5,"events":[{"type":"change","side":"ask","price":"6635.61","remaining":"17.97336167","delta":"17.97336167","reason":"place"}]}
< {"type":"update","eventId":64678,"timestamp":1528249469,"timestampms":1528249469405,"socket_sequence":6,"events":[{"type":"change","side":"bid","price":"6596.96","remaining":"21.93141551","delta":"21.93141551","reason":"place"}]}
< {"type":"update","eventId":64703,"timestamp":1528249471,"timestampms":1528249471450,"socket_sequence":7,"events":[{"type":"change","side":"bid","price":"6588.67","remaining":"17.66913232","delta":"17.66913232","reason":"place"}]}
< {"type":"update","eventId":64708,"timestamp":1528249471,"timestampms":1528249471858,"socket_sequence":8,"events":[{"type":"change","side":"ask","price":"6623.78","remaining":"16.44716907","delta":"16.44716907","reason":"place"}]}
< {"type":"update","eventId":64736,"timestamp":1528249474,"timestampms":1528249474104,"socket_sequence":9,"events":[{"type":"change","side":"ask","price":"6623.89","remaining":"36.91752526","delta":"36.91752526","reason":"place"}]}
< {"type":"update","eventId":64748,"timestamp":1528249475,"timestampms":1528249475127,"socket_sequence":10,"events":[{"type":"change","side":"ask","price":"6630.94","remaining":"17.8888451","delta":"17.8888451","reason":"place"}]}

The initial response message will show the existing state of the order book for both bids and offers, regardless of the additional parameters applied in the URL. Subsequent messages will show all executed trades, as well as all other changes to the order book from orders placed or canceled.

WebSocket Request

wss://api.gemini.com/v1/marketdata/:symbol

URL Parameters

Parameter Required Default Description
heartbeat No false Optionally add this parameter and set to true to receive a heartbeat every 5 seconds
top_of_book No false If absent or false, receive full order book depth; if present and true, receive top of book only. Only applies to bids and offers.
bids No true Include bids in change events
offers No true Include asks in change events
trades No true Include trade events

The semantics of entry type filtering is:

NOTE: top_of_book has no meaning and initial book events are empty when only trades is specified

Response

Initial JSON response message for BTC top of book

{
  "type": "update",
  "eventId": 5375461993,
  "socket_sequence": 0,
  "events": [
    {
      "type": "change",
      "reason": "initial",
      "price": "3641.61",
      "delta": "0.83372051",
      "remaining": "0.83372051",
      "side": "bid"
    },
    {
      "type": "change",
      "reason": "initial",
      "price": "3641.62",
      "delta": "4.072",
      "remaining": "4.072",
      "side": "ask"
    }
  ]
}

If heartbeat is enabled:

{
   "type":"heartbeat",
   "socket_sequence":30
}

A WebSocket stream with each frame containing a JSON message of the following format:

Field Type Description
type string heartbeat or update
socket_sequence integer zero-indexed monotonic increasing sequence number attached to each message sent - if there is a gap in this sequence, you have missed a message. If you choose to enable heartbeats, then heartbeat and update messages will share a single increasing sequence. See Sequence Numbers for more information.

Messages with type heartbeat have no additional fields.

Messages of type update have the following additional fields:

Field Type Description
eventId integer A monotonically increasing sequence number indicating when this change occurred. These numbers are persistent and consistent between market data connections.
events array Either a change to the order book, or the indication that a trade has occurred.
timestamp timestamp The timestamp in seconds for this group of events (included for compatibility reasons). We recommend using the timestampms field instead.
timestampms timestampms The timestamp in milliseconds for this group of events.

Common fields

All elements of the events share the following fields:

Field Type Description
type string Either trade or change.

Change event

When an order is placed:

{
  "type": "update",
  "eventId": 5375504382,
  "timestamp": 1547759967,
  "timestampms": 1547759967559,
  "socket_sequence": 66,
  "events": [
    {
      "type": "change",
      "side": "bid",
      "price": "3626.73",
      "remaining": "1.6",
      "delta": "0.8",
      "reason": "place"
    }
  ]
}

When an order is canceled:

{
  "type": "update",
  "eventId": 5375503736,
  "timestamp": 1547759964,
  "timestampms": 1547759964051,
  "socket_sequence": 2,
  "events": [
    {
      "type": "change",
      "side": "bid",
      "price": "3628.01",
      "remaining": "0",
      "delta": "-2",
      "reason": "cancel"
    }
  ]
}

Elements of type change have the following fields:

Field Type Description
price decimal The price of this order book entry.
side string Either bid or ask.
reason string Either place, trade, cancel, or initial, to indicate why the change has occurred. initial is for the initial response message, which will show the entire existing state of the order book.
remaining decimal The quantity remaining at that price level after this change occurred. May be zero if all orders at this price level have been filled or canceled.
delta decimal The quantity changed. May be negative, if an order is filled or canceled. For initial messages, delta will equal remaining.

Note that every trade will trigger a message with entries of both types trade and change.

To keep an up-to-date order book, just watch for any events with {"type": "change"}, and update the price level at price with the amount at remaining. The initial response message will contain all the change events necessary to populate your order book from scratch.

Trade event

When a trade occurs:

{
  "type": "update",
  "eventId": 5375547515,
  "timestamp": 1547760288,
  "timestampms": 1547760288001,
  "socket_sequence": 15,
  "events": [
    {
      "type": "trade",
      "tid": 5375547515,
      "price": "3632.54",
      "amount": "0.1362819142",
      "makerSide": "ask"
    }
  ]
}

Elements of the type trade have the following fields:

Field Type Description
price decimal The price this trade executed at.
amount decimal The amount traded.
makerSide string The side of the book the maker of the trade placed their order on. Either bid, ask.

Market Data Version 2

The initial response message will show the existing state of the order books and last 50 trades. Subsequent messages will show all executed trades, as well as all other changes to the order book from order placed or cancelled.

Level 2 Subscribe Message Fields

Send a JSON formatted message with the following fields upon connecting to v2/marketdata

BTC Market Data Feed

import ssl
import websocket
import _thread as thread

def on_message(ws, message):
    print(message)

def on_error(ws, error):
    print(error)

def on_close(ws):
    print("### closed ###")

def on_open(ws):
    def run(*args):
        ws.send(logon_msg)
    thread.start_new_thread(run, ())

if __name__ == "__main__":
    logon_msg = '{"type": "subscribe","subscriptions":[{"name":"l2","symbols":["BTCUSD","ETHUSD","ETHBTC"]}]}'
    websocket.enableTrace(True)
    ws = websocket.WebSocketApp("wss://api.gemini.com/v2/marketdata",
                                on_message = on_message,
                                on_error = on_error,
                                on_close = on_close,
                                on_open = on_open)
    ws.on_open = on_open
    ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE})
$ wscat --connect wss://api.gemini.com/v2/marketdata
> connected (press CTRL+C to quit)
> {"type": "subscribe","subscriptions":[{"name":"l2","symbols":["BTCUSD","ETHUSD","ETHBTC"]}]}

Market data v2 is a public API that can stream all market and candle data across books. Market data v2 also supports multiple subscriptions in the same data feed.

WebSocket Request

wss://api.gemini.com/v2/marketdata

Subscription Message

After connecting to v2/marketdata you can subscribe to any of the following data feeds.

Name Data Description
l2 Level 2 book data
candles_1m 1 minute candle data
candles_5m 5 minute candle data
candles_15m 15 minute candle data
candles_30m 30 minute candle data
candles_1h 1 hour candle data
candles_6h 6 hour candle data
candles_1d 1 day candle data

To subcribe to a data feed, send a subscription message in the following format.

Field Name Type Values
type string subscribe
subscriptions array
-- name string l2, candle_1m, etc.
-- symbols array ["BTCUSD, "ETHBTC", ... ]

Level 2 Data

Initial JSON response for l2 subscription

{
  "type": "l2_updates",
  "symbol": "BTCUSD",
  "changes": [
    [
      "buy",
      "9122.04",
      "0.00121425"
    ],
    ...,
    [
      "sell",
      "9122.07",
      "0.98942292"
    ]
    ...
  ],
  "trades": [
      {
          "type": "trade",
          "symbol": "BTCUSD",
          "eventid": 169841458,
          "timestamp": 1560976400428,
          "price": "9122.04",
          "quantity": "0.0073173",
          "side": "sell"
      },
      ...
  ],
}
Field Name Type Values
type string subscribe
subscriptions array
-- name string l2
-- symbols array ["BTCUSD", "ETHBTC", ...]

Level 2 Update Response

Field Name Type Values
type string l2_updates
symbol string BTCUSD, etc
changes array of arrays Changes to order book
-- string Buy or Sell
-- string Price Level
-- string Quantity

JSON reponse for l2 update

{
  "type": "l2_updates",
  "symbol": "BTCUSD",
  "changes": [
    [
      "sell",
      "9160.20",
      "0.1921229751"
    ]
  ]
}

Trade Response

Field Name Type Values
type string trade
symbol string BTCUSD, etc
event_id long Event ID of the trade
timestamp long Time of the trade in milliseconds
price string Price of the trade
quantity string Quantity traded
side string Side of the taker in the trade. buy or sell

JSON response trade execution

{
    "type": "trade",
    "symbol": "BTCUSD",
    "event_id": 3575573053,
    “timestamp”: 151231241,
    "price": "9004.21000000",
    "quantity": "0.09110000",
    "side": "buy"
}

Candles Data Feed

The Candle Data feed provides periodic updates with OHLCV data for the given timeframe.

Candle Data Feed Subcribe Message

Send a JSON formatted message with the following fields upon connecting to v2/marketdata

Example JSON Candle Subscription Message

{
  "type": "subscribe",
  "subscriptions": [
    {
      "name": "candles_15m",
      "symbols": [
        "BTCUSD"
      ]
    }
  ]
}
Field Name Type Values
type string subscribe
subscriptions array
-- name string candles_1m, candles_5m, etc.
-- symbols array ["BTCUSD", "ETHBTC", ...]

Example JSON Candle Response

{
  "type": "candles_15m_updates",
  "symbol": "BTCUSD",
  "changes": [
    [
        1561054500000,
        9350.18,
        9358.35,
        9350.18,
        9355.51,
        2.07
    ],
    [
        1561053600000,
        9357.33,
        9357.33,
        9350.18,
        9350.18,
        1.5900161
    ]
    ...
  ]
}

Candle Data Response

Field Name Type Values
type string candles_1m_updates, candles_5m_updates, etc.
symbol string BTCUSD, etc.
candles Array of Arrays (TOHLCV) Changes to order book
-- -- time long milliseconds
-- -- open decimal Open price
-- -- high decimal High price
-- -- low decimal Low price
-- -- close decimal Close price
-- -- volume decimal Volume

Mark Price Feed

The Mark Price feed provides mark price updates for a subscribed perpetual instrument

Mark Price Feed Subscribe Message

Send a JSON formatted message with following fields upon connecting to v2/marketdata

Example JSON Mark Price Subscription Message

{
  "type": "subscribe",
  "subscriptions": [
    {
      "name": "mark_price",
      "symbols": [
        "BTC-GUSD-PERP"
      ]
    }
  ]
}
Field Name Type Values
type string subscribe
subscriptions array
-- name string mark_price
-- symbols array ["BTC-GUSD-PERP", ...]

Mark Price Response

Example JSON Mark Price Response

{
  "type": "mark_price_updates",
  "symbol": "BTCGUSDPERP",
  "changes": [
    {
      "timestamp": 1673932381478308169,
      "mark_price": "21154.098",
      "spot_index": "21175.27333"
    }
  ]
}
Field Name Type Values
type string mark_price_updates
symbol string BTC-GUSD-PERP
changes array change to mark price

All elements of changes share the following fields:

Field Name Type Values
timestamp integer nanoseconds
mark_price string mark price
spot_index string spot index

Funding Amount Feed

The Funding Amount feed provides funding amount updates for a subscribed perpetual instrument

Funding Amount Feed Subscribe Message

Send a JSON formatted message with following fields upon connecting to v2/marketdata

Example JSON Funding Amount Subscription Message

{
  "type": "subscribe",
  "subscriptions": [
    {
      "name": "funding_amount",
      "symbols": [
        "BTC-GUSD-PERP"
      ]
    }
  ]
}
Field Name Type Values
type string subscribe
subscriptions array
-- name string funding_amount
-- symbols array ["BTC-GUSD-PERP", ...]

Funding Amount Response

Example JSON Funding Amount Response

{
  "type": "funding_amount_updates",
  "symbol": "BTCGUSDPERP",
  "changes": [
    {
      "timestamp": 1673932380007696874,
      "funding_amount": "0",
      "funding_date_time": 1673932380007696874,
      "funding_interval_in_minutes": 60,
      "is_realized": false
    }
  ]
}
Field Name Type Values
type string funding_amount_updates
symbol string BTC-GUSD-PERP
changes array change to funding amount

All elements of changes share the following fields:

Field Name Type Values
timestamp integer nanoseconds
funding_amount string funding amount
funding_date_time integer funding date time
funding_interval_in_minutes integer funding interval in minutes
is_realized boolean is realized funding

Unsubscribe

Unsubscribe from data feeds by sending a message in the following format.

Sample unsubscribe message

{
    "type": "unsubscribe",
    "subscriptions": [{
            "name": "l2",
            "symbols": [
                "BTCUSD",
                "ETHBTC"
            ]
        },
        {
            "name": "candles_1m",
            "symbols": [
                "BTCUSD",
                "ETHBTC"
            ]
        }
    ]
}
Field Name Type Values
type string unsubscribe
subscriptions array
-- name string l2, candles_1m, etc.
-- symbols array ["BTCUSD", "ETHBTC", ...]

Multi Market Data

Multi market data is a public API which allows for multiple symbols to be streamed via a single endpoint.

BTCUSD and ETHUSD Multi Market Data Feed

import ssl
import websocket

def on_message(ws, message):
    print(message)

ws = websocket.WebSocketApp(
    "wss://api.gemini.com/v1/multimarketdata?symbols=BTCUSD,ETHUSD",
    on_message=on_message)
ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE})
npm install -g wscat
wscat --connect wss://api.gemini.com/v1/v1/multimarketdata?symbols=BTCUSD,ETHUSD
< {"type":"update","eventId":773797793,"socket_sequence":0,"events":[{"type":"change","reason":"initial","price":"1.00","delta":"236.5","remaining":"236.5","side":"bid","symbol":"BTCUSD"},{"type":"change","reason":"initial","price":"2.00","delta":"176"},
...
{"type":"change","reason":"initial","price":"59137.50","delta":"0.00031","remaining":"0.00031","side":"ask","symbol":"BTCUSD"}]}
< {"type":"update","eventId":773797763,"socket_sequence":1,"events":[{"type":"change","reason":"initial","price":"6.95","delta":"9","remaining":"9","side":"bid","symbol":"ETHUSD"},
...
{"type":"change","reason":"initial","price":"1827.84","delta":"14.8","remaining":"14.8","side":"ask","symbol":"ETHUSD"}]}
< {"type":"update","eventId":773797906,"timestamp":1617045817,"timestampms":1617045817599,"socket_sequence":2,"events":[{"type":"trade","tid":773797906,"price":"57734.10","amount":"0.002","makerSide":"bid","symbol":"BTCUSD"},{"type":"change","side":"bid","price":"57734.10","remaining":"0.0107803","delta":"-0.002","reason":"trade","symbol":"BTCUSD"}]}

The initial response message will show the existing state of the order books requested. Subsequent messages will show all executed trades, as well as all other changes to the order books from orders placed or canceled.

WebSocket Request

wss://api.gemini.com/v1/multimarketdata?symbols=BTCUSD,ETHUSD

URL Parameters

Parameter Required Default Description
symbols Yes false required. Will stream market data for symbols provided. Can provide data for multiple symbols on the same stream.
heartbeat No false Optionally add this parameter and set to true to receive a heartbeat every 5 seconds
top_of_book No false If absent or false, receive full order book depth; if present and true, receive top of book only. Only applies to bids and offers.
bids No true Include bids in change events
offers No true Include asks in change events
trades No true Include trade events

The semantics of entry type filtering is:

NOTE: top_of_book has no meaning and initial book events are empty when only trades is specified

Response

Initial JSON response messages for BTCUSD and ETHUSD

{
    "type":"update",
    "eventId":773797793,"socket_sequence":0,
    "events":[
        {
            "type":"change",
            "reason":"initial",
            "price":"1.00",
            "delta":"236.5",
            "remaining":"236.5",
            "side":"bid",
            "symbol":"BTCUSD"
        },
...
        {
            "type":"change",
            "reason":"initial",
            "price":"59137.50",
            "delta":"0.00031",
            "remaining":"0.00031",
            "side":"ask",
            "symbol":"BTCUSD"
        }
    ]
}

{
    "type":"update",
    "eventId":773797763,"socket_sequence":1,
    "events":[
        {
            "type":"change",
            "reason":"initial",
            "price":"6.95",
            "delta":"9",
            "remaining":"9",
            "side":"bid",
            "symbol":"ETHUSD"
        },
...
        {
            "type":"change",
            "reason":"initial",
            "price":"1827.84",
            "delta":"14.8",
            "remaining":"14.8",
            "side":"ask",
            "symbol":"ETHUSD"
        }
    ]
}

A WebSocket stream that provides multiple symbols with each frame containing a JSON message of the following format:

Field Type Description
type string heartbeat or update
socket_sequence integer zero-indexed monotonic increasing sequence number attached to each message sent - if there is a gap in this sequence, you have missed a message. If you choose to enable heartbeats, then heartbeat and update messages will share a single increasing sequence. See Sequence Numbers for more information.

Messages with type heartbeat have no additional fields.

Messages of type update have the following additional fields:

Field Type Description
eventId integer A monotonically increasing sequence number indicating when this change occurred. These numbers are persistent and consistent between market data connections.
events array Either a change to the order book, or the indication that a trade has occurred.
timestamp timestamp The timestamp in seconds for this group of events (included for compatibility reasons). We recommend using the timestampms field instead.
timestampms timestampms The timestamp in milliseconds for this group of events.

Common fields

All elements of the events share the following fields:

Field Type Description
type string Either trade or change.
symbol string Will return the order book for which the message type is for. Only symbols provided in the URL parameter will be present in the stream. BTCUSD, ETHUSD or any supported symbol

Change event

Elements of type change have the following fields:

Field Type Description
price decimal The price of this order book entry.
side string Either bid or ask.
reason string Either place, trade, cancel, or initial, to indicate why the change has occurred. initial is for the initial response message, which will show the entire existing state of the order book.
remaining decimal The quantity remaining at that price level after this change occurred. May be zero if all orders at this price level have been filled or canceled.
delta decimal The quantity changed. May be negative, if an order is filled or canceled. For initial messages, delta will equal remaining.

Note that every trade will trigger a message with entries of both types trade and change.

To keep an up-to-date order book, just watch for any events with {"type": "change"}, and update the price level at price with the amount at remaining. The initial response message will contain all the change events necessary to populate your order book from scratch.

Trade event

When a trade occurs:

{
  "type": "update",
  "eventId": 5375547515,
  "timestamp": 1547760288,
  "timestampms": 1547760288001,
  "socket_sequence": 15,
  "events": [
    {
      "type": "trade",
      "tid": 5375547515,
      "price": "3632.54",
      "amount": "0.1362819142",
      "makerSide": "ask",
      "symbol": "BTCUSD"
    }
  ]
}

Elements of the type trade have the following fields:

Field Type Description
price decimal The price this trade executed at.
amount decimal The amount traded.
makerSide string The side of the book the maker of the trade placed their order on. Either bid or ask.

Error Codes

If a response is in error, then the HTTP response code will be set to reflect this, and a JSON body will be returned that will contain information about the failure.

HTTP Error Codes

HTTP Status Meaning
200 Request was successful
30x API entry point has moved, see Location: header. Most likely an http: to https: redirect.
400 Market not open, or the request was malformed; in the case of a private API request, missing or malformed Gemini private API authentication headers
403 The API key is missing the role necessary to access this private API endpoint
404 Unknown API entry point or Order not found
406 Insufficient Funds
429 Rate Limiting was applied
500 The server encountered an error
502 Technical issues are preventing the request from being satisfied
503 The exchange is down for maintenance

Error payload


{
    "result": "error",
    "reason": "BadNonce",
    "message": "Out-of-sequence nonce <1234> precedes previously used nonce <2345>"
}

In the event of an error, a non-200 error code will be returned, and the response body will be a json object with three fields:

  1. result, which will always be "error"
  2. reason, which will be one of the strings listed in the table below
  3. message, a human-readable English string indicating additional error information.
Reason Meaning
ClientOrderIdTooLong The Client Order ID must be under 100 characters
ClientOrderIdMustBeString The Client Order ID must be a string
ConflictingOptions New orders using a combination of order execution options are not supported
ConflictingAccountName The specified name is already in use within the master group
EndpointMismatch The request was submitted to an endpoint different than the one in the payload
EndpointNotFound No endpoint was specified
GTSTradeIDMustBeString The Clearing ID must be a string
InsufficientFunds The order was rejected because of insufficient funds
InvalidJson The JSON provided is invalid
InvalidNonce The nonce was not greater than the previously used nonce or was not within +/- 30 seconds of Unix Epoch timestamp
InvalidOrderType An unknown order type was provided
InvalidPrice For new orders, the price was invalid
InvalidStopPrice For new stop limit orders, the price was invalid
InvalidStopPriceSell For new stop limit sell orders, the "stop_price" price was lower than the "sell" price
InvalidStopPriceBuy For new stop limit buy orders, the "stop_price" price was greater than the "buy" price
InvalidStopPriceRatio For new stop limit orders, the "buy" or "sell" price was not within 50% of the "stop_price"
InvalidQuantity A negative or otherwise invalid quantity was specified
InvalidSide For new orders, and invalid side was specified
InvalidSignature The signature did not match the expected signature
InvalidSymbol An invalid symbol was specified
InvalidTimestampInPayload The JSON payload contained a timestamp parameter with an unsupported value.
InvalidAccountName The specified name did not match any accounts within the master group
InvalidAccountType The specified type did not match exchange or custody
InvalidFundTransfer The fund transfer was not successful
Maintenance The system is down for maintenance
MarketNotOpen The order was rejected because the market is not accepting new orders
MissingAccountName A required account name was not specified in a field requiring one
MissingAccounts A required account field was not specified
MissingApikeyHeader The X-GEMINI-APIKEY header was missing
MissingOrderField A required order_id field was not specified
MissingRole The API key used to access this endpoint does not have the required role assigned to it
MissingPayloadHeader The X-GEMINI-PAYLOAD header was missing
MissingPayloadKey The payload is missing a required key
MissingSignatureHeader The X-GEMINI-SIGNATURE header was missing
MissingName A required name field was not specified
MissingNonce A nonce was not provided in the payload. See Private API Invocation for more detail.
MoreThanOneAccount More than one account was specified on an API that only accepts a single account
AccountClosed Account account is closed and cannot be used for this operation.
AccountsOnGroupOnlyApi The account field was specified on a non-master API key
AccountLimitExceeded The account field specified more than the maximum supported accounts for that API
NoAccountOfTypeRequired The account field specified multiple accounts and some were not of the required account type
AccountNotOfTypeRequired The account specified in the account field was not of the required account type
NotGroupApiCompatible A master API key was used to invoke an account only API
ExceededMaxAccountsInGroup An account could not be created as the master group already has the maximum number of allowed accounts in it
NoSSL You must use HTTPS to access the API
OptionsMustBeArray The options parameter must be an array.
OrderNotFound The order specified was not found
RateLimit Requests were made too frequently. See Rate Limits below.
System We are experiencing technical issues
UnsupportedOption This order execution option is not supported.
HasNotAgreedToCustodyTerms The Group has not yet agreed to the Custody terms and conditions. Please visit https://exchange.gemini.com/custody to read the terms and conditions of custody accounts.
BadAccountType The type parameter must contain a string of either exchange or custody.
RemoteAddressForbidden Request received from an IP address that is not whitelisted under the group.

Revision History

Date Notes
2016/11/10 Initial WebSocket API documentation
2016/12/14 New feature: API key roles
2017/02/08 Better market data examples
2017/03/06 Documentation bugfix: correct location of market data JSON example for trade events
2017/05/15 Document Order Events Subscription Acknowledgement subscriptionId field
2017/05/15 Clarified how Gemini rate limits incoming requests to public WebSocket APIs
2017/07/13 API Change timestamp and timestampms added to Market Data API
2017/07/27 Documentation bugfix: clarify the purpose of the trace_id in Order Events: Heartbeats
2017/08/10 New Feature to make it easy to detect WebSocket messages that were missed or received out-of-order, Gemini has added a socket_sequence field to both the Market Data and Order Events APIs. Further details available in Sequence Numbers.
2017/12/01 API Change collar_price added to Market Data API
2018/04/06 API Change Document block trades in Market Data and Order Events APIs.
2018/06/06 API Change Market depth and entry filtering added to Market Data API
2019/06/20 Adding documentation for Market Data v2 and Candles Data Feed
2019/11/22 Updated response messages for Candles Data Feed on Market Data v2
2020/04/09 Documentation for new token support: BAT, DAI, LINK, OXT
2020/08/28 Removing DAIBTCand DAIETH trading pairs
2020/10/05 Documentation for new order book support: BTCDAI and ETHDAI
2020/10/07 Documentation for new token support: AAVE
2020/10/14 Documentation for new token support: FIL
2021/01/28 Documentation for new symbol support: BTCSGD and ETHSGD
2021/03/11 Added new optional heartbeat filter
2021/03/22 Documentation for new token support: SKL, GRT, BNT, 1INCH, ENJ, LRC, SAND
2021/03/29 Documentation for new Multi Market Data Feed
2021/04/27 Documentation for new token support: CUBE, LPT, BOND, MATIC, INJ, SUSHI
2021/05/05 Documentation for new token support: DOGE
2021/06/16 Documentation for new token support: ALCX, MIR, FTM, ANKR
2021/07/14 Documentation for new token support: CTX
2021/07/21 Documentation for new token support: XTZ
2021/09/15 Documentation for new token support: AXS, SLP, LUNA, UST, MCO2
2021/11/13 Documentation for new token support: WCFG, RARE, RAD, QNT, NMR, MASK, FET, ASH, AUDIO, API3, USDC, SHIB
2021/12/20 Documentation for new token support: RNDR, MC, GALA, ENS, KP3R, CVC, ELON, MIM, SPELL
2022/02/01 Documentation for new token support: TOKE, LDO, RLY
2022/02/28 Documentation for new token support: SOL
2022/03/01 Documentation for new token support: RAY, SBR
2022/03/16 Documentation for new token support: APE
2022/03/29 Documentation for new token support: RBN, FXS, DPI, LQTY, LUSD, FRAX, INDEX, MPL
2022/04/26 Documentation for new token support: GUSDSGD
2022/04/27 Documentation for new token support: METIS, QRDO, ZBC, CHZ, REVV, JAM, FIDA, GMT
2022/05/17 Documentation for new token support: GFI, ORCA
2022/06/14 Documentation for new token support: ALI, TRU
2022/06/22 Documentation for new token support: GUSDGBP
2022/06/23 Deprecating documentation for Auction and Block trading support
2022/07/06 Documentation for new token support: DOT, ERN
2022/08/01 Documentation for new token support: GAL, EUL, SAMO
2022/08/23 Documentation for new token support: BICO, IMX, PLA, IOTX
2022/09/07 Documentation for new token support: BUSD
2022/10/11 Documentation for new token support: AVAX
2023/01/10 Documentation for new token support: ATOM, USDT
2023/05/09 Documentation for new token support: PEPE
2023/08/04 Documentation for token delist: ENJ
2023/08/10 Documentation for new token support: XRP
2023/09/11 Documentation for new token support: HNT
2023/09/18 Removed Documentation for new token support: MPL, MC, METIS, RBN, GFI, LQTY, and LUSD
2023/11/15 Remove Documentation for delisted token: MIR, UST, FXS, FRAX, BUSD