-
Notifications
You must be signed in to change notification settings - Fork 5
Home
We provide a set of easy to use REST APIs and Websocket APIs for you to trade cryptos. You can set up an account with us within 5 minutes using your email and phone number and then try our API with the FREE Litecoin immediately deposited into your newly created account. Should you have any question regarding our API, feel free to talk to us at our Telegram group.
Endpoint: https://api.coinut.com
Our REST APIs use HMAC-SHA256 to authenticate users. To authenticate, simply put your username and signature in the HTTP header part:
X-USER: <your username>
X-SIGNATURE: HMAC-SHA256(<your api key>, payload)
Your API key can be found on the Settings page, and you should never disclose it to anyone else. To verify your HMAC-SHA256 function, check this example
HMAC-SHA256('b45e65ff-d4c4-433c-b032-093423b1aaa4', '{"nonce":3062542,"request":"user_balance"}') = 'd1893b047c4f2f39a229eff4342c1a5c3717cddea01fdfd996199a9bb95f58ea'
For Python2.7 or Python 3, you can use the following sample code to obtain the above signature.
import hmac
import hashlib
signature = hmac.new(key='b45e65ff-d4c4-433c-b032-093423b1aaa4'.encode('utf-8'), msg='{"nonce":3062542,"request":"user_balance"}'.encode('utf-8'), digestmod=hashlib.sha256).hexdigest()
The payloads for APIs that require authentication are JSON dictionaries. For your security, you should put a nonce field in the dictionary with a monotonically increasing integer value to avoid a replay attack.
Our REST APIs and Websocket APIs are mostly the same. The documentation for Websocket APIs below also applies to REST APIs. Due to the HTTP connection constraints, REST APIs do not support incremental updates. Therefore, all subscribe
fields in the Websocket APIs have no effect on REST APIs. If you need incremental updates, use Websocket instead.
Our code library for REST API can be found here.
- Websocket endpoint: wss://wsapi.coinut.com
If you are using NodeJS, you can install the websocket package through the command npm install websocket
, and use the following code to connect to our WebSocket server.
var W3CWebSocket = require('websocket').w3cwebsocket;
var client = new W3CWebSocket('wss://wsapi.coinut.com');
Using python, you can connect to our WebSocket server using the websocket-client package like the following. Please use the command sudo pip install websocket-client
or git to install the newest version. Older version may give you a SSLV3_ALERT_HANDSHAKE_FAILURE
error.
import websocket
ws = websocket.WebSocket()
ws.connect("wss://wsapi.coinut.com")
Heartbeats can be used to maintain a connection or check the status of a connection.
{"request":"hb","nonce":3637472}
{
"nonce":3637472,
"reply":"hb",
"status":[
"OK"
]
}
- NodeJS
var W3CWebSocket = require('websocket').w3cwebsocket;
var client = new W3CWebSocket('wss://wsapi.coinut.com');
client.onmessage = function(e) {
console.log(e.data);
};
client.onopen = function () {
client.send('{"request":"hb","nonce":3637}')
}
- Python
import websocket
ws = websocket.WebSocket()
ws.connect("wss://wsapi.coinut.com")
ws.send('{"request":"hb","nonce":3637}')
print(ws.recv())
Each request should include a unique nonce within the range of [1, 16777215], which will be then included in the replies for that request. Therefore, nonce can be used to track the replies for a particular request.
{"request": "inst_list", "sec_type": "SPOT", "nonce": 39116}
{
"SPOT":{
"LTCBTC":[
{
"base":"LTC",
"inst_id":1,
"decimal_places":5,
"quote":"BTC"
}
],
"ETHBTC":[
{
"quote":"BTC",
"base":"ETH",
"decimal_places":5,
"inst_id":2
}
]
},
"nonce":39116,
"reply":"inst_list",
"status":[
"OK"
]
}
-
inst_id
, the id of the instrument, will not change over time. -
decimal_places
is the number of decimal places of the price.
{"request":"inst_tick","inst_id":1, "subscribe": true, "nonce":61514}
-
subscribe
is only needed when you need updates of new ticks. - once you start to subscribe the ticks for one instrument, use this request with
"subscribe": "false"
to unsubscribe.
{
"highest_buy": "750.58100000",
"inst_id": 1,
"last": "752.00000000",
"lowest_sell": "752.00000000",
"reply": "inst_tick",
"timestamp": 1481355058109705,
"trans_id": 170064,
"volume": "0.07650000",
"volume24": "56.07650000"
}
-
volume
is the total volume since the launch of the exchange -
volume24
gives the trading volume of the last 24 hours
{"request":"inst_order_book","inst_id":1, "subscribe": true, "nonce":704114}
-
inst_id
is required -
subscribe
is optional. It's needed only if you need incremental updates. - To unsubscribe, use this request with
subscribe
set asfalse
.
The server will immediately return a snapshot of the current orderbook as the following:
{
"buy":
[ { "count": 7, "price": "750.00000000", "qty": "0.07000000" },
{ "count": 1, "price": "751.00000000", "qty": "0.01000000" },
{ "count": 1, "price": "751.34500000", "qty": "0.01000000" } ],
"sell":
[ { "count": 6, "price": "750.58100000", "qty": "0.06000000" },
{ "count": 1, "price": "750.58200000", "qty": "0.01000000" },
{ "count": 1, "price": "750.58300000", "qty": "0.01000000" } ],
"inst_id": 1,
"nonce": 704114,
"total_buy": "67.52345000",
"total_sell": "0.08000000",
"reply": "inst_order_book",
"status": [ "OK" ]
}
After that, whenever the orderbook changes, the server will push incremental updates (if subscribe
is set as true
in the request):
{ "count": 7,
"inst_id": 1,
"price": "750.58100000",
"qty": "0.07000000",
"total_buy": "120.06412000",
"reply": "inst_order_book_update",
"side": "BUY",
"trans_id": 169384
}
To use the incremental update, first find an entry in the original orderbook with the same price
field, and then replace that entry with this new update if qty
is not 0. If qty
is 0, the original entry needs to be deleted. If no such entry is found, insert this update into the original orderbook.
Instead of keeping track of the full orderbook, we can also use aggregated ones.
{
"request":"inst_order_book",
"inst_id":1,
"decimal_places":2,
"top_n":10,
"subscribe":true,
"nonce":704114
}
-
top_n
can be any of 10, 50, 100, and 200. It indicates how many entries of the buy/sell side of the orderbook should be returned. -
decimal_places
indicates how many decimal places shall be used for prices. - incremental updates are also adjusted according to the
top_n
anddecimal_places
.
{"request":"inst_trade", "subscribe": true, "inst_id":1,"nonce":450319}
-
subscribe
is only needed if you need incremental updates.
A snapshot will be returned immediately from the server.
{
"nonce": 450319,
"reply": "inst_trade",
"status": [
"OK"
],
"trades": [
{
"price": "750.00000000",
"qty": "0.01000000",
"side": "BUY",
"timestamp": 1481193563288963,
"trans_id": 169514
},
{
"price": "750.00000000",
"qty": "0.01000000",
"side": "BUY",
"timestamp": 1481193345279104,
"trans_id": 169510
},
{
"price": "750.00000000",
"qty": "0.01000000",
"side": "BUY",
"timestamp": 1481193333272230,
"trans_id": 169506
},
{
"price": "750.00000000",
"qty": "0.01000000",
"side": "BUY",
"timestamp": 1481193007342874,
"trans_id": 169502
}]
}
And updates will come after that (Some updates may come before the snapshot. You may check the trans_id
field for the chronological order of them):
{
"inst_id": 1,
"price": "750.58300000",
"reply": "inst_trade_update",
"side": "BUY",
"timestamp": 0,
"trans_id": 169478
}
There are two login methods. One is through username and password; the other is through the API key.
{
"request":"login",
"username":"test",
"password":"Abcdefg12345",
"nonce":829055
}
If you enabled two-factor authentication for your account, you will need to proivde an OTP field as well like the following:
{
"request":"login",
"username":"test",
"password":"Abcdefg12345",
"otp": "545848",
"nonce":829055
}
{
"api_key":"b46e658f-d4c4-433c-b032-093423b1aaa4",
"country":"NA",
"email":"tester@test.com",
"failed_times":0,
"lang":"en_US",
"nonce":829055,
"otp_enabled":false,
"products_enabled":[
"SPOT",
"FUTURE",
"BINARY_OPTION",
"OPTION"
],
"reply":"login",
"session_id":"f8833081-af69-4266-904d-eea088cdcc52",
"status":[
"OK"
],
"timezone":"Asia/Singapore",
"unverified_email":"",
"username":"test"
}
The session_id
field can be used to login again if your connection dropped and needs to reconnect. This avoids user interaction if your two-factor authentication is enabled. To achieve that, just use the following request. Please notice that session_id
only last one hour after you disconnect.
{
"request":"login",
"username":"test",
"session_id":"f8833081-af69-4266-904d-eea088cdcc52",
"nonce":829055
}
This method does not need to reveal your password and also avoid two-factor authentication. To login through the API key, simply concatenate your username, the current unix timestamp, and request nonce into a message as the following, and then calculate the HMAC-SHA256 digest as the following. You should make sure our computer's clock is reasonably correct.
HMAC-SHA256(YOUR_API_KEY, username|timestamp|nonce)
For example, if the username = "test", timestamp = 1542603878, and nonce = 67130554, concatenate them as the following:
test|1542603878|67130554
Then calculate the HMAC-SHA256 digest (suppose the API key is "ec9dd76b-71da-4ab9-bb65-1a19d1184b84", you can find yours on Settings)
HMAC-SHA256("ec9dd76b-71da-4ab9-bb65-1a19d1184b84", "test|1542603878|67130554")
which should give you the following result:
208ade71dc150118feebef664e2262358079d3b445971dedf0eb1d6de3cc2e04
And then make a login request immediately. Make sure the timestamp, nonce, and username in the login request are the same as those for computing the HMAC-SHA256 value. For this example, the login request should be:
{
"request": "login",
"username": "test",
"nonce": 67130554,
"hmac_sha256": "208ade71dc150118feebef664e2262358079d3b445971dedf0eb1d6de3cc2e04",
"timestamp": 1542603878
}
{
"nonce": 306254,
"request": "user_balance"
}
{
"nonce": 306254,
"status": [
"OK"
],
"BTC": "192.46630415",
"LTC": "6000.00000000",
"ETC": "800.00000000",
"ETH": "496.99938000",
"floating_pl": "0.00000000",
"initial_margin": "0.00000000",
"realized_pl": "0.00000000",
"maintenance_margin": "0.00000000",
"equity": "192.46630415",
"reply": "user_balance",
"trans_id": 15159032
}
- If you only trade spots,
floating_pl
,initial_margin
,realized_pl
,maintenance_margin
, andequity
can be ignored.
{
"request":"new_order",
"nonce": 956475,
"inst_id":1,
"price":"750.581",
"qty":"0.01",
"client_ord_id":1345,
"side":"SELL"
}
-
inst_id
is the id of the instrument returned by theinst_list
API. -
price
is the price for a limit order. Market orders do not need this field. -
qty
is the quantity you that want to buy or sell. -
client_ord_id
can be any integer within the range of [1, 16777215]. It can be used by the client to identify the order - side BUY/SELL
There are three kinds of responses: accepted, filled, and rejected.
If an order cannot be fully filled immediately but may be able to be filled later, the order will be inserted into the exchange's orderbook, and a reply with order_accepted
will be returned to the user. This only applies to a limit order. A market order will never receive an order_accepted
reply.
{
"nonce":956475,
"status":[
"OK"
],
"order_id":1,
"open_qty": "0.01",
"inst_id":1,
"qty":"0.01",
"client_ord_id": 1345,
"order_price":"750.581",
"reply":"order_accepted",
"side":"SELL",
"trans_id":127303
}
If an order is partially or fully filled, order_filled
replies will be returned. The format is like the following:
{
"commission": {
"amount": "0.00799000",
"currency": "USD"
},
"fill_price": "799.00000000",
"fill_qty": "0.01000000",
"nonce": 956475,
"order": {
"client_ord_id": 12345,
"inst_id": 2,
"open_qty": "0.00000000",
"order_id": 721923,
"price": "748.00000000",
"qty": "0.01000000",
"side": "SELL",
"timestamp": 1482903034617491
},
"reply": "order_filled",
"status": [
"OK"
],
"timestamp": 1482903034617491,
"trans_id": 20859252
}
One order may be filled at different price levels. And each fill will generate a single order_fill
reply. Unfilled market orders will be rejected immediately. Unfilled limit orders will remain in the orderbook.
An order may be rejected because of various reasons. For example, an order that requires too much balance to open will be rejected with a NOT_ENOUGH_BALANCE
error; an unfilled market order will be rejected with a NOT_ENOUGH_LIQUIDITY
error; an order with invalid price will be rejected with an INVALID_PRICE
error. The following gives a complete list of possible errors:
UNKNOWN_ERROR
INVALID_INSTRUMENT
INST_EXPIRED
INVALID_PRICE
INVALID_QUANTITY
NOT_ENOUGH_BALANCE
NOT_ENOUGH_LIQUIDTY
INVALID_CLIENT_ORD_ID
TRADE_DISABLED
The format of order_reject
replies is as the following.
{
"nonce": 275825,
"status": [
"OK"
],
"order_id": 7171,
"open_qty": "100000.00000000",
"price": "750.60000000",
"inst_id": 2,
"reasons": [
"NOT_ENOUGH_BALANCE"
],
"client_ord_id": 4,
"timestamp": 1482080535098689,
"reply": "order_rejected",
"qty": "100000.00000000",
"side": "BUY",
"trans_id": 3282993
}
Liquidity providers may need to submit multiple orders at once. This API enables that.
{
"request":"new_orders",
"nonce":621701,
"orders":[
{
"inst_id":1,
"price":"750.581",
"qty":"0.01",
"client_ord_id":1345,
"side":"SELL"
},
{
"inst_id":1,
"price":"750.321",
"qty":"0.01",
"client_ord_id":50001346,
"side":"BUY"
}
]
}
-
orders
array shall include all orders' information. The maximum number of orders per batch should not exceed1000
.
[
{
"nonce": 621701,
"status": [
"OK"
],
"order_id": 331,
"open_qty": "0.01000000",
"price": "750.58100000",
"inst_id": 1,
"client_ord_id": 1345,
"timestamp": 1490713990542441,
"reply": "order_accepted",
"qty": "0.01000000",
"side": "SELL",
"trans_id": 15155495
},
{
"nonce": 621701,
"status": [
"OK"
],
"order_id": 332,
"open_qty": "0.01000000",
"price": "750.32100000",
"inst_id": 1,
"client_ord_id": 50001346,
"timestamp": 1490713990542441,
"reply": "order_accepted",
"qty": "0.01000000",
"side": "BUY",
"trans_id": 15155497
}
]
- Orders are executed one by one following the order in the request.
- The response is an array containing each order's result.
{"request": "user_open_orders", "nonce": 1234, "inst_id": 1}
-
inst_id
specifies the instrument of the open orders that you want to get.
{
"nonce": 1234,
"reply": "user_open_orders",
"status": [
"OK"
],
"orders": [
{
"order_id": 35,
"open_qty": "0.01000000",
"price": "750.58200000",
"inst_id": 1,
"client_ord_id": 4,
"timestamp": 1481138766081720,
"qty": "0.01000000",
"side": "BUY"
},
{
"order_id": 30,
"open_qty": "0.01000000",
"price": "750.58100000",
"inst_id": 1,
"client_ord_id": 5,
"timestamp": 1481137697919617,
"qty": "0.01000000",
"side": "BUY"
}
]
}
Accepted orders will also become part of the user's open orders. Therefore, to incrementally update the user's open orders list, first use this user_open_orders
request, and then listen to order_accepted
messages. There is no need to subscribe or unsubscribe order_accepted
messages. They are always delivered to all websocket connections belonging to the user.
{"request":"cancel_order","inst_id":1,"order_id":39,"nonce":547201}
-
inst_id
andorder_id
are all required.
If successful, the result is similar to following
{
"nonce": 547201,
"reply": "cancel_order",
"order_id": 1,
"client_ord_id": 13556,
"status": [
"OK"
]
}
{
"request":"cancel_orders",
"entries":[
{
"inst_id":1,
"order_id":332
},
{
"inst_id":1,
"order_id":329
}
],
"nonce":547201
}
- The maximum number of orders can be canceled in one request is
1000
.
{
"nonce": 547201,
"reply": "cancel_orders",
"status": [
"OK"
],
"results": [
{
"order_id": 329,
"status": "OK",
"inst_id": 1,
"client_ord_id": 13561
},
{
"order_id": 332,
"status": "OK",
"inst_id": 1,
"client_ord_id": 13562
}
],
"trans_id": 15166063
}
- The
results
field contains each order's cancel request result.
{"request":"trade_history","inst_id":1,"start":1,"limit":2,"nonce":326181}
- start and limit are for pagination and are optional. The default value for
start
is0
, andlimit
100
.
{
"nonce": 326181,
"reply": "trade_history",
"status": [
"OK"
],
"trades": [
{
"commission": {
"amount": "0.00000100",
"currency": "BTC"
},
"order": {
"client_ord_id": 297125564,
"inst_id": 1,
"open_qty": "0.00000000",
"order_id": 721327,
"price": "1.00000000",
"qty": "0.00100000",
"side": "SELL",
"timestamp": 1482490337560987
},
"fill_price": "1.00000000",
"fill_qty": "0.00100000",
"timestamp": 1482490337560987,
"trans_id": 10020695
},
{
"commission": {
"amount": "0.00000100",
"currency": "BTC"
},
"order": {
"client_ord_id": 297118937,
"inst_id": 1,
"open_qty": "0.00000000",
"order_id": 721326,
"price": "1.00000000",
"qty": "0.00100000",
"side": "SELL",
"timestamp": 1482490330557949
},
"fill_price": "1.00000000",
"fill_qty": "0.00100000",
"timestamp": 1482490330557949,
"trans_id": 10020514
}
]
}
order_filled
messages can be used as incremental updates of history trades.
Check our API code library.