NAV
python shell

Gemini Instant

Gemini Instant is an order manager that guarantees execution of market orders and powers orders placed on the Gemini Mobile App and Web Interface. Gemini Instant orders are not available for all pairs and is intended to simplify the buying and selling experience.

NOTE: Trades made via the Instant API are subject to the Mobile Fee Schedule.

Workflow

The Gemini Instant workflow is as follows

  1. Request quote price for supported symbol from v1/instant/quote. The request must include totalSpend, side andsymbol for the order. The totalSpend will be in the base currency (CCY2) for buy orders and the top currency (CCY1) for sell orders. The totalSpendCurrency will be returned in the response from both v1/instant/quote and v1/instant/execute.
  2. v1/instant/quote will return a price, quoteId and maxAgeMs that indicates the total milliseconds until the quote expires. The endpoint will also return the quantity of currency to be received as well as the fee for the order.
  3. Request execution from v1/instant/execute by passing in the quoteId and other required parameters before the quote expires.
  4. The response will confirm that the order has been executed and will return order details.

Gemini Instant Quote

Roles

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

The OAuth scope must have orders:create assigned to access this endpoint. See OAuth Scopes for more information.

Sample Quote Request Payload for BTCUSD purchase

{
    "request": "/v1/instant/quote",
    "nonce": <nonce>,
    "symbol": "btcusd",
    "side": "buy",
    "totalSpend": "100"
}

Sample Quote Request Payload of ETHUSD sale

{
    "request": "/v1/instant/quote",
    "nonce": <nonce>,
    "symbol": "ethusd",
    "side": "sell",
    "totalSpend": "1"
}

HTTP Request

POST https://api.gemini.com/v1/instant/quote/

Payload Parameters

Parameter Type Description
request string The literal string "/v1/instant/quote/"
side string "buy" or "sell"
symbol string The symbol for the order. Instant includes order books denominated in a supported currency, as CCY2
totalSpend string Quoted decimal amount to spend on the order. Must comply with stated minimums. The totalSpend will be CCY2 in buy orders and CCY1 in sell orders.
paymentMethodUuid string Optional. uuid provided as bankId in Payment Methods API
paymentMethodType string Optional. Method used to specify payment method in buy order. Can be "AccountBalancePaymentType" to use funds available in USD balance held on Gemini, "BankAccountType" to initial an ACH from a linked bank account, or "CardAccountType" to use a linked debit card to fund the purchase.
account string Optional. Required for Master API keys as described in Private API Invocation. The name of the account within the subaccount group. Specifies the account on which you intend to place the order. Only available for exchange accounts.

Sample BTCUSD Buy Response

{
  "quoteId": 1328,
  "maxAgeMs": 60000,
  "pair": "BTCUSD",
  "price": "6445.07",
  "priceCurrency": "USD",
  "side": "buy",
  "quantity": "0.01505181",
  "quantityCurrency": "BTC",
  "fee": "2.9900309233",
  "feeCurrency": "USD",
  "depositFee": "0",
  "depositFeeCurrency": "USD",
  "totalSpend": "100",
  "totalSpendCurrency": "USD"
}

Sample ETHUSD Sell Response

{
  "quoteId": "20930",
  "maxAgeMs": "60000",
  "pair": "ETHUSD",
  "price": "225.42",
  "priceCurrency": "USD",
  "side": "sell",
  "quantity": "1",
  "quantityCurrency": "ETH",
  "fee": "2.99",
  "feeCurrency": "USD",
  "depositFee": "0",
  "depositFeeCurrency": "USD",
  "totalSpend": "1",
  "totalSpendCurrency": "ETH"
}

Response

Field Type Description
quoteId integer Unique ID for the quote. This is used in the execution of the order
maxAgeMs integer Number of milliseconds until this quote price expires. Once expired, you will need to request a new quote
pair string The symbol passed in the quote request
price string The quoted price of the asset. This will not change when attempting execution
priceCurrency string The currency in which the order is priced. Matches CCY2 in the symbol
side string Either "buy" or "sell"
quantity string The quantity of the asset to be bought or sold
quantityCurrency string The currency label for the quantity field. Matches CCY1 in the symbol
fee string The fee quantity to be taken for the order upon execution
feeCurrency string The currency label for the order
depositFee string The deposit fee quantity. Will be applied if a debit card is used for the order. Will return 0 if there is no depositFee
depositFeeCurrency string Currency in which depositFee is taken
totalSpend string Total quantity to spend for the order. Will be the sum inclusive of all fees and amount to be traded.
totalSpendCurrency string Currency of the totalSpend to be spent on the order

Gemini Instant Execution

Once a quote is returned, the order may be executed using the /v1/instant/execute endpoint.

Roles

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

The OAuth scope must have orders:create assigned to access this endpoint. See OAuth Scopes for more information.

Sample Instant Order Execution Request Payload BTCUSD Buy

{
    "request": "/v1/instant/execute",
    "nonce": <nonce>,
    "symbol": "BTCUSD",
    "side": "buy",
    "quantity": "0.01505181",
    "price": "6445.07",
    "fee": "2.9900309233",
    "quoteId": 1328
}

Sample Instant Order Execution Request Payload ETHUSD Sell

{
    "request": "/v1/instant/execute",
    "nonce": <nonce>,
    "symbol": "ETHUSD",
    "side": "sell",
    "quantity": "1",
    "price": "225.42",
    "fee": "2.99",
    "quoteId": 20930
}

HTTP Request

POST https://api.gemini.com/v1/instant/execute

Payload Parameters

These parameters must match what is returned in the quote

Parameter Type Description
request string The literal string "/v1/instant/execute"
nonce integer The nonce, as described in Private API Invocation
symbol string The symbol for the order.
side string "buy" or "sell"
quantity string The quantity of the asset bought or sold. quantity must match quantity returned in the quote
fee string The fee for the order. fee must match fee returned in the quote
quoteId integer Unique ID for the quote. quoteId must match quoteId returned in the quote
account string Optional. Required for Master API keys as described in Private API Invocation. The name of the account within the subaccount group. Specifies the account on which you intend to place the order. Only available for exchange accounts.

Sample Response BTCUSD Buy

{
  "orderId": 375089415,
  "pair": "BTCUSD",
  "price": "6445.07",
  "priceCurrency": "USD",
  "side": "buy",
  "quantity": "0.01505181",
  "quantityCurrency": "BTC",
  "totalSpend": "100",
  "totalSpendCurrency": "USD",
  "fee": "2.9900309233",
  "feeCurrency": "USD",
  "depositFee": "0",
  "depositFeeCurrency": "USD"
}

Sample Response ETHUSD Sell

{
  "orderId": 377326322,
  "pair": "ETHUSD",
  "price": "225.42",
  "priceCurrency": "USD",
  "side": "sell",
  "quantity": "1",
  "quantityCurrency": "ETH",
  "totalSpend": "0.1",
  "totalSpendCurrency": "ETH",
  "fee": "2.99",
  "feeCurrency": "USD",
  "depositFee": "0",
  "depositFeeCurrency": "USD"
}

Response

Field Type Description
orderId integer The ID for the executed order
pair string The symbol for the order.
price string The price at which the order was executed
priceCurrency string The currency in which the order is priced. Matches CCY2 in the symbol
side string Either "buy" or "sell"
quantity string The quantity of the asset bought or sold
quantityCurrency string The currency label for the quantity field.
totalSpend string Total quantity to spend for the order. Will be the sum inclusive of all fees and amount to be traded.
totalSpendCurrency string Currency of the totalSpend to be spent on the order
fee string The fee quantity charged for the order
feeCurrency string The currency label for the fee.
depositFee string The deposit fee quantity. Will be applied if a debit card is used for the order. Will return 0 if there is no depositFee
depositFeeCurrency string Currency in which depositFee is taken

Sandbox

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

Sandbox URLs

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

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

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

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

Create your account

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

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

Requests

There are two types of APIs below, the public ones and the private ones, which are subdivided into order placement, order status, and account status.

Public API invocation

Public APIs are accessible via GET, and the parameters for the request are included in the query string.

Private API invocation

Payload creation

{
    "request": "/v1/order/status",
    "nonce": <nonce>,
    "order_id": 18834
}

Whitespace is valid JSON, so it 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/status",
>     "nonce": 123456,
>
>     "order_id": 18834
> }
> EOF
ewogICAgInJlcXVlc3QiOiAiL3YxL29yZGVyL3N0YXR1cyIsCiAgICAibm9uY2UiOiAxMjM0NTYs
CgogICAgIm9yZGVyX2lkIjogMTg4MzQKfQo=
encoded_payload = json.dumps(payload)
b64 = base64.b64encode(encoded_payload)

In this example, the api_secret is 1234abcd

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

The final request will look like this:

curl --request POST \
  --url https://api.gemini.com/v1/order/status \
  --header 'Cache-Control: no-cache' \
  --header 'Content-Length: 0' \
  --header 'Content-Type: text/plain' \
  --header 'X-GEMINI-APIKEY: mykey' \
  --header 'X-GEMINI-PAYLOAD: ewogICAgInJlcXVlc3QiOiAiL3YxL29yZGVyL3N0YXR1cyIsCiAgICAibm9uY2UiOiAxMjM0NTYsCgogICAgIm9yZGVyX2lkIjogMTg4MzQKfQo=' \
  --header 'X-GEMINI-SIGNATURE: 337cc8b4ea692cfe65b4a85fcc9f042b2e3f702ac956fd098d600ab15705775017beae402be773ceee10719ff70d710f'
import requests
import json
import base64
import hmac
import hashlib
import time

url = "https://api.gemini.com/v1/mytrades"
gemini_api_key = "mykey"
gemini_api_secret = "1234abcd".encode()

payload_nonce = time.time()

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

request_headers = {
    'Content-Type': "text/plain",
    'Content-Length': "0",
    'X-GEMINI-APIKEY': gemini_api_key,
    'X-GEMINI-PAYLOAD': b64,
    'X-GEMINI-SIGNATURE': signature,
    'Cache-Control': "no-cache"
    }

response = requests.post(url, headers=request_headers)

my_trades = response.json()
print(my_trades)

Which produces these HTTP headers

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

Authentication

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

All requests must contain a nonce. When provisioning a session key, you have the option of selecting "Uses a time based nonce". If this option is selected, the nonce, which must be in seconds, has to be within +/- 30 seconds of Unix Epoch timestamp to be deemed valid.

If you do not choose the option of a time based nonce, then the nonce has to be 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.

Sessions

A single account may have multiple API keys provisioned. In this document, we'll refer to these as "sessions". All orders will be recorded with the session that created them. The nonce associated with a request needs to be increasing with respect to the session that the nonce is used on.

This allows multithreaded or distributed trading systems to place orders independently of each other, without needing to synchronize clocks to avoid race conditions.

In addition, some operations (such as Cancel All Session Orders) act on the orders associated with a specific session.

Require Heartbeat

When provisioning a session key you have the option of marking the session as "Requires Heartbeat". The intention here is to specify that if connectivity to the exchange is lost for any reason, then all outstanding orders on this session should be canceled.

If this option is selected for a session, then if the exchange does not receive a message for 30 seconds, then it will assume there has been an interruption in service, and cancel all outstanding orders. To maintain the session, the trading system should send a heartbeat message at a more frequent interval. We suggest at most 15 seconds between heartbeats.

The heartbeat message is provided for convenience when there is no trading activity. Any authenticated API call will reset the 30 second clock, even if explicit heartbeats are not sent.

This feature is often referred to as "Cancel on Disconnect" on connection-oriented exchange protocols.

Payload

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

All of them will include the request name and the nonce associated with the request.

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

Master API

A group that contains multiple accounts can provision a Master API key. Master API keys offer the convenience of invoking any account API on behalf of an account within that group. To invoke an API on behalf of an account, add that account's nickname as an account parameter to your request payload.

Master API keys are formatted with a prepending master-, while account level API keys are formatted with a prepending account-.

The account parameter may be used on any API that performs an action for or against a single account.

Example of adding the account parameter to an API call, in this case New Order

{
    "request": "/v1/order/new",
    "account": "my-trading-account",
    "nonce": <nonce>,
    "client_order_id": <client_order_id>,
    "symbol": "btcusd",
    "amount": "5",
    "price": "3633.00",
    "side": "buy",
    "type": "exchange limit"
}

Roles

Example of error response due to API key missing a role

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

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

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

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

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

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

See Error Codes for more information about API error responses.

Administrator

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

Trader

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

Fund Manager

Assigning the Fund Manager role to an API key allows this API key to:

Auditor

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

Endpoint summary

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

Account Scoped API

Endpoint URI Trader can access? Fund Manager can access? Auditor can access?
New Order /v1/order/new
Cancel Order /v1/order/cancel
Cancel All Session Orders /v1/order/cancel/session
Cancel All Active Orders /v1/order/cancel/all
Wrap Order /v1/wrap/:symbol
Order Status /v1/order/status
Get Active Orders /v1/orders
Get Past Trades /v1/mytrades
Get Orders History /v1/orders/history
Get Trade Volume /v1/tradevolume
Get Notional Volume /v1/notionalvolume
Heartbeat /v1/heartbeat
Get Available Balances /v1/balances
Get Notional Balances v1/notionalbalances/:currency
Get Deposit Addresses /v1/addresses/:network
New Deposit Address /v1/deposit/:network/newAddress
Transfers /v1/transfers
Custody Account Fees /v1/custodyaccountfees
Withdraw Crypto Funds /v1/withdraw/:currency
New Clearing Order /v1/clearing/new
Clearing Order Status /v1/clearing/status
Cancel Clearing Order /v1/clearing/cancel
Confirm Clearing Order /v1/clearing/confirm
Clearing Order List /v1/clearing/list
Clearing Broker List /v1/clearing/broker/list
Clearing Trades /v1/clearing/trades
Get Instant Quote /v1/instant/quote/:side/:symbol
Execute Instant Order /v1/instant/execute
Add A Bank /v1/payments/addbank
Add A Bank CAD /v1/payments/addbank/cad
View Payment Methods /v1/payments/methods
Account Detail /v1/account
Create Approved Address /v1/approvedAddresses/:network/request
View Approved Address List /v1/approvedAddresses/account/:network
Remove Address from Approved Address List /v1/approvedAddresses/:network/remove
FX Rate /v2/fxrate/:symbol/:timestamp

Master Scoped API

Endpoint URI Administrator can access? Trader can access? Fund Manager can access? Auditor can access?
Create Account /v1/account/create
Rename Account /v1/account/rename
Get Accounts /v1/account/list
Internal Transfer /v1/account/transfer/:currency
Transactions /v1/transactions

Error Codes


{
    "result": "error",
    "reason": "InsufficientFunds",
    "message": "Primary bank/card account has insufficient funds"
}

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

  1. result, which will always be "error"
  2. reason, which will be one of the strings listed in the table below
  3. message, a human-readable English string indicating additional error information.
Reason Message
InsufficientFunds Primary bank/card account has insufficient funds.
MarketNotOpen The market is not currently accepting orders.
DuplicateOrder An internal error occurred. This order is a duplicate.
InvalidPrice The price entered was below the market minimum.
InvalidQuantity The quantity entered was below the market minimum.
StaleQuote An internal error occurred. Please try placing the order again.
InvalidOrder The order details you submitted are either invalid or stale. Please verify the order details and try again.
InvalidOrderType An internal error occurred. The order type is invalid.
InvalidQuoteId Invalid quoteId for symbol {symbol}.
AboveMaximum Maximum order size exceeded. Please enter an amount less than {0}
StaleFee The fee rate for this transaction has changed since you submitted. Please try again.
InsufficientPermissions Sorry, you do not have sufficient privilege to complete this action.
InsufficientFunds Sorry, you do not have sufficient funds available in your account to complete this order.
NegativeBalance You may only place an order if your balance is non-negative.
AccountClosed Account is closed and cannot be used for this operation.

Revision History

Date Notes
2020/05/28 Initial Gemini Instant API documentation