API version 2

Path prefix: /api/v2
Response format: JSON

Public/Private API

GRAVIEX API v2 includes both public API and private API.

Public APIPrivate API
No authentication requiredAuthentication required
Unlimited6000 requests/keypair/5minutes, you can contact GRAVIEX if you need more.
Ready to useYou need to request for access/secret key at first


To use private API, you need to get your access/secret key first. After signed up and verified, please visit API Tokens page to get your keys.

All private API requires 3 authentication parameters and zero or more API specific parameters. The 3 authentication parameters are:

access_keyYour access key.
toncetonce is a timestamp in integer, stands for milliseconds elapsed since Unix epoch. Tonce must be within 30 seconds of server's current time. Each tonce can only be used once.
signatureSignature of the API request, generated by you, use your secret key.

Signature is a hash of the request (in canonical string form):

hash = HMAC-SHA256(payload, secret_key).to_hex

Payload is a combination of HTTP verb, uri, and query string:

# canonical_verb is HTTP verb like GET/POST in upcase.
# canonical_uri is request path like /api/v2/markets.
# canonical_query is the request query sorted in alphabetica order, including access_key and tonce, e.g. access_key=xxx&foo=bar&tonce=123456789
# The combined string looks like: GET|/api/v2/markets|access_key=xxx&foo=bar&tonce=123456789
def payload

Note: query parameters are sorted in payload, so it must be "access_key=xxx&foo=bar" not "foo=bar&&access_key=xxx".

Suppose my secret key is 'yyy', then the result of HMAC-SHA256 of above payload is:

hash = HMAC-SHA256('GET|/api/v2/markets|access_key=xxx&foo=bar&tonce=123456789', 'yyy').to_hex
     = 'e324059be4491ed8e528aa7b8735af1e96547fbec96db962d51feb7bf1b64dee'

Now we hav a signed request which can be used like this:

curl -X GET 'https://graviex.net/api/v2/markets?access_key=xxx&foo=bar&tonce=123456789&signature=e324059be4491ed8e528aa7b8735af1e96547fbec96db962d51feb7bf1b64dee'

Response Format

Corresponding HTTP status code will be used in API response. GRAVIEX will also return a JSON structure including error details on failed request, for example:

{"error":{"code":1001,"message":"market does not have a valid value"}}

All errors follow the message format above, only differentiates in code and message. Code is a GRAVIEX defined error code, indicates the error's category, message is human-readable details.

GRAVIEX returns HTTP 200 response on successful request, with requested data in JSON format.

Data TypeExampleComments
{"at":1398410899, "ticker":{"buy":"3000.0","sell":"3100.0","low":"3000.0","high":"3000.0","last":"3000.0","vol":"0.11"}}

at: A timestamp in seconds since Epoch

buy/sell: Current buy/sell price

low/high: Lowest/highest price in last 24 hours

last: Last price

vol: Trade volume in last 24 hours

{"sn":"PEA5TFFOGQHTIO","name":"foo","email":"[email protected]","activated":true,"accounts":[{"currency":"usd","balance":"1002.0","locked":"0.0"},{"currency":"btc","balance":"8.26","locked":"0.8"}]}

sn: Unique identifier of user

name: User name

email: User email

activated: Whether user is activated

accounts: User's accounts info, see Account


currency: Account type, like 'btc' or 'usd'

balance: Account balance, exclude locked funds

locked: locked funds


id: Unique order ID

side: Buy/Sell

price: Order price

avg_price: Average execution price

state: wait, done or cancel. 'wait' represents the order is active, it may be a new order or partial complete order; 'done' means the order has been fulfilled completely; 'cancel' means the order has been cancelled.

market: Which market the order belongs to

created_at: Order created time

volume: volume to buy/sell

remaining_volume: remaining_volume is always less or equal than volume

executed_volume: volume = remaining_volume + executed_volume

trades: the order's trade history, see Trade. Note: not all order include trades, only detailed order data returned by certain API will.


id: Unique ID

price: trade price

volume: trade volume

market: the market trade belongs to, like 'btcusd'

created_at: trade time

{"asks": [...],"bids": [...]}

OrderBook shows orders on market.

Some Examples

Buy 1BTC at price 10000USD:

curl -X POST 'https://graviex.net/api/v2/orders' -d 'access_key=your_access_key&tonce=1234567&signature=computed_signature&market=btcusd&price=10000&side=buy&volume=1'

Create multiple orders with a single request:

curl -X POST 'https://graviex.net/api/v2/orders/multi' -d 'access_key=your_access_key&tonce=123456789&signature=computed_signature&market=btcusd&orders[][price]=10000&orders[][side]=sell&orders[][volume]=0.5&orders[][price]=3999&orders[][side]=sell&orders[][volume]=0.99'

Python script with markets and put order sample:

import hashlib
import hmac
import urllib2
import urllib
import time
import ssl

access_key = '00000000000000000000000000'
secret_key = '00000000000000000000000000'

# 0. making ssl context - verify should be turned off
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE

# ------------------
# Get markets list
# ------------------

# 1. list markets
epoch_time = str(int(time.time())) + '000'
request = 'access_key=' + access_key + '&tonce=' + epoch_time
message = 'GET|/api/v2/markets|' + request

# 1.1 generate the hash.
signature = hmac.new(

# 1.2 list markets
query = 'https://graviex.net/api/v2/markets?' + request + '&signature=' + signature
content = urllib2.urlopen(query, context=ctx).read()

# ------------------
# Put sell order
# ------------------

# 2. put order
epoch_time = str(int(time.time())) + '001' # tonce should be different from previous one

request = 'access_key=' + access_key + '&market=giobtc&price=0.000000042&side=sell' + '&tonce=' + epoch_time + '&volume=100.0'
message = 'POST|/api/v2/orders|' + request

# 2.1 generate the hash.
signature = hmac.new(

# 2.2 put order
query = 'https://graviex.net/api/v2/orders?' + request
result = urllib2.Request(query, urllib.urlencode({'signature' : signature})) #there is a trick - we need a POST request, thats why urlencode used
content = urllib2.urlopen(result, context=ctx).read()


POST /api/v2/order/deleteCancel order is an asynchronous operation. A success response only means your cancel request has been accepted, it doesn't mean the order has been cancelled. You should always use /api/v2/order or websocket api to get order's latest state.
POST /api/v2/orders/clearCancel all your orders is an asynchronous operation. A success response only means your request has been accepted. The orders in response may or may not have been cancelled yet.
GET /api/v2/orders market=allAbility to get all placed orders for all markets

API List

All API are listed below with details. Those require access_key/tonce/signature are private API.