Trading Websocket Streams
Order
Order
STREAM: v1.order
Subscribes to a feed of order updates pertaining to orders made by your account.
Each Order can be uniquely identified by its order_id
or client_order_id
.
To subscribe to all orders, specify an empty instrument
(eg. 2345123
).
Otherwise, specify the instrument
to only receive orders for that instrument (eg. 2345123-BTC_USDT_Perp
).
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
sub_account_idsa |
string | True | The subaccount ID to filter by |
instrumenti |
string | False'all' |
The instrument filter to apply. |
JSONRPC Wrappers
All Websocket JSON RPC Requests are housed in this wrapper. You may specify a stream, and a list of feeds to subscribe to.
If a request_id
is supplied in this JSON RPC request, it will be propagated back to any relevant JSON RPC responses (including error).
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See Overview
page for more details.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
jsonrpcj |
string | True | The JSON RPC version to use for the request |
methodm |
string | True | The method to use for the request (eg: subscribe / unsubscribe / v1/instrument ) |
paramsp |
object | True | The parameters for the request |
idi |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
All Websocket JSON RPC Responses are housed in this wrapper. It returns a confirmation of the JSON RPC subscribe request.
If a request_id
is supplied in the JSON RPC request, it will be propagated back in this JSON RPC response.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
jsonrpcj |
string | True | The JSON RPC version to use for the request |
resultr |
object | Falsenull |
The result for the request |
errore |
Error | Falsenull |
The error for the request |
idi |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
methodm |
string | True | The method used in the request for this response (eg: subscribe / unsubscribe / v1/instrument ) |
Error
An error response
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
codec |
integer | True | The error code for the request |
messagem |
string | True | The error message for the request |
All V1 Websocket Subscription Requests are housed in this wrapper. You may specify a stream and a list of feeds to subscribe to.
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See Overview
page for more details.
Sequence numbers can be either gateway-specific or global:
- Gateway Unique Sequence Number: Increments by one per stream, resets to 0 on gateway restart.
- Global Unique Sequence Number: A cluster-wide unique number assigned to each cluster payload, does not reset on gateway restarts, and can be used to track and identify message order across streams using sequence_number
and prev_sequence_number
in the feed response.
Set useGlobalSequenceNumber = true
if you need a persistent, unique identifier across all streams or ordering across multiple feeds.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
selectorss1 |
[string] | True | The list of feeds to subscribe to |
To ensure you always know if you have missed any payloads, GRVT servers apply the following heuristics to sequence numbers:
- All snapshot payloads will have a sequence number of
0
. All delta payloads will have a sequence number of1+
. So its easy to distinguish between snapshots, and deltas - Num snapshots returned in Response (per stream): You can ensure that you received the right number of snapshots
- First sequence number returned in Response (per stream): You can ensure that you received the first stream, without gaps from snapshots
- Sequence numbers should always monotonically increase by
1
. If it decreases, or increases by more than1
. Please reconnect - Duplicate sequence numbers are possible due to network retries. If you receive a duplicate, please ignore it, or idempotently re-update it.
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See
Overview
page for more details.NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
subss1 |
[string] | True | The list of feeds subscribed to |
unsubsu |
[string] | True | The list of feeds unsubscribed from |
num_snapshotsns |
[integer] | True | The number of snapshot payloads to expect for each subscribed feed. Returned in same order as subs |
first_sequence_numberfs |
[string] | True | The first sequence number to expect for each subscribed feed. Returned in same order as subs |
All V1 Websocket Unsubscription Requests are housed in this wrapper. You may specify a stream, a list of feeds and whether those feeds use global sequence numbers to unsubscribe from.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The channel to unsubscribe from (eg: ticker.s / ticker.d) |
selectorss1 |
[string] | True | The list of feeds to unsubscribe from |
Returns a confirmation of all unsubscribes
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
unsubsu |
[string] | True | The list of feeds unsubscribed from |
All V1 Websocket Requests are housed in this wrapper. You may specify a stream, and a list of feeds to subscribe to.
If a request_id
is supplied in this JSON RPC request, it will be propagated back to any relevant JSON RPC responses (including error).
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See Overview
page for more details.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
request_idri |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
feedf |
[string] | True | The list of feeds to subscribe to |
methodm |
string | True | The method to use for the request (eg: subscribe / unsubscribe) |
is_fullif |
boolean | Falsefalse |
Whether the request is for full data or lite data |
All V1 Websocket Responses are housed in this wrapper. It returns a confirmation of the JSON RPC subscribe request.
If a request_id
is supplied in the JSON RPC request, it will be propagated back in this JSON RPC response.
To ensure you always know if you have missed any payloads, GRVT servers apply the following heuristics to sequence numbers:
- All snapshot payloads will have a sequence number of
0
. All delta payloads will have a sequence number of1+
. So its easy to distinguish between snapshots, and deltas - Num snapshots returned in Response (per stream): You can ensure that you received the right number of snapshots
- First sequence number returned in Response (per stream): You can ensure that you received the first stream, without gaps from snapshots
- Sequence numbers should always monotonically increase by
1
. If it decreases, or increases by more than1
. Please reconnect - Duplicate sequence numbers are possible due to network retries. If you receive a duplicate, please ignore it, or idempotently re-update it.
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See
Overview
page for more details.NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
request_idri |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
subss1 |
[string] | True | The list of feeds subscribed to |
unsubsu |
[string] | True | The list of feeds unsubscribed from |
num_snapshotsns |
[integer] | True | The number of snapshot payloads to expect for each subscribed feed. Returned in same order as subs |
first_sequence_numberfs |
[string] | True | The first sequence number to expect for each subscribed feed. Returned in same order as subs |
Subscribe
Full Subscribe Request
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.order",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
{
"jsonrpc": "2.0",
"result": {
"stream": "v1.order",
"subs": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"unsubs": [],
"num_snapshots": [10],
"first_sequence_number": [872634876]
},
"id": 123,
"method": "subscribe"
}
Unsubscribe
Full Unsubscribe Request
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.order",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
{
"jsonrpc": "2.0",
"result": {
"stream": "v1.order",
"unsubs": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123,
"method": "subscribe"
}
Legacy Subscribe
Full Subscribe Request
{
"request_id":1,
"stream":"v1.order",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":true
}
{
"request_id":1,
"stream":"v1.order",
"subs":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"unsubs":[],
"num_snapshots":[1],
"first_sequence_number":[2813]
}
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | Stream name |
selectors1 |
string | True | Primary selector |
sequence_numbersn |
string | True | A sequence number used to determine message order within a stream. - If useGlobalSequenceNumber is false, this returns the gateway sequence number, which increments by one locally within each stream and resets on gateway restarts.- If useGlobalSequenceNumber is true, this returns the global sequence number, which uniquely identifies messages across the cluster.- A single cluster payload can be multiplexed into multiple stream payloads. - To distinguish each stream payload, a dedupCounter is included.- The returned sequence number is computed as: cluster_sequence_number * 10^5 + dedupCounter . |
feedf |
Order | True | The order object being created or updated |
Order
Order is a typed payload used throughout the GRVT platform to express all orderbook, RFQ, and liquidation orders.
GRVT orders are capable of expressing both single-legged, and multi-legged orders by default.
This increases the learning curve slightly but reduces overall integration load, since the order payload is used across all GRVT trading venues.
Given GRVT's trustless settlement model, the Order payload also carries the signature, required to trade the order on our ZKSync Hyperchain.
All fields in the Order payload (except id
, metadata
, and state
) are trustlessly enforced on our Hyperchain.
This minimizes the amount of trust users have to offer to GRVT
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
order_idoi |
string | False0 |
[Filled by GRVT Backend] A unique 128-bit identifier for the order, deterministically generated within the GRVT backend |
sub_account_idsa |
string | True | The subaccount initiating the order |
is_marketim |
boolean | Falsefalse |
If the order is a market order Market Orders do not have a limit price, and are always executed according to the maker order price. Market Orders must always be taker orders |
time_in_forceti |
TimeInForce | True | Four supported types of orders: GTT, IOC, AON, FOK:
RFQ Maker only supports (GTT, AON), RFQ Taker only supports (FOK) |
post_onlypo |
boolean | Falsefalse |
If True, Order must be a maker order. It has to fill the orderbook instead of match it. If False, Order can be either a maker or taker order. In this case, order creation is currently subject to a speedbump of 25ms to ensure orders are matched against updated orderbook quotes. |
reduce_onlyro |
boolean | Falsefalse |
If True, Order must reduce the position size, or be cancelled |
legsl |
[OrderLeg] | True | The legs present in this order The legs must be sorted by Asset.Instrument/Underlying/Quote/Expiration/StrikePrice |
signatures |
Signature | True | The signature approving this order |
metadatam |
OrderMetadata | True | Order Metadata, ignored by the smart contract, and unsigned by the client |
states1 |
OrderState | False'' |
[Filled by GRVT Backend] The current state of the order, ignored by the smart contract, and unsigned by the client |
TimeInForce
Must Fill All | Can Fill Partial | |
---|---|---|
Must Fill Immediately | FOK | IOC |
Can Fill Till Time | AON | GTC |
Value | Description |
---|---|
GOOD_TILL_TIME = 1 |
GTT - Remains open until it is cancelled, or expired |
ALL_OR_NONE = 2 |
AON - Either fill the whole order or none of it (Block Trades Only) |
IMMEDIATE_OR_CANCEL = 3 |
IOC - Fill the order as much as possible, when hitting the orderbook. Then cancel it |
FILL_OR_KILL = 4 |
FOK - Both AoN and IoC. Either fill the full order when hitting the orderbook, or cancel it |
RETAIL_PRICE_IMPROVEMENT = 5 |
RPI - A GTT + PostOnly maker order, that can only be taken by non-algorithmic UI users. |
OrderLeg
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
instrumenti |
string | True | The instrument to trade in this leg |
sizes |
string | True | The total number of assets to trade in this leg, expressed in base asset decimal units. |
limit_pricelp |
string | False0 |
The limit price of the order leg, expressed in 9 decimals.This is the number of quote currency units to pay/receive for this leg. This should be null/0 if the order is a market order |
is_buying_assetib |
boolean | True | Specifies if the order leg is a buy or sell |
Signature
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
signers |
string | True | The address (public key) of the wallet signing the payload |
rr |
string | True | Signature R |
ss1 |
string | True | Signature S |
vv |
integer | True | Signature V |
expiratione |
string | True | Timestamp after which this signature expires, expressed in unix nanoseconds. Must be capped at 30 days |
noncen |
integer | True | Users can randomly generate this value, used as a signature deconflicting key. ie. You can send the same exact instruction twice with different nonces. When the same nonce is used, the same payload will generate the same signature. Our system will consider the payload a duplicate, and ignore it. |
OrderMetadata
Metadata fields are used to support Backend only operations. These operations are not trustless by nature.
Hence, fields in here are never signed, and is never transmitted to the smart contract.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
client_order_idco |
string | True | A unique identifier for the active order within a subaccount, specified by the client This is used to identify the order in the client's system This field can be used for order amendment/cancellation, but has no bearing on the smart contract layer This field will not be propagated to the smart contract, and should not be signed by the client This value must be unique for all active orders in a subaccount, or amendment/cancellation will not work as expected Gravity UI will generate a random clientOrderID for each order in the range [0, 2^63 - 1] To prevent any conflicts, client machines should generate a random clientOrderID in the range [2^63, 2^64 - 1] When GRVT Backend receives an order with an overlapping clientOrderID, we will reject the order with rejectReason set to overlappingClientOrderId |
create_timect |
string | False0 |
[Filled by GRVT Backend] Time at which the order was received by GRVT in unix nanoseconds |
triggert |
TriggerOrderMetadata | False `` |
Trigger fields are used to support any type of trigger order such as TP/SL |
brokerb |
BrokerTag | False `` |
Specifies the broker who brokered the order |
TriggerOrderMetadata
Contains metadata related to trigger orders, such as Take Profit (TP) or Stop Loss (SL).
Trigger orders are used to automatically execute an order when a predefined price condition is met, allowing traders to implement risk management strategies.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
trigger_typett |
TriggerType | True | Type of the trigger order. eg: Take Profit, Stop Loss, etc |
tpslt |
TPSLOrderMetadata | True | Contains metadata for Take Profit (TP) and Stop Loss (SL) trigger orders. |
TriggerType
Defines the type of trigger order used in trading, such as Take Profit or Stop Loss.
Trigger orders allow execution based on pre-defined price conditions rather than immediate market conditions.
Value | Description |
---|---|
UNSPECIFIED = 0 |
Not a trigger order. The order executes normally without any trigger conditions. |
TAKE_PROFIT = 1 |
Take Profit Order - Executes when the price reaches a specified level to secure profits. |
STOP_LOSS = 2 |
Stop Loss Order - Executes when the price reaches a specified level to limit losses. |
TPSLOrderMetadata
Contains metadata for Take Profit (TP) and Stop Loss (SL) trigger orders.
### Fields:
- triggerBy: Defines the price type that activates the order (e.g., index price).
- triggerPrice: The price at which the order is triggered, expressed in 9
decimal precision.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
trigger_bytb |
TriggerBy | True | Defines the price type that activates a Take Profit (TP) or Stop Loss (SL) order |
trigger_pricetp |
string | True | The Trigger Price of the order, expressed in 9 decimals. |
close_positioncp |
boolean | True | If True, the order will close the position when the trigger price is reached |
TriggerBy
Defines the price type that activates a Take Profit (TP) or Stop Loss (SL) order.
Trigger orders are executed when the selected price type reaches the specified trigger price.Different price types ensure flexibility in executing strategies based on market conditions.
Value | Description |
---|---|
UNSPECIFIED = 0 |
no trigger condition |
INDEX = 1 |
INDEX - Order is activated when the index price reaches the trigger price |
LAST = 2 |
LAST - Order is activated when the last trade price reaches the trigger price |
BrokerTag
BrokerTag is a tag for the broker that the order is sent from.
Value | Description |
---|---|
UNSPECIFIED = 0 |
|
COIN_ROUTES = 1 |
CoinRoutes |
ALERTATRON = 2 |
Alertatron |
ORIGAMI = 3 |
Origami |
OrderState
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
statuss |
OrderStatus | True | The status of the order |
reject_reasonrr |
OrderRejectReason | True | The reason for rejection or cancellation |
book_sizebs |
[string] | True | The number of assets available for orderbook/RFQ matching. Sorted in same order as Order.Legs |
traded_sizets |
[string] | True | The total number of assets traded. Sorted in same order as Order.Legs |
update_timeut |
string | True | Time at which the order was updated by GRVT, expressed in unix nanoseconds |
avg_fill_priceaf |
[string] | True | The average fill price of the order. Sorted in same order as Order.Legs |
OrderStatus
Value | Description |
---|---|
PENDING = 1 |
Order has been sent to the matching engine and is pending a transition to open/filled/rejected. |
OPEN = 2 |
Order is actively matching on the matching engine, could be unfilled or partially filled. |
FILLED = 3 |
Order is fully filled and hence closed. Taker Orders can transition directly from pending to filled, without going through open. |
REJECTED = 4 |
Order is rejected by matching engine since if fails a particular check (See OrderRejectReason). Once an order is open, it cannot be rejected. |
CANCELLED = 5 |
Order is cancelled by the user using one of the supported APIs (See OrderRejectReason). Before an order is open, it cannot be cancelled. |
OrderRejectReason
Value | Description |
---|---|
UNSPECIFIED = 0 |
order is not cancelled or rejected |
CLIENT_CANCEL = 1 |
client called a Cancel API |
CLIENT_BULK_CANCEL = 2 |
client called a Bulk Cancel API |
CLIENT_SESSION_END = 3 |
client called a Session Cancel API, or set the WebSocket connection to 'cancelOrdersOnTerminate' |
MARKET_CANCEL = 4 |
the market order was cancelled after no/partial fill. Lower precedence than other TimeInForce cancel reasons |
IOC_CANCEL = 5 |
the IOC order was cancelled after no/partial fill |
AON_CANCEL = 6 |
the AON order was cancelled as it could not be fully matched |
FOK_CANCEL = 7 |
the FOK order was cancelled as it could not be fully matched |
EXPIRED = 8 |
the order was cancelled as it has expired |
FAIL_POST_ONLY = 9 |
the post-only order could not be posted into the orderbook |
FAIL_REDUCE_ONLY = 10 |
the reduce-only order would have caused position size to increase |
MM_PROTECTION = 11 |
the order was cancelled due to market maker protection trigger |
SELF_TRADE_PROTECTION = 12 |
the order was cancelled due to self-trade protection trigger |
SELF_MATCHED_SUBACCOUNT = 13 |
the order matched with another order from the same sub account |
OVERLAPPING_CLIENT_ORDER_ID = 14 |
an active order on your sub account shares the same clientOrderId |
BELOW_MARGIN = 15 |
the order will bring the sub account below initial margin requirement |
LIQUIDATION = 16 |
the sub account is liquidated (and all open orders are cancelled by Gravity) |
INSTRUMENT_INVALID = 17 |
instrument is invalid or not found on Gravity |
INSTRUMENT_DEACTIVATED = 18 |
instrument is no longer tradable on Gravity. (typically due to a market halt, or instrument expiry) |
SYSTEM_FAILOVER = 19 |
system failover resulting in loss of order state |
UNAUTHORISED = 20 |
the credentials used (userSession/apiKeySession/walletSignature) is not authorised to perform the action |
SESSION_KEY_EXPIRED = 21 |
the session key used to sign the order expired |
SUB_ACCOUNT_NOT_FOUND = 22 |
the subaccount does not exist |
NO_TRADE_PERMISSION = 23 |
the signature used to sign the order has no trade permission |
UNSUPPORTED_TIME_IN_FORCE = 24 |
the order payload does not contain a supported TimeInForce value |
MULTI_LEGGED_ORDER = 25 |
the order has multiple legs, but multiple legs are not supported by this venue |
EXCEED_MAX_POSITION_SIZE = 26 |
the order would have caused the subaccount to exceed the max position size |
EXCEED_MAX_SIGNATURE_EXPIRATION = 27 |
the signature supplied is more than 30 days in the future |
MARKET_ORDER_WITH_LIMIT_PRICE = 28 |
the market order has a limit price set |
CLIENT_CANCEL_ON_DISCONNECT_TRIGGERED = 29 |
client cancel on disconnect triggered |
OCO_COUNTER_PART_TRIGGERED = 30 |
the OCO counter part order was triggered |
REDUCE_ONLY_LIMIT = 31 |
the remaining order size was cancelled because it exceeded current position size |
CLIENT_REPLACE = 32 |
the order was replaced by a client replace request |
Success
Full Feed Response
{
"stream": "v1.order",
"selector": "BTC_USDT_Perp",
"sequence_number": "872634876",
"feed": {
"order_id": "0x1234567890abcdef",
"sub_account_id": "'$GRVT_SUB_ACCOUNT_ID'",
"is_market": false,
"time_in_force": "GOOD_TILL_TIME",
"post_only": false,
"reduce_only": false,
"legs": [{
"instrument": "BTC_USDT_Perp",
"size": "10.5",
"limit_price": "65038.01",
"is_buying_asset": true
}],
"signature": {
"signer": "0xc73c0c2538fd9b833d20933ccc88fdaa74fcb0d0",
"r": "0xb788d96fee91c7cdc35918e0441b756d4000ec1d07d900c73347d9abbc20acc8",
"s": "0x3d786193125f7c29c958647da64d0e2875ece2c3f845a591bdd7dae8c475e26d",
"v": 28,
"expiration": "1697788800000000000",
"nonce": 1234567890
},
"metadata": {
"client_order_id": "23042",
"create_time": "1697788800000000000",
"trigger": {
"trigger_type": "TAKE_PROFIT",
"tpsl": {
"trigger_by": "LAST",
"trigger_price": "65038.10",
"close_position": false
}
},
"broker": "BROKER_CODE"
},
"state": {
"status": "PENDING",
"reject_reason": "CLIENT_CANCEL",
"book_size": ["10.5"],
"traded_size": ["1.5"],
"update_time": "1697788800000000000",
"avg_fill_price": ["60000.4"]
}
}
}
{
"s": "v1.order",
"s1": "BTC_USDT_Perp",
"sn": "872634876",
"f": {
"oi": "0x1234567890abcdef",
"sa": "'$GRVT_SUB_ACCOUNT_ID'",
"im": false,
"ti": "GOOD_TILL_TIME",
"po": false,
"ro": false,
"l": [{
"i": "BTC_USDT_Perp",
"s": "10.5",
"lp": "65038.01",
"ib": true
}],
"s": {
"s": "0xc73c0c2538fd9b833d20933ccc88fdaa74fcb0d0",
"r": "0xb788d96fee91c7cdc35918e0441b756d4000ec1d07d900c73347d9abbc20acc8",
"s1": "0x3d786193125f7c29c958647da64d0e2875ece2c3f845a591bdd7dae8c475e26d",
"v": 28,
"e": "1697788800000000000",
"n": 1234567890
},
"m": {
"co": "23042",
"ct": "1697788800000000000",
"t": {
"tt": "TAKE_PROFIT",
"t": {
"tb": "LAST",
"tp": "65038.10",
"cp": false
}
},
"b": "BROKER_CODE"
},
"s1": {
"s": "PENDING",
"rr": "CLIENT_CANCEL",
"bs": ["10.5"],
"ts": ["1.5"],
"ut": "1697788800000000000",
"af": ["60000.4"]
}
}
}
Error Codes
Code | HttpStatus | Description |
---|---|---|
1000 | 401 | You need to authenticate prior to using this functionality |
1001 | 403 | You are not authorized to access this functionality |
1002 | 500 | Internal Server Error |
1008 | 401 | Your IP has not been whitelisted for access |
1101 | 400 | Feed Format must be in the format of |
1102 | 400 | Wrong number of primary selectors |
1103 | 400 | Wrong number of secondary selectors |
3000 | 400 | Instrument is invalid |
3020 | 400 | Sub account ID must be an uint64 integer |
All Websocket JSON RPC Responses are housed in this wrapper. It returns a confirmation of the JSON RPC subscribe request.
If a request_id
is supplied in the JSON RPC request, it will be propagated back in this JSON RPC response.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
jsonrpcj |
string | True | The JSON RPC version to use for the request |
resultr |
object | Falsenull |
The result for the request |
errore |
Error | Falsenull |
The error for the request |
idi |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
methodm |
string | True | The method used in the request for this response (eg: subscribe / unsubscribe / v1/instrument ) |
Error
An error response
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
codec |
integer | True | The error code for the request |
messagem |
string | True | The error message for the request |
Error
Full Error Response
{
"jsonrpc": "2.0",
"error": {
"code": 1000,
"message": "You need to authenticate prior to using this functionality"
},
"id": 123,
"method": "subscribe"
}
{
"j": "2.0",
"e": {
"c": 1000,
"m": "You need to authenticate prior to using this functionality"
},
"i": 123,
"m": "subscribe"
}
{
"code":1000,
"message":"You need to authenticate prior to using this functionality",
"status":401
}
Authentication
In order to authenticate, you must first provision a valid API key. API keys can be provisioned via the GRVT UI.
# These are the variables you will need to set manually
GRVT_API_KEY="<insert_key_here>"
GRVT_SUB_ACCOUNT_ID="<insert_sub_account_id_here>"
Then, choose the environment you want to authenticate against.
# dev
GRVT_AUTH_ENDPOINT="https://edge.dev.gravitymarkets.io/auth/api_key/login"
# staging
GRVT_AUTH_ENDPOINT="https://edge.staging.gravitymarkets.io/auth/api_key/login"
# testnet
GRVT_AUTH_ENDPOINT="https://edge.testnet.grvt.io/auth/api_key/login"
# prod
GRVT_AUTH_ENDPOINT="https://edge.grvt.io/auth/api_key/login"
Now, let’s authenticate and retrieve both the session cookie and the X-Grvt-Account-Id
header value that you’ll need to access any endpoints requiring authentication.
echo $GRVT_API_KEY
echo $GRVT_SUB_ACCOUNT_ID
echo $GRVT_AUTH_ENDPOINT
RESPONSE=$(
curl $GRVT_AUTH_ENDPOINT \
-H 'Content-Type: application/json' \
-H 'Cookie: rm=true;' \
-d '{"api_key": "'$GRVT_API_KEY'"}' \
-s -i
)
GRVT_COOKIE=$(echo "$RESPONSE" | grep -i 'set-cookie:' | grep -o 'gravity=[^;]*')
GRVT_ACCOUNT_ID=$(echo "$RESPONSE" | grep 'x-grvt-account-id:' | awk '{print $2}' | tr -d '\r')
echo "$GRVT_COOKIE"
echo "$GRVT_ACCOUNT_ID"
Subscribe Full
wscat -c "wss://trades.dev.gravitymarkets.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.order",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
' -w 360
Unsubscribe Full
wscat -c "wss://trades.dev.gravitymarkets.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.order",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
' -w 360
Legacy Subscribe Full
wscat -c "wss://trades.dev.gravitymarkets.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.order",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":true
}
' -w 360
Subscribe Lite
wscat -c "wss://trades.dev.gravitymarkets.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "subscribe",
"p": {
"s": "v1.order",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"i": 123
}
' -w 360
Unsubscribe Lite
wscat -c "wss://trades.dev.gravitymarkets.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "unsubscribe",
"p": {
"s": "v1.order",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"i": 123
}
' -w 360
Legacy Subscribe Lite
wscat -c "wss://trades.dev.gravitymarkets.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.order",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":false
}
' -w 360
Subscribe Full
wscat -c "wss://trades.staging.gravitymarkets.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.order",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
' -w 360
Unsubscribe Full
wscat -c "wss://trades.staging.gravitymarkets.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.order",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
' -w 360
Legacy Subscribe Full
wscat -c "wss://trades.staging.gravitymarkets.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.order",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":true
}
' -w 360
Subscribe Lite
wscat -c "wss://trades.staging.gravitymarkets.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "subscribe",
"p": {
"s": "v1.order",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"i": 123
}
' -w 360
Unsubscribe Lite
wscat -c "wss://trades.staging.gravitymarkets.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "unsubscribe",
"p": {
"s": "v1.order",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"i": 123
}
' -w 360
Legacy Subscribe Lite
wscat -c "wss://trades.staging.gravitymarkets.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.order",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":false
}
' -w 360
Subscribe Full
wscat -c "wss://trades.testnet.grvt.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.order",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
' -w 360
Unsubscribe Full
wscat -c "wss://trades.testnet.grvt.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.order",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
' -w 360
Legacy Subscribe Full
wscat -c "wss://trades.testnet.grvt.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.order",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":true
}
' -w 360
Subscribe Lite
wscat -c "wss://trades.testnet.grvt.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "subscribe",
"p": {
"s": "v1.order",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"i": 123
}
' -w 360
Unsubscribe Lite
wscat -c "wss://trades.testnet.grvt.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "unsubscribe",
"p": {
"s": "v1.order",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"i": 123
}
' -w 360
Legacy Subscribe Lite
wscat -c "wss://trades.testnet.grvt.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.order",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":false
}
' -w 360
Subscribe Full
wscat -c "wss://trades.grvt.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.order",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
' -w 360
Unsubscribe Full
wscat -c "wss://trades.grvt.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.order",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
' -w 360
Legacy Subscribe Full
wscat -c "wss://trades.grvt.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.order",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":true
}
' -w 360
Subscribe Lite
wscat -c "wss://trades.grvt.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "subscribe",
"p": {
"s": "v1.order",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"i": 123
}
' -w 360
Unsubscribe Lite
wscat -c "wss://trades.grvt.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "unsubscribe",
"p": {
"s": "v1.order",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"i": 123
}
' -w 360
Legacy Subscribe Lite
wscat -c "wss://trades.grvt.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.order",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":false
}
' -w 360
Order State
STREAM: v1.state
Subscribes to a feed of order updates pertaining to orders made by your account.
Unlike the Order Stream, this only streams state updates, drastically improving throughput, and latency.
Each Order can be uniquely identified by its order_id
or client_order_id
.
To subscribe to all orders, specify an empty instrument
(eg. 2345123
).
Otherwise, specify the instrument
to only receive orders for that instrument (eg. 2345123-BTC_USDT_Perp
).
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
sub_account_idsa |
string | True | The subaccount ID to filter by |
instrumenti |
string | False'all' |
The instrument filter to apply. |
JSONRPC Wrappers
All Websocket JSON RPC Requests are housed in this wrapper. You may specify a stream, and a list of feeds to subscribe to.
If a request_id
is supplied in this JSON RPC request, it will be propagated back to any relevant JSON RPC responses (including error).
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See Overview
page for more details.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
jsonrpcj |
string | True | The JSON RPC version to use for the request |
methodm |
string | True | The method to use for the request (eg: subscribe / unsubscribe / v1/instrument ) |
paramsp |
object | True | The parameters for the request |
idi |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
All Websocket JSON RPC Responses are housed in this wrapper. It returns a confirmation of the JSON RPC subscribe request.
If a request_id
is supplied in the JSON RPC request, it will be propagated back in this JSON RPC response.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
jsonrpcj |
string | True | The JSON RPC version to use for the request |
resultr |
object | Falsenull |
The result for the request |
errore |
Error | Falsenull |
The error for the request |
idi |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
methodm |
string | True | The method used in the request for this response (eg: subscribe / unsubscribe / v1/instrument ) |
Error
An error response
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
codec |
integer | True | The error code for the request |
messagem |
string | True | The error message for the request |
All V1 Websocket Subscription Requests are housed in this wrapper. You may specify a stream and a list of feeds to subscribe to.
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See Overview
page for more details.
Sequence numbers can be either gateway-specific or global:
- Gateway Unique Sequence Number: Increments by one per stream, resets to 0 on gateway restart.
- Global Unique Sequence Number: A cluster-wide unique number assigned to each cluster payload, does not reset on gateway restarts, and can be used to track and identify message order across streams using sequence_number
and prev_sequence_number
in the feed response.
Set useGlobalSequenceNumber = true
if you need a persistent, unique identifier across all streams or ordering across multiple feeds.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
selectorss1 |
[string] | True | The list of feeds to subscribe to |
To ensure you always know if you have missed any payloads, GRVT servers apply the following heuristics to sequence numbers:
- All snapshot payloads will have a sequence number of
0
. All delta payloads will have a sequence number of1+
. So its easy to distinguish between snapshots, and deltas - Num snapshots returned in Response (per stream): You can ensure that you received the right number of snapshots
- First sequence number returned in Response (per stream): You can ensure that you received the first stream, without gaps from snapshots
- Sequence numbers should always monotonically increase by
1
. If it decreases, or increases by more than1
. Please reconnect - Duplicate sequence numbers are possible due to network retries. If you receive a duplicate, please ignore it, or idempotently re-update it.
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See
Overview
page for more details.NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
subss1 |
[string] | True | The list of feeds subscribed to |
unsubsu |
[string] | True | The list of feeds unsubscribed from |
num_snapshotsns |
[integer] | True | The number of snapshot payloads to expect for each subscribed feed. Returned in same order as subs |
first_sequence_numberfs |
[string] | True | The first sequence number to expect for each subscribed feed. Returned in same order as subs |
All V1 Websocket Unsubscription Requests are housed in this wrapper. You may specify a stream, a list of feeds and whether those feeds use global sequence numbers to unsubscribe from.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The channel to unsubscribe from (eg: ticker.s / ticker.d) |
selectorss1 |
[string] | True | The list of feeds to unsubscribe from |
Returns a confirmation of all unsubscribes
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
unsubsu |
[string] | True | The list of feeds unsubscribed from |
All V1 Websocket Requests are housed in this wrapper. You may specify a stream, and a list of feeds to subscribe to.
If a request_id
is supplied in this JSON RPC request, it will be propagated back to any relevant JSON RPC responses (including error).
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See Overview
page for more details.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
request_idri |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
feedf |
[string] | True | The list of feeds to subscribe to |
methodm |
string | True | The method to use for the request (eg: subscribe / unsubscribe) |
is_fullif |
boolean | Falsefalse |
Whether the request is for full data or lite data |
All V1 Websocket Responses are housed in this wrapper. It returns a confirmation of the JSON RPC subscribe request.
If a request_id
is supplied in the JSON RPC request, it will be propagated back in this JSON RPC response.
To ensure you always know if you have missed any payloads, GRVT servers apply the following heuristics to sequence numbers:
- All snapshot payloads will have a sequence number of
0
. All delta payloads will have a sequence number of1+
. So its easy to distinguish between snapshots, and deltas - Num snapshots returned in Response (per stream): You can ensure that you received the right number of snapshots
- First sequence number returned in Response (per stream): You can ensure that you received the first stream, without gaps from snapshots
- Sequence numbers should always monotonically increase by
1
. If it decreases, or increases by more than1
. Please reconnect - Duplicate sequence numbers are possible due to network retries. If you receive a duplicate, please ignore it, or idempotently re-update it.
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See
Overview
page for more details.NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
request_idri |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
subss1 |
[string] | True | The list of feeds subscribed to |
unsubsu |
[string] | True | The list of feeds unsubscribed from |
num_snapshotsns |
[integer] | True | The number of snapshot payloads to expect for each subscribed feed. Returned in same order as subs |
first_sequence_numberfs |
[string] | True | The first sequence number to expect for each subscribed feed. Returned in same order as subs |
Subscribe
Full Subscribe Request
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.state",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
{
"jsonrpc": "2.0",
"result": {
"stream": "v1.state",
"subs": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"unsubs": [],
"num_snapshots": [10],
"first_sequence_number": [872634876]
},
"id": 123,
"method": "subscribe"
}
Unsubscribe
Full Unsubscribe Request
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.state",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
{
"jsonrpc": "2.0",
"result": {
"stream": "v1.state",
"unsubs": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123,
"method": "subscribe"
}
Legacy Subscribe
Full Subscribe Request
{
"request_id":1,
"stream":"v1.state",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":true
}
{
"request_id":1,
"stream":"v1.state",
"subs":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"unsubs":[],
"num_snapshots":[1],
"first_sequence_number":[2813]
}
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | Stream name |
selectors1 |
string | True | Primary selector |
sequence_numbersn |
string | True | A sequence number used to determine message order within a stream. - If useGlobalSequenceNumber is false, this returns the gateway sequence number, which increments by one locally within each stream and resets on gateway restarts.- If useGlobalSequenceNumber is true, this returns the global sequence number, which uniquely identifies messages across the cluster.- A single cluster payload can be multiplexed into multiple stream payloads. - To distinguish each stream payload, a dedupCounter is included.- The returned sequence number is computed as: cluster_sequence_number * 10^5 + dedupCounter . |
feedf |
OrderStateFeed | True | The Order State Feed |
OrderStateFeed
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
order_idoi |
string | True | A unique 128-bit identifier for the order, deterministically generated within the GRVT backend |
client_order_idco |
string | True | A unique identifier for the active order within a subaccount, specified by the client |
order_stateos |
OrderState | True | The order state object being created or updated |
OrderState
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
statuss |
OrderStatus | True | The status of the order |
reject_reasonrr |
OrderRejectReason | True | The reason for rejection or cancellation |
book_sizebs |
[string] | True | The number of assets available for orderbook/RFQ matching. Sorted in same order as Order.Legs |
traded_sizets |
[string] | True | The total number of assets traded. Sorted in same order as Order.Legs |
update_timeut |
string | True | Time at which the order was updated by GRVT, expressed in unix nanoseconds |
avg_fill_priceaf |
[string] | True | The average fill price of the order. Sorted in same order as Order.Legs |
OrderStatus
Value | Description |
---|---|
PENDING = 1 |
Order has been sent to the matching engine and is pending a transition to open/filled/rejected. |
OPEN = 2 |
Order is actively matching on the matching engine, could be unfilled or partially filled. |
FILLED = 3 |
Order is fully filled and hence closed. Taker Orders can transition directly from pending to filled, without going through open. |
REJECTED = 4 |
Order is rejected by matching engine since if fails a particular check (See OrderRejectReason). Once an order is open, it cannot be rejected. |
CANCELLED = 5 |
Order is cancelled by the user using one of the supported APIs (See OrderRejectReason). Before an order is open, it cannot be cancelled. |
OrderRejectReason
Value | Description |
---|---|
UNSPECIFIED = 0 |
order is not cancelled or rejected |
CLIENT_CANCEL = 1 |
client called a Cancel API |
CLIENT_BULK_CANCEL = 2 |
client called a Bulk Cancel API |
CLIENT_SESSION_END = 3 |
client called a Session Cancel API, or set the WebSocket connection to 'cancelOrdersOnTerminate' |
MARKET_CANCEL = 4 |
the market order was cancelled after no/partial fill. Lower precedence than other TimeInForce cancel reasons |
IOC_CANCEL = 5 |
the IOC order was cancelled after no/partial fill |
AON_CANCEL = 6 |
the AON order was cancelled as it could not be fully matched |
FOK_CANCEL = 7 |
the FOK order was cancelled as it could not be fully matched |
EXPIRED = 8 |
the order was cancelled as it has expired |
FAIL_POST_ONLY = 9 |
the post-only order could not be posted into the orderbook |
FAIL_REDUCE_ONLY = 10 |
the reduce-only order would have caused position size to increase |
MM_PROTECTION = 11 |
the order was cancelled due to market maker protection trigger |
SELF_TRADE_PROTECTION = 12 |
the order was cancelled due to self-trade protection trigger |
SELF_MATCHED_SUBACCOUNT = 13 |
the order matched with another order from the same sub account |
OVERLAPPING_CLIENT_ORDER_ID = 14 |
an active order on your sub account shares the same clientOrderId |
BELOW_MARGIN = 15 |
the order will bring the sub account below initial margin requirement |
LIQUIDATION = 16 |
the sub account is liquidated (and all open orders are cancelled by Gravity) |
INSTRUMENT_INVALID = 17 |
instrument is invalid or not found on Gravity |
INSTRUMENT_DEACTIVATED = 18 |
instrument is no longer tradable on Gravity. (typically due to a market halt, or instrument expiry) |
SYSTEM_FAILOVER = 19 |
system failover resulting in loss of order state |
UNAUTHORISED = 20 |
the credentials used (userSession/apiKeySession/walletSignature) is not authorised to perform the action |
SESSION_KEY_EXPIRED = 21 |
the session key used to sign the order expired |
SUB_ACCOUNT_NOT_FOUND = 22 |
the subaccount does not exist |
NO_TRADE_PERMISSION = 23 |
the signature used to sign the order has no trade permission |
UNSUPPORTED_TIME_IN_FORCE = 24 |
the order payload does not contain a supported TimeInForce value |
MULTI_LEGGED_ORDER = 25 |
the order has multiple legs, but multiple legs are not supported by this venue |
EXCEED_MAX_POSITION_SIZE = 26 |
the order would have caused the subaccount to exceed the max position size |
EXCEED_MAX_SIGNATURE_EXPIRATION = 27 |
the signature supplied is more than 30 days in the future |
MARKET_ORDER_WITH_LIMIT_PRICE = 28 |
the market order has a limit price set |
CLIENT_CANCEL_ON_DISCONNECT_TRIGGERED = 29 |
client cancel on disconnect triggered |
OCO_COUNTER_PART_TRIGGERED = 30 |
the OCO counter part order was triggered |
REDUCE_ONLY_LIMIT = 31 |
the remaining order size was cancelled because it exceeded current position size |
CLIENT_REPLACE = 32 |
the order was replaced by a client replace request |
Success
Full Feed Response
{
"stream": "v1.state",
"selector": "BTC_USDT_Perp",
"sequence_number": "872634876",
"feed": {
"order_id": "10000101000203040506",
"client_order_id": "23042",
"order_state": {
"status": "PENDING",
"reject_reason": "CLIENT_CANCEL",
"book_size": ["10.5"],
"traded_size": ["1.5"],
"update_time": "1697788800000000000",
"avg_fill_price": ["60000.4"]
}
}
}
{
"s": "v1.state",
"s1": "BTC_USDT_Perp",
"sn": "872634876",
"f": {
"oi": "10000101000203040506",
"co": "23042",
"os": {
"s": "PENDING",
"rr": "CLIENT_CANCEL",
"bs": ["10.5"],
"ts": ["1.5"],
"ut": "1697788800000000000",
"af": ["60000.4"]
}
}
}
Error Codes
Code | HttpStatus | Description |
---|---|---|
1000 | 401 | You need to authenticate prior to using this functionality |
1001 | 403 | You are not authorized to access this functionality |
1002 | 500 | Internal Server Error |
1008 | 401 | Your IP has not been whitelisted for access |
1101 | 400 | Feed Format must be in the format of |
1102 | 400 | Wrong number of primary selectors |
1103 | 400 | Wrong number of secondary selectors |
3000 | 400 | Instrument is invalid |
3020 | 400 | Sub account ID must be an uint64 integer |
All Websocket JSON RPC Responses are housed in this wrapper. It returns a confirmation of the JSON RPC subscribe request.
If a request_id
is supplied in the JSON RPC request, it will be propagated back in this JSON RPC response.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
jsonrpcj |
string | True | The JSON RPC version to use for the request |
resultr |
object | Falsenull |
The result for the request |
errore |
Error | Falsenull |
The error for the request |
idi |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
methodm |
string | True | The method used in the request for this response (eg: subscribe / unsubscribe / v1/instrument ) |
Error
An error response
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
codec |
integer | True | The error code for the request |
messagem |
string | True | The error message for the request |
Error
Full Error Response
{
"jsonrpc": "2.0",
"error": {
"code": 1000,
"message": "You need to authenticate prior to using this functionality"
},
"id": 123,
"method": "subscribe"
}
{
"j": "2.0",
"e": {
"c": 1000,
"m": "You need to authenticate prior to using this functionality"
},
"i": 123,
"m": "subscribe"
}
{
"code":1000,
"message":"You need to authenticate prior to using this functionality",
"status":401
}
Authentication
In order to authenticate, you must first provision a valid API key. API keys can be provisioned via the GRVT UI.
# These are the variables you will need to set manually
GRVT_API_KEY="<insert_key_here>"
GRVT_SUB_ACCOUNT_ID="<insert_sub_account_id_here>"
Then, choose the environment you want to authenticate against.
# dev
GRVT_AUTH_ENDPOINT="https://edge.dev.gravitymarkets.io/auth/api_key/login"
# staging
GRVT_AUTH_ENDPOINT="https://edge.staging.gravitymarkets.io/auth/api_key/login"
# testnet
GRVT_AUTH_ENDPOINT="https://edge.testnet.grvt.io/auth/api_key/login"
# prod
GRVT_AUTH_ENDPOINT="https://edge.grvt.io/auth/api_key/login"
Now, let’s authenticate and retrieve both the session cookie and the X-Grvt-Account-Id
header value that you’ll need to access any endpoints requiring authentication.
echo $GRVT_API_KEY
echo $GRVT_SUB_ACCOUNT_ID
echo $GRVT_AUTH_ENDPOINT
RESPONSE=$(
curl $GRVT_AUTH_ENDPOINT \
-H 'Content-Type: application/json' \
-H 'Cookie: rm=true;' \
-d '{"api_key": "'$GRVT_API_KEY'"}' \
-s -i
)
GRVT_COOKIE=$(echo "$RESPONSE" | grep -i 'set-cookie:' | grep -o 'gravity=[^;]*')
GRVT_ACCOUNT_ID=$(echo "$RESPONSE" | grep 'x-grvt-account-id:' | awk '{print $2}' | tr -d '\r')
echo "$GRVT_COOKIE"
echo "$GRVT_ACCOUNT_ID"
Subscribe Full
wscat -c "wss://trades.dev.gravitymarkets.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.state",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
' -w 360
Unsubscribe Full
wscat -c "wss://trades.dev.gravitymarkets.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.state",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
' -w 360
Legacy Subscribe Full
wscat -c "wss://trades.dev.gravitymarkets.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.state",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":true
}
' -w 360
Subscribe Lite
wscat -c "wss://trades.dev.gravitymarkets.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "subscribe",
"p": {
"s": "v1.state",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"i": 123
}
' -w 360
Unsubscribe Lite
wscat -c "wss://trades.dev.gravitymarkets.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "unsubscribe",
"p": {
"s": "v1.state",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"i": 123
}
' -w 360
Legacy Subscribe Lite
wscat -c "wss://trades.dev.gravitymarkets.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.state",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":false
}
' -w 360
Subscribe Full
wscat -c "wss://trades.staging.gravitymarkets.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.state",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
' -w 360
Unsubscribe Full
wscat -c "wss://trades.staging.gravitymarkets.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.state",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
' -w 360
Legacy Subscribe Full
wscat -c "wss://trades.staging.gravitymarkets.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.state",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":true
}
' -w 360
Subscribe Lite
wscat -c "wss://trades.staging.gravitymarkets.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "subscribe",
"p": {
"s": "v1.state",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"i": 123
}
' -w 360
Unsubscribe Lite
wscat -c "wss://trades.staging.gravitymarkets.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "unsubscribe",
"p": {
"s": "v1.state",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"i": 123
}
' -w 360
Legacy Subscribe Lite
wscat -c "wss://trades.staging.gravitymarkets.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.state",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":false
}
' -w 360
Subscribe Full
wscat -c "wss://trades.testnet.grvt.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.state",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
' -w 360
Unsubscribe Full
wscat -c "wss://trades.testnet.grvt.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.state",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
' -w 360
Legacy Subscribe Full
wscat -c "wss://trades.testnet.grvt.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.state",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":true
}
' -w 360
Subscribe Lite
wscat -c "wss://trades.testnet.grvt.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "subscribe",
"p": {
"s": "v1.state",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"i": 123
}
' -w 360
Unsubscribe Lite
wscat -c "wss://trades.testnet.grvt.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "unsubscribe",
"p": {
"s": "v1.state",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"i": 123
}
' -w 360
Legacy Subscribe Lite
wscat -c "wss://trades.testnet.grvt.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.state",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":false
}
' -w 360
Subscribe Full
wscat -c "wss://trades.grvt.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.state",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
' -w 360
Unsubscribe Full
wscat -c "wss://trades.grvt.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.state",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
' -w 360
Legacy Subscribe Full
wscat -c "wss://trades.grvt.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.state",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":true
}
' -w 360
Subscribe Lite
wscat -c "wss://trades.grvt.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "subscribe",
"p": {
"s": "v1.state",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"i": 123
}
' -w 360
Unsubscribe Lite
wscat -c "wss://trades.grvt.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "unsubscribe",
"p": {
"s": "v1.state",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"i": 123
}
' -w 360
Legacy Subscribe Lite
wscat -c "wss://trades.grvt.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.state",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":false
}
' -w 360
Cancel Status
STREAM: v1.cancel
Subscribes to a feed of time-to-live expiry events for order cancellations requested by a given subaccount.
This stream presently only provides expiry updates for cancel-order requests set with a valid TTL value.
Successful order cancellations will reflect as updates published to the order-state stream.
A future release will expand the functionality of this stream to provide more general status updates on order cancellation requests.
Each Order can be uniquely identified by its client_order_id
.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
sub_account_idsa |
string | True | The subaccount ID to filter by |
JSONRPC Wrappers
All Websocket JSON RPC Requests are housed in this wrapper. You may specify a stream, and a list of feeds to subscribe to.
If a request_id
is supplied in this JSON RPC request, it will be propagated back to any relevant JSON RPC responses (including error).
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See Overview
page for more details.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
jsonrpcj |
string | True | The JSON RPC version to use for the request |
methodm |
string | True | The method to use for the request (eg: subscribe / unsubscribe / v1/instrument ) |
paramsp |
object | True | The parameters for the request |
idi |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
All Websocket JSON RPC Responses are housed in this wrapper. It returns a confirmation of the JSON RPC subscribe request.
If a request_id
is supplied in the JSON RPC request, it will be propagated back in this JSON RPC response.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
jsonrpcj |
string | True | The JSON RPC version to use for the request |
resultr |
object | Falsenull |
The result for the request |
errore |
Error | Falsenull |
The error for the request |
idi |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
methodm |
string | True | The method used in the request for this response (eg: subscribe / unsubscribe / v1/instrument ) |
Error
An error response
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
codec |
integer | True | The error code for the request |
messagem |
string | True | The error message for the request |
All V1 Websocket Subscription Requests are housed in this wrapper. You may specify a stream and a list of feeds to subscribe to.
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See Overview
page for more details.
Sequence numbers can be either gateway-specific or global:
- Gateway Unique Sequence Number: Increments by one per stream, resets to 0 on gateway restart.
- Global Unique Sequence Number: A cluster-wide unique number assigned to each cluster payload, does not reset on gateway restarts, and can be used to track and identify message order across streams using sequence_number
and prev_sequence_number
in the feed response.
Set useGlobalSequenceNumber = true
if you need a persistent, unique identifier across all streams or ordering across multiple feeds.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
selectorss1 |
[string] | True | The list of feeds to subscribe to |
To ensure you always know if you have missed any payloads, GRVT servers apply the following heuristics to sequence numbers:
- All snapshot payloads will have a sequence number of
0
. All delta payloads will have a sequence number of1+
. So its easy to distinguish between snapshots, and deltas - Num snapshots returned in Response (per stream): You can ensure that you received the right number of snapshots
- First sequence number returned in Response (per stream): You can ensure that you received the first stream, without gaps from snapshots
- Sequence numbers should always monotonically increase by
1
. If it decreases, or increases by more than1
. Please reconnect - Duplicate sequence numbers are possible due to network retries. If you receive a duplicate, please ignore it, or idempotently re-update it.
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See
Overview
page for more details.NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
subss1 |
[string] | True | The list of feeds subscribed to |
unsubsu |
[string] | True | The list of feeds unsubscribed from |
num_snapshotsns |
[integer] | True | The number of snapshot payloads to expect for each subscribed feed. Returned in same order as subs |
first_sequence_numberfs |
[string] | True | The first sequence number to expect for each subscribed feed. Returned in same order as subs |
All V1 Websocket Unsubscription Requests are housed in this wrapper. You may specify a stream, a list of feeds and whether those feeds use global sequence numbers to unsubscribe from.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The channel to unsubscribe from (eg: ticker.s / ticker.d) |
selectorss1 |
[string] | True | The list of feeds to unsubscribe from |
Returns a confirmation of all unsubscribes
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
unsubsu |
[string] | True | The list of feeds unsubscribed from |
All V1 Websocket Requests are housed in this wrapper. You may specify a stream, and a list of feeds to subscribe to.
If a request_id
is supplied in this JSON RPC request, it will be propagated back to any relevant JSON RPC responses (including error).
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See Overview
page for more details.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
request_idri |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
feedf |
[string] | True | The list of feeds to subscribe to |
methodm |
string | True | The method to use for the request (eg: subscribe / unsubscribe) |
is_fullif |
boolean | Falsefalse |
Whether the request is for full data or lite data |
All V1 Websocket Responses are housed in this wrapper. It returns a confirmation of the JSON RPC subscribe request.
If a request_id
is supplied in the JSON RPC request, it will be propagated back in this JSON RPC response.
To ensure you always know if you have missed any payloads, GRVT servers apply the following heuristics to sequence numbers:
- All snapshot payloads will have a sequence number of
0
. All delta payloads will have a sequence number of1+
. So its easy to distinguish between snapshots, and deltas - Num snapshots returned in Response (per stream): You can ensure that you received the right number of snapshots
- First sequence number returned in Response (per stream): You can ensure that you received the first stream, without gaps from snapshots
- Sequence numbers should always monotonically increase by
1
. If it decreases, or increases by more than1
. Please reconnect - Duplicate sequence numbers are possible due to network retries. If you receive a duplicate, please ignore it, or idempotently re-update it.
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See
Overview
page for more details.NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
request_idri |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
subss1 |
[string] | True | The list of feeds subscribed to |
unsubsu |
[string] | True | The list of feeds unsubscribed from |
num_snapshotsns |
[integer] | True | The number of snapshot payloads to expect for each subscribed feed. Returned in same order as subs |
first_sequence_numberfs |
[string] | True | The first sequence number to expect for each subscribed feed. Returned in same order as subs |
Subscribe
Full Subscribe Request
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.cancel",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'"]
},
"id": 123
}
{
"jsonrpc": "2.0",
"result": {
"stream": "v1.cancel",
"subs": ["'$GRVT_SUB_ACCOUNT_ID'"],
"unsubs": [],
"num_snapshots": [10],
"first_sequence_number": [872634876]
},
"id": 123,
"method": "subscribe"
}
Unsubscribe
Full Unsubscribe Request
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.cancel",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'"]
},
"id": 123
}
{
"jsonrpc": "2.0",
"result": {
"stream": "v1.cancel",
"unsubs": ["'$GRVT_SUB_ACCOUNT_ID'"]
},
"id": 123,
"method": "subscribe"
}
Legacy Subscribe
Full Subscribe Request
{
"request_id":1,
"stream":"v1.cancel",
"feed":["'$GRVT_SUB_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":true
}
{
"request_id":1,
"stream":"v1.cancel",
"subs":["'$GRVT_SUB_ACCOUNT_ID'"],
"unsubs":[],
"num_snapshots":[1],
"first_sequence_number":[2813]
}
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | Stream name |
selectors1 |
string | True | Primary selector |
sequence_numbersn |
string | True | A sequence number used to determine message order within a stream. - If useGlobalSequenceNumber is false, this returns the gateway sequence number, which increments by one locally within each stream and resets on gateway restarts.- If useGlobalSequenceNumber is true, this returns the global sequence number, which uniquely identifies messages across the cluster.- A single cluster payload can be multiplexed into multiple stream payloads. - To distinguish each stream payload, a dedupCounter is included.- The returned sequence number is computed as: cluster_sequence_number * 10^5 + dedupCounter . |
feedf |
CancelStatusFeed | True | Data relating to the status of the cancellation attempt |
CancelStatusFeed
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
sub_account_idsa |
string | True | The subaccount ID that requested the cancellation |
client_order_idco |
string | True | A unique identifier for the active order within a subaccount, specified by the client |
order_idoi |
string | True | A unique 128-bit identifier for the order, deterministically generated within the GRVT backend |
reasonr |
OrderRejectReason | True | The user-provided reason for cancelling the order |
update_timeut |
string | False0 |
[Filled by GRVT Backend] Time at which the cancellation status was updated by GRVT in unix nanoseconds |
cancel_statuscs |
CancelStatus | True | Status of the cancellation attempt |
OrderRejectReason
Value | Description |
---|---|
UNSPECIFIED = 0 |
order is not cancelled or rejected |
CLIENT_CANCEL = 1 |
client called a Cancel API |
CLIENT_BULK_CANCEL = 2 |
client called a Bulk Cancel API |
CLIENT_SESSION_END = 3 |
client called a Session Cancel API, or set the WebSocket connection to 'cancelOrdersOnTerminate' |
MARKET_CANCEL = 4 |
the market order was cancelled after no/partial fill. Lower precedence than other TimeInForce cancel reasons |
IOC_CANCEL = 5 |
the IOC order was cancelled after no/partial fill |
AON_CANCEL = 6 |
the AON order was cancelled as it could not be fully matched |
FOK_CANCEL = 7 |
the FOK order was cancelled as it could not be fully matched |
EXPIRED = 8 |
the order was cancelled as it has expired |
FAIL_POST_ONLY = 9 |
the post-only order could not be posted into the orderbook |
FAIL_REDUCE_ONLY = 10 |
the reduce-only order would have caused position size to increase |
MM_PROTECTION = 11 |
the order was cancelled due to market maker protection trigger |
SELF_TRADE_PROTECTION = 12 |
the order was cancelled due to self-trade protection trigger |
SELF_MATCHED_SUBACCOUNT = 13 |
the order matched with another order from the same sub account |
OVERLAPPING_CLIENT_ORDER_ID = 14 |
an active order on your sub account shares the same clientOrderId |
BELOW_MARGIN = 15 |
the order will bring the sub account below initial margin requirement |
LIQUIDATION = 16 |
the sub account is liquidated (and all open orders are cancelled by Gravity) |
INSTRUMENT_INVALID = 17 |
instrument is invalid or not found on Gravity |
INSTRUMENT_DEACTIVATED = 18 |
instrument is no longer tradable on Gravity. (typically due to a market halt, or instrument expiry) |
SYSTEM_FAILOVER = 19 |
system failover resulting in loss of order state |
UNAUTHORISED = 20 |
the credentials used (userSession/apiKeySession/walletSignature) is not authorised to perform the action |
SESSION_KEY_EXPIRED = 21 |
the session key used to sign the order expired |
SUB_ACCOUNT_NOT_FOUND = 22 |
the subaccount does not exist |
NO_TRADE_PERMISSION = 23 |
the signature used to sign the order has no trade permission |
UNSUPPORTED_TIME_IN_FORCE = 24 |
the order payload does not contain a supported TimeInForce value |
MULTI_LEGGED_ORDER = 25 |
the order has multiple legs, but multiple legs are not supported by this venue |
EXCEED_MAX_POSITION_SIZE = 26 |
the order would have caused the subaccount to exceed the max position size |
EXCEED_MAX_SIGNATURE_EXPIRATION = 27 |
the signature supplied is more than 30 days in the future |
MARKET_ORDER_WITH_LIMIT_PRICE = 28 |
the market order has a limit price set |
CLIENT_CANCEL_ON_DISCONNECT_TRIGGERED = 29 |
client cancel on disconnect triggered |
OCO_COUNTER_PART_TRIGGERED = 30 |
the OCO counter part order was triggered |
REDUCE_ONLY_LIMIT = 31 |
the remaining order size was cancelled because it exceeded current position size |
CLIENT_REPLACE = 32 |
the order was replaced by a client replace request |
CancelStatus
Value | Description |
---|---|
EXPIRED = 1 |
Cancellation has expired because corresponding order had not arrived within the defined time-to-live window. |
DROPPED_DUPLICATE = 2 |
This cancellation request was dropped because its TTL window overlaps with another cancellation request for the same order. |
Success
Full Feed Response
{
"stream": "v1.cancel",
"selector": "'$GRVT_SUB_ACCOUNT_ID'",
"sequence_number": "872634876",
"feed": {
"sub_account_id": "'$GRVT_SUB_ACCOUNT_ID'",
"client_order_id": "23042",
"order_id": "10000101000203040506",
"reason": "UNSPECIFIED",
"update_time": "1697788800000000000",
"cancel_status": "EXPIRED"
}
}
{
"s": "v1.cancel",
"s1": "'$GRVT_SUB_ACCOUNT_ID'",
"sn": "872634876",
"f": {
"sa": "'$GRVT_SUB_ACCOUNT_ID'",
"co": "23042",
"oi": "10000101000203040506",
"r": "UNSPECIFIED",
"ut": "1697788800000000000",
"cs": "EXPIRED"
}
}
Error Codes
Code | HttpStatus | Description |
---|---|---|
1000 | 401 | You need to authenticate prior to using this functionality |
1001 | 403 | You are not authorized to access this functionality |
1002 | 500 | Internal Server Error |
1008 | 401 | Your IP has not been whitelisted for access |
1101 | 400 | Feed Format must be in the format of |
1102 | 400 | Wrong number of primary selectors |
1103 | 400 | Wrong number of secondary selectors |
3000 | 400 | Instrument is invalid |
3020 | 400 | Sub account ID must be an uint64 integer |
All Websocket JSON RPC Responses are housed in this wrapper. It returns a confirmation of the JSON RPC subscribe request.
If a request_id
is supplied in the JSON RPC request, it will be propagated back in this JSON RPC response.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
jsonrpcj |
string | True | The JSON RPC version to use for the request |
resultr |
object | Falsenull |
The result for the request |
errore |
Error | Falsenull |
The error for the request |
idi |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
methodm |
string | True | The method used in the request for this response (eg: subscribe / unsubscribe / v1/instrument ) |
Error
An error response
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
codec |
integer | True | The error code for the request |
messagem |
string | True | The error message for the request |
Error
Full Error Response
{
"jsonrpc": "2.0",
"error": {
"code": 1000,
"message": "You need to authenticate prior to using this functionality"
},
"id": 123,
"method": "subscribe"
}
{
"j": "2.0",
"e": {
"c": 1000,
"m": "You need to authenticate prior to using this functionality"
},
"i": 123,
"m": "subscribe"
}
{
"code":1000,
"message":"You need to authenticate prior to using this functionality",
"status":401
}
Authentication
In order to authenticate, you must first provision a valid API key. API keys can be provisioned via the GRVT UI.
# These are the variables you will need to set manually
GRVT_API_KEY="<insert_key_here>"
GRVT_SUB_ACCOUNT_ID="<insert_sub_account_id_here>"
Then, choose the environment you want to authenticate against.
# dev
GRVT_AUTH_ENDPOINT="https://edge.dev.gravitymarkets.io/auth/api_key/login"
# staging
GRVT_AUTH_ENDPOINT="https://edge.staging.gravitymarkets.io/auth/api_key/login"
# testnet
GRVT_AUTH_ENDPOINT="https://edge.testnet.grvt.io/auth/api_key/login"
# prod
GRVT_AUTH_ENDPOINT="https://edge.grvt.io/auth/api_key/login"
Now, let’s authenticate and retrieve both the session cookie and the X-Grvt-Account-Id
header value that you’ll need to access any endpoints requiring authentication.
echo $GRVT_API_KEY
echo $GRVT_SUB_ACCOUNT_ID
echo $GRVT_AUTH_ENDPOINT
RESPONSE=$(
curl $GRVT_AUTH_ENDPOINT \
-H 'Content-Type: application/json' \
-H 'Cookie: rm=true;' \
-d '{"api_key": "'$GRVT_API_KEY'"}' \
-s -i
)
GRVT_COOKIE=$(echo "$RESPONSE" | grep -i 'set-cookie:' | grep -o 'gravity=[^;]*')
GRVT_ACCOUNT_ID=$(echo "$RESPONSE" | grep 'x-grvt-account-id:' | awk '{print $2}' | tr -d '\r')
echo "$GRVT_COOKIE"
echo "$GRVT_ACCOUNT_ID"
Subscribe Full
wscat -c "wss://trades.dev.gravitymarkets.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.cancel",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'"]
},
"id": 123
}
' -w 360
Unsubscribe Full
wscat -c "wss://trades.dev.gravitymarkets.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.cancel",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'"]
},
"id": 123
}
' -w 360
Legacy Subscribe Full
wscat -c "wss://trades.dev.gravitymarkets.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.cancel",
"feed":["'$GRVT_SUB_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":true
}
' -w 360
Subscribe Lite
wscat -c "wss://trades.dev.gravitymarkets.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "subscribe",
"p": {
"s": "v1.cancel",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'"]
},
"i": 123
}
' -w 360
Unsubscribe Lite
wscat -c "wss://trades.dev.gravitymarkets.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "unsubscribe",
"p": {
"s": "v1.cancel",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'"]
},
"i": 123
}
' -w 360
Legacy Subscribe Lite
wscat -c "wss://trades.dev.gravitymarkets.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.cancel",
"feed":["'$GRVT_SUB_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":false
}
' -w 360
Subscribe Full
wscat -c "wss://trades.staging.gravitymarkets.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.cancel",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'"]
},
"id": 123
}
' -w 360
Unsubscribe Full
wscat -c "wss://trades.staging.gravitymarkets.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.cancel",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'"]
},
"id": 123
}
' -w 360
Legacy Subscribe Full
wscat -c "wss://trades.staging.gravitymarkets.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.cancel",
"feed":["'$GRVT_SUB_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":true
}
' -w 360
Subscribe Lite
wscat -c "wss://trades.staging.gravitymarkets.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "subscribe",
"p": {
"s": "v1.cancel",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'"]
},
"i": 123
}
' -w 360
Unsubscribe Lite
wscat -c "wss://trades.staging.gravitymarkets.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "unsubscribe",
"p": {
"s": "v1.cancel",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'"]
},
"i": 123
}
' -w 360
Legacy Subscribe Lite
wscat -c "wss://trades.staging.gravitymarkets.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.cancel",
"feed":["'$GRVT_SUB_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":false
}
' -w 360
Subscribe Full
wscat -c "wss://trades.testnet.grvt.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.cancel",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'"]
},
"id": 123
}
' -w 360
Unsubscribe Full
wscat -c "wss://trades.testnet.grvt.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.cancel",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'"]
},
"id": 123
}
' -w 360
Legacy Subscribe Full
wscat -c "wss://trades.testnet.grvt.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.cancel",
"feed":["'$GRVT_SUB_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":true
}
' -w 360
Subscribe Lite
wscat -c "wss://trades.testnet.grvt.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "subscribe",
"p": {
"s": "v1.cancel",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'"]
},
"i": 123
}
' -w 360
Unsubscribe Lite
wscat -c "wss://trades.testnet.grvt.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "unsubscribe",
"p": {
"s": "v1.cancel",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'"]
},
"i": 123
}
' -w 360
Legacy Subscribe Lite
wscat -c "wss://trades.testnet.grvt.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.cancel",
"feed":["'$GRVT_SUB_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":false
}
' -w 360
Subscribe Full
wscat -c "wss://trades.grvt.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.cancel",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'"]
},
"id": 123
}
' -w 360
Unsubscribe Full
wscat -c "wss://trades.grvt.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.cancel",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'"]
},
"id": 123
}
' -w 360
Legacy Subscribe Full
wscat -c "wss://trades.grvt.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.cancel",
"feed":["'$GRVT_SUB_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":true
}
' -w 360
Subscribe Lite
wscat -c "wss://trades.grvt.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "subscribe",
"p": {
"s": "v1.cancel",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'"]
},
"i": 123
}
' -w 360
Unsubscribe Lite
wscat -c "wss://trades.grvt.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "unsubscribe",
"p": {
"s": "v1.cancel",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'"]
},
"i": 123
}
' -w 360
Legacy Subscribe Lite
wscat -c "wss://trades.grvt.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.cancel",
"feed":["'$GRVT_SUB_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":false
}
' -w 360
Execution
Fill
STREAM: v1.fill
Subscribes to a feed of private trade updates. This happens when a trade is executed.
To subscribe to all private trades, specify an empty instrument
(eg. 2345123
).
Otherwise, specify the instrument
to only receive private trades for that instrument (eg. 2345123-BTC_USDT_Perp
).
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
sub_account_idsa |
string | True | The sub account ID to request for |
instrumenti |
string | False'all' |
The instrument filter to apply. |
JSONRPC Wrappers
All Websocket JSON RPC Requests are housed in this wrapper. You may specify a stream, and a list of feeds to subscribe to.
If a request_id
is supplied in this JSON RPC request, it will be propagated back to any relevant JSON RPC responses (including error).
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See Overview
page for more details.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
jsonrpcj |
string | True | The JSON RPC version to use for the request |
methodm |
string | True | The method to use for the request (eg: subscribe / unsubscribe / v1/instrument ) |
paramsp |
object | True | The parameters for the request |
idi |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
All Websocket JSON RPC Responses are housed in this wrapper. It returns a confirmation of the JSON RPC subscribe request.
If a request_id
is supplied in the JSON RPC request, it will be propagated back in this JSON RPC response.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
jsonrpcj |
string | True | The JSON RPC version to use for the request |
resultr |
object | Falsenull |
The result for the request |
errore |
Error | Falsenull |
The error for the request |
idi |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
methodm |
string | True | The method used in the request for this response (eg: subscribe / unsubscribe / v1/instrument ) |
Error
An error response
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
codec |
integer | True | The error code for the request |
messagem |
string | True | The error message for the request |
All V1 Websocket Subscription Requests are housed in this wrapper. You may specify a stream and a list of feeds to subscribe to.
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See Overview
page for more details.
Sequence numbers can be either gateway-specific or global:
- Gateway Unique Sequence Number: Increments by one per stream, resets to 0 on gateway restart.
- Global Unique Sequence Number: A cluster-wide unique number assigned to each cluster payload, does not reset on gateway restarts, and can be used to track and identify message order across streams using sequence_number
and prev_sequence_number
in the feed response.
Set useGlobalSequenceNumber = true
if you need a persistent, unique identifier across all streams or ordering across multiple feeds.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
selectorss1 |
[string] | True | The list of feeds to subscribe to |
To ensure you always know if you have missed any payloads, GRVT servers apply the following heuristics to sequence numbers:
- All snapshot payloads will have a sequence number of
0
. All delta payloads will have a sequence number of1+
. So its easy to distinguish between snapshots, and deltas - Num snapshots returned in Response (per stream): You can ensure that you received the right number of snapshots
- First sequence number returned in Response (per stream): You can ensure that you received the first stream, without gaps from snapshots
- Sequence numbers should always monotonically increase by
1
. If it decreases, or increases by more than1
. Please reconnect - Duplicate sequence numbers are possible due to network retries. If you receive a duplicate, please ignore it, or idempotently re-update it.
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See
Overview
page for more details.NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
subss1 |
[string] | True | The list of feeds subscribed to |
unsubsu |
[string] | True | The list of feeds unsubscribed from |
num_snapshotsns |
[integer] | True | The number of snapshot payloads to expect for each subscribed feed. Returned in same order as subs |
first_sequence_numberfs |
[string] | True | The first sequence number to expect for each subscribed feed. Returned in same order as subs |
All V1 Websocket Unsubscription Requests are housed in this wrapper. You may specify a stream, a list of feeds and whether those feeds use global sequence numbers to unsubscribe from.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The channel to unsubscribe from (eg: ticker.s / ticker.d) |
selectorss1 |
[string] | True | The list of feeds to unsubscribe from |
Returns a confirmation of all unsubscribes
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
unsubsu |
[string] | True | The list of feeds unsubscribed from |
All V1 Websocket Requests are housed in this wrapper. You may specify a stream, and a list of feeds to subscribe to.
If a request_id
is supplied in this JSON RPC request, it will be propagated back to any relevant JSON RPC responses (including error).
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See Overview
page for more details.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
request_idri |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
feedf |
[string] | True | The list of feeds to subscribe to |
methodm |
string | True | The method to use for the request (eg: subscribe / unsubscribe) |
is_fullif |
boolean | Falsefalse |
Whether the request is for full data or lite data |
All V1 Websocket Responses are housed in this wrapper. It returns a confirmation of the JSON RPC subscribe request.
If a request_id
is supplied in the JSON RPC request, it will be propagated back in this JSON RPC response.
To ensure you always know if you have missed any payloads, GRVT servers apply the following heuristics to sequence numbers:
- All snapshot payloads will have a sequence number of
0
. All delta payloads will have a sequence number of1+
. So its easy to distinguish between snapshots, and deltas - Num snapshots returned in Response (per stream): You can ensure that you received the right number of snapshots
- First sequence number returned in Response (per stream): You can ensure that you received the first stream, without gaps from snapshots
- Sequence numbers should always monotonically increase by
1
. If it decreases, or increases by more than1
. Please reconnect - Duplicate sequence numbers are possible due to network retries. If you receive a duplicate, please ignore it, or idempotently re-update it.
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See
Overview
page for more details.NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
request_idri |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
subss1 |
[string] | True | The list of feeds subscribed to |
unsubsu |
[string] | True | The list of feeds unsubscribed from |
num_snapshotsns |
[integer] | True | The number of snapshot payloads to expect for each subscribed feed. Returned in same order as subs |
first_sequence_numberfs |
[string] | True | The first sequence number to expect for each subscribed feed. Returned in same order as subs |
Subscribe
Full Subscribe Request
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.fill",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
{
"jsonrpc": "2.0",
"result": {
"stream": "v1.fill",
"subs": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"unsubs": [],
"num_snapshots": [10],
"first_sequence_number": [872634876]
},
"id": 123,
"method": "subscribe"
}
Unsubscribe
Full Unsubscribe Request
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.fill",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
{
"jsonrpc": "2.0",
"result": {
"stream": "v1.fill",
"unsubs": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123,
"method": "subscribe"
}
Legacy Subscribe
Full Subscribe Request
{
"request_id":1,
"stream":"v1.fill",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":true
}
{
"request_id":1,
"stream":"v1.fill",
"subs":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"unsubs":[],
"num_snapshots":[1],
"first_sequence_number":[2813]
}
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The websocket channel to which the response is sent |
selectors1 |
string | True | Primary selector |
sequence_numbersn |
string | True | A sequence number used to determine message order within a stream. - If useGlobalSequenceNumber is false, this returns the gateway sequence number, which increments by one locally within each stream and resets on gateway restarts.- If useGlobalSequenceNumber is true, this returns the global sequence number, which uniquely identifies messages across the cluster.- A single cluster payload can be multiplexed into multiple stream payloads. - To distinguish each stream payload, a dedupCounter is included.- The returned sequence number is computed as: cluster_sequence_number * 10^5 + dedupCounter . |
feedf |
Fill | True | A private trade matching the request filter |
Fill
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
event_timeet |
string | True | Time at which the event was emitted in unix nanoseconds |
sub_account_idsa |
string | True | The sub account ID that participated in the trade |
instrumenti |
string | True | The instrument being represented |
is_buyerib |
boolean | True | The side that the subaccount took on the trade |
is_takerit |
boolean | True | The role that the subaccount took on the trade |
sizes |
string | True | The number of assets being traded, expressed in base asset decimal units |
pricep |
string | True | The traded price, expressed in 9 decimals |
mark_pricemp |
string | True | The mark price of the instrument at point of trade, expressed in 9 decimals |
index_priceip |
string | True | The index price of the instrument at point of trade, expressed in 9 decimals |
interest_rateir |
string | True | The interest rate of the underlying at point of trade, expressed in centibeeps (1/100th of a basis point) |
forward_pricefp |
string | True | [Options] The forward price of the option at point of trade, expressed in 9 decimals |
realized_pnlrp |
string | True | The realized PnL of the trade, expressed in quote asset decimal units (0 if increasing position size) |
feef |
string | True | The fees paid on the trade, expressed in quote asset decimal unit (negative if maker rebate applied) |
fee_ratefr |
string | True | The fee rate paid on the trade |
trade_idti |
string | True | A trade identifier, globally unique, and monotonically increasing (not by 1 ).All trades sharing a single taker execution share the same first component (before - ), and event_time .trade_id is guaranteed to be consistent across MarketData Trade and Trading Fill . |
order_idoi |
string | True | An order identifier |
venuev |
Venue | True | The venue where the trade occurred |
client_order_idco |
string | True | A unique identifier for the active order within a subaccount, specified by the client This is used to identify the order in the client's system This field can be used for order amendment/cancellation, but has no bearing on the smart contract layer This field will not be propagated to the smart contract, and should not be signed by the client This value must be unique for all active orders in a subaccount, or amendment/cancellation will not work as expected Gravity UI will generate a random clientOrderID for each order in the range [0, 2^63 - 1] To prevent any conflicts, client machines should generate a random clientOrderID in the range [2^63, 2^64 - 1] When GRVT Backend receives an order with an overlapping clientOrderID, we will reject the order with rejectReason set to overlappingClientOrderId |
signers1 |
string | True | The address (public key) of the wallet signing the payload |
brokerb |
BrokerTag | False `` |
Specifies the broker who brokered the order |
is_rpiir1 |
boolean | True | If the trade is a RPI trade |
Venue
The list of Trading Venues that are supported on the GRVT exchange
Value | Description |
---|---|
ORDERBOOK = 1 |
the trade is cleared on the orderbook venue |
RFQ = 2 |
the trade is cleared on the RFQ venue |
BrokerTag
BrokerTag is a tag for the broker that the order is sent from.
Value | Description |
---|---|
UNSPECIFIED = 0 |
|
COIN_ROUTES = 1 |
CoinRoutes |
ALERTATRON = 2 |
Alertatron |
ORIGAMI = 3 |
Origami |
Success
Full Feed Response
{
"stream": "v1.fill",
"selector": "BTC_USDT_Perp",
"sequence_number": "872634876",
"feed": {
"event_time": "1697788800000000000",
"sub_account_id": "'$GRVT_SUB_ACCOUNT_ID'",
"instrument": "BTC_USDT_Perp",
"is_buyer": true,
"is_taker": true,
"size": "0.30",
"price": "65038.01",
"mark_price": "65038.01",
"index_price": "65038.01",
"interest_rate": 0.0003,
"forward_price": "65038.01",
"realized_pnl": "2400.50",
"fee": "9.75",
"fee_rate": 0.0003,
"trade_id": "209358-2",
"order_id": "0x10000101000203040506",
"venue": "ORDERBOOK",
"client_order_id": "23042",
"signer": "0xc73c0c2538fd9b833d20933ccc88fdaa74fcb0d0",
"broker": "UNSPECIFIED",
"is_rpi": false
}
}
{
"s": "v1.fill",
"s1": "BTC_USDT_Perp",
"sn": "872634876",
"f": {
"et": "1697788800000000000",
"sa": "'$GRVT_SUB_ACCOUNT_ID'",
"i": "BTC_USDT_Perp",
"ib": true,
"it": true,
"s": "0.30",
"p": "65038.01",
"mp": "65038.01",
"ip": "65038.01",
"ir": 0.0003,
"fp": "65038.01",
"rp": "2400.50",
"f": "9.75",
"fr": 0.0003,
"ti": "209358-2",
"oi": "0x10000101000203040506",
"v": "ORDERBOOK",
"co": "23042",
"s1": "0xc73c0c2538fd9b833d20933ccc88fdaa74fcb0d0",
"b": "UNSPECIFIED",
"ir1": false
}
}
Error Codes
Code | HttpStatus | Description |
---|---|---|
1000 | 401 | You need to authenticate prior to using this functionality |
1001 | 403 | You are not authorized to access this functionality |
1002 | 500 | Internal Server Error |
1008 | 401 | Your IP has not been whitelisted for access |
1101 | 400 | Feed Format must be in the format of |
1102 | 400 | Wrong number of primary selectors |
1103 | 400 | Wrong number of secondary selectors |
3000 | 400 | Instrument is invalid |
3020 | 400 | Sub account ID must be an uint64 integer |
All Websocket JSON RPC Responses are housed in this wrapper. It returns a confirmation of the JSON RPC subscribe request.
If a request_id
is supplied in the JSON RPC request, it will be propagated back in this JSON RPC response.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
jsonrpcj |
string | True | The JSON RPC version to use for the request |
resultr |
object | Falsenull |
The result for the request |
errore |
Error | Falsenull |
The error for the request |
idi |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
methodm |
string | True | The method used in the request for this response (eg: subscribe / unsubscribe / v1/instrument ) |
Error
An error response
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
codec |
integer | True | The error code for the request |
messagem |
string | True | The error message for the request |
Error
Full Error Response
{
"jsonrpc": "2.0",
"error": {
"code": 1000,
"message": "You need to authenticate prior to using this functionality"
},
"id": 123,
"method": "subscribe"
}
{
"j": "2.0",
"e": {
"c": 1000,
"m": "You need to authenticate prior to using this functionality"
},
"i": 123,
"m": "subscribe"
}
{
"code":1000,
"message":"You need to authenticate prior to using this functionality",
"status":401
}
Authentication
In order to authenticate, you must first provision a valid API key. API keys can be provisioned via the GRVT UI.
# These are the variables you will need to set manually
GRVT_API_KEY="<insert_key_here>"
GRVT_SUB_ACCOUNT_ID="<insert_sub_account_id_here>"
Then, choose the environment you want to authenticate against.
# dev
GRVT_AUTH_ENDPOINT="https://edge.dev.gravitymarkets.io/auth/api_key/login"
# staging
GRVT_AUTH_ENDPOINT="https://edge.staging.gravitymarkets.io/auth/api_key/login"
# testnet
GRVT_AUTH_ENDPOINT="https://edge.testnet.grvt.io/auth/api_key/login"
# prod
GRVT_AUTH_ENDPOINT="https://edge.grvt.io/auth/api_key/login"
Now, let’s authenticate and retrieve both the session cookie and the X-Grvt-Account-Id
header value that you’ll need to access any endpoints requiring authentication.
echo $GRVT_API_KEY
echo $GRVT_SUB_ACCOUNT_ID
echo $GRVT_AUTH_ENDPOINT
RESPONSE=$(
curl $GRVT_AUTH_ENDPOINT \
-H 'Content-Type: application/json' \
-H 'Cookie: rm=true;' \
-d '{"api_key": "'$GRVT_API_KEY'"}' \
-s -i
)
GRVT_COOKIE=$(echo "$RESPONSE" | grep -i 'set-cookie:' | grep -o 'gravity=[^;]*')
GRVT_ACCOUNT_ID=$(echo "$RESPONSE" | grep 'x-grvt-account-id:' | awk '{print $2}' | tr -d '\r')
echo "$GRVT_COOKIE"
echo "$GRVT_ACCOUNT_ID"
Subscribe Full
wscat -c "wss://trades.dev.gravitymarkets.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.fill",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
' -w 360
Unsubscribe Full
wscat -c "wss://trades.dev.gravitymarkets.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.fill",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
' -w 360
Legacy Subscribe Full
wscat -c "wss://trades.dev.gravitymarkets.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.fill",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":true
}
' -w 360
Subscribe Lite
wscat -c "wss://trades.dev.gravitymarkets.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "subscribe",
"p": {
"s": "v1.fill",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"i": 123
}
' -w 360
Unsubscribe Lite
wscat -c "wss://trades.dev.gravitymarkets.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "unsubscribe",
"p": {
"s": "v1.fill",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"i": 123
}
' -w 360
Legacy Subscribe Lite
wscat -c "wss://trades.dev.gravitymarkets.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.fill",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":false
}
' -w 360
Subscribe Full
wscat -c "wss://trades.staging.gravitymarkets.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.fill",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
' -w 360
Unsubscribe Full
wscat -c "wss://trades.staging.gravitymarkets.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.fill",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
' -w 360
Legacy Subscribe Full
wscat -c "wss://trades.staging.gravitymarkets.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.fill",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":true
}
' -w 360
Subscribe Lite
wscat -c "wss://trades.staging.gravitymarkets.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "subscribe",
"p": {
"s": "v1.fill",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"i": 123
}
' -w 360
Unsubscribe Lite
wscat -c "wss://trades.staging.gravitymarkets.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "unsubscribe",
"p": {
"s": "v1.fill",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"i": 123
}
' -w 360
Legacy Subscribe Lite
wscat -c "wss://trades.staging.gravitymarkets.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.fill",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":false
}
' -w 360
Subscribe Full
wscat -c "wss://trades.testnet.grvt.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.fill",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
' -w 360
Unsubscribe Full
wscat -c "wss://trades.testnet.grvt.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.fill",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
' -w 360
Legacy Subscribe Full
wscat -c "wss://trades.testnet.grvt.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.fill",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":true
}
' -w 360
Subscribe Lite
wscat -c "wss://trades.testnet.grvt.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "subscribe",
"p": {
"s": "v1.fill",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"i": 123
}
' -w 360
Unsubscribe Lite
wscat -c "wss://trades.testnet.grvt.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "unsubscribe",
"p": {
"s": "v1.fill",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"i": 123
}
' -w 360
Legacy Subscribe Lite
wscat -c "wss://trades.testnet.grvt.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.fill",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":false
}
' -w 360
Subscribe Full
wscat -c "wss://trades.grvt.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.fill",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
' -w 360
Unsubscribe Full
wscat -c "wss://trades.grvt.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.fill",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
' -w 360
Legacy Subscribe Full
wscat -c "wss://trades.grvt.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.fill",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":true
}
' -w 360
Subscribe Lite
wscat -c "wss://trades.grvt.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "subscribe",
"p": {
"s": "v1.fill",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"i": 123
}
' -w 360
Unsubscribe Lite
wscat -c "wss://trades.grvt.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "unsubscribe",
"p": {
"s": "v1.fill",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"i": 123
}
' -w 360
Legacy Subscribe Lite
wscat -c "wss://trades.grvt.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.fill",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":false
}
' -w 360
Positions
STREAM: v1.position
Subscribes to a feed of position updates.
Updates get published when a trade is executed, and when leverage configurations are changed for instruments with ongoing positions.
To subscribe to all positions, specify an empty instrument
(eg. 2345123
).
Otherwise, specify the instrument
to only receive positions for that instrument (eg. 2345123-BTC_USDT_Perp
).
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
sub_account_idsa |
string | True | The subaccount ID to filter by |
instrumenti |
string | False'all' |
The instrument filter to apply. |
JSONRPC Wrappers
All Websocket JSON RPC Requests are housed in this wrapper. You may specify a stream, and a list of feeds to subscribe to.
If a request_id
is supplied in this JSON RPC request, it will be propagated back to any relevant JSON RPC responses (including error).
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See Overview
page for more details.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
jsonrpcj |
string | True | The JSON RPC version to use for the request |
methodm |
string | True | The method to use for the request (eg: subscribe / unsubscribe / v1/instrument ) |
paramsp |
object | True | The parameters for the request |
idi |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
All Websocket JSON RPC Responses are housed in this wrapper. It returns a confirmation of the JSON RPC subscribe request.
If a request_id
is supplied in the JSON RPC request, it will be propagated back in this JSON RPC response.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
jsonrpcj |
string | True | The JSON RPC version to use for the request |
resultr |
object | Falsenull |
The result for the request |
errore |
Error | Falsenull |
The error for the request |
idi |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
methodm |
string | True | The method used in the request for this response (eg: subscribe / unsubscribe / v1/instrument ) |
Error
An error response
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
codec |
integer | True | The error code for the request |
messagem |
string | True | The error message for the request |
All V1 Websocket Subscription Requests are housed in this wrapper. You may specify a stream and a list of feeds to subscribe to.
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See Overview
page for more details.
Sequence numbers can be either gateway-specific or global:
- Gateway Unique Sequence Number: Increments by one per stream, resets to 0 on gateway restart.
- Global Unique Sequence Number: A cluster-wide unique number assigned to each cluster payload, does not reset on gateway restarts, and can be used to track and identify message order across streams using sequence_number
and prev_sequence_number
in the feed response.
Set useGlobalSequenceNumber = true
if you need a persistent, unique identifier across all streams or ordering across multiple feeds.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
selectorss1 |
[string] | True | The list of feeds to subscribe to |
To ensure you always know if you have missed any payloads, GRVT servers apply the following heuristics to sequence numbers:
- All snapshot payloads will have a sequence number of
0
. All delta payloads will have a sequence number of1+
. So its easy to distinguish between snapshots, and deltas - Num snapshots returned in Response (per stream): You can ensure that you received the right number of snapshots
- First sequence number returned in Response (per stream): You can ensure that you received the first stream, without gaps from snapshots
- Sequence numbers should always monotonically increase by
1
. If it decreases, or increases by more than1
. Please reconnect - Duplicate sequence numbers are possible due to network retries. If you receive a duplicate, please ignore it, or idempotently re-update it.
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See
Overview
page for more details.NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
subss1 |
[string] | True | The list of feeds subscribed to |
unsubsu |
[string] | True | The list of feeds unsubscribed from |
num_snapshotsns |
[integer] | True | The number of snapshot payloads to expect for each subscribed feed. Returned in same order as subs |
first_sequence_numberfs |
[string] | True | The first sequence number to expect for each subscribed feed. Returned in same order as subs |
All V1 Websocket Unsubscription Requests are housed in this wrapper. You may specify a stream, a list of feeds and whether those feeds use global sequence numbers to unsubscribe from.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The channel to unsubscribe from (eg: ticker.s / ticker.d) |
selectorss1 |
[string] | True | The list of feeds to unsubscribe from |
Returns a confirmation of all unsubscribes
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
unsubsu |
[string] | True | The list of feeds unsubscribed from |
All V1 Websocket Requests are housed in this wrapper. You may specify a stream, and a list of feeds to subscribe to.
If a request_id
is supplied in this JSON RPC request, it will be propagated back to any relevant JSON RPC responses (including error).
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See Overview
page for more details.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
request_idri |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
feedf |
[string] | True | The list of feeds to subscribe to |
methodm |
string | True | The method to use for the request (eg: subscribe / unsubscribe) |
is_fullif |
boolean | Falsefalse |
Whether the request is for full data or lite data |
All V1 Websocket Responses are housed in this wrapper. It returns a confirmation of the JSON RPC subscribe request.
If a request_id
is supplied in the JSON RPC request, it will be propagated back in this JSON RPC response.
To ensure you always know if you have missed any payloads, GRVT servers apply the following heuristics to sequence numbers:
- All snapshot payloads will have a sequence number of
0
. All delta payloads will have a sequence number of1+
. So its easy to distinguish between snapshots, and deltas - Num snapshots returned in Response (per stream): You can ensure that you received the right number of snapshots
- First sequence number returned in Response (per stream): You can ensure that you received the first stream, without gaps from snapshots
- Sequence numbers should always monotonically increase by
1
. If it decreases, or increases by more than1
. Please reconnect - Duplicate sequence numbers are possible due to network retries. If you receive a duplicate, please ignore it, or idempotently re-update it.
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See
Overview
page for more details.NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
request_idri |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
subss1 |
[string] | True | The list of feeds subscribed to |
unsubsu |
[string] | True | The list of feeds unsubscribed from |
num_snapshotsns |
[integer] | True | The number of snapshot payloads to expect for each subscribed feed. Returned in same order as subs |
first_sequence_numberfs |
[string] | True | The first sequence number to expect for each subscribed feed. Returned in same order as subs |
Subscribe
Full Subscribe Request
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.position",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
{
"jsonrpc": "2.0",
"result": {
"stream": "v1.position",
"subs": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"unsubs": [],
"num_snapshots": [10],
"first_sequence_number": [872634876]
},
"id": 123,
"method": "subscribe"
}
Unsubscribe
Full Unsubscribe Request
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.position",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
{
"jsonrpc": "2.0",
"result": {
"stream": "v1.position",
"unsubs": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123,
"method": "subscribe"
}
Legacy Subscribe
Full Subscribe Request
{
"request_id":1,
"stream":"v1.position",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":true
}
{
"request_id":1,
"stream":"v1.position",
"subs":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"unsubs":[],
"num_snapshots":[1],
"first_sequence_number":[2813]
}
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | Stream name |
selectors1 |
string | True | Primary selector |
sequence_numbersn |
string | True | A sequence number used to determine message order within a stream. - If useGlobalSequenceNumber is false, this returns the gateway sequence number, which increments by one locally within each stream and resets on gateway restarts.- If useGlobalSequenceNumber is true, this returns the global sequence number, which uniquely identifies messages across the cluster.- A single cluster payload can be multiplexed into multiple stream payloads. - To distinguish each stream payload, a dedupCounter is included.- The returned sequence number is computed as: cluster_sequence_number * 10^5 + dedupCounter . |
feedf |
Positions | True | A Position being created or updated matching the request filter |
Positions
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
event_timeet |
string | True | Time at which the event was emitted in unix nanoseconds |
sub_account_idsa |
string | True | The sub account ID that participated in the trade |
instrumenti |
string | True | The instrument being represented |
sizes |
string | True | The size of the position, expressed in base asset decimal units. Negative for short positions |
notionaln |
string | True | The notional value of the position, negative for short assets, expressed in quote asset decimal units |
entry_priceep |
string | True | The entry price of the position, expressed in 9 decimalsWhenever increasing the size of a position, the entry price is updated to the new average entry price new_entry_price = (old_entry_price * old_size + trade_price * trade_size) / (old_size + trade_size) |
exit_priceep1 |
string | True | The exit price of the position, expressed in 9 decimalsWhenever decreasing the size of a position, the exit price is updated to the new average exit price new_exit_price = (old_exit_price * old_exit_trade_size + trade_price * trade_size) / (old_exit_trade_size + trade_size) |
mark_pricemp |
string | True | The mark price of the position, expressed in 9 decimals |
unrealized_pnlup |
string | True | The unrealized PnL of the position, expressed in quote asset decimal unitsunrealized_pnl = (mark_price - entry_price) * size |
realized_pnlrp |
string | True | The realized PnL of the position, expressed in quote asset decimal unitsrealized_pnl = (exit_price - entry_price) * exit_trade_size |
total_pnltp |
string | True | The total PnL of the position, expressed in quote asset decimal unitstotal_pnl = realized_pnl + unrealized_pnl |
roir |
string | True | The ROI of the position, expressed as a percentageroi = (total_pnl / (entry_price * abs(size))) * 100^ |
quote_index_priceqi |
string | True | The index price of the quote currency. (reported in USD ) |
est_liquidation_priceel |
string | True | The estimated liquidation price |
leveragel |
string | True | The current leverage value for this position |
Success
Full Feed Response
{
"stream": "v1.position",
"selector": "BTC_USDT_Perp",
"sequence_number": "872634876",
"feed": {
"event_time": "1697788800000000000",
"sub_account_id": "'$GRVT_SUB_ACCOUNT_ID'",
"instrument": "BTC_USDT_Perp",
"size": "2635000.50",
"notional": "2635000.50",
"entry_price": "65038.01",
"exit_price": "65038.01",
"mark_price": "65038.01",
"unrealized_pnl": "135000.50",
"realized_pnl": "-35000.30",
"total_pnl": "100000.20",
"roi": "10.20",
"quote_index_price": "1.0000102",
"est_liquidation_price": 60000.25,
"leverage": "10"
}
}
{
"s": "v1.position",
"s1": "BTC_USDT_Perp",
"sn": "872634876",
"f": {
"et": "1697788800000000000",
"sa": "'$GRVT_SUB_ACCOUNT_ID'",
"i": "BTC_USDT_Perp",
"s": "2635000.50",
"n": "2635000.50",
"ep": "65038.01",
"ep1": "65038.01",
"mp": "65038.01",
"up": "135000.50",
"rp": "-35000.30",
"tp": "100000.20",
"r": "10.20",
"qi": "1.0000102",
"el": 60000.25,
"l": "10"
}
}
Error Codes
Code | HttpStatus | Description |
---|---|---|
1000 | 401 | You need to authenticate prior to using this functionality |
1001 | 403 | You are not authorized to access this functionality |
1002 | 500 | Internal Server Error |
1008 | 401 | Your IP has not been whitelisted for access |
1101 | 400 | Feed Format must be in the format of |
1102 | 400 | Wrong number of primary selectors |
1103 | 400 | Wrong number of secondary selectors |
3000 | 400 | Instrument is invalid |
3020 | 400 | Sub account ID must be an uint64 integer |
All Websocket JSON RPC Responses are housed in this wrapper. It returns a confirmation of the JSON RPC subscribe request.
If a request_id
is supplied in the JSON RPC request, it will be propagated back in this JSON RPC response.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
jsonrpcj |
string | True | The JSON RPC version to use for the request |
resultr |
object | Falsenull |
The result for the request |
errore |
Error | Falsenull |
The error for the request |
idi |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
methodm |
string | True | The method used in the request for this response (eg: subscribe / unsubscribe / v1/instrument ) |
Error
An error response
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
codec |
integer | True | The error code for the request |
messagem |
string | True | The error message for the request |
Error
Full Error Response
{
"jsonrpc": "2.0",
"error": {
"code": 1000,
"message": "You need to authenticate prior to using this functionality"
},
"id": 123,
"method": "subscribe"
}
{
"j": "2.0",
"e": {
"c": 1000,
"m": "You need to authenticate prior to using this functionality"
},
"i": 123,
"m": "subscribe"
}
{
"code":1000,
"message":"You need to authenticate prior to using this functionality",
"status":401
}
Authentication
In order to authenticate, you must first provision a valid API key. API keys can be provisioned via the GRVT UI.
# These are the variables you will need to set manually
GRVT_API_KEY="<insert_key_here>"
GRVT_SUB_ACCOUNT_ID="<insert_sub_account_id_here>"
Then, choose the environment you want to authenticate against.
# dev
GRVT_AUTH_ENDPOINT="https://edge.dev.gravitymarkets.io/auth/api_key/login"
# staging
GRVT_AUTH_ENDPOINT="https://edge.staging.gravitymarkets.io/auth/api_key/login"
# testnet
GRVT_AUTH_ENDPOINT="https://edge.testnet.grvt.io/auth/api_key/login"
# prod
GRVT_AUTH_ENDPOINT="https://edge.grvt.io/auth/api_key/login"
Now, let’s authenticate and retrieve both the session cookie and the X-Grvt-Account-Id
header value that you’ll need to access any endpoints requiring authentication.
echo $GRVT_API_KEY
echo $GRVT_SUB_ACCOUNT_ID
echo $GRVT_AUTH_ENDPOINT
RESPONSE=$(
curl $GRVT_AUTH_ENDPOINT \
-H 'Content-Type: application/json' \
-H 'Cookie: rm=true;' \
-d '{"api_key": "'$GRVT_API_KEY'"}' \
-s -i
)
GRVT_COOKIE=$(echo "$RESPONSE" | grep -i 'set-cookie:' | grep -o 'gravity=[^;]*')
GRVT_ACCOUNT_ID=$(echo "$RESPONSE" | grep 'x-grvt-account-id:' | awk '{print $2}' | tr -d '\r')
echo "$GRVT_COOKIE"
echo "$GRVT_ACCOUNT_ID"
Subscribe Full
wscat -c "wss://trades.dev.gravitymarkets.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.position",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
' -w 360
Unsubscribe Full
wscat -c "wss://trades.dev.gravitymarkets.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.position",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
' -w 360
Legacy Subscribe Full
wscat -c "wss://trades.dev.gravitymarkets.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.position",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":true
}
' -w 360
Subscribe Lite
wscat -c "wss://trades.dev.gravitymarkets.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "subscribe",
"p": {
"s": "v1.position",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"i": 123
}
' -w 360
Unsubscribe Lite
wscat -c "wss://trades.dev.gravitymarkets.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "unsubscribe",
"p": {
"s": "v1.position",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"i": 123
}
' -w 360
Legacy Subscribe Lite
wscat -c "wss://trades.dev.gravitymarkets.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.position",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":false
}
' -w 360
Subscribe Full
wscat -c "wss://trades.staging.gravitymarkets.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.position",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
' -w 360
Unsubscribe Full
wscat -c "wss://trades.staging.gravitymarkets.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.position",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
' -w 360
Legacy Subscribe Full
wscat -c "wss://trades.staging.gravitymarkets.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.position",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":true
}
' -w 360
Subscribe Lite
wscat -c "wss://trades.staging.gravitymarkets.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "subscribe",
"p": {
"s": "v1.position",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"i": 123
}
' -w 360
Unsubscribe Lite
wscat -c "wss://trades.staging.gravitymarkets.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "unsubscribe",
"p": {
"s": "v1.position",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"i": 123
}
' -w 360
Legacy Subscribe Lite
wscat -c "wss://trades.staging.gravitymarkets.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.position",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":false
}
' -w 360
Subscribe Full
wscat -c "wss://trades.testnet.grvt.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.position",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
' -w 360
Unsubscribe Full
wscat -c "wss://trades.testnet.grvt.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.position",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
' -w 360
Legacy Subscribe Full
wscat -c "wss://trades.testnet.grvt.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.position",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":true
}
' -w 360
Subscribe Lite
wscat -c "wss://trades.testnet.grvt.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "subscribe",
"p": {
"s": "v1.position",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"i": 123
}
' -w 360
Unsubscribe Lite
wscat -c "wss://trades.testnet.grvt.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "unsubscribe",
"p": {
"s": "v1.position",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"i": 123
}
' -w 360
Legacy Subscribe Lite
wscat -c "wss://trades.testnet.grvt.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.position",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":false
}
' -w 360
Subscribe Full
wscat -c "wss://trades.grvt.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.position",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
' -w 360
Unsubscribe Full
wscat -c "wss://trades.grvt.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.position",
"selectors": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"id": 123
}
' -w 360
Legacy Subscribe Full
wscat -c "wss://trades.grvt.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.position",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":true
}
' -w 360
Subscribe Lite
wscat -c "wss://trades.grvt.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "subscribe",
"p": {
"s": "v1.position",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"i": 123
}
' -w 360
Unsubscribe Lite
wscat -c "wss://trades.grvt.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "unsubscribe",
"p": {
"s": "v1.position",
"s1": ["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"]
},
"i": 123
}
' -w 360
Legacy Subscribe Lite
wscat -c "wss://trades.grvt.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.position",
"feed":["'$GRVT_SUB_ACCOUNT_ID'-BTC_USDT_Perp"],
"method":"subscribe",
"is_full":false
}
' -w 360
Transfer
Deposit
STREAM: v1.deposit
Subscribes to a feed of deposits. This will execute when there is any deposit to selected account.
To subscribe to a main account, specify the account ID (eg. 0x9fe3758b67ce7a2875ee4b452f01a5282d84ed8a
).
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
main_account_idma |
string | True | The main account ID to request for |
JSONRPC Wrappers
All Websocket JSON RPC Requests are housed in this wrapper. You may specify a stream, and a list of feeds to subscribe to.
If a request_id
is supplied in this JSON RPC request, it will be propagated back to any relevant JSON RPC responses (including error).
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See Overview
page for more details.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
jsonrpcj |
string | True | The JSON RPC version to use for the request |
methodm |
string | True | The method to use for the request (eg: subscribe / unsubscribe / v1/instrument ) |
paramsp |
object | True | The parameters for the request |
idi |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
All Websocket JSON RPC Responses are housed in this wrapper. It returns a confirmation of the JSON RPC subscribe request.
If a request_id
is supplied in the JSON RPC request, it will be propagated back in this JSON RPC response.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
jsonrpcj |
string | True | The JSON RPC version to use for the request |
resultr |
object | Falsenull |
The result for the request |
errore |
Error | Falsenull |
The error for the request |
idi |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
methodm |
string | True | The method used in the request for this response (eg: subscribe / unsubscribe / v1/instrument ) |
Error
An error response
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
codec |
integer | True | The error code for the request |
messagem |
string | True | The error message for the request |
All V1 Websocket Subscription Requests are housed in this wrapper. You may specify a stream and a list of feeds to subscribe to.
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See Overview
page for more details.
Sequence numbers can be either gateway-specific or global:
- Gateway Unique Sequence Number: Increments by one per stream, resets to 0 on gateway restart.
- Global Unique Sequence Number: A cluster-wide unique number assigned to each cluster payload, does not reset on gateway restarts, and can be used to track and identify message order across streams using sequence_number
and prev_sequence_number
in the feed response.
Set useGlobalSequenceNumber = true
if you need a persistent, unique identifier across all streams or ordering across multiple feeds.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
selectorss1 |
[string] | True | The list of feeds to subscribe to |
To ensure you always know if you have missed any payloads, GRVT servers apply the following heuristics to sequence numbers:
- All snapshot payloads will have a sequence number of
0
. All delta payloads will have a sequence number of1+
. So its easy to distinguish between snapshots, and deltas - Num snapshots returned in Response (per stream): You can ensure that you received the right number of snapshots
- First sequence number returned in Response (per stream): You can ensure that you received the first stream, without gaps from snapshots
- Sequence numbers should always monotonically increase by
1
. If it decreases, or increases by more than1
. Please reconnect - Duplicate sequence numbers are possible due to network retries. If you receive a duplicate, please ignore it, or idempotently re-update it.
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See
Overview
page for more details.NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
subss1 |
[string] | True | The list of feeds subscribed to |
unsubsu |
[string] | True | The list of feeds unsubscribed from |
num_snapshotsns |
[integer] | True | The number of snapshot payloads to expect for each subscribed feed. Returned in same order as subs |
first_sequence_numberfs |
[string] | True | The first sequence number to expect for each subscribed feed. Returned in same order as subs |
All V1 Websocket Unsubscription Requests are housed in this wrapper. You may specify a stream, a list of feeds and whether those feeds use global sequence numbers to unsubscribe from.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The channel to unsubscribe from (eg: ticker.s / ticker.d) |
selectorss1 |
[string] | True | The list of feeds to unsubscribe from |
Returns a confirmation of all unsubscribes
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
unsubsu |
[string] | True | The list of feeds unsubscribed from |
All V1 Websocket Requests are housed in this wrapper. You may specify a stream, and a list of feeds to subscribe to.
If a request_id
is supplied in this JSON RPC request, it will be propagated back to any relevant JSON RPC responses (including error).
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See Overview
page for more details.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
request_idri |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
feedf |
[string] | True | The list of feeds to subscribe to |
methodm |
string | True | The method to use for the request (eg: subscribe / unsubscribe) |
is_fullif |
boolean | Falsefalse |
Whether the request is for full data or lite data |
All V1 Websocket Responses are housed in this wrapper. It returns a confirmation of the JSON RPC subscribe request.
If a request_id
is supplied in the JSON RPC request, it will be propagated back in this JSON RPC response.
To ensure you always know if you have missed any payloads, GRVT servers apply the following heuristics to sequence numbers:
- All snapshot payloads will have a sequence number of
0
. All delta payloads will have a sequence number of1+
. So its easy to distinguish between snapshots, and deltas - Num snapshots returned in Response (per stream): You can ensure that you received the right number of snapshots
- First sequence number returned in Response (per stream): You can ensure that you received the first stream, without gaps from snapshots
- Sequence numbers should always monotonically increase by
1
. If it decreases, or increases by more than1
. Please reconnect - Duplicate sequence numbers are possible due to network retries. If you receive a duplicate, please ignore it, or idempotently re-update it.
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See
Overview
page for more details.NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
request_idri |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
subss1 |
[string] | True | The list of feeds subscribed to |
unsubsu |
[string] | True | The list of feeds unsubscribed from |
num_snapshotsns |
[integer] | True | The number of snapshot payloads to expect for each subscribed feed. Returned in same order as subs |
first_sequence_numberfs |
[string] | True | The first sequence number to expect for each subscribed feed. Returned in same order as subs |
Subscribe
Full Subscribe Request
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.deposit",
"selectors": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"id": 123
}
{
"jsonrpc": "2.0",
"result": {
"stream": "v1.deposit",
"subs": ["'$GRVT_MAIN_ACCOUNT_ID'"],
"unsubs": [],
"num_snapshots": [10],
"first_sequence_number": [872634876]
},
"id": 123,
"method": "subscribe"
}
Unsubscribe
Full Unsubscribe Request
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.deposit",
"selectors": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"id": 123
}
{
"jsonrpc": "2.0",
"result": {
"stream": "v1.deposit",
"unsubs": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"id": 123,
"method": "subscribe"
}
Legacy Subscribe
Full Subscribe Request
{
"request_id":1,
"stream":"v1.deposit",
"feed":["'$GRVT_MAIN_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":true
}
{
"request_id":1,
"stream":"v1.deposit",
"subs":["'$GRVT_MAIN_ACCOUNT_ID'"],
"unsubs":[],
"num_snapshots":[1],
"first_sequence_number":[2813]
}
Subscribes to a feed of deposit updates.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The websocket channel to which the response is sent |
selectors1 |
string | True | Primary selector |
sequence_numbersn |
string | True | A sequence number used to determine message order within a stream. - If useGlobalSequenceNumber is false, this returns the gateway sequence number, which increments by one locally within each stream and resets on gateway restarts.- If useGlobalSequenceNumber is true, this returns the global sequence number, which uniquely identifies messages across the cluster.- A single cluster payload can be multiplexed into multiple stream payloads. - To distinguish each stream payload, a dedupCounter is included.- The returned sequence number is computed as: cluster_sequence_number * 10^5 + dedupCounter . |
feedf |
Deposit | True | The Deposit object |
Deposit
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
tx_hashth |
string | True | The hash of the bridgemint event producing the deposit |
to_account_idta |
string | True | The account to deposit into |
currencyc |
Currency | True | The token currency to deposit |
num_tokensnt |
string | True | The number of tokens to deposit |
Currency
The list of Currencies that are supported on the GRVT exchange
Value | Description |
---|---|
USD = 1 |
the USD fiat currency |
USDC = 2 |
the USDC token |
USDT = 3 |
the USDT token |
ETH = 4 |
the ETH token |
BTC = 5 |
the BTC token |
SOL = 6 |
the SOL token |
ARB = 7 |
the ARB token |
BNB = 8 |
the BNB token |
ZK = 9 |
the ZK token |
POL = 10 |
the POL token |
OP = 11 |
the OP token |
ATOM = 12 |
the ATOM token |
KPEPE = 13 |
the 1000PEPE token |
TON = 14 |
the TON token |
XRP = 15 |
the XRP token |
TRUMP = 20 |
the TRUMP token |
SUI = 21 |
the SUI token |
LINK = 25 |
the LINK token |
JUP = 27 |
the JUP token |
FARTCOIN = 28 |
the FARTCOIN token |
ENA = 29 |
the ENA token |
DOGE = 30 |
the DOGE token |
ADA = 33 |
the ADA token |
AAVE = 34 |
the AAVE token |
BERA = 35 |
the BERA token |
IP = 40 |
the IP token |
Success
Full Feed Response
{
"stream": "v1.deposit",
"selector": "BTC_USDT_Perp",
"sequence_number": "872634876",
"feed": {
"tx_hash": "0x1234567890123456789012345678901234567890123456789012345678901234",
"to_account_id": "0xc73c0c2538fd9b833d20933ccc88fdaa74fcb0d0",
"currency": "USDT",
"num_tokens": "10.50"
}
}
{
"s": "v1.deposit",
"s1": "BTC_USDT_Perp",
"sn": "872634876",
"f": {
"th": "0x1234567890123456789012345678901234567890123456789012345678901234",
"ta": "0xc73c0c2538fd9b833d20933ccc88fdaa74fcb0d0",
"c": "USDT",
"nt": "10.50"
}
}
Error Codes
Code | HttpStatus | Description |
---|---|---|
1001 | 403 | You are not authorized to access this functionality |
1008 | 401 | Your IP has not been whitelisted for access |
1101 | 400 | Feed Format must be in the format of |
1102 | 400 | Wrong number of primary selectors |
1103 | 400 | Wrong number of secondary selectors |
All Websocket JSON RPC Responses are housed in this wrapper. It returns a confirmation of the JSON RPC subscribe request.
If a request_id
is supplied in the JSON RPC request, it will be propagated back in this JSON RPC response.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
jsonrpcj |
string | True | The JSON RPC version to use for the request |
resultr |
object | Falsenull |
The result for the request |
errore |
Error | Falsenull |
The error for the request |
idi |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
methodm |
string | True | The method used in the request for this response (eg: subscribe / unsubscribe / v1/instrument ) |
Error
An error response
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
codec |
integer | True | The error code for the request |
messagem |
string | True | The error message for the request |
Error
Full Error Response
{
"jsonrpc": "2.0",
"error": {
"code": 1001,
"message": "You are not authorized to access this functionality"
},
"id": 123,
"method": "subscribe"
}
{
"j": "2.0",
"e": {
"c": 1001,
"m": "You are not authorized to access this functionality"
},
"i": 123,
"m": "subscribe"
}
{
"code":1001,
"message":"You are not authorized to access this functionality",
"status":403
}
Authentication
In order to authenticate, you must first provision a valid API key. API keys can be provisioned via the GRVT UI.
# These are the variables you will need to set manually
GRVT_API_KEY="<insert_key_here>"
GRVT_SUB_ACCOUNT_ID="<insert_sub_account_id_here>"
Then, choose the environment you want to authenticate against.
# dev
GRVT_AUTH_ENDPOINT="https://edge.dev.gravitymarkets.io/auth/api_key/login"
# staging
GRVT_AUTH_ENDPOINT="https://edge.staging.gravitymarkets.io/auth/api_key/login"
# testnet
GRVT_AUTH_ENDPOINT="https://edge.testnet.grvt.io/auth/api_key/login"
# prod
GRVT_AUTH_ENDPOINT="https://edge.grvt.io/auth/api_key/login"
Now, let’s authenticate and retrieve both the session cookie and the X-Grvt-Account-Id
header value that you’ll need to access any endpoints requiring authentication.
echo $GRVT_API_KEY
echo $GRVT_SUB_ACCOUNT_ID
echo $GRVT_AUTH_ENDPOINT
RESPONSE=$(
curl $GRVT_AUTH_ENDPOINT \
-H 'Content-Type: application/json' \
-H 'Cookie: rm=true;' \
-d '{"api_key": "'$GRVT_API_KEY'"}' \
-s -i
)
GRVT_COOKIE=$(echo "$RESPONSE" | grep -i 'set-cookie:' | grep -o 'gravity=[^;]*')
GRVT_ACCOUNT_ID=$(echo "$RESPONSE" | grep 'x-grvt-account-id:' | awk '{print $2}' | tr -d '\r')
echo "$GRVT_COOKIE"
echo "$GRVT_ACCOUNT_ID"
Subscribe Full
wscat -c "wss://trades.dev.gravitymarkets.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.deposit",
"selectors": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"id": 123
}
' -w 360
Unsubscribe Full
wscat -c "wss://trades.dev.gravitymarkets.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.deposit",
"selectors": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"id": 123
}
' -w 360
Legacy Subscribe Full
wscat -c "wss://trades.dev.gravitymarkets.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.deposit",
"feed":["'$GRVT_MAIN_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":true
}
' -w 360
Subscribe Lite
wscat -c "wss://trades.dev.gravitymarkets.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "subscribe",
"p": {
"s": "v1.deposit",
"s1": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"i": 123
}
' -w 360
Unsubscribe Lite
wscat -c "wss://trades.dev.gravitymarkets.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "unsubscribe",
"p": {
"s": "v1.deposit",
"s1": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"i": 123
}
' -w 360
Legacy Subscribe Lite
wscat -c "wss://trades.dev.gravitymarkets.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.deposit",
"feed":["'$GRVT_MAIN_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":false
}
' -w 360
Subscribe Full
wscat -c "wss://trades.staging.gravitymarkets.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.deposit",
"selectors": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"id": 123
}
' -w 360
Unsubscribe Full
wscat -c "wss://trades.staging.gravitymarkets.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.deposit",
"selectors": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"id": 123
}
' -w 360
Legacy Subscribe Full
wscat -c "wss://trades.staging.gravitymarkets.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.deposit",
"feed":["'$GRVT_MAIN_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":true
}
' -w 360
Subscribe Lite
wscat -c "wss://trades.staging.gravitymarkets.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "subscribe",
"p": {
"s": "v1.deposit",
"s1": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"i": 123
}
' -w 360
Unsubscribe Lite
wscat -c "wss://trades.staging.gravitymarkets.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "unsubscribe",
"p": {
"s": "v1.deposit",
"s1": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"i": 123
}
' -w 360
Legacy Subscribe Lite
wscat -c "wss://trades.staging.gravitymarkets.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.deposit",
"feed":["'$GRVT_MAIN_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":false
}
' -w 360
Subscribe Full
wscat -c "wss://trades.testnet.grvt.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.deposit",
"selectors": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"id": 123
}
' -w 360
Unsubscribe Full
wscat -c "wss://trades.testnet.grvt.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.deposit",
"selectors": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"id": 123
}
' -w 360
Legacy Subscribe Full
wscat -c "wss://trades.testnet.grvt.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.deposit",
"feed":["'$GRVT_MAIN_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":true
}
' -w 360
Subscribe Lite
wscat -c "wss://trades.testnet.grvt.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "subscribe",
"p": {
"s": "v1.deposit",
"s1": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"i": 123
}
' -w 360
Unsubscribe Lite
wscat -c "wss://trades.testnet.grvt.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "unsubscribe",
"p": {
"s": "v1.deposit",
"s1": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"i": 123
}
' -w 360
Legacy Subscribe Lite
wscat -c "wss://trades.testnet.grvt.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.deposit",
"feed":["'$GRVT_MAIN_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":false
}
' -w 360
Subscribe Full
wscat -c "wss://trades.grvt.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.deposit",
"selectors": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"id": 123
}
' -w 360
Unsubscribe Full
wscat -c "wss://trades.grvt.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.deposit",
"selectors": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"id": 123
}
' -w 360
Legacy Subscribe Full
wscat -c "wss://trades.grvt.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.deposit",
"feed":["'$GRVT_MAIN_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":true
}
' -w 360
Subscribe Lite
wscat -c "wss://trades.grvt.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "subscribe",
"p": {
"s": "v1.deposit",
"s1": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"i": 123
}
' -w 360
Unsubscribe Lite
wscat -c "wss://trades.grvt.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "unsubscribe",
"p": {
"s": "v1.deposit",
"s1": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"i": 123
}
' -w 360
Legacy Subscribe Lite
wscat -c "wss://trades.grvt.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.deposit",
"feed":["'$GRVT_MAIN_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":false
}
' -w 360
Transfer
STREAM: v1.transfer
Subscribes to a feed of transfers. This will execute when there is any transfer to or from the selected account.
To subscribe to a main account, specify the account ID (eg. 0x9fe3758b67ce7a2875ee4b452f01a5282d84ed8a
).
To subscribe to a sub account, specify the main account and the sub account dash separated (eg. 0x9fe3758b67ce7a2875ee4b452f01a5282d84ed8a-1920109784202388
).
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
main_account_idma |
string | True | The main account ID to request for |
sub_account_idsa |
string | False'0' |
The sub account ID to request for |
JSONRPC Wrappers
All Websocket JSON RPC Requests are housed in this wrapper. You may specify a stream, and a list of feeds to subscribe to.
If a request_id
is supplied in this JSON RPC request, it will be propagated back to any relevant JSON RPC responses (including error).
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See Overview
page for more details.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
jsonrpcj |
string | True | The JSON RPC version to use for the request |
methodm |
string | True | The method to use for the request (eg: subscribe / unsubscribe / v1/instrument ) |
paramsp |
object | True | The parameters for the request |
idi |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
All Websocket JSON RPC Responses are housed in this wrapper. It returns a confirmation of the JSON RPC subscribe request.
If a request_id
is supplied in the JSON RPC request, it will be propagated back in this JSON RPC response.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
jsonrpcj |
string | True | The JSON RPC version to use for the request |
resultr |
object | Falsenull |
The result for the request |
errore |
Error | Falsenull |
The error for the request |
idi |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
methodm |
string | True | The method used in the request for this response (eg: subscribe / unsubscribe / v1/instrument ) |
Error
An error response
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
codec |
integer | True | The error code for the request |
messagem |
string | True | The error message for the request |
All V1 Websocket Subscription Requests are housed in this wrapper. You may specify a stream and a list of feeds to subscribe to.
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See Overview
page for more details.
Sequence numbers can be either gateway-specific or global:
- Gateway Unique Sequence Number: Increments by one per stream, resets to 0 on gateway restart.
- Global Unique Sequence Number: A cluster-wide unique number assigned to each cluster payload, does not reset on gateway restarts, and can be used to track and identify message order across streams using sequence_number
and prev_sequence_number
in the feed response.
Set useGlobalSequenceNumber = true
if you need a persistent, unique identifier across all streams or ordering across multiple feeds.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
selectorss1 |
[string] | True | The list of feeds to subscribe to |
To ensure you always know if you have missed any payloads, GRVT servers apply the following heuristics to sequence numbers:
- All snapshot payloads will have a sequence number of
0
. All delta payloads will have a sequence number of1+
. So its easy to distinguish between snapshots, and deltas - Num snapshots returned in Response (per stream): You can ensure that you received the right number of snapshots
- First sequence number returned in Response (per stream): You can ensure that you received the first stream, without gaps from snapshots
- Sequence numbers should always monotonically increase by
1
. If it decreases, or increases by more than1
. Please reconnect - Duplicate sequence numbers are possible due to network retries. If you receive a duplicate, please ignore it, or idempotently re-update it.
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See
Overview
page for more details.NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
subss1 |
[string] | True | The list of feeds subscribed to |
unsubsu |
[string] | True | The list of feeds unsubscribed from |
num_snapshotsns |
[integer] | True | The number of snapshot payloads to expect for each subscribed feed. Returned in same order as subs |
first_sequence_numberfs |
[string] | True | The first sequence number to expect for each subscribed feed. Returned in same order as subs |
All V1 Websocket Unsubscription Requests are housed in this wrapper. You may specify a stream, a list of feeds and whether those feeds use global sequence numbers to unsubscribe from.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The channel to unsubscribe from (eg: ticker.s / ticker.d) |
selectorss1 |
[string] | True | The list of feeds to unsubscribe from |
Returns a confirmation of all unsubscribes
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
unsubsu |
[string] | True | The list of feeds unsubscribed from |
All V1 Websocket Requests are housed in this wrapper. You may specify a stream, and a list of feeds to subscribe to.
If a request_id
is supplied in this JSON RPC request, it will be propagated back to any relevant JSON RPC responses (including error).
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See Overview
page for more details.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
request_idri |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
feedf |
[string] | True | The list of feeds to subscribe to |
methodm |
string | True | The method to use for the request (eg: subscribe / unsubscribe) |
is_fullif |
boolean | Falsefalse |
Whether the request is for full data or lite data |
All V1 Websocket Responses are housed in this wrapper. It returns a confirmation of the JSON RPC subscribe request.
If a request_id
is supplied in the JSON RPC request, it will be propagated back in this JSON RPC response.
To ensure you always know if you have missed any payloads, GRVT servers apply the following heuristics to sequence numbers:
- All snapshot payloads will have a sequence number of
0
. All delta payloads will have a sequence number of1+
. So its easy to distinguish between snapshots, and deltas - Num snapshots returned in Response (per stream): You can ensure that you received the right number of snapshots
- First sequence number returned in Response (per stream): You can ensure that you received the first stream, without gaps from snapshots
- Sequence numbers should always monotonically increase by
1
. If it decreases, or increases by more than1
. Please reconnect - Duplicate sequence numbers are possible due to network retries. If you receive a duplicate, please ignore it, or idempotently re-update it.
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See
Overview
page for more details.NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
request_idri |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
subss1 |
[string] | True | The list of feeds subscribed to |
unsubsu |
[string] | True | The list of feeds unsubscribed from |
num_snapshotsns |
[integer] | True | The number of snapshot payloads to expect for each subscribed feed. Returned in same order as subs |
first_sequence_numberfs |
[string] | True | The first sequence number to expect for each subscribed feed. Returned in same order as subs |
Subscribe
Full Subscribe Request
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.transfer",
"selectors": ["'$GRVT_MAIN_ACCOUNT_ID'-'$GRVT_SUB_ACCOUNT_ID'"]
},
"id": 123
}
{
"jsonrpc": "2.0",
"result": {
"stream": "v1.transfer",
"subs": ["'$GRVT_MAIN_ACCOUNT_ID'-'$GRVT_SUB_ACCOUNT_ID'"],
"unsubs": [],
"num_snapshots": [10],
"first_sequence_number": [872634876]
},
"id": 123,
"method": "subscribe"
}
Unsubscribe
Full Unsubscribe Request
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.transfer",
"selectors": ["'$GRVT_MAIN_ACCOUNT_ID'-'$GRVT_SUB_ACCOUNT_ID'"]
},
"id": 123
}
{
"jsonrpc": "2.0",
"result": {
"stream": "v1.transfer",
"unsubs": ["'$GRVT_MAIN_ACCOUNT_ID'-'$GRVT_SUB_ACCOUNT_ID'"]
},
"id": 123,
"method": "subscribe"
}
Legacy Subscribe
Full Subscribe Request
{
"request_id":1,
"stream":"v1.transfer",
"feed":["'$GRVT_MAIN_ACCOUNT_ID'-'$GRVT_SUB_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":true
}
{
"request_id":1,
"stream":"v1.transfer",
"subs":["'$GRVT_MAIN_ACCOUNT_ID'-'$GRVT_SUB_ACCOUNT_ID'"],
"unsubs":[],
"num_snapshots":[1],
"first_sequence_number":[2813]
}
Subscribes to a feed of transfer updates.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The websocket channel to which the response is sent |
selectors1 |
string | True | Primary selector |
sequence_numbersn |
string | True | A sequence number used to determine message order within a stream. - If useGlobalSequenceNumber is false, this returns the gateway sequence number, which increments by one locally within each stream and resets on gateway restarts.- If useGlobalSequenceNumber is true, this returns the global sequence number, which uniquely identifies messages across the cluster.- A single cluster payload can be multiplexed into multiple stream payloads. - To distinguish each stream payload, a dedupCounter is included.- The returned sequence number is computed as: cluster_sequence_number * 10^5 + dedupCounter . |
feedf |
TransferHistory | True | The transfer history matching the requested filters |
TransferHistory
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
tx_idti |
string | True | The transaction ID of the transfer |
from_account_idfa |
string | True | The account to transfer from |
from_sub_account_idfs |
string | True | The subaccount to transfer from (0 if transferring from main account) |
to_account_idta |
string | True | The account to deposit into |
to_sub_account_idts |
string | True | The subaccount to transfer to (0 if transferring to main account) |
currencyc |
Currency | True | The token currency to transfer |
num_tokensnt |
string | True | The number of tokens to transfer |
signatures |
Signature | True | The signature of the transfer |
event_timeet |
string | True | The timestamp of the transfer in unix nanoseconds |
transfer_typett |
TransferType | True | The type of transfer |
transfer_metadatatm |
string | True | The metadata of the transfer |
Currency
The list of Currencies that are supported on the GRVT exchange
Value | Description |
---|---|
USD = 1 |
the USD fiat currency |
USDC = 2 |
the USDC token |
USDT = 3 |
the USDT token |
ETH = 4 |
the ETH token |
BTC = 5 |
the BTC token |
SOL = 6 |
the SOL token |
ARB = 7 |
the ARB token |
BNB = 8 |
the BNB token |
ZK = 9 |
the ZK token |
POL = 10 |
the POL token |
OP = 11 |
the OP token |
ATOM = 12 |
the ATOM token |
KPEPE = 13 |
the 1000PEPE token |
TON = 14 |
the TON token |
XRP = 15 |
the XRP token |
TRUMP = 20 |
the TRUMP token |
SUI = 21 |
the SUI token |
LINK = 25 |
the LINK token |
JUP = 27 |
the JUP token |
FARTCOIN = 28 |
the FARTCOIN token |
ENA = 29 |
the ENA token |
DOGE = 30 |
the DOGE token |
ADA = 33 |
the ADA token |
AAVE = 34 |
the AAVE token |
BERA = 35 |
the BERA token |
IP = 40 |
the IP token |
Signature
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
signers |
string | True | The address (public key) of the wallet signing the payload |
rr |
string | True | Signature R |
ss1 |
string | True | Signature S |
vv |
integer | True | Signature V |
expiratione |
string | True | Timestamp after which this signature expires, expressed in unix nanoseconds. Must be capped at 30 days |
noncen |
integer | True | Users can randomly generate this value, used as a signature deconflicting key. ie. You can send the same exact instruction twice with different nonces. When the same nonce is used, the same payload will generate the same signature. Our system will consider the payload a duplicate, and ignore it. |
TransferType
Value | Description |
---|---|
STANDARD = 1 |
Standard transfer that has nothing to do with bridging |
FAST_ARB_DEPOSIT = 2 |
Fast Arb Deposit Metadata type |
FAST_ARB_WITHDRAWAL = 3 |
Fast Arb Withdrawal Metadata type |
NON_NATIVE_BRIDGE_DEPOSIT = 4 |
Transfer type for non native bridging deposit |
NON_NATIVE_BRIDGE_WITHDRAWAL = 5 |
Transfer type for non native bridging withdrawal |
Success
Full Feed Response
{
"stream": "v1.transfer",
"selector": "BTC_USDT_Perp",
"sequence_number": "872634876",
"feed": {
"tx_id": "1028403",
"from_account_id": "0xc73c0c2538fd9b833d20933ccc88fdaa74fcb0d0",
"from_sub_account_id": "'$GRVT_SUB_ACCOUNT_ID'",
"to_account_id": "0xc73c0c2538fd9b833d20933ccc88fdaa74fcb0d0",
"to_sub_account_id": "'$GRVT_SUB_ACCOUNT_ID'",
"currency": "USDT",
"num_tokens": "1500.0",
"signature": {
"signer": "0xc73c0c2538fd9b833d20933ccc88fdaa74fcb0d0",
"r": "0xb788d96fee91c7cdc35918e0441b756d4000ec1d07d900c73347d9abbc20acc8",
"s": "0x3d786193125f7c29c958647da64d0e2875ece2c3f845a591bdd7dae8c475e26d",
"v": 28,
"expiration": "1697788800000000000",
"nonce": 1234567890
},
"event_time": "1697788800000000000",
"transfer_type": "STANDARD",
"transfer_metadata": null
}
}
{
"s": "v1.transfer",
"s1": "BTC_USDT_Perp",
"sn": "872634876",
"f": {
"ti": "1028403",
"fa": "0xc73c0c2538fd9b833d20933ccc88fdaa74fcb0d0",
"fs": "'$GRVT_SUB_ACCOUNT_ID'",
"ta": "0xc73c0c2538fd9b833d20933ccc88fdaa74fcb0d0",
"ts": "'$GRVT_SUB_ACCOUNT_ID'",
"c": "USDT",
"nt": "1500.0",
"s": {
"s": "0xc73c0c2538fd9b833d20933ccc88fdaa74fcb0d0",
"r": "0xb788d96fee91c7cdc35918e0441b756d4000ec1d07d900c73347d9abbc20acc8",
"s1": "0x3d786193125f7c29c958647da64d0e2875ece2c3f845a591bdd7dae8c475e26d",
"v": 28,
"e": "1697788800000000000",
"n": 1234567890
},
"et": "1697788800000000000",
"tt": "STANDARD",
"tm": null
}
}
Error Codes
Code | HttpStatus | Description |
---|---|---|
1001 | 403 | You are not authorized to access this functionality |
1008 | 401 | Your IP has not been whitelisted for access |
1101 | 400 | Feed Format must be in the format of |
1102 | 400 | Wrong number of primary selectors |
1103 | 400 | Wrong number of secondary selectors |
3020 | 400 | Sub account ID must be an uint64 integer |
All Websocket JSON RPC Responses are housed in this wrapper. It returns a confirmation of the JSON RPC subscribe request.
If a request_id
is supplied in the JSON RPC request, it will be propagated back in this JSON RPC response.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
jsonrpcj |
string | True | The JSON RPC version to use for the request |
resultr |
object | Falsenull |
The result for the request |
errore |
Error | Falsenull |
The error for the request |
idi |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
methodm |
string | True | The method used in the request for this response (eg: subscribe / unsubscribe / v1/instrument ) |
Error
An error response
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
codec |
integer | True | The error code for the request |
messagem |
string | True | The error message for the request |
Error
Full Error Response
{
"jsonrpc": "2.0",
"error": {
"code": 1001,
"message": "You are not authorized to access this functionality"
},
"id": 123,
"method": "subscribe"
}
{
"j": "2.0",
"e": {
"c": 1001,
"m": "You are not authorized to access this functionality"
},
"i": 123,
"m": "subscribe"
}
{
"code":1001,
"message":"You are not authorized to access this functionality",
"status":403
}
Authentication
In order to authenticate, you must first provision a valid API key. API keys can be provisioned via the GRVT UI.
# These are the variables you will need to set manually
GRVT_API_KEY="<insert_key_here>"
GRVT_SUB_ACCOUNT_ID="<insert_sub_account_id_here>"
Then, choose the environment you want to authenticate against.
# dev
GRVT_AUTH_ENDPOINT="https://edge.dev.gravitymarkets.io/auth/api_key/login"
# staging
GRVT_AUTH_ENDPOINT="https://edge.staging.gravitymarkets.io/auth/api_key/login"
# testnet
GRVT_AUTH_ENDPOINT="https://edge.testnet.grvt.io/auth/api_key/login"
# prod
GRVT_AUTH_ENDPOINT="https://edge.grvt.io/auth/api_key/login"
Now, let’s authenticate and retrieve both the session cookie and the X-Grvt-Account-Id
header value that you’ll need to access any endpoints requiring authentication.
echo $GRVT_API_KEY
echo $GRVT_SUB_ACCOUNT_ID
echo $GRVT_AUTH_ENDPOINT
RESPONSE=$(
curl $GRVT_AUTH_ENDPOINT \
-H 'Content-Type: application/json' \
-H 'Cookie: rm=true;' \
-d '{"api_key": "'$GRVT_API_KEY'"}' \
-s -i
)
GRVT_COOKIE=$(echo "$RESPONSE" | grep -i 'set-cookie:' | grep -o 'gravity=[^;]*')
GRVT_ACCOUNT_ID=$(echo "$RESPONSE" | grep 'x-grvt-account-id:' | awk '{print $2}' | tr -d '\r')
echo "$GRVT_COOKIE"
echo "$GRVT_ACCOUNT_ID"
Subscribe Full
wscat -c "wss://trades.dev.gravitymarkets.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.transfer",
"selectors": ["'$GRVT_MAIN_ACCOUNT_ID'-'$GRVT_SUB_ACCOUNT_ID'"]
},
"id": 123
}
' -w 360
Unsubscribe Full
wscat -c "wss://trades.dev.gravitymarkets.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.transfer",
"selectors": ["'$GRVT_MAIN_ACCOUNT_ID'-'$GRVT_SUB_ACCOUNT_ID'"]
},
"id": 123
}
' -w 360
Legacy Subscribe Full
wscat -c "wss://trades.dev.gravitymarkets.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.transfer",
"feed":["'$GRVT_MAIN_ACCOUNT_ID'-'$GRVT_SUB_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":true
}
' -w 360
Subscribe Lite
wscat -c "wss://trades.dev.gravitymarkets.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "subscribe",
"p": {
"s": "v1.transfer",
"s1": ["'$GRVT_MAIN_ACCOUNT_ID'-'$GRVT_SUB_ACCOUNT_ID'"]
},
"i": 123
}
' -w 360
Unsubscribe Lite
wscat -c "wss://trades.dev.gravitymarkets.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "unsubscribe",
"p": {
"s": "v1.transfer",
"s1": ["'$GRVT_MAIN_ACCOUNT_ID'-'$GRVT_SUB_ACCOUNT_ID'"]
},
"i": 123
}
' -w 360
Legacy Subscribe Lite
wscat -c "wss://trades.dev.gravitymarkets.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.transfer",
"feed":["'$GRVT_MAIN_ACCOUNT_ID'-'$GRVT_SUB_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":false
}
' -w 360
Subscribe Full
wscat -c "wss://trades.staging.gravitymarkets.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.transfer",
"selectors": ["'$GRVT_MAIN_ACCOUNT_ID'-'$GRVT_SUB_ACCOUNT_ID'"]
},
"id": 123
}
' -w 360
Unsubscribe Full
wscat -c "wss://trades.staging.gravitymarkets.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.transfer",
"selectors": ["'$GRVT_MAIN_ACCOUNT_ID'-'$GRVT_SUB_ACCOUNT_ID'"]
},
"id": 123
}
' -w 360
Legacy Subscribe Full
wscat -c "wss://trades.staging.gravitymarkets.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.transfer",
"feed":["'$GRVT_MAIN_ACCOUNT_ID'-'$GRVT_SUB_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":true
}
' -w 360
Subscribe Lite
wscat -c "wss://trades.staging.gravitymarkets.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "subscribe",
"p": {
"s": "v1.transfer",
"s1": ["'$GRVT_MAIN_ACCOUNT_ID'-'$GRVT_SUB_ACCOUNT_ID'"]
},
"i": 123
}
' -w 360
Unsubscribe Lite
wscat -c "wss://trades.staging.gravitymarkets.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "unsubscribe",
"p": {
"s": "v1.transfer",
"s1": ["'$GRVT_MAIN_ACCOUNT_ID'-'$GRVT_SUB_ACCOUNT_ID'"]
},
"i": 123
}
' -w 360
Legacy Subscribe Lite
wscat -c "wss://trades.staging.gravitymarkets.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.transfer",
"feed":["'$GRVT_MAIN_ACCOUNT_ID'-'$GRVT_SUB_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":false
}
' -w 360
Subscribe Full
wscat -c "wss://trades.testnet.grvt.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.transfer",
"selectors": ["'$GRVT_MAIN_ACCOUNT_ID'-'$GRVT_SUB_ACCOUNT_ID'"]
},
"id": 123
}
' -w 360
Unsubscribe Full
wscat -c "wss://trades.testnet.grvt.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.transfer",
"selectors": ["'$GRVT_MAIN_ACCOUNT_ID'-'$GRVT_SUB_ACCOUNT_ID'"]
},
"id": 123
}
' -w 360
Legacy Subscribe Full
wscat -c "wss://trades.testnet.grvt.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.transfer",
"feed":["'$GRVT_MAIN_ACCOUNT_ID'-'$GRVT_SUB_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":true
}
' -w 360
Subscribe Lite
wscat -c "wss://trades.testnet.grvt.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "subscribe",
"p": {
"s": "v1.transfer",
"s1": ["'$GRVT_MAIN_ACCOUNT_ID'-'$GRVT_SUB_ACCOUNT_ID'"]
},
"i": 123
}
' -w 360
Unsubscribe Lite
wscat -c "wss://trades.testnet.grvt.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "unsubscribe",
"p": {
"s": "v1.transfer",
"s1": ["'$GRVT_MAIN_ACCOUNT_ID'-'$GRVT_SUB_ACCOUNT_ID'"]
},
"i": 123
}
' -w 360
Legacy Subscribe Lite
wscat -c "wss://trades.testnet.grvt.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.transfer",
"feed":["'$GRVT_MAIN_ACCOUNT_ID'-'$GRVT_SUB_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":false
}
' -w 360
Subscribe Full
wscat -c "wss://trades.grvt.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.transfer",
"selectors": ["'$GRVT_MAIN_ACCOUNT_ID'-'$GRVT_SUB_ACCOUNT_ID'"]
},
"id": 123
}
' -w 360
Unsubscribe Full
wscat -c "wss://trades.grvt.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.transfer",
"selectors": ["'$GRVT_MAIN_ACCOUNT_ID'-'$GRVT_SUB_ACCOUNT_ID'"]
},
"id": 123
}
' -w 360
Legacy Subscribe Full
wscat -c "wss://trades.grvt.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.transfer",
"feed":["'$GRVT_MAIN_ACCOUNT_ID'-'$GRVT_SUB_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":true
}
' -w 360
Subscribe Lite
wscat -c "wss://trades.grvt.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "subscribe",
"p": {
"s": "v1.transfer",
"s1": ["'$GRVT_MAIN_ACCOUNT_ID'-'$GRVT_SUB_ACCOUNT_ID'"]
},
"i": 123
}
' -w 360
Unsubscribe Lite
wscat -c "wss://trades.grvt.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "unsubscribe",
"p": {
"s": "v1.transfer",
"s1": ["'$GRVT_MAIN_ACCOUNT_ID'-'$GRVT_SUB_ACCOUNT_ID'"]
},
"i": 123
}
' -w 360
Legacy Subscribe Lite
wscat -c "wss://trades.grvt.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.transfer",
"feed":["'$GRVT_MAIN_ACCOUNT_ID'-'$GRVT_SUB_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":false
}
' -w 360
Withdrawal
STREAM: v1.withdrawal
Subscribes to a feed of withdrawals. This will execute when there is any withdrawal from the selected account.
To subscribe to a main account, specify the account ID (eg. 0x9fe3758b67ce7a2875ee4b452f01a5282d84ed8a
).
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
main_account_idma |
string | True | The main account ID to request for |
JSONRPC Wrappers
All Websocket JSON RPC Requests are housed in this wrapper. You may specify a stream, and a list of feeds to subscribe to.
If a request_id
is supplied in this JSON RPC request, it will be propagated back to any relevant JSON RPC responses (including error).
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See Overview
page for more details.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
jsonrpcj |
string | True | The JSON RPC version to use for the request |
methodm |
string | True | The method to use for the request (eg: subscribe / unsubscribe / v1/instrument ) |
paramsp |
object | True | The parameters for the request |
idi |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
All Websocket JSON RPC Responses are housed in this wrapper. It returns a confirmation of the JSON RPC subscribe request.
If a request_id
is supplied in the JSON RPC request, it will be propagated back in this JSON RPC response.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
jsonrpcj |
string | True | The JSON RPC version to use for the request |
resultr |
object | Falsenull |
The result for the request |
errore |
Error | Falsenull |
The error for the request |
idi |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
methodm |
string | True | The method used in the request for this response (eg: subscribe / unsubscribe / v1/instrument ) |
Error
An error response
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
codec |
integer | True | The error code for the request |
messagem |
string | True | The error message for the request |
All V1 Websocket Subscription Requests are housed in this wrapper. You may specify a stream and a list of feeds to subscribe to.
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See Overview
page for more details.
Sequence numbers can be either gateway-specific or global:
- Gateway Unique Sequence Number: Increments by one per stream, resets to 0 on gateway restart.
- Global Unique Sequence Number: A cluster-wide unique number assigned to each cluster payload, does not reset on gateway restarts, and can be used to track and identify message order across streams using sequence_number
and prev_sequence_number
in the feed response.
Set useGlobalSequenceNumber = true
if you need a persistent, unique identifier across all streams or ordering across multiple feeds.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
selectorss1 |
[string] | True | The list of feeds to subscribe to |
To ensure you always know if you have missed any payloads, GRVT servers apply the following heuristics to sequence numbers:
- All snapshot payloads will have a sequence number of
0
. All delta payloads will have a sequence number of1+
. So its easy to distinguish between snapshots, and deltas - Num snapshots returned in Response (per stream): You can ensure that you received the right number of snapshots
- First sequence number returned in Response (per stream): You can ensure that you received the first stream, without gaps from snapshots
- Sequence numbers should always monotonically increase by
1
. If it decreases, or increases by more than1
. Please reconnect - Duplicate sequence numbers are possible due to network retries. If you receive a duplicate, please ignore it, or idempotently re-update it.
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See
Overview
page for more details.NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
subss1 |
[string] | True | The list of feeds subscribed to |
unsubsu |
[string] | True | The list of feeds unsubscribed from |
num_snapshotsns |
[integer] | True | The number of snapshot payloads to expect for each subscribed feed. Returned in same order as subs |
first_sequence_numberfs |
[string] | True | The first sequence number to expect for each subscribed feed. Returned in same order as subs |
All V1 Websocket Unsubscription Requests are housed in this wrapper. You may specify a stream, a list of feeds and whether those feeds use global sequence numbers to unsubscribe from.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The channel to unsubscribe from (eg: ticker.s / ticker.d) |
selectorss1 |
[string] | True | The list of feeds to unsubscribe from |
Returns a confirmation of all unsubscribes
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
unsubsu |
[string] | True | The list of feeds unsubscribed from |
All V1 Websocket Requests are housed in this wrapper. You may specify a stream, and a list of feeds to subscribe to.
If a request_id
is supplied in this JSON RPC request, it will be propagated back to any relevant JSON RPC responses (including error).
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See Overview
page for more details.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
request_idri |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
feedf |
[string] | True | The list of feeds to subscribe to |
methodm |
string | True | The method to use for the request (eg: subscribe / unsubscribe) |
is_fullif |
boolean | Falsefalse |
Whether the request is for full data or lite data |
All V1 Websocket Responses are housed in this wrapper. It returns a confirmation of the JSON RPC subscribe request.
If a request_id
is supplied in the JSON RPC request, it will be propagated back in this JSON RPC response.
To ensure you always know if you have missed any payloads, GRVT servers apply the following heuristics to sequence numbers:
- All snapshot payloads will have a sequence number of
0
. All delta payloads will have a sequence number of1+
. So its easy to distinguish between snapshots, and deltas - Num snapshots returned in Response (per stream): You can ensure that you received the right number of snapshots
- First sequence number returned in Response (per stream): You can ensure that you received the first stream, without gaps from snapshots
- Sequence numbers should always monotonically increase by
1
. If it decreases, or increases by more than1
. Please reconnect - Duplicate sequence numbers are possible due to network retries. If you receive a duplicate, please ignore it, or idempotently re-update it.
When subscribing to the same primary selector again, the previous secondary selector will be replaced. See
Overview
page for more details.NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
request_idri |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
streams |
string | True | The channel to subscribe to (eg: ticker.s / ticker.d) |
subss1 |
[string] | True | The list of feeds subscribed to |
unsubsu |
[string] | True | The list of feeds unsubscribed from |
num_snapshotsns |
[integer] | True | The number of snapshot payloads to expect for each subscribed feed. Returned in same order as subs |
first_sequence_numberfs |
[string] | True | The first sequence number to expect for each subscribed feed. Returned in same order as subs |
Subscribe
Full Subscribe Request
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.withdrawal",
"selectors": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"id": 123
}
{
"jsonrpc": "2.0",
"result": {
"stream": "v1.withdrawal",
"subs": ["'$GRVT_MAIN_ACCOUNT_ID'"],
"unsubs": [],
"num_snapshots": [10],
"first_sequence_number": [872634876]
},
"id": 123,
"method": "subscribe"
}
Unsubscribe
Full Unsubscribe Request
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.withdrawal",
"selectors": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"id": 123
}
{
"jsonrpc": "2.0",
"result": {
"stream": "v1.withdrawal",
"unsubs": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"id": 123,
"method": "subscribe"
}
Legacy Subscribe
Full Subscribe Request
{
"request_id":1,
"stream":"v1.withdrawal",
"feed":["'$GRVT_MAIN_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":true
}
{
"request_id":1,
"stream":"v1.withdrawal",
"subs":["'$GRVT_MAIN_ACCOUNT_ID'"],
"unsubs":[],
"num_snapshots":[1],
"first_sequence_number":[2813]
}
Subscribes to a feed of withdrawal updates.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
streams |
string | True | The websocket channel to which the response is sent |
selectors1 |
string | True | Primary selector |
sequence_numbersn |
string | True | A sequence number used to determine message order within a stream. - If useGlobalSequenceNumber is false, this returns the gateway sequence number, which increments by one locally within each stream and resets on gateway restarts.- If useGlobalSequenceNumber is true, this returns the global sequence number, which uniquely identifies messages across the cluster.- A single cluster payload can be multiplexed into multiple stream payloads. - To distinguish each stream payload, a dedupCounter is included.- The returned sequence number is computed as: cluster_sequence_number * 10^5 + dedupCounter . |
feedf |
Withdrawal | True | The Withdrawal object |
Withdrawal
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
from_account_idfa |
string | True | The subaccount to withdraw from |
to_eth_addresste |
string | True | The ethereum address to withdraw to |
currencyc |
Currency | True | The token currency to withdraw |
num_tokensnt |
string | True | The number of tokens to withdraw |
signatures |
Signature | True | The signature of the withdrawal |
Currency
The list of Currencies that are supported on the GRVT exchange
Value | Description |
---|---|
USD = 1 |
the USD fiat currency |
USDC = 2 |
the USDC token |
USDT = 3 |
the USDT token |
ETH = 4 |
the ETH token |
BTC = 5 |
the BTC token |
SOL = 6 |
the SOL token |
ARB = 7 |
the ARB token |
BNB = 8 |
the BNB token |
ZK = 9 |
the ZK token |
POL = 10 |
the POL token |
OP = 11 |
the OP token |
ATOM = 12 |
the ATOM token |
KPEPE = 13 |
the 1000PEPE token |
TON = 14 |
the TON token |
XRP = 15 |
the XRP token |
TRUMP = 20 |
the TRUMP token |
SUI = 21 |
the SUI token |
LINK = 25 |
the LINK token |
JUP = 27 |
the JUP token |
FARTCOIN = 28 |
the FARTCOIN token |
ENA = 29 |
the ENA token |
DOGE = 30 |
the DOGE token |
ADA = 33 |
the ADA token |
AAVE = 34 |
the AAVE token |
BERA = 35 |
the BERA token |
IP = 40 |
the IP token |
Signature
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
signers |
string | True | The address (public key) of the wallet signing the payload |
rr |
string | True | Signature R |
ss1 |
string | True | Signature S |
vv |
integer | True | Signature V |
expiratione |
string | True | Timestamp after which this signature expires, expressed in unix nanoseconds. Must be capped at 30 days |
noncen |
integer | True | Users can randomly generate this value, used as a signature deconflicting key. ie. You can send the same exact instruction twice with different nonces. When the same nonce is used, the same payload will generate the same signature. Our system will consider the payload a duplicate, and ignore it. |
Success
Full Feed Response
{
"stream": "v1.withdrawal",
"selector": "BTC_USDT_Perp",
"sequence_number": "872634876",
"feed": {
"from_account_id": "0xc73c0c2538fd9b833d20933ccc88fdaa74fcb0d0",
"to_eth_address": "0xc73c0c2538fd9b833d20933ccc88fdaa74fcb0d0",
"currency": "USDT",
"num_tokens": "10.50",
"signature": {
"signer": "0xc73c0c2538fd9b833d20933ccc88fdaa74fcb0d0",
"r": "0xb788d96fee91c7cdc35918e0441b756d4000ec1d07d900c73347d9abbc20acc8",
"s": "0x3d786193125f7c29c958647da64d0e2875ece2c3f845a591bdd7dae8c475e26d",
"v": 28,
"expiration": "1697788800000000000",
"nonce": 1234567890
}
}
}
{
"s": "v1.withdrawal",
"s1": "BTC_USDT_Perp",
"sn": "872634876",
"f": {
"fa": "0xc73c0c2538fd9b833d20933ccc88fdaa74fcb0d0",
"te": "0xc73c0c2538fd9b833d20933ccc88fdaa74fcb0d0",
"c": "USDT",
"nt": "10.50",
"s": {
"s": "0xc73c0c2538fd9b833d20933ccc88fdaa74fcb0d0",
"r": "0xb788d96fee91c7cdc35918e0441b756d4000ec1d07d900c73347d9abbc20acc8",
"s1": "0x3d786193125f7c29c958647da64d0e2875ece2c3f845a591bdd7dae8c475e26d",
"v": 28,
"e": "1697788800000000000",
"n": 1234567890
}
}
}
Error Codes
Code | HttpStatus | Description |
---|---|---|
1001 | 403 | You are not authorized to access this functionality |
1008 | 401 | Your IP has not been whitelisted for access |
1101 | 400 | Feed Format must be in the format of |
1102 | 400 | Wrong number of primary selectors |
1103 | 400 | Wrong number of secondary selectors |
All Websocket JSON RPC Responses are housed in this wrapper. It returns a confirmation of the JSON RPC subscribe request.
If a request_id
is supplied in the JSON RPC request, it will be propagated back in this JSON RPC response.
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
jsonrpcj |
string | True | The JSON RPC version to use for the request |
resultr |
object | Falsenull |
The result for the request |
errore |
Error | Falsenull |
The error for the request |
idi |
integer | False0 |
Optional Field which is used to match the response by the client. If not passed, this field will not be returned |
methodm |
string | True | The method used in the request for this response (eg: subscribe / unsubscribe / v1/instrument ) |
Error
An error response
NameLite |
Type | RequiredDefault |
Description |
---|---|---|---|
codec |
integer | True | The error code for the request |
messagem |
string | True | The error message for the request |
Error
Full Error Response
{
"jsonrpc": "2.0",
"error": {
"code": 1001,
"message": "You are not authorized to access this functionality"
},
"id": 123,
"method": "subscribe"
}
{
"j": "2.0",
"e": {
"c": 1001,
"m": "You are not authorized to access this functionality"
},
"i": 123,
"m": "subscribe"
}
{
"code":1001,
"message":"You are not authorized to access this functionality",
"status":403
}
Authentication
In order to authenticate, you must first provision a valid API key. API keys can be provisioned via the GRVT UI.
# These are the variables you will need to set manually
GRVT_API_KEY="<insert_key_here>"
GRVT_SUB_ACCOUNT_ID="<insert_sub_account_id_here>"
Then, choose the environment you want to authenticate against.
# dev
GRVT_AUTH_ENDPOINT="https://edge.dev.gravitymarkets.io/auth/api_key/login"
# staging
GRVT_AUTH_ENDPOINT="https://edge.staging.gravitymarkets.io/auth/api_key/login"
# testnet
GRVT_AUTH_ENDPOINT="https://edge.testnet.grvt.io/auth/api_key/login"
# prod
GRVT_AUTH_ENDPOINT="https://edge.grvt.io/auth/api_key/login"
Now, let’s authenticate and retrieve both the session cookie and the X-Grvt-Account-Id
header value that you’ll need to access any endpoints requiring authentication.
echo $GRVT_API_KEY
echo $GRVT_SUB_ACCOUNT_ID
echo $GRVT_AUTH_ENDPOINT
RESPONSE=$(
curl $GRVT_AUTH_ENDPOINT \
-H 'Content-Type: application/json' \
-H 'Cookie: rm=true;' \
-d '{"api_key": "'$GRVT_API_KEY'"}' \
-s -i
)
GRVT_COOKIE=$(echo "$RESPONSE" | grep -i 'set-cookie:' | grep -o 'gravity=[^;]*')
GRVT_ACCOUNT_ID=$(echo "$RESPONSE" | grep 'x-grvt-account-id:' | awk '{print $2}' | tr -d '\r')
echo "$GRVT_COOKIE"
echo "$GRVT_ACCOUNT_ID"
Subscribe Full
wscat -c "wss://trades.dev.gravitymarkets.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.withdrawal",
"selectors": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"id": 123
}
' -w 360
Unsubscribe Full
wscat -c "wss://trades.dev.gravitymarkets.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.withdrawal",
"selectors": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"id": 123
}
' -w 360
Legacy Subscribe Full
wscat -c "wss://trades.dev.gravitymarkets.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.withdrawal",
"feed":["'$GRVT_MAIN_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":true
}
' -w 360
Subscribe Lite
wscat -c "wss://trades.dev.gravitymarkets.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "subscribe",
"p": {
"s": "v1.withdrawal",
"s1": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"i": 123
}
' -w 360
Unsubscribe Lite
wscat -c "wss://trades.dev.gravitymarkets.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "unsubscribe",
"p": {
"s": "v1.withdrawal",
"s1": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"i": 123
}
' -w 360
Legacy Subscribe Lite
wscat -c "wss://trades.dev.gravitymarkets.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.withdrawal",
"feed":["'$GRVT_MAIN_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":false
}
' -w 360
Subscribe Full
wscat -c "wss://trades.staging.gravitymarkets.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.withdrawal",
"selectors": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"id": 123
}
' -w 360
Unsubscribe Full
wscat -c "wss://trades.staging.gravitymarkets.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.withdrawal",
"selectors": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"id": 123
}
' -w 360
Legacy Subscribe Full
wscat -c "wss://trades.staging.gravitymarkets.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.withdrawal",
"feed":["'$GRVT_MAIN_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":true
}
' -w 360
Subscribe Lite
wscat -c "wss://trades.staging.gravitymarkets.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "subscribe",
"p": {
"s": "v1.withdrawal",
"s1": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"i": 123
}
' -w 360
Unsubscribe Lite
wscat -c "wss://trades.staging.gravitymarkets.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "unsubscribe",
"p": {
"s": "v1.withdrawal",
"s1": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"i": 123
}
' -w 360
Legacy Subscribe Lite
wscat -c "wss://trades.staging.gravitymarkets.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.withdrawal",
"feed":["'$GRVT_MAIN_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":false
}
' -w 360
Subscribe Full
wscat -c "wss://trades.testnet.grvt.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.withdrawal",
"selectors": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"id": 123
}
' -w 360
Unsubscribe Full
wscat -c "wss://trades.testnet.grvt.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.withdrawal",
"selectors": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"id": 123
}
' -w 360
Legacy Subscribe Full
wscat -c "wss://trades.testnet.grvt.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.withdrawal",
"feed":["'$GRVT_MAIN_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":true
}
' -w 360
Subscribe Lite
wscat -c "wss://trades.testnet.grvt.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "subscribe",
"p": {
"s": "v1.withdrawal",
"s1": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"i": 123
}
' -w 360
Unsubscribe Lite
wscat -c "wss://trades.testnet.grvt.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "unsubscribe",
"p": {
"s": "v1.withdrawal",
"s1": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"i": 123
}
' -w 360
Legacy Subscribe Lite
wscat -c "wss://trades.testnet.grvt.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.withdrawal",
"feed":["'$GRVT_MAIN_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":false
}
' -w 360
Subscribe Full
wscat -c "wss://trades.grvt.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"stream": "v1.withdrawal",
"selectors": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"id": 123
}
' -w 360
Unsubscribe Full
wscat -c "wss://trades.grvt.io/ws/full" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"jsonrpc": "2.0",
"method": "unsubscribe",
"params": {
"stream": "v1.withdrawal",
"selectors": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"id": 123
}
' -w 360
Legacy Subscribe Full
wscat -c "wss://trades.grvt.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.withdrawal",
"feed":["'$GRVT_MAIN_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":true
}
' -w 360
Subscribe Lite
wscat -c "wss://trades.grvt.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "subscribe",
"p": {
"s": "v1.withdrawal",
"s1": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"i": 123
}
' -w 360
Unsubscribe Lite
wscat -c "wss://trades.grvt.io/ws/lite" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"j": "2.0",
"m": "unsubscribe",
"p": {
"s": "v1.withdrawal",
"s1": ["'$GRVT_MAIN_ACCOUNT_ID'"]
},
"i": 123
}
' -w 360
Legacy Subscribe Lite
wscat -c "wss://trades.grvt.io/ws" \
-H "Cookie: $GRVT_COOKIE" \
-H "X-Grvt-Account-Id: $GRVT_ACCOUNT_ID" \
-x '
{
"request_id":1,
"stream":"v1.withdrawal",
"feed":["'$GRVT_MAIN_ACCOUNT_ID'"],
"method":"subscribe",
"is_full":false
}
' -w 360