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
Core Concepts
    Events, contracts, and outcomesCombo contracts
Market Data
    OverviewFetching Markets
    Ticker formats
      OverviewCryptoSportsSports Market TaxonomyCommoditiesWeather
Trading
    QuickstartOrder lifecycle and settlement
    Full REST reference
      Combo RFQ
      Events
      Volume
      Terms
      Order Management
      Positions
      Rewards
    WebSocket APIs
      OverviewAuthenticationMessage format
      Streams
        Book tickerL2 partial depthL2 differential depthTrade streamOrder eventsBalance updatesPosition updatesContract statusPrediction
      Utility
      Subscriptions
      L2 Data
      Order management
      Combo RFQ
        OverviewWebSocket streamsQuote methodsMaker integrationExamples
Market Makers
    Maker Fee-Free Trading PromoTaker Rewards ProgramMaker Rebate ProgramLiquidity Rewards ProgramMarket Maker Program
Resources
    SchemasDemo environmentRate limitsErrors
AuthenticationMessage Format
Streams
    OverviewBook TickerL2 Partial DepthL2 Differential DepthTrade StreamOrder EventsBalance UpdatesPosition UpdatesContract Status
Utility
    conninfopingtime
Subscriptions
    SUBSCRIBEUNSUBSCRIBELIST_SUBSCRIPTIONS
L2 Data
    depth
Trading
    order.placeorder.cancelorder.cancel_allorder.cancel_session

Stream Reference

Core API

Prediction Markets uses the core book, depth, trade, order, balance, and position stream protocol.

Prediction Markets WebSocket streams follow the standard Gemini WebSocket protocol. Symbols use the prediction markets format (e.g. GEMI-BTC05M2606011000-UP). Replace example symbols with active instrumentSymbol values from GET /v1/prediction-markets/events.

Use WebSocket streams for active trading and market making. Use REST endpoints for event discovery and state reconciliation.

Stream Matrix

StreamAuthUse forStart here
{symbol}@bookTickerPublicBest bid/ask prices and quantitiesFirst price watcher
{symbol}@depth5, {symbol}@depth10, {symbol}@depth20PublicPeriodic top-of-book snapshotsSimple dashboards
{symbol}@depth, {symbol}@depth@100msPublicMaintaining a local order bookMarket making
{symbol}@tradePublicRecent executionsTrade tape and analytics
{agency}:{index}@indexPricePublicPrice reference feeds for prediction-market contractsContract pricing and settlement
orders@accountAuthenticatedOrder lifecycle eventsOrder state tracking
balances@accountAuthenticatedBalance changesRisk checks
positions@accountAuthenticatedLow-latency position and settlement deltasExposure and settlement tracking
contractStatusPublicContract status and strike updatesLifecycle monitors

Authenticated streams require Gemini authentication headers (HMAC or OAuth bearer token) during the WebSocket handshake. Browser WebSocket clients cannot set custom headers; use backend services or proxy servers for account streams.

Index-Keyed Price Streams

Index-keyed price streams provide the live reference price associated with a prediction-market contract's sourceDetails.agency and sourceDetails.index. Subscribe using the exact values returned by the contract or event discovery API:

Code
{agency}:{index}@indexPrice

For example:

Code
lukka:LS-LRRR-ZECUSD@indexPrice lukka:LS-LRRR-HYPE22USD@indexPrice

These streams are public and event-driven. The server resolves the agency/index pair to the corresponding price feed and delivers the reference-price update using the standard third-party price message format. The matching is case-insensitive, but clients should use the values exactly as returned by the source-details fields. Unknown pairs are rejected as invalid stream names.

Book Ticker

SchemaFrequencyDescription
{symbol}@bookTickerReal-timeReal time updates to the best bid/ask price for an order book.
Try ItGEMI-BTC05M2606011000-UP@bookTicker
disconnected
Code
{ "u": 1751505576085, "E": 1751508438600117161, "s": "GEMI-BTC05M2606011000-UP", "b": "0.48", "B": "5000", "a": "0.52", "A": "3200" }
FieldTypeDescription
unumberUpdate ID
EnumberEvent time (nanoseconds)
sstringSymbol
bstringBest bid price
BstringBest bid quantity
astringBest ask price
AstringBest ask quantity
cstringLast trade price (present once the book has traded; omitted otherwise)
CstringLast trade size (present once the book has traded; omitted otherwise)

L2 Partial Depth Streams

SchemaFrequencyDescription
{symbol}@depth5Periodic (1s)Periodic snapshot of the top 5 levels once per second
{symbol}@depth10Periodic (1s)Top 10 levels
{symbol}@depth20Periodic (1s)Top 20 levels
{symbol}@depth5@100msPeriodic (100ms)Top 5 levels every 100 milliseconds
{symbol}@depth10@100msPeriodic (100ms)Top 10 levels
{symbol}@depth20@100msPeriodic (100ms)Top 20 levels
Try ItGEMI-BTC05M2606011000-UP@depth10@100ms
disconnected
Code
{ "lastUpdateId": 12345678, "bids": [ ["0.26", "5000"], ["0.25", "2000"] ], "asks": [ ["0.28", "3200"], ["0.29", "1500"] ] }
FieldTypeDescription
lastUpdateIdnumberLast update ID
bidsarrayArray of [price, quantity]
asksarrayArray of [price, quantity]

Use a depth snapshot as the starting point for any local order book or dollar calculation, then apply differential depth updates to keep it current. Each level is [price, quantity]. Public depth for event contracts is normalized in YES space: for YES notional, compute yesPrice * quantity; for NO notional, compute (1 - yesPrice) * quantity.


L2 Differential Depth Streams

SchemaFrequencyDescription
{symbol}@depthPeriodic (1s)List of all changed price levels in the last second
{symbol}@depth@100msPeriodic (100ms)In the last 100 milliseconds
Try ItGEMI-BTC05M2606011000-UP@depth@100ms
disconnected

Initial Snapshot

Use the snapshot connection parameter to receive an initial orderbook snapshot when subscribing. Connect with wss://ws.gemini.com?snapshot=-1 for a full snapshot, or specify a positive number for top N levels.

Quantity zero indicates price level removal.

There is no separate snapshot message and no lastUpdateId field on this stream. When you subscribe with the snapshot parameter set to a non-zero value, the first depthUpdate frame you receive is the snapshot — it carries the full requested book state in its b/a arrays instead of a delta. Its U and u identify the first and last update IDs covered by the snapshot; use u as the last applied update ID. Every frame after that first one is a normal incremental delta: apply it directly to your local book. If a later frame's U skips ahead of the last applied u, discard the local book and resubscribe to resync. Without the snapshot parameter, or with it set to 0, every frame you receive (including the first) is an incremental delta.

Code
{ "e": "depthUpdate", "E": 1751508260659505382, "s": "GEMI-BTC05M2606011000-UP", "U": 12345677, "u": 12345678, "b": [ ["0.48", "5000"], ["0.47", "0.00"] ], "a": [ ["0.52", "3200"] ] }
FieldTypeDescription
estringEvent type ("depthUpdate")
EnumberEvent time (nanoseconds)
sstringSymbol
UnumberFirst update ID in this event
unumberLast update ID in this event
barrayBid updates [price, quantity]
aarrayAsk updates [price, quantity]

Trade Stream

SchemaFrequencyDescription
{symbol}@tradeReal-timeReal time trade executions
Try ItGEMI-BTC05M2606011000-UP@trade
disconnected
Code
{ "E": 1759873803503023900, "s": "GEMI-BTC05M2606011000-UP", "t": 2840140956529623, "p": "0.50", "q": "10", "m": true }
FieldTypeDescription
EnumberEvent time (nanoseconds)
sstringSymbol
tnumberTrade ID
pstringPrice
qstringQuantity
mbooleanIs buyer the maker

Order Events

Requires an authenticated session

SchemaFrequencyDescription
orders@accountReal-timeReal time order activity for the account associated with the authenticated API key
orders@sessionReal-timeReal time order activity for the authenticated API key

Order Event - New:

Code
{ "e": "orderUpdate", "E": 1759291847686856569, "s": "GEMI-BTC05M2606011000-UP", "i": 73797746498585286, "c": "btc-5m-quote-001", "S": "BUY", "o": "LIMIT", "X": "NEW", "O": "YES", "p": "0.48000", "q": "10", "z": "10", "T": 1759291847686856569 }

Order Event - Canceled:

Code
{ "e": "orderUpdate", "E": 1759291847731455006, "s": "GEMI-BTC05M2606011000-UP", "i": 73797746498585286, "c": "btc-5m-quote-001", "X": "CANCELED", "T": 1759291847731455006 }
FieldTypeDescription
estringEvent type (orderUpdate)
EnumberEvent time (nanoseconds)
sstringSymbol
inumberOrder ID
cstringClient order ID. For RFQ maker fills, this is the clientId supplied to rfq.submit_quote, or Gemini's deterministic RFQ client order ID when omitted.
SstringSide, BUY / SELL
ostringType, LIMIT / MARKET / STOP_LIMIT / STOP_MARKET
XstringStatus, NEW / OPEN / FILLED / PARTIALLY_FILLED / CANCELED / REJECTED / MODIFIED
OstringEvent outcome, YES / NO
pstringOrder price
PstringStop price (0 when not a stop order)
qstringOriginal quantity
zstringRemaining quantity
ZstringExecuted quantity. For FILLED / PARTIALLY_FILLED events, this is the quantity filled in the last execution. For CANCELED and other events, this is the cumulative quantity filled over the lifetime of the order. Use Z (not the order status) to determine how much filled — e.g. a fully-filled IOC terminates as CANCELED.
LstringLast execution price
tnumberTrade ID
nstringFee amount (only present in 'FILLED' events)
mbooleanMaker flag on fills: true = maker, false = taker (present on fills only)
rstringRejection reason
TnumberUpdate time (nanoseconds)

Fields with empty or zero values may be omitted from the event.

Post-only and immediate time-in-force orders are accepted, then cancelled — they are never REJECTED:

  • MOC (maker-or-cancel / post-only): if it would take liquidity, the order is cancelled with MakerOrCancelWouldTake and never fills.
  • IOC (immediate-or-cancel): fills whatever crosses immediately, then cancels the remainder with ImmediateOrCancelWouldPost. A fully-filled IOC still ends with a CANCELED event — so determine what filled from the executed quantity (Z), never from the final order status.
  • FOK (fill-or-kill): fills completely and immediately, or is cancelled in full with FillOrKillWouldNotFill (no partial fills).

order.place for these still returns a 200 response with an initial NEW; a true rejection returns a non-200 status with an error code.

Rejection Reasons

When an order is REJECTED, the r field contains one of:

ReasonDescription
MarketNotOpenMarket is closed or paused
InsufficientFundsAccount lacks sufficient balance
InvalidPricePrice must be between $0.01–$0.99
LimitPriceOffTickPrice does not align with tick size
InvalidQuantityQuantity below minimum or off increment
InvalidTotalSpendTotal spend calculation error
DuplicateOrderDuplicate client order ID
InsufficientLiquidityNot enough liquidity at price
UnknownInstrumentTrading pair does not exist
TERMS_NOT_ACCEPTEDLatest Prediction Markets terms not accepted. Use the REST terms endpoints to read, check, and accept terms before retrying.

Cancellation Reasons

When an order is CANCELED by the system, the r field contains one of:

ReasonDescription
SelfCrossPreventedSelf-trade prevention triggered
FillOrKillWouldNotFillFOK order could not fill completely
ImmediateOrCancelWouldPostIOC order would post to book
MakerOrCancelWouldTakeMOC order would take liquidity
AuctionCancelledAuction-related cancellation
ExceedsPriceLimitsPrice moved beyond limits

Balance Updates

Requires an authenticated session

SchemaFrequencyDescription
balances@accountReal-timeReal time balance updates for the account associated with the authenticated API key
balances@account@1sPeriodic (1s)Periodic snapshot of all balances every second for the account associated with the authenticated API key

The balances@account stream pushes updates in real time whenever a balance change occurs, and only includes the assets that changed. The balances@account@1s stream sends a complete snapshot of all account balances every second, regardless of whether they changed. On subscribe, balances@account@1s will immediately send the current balances if available.

Balance Update:

Code
{ "e": "balanceUpdate", "E": 1768250434780000000, "u": 1768250421600000000, "B": [ { "a": "USD", "f": "207.39", "c": "207.39" } ] }
FieldTypeDescription
estringEvent type ("balanceUpdate")
EnumberEvent time (nanoseconds)
unumberTime of the last account update (nanoseconds)
BarrayBalance updates
astringAsset code
fstringAvailable balance (amount available to trade)
cstringConfirmed balance (total balance including pending)

Position Updates

Requires an authenticated session

SchemaFrequencyDescription
positions@accountReal-timeReal time event-contract position updates for the account associated with the authenticated API key
positions@account@1sPeriodic (1s)Periodic snapshot of all open event-contract positions every second for the account associated with the authenticated API key

The positions@account stream pushes deltas in real time on fill, position open/close, and event-contract settlement events, and only includes the rows that changed. A settlement close is delivered as a terminal row with position set to "0", followed by a settlement_payout amount carrying the payout currency and outcome. The positions@account@1s stream sends a complete snapshot of all open positions every second, regardless of whether they changed. On subscribe, positions@account@1s will immediately send the current positions if available.

Use positions@account for low-latency event-contract position deltas on the same WebSocket connection you use for trading. Reconcile with POST /v1/prediction-markets/positions after reconnects, missed messages, and settlement windows.

Connect to wss://ws.gemini.com. Authentication must be provided on the WebSocket upgrade — you cannot authenticate after the connection is established. Use either HMAC-signed API key headers (account-scoped only; master/group keys are rejected with HTTP 401) or an OAuth 2.0 bearer token (Authorization: Bearer <access_token>). See Authentication.

Subscribe after the connection opens:

Code
{ "id": "1", "method": "SUBSCRIBE", "params": ["positions@account"] }

Server acknowledgement:

Code
{ "id": "1", "status": 200 }

Snapshot and delta frames share the same shape:

Code
{ "e": "positionReport", "E": 1760000000000000000, "u": 1759999999000000000, "A": 12345, "P": [ { "t": "ec", "s": "GEMI-BTC05M2606011000-UP", "a": [ { "t": "position", "v": "2.5" } ] } ] }
FieldTypeDescription
estringEvent type, always positionReport
EnumberEvent timestamp in nanoseconds
unumberLast account update timestamp in nanoseconds
AnumberAccount ID
ParrayPosition rows for this account; an empty array means no open position rows are included
P[].tstringProduct type. Event contracts use ec
P[].sstringInstrument symbol
P[].aarrayNamed amount array
P[].a[].tstringAmount label. Position quantity uses position; a settlement close also includes settlement_payout
P[].a[].vstringDecimal string amount. position is signed; settlement_payout is the payout amount
P[].a[].cstringOptional asset code. Settlement payouts use usd; position quantities omit this field
P[].a[].ostringSettlement outcome on settlement_payout: YES, NO, or UNSPECIFIED

The first subscription for an account returns a snapshot of currently open positions. Subsequent frames are deltas carrying only rows that changed. A position close emits a row with position value "0" before that row is evicted; a settlement close includes settlement_payout and outcome in that same terminal row. Later snapshots omit zero-position rows. The a array is intentionally extensible; clients should ignore unknown amount labels instead of failing.


Settlements

Requires an authenticated session

There is no standalone settlements@account stream. Settlement details are delivered in the terminal positionReport delta on positions@account.

The terminal row contains a zero position amount and a settlement_payout amount. The payout amount uses c: "usd"; its o value is YES, NO, or UNSPECIFIED. Subscribe using the standard Position Updates request format.

Use POST /v1/prediction-markets/positions/settled for historical settled positions and reconciliation after reconnects or missed messages.


Contract Status

Prediction marketsAdds to or differs from the core API.

Prediction-market contract lifecycle events — status transitions (e.g. Awaiting Approval → Approved → Active) and strike-populated moments for Up/Down contracts.

SchemaFrequencyDescription
contractStatusReal-timeStatus changes and strike-price updates for prediction-market contracts
Code
# Strike-based contract (e.g. HI78999D63) { "e": "contractStatus", "E": 1776871540195, "s": "gemi-btc15m2604221545-hi78999d63", "k": "btc15m2604221545", "c": "HI78999D63", "i": 134794, "p": "78999.63", "o": "Awaiting Approval", "n": "Approved" } # Up/Down contract (no numeric strike — `p` omitted until populated) { "e": "contractStatus", "E": 1776871295498, "s": "gemi-btc05m2604221630-up", "k": "btc05m2604221630", "c": "UP", "i": 134791, "o": "Awaiting Approval", "n": "Approved" }
FieldTypeDescription
estringEvent type (contractStatus)
EnumberEvent time (Unix milliseconds)
sstringInstrument symbol
kstringEvent ticker
cstringContract ticker (e.g. HI78999D63, UP, DOWN)
inumberContract ID
pstringStrike price parsed from the contract ticker. Omitted for Up/Down contracts until the strike is set at activation
ostringPrevious status
nstringNew status

For Up/Down contracts, p is omitted while the strike is unknown and included once it is set — subscribers can detect strike availability by the field's presence.

Message formatOverview
On this page
  • Stream Matrix
  • Index-Keyed Price Streams
  • Book Ticker
  • L2 Partial Depth Streams
  • L2 Differential Depth Streams
  • Trade Stream
  • Order Events
    • Rejection Reasons
    • Cancellation Reasons
  • Balance Updates
  • Position Updates
  • Settlements
  • Contract Status
JSON
JSON
JSON
JSON
JSON
JSON
JSON
JSON
JSON
JSON
JSON