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
- Request quote price for supported symbol from v1/instant/quote. The request must include
totalSpend
,side
andsymbol
for the order. ThetotalSpend
will be in the base currency (CCY2
) for buy orders and the top currency (CCY1
) for sell orders. ThetotalSpendCurrency
will be returned in the response from both v1/instant/quote and v1/instant/execute. - v1/instant/quote will return a
price
,quoteId
andmaxAgeMs
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. - Request execution from v1/instant/execute by passing in the
quoteId
and other required parameters before the quote expires. - 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.
- 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:
- At the Authy 2FA entry screen, set a cookie or an HTTP header with the name GEMINI-SANDBOX-2FA. The value doesn’t matter.
- 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
is1234abcd
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
- one API key that can trade, and
- another API key that can withdraw digital assets, or
- 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 toMissingRole
, andmessage
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.
Administrator
Assigning the Administrator role to an API key allows this API key to:
- Create accounts within the Master Group
- View accounts within the Master Group
Trader
Assigning the Trader role to an API key allows this API key to:
- Check balances
- Place and cancel orders
- Check the status of orders
- See all deposit addresses
- See all active orders
- See your trade history and volume
- View accounts within the Master Group
Fund Manager
Assigning the Fund Manager role to an API key allows this API key to:
- Check balances
- See all deposit addresses
- Request new cryptocurrency deposit addresses
- Withdraw cryptocurrency funds
- View accounts within the Master Group
- Execute internal transfers between two accounts within the same Master group
Auditor
Assigning the Auditor role to an API key allows this API key to:
- Check balances
- Check the status of orders
- See transfers such as deposits and withdrawals
- See all deposit addresses
- See all active orders
- See trade volume
- See past trades
- View accounts within the Master Group
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:
result
, which will always be "error"reason
, which will be one of the strings listed in the table belowmessage
, 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 |
- Trust is Our Product™
- For trademarks and patents, please see the Legal Notice.
- NMLS #1518126
- © Copyright 2022 Gemini Trust Company, LLC.