This documentation is archived for reference only. These APIs have been replaced by the new WebSocket API. Start new integrations with the new WebSocket API.
WebSocket API v1 Overview
Introduction
Using WebSockets provides several advantages:
- 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. Using the private Order Events API, you would subscribe once and receive real time notifications of all order activity.
WebSocket Protocol Resources
Requests
Both public and private WebSocket API requests begin with a GET request that includes headers asking for an upgrade to the WebSocket protocol. The private API WebSocket request also includes the standard private API headers.
Public API Request Headers
Code
Private API Request Headers
Code
Private API Invocation
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.
Payload
The payload of the requests will be a JSON object. 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.
Authenticated APIs do not submit their payload as POSTed data, but instead put it in the X-GEMINI-PAYLOAD header.
Headers
| 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 |
Example
Code
Base64 encode, then sign with HMAC-SHA384:
Code
Roles
Gemini uses a role-based system for private API endpoints so that you can separate privileges for your API keys.
| Endpoint | URI | Trader | Fund Manager | Auditor |
|---|---|---|---|---|
| Order Events | /v1/order/events | Yes | No | Yes |
Responses
If successful, API requests will return an HTTP 101 Switching Protocols code in the response headers:
Code
Then the HTTP connection will be replaced by a WebSocket connection.
Data Types
| Type | Description |
|---|---|
string | A simple quoted string, following standard JSON rules. |
decimal | A decimal value, encoded in a JSON string. |
timestamp | The number of seconds since 1970-01-01 UTC. Use timestampms when available. |
timestampms | The number of milliseconds since 1970-01-01 UTC. Transmitted as a JSON number. |
integer | A whole number, transmitted as a JSON number. |
boolean | A JSON boolean, the literal string true or false. |
array | A JSON array. |
Timestamps
The timestamp data type describes a date and time as a whole number in Unix Time format.
Gemini strongly recommends using milliseconds instead of seconds for timestamps.
| 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 |
In responses, timestamp denotes seconds and timestampms denotes milliseconds since 1970-01-01 UTC.
Basis Points
Fees are calculated as a fraction of the notional value of each trade (price x amount) in basis points ("bps"), which represent 1/100th of a percent. For example, a fee of 25 bps means 0.25% of the denominated value.
Sequence Numbers
Events and heartbeats contain a socket_sequence number:
- WebSocket connection is established
- Optional subscription acknowledgement
- First event with
socket_sequenceset to0 - Each subsequent message increases the sequence by one
If you see a gap in the sequence number, disconnect and reconnect.
Each time you reconnect, the sequence number resets to zero. Multiple WebSocket connections each have separate sequence numbers.
Rate Limits
To prevent abuse, Gemini imposes rate limits on incoming requests.
For public WebSocket APIs, we recommend that you do not exceed 1 request per symbol per minute.
Error Codes
If a response is in error, the HTTP response code will reflect this, and a JSON body will be returned:
Code
HTTP Status Codes
| HTTP Status | Meaning |
|---|---|
| 200 | Request was successful |
| 30x | API entry point has moved, see Location header |
| 400 | Market not open, or the request was malformed |
| 403 | The API key is missing the role necessary to access this 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 Reasons
| Reason | Meaning |
|---|---|
| ClientOrderIdTooLong | The Client Order ID must be under 100 characters |
| ConflictingOptions | New orders using a combination of order execution options are not supported |
| EndpointMismatch | The request was submitted to an endpoint different than the one in the payload |
| 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 |
| InvalidOrderType | An unknown order type was provided |
| InvalidPrice | For new orders, the price was invalid |
| InvalidQuantity | A negative or otherwise invalid quantity was specified |
| InvalidSide | For new orders, an invalid side was specified |
| InvalidSignature | The signature did not match the expected signature |
| InvalidSymbol | An invalid symbol was specified |
| MarketNotOpen | The order was rejected because the market is not accepting new orders |
| MissingApikeyHeader | The X-GEMINI-APIKEY header was missing |
| MissingPayloadHeader | The X-GEMINI-PAYLOAD header was missing |
| MissingSignatureHeader | The X-GEMINI-SIGNATURE header was missing |
| MissingRole | The API key does not have the required role assigned |
| OrderNotFound | The order specified was not found |
| RateLimit | Requests were made too frequently |
| System | We are experiencing technical issues |
Sandbox
Gemini's sandbox site is an instance of the Gemini Exchange that offers full exchange functionality using test funds.
| Resource | URL |
|---|---|
| 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 |
Go to the sandbox site to register for a test account. Your account will automatically be credited with USD, BTC, ETH, BCH, LTC, OXT, LINK, BAT and DAI.
Two Factor Authentication: 2FA is enabled by default. To disable for automated testing, set a cookie or HTTP header named GEMINI-SANDBOX-2FA and enter 9999999 as the 2FA code.
Client Order ID
Client order ID is a client-supplied order identifier that Gemini will echo back in all subsequent messages about that order. Gemini strongly recommends supplying client_order_id when placing orders.
Your client order IDs are only visible to Gemini and you. They should be unique per trading session and must match: [:\-_\.#a-zA-Z0-9]{1,100}.
| Characters | Description | ASCII Codes |
|---|---|---|
A-Z | Uppercase letters | 65-90 |
a-z | Lowercase letters | 97-122 |
0-9 | Digits | 48-57 |
# - . : _ | Special characters | 35, 45, 46, 58, 95 |
Market Data v1
Market data is a public API that streams all the market data on a given symbol.
WebSocket Request
wss://api.gemini.com/v1/marketdata/:symbol
URL Parameters
| Parameter | Required | Default | Description |
|---|---|---|---|
heartbeat | No | false | Set to true to receive a heartbeat every 5 seconds |
top_of_book | No | false | If true, receive top of book only (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:
- To be excluded from
changeevents, an entry type must be explicitly flaggedfalse - If no filtering parameters are included, all entry types will appear
top_of_book has no meaning and initial book events are empty when only trades is specified.
Response
Each frame contains a JSON message with the following format:
| Field | Type | Description |
|---|---|---|
type | string | heartbeat or update |
socket_sequence | integer | Monotonic increasing sequence number |
Messages of type update also include:
| Field | Type | Description |
|---|---|---|
eventId | integer | Monotonically increasing sequence number for changes |
events | array | Order book changes or trade indications |
timestamp | timestamp | Timestamp in seconds (use timestampms instead) |
timestampms | timestampms | Timestamp in milliseconds |
All elements of events share:
| Field | Type | Description |
|---|---|---|
type | string | Either trade or change |
Change Event
| Field | Type | Description |
|---|---|---|
price | decimal | Price of this order book entry |
side | string | bid or ask |
reason | string | place, trade, cancel, or initial |
remaining | decimal | Quantity remaining at this price level |
delta | decimal | Quantity changed (may be negative) |
Every trade triggers a message with entries of both types trade and change.
To keep an up-to-date order book, watch for {"type": "change"} events and update the price level at price with the amount at remaining.
Trade Event
| Field | Type | Description |
|---|---|---|
price | decimal | Execution price |
amount | decimal | Amount traded |
makerSide | string | bid or ask |
Examples
Code
Initial Response (top of book)
Code
When a trade occurs
Code
Heartbeat
Code

