GeminiGemini
Demo environmentGet API key
  • Overview
  • Crypto Trading
  • Prediction Markets
  • Perpetuals
  • Stocks
  • API Reference
  • SDKs & Tools
Changelog
Gemini logoGemini logo

© 2026 Gemini Space Station, Inc.

Overview
Spot
    OverviewGet started
    Orders API
    Market Data API
    Fund Management API
    Instant Orders API
    WebSocket API
    FIX API
Margin
    Overview
    Margin REST API
      Get Margin Account SummaryGet Margin Interest RatesPreview Margin Order Impact
Staking
    Overview
    Staking REST API
      List Staking BalancesStake Crypto FundsUnstake Crypto FundsList Staking Event HistoryList Staking RatesList Staking Rewards
Clearing
    Clearing REST API
      Clearing Orders
      Broker & Trade Operations
Crypto Trading

Spot crypto

Spot crypto on Gemini

Discover crypto markets, place spot orders, and manage balances through Gemini's REST, WebSocket, and FIX interfaces.

Get API key

Spot crypto REST API

Place spot orders, query market data, and manage crypto balances.

1

Get your API credentials

Sign up at exchange.gemini.com, navigate to Settings → API, and create a key with the Trading scope enabled.

Terminal
export GEMINI_API_KEY="account-xxxxxxxxxxxxxxxx"
export GEMINI_API_SECRET="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
2

Clone the samples repo and install dependencies

Clone the Gemini API samples repository, navigate to the Python directory, and install the required packages (requests and python-dotenv).

Python
git clone https://github.com/gemini/developer-platform.git
cd developer-platform/samples/python
pip install -r requirements.txt
3

Configure your environment

Create a .env file with your API credentials and the sandbox base URL. The sample uses python-dotenv to load these automatically.

Python
cat > .env << 'EOF'
GEMINI_API_KEY=account-xxxxxxxxxxxxxxxx
GEMINI_API_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
GEMINI_BASE_URL=https://api.sandbox.gemini.com/v1
EOF
4

Run the place order example

Run the example to place a sandbox limit order. The script handles HMAC-SHA384 signing automatically.

Terminal
python place_order.py
5

You're done!

Your order is live in the sandbox. Check the response for order_id and use it to query status or cancel.

Python
# Order confirmed ✓
Order placed: {'order_id': '7651834', 'symbol': 'btcusd', 'side': 'buy', ...}

WebSocket

Stream real-time prices, place orders, and receive fill notifications over a persistent WebSocket connection to wss://ws.gemini.com.

1

Set up credentials

Export your API key and secret as environment variables. WebSocket authentication requires account-scoped keys with time-based nonces enabled — keys without these settings will be rejected at connection time.

Terminal
export GEMINI_API_KEY="account-xxxxxxxxxxxxxxxx"
export GEMINI_API_SECRET="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
2

Connect and stream prices

Connect to wss://ws.gemini.com, sign the handshake headers with your secret, then subscribe to {symbol}@bookTicker for real-time best-bid/ask updates.

Python
# pip install websockets
import asyncio, websockets, hmac, hashlib, base64, json, time

API_KEY = "your-api-key"
API_SECRET = "your-api-secret"
SYMBOL = "BTCUSD"

def auth_headers():
    nonce = str(int(time.time()))
    payload = base64.b64encode(nonce.encode())
    signature = hmac.new(API_SECRET.encode(), payload, hashlib.sha384).hexdigest()
    return {
        "X-GEMINI-APIKEY": API_KEY,
        "X-GEMINI-NONCE": nonce,
        "X-GEMINI-PAYLOAD": payload.decode(),
        "X-GEMINI-SIGNATURE": signature,
    }

async def stream_prices():
    async with websockets.connect("wss://ws.gemini.com", additional_headers=auth_headers()) as ws:
        await ws.send(json.dumps({
            "id": "1",
            "method": "subscribe",
            "params": [f"{SYMBOL}@bookTicker"],
        }))

        async for msg in ws:
            data = json.loads(msg)
            if "b" in data and "a" in data:
                print(f"{data['s']}  bid: ${data['b']} ({data['B']} BTC)  ask: ${data['a']} ({data['A']} BTC)")

asyncio.run(stream_prices())
3

Place an order

Subscribe to orders@account alongside the price stream, then send order.place once you see a price. Use cancelOnDisconnect=true as a query parameter to automatically cancel open orders if your connection drops.

Python
async def trade():
    url = "wss://ws.gemini.com?cancelOnDisconnect=true"
    async with websockets.connect(url, additional_headers=auth_headers()) as ws:
        await ws.send(json.dumps({
            "id": "1",
            "method": "subscribe",
            "params": [
                f"{SYMBOL}@bookTicker",  # live prices
                "orders@account",         # your order updates
            ],
        }))

        # Wait for a price, then place an order
        async for msg in ws:
            data = json.loads(msg)
            if "b" in data and "a" in data and data.get("s") == SYMBOL:
                break

        await ws.send(json.dumps({
            "id": "2",
            "method": "order.place",
            "params": {
                "symbol": SYMBOL,
                "side": "BUY",
                "type": "LIMIT",
                "timeInForce": "GTC",
                "price": "95000.00",
                "quantity": "0.01",
                "clientOrderId": "my-first-ws-order",
            },
        }))
4

Listen for fills & cancel

Order lifecycle events arrive on the orders@account stream. The X field carries the status (NEW, FILLED, etc.). To cancel, send order.cancel with the order ID from the i field.

Python
        # Watch order updates
        # X = status, S = side, p = price, q = quantity
        async for msg in ws:
            data = json.loads(msg)
            if data.get("X") in ("NEW", "OPEN", "FILLED", "PARTIALLY_FILLED"):
                print(f"Order {data['X']}: side={data.get('S')} price=${data.get('p')} qty={data.get('q')}")

            # Cancel once filled
            if data.get("X") == "FILLED":
                await ws.send(json.dumps({
                    "id": "3",
                    "method": "order.cancel",
                    "params": { "orderId": data.get("i") },
                }))
                break
5
Output
BTCUSD  bid: $95000.00 (0.50 BTC)  ask: $95001.00 (0.25 BTC)
Order NEW: side=BUY price=$95000.00 qty=0.01
Order OPEN: side=BUY price=$95000.00 qty=0.01
Order FILLED: side=BUY price=$95000.00 qty=0.01