Gemini WebSocket API Reference (2024)

Gemini offers two WebSocket APIs for streaming data:

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

Advantages include:

  • receive notifications in real time
  • reduce the amount of data you have to transfer over the network
  • reduce latency introduced by polling interval

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.

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

  • Gemini has an automated system that makes trades on the exchange to simulate normal exchange activity
  • all funds are for testing purposes. Only Testnet BTC deposits and withdrawals are supported.

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.

  • use the website to get comfortable trading on Gemini
  • use the API to validate your trading systems before deploying them against the real Gemini exchange

Your account will automatically be credited with USD, BTC, ETH, 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

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.

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>> }> EOFewogICAgInJlcXVlc3QiOiAiL3YxL29yZGVyL3N0YXR1cyIsCiAgICAibm9uY2UiOiAxMjM0NTYsCgogICAgIm9yZGVyX2lkIjogMTg4MzQKfQo=
import sslimport websocketimport jsonimport base64import hmacimport hashlibimport timedef 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 forclarity, your http library may or may not put them in.

POST /v1/order/eventsContent-Type: text/plainContent-Length: 0X-GEMINI-APIKEY: mykeyX-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 describedin the documentation below. Rather than being sent as the body of the POSTrequest, 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 therequest. The nonce must be increasing with each request to preventreplay attacks.

HeaderValue
Content-Length0
Content-Typetext/plain
X-GEMINI-APIKEYYour Gemini API key
X-GEMINI-PAYLOADThe base64-encoded JSON payload
X-GEMINI-SIGNATUREhex(HMAC_SHA384(base64(payload), key=api_secret))
Cache-Controlno-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:

  • 403 status
  • a JSON response body with
    • reason set to MissingRole, and
    • message explaining what role you need to add to your API key to use this endpoint

See Error Codes for more information about API error responses.

Trader

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

  • access the Order Events WebSocket API

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:

  • New Deposit Address
  • Withdraw Crypto Funds

Auditor

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

  • access the Order Events WebSocket API

Endpoint summary

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

EndpointURITrader can access?Fund Manager can access?Auditor can access?
Order Events/v1/order/events

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.

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}.

CharactersDescriptionASCII Codes (Dec)
A-ZUppercase A-Z65 - 90
a-zLowercase a-z97 - 122
0-9Digits48 - 57
#Hash, octothorpe, number sign35
-Hyphen45
.Period46
:Colon58
_Underscore95

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

TypeDescription
stringA simple quoted string, following standard JSON rules; see the JSON spec for details.
decimalA decimal value, encoded in a JSON string. The contents will be a series of digits, followed by an optional decimal point and additional digits.
timestampThe 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
timestampmsThe 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.
integerAn whole number, transmitted as a JSON number.
booleanA JSON boolean, the literal string true or false
arraya 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 formatexampleSupported request type
whole number (seconds)1495127793GET, POST
string (seconds)"1495127793"POST only
whole number (milliseconds)1495127793000GET, 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

  • timestamp denotes the number of seconds since 1970-01-01 UTC
  • timestampms denotes the number of milliseconds since 1970-01-01 UTC

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 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:

SymbolMinimum Order SizeTick SizeQuote Currency Price Increment
btcusd0.00001 BTC (1e-5)0.00000001 BTC (1e-8)0.01 USD
btceur0.00001 BTC (1e-5)0.00000001 BTC (1e-8)0.01 EUR
btcgbp0.00001 BTC (1e-5)0.00000001 BTC (1e-8)0.01 GBP
btcsgd0.00001 BTC (1e-5)0.00000001 BTC (1e-8)0.01 SGD
ethbtc0.001 ETH (1e-3)0.000001 ETH (1e-6)0.00001 BTC (1e-5)
ethusd0.001 ETH (1e-3)0.000001 ETH (1e-6)0.01 USD
etheur0.001 ETH (1e-3)0.000001 ETH (1e-6)0.01 EUR
ethgbp0.001 ETH (1e-3)0.000001 ETH (1e-6)0.01 GBP
ethsgd0.001 ETH (1e-3)0.000001 ETH (1e-6)0.01 SGD
bchusd0.001 BCH (1e-3)0.000001 BCH (1e-6)0.01 USD
bchbtc0.001 BCH (1e-3)0.000001 BCH (1e-6)0.00001 BTC (1e-5)
bcheth0.001 BCH (1e-3)0.000001 BCH (1e-6)0.0001 ETH (1e-4)
ltcusd0.01 LTC (1e-2)0.00001 LTC (1e-5)0.01 USD
ltcbtc0.01 LTC (1e-2)0.00001 LTC (1e-5)0.0000001 BTC (1e-7)
ltceth0.01 LTC (1e-2)0.00001 LTC (1e-5)0.00001 ETH (1e-5)
ltcbch0.01 LTC (1e-2)0.00001 LTC (1e-5)0.0001 BCH (1e-4)
batusd1.0 BAT (1e0)0.000001 BAT (1e-6)0.00001 USD (1e-5)
daiusd0.1 DAI (1e-1)0.000001 DAI (1e-6)0.00001 USD (1e-5)
linkusd0.1 LINK (1e-1)0.000001 LINK (1e-6)0.00001 USD (1e-5)
oxtusd1.0 OXT (1e0)0.000001 OXT (1e-6)0.00001 USD (1e-5)
linkbtc0.1 LINK (1e-1)0.000001 LINK (1e-6)0.00000001 BTC (1e-8)
linketh0.1 LINK (1e-1)0.000001 LINK (1e-6)0.0000001 ETH (1e-7)
ampusd10.0 AMP (1e1)0.000001 AMP (1e-6)0.00001 USD (1e-5)
compusd0.001 COMP (1e-3)0.000001 COMP (1e-6)0.01 USD
paxgusd0.0001 PAXG (1e-4)0.00000001 PAXG (1e-8)0.01 USD
mkrusd0.001 MKR (1e-3)0.000001 MKR (1e-6)0.01 USD
zrxusd0.1 ZRX (1e-1)0.000001 ZRX (1e-6)0.00001 USD (1e-5)
manausd1.0 MANA (1e0)0.000001 MANA (1e-6)0.00001 USD (1e-5)
storjusd0.1 STORJ (1e-1)0.000001 STORJ (1e-6)0.00001 USD (1e-5)
snxusd0.01 SNX (1e-2)0.000001 SNX (1e-6)0.0001 USD (1e-4)
crvusd0.1 CRV (1e-1)0.000001 CRV (1e-6)0.0001 USD (1e-4)
uniusd0.01 UNI (1e-2)0.000001 UNI (1e-6)0.0001 USD (1e-4)
renusd0.01 REN (1e-2)0.000001 REN (1e-6)0.00001 USD (1e-5)
umausd0.01 UMA (1e-2)0.000001 UMA (1e-6)0.0001 USD (1e-4)
yfiusd0.00001 YFI (1e-5)0.000001 YFI (1e-6)0.01 USD
aaveusd0.001 AAVE (1e-3)0.000001 AAVE (1e-6)0.0001 USD (1e-4)
filusd0.1 FIL (1e-1)0.000001 FIL (1e-6)0.0001 USD (1e-4)
sklusd0.1 SKL (1e-1)0.000001 SKL (1e-6)0.00001 USD (1e-5)
grtusd0.1 GRT (1e-1)0.000001 GRT (1e-6)0.0001 USD (1e-4)
lrcusd0.1 LRC (1e-1)0.000001 LRC (1e-6)0.00001 USD (1e-5)
sandusd0.1 SAND (1e-1)0.000001 SAND (1e-6)0.00001 USD (1e-5)
cubeusd0.01 CUBE (1e-2)0.000001 CUBE (1e-6)0.0001 USD (1e-4)
lptusd0.001 LPT (1e-3)0.000001 LPT (1e-6)0.0001 USD (1e-4)
maticusd0.1 MATIC (1e-1)0.000001 MATIC (1e-6)0.00001 USD (1e-5)
injusd0.01 INJ (1e-2)0.000001 INJ (1e-6)0.0001 USD (1e-4)
sushiusd0.01 SUSHI (1e-2)0.000001 SUSHI (1e-6)0.0001 USD (1e-4)
dogeusd0.1 DOGE (1e-1)0.000001 DOGE (1e-6)0.00001 USD (1e-5)
ftmusd0.03 FTM (3e-2)0.000001 FTM (1e-6)0.0001 USD (1e-4)
ankrusd0.1 ANKR (1e-1)0.000001 ANKR (1e-6)0.00001 USD (1e-5)
btcgusd0.00001 BTC (1e-5)0.00000001 BTC (1e-8)0.01 GUSD
ethgusd0.001 ETH (1e-3)0.000001 ETH (1e-6)0.01 GUSD
ctxusd0.002 CTX (2e-3)0.000001 CTX (1e-6)0.0001 USD (1e-4)
xtzusd0.02 XTZ (2e-2)0.000001 XTZ (1e-6)0.0001 USD (1e-4)
axsusd0.003 AXS (3e-3)0.000001 AXS (1e-6)0.01 USD (1e-2)
lunausd1 LUNA (1e0)0.000001 LUNA (1e-6)0.00000001 USD (1e-8)
dogebtc1.0 DOGE (1e0)0.00000001 DOGE (1e-8)0.000000001 BTC (1e-9)
dogeeth1.0 DOGE (1e0)0.00000001 DOGE (1e-8)0.00000001 ETH (1e-8)
rareusd0.1 RARE (1e-1)0.000001 RARE (1e-6)0.001 USD (1e-3)
qntusd0.0004 QNT (4e-4)0.000001 QNT (1e-6)0.01 USD (1e-2)
maskusd0.01 MASK (1e-2)0.000001 MASK (1e-6)0.001 USD (1e-3)
fetusd0.1 FET (1e-1)0.000001 FET (1e-6)0.00001 USD (1e-5)
api3usd0.03 API3 (3e-2)0.000001 API3 (1e-6)0.001 USD (1e-3)
usdcusd0.1 USDC (1e-1)0.000001 USDC (1e-6)0.00001 USD (1e-5)
shibusd1000.0 SHIB (1e3)0.000001 SHIB (1e-6)0.000000001 USD (1e-9)
rndrusd0.02 RNDR (2e-2)0.000001 RNDR (1e-6)0.001 USD (1e-3)
galausd0.4 GALA (4e-1)0.000001 GALA (1e-6)0.00001 USD (1e-5)
ensusd0.002 ENS (2e-3)0.000001 ENS (1e-6)0.001 USD (1e-3)
tokeusd0.002 TOKE (2e-3)0.000001 TOKE (1e-6)0.001 USD (1e-3)
ldousd0.02 LDO (2e-2)0.000001 LDO (1e-6)0.001 USD (1e-3)
rlyusd0.2 RLY (2e-1)0.000001 RLY (1e-6)0.00001 USD (1e-5)
solusd0.001 SOL (1e-3)0.000001 SOL (1e-6)0.001 USD (1e-3)
apeusd0.02 APE (2e-2)0.000001 APE (1e-6)0.001 USD (1e-3)
gusdsgd0.1 GUSD0.000001 GUSD (1e-6)0.001 SGD (1e-3)
qrdousd0.04 QRDO (4e-2)0.000001 QRDO (1e-6)0.00001 USD (1e-5)
zbcusd3.0 ZBC (3e0)0.000001 ZBC (1e-6)0.00001 USD (1e-5)
chzusd0.5 CHZ (5e-1)0.000001 CHZ (1e-6)0.00001 USD (1e-5)
jamusd10.0 JAM (1e1)0.000001 JAM (1e-6)0.0000001 USD (1e-7)
gmtusd0.1 GMT (1e-1)0.000001 GMT (1e-6)0.00001 USD (1e-5)
aliusd2.0 ALI (2e0)0.000001 ALI (1e-6)0.000001 USD (1e-6)
gusdgbp0.1 GUSD0.0001 GUSD (1e-4)0.001 GBP (1e-3)
dotusd0.01 DOT (1e-2)0.000001 DOT (1e-6)0.0001 USD (1e-4)
ernusd0.05 ERN (5e-2)0.000001 ERN (1e-6)0.0001 USD (1e-4)
elonusd60000.0 ELON (6e4)0.000001 ELON (1e-6)0.00000000001 USD (1e-11)
galusd0.04 GAL (4e-2)0.000001 GAL (1e-6)0.0001 USD (1e-4)
samousd10.0 SAMO (1e+1)0.000001 SAMO (1e-6)0.0000001 USD (1e-7)
imxusd0.1 IMX (1e-1)0.000001 IMX (1e-6)0.00001 USD (1e-5)
iotxusd3.0 IOTX (3e+0)0.000001 IOTX (1e-6)0.000001 USD (1e-6)
avaxusd0.005 AVAX (5e-3)0.000001 AVAX (1e-6)0.001 USD (1e-3)
atomusd0.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)
pepeusd1000 PEPE (1e3)0.000001 PEPE (1e-6)0.000000001 USD (1e-9)
xrpusd0.1 XRP (1e-1)0.000001 XRP (1e-6)0.00001 USD (1e-5)
hntusd0.04 HNT (1e-1)0.000001 HNT (1e-6)0.0001 USD (1e-4)

*Note: Not available to trade for customers in New York

All Supported Symbols

btcusdethbtcethusdbchusdbchbtcbchethltcusdltcbtcltcethltcbchbatusddaiusdlinkusdoxtusdlinkbtclinkethampusdcompusdpaxgusdmkrusdzrxusdmanausdstorjusdsnxusdcrvusduniusdrenusdumausdyfiusdaaveusdfilusdbtceurbtcgbpetheurethgbpbtcsgdethsgdsklusdgrtusdlrcusdsandusdcubeusdlptusdmaticusdinjusdsushiusddogeusdftmusdankrusdbtcgusdethgusdctxusdxtzusdaxsusdlunausddogebtcdogeethrareusdqntusdmaskusdfetusdapi3usdusdcusdshibusdrndrusdgalausdensusdelonusdtokeusdldousdrlyusdsolusdapeusdgusdsgdqrdousdzbcusdchzusdjamusdgmtusdaliusdgusdgbpdotusdernusdgalusdsamousdimxusdiotxusdavaxusdatomusdusdtusdbtcusdtethusdtpepeusdxrpusdhntusd

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:

  • Each time you reconnect, the sequence number resets to zero.
  • If you have multiple WebSocket connections, each will have a separate sequence number beginning with zero - make sure to keep track of each sequence number separately!

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:

  • when your orders are accepted by the exchange
  • when your orders first appear on the book
  • fills
  • cancels

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

    • Entry Type
    • Can be filtered?
    • Description
    • subscription_ack
    • N
    • Acknowledges your order events subscription and echoes back your parsed filters.
    • heartbeat
    • Y
    • Sent at five-second intervals to show that your WebSocket connection to Gemini is alive. This is filtered independently from the eventTypeFilter as heartbeat=true. The default for the heartbeat parameter is true.
    • initial
    • Y
    • At the time you begin your subscription, you receive a list of your current active orders. Each active order will have the initial event type. You only see this event type at the beginning of each subscription.
    • accepted
    • Y
    • Acknowledges that the exchange has received your order for initial processing. An order which cannot be accepted for initial processing receives a rejected event.
    • rejected
    • Y
    • When an order is rejected.
    • booked
    • Y
    • Your order is now visible on the Gemini order book. Under certain conditions, when you place an order you will not receive a booked event. These include:

      • When your order is completely filled after being accepted
      • When your order is accepted for initial processing but then immediately cancelled because some condition cannot be fulfilled (for instance, if you submit a maker-or-cancel order but your order would cross)
    • fill
    • Y
    • When an order is filled.
    • cancelled
    • Y
    • When an order is cancelled.
    • cancel_rejected
    • Y
    • When your request to cancel an order cannot be fulfilled. Reasons this might happen include:

      • The order cannot be found
    • closed
    • Y
    • The last event in the order lifecycle: whether this order was completely filled or cancelled, the consumer can use the closed event as a signal that the order is off the book on the Gemini side.

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 wscatwscat -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 sslimport websocketimport jsonimport base64import hmacimport hashlibimport timedef 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:

HeaderValue
X-GEMINI-APIKEYYour Gemini API session key
X-GEMINI-PAYLOADBefore 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-SIGNATURESee Private API Invocation for an explanation of how to create the signature hash.

URL Parameters

ParameterTypeRequired?Description
symbolFilterstringNOptional symbol filter for order event subscription
apiSessionFilterstringNOptional API session key filter for order event subscription
eventTypeFilterstringNOptional order event type filter for order event subscription
heartbeatbooleanNOptional 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.

    • Field
    • Type
    • Required?
    • Description
    • type
    • string
    • Y
    • An order event type, e.g. accepted, booked, fill, cancelled
    • 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.
    • order_id
    • string
    • Y
    • The order id that Gemini has assigned to this order, first provided in the accepted or rejected message. All further events (fill, booked, cancelled, closed) will refer to this order_id
    • event_id
    • string
    • Y*
    • The event id associated with this specific order event. event_id is supplied for every order event type except the initial events that supply the active orders when you initially subscribe.
    • account_name
    • string
    • N
    • Returned when using a Master scoped API key. The name of the account within the subaccount group. Master API keys can get all account names using the Get Accounts endpoint.
    • api_session
    • string
    • Y*
    • The API session key associated with this order.
      • Orders placed by website users show UI as the API session key.
    • client_order_id
    • Client Order ID
    • N
    • The optional client-specified order id
    • symbol
    • string
    • Y
    • The symbol of the order
    • side
    • string
    • Y
    • Either buy or sell
    • behavior
    • string
    • N
    • When limit orders are placed with immediate-or-cancel, fill-or-kill, or maker-or-cancel behavior, this field will indicate the order behavior.
    • order_type
    • string
    • Y
    • Description of the order
    • timestamp
    • string
    • Y
    • The timestamp the order was submitted. Note that for compatibility reasons, this is returned as a string. We recommend using the timestampms field instead.
    • timestampms
    • timestampms
    • Y
    • The timestamp the order was submitted in milliseconds.
    • is_live
    • boolean
    • Y
    • true if the order is active on the book (has remaining quantity and has not been canceled)
    • is_cancelled
    • boolean
    • Y
    • true if the order has been canceled. Note the spelling, "cancelled" instead of "canceled". This is for compatibility reasons.
    • is_hidden
    • boolean
    • Y
    • true if the order is active but not visible
    • avg_execution_price
    • decimal
    • N
    • The average price at which this order as been executed so far. 0 if the order has not been executed at all.
    • executed_amount
    • decimal
    • N
    • The amount of the order that has been filled.
    • remaining_amount
    • decimal
    • N
    • The amount of the order that has not been filled. Present for limit and market sell orders; absent for market buy orders.
    • original_amount
    • decimal
    • N
    • For limit orders and market sells, the quantity the order was placed for. Not present for market buys.
    • price
    • decimal
    • N
    • For limit orders, the price the order was placed for. Not present for market buys and sells.
    • total_spend
    • decimal
    • N
    • For market buys, the total spend (fee-inclusive notional value) the order was placed for. Not present for limit orders and market sells.

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.

FieldTypeRequired?Description
typeorder event typeYsubscription_ack
accountIdintegerYThe 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.
subscriptionIdstringYThe 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.
symbolFilterstring arrayYAn array of zero or more supported symbols. An empty array means your subscription is not filtered by symbol.
apiSessionFilterstring arrayYAn 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.
eventTypeFilterstring arrayYAn 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.

FieldTypeRequired?Description
typeorder event typeNheartbeat. This can be set to true in the [heartbeat URL parameter]((#order-events). Defaults to true
timestampmstimestampmsYGemini adds a timestamp so if you get disconnected, you may contact Gemini support with the timestamp of the last heartbeat you received.
sequenceintegerYGemini adds a monotonically incrementing sequence to make it easy to tell if you've missed a heartbeat. Not the same as socket_sequence!
socket_sequenceintegerYzero-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_idstringYGemini 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": "solusd", "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.)

FieldTypeRequired?Description
typeorder event typeYinitial

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:

  • if your limit order can be immediately filled and you have not chosen maker-or-cancel behavior, you will get zero or more initial fill events, followed by
    • if your order has remaining quantity, then you will receive a booked event to let you know that the remaining quantity is now visible on the exchange
    • if your order has been completely filled, you will receive a closed event
  • if your limit order includes behavior such as maker-or-cancel which cannot be fulfilled, cancelled and then closed
  • market orders will be immediately filled with one or more fill events followed by a closed event
FieldTypeRequired?Description
typeorder event typeYaccepted

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.

FieldTypeRequired?Description
typeorder event typeYrejected
reasonstringThe 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.

FieldTypeRequired?Description
typeorder event typeYbooked

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).

FieldTypeRequired?Description
typeorder event typeYfill
fill.trade_idstringYthe event id the order was filled at
fill.liquiditystringYwhether this side of the trade represents Maker or Taker liquidity
fill.pricedecimalYthe price the trade filled at
fill.amountdecimalYthe amount of the trade fill
fill.feedecimalYthe fee associated with this side of the trade
fill.fee_currencystringYthe 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:

  • you requested it
  • when you placed the order, you added a behavior such as immediate-or-cancel, fill-or-kill, or maker-or-cancel which the exchange could not fulfil - in this case, your order is cancelled and closed instead of being booked
  • your FIX connection was disconnected, and all your orders have been cancelled
  • your API session key has been provisioned to require a heartbeat and due to a heartbeat timeout, all your orders have been cancelled
FieldTypeRequired?Description
typeorder event typeYfill
cancel_command_idstringNThe event id of the command to cancel your order.
reasonstringNWhen 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:

  • the order you tried to cancel can't be found
FieldTypeRequired?Description
typeorder event typeYcancel_rejected
cancel_command_idstringYThe event id of the command to cancel your order.
reasonstringYThe 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.

FieldTypeRequired?Description
typeorder event typeYclosed

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

BTC Market Data Feed

import sslimport websocketdef 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 wscatwscat --connect wss://api.gemini.com/v1/marketdata/btcusd

Example: Offers only, top of book

import sslimport websocketdef 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=falseconnected (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 sslimport websocketdef 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=trueconnected (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 sslimport websocketdef 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=trueconnected (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 orderbook 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

ParameterRequiredDefaultDescription
heartbeatNofalseOptionally add this parameter and set to true to receive a heartbeat every 5 seconds
top_of_bookNofalseIf absent or false, receive full order book depth; if present and true, receive top of book only. Only applies to bids and offers.
bidsNotrueInclude bids in change events
offersNotrueInclude asks in change events
tradesNotrueInclude trade events

The semantics of entry type filtering is:

  • To be excluded from change events in the response, an entry type must be explicitly flagged false
  • If no entry types filtering parameters are included in the url, then all entry types will appear in the response

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:

FieldTypeDescription
typestringheartbeat or update
socket_sequenceintegerzero-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:

FieldTypeDescription
eventIdintegerA monotonically increasing sequence number indicating when this change occurred. These numbers are persistent and consistent between market data connections.
eventsarrayEither a change to the order book, or the indication that a trade has occurred.
timestamptimestampThe timestamp in seconds for this group of events (included for compatibility reasons). We recommend using the timestampms field instead.
timestampmstimestampmsThe timestamp in milliseconds for this group of events.

Common fields

All elements of the events share the following fields:

FieldTypeDescription
typestringEither 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:

FieldTypeDescription
pricedecimalThe price of this order book entry.
sidestringEither bid or ask.
reasonstringEither 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.
remainingdecimalThe 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.
deltadecimalThe 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 pricelevel at price with the amount at remaining. The initial response message will contain all the change events necessaryto 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:

FieldTypeDescription
pricedecimalThe price this trade executed at.
amountdecimalThe amount traded.
makerSidestringThe side of the book the maker of the trade placed their order on. Either bid, ask.

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 sslimport websocketimport _thread as threaddef 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.

NameData Description
l2Level 2 book data
candles_1m1 minute candle data
candles_5m5 minute candle data
candles_15m15 minute candle data
candles_30m30 minute candle data
candles_1h1 hour candle data
candles_6h6 hour candle data
candles_1d1 day candle data

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

Field NameTypeValues
typestringsubscribe
subscriptionsarray
-- namestringl2, candle_1m, etc.
-- symbolsarray["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", "tid": 2840140800042677 }, ... ],}
Field NameTypeValues
typestringsubscribe
subscriptionsarray
-- namestringl2
-- symbolsarray["BTCUSD", "ETHBTC", ...]

Level 2 Update Response

Field NameTypeValues
typestringl2_updates
symbolstringBTCUSD, etc
changesarray of arraysChanges to order book
--stringBuy or Sell
--stringPrice Level
--stringQuantity

JSON reponse for l2 update

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

Trade Response

Field NameTypeValues
typestringtrade
symbolstringBTCUSD, etc
event_idlongEvent ID of the trade
timestamplongTime of the trade in milliseconds
pricestringPrice of the trade
quantitystringQuantity traded
sidestringSide of the taker in the trade. buy or sell
tidlongTrade ID of the trade

JSON response trade execution

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

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 NameTypeValues
typestringsubscribe
subscriptionsarray
-- namestringcandles_1m, candles_5m, etc.
-- symbolsarray["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 NameTypeValues
typestringcandles_1m_updates, candles_5m_updates, etc.
symbolstringBTCUSD, etc.
candlesArray of Arrays (TOHLCV)Changes to order book
-- -- timelongmilliseconds
-- -- opendecimalOpen price
-- -- highdecimalHigh price
-- -- lowdecimalLow price
-- -- closedecimalClose price
-- -- volumedecimalVolume

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 NameTypeValues
typestringsubscribe
subscriptionsarray
-- namestringmark_price
-- symbolsarray["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 NameTypeValues
typestringmark_price_updates
symbolstringBTC-GUSD-PERP
changesarraychange to mark price

All elements of changes share the following fields:

Field NameTypeValues
timestampintegernanoseconds
mark_pricestringmark price
spot_indexstringspot 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 NameTypeValues
typestringsubscribe
subscriptionsarray
-- namestringfunding_amount
-- symbolsarray["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 NameTypeValues
typestringfunding_amount_updates
symbolstringBTC-GUSD-PERP
changesarraychange to funding amount

All elements of changes share the following fields:

Field NameTypeValues
timestampintegernanoseconds
funding_amountstringfunding amount
funding_date_timeintegerfunding date time
funding_interval_in_minutesintegerfunding interval in minutes
is_realizedbooleanis 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 NameTypeValues
typestringunsubscribe
subscriptionsarray
-- namestringl2, candles_1m, etc.
-- symbolsarray["BTCUSD", "ETHBTC", ...]

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 sslimport websocketdef 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 wscatwscat --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 orderbooks 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

ParameterRequiredDefaultDescription
symbolsYesfalserequired. Will stream market data for symbols provided. Can provide data for multiple symbols on the same stream.
heartbeatNofalseOptionally add this parameter and set to true to receive a heartbeat every 5 seconds
top_of_bookNofalseIf absent or false, receive full order book depth; if present and true, receive top of book only. Only applies to bids and offers.
bidsNotrueInclude bids in change events
offersNotrueInclude asks in change events
tradesNotrueInclude trade events

The semantics of entry type filtering is:

  • If any entry type is specified as true or false, all of them must be explicitly flagged true to show up in the response
  • If no entry types filtering parameters are included in the url, then all entry types will appear in the response

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:

FieldTypeDescription
typestringheartbeat or update
socket_sequenceintegerzero-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:

FieldTypeDescription
eventIdintegerA monotonically increasing sequence number indicating when this change occurred. These numbers are persistent and consistent between market data connections.
eventsarrayEither a change to the order book, or the indication that a trade has occurred.
timestamptimestampThe timestamp in seconds for this group of events (included for compatibility reasons). We recommend using the timestampms field instead.
timestampmstimestampmsThe timestamp in milliseconds for this group of events.

Common fields

All elements of the events share the following fields:

FieldTypeDescription
typestringEither trade or change.
symbolstringWill 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:

FieldTypeDescription
pricedecimalThe price of this order book entry.
sidestringEither bid or ask.
reasonstringEither 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.
remainingdecimalThe 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.
deltadecimalThe 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 pricelevel at price with the amount at remaining. The initial response message will contain all the change events necessaryto 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:

FieldTypeDescription
pricedecimalThe price this trade executed at.
amountdecimalThe amount traded.
makerSidestringThe side of the book the maker of the trade placed their order on. Either bid or ask.

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 StatusMeaning
200Request was successful
30xAPI entry point has moved, see Location: header. Most likely an http: to https: redirect.
400Market not open, or the request was malformed; in the case of a private API request, missing or malformed Gemini private API authentication headers
403The API key is missing the role necessary to access this private API endpoint
404Unknown API entry point or Order not found
406Insufficient Funds
429Rate Limiting was applied
500The server encountered an error
502Technical issues are preventing the request from being satisfied
503The 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.
ReasonMeaning
ClientOrderIdTooLongThe Client Order ID must be under 100 characters
ClientOrderIdMustBeStringThe Client Order ID must be a string
ConflictingOptionsNew orders using a combination of order execution options are not supported
ConflictingAccountNameThe specified name is already in use within the master group
EndpointMismatchThe request was submitted to an endpoint different than the one in the payload
EndpointNotFoundNo endpoint was specified
GTSTradeIDMustBeStringThe Clearing ID must be a string
InsufficientFundsThe order was rejected because of insufficient funds
InvalidJsonThe JSON provided is invalid
InvalidNonceThe nonce was not greater than the previously used nonce or was not within +/- 30 seconds of Unix Epoch timestamp
InvalidOrderTypeAn unknown order type was provided
InvalidPriceFor new orders, the price was invalid
InvalidStopPriceFor new stop limit orders, the price was invalid
InvalidStopPriceSellFor new stop limit sell orders, the "stop_price" price was lower than the "sell" price
InvalidStopPriceBuyFor new stop limit buy orders, the "stop_price" price was greater than the "buy" price
InvalidStopPriceRatioFor new stop limit orders, the "buy" or "sell" price was not within 50% of the "stop_price"
InvalidQuantityA negative or otherwise invalid quantity was specified
InvalidSideFor new orders, and invalid side was specified
InvalidSignatureThe signature did not match the expected signature
InvalidSymbolAn invalid symbol was specified
InvalidTimestampInPayloadThe JSON payload contained a timestamp parameter with an unsupported value.
InvalidAccountNameThe specified name did not match any accounts within the master group
InvalidAccountTypeThe specified type did not match exchange or custody
InvalidFundTransferThe fund transfer was not successful
MaintenanceThe system is down for maintenance
MarketNotOpenThe order was rejected because the market is not accepting new orders
MissingAccountNameA required account name was not specified in a field requiring one
MissingAccountsA required account field was not specified
MissingApikeyHeaderThe X-GEMINI-APIKEY header was missing
MissingOrderFieldA required order_id field was not specified
MissingRoleThe API key used to access this endpoint does not have the required role assigned to it
MissingPayloadHeaderThe X-GEMINI-PAYLOAD header was missing
MissingPayloadKeyThe payload is missing a required key
MissingSignatureHeaderThe X-GEMINI-SIGNATURE header was missing
MissingNameA required name field was not specified
MissingNonceA nonce was not provided in the payload. See Private API Invocation for more detail.
MoreThanOneAccountMore than one account was specified on an API that only accepts a single account
AccountClosedAccount account is closed and cannot be used for this operation.
AccountsOnGroupOnlyApiThe account field was specified on a non-master API key
AccountLimitExceededThe account field specified more than the maximum supported accounts for that API
NoAccountOfTypeRequiredThe account field specified multiple accounts and some were not of the required account type
AccountNotOfTypeRequiredThe account specified in the account field was not of the required account type
NotGroupApiCompatibleA master API key was used to invoke an account only API
ExceededMaxAccountsInGroupAn account could not be created as the master group already has the maximum number of allowed accounts in it
NoSSLYou must use HTTPS to access the API
OptionsMustBeArrayThe options parameter must be an array.
OrderNotFoundThe order specified was not found
RateLimitRequests were made too frequently. See Rate Limits below.
SystemWe are experiencing technical issues
UnsupportedOptionThis order execution option is not supported.
HasNotAgreedToCustodyTermsThe 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.
BadAccountTypeThe type parameter must contain a string of either exchange or custody.
RemoteAddressForbiddenRequest received from an IP address that is not whitelisted under the group.
DateNotes
2016/11/10Initial WebSocket API documentation
2016/12/14New feature: API key roles
2017/02/08Better market data examples
2017/03/06Documentation bugfix: correct location of market data JSON example for trade events
2017/05/15Document Order Events Subscription Acknowledgement subscriptionId field
2017/05/15Clarified how Gemini rate limits incoming requests to public WebSocket APIs
2017/07/13API Change timestamp and timestampms added to Market Data API
2017/07/27Documentation bugfix: clarify the purpose of the trace_id in Order Events: Heartbeats
2017/08/10New 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/01API Change collar_price added to Market Data API
2018/04/06API Change Document block trades in Market Data and Order Events APIs.
2018/06/06API Change Market depth and entry filtering added to Market Data API
2019/06/20Adding documentation for Market Data v2 and Candles Data Feed
2019/11/22Updated response messages for Candles Data Feed on Market Data v2
2020/04/09Documentation for new token support: BAT, DAI, LINK, OXT
2020/08/28Removing DAIBTCand DAIETH trading pairs
2020/10/05Documentation for new order book support: BTCDAI and ETHDAI
2020/10/07Documentation for new token support: AAVE
2020/10/14Documentation for new token support: FIL
2021/01/28Documentation for new symbol support: BTCSGD and ETHSGD
2021/03/11Added new optional heartbeat filter
2021/03/22Documentation for new token support: SKL, GRT, BNT, 1INCH, ENJ, LRC, SAND
2021/03/29Documentation for new Multi Market Data Feed
2021/04/27Documentation for new token support: CUBE, LPT, BOND, MATIC, INJ, SUSHI
2021/05/05Documentation for new token support: DOGE
2021/06/16Documentation for new token support: ALCX, MIR, FTM, ANKR
2021/07/14Documentation for new token support: CTX
2021/07/21Documentation for new token support: XTZ
2021/09/15Documentation for new token support: AXS, SLP, LUNA, UST, MCO2
2021/11/13Documentation for new token support: WCFG, RARE, RAD, QNT, NMR, MASK, FET, ASH, AUDIO, API3, USDC, SHIB
2021/12/20Documentation for new token support: RNDR, MC, GALA, ENS, KP3R, CVC, ELON, MIM, SPELL
2022/02/01Documentation for new token support: TOKE, LDO, RLY
2022/02/28Documentation for new token support: SOL
2022/03/01Documentation for new token support: RAY, SBR
2022/03/16Documentation for new token support: APE
2022/03/29Documentation for new token support: RBN, FXS, DPI, LQTY, LUSD, FRAX, INDEX, MPL
2022/04/26Documentation for new token support: GUSDSGD
2022/04/27Documentation for new token support: METIS, QRDO, ZBC, CHZ, REVV, JAM, FIDA, GMT
2022/05/17Documentation for new token support: GFI, ORCA
2022/06/14Documentation for new token support: ALI, TRU
2022/06/22Documentation for new token support: GUSDGBP
2022/06/23Deprecating documentation for Auction and Block trading support
2022/07/06Documentation for new token support: DOT, ERN
2022/08/01Documentation for new token support: GAL, EUL, SAMO
2022/08/23Documentation for new token support: BICO, IMX, PLA, IOTX
2022/09/07Documentation for new token support: BUSD
2022/10/11Documentation for new token support: AVAX
2023/01/10Documentation for new token support: ATOM, USDT
2023/05/09Documentation for new token support: PEPE
2023/08/04Documentation for token delist: ENJ
2023/08/10Documentation for new token support: XRP
2023/09/11Documentation for new token support: HNT
2023/09/18Removed Documentation for new token support: MPL, MC, METIS, RBN, GFI, LQTY, and LUSD
2023/11/15Remove Documentation for delisted token: MIR, UST, FXS, FRAX, BUSD
2024/04/23Remove Documentation for delisted token: ZEC
2024/05/21Adding 'tid' to the TRADE RESPONSE events under Market Data v2
2024/05/05Remove Documentation for delisted token: OXT-BTC,OXT-ETH,BAT-BTC,BAT-ETH, BTC-DAI, ETH-DAI
  • Trust is Our Product™
  • For trademarks and patents, please see the Legal Notice.
  • NMLS #1518126
  • © Copyright 2022 Gemini Trust Company, LLC.
Gemini WebSocket API Reference (2024)
Top Articles
Latest Posts
Article information

Author: Msgr. Benton Quitzon

Last Updated:

Views: 6240

Rating: 4.2 / 5 (43 voted)

Reviews: 82% of readers found this page helpful

Author information

Name: Msgr. Benton Quitzon

Birthday: 2001-08-13

Address: 96487 Kris Cliff, Teresiafurt, WI 95201

Phone: +9418513585781

Job: Senior Designer

Hobby: Calligraphy, Rowing, Vacation, Geocaching, Web surfing, Electronics, Electronics

Introduction: My name is Msgr. Benton Quitzon, I am a comfortable, charming, thankful, happy, adventurous, handsome, precious person who loves writing and wants to share my knowledge and understanding with you.