Trading on Gemini
Build spot trading applications with real-time market data, order management, and account services on Gemini's institutional-grade exchange.
REST APIs
APIs for every type of user — retail, business, and institutional.
Get your API credentials
Sign up at exchange.gemini.com, navigate to Settings → API, and create a key with the Trading scope enabled.
export GEMINI_API_KEY="account-xxxxxxxxxxxxxxxx"
export GEMINI_API_SECRET="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"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).
git clone https://github.com/gemini/developer-platform.git
cd developer-platform/samples/python
pip install -r requirements.txtConfigure your environment
Create a .env file with your API credentials and the sandbox base URL. The sample uses python-dotenv to load these automatically.
cat > .env << 'EOF'
GEMINI_API_KEY=account-xxxxxxxxxxxxxxxx
GEMINI_API_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
GEMINI_BASE_URL=https://api.sandbox.gemini.com/v1
EOFRun the place order example
Run the example to place a sandbox limit order. The script handles HMAC-SHA384 signing automatically.
python place_order.pyYou're done!
Your order is live in the sandbox. Check the response for order_id and use it to query status or cancel.
# 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.
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.
export GEMINI_API_KEY="account-xxxxxxxxxxxxxxxx"
export GEMINI_API_SECRET="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"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.
# 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())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.
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",
},
}))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.
# 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") },
}))
breakBTCUSD 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.01Agentic
Build AI-powered trading agents using Gemini's MCP server and plug-and-play skills.
Build
cd developer-platform/packages/mcp-server
npm install
npm run build
Configure
# For Claude Code: (This will be be different for other tools.)
claude mcp add gemini -s user -e GEMINI_API_KEY=<your_key> -e \
GEMINI_API_SECRET=<your_secret> -- node <repo_root>/packages/mcp-server/dist/index.js
Validate
claude mcp list