Introduction
Welcome to the Caspian API v1! You can use our API to access Caspian API endpoints, which can get various information about market data.
We also keep a changelog with all notable changes made to the Caspian API, therefore the documentation would be up to date. Please do not forget to take a look over the Changelog section too at every new release in order to take in consideration the new notable changes.
Authentication
An access token is required in order to interact with the data APIs. This can be obtained by sending an HTTP request as described below.
Request
Request URL: https://sandbox.api.caspian.tech/v1/auth/authenticate
Request Method: POST
Content-Type: application/json
Content:
{
"type:" string,
"payload:" object
}
Authentication request example:
{
"type": "Key",
"payload": {
"accessKeyID": "<YOUR_ACCESS_KEY_ID>",
"secretAccessKey": "<YOUR_SECRET_ACCESS_KEY>"
}
}
where:
- type: one of the below
- Credential
- Key
- payload: based on type
- Credential
- Key
{
"user": string,
"pass": string
}
{
"accessKeyID": string,
"secretAccessKey": string
}
Response
Authorization successful
Here is a sample response:
{
"accessToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJWMVFIVFFQSjAxOTIxQzNNREZIWSIsImlzcyI6IkNhc3BpYW4gVGVjaCIsImV4cCI6MTY0ODg4NzI1N30.MmJ7ZTr9mSK-bsgNif5HyjU8Z9__WGTN_oGvUxdZ3XI",
"expiration": "2018-07-25T15:34:11.536123"
}
Status Code: 200
Content-Type: application/json
Content:
{
"accessToken": string,
"expiration": string
}
where:
- accessToken - the token to be used in subsequent communication with the service
- expiration - the time when the token will expire (expressed in YYYY-MM-DDTHH:MM:SS.mmmmmm)
Bad Request
Meaning: The request body contains an invalid JSON or it is missing the required attributes.
Status Code: 400
Content-Type: application/json
Content:
{
"code": int,
"message": string
}
Posible values for code
:
- 4000 - Request is not properly formatted
- 4001 - Authentication type not found
- 4002 - Authentication details not found
- 4003 - Unsupported authentication type
Unauthorized
Meaning: Incorrect credentials or key.
Status Code: 401
Content: N/A
Internal Server Error
Meaning: The request is properly formatted but the server was unable to fulfill it due to an internal error.
Status Code: 500
Content-Type: application/json
Content:
{
"code": int,
"message": string
}
Real-time Data
The following section describes the interaction between a client application and the Real-time Data service, using web socket technology. In order to use this service, a token must first be obtained, as described in the authentication section.
Connection initialization
Target URL: wss://sandbox.api.caspian.tech/v1/mdata/realtime/stream
When establishing the websocket connection, the user must supply the access token via one of the following ways:
Connection initialization example
Target URL: wss://sandbox.api.caspian.tech/v1/mdata/realtime/stream?access_token=dummyAccessToken
- By setting the HTTP header Authorization Authorization:
- By adding the accessToken parameter in the URL
${accessToken}
wss://sandbox.api.caspian.tech/v1/mdata/realtime/stream?access_token=${accesToken}
If the token is not specified or if it's invalid/ expired, the websocket connection will be closed by the server with one of the following reasons mentioned in the CloseState (see RFC 6455 on protocol details):
- 3000 - Access token not found
- 3001 - Supplied token is not valid
- 3002 - Token has expired
Once the connection is established successfully, the user can proceed with sending requests to the service. The connection will be closed by the service when the token expires (please see Authentication Response section for the token expiration time). In order to keep the old connection alive, user must generate a new valid token and make a Token Refresh request as described in Token Refresh section. The Token Refresh request will replace the token used for the current connection with the newly generated one. If the Token Refresh request succeeds (please see Token Refresh Response section) the connection lifetime will be extended according with the new token.
Messages Format
Both outbound and inbound messages are formatted using JSON standard.
Every outbound & inbound JSON message follows the following format:
{
"requestId": string,
"type": string,
"payload": object
}
where:
- requestId - a unique string identifying the request; it's recommended that UUID is used for populating this field. The value N/A is reserved for protocol usage.
- type - a string indicating the message type
- payload - an object holding additional data, based on the message type
For outbound messages, the requestId
value will be the same as the one used in generating the
request (except for the ProtocolError. Those are returning the
requestId
as "N/A").
Inbound Messages
Subscribe
Request streaming data for a symbol.
Message Payload
Examples
Here is a code sample for Level1:
{
"requestId": "96113dcc-734d-42d3-b347-965a4218e0a2",
"type": "Subscribe",
"payload": {
"symbol": "FX-BTC/USD=GEMINI",
"type": "Level1"
}
}
Here is a code sample for Level2:
{
"requestId": "1e668db8-0eab-4468-8c50-bbae26b73de2",
"type": "Subscribe",
"payload": {
"symbol": "FUT-BTC/JPY-2018JUN30=BITFLYER",
"type": "Level2"
}
}
{
"symbol": string,
"symbolType": string, // (optional)
"type": string,
"numberOfLevels": integer, // (optional)
"conflation": string // (optional)
}
Where:
- symbol - the symbol for which market data is requested
- symbolType - each symbol can be identified by multiple code types (if none specified,
Caspian
will be used): - Pseudo - symbol example:
BTCUSDT=BINANCE
- Caspian - symbol example:
FX-BTC/USDT=BINANCE
- Tora - symbol example:
FX.NULL.FOREX.BNANCE.NUL.BTCUST
- type
- Level1 - for trade and quote data
- Level2 - for depth data
- numberOfLevels - the number of levels for depth. Default value is 20. Max value is 100.
- conflation - if the
conflation
value will be different thanNone
, updates will be conflated and only sent at the specified time interval. Default value is 330ms. - None
- 250ms
- 330ms
- 500ms
- 1s
- 3s
- 5s
Associated Outbound Message Types
Unsubscribe
Description
Terminate an active streaming request, based on the original request ID
Message Payload
Example
{
"requestId": "45953af9-e9fc-4809-8974-fb1badc022ee",
"type": "Unsubscribe",
"payload": {
"subscribeRequestId": "96113dcc-734d-42d3-b347-965a4218e0a2"
}
}
{
"subscribeRequestId": string
}
where:
- subscribeRequestId - the request ID of the subscribe message
Associated Outbound Message Types
Token Refresh
Description
Replace the expiring token with the newly generated one
Message Payload
Examples
{
"requestId": "96113dcc-734d-42d3-b347-965a4218e0a2",
"type": "TokenRefresh",
"payload": {
"accessToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJSZWFsVGltZUFQSSIsImlzcyI6IkNhc3BpYW4gVGVjaCIsImV4cCI6MTY0MTg5OTE0NH0.0YItnz0Uwc3Gf11IKHAuzeO_c5N1LZb__S51OQwh-NY"
}
}
{
"accessToken": string
}
where:
- accessToken - the new generated token to be used for the connection with the service
Associated Outbound Message Types
Outbound Messages
ProtocolError
Description
Sent by the service when a received message is not properly formatted. The requestId of this message is always N/A
.
Message Payload
Example
{
"requestId": "N/A",
"type": "ProtocolError",
"payload": {
"code": 100,
"message": "Request was not properly formatted as JSON"
}
}
{
"code": int,
"message": string
}
where:
- code - an integer identifying the error; possible values are:
- 100 - request not properly formatted as JSON
- 101 - no requestId found in the message
- 102 - no type found in the message
- 103 - unknown type
- 104 - no accessToken found in the message
- 105 - no subscribeRequestId found in the message
- 199 - server could not process the request
- message - a descriptive text for the error
SubscribeResponse
Description
Sent by the service to confirm the status of a subscription received from the user.
Message Payload
Example
{
"requestId": "96113dcc-734d-42d3-b347-965a4218e0a2",
"type": "SubscribeResponse",
"payload": {
"code": 200,
"message": "All OK"
}
}
{
"code": int,
"message": string
}
where:
- code - an integer identifying the error; possible values are:
- 200 - All OK
- 201 - Duplicated Request ID
- 202 - Invalid subscription symbol
- 203 - Invalid subscription type
- 204 - Another subscription already exists
- 205 - Not authorized
- 206 - Subscription limit reached
- 207 - Invalid symbol type
- 208 - Invalid number of levels
- 209 - Symbol type not currently supported
- message - a descriptive text for the error
UnsubscribeResponse
Description
Sent by the service to confirm the status of an unsubscription received from the user.
Message Payload
Example
{
"requestId": "45953af9-e9fc-4809-8974-fb1badc022ee",
"type": "UnsubscribeResponse",
"payload": {
"code": 300,
"message": "All OK"
}
}
{
"code": int,
"message": string,
}
where:
- code - an integer identifying the error; possible values are:
- 300 - All OK
- 301 - Subscription not found
- 302 - Duplicated requestId
- message - a descriptive text for the error
Level1
Example
{
"requestId": "96113dcc-734d-42d3-b347-965a4218e0a2",
"type": "Level1",
"bboStream": "connected",
"tradeStream": "connected",
"payload":
{
"ask": 7641.12630702,
"askSize": 8.793364,
"bid": 7631.49215744,
"bidSize": 0.27087741,
"bboExchangeTimestamp": "2018-06-08T08:13:44.653000",
"bboCaspianTimestamp": "2018-06-08T08:13:44.683000",
"tradePrice": 7641.14468713,
"tradeSize": 0.00826056,
"tradeExchangeTimestamp": "2018-06-08T08:13:46.653000",
"tradeCaspianTimestamp": "2018-06-08T08:13:46.683000"
}
}
Description
Contains Level1 data updates for a subscription made by the client.
The initial update could contain only a part of the fields mentioned according to their availability.
A recurrent case is when BBO fields are available, but not the Trade fields, therefore only the available fields would be shown.
The Level1 JSON message follows the following format:
{
"requestId": string,
"type": string,
"bboStream": string,
"tradeStream": string,
"payload": object
}
where:
- requestId - a unique string identifying the request; it's recommended that UUID is used for populating this field. The value N/A is reserved for protocol usage.
- type - a string indicating the message type, in this case "Level1"
- bboStream - a string with values either 'connected' or 'disconnected', indicating the status of the underlying provider or exchange BestBidOffer (bbo) connection. This status field concerns the following fields:
- ask
- askSize
- bid
- bidSize
- bboExchangeTimestamp
- bboCaspianTimestamp
- tradeStream - a string with values either 'connected' or 'disconnected', indicating the status of the underlying provider or exchange trade connection. This status field concerns the following fields:
- tradePrice
- tradeSize
- tradeExchangeTimestamp
- tradeCaspianTimestamp
- tradeId
- exchangeSpecificInfo
- payload - an object holding additional data, based on the message type
Message Payload
Example exchangeSpecificInfo
{
"requestId": "96113dcc-734d-42d3-b347-965a4218e0a3",
"type": "Level1",
"payload":
{
"exchangeSpecificInfo":
{
"buy_child_order_acceptance_id": "JRF20181210-133622-783108",
"sell_child_order_acceptance_id": "JRF20181210-133622-670019",
"side": "BUY"
}
}
}
{
"ask": double,
"askSize": double,
"bid": double,
"bidSize": double,
"bboExchangeTimestamp": string,
"bboCaspianTimestamp": string,
"tradePrice": double,
"tradeSize": double,
"tradeExchangeTimestamp": string,
"tradeCaspianTimestamp": string,
"tradeId": string,
"exchangeSpecificInfo": {
string : string
...
}
}
where:
- ask - the last ask price
- askSize - the last ask size
- bid - the last bid price
- bidSize - the last bid size
- bboExchangeTimestamp - the time of the last bid / ask update (expressed in YYYY-MM-DDTHH:MM:SS.mmmmmm) reported by the exchange. If not available, this field is absent
- bboCaspianTimestamp - the time of the last bid / ask update (expressed in YYYY-MM-DDTHH:MM:SS.mmmmmm) received by Caspian
- tradePrice - the last traded price
- tradeSize - the last traded size
- tradeExchangeTimestamp - the time of the last trade (expressed in YYYY-MM-DDTHH:MM:SS.mmmmmm) reported by exchange. If not available, this field is absent
- tradeCaspianTimestamp - the receive time of the last trade (expressed in YYYY-MM-DDTHH:MM:SS.mmmmmm) received by Caspian
- tradeId - the last traded id
- exchangeSpecificInfo - is a map of string and string that contains specific values for a particular exchange; see examples in the code section
Level2
Description
Contains Level2 data updates for a subscription made by the client. The payload is an array of objects.
First update may include only the stream status field with an empty payload. The client should expect the next
non-empty payload messages to contain the Level2 actual array of objects necessary for constructing the depth.
The Level2 JSON message follows the following format:
{
"requestId": string,
"type": string,
"exchangeTimestamp": string,
"caspianTimestamp": string,
"depthStream": string,
"payload": object
}
where:
- requestId - a unique string identifying the request; it's recommended that UUID is used for populating this field. The value N/A is reserved for protocol usage.
- type - a string indicating the message type, in this case "Level2"
- exchangeTimestamp - the time of the last Level2 update (expressed in YYYY-MM-DDTHH:MM:SS.mmmmmm) reported by the exchange. If not available, this field is absent
- caspianTimestamp - the time of the last Level2 update (expressed in YYYY-MM-DDTHH:MM:SS.mmmmmm) received by Caspian
- depthStream - a string with values either 'connected' or 'disconnected', indicating the status of the underlying provider or exchange depth connection
- payload - an object holding additional data, based on the message type
Message Payload
Example
{
"requestId": "45953af9-e9fc-4809-8974-fb1badc022ee",
"type": "Level2",
"exchangeTimestamp": "2018-06-08T08:13:46.653000",
"caspianTimestamp": "2018-06-08T08:13:46.683000",
"depthStream": "connected",
"payload": [
{
"price": 74999,
"size": 2,
"side": "ask"
},
{
"price": 74681,
"size": 0.55,
"side": "bid"
},
{
"price": 73101,
"size": 0,
"side": "bid"
}
]
}
[
{
"price": double,
"size": double,
"side": string
}
]
where:
- price - the price level for the array entry
- size - the size for the array entry:
- A non-zero size translates to a change of size for a specific price level, on provided side
- A zero size means that the specified price level no longer contains orders
- side - the side for the array entry; can be ask or bid
TokenRefreshResponse
Description
Sent by the service to confirm the status of a TokenRefresh request.
Message Payload
Example
{
"requestId": "96113dcc-734d-42d3-b347-965a4218e0a2",
"type": "TokenRefreshResponse",
"payload": {
"code": 200,
"message": "All OK"
}
}
{
"code": int,
"message": string
}
where:
- code - an integer identifying the error; possible values are:
- 200 - All OK
- 202 - Access Token is invalid.
- 203 - Access Token has expired.
- 204 - Request ID is duplicated.
- message - a descriptive text for the error
Reference Data
Exchanges
Description
An endpoint to return all available exchanges.
Request
Request URL: https://sandbox.api.caspian.tech/v1/refdata/exchanges
Request Method: GET
Possible responses
Success
Status Code: 200
Content-Type: application/json
Content:
Example response:
[
{
"name": "BitMEX",
"code": "BITMEX"
},
{
"name": "Coin Market Cap",
"code": "COINMKTCAP"
},
{
"name": "Gemini",
"code": "GEMINI"
}
]
[
{
"name:" string,
"code:" string
},
{
"name:" string,
"code:" string
},
...
{
"name:" string,
"code:" string
}
]
Where:
- name - exchange name
- code: - exchange code
Internal Server Error
Here is a sample of a response:
{
"code": 5001,
"message": "Could not access the database"
}
Meaning: The request is properly formatted but the server was unable to fulfill it due to an internal error.
Status Code: 500
Content-Type: application/json
Content:
{
"code": int,
"message": string
}
Products
Description
An endpoint to return all products of a certain exchange.
Request
Request URL: https://sandbox.api.caspian.tech/v1/refdata/products
Request Method: POST
Content-Type: application/json
Content:
Example:
{
"exchanges": ["GEMINI"]
}
{
"exchanges": [
string
]
}
where:
- exchanges - the list of the exchanges that the products would be provided for
Response
Success
Status Code: 200
Content-Type: application/json
Content:
Here is a sample of Success response:
[
{
"caspianCode": "FX-ETH/USD=GEMINI",
"ccyFrom": "ETH",
"ccyTo": "USD",
"toraMarket": "FX.NULL.FOREX.GEMINI.NUL",
"toraCode": "FX.NULL.FOREX.GEMINI.NUL.ETHUSD",
"description": "Ethereum - US Dollar - FX pair",
"lotSize": "0.000001",
"nativeCode": "ethusd",
"tickRule": ",,0.01",
"pseudoCode": "ETHUSD=GEMINI",
"createdTime": "2018-01-18T03:13:55.000000",
"updatedTime": "2019-11-28T15:56:30.204000",
"exchange": "GEMINI"
}
]
[
{
"toraCode": string,
"toraMarket": string,
"caspianCode": string,
"lotSize": string,
"pseudoCode": string,
"createdTime": string,
"updatedTime": string,
"ccyFrom": string,
"ccyTo": string,
"nativeCode": string,
"tickRule": string,
"description": string,
"exchange": string,
"multiplier": string,
"lastTradingDate": string,
"expireDate": string,
"type": string,
"strike": string,
"underlyingCaspianCode": string,
"nativeCode_v2": string
}
]
Bad Request
Here is a sample of a Bad Request response:
{
"code": 4001,
"message": "No exchange specified"
}
Meaning: The request body contains an invalid JSON or it is missing the required attributes.
Status Code: 400
Content-Type: application/json
Content:
{
"code": int,
"message": string
}
Internal Server Error
Here is a sample of Internal Server Error response:
{
"code": 5001,
"message": "Could not access the database"
}
Meaning: The request is properly formatted but the server was unable to fulfill it due to an internal error.
Status Code: 500
Content-Type: application/json
Content:
{
"code": int,
"message": string
}
Details of a product
Description
An endpoint to get the details of a certain product.
Request
Request URL: https://sandbox.api.caspian.tech/v1/refdata/product/${caspianProduct}
Request Method: GET
Content-Type: application/json
Content:
Request example for caspian code "FX-LTC/ETH=GEMINI":
https://sandbox.api.caspian.tech/v1/refdata/product/FX-LTC/ETH=GEMINI
Response
Success
Status Code: 200
Content-Type: application/json
Content:
Here is a sample of Success response:
[
{
"caspianCode": "FX-LTC/ETH=GEMINI",
"ccyFrom": "LTC",
"ccyTo": "ETH",
"toraMarket": "FX.NULL.FOREX.GEMINI.NUL",
"toraCode": "FX.NULL.FOREX.GEMINI.NUL.LTCETH",
"description": "Litecoin - Ethereum - FX pair",
"lotSize": "1",
"nativeCode": "ltceth",
"pseudoCode": "LTCETH=GEMINI",
"createdTime": "2018-10-13T00:24:04.000000",
"updatedTime": "2019-11-28T15:56:30.269000",
"exchange": "GEMINI"
}
]
[
{
"toraCode": string,
"toraMarket": string,
"caspianCode": string,
"lotSize": string,
"pseudoCode": string,
"createdTime": string,
"updatedTime": string,
"ccyFrom": string,
"ccyTo": string,
"nativeCode": string,
"tickRule": string,
"description": string,
"exchange": string,
"multiplier": string,
"lastTradingDate": string,
"expireDate": string,
"type": string,
"strike": string,
"underlyingCaspianCode": string,
"nativeCode_v2": string
}
]
Bad Request
Here is a sample of a Bad Request response:
{
"code": 4001,
"message": "No product specified"
}
Meaning: The request body contains an invalid JSON or it is missing the required attributes.
Status Code: 400
Content-Type: application/json
Content:
{
"code": int,
"message": string
}
Internal Server Error
Here is a sample of Internal Server Error response:
{
"code": 5001,
"message": "Could not access the database"
}
Meaning: The request is properly formatted but the server was unable to fulfill it due to an internal error.
Status Code: 500
Content-Type: application/json
Content:
{
"code": int,
"message": string
}
Changelog
All notable changes to this project are documented here.
2020-06-10
Added
- Fields bboStream and tradeStream (with possible values connected or disconnected) at Level1 updates here
- Field depthStream (with possible values connected or disconnected) at Level2 updates here
2019-02-20
Added
- A heartbeat of 15 sec was implemented. The server will send ping frames that should be handled at client level library.
Although PINGs are handled, the client should ensure that this is the case, otherwise is needed to handle the PING frames and acknowledge them with PONG frames.
Due to the heartbeat mechanism in case PINGs are not acknowledge, the session will get disconnected.
- A queueing per each session was implemented, such that slow clients for which the queue accumulates up to 50k messages will get disconnected. Due to the heartbeat and queueing per each session mechanisms client's application should implement recovery from possible disconnects.
- Pseudo codes symbol type here
- Optional conflation parameter that can be specified in subscription here
- Fields tradeID and exchangeSpecificInfo at Level1 updates here
- Fields createdTime and updatedTime here
Changed
- Changed access_token to accessToken here
- The default symbolType has been changed to Caspian here
- Renamed tradeTime from Level1 updates to tradeExchangeTimestamp here
FAQ
There might be 2 causes for this:
1) There is a heartbeat mechanism. The server will send ping frames that should be handled at client level library.
In case PINGs are not acknowledge, the session will get disconnected. Make sure those pings are handled,
otherwise is needed to handle the PING frames and acknowledge them with PONG frames.
2) Slow clients are disconnected as a result of the threshold setted for accumulated messages.
Please discuss this with your Caspian representative.
Supported exchanges: Binance, Bitfinex, Bitflyer, Bithumb, Bitmex, Bitstamp, Bittrex, BTCC, CEX, Coinbase Pro (GDAX),
CoinOne, Deribit, Gemini, Hitbtc, Huobi, ItBit, Korbit, Kraken, Kucoin, Liquid, OKEx, Poloniex
The API is down on Sunday between 00:15 and 00:16 GMT.
Every timestamp is represented as GMT.
Please discuss these details with your Caspian representative.
The access token expires after 24 hours. You have to obtain a new access token following the steps described in section
Authentication - REST
New fields could be added without prior notice. The implementation should be resilient to such changes.
For questions not covered in this FAQ please send an email to api@caspian.tech.
Errors
The Caspian API uses the following error codes:
Error Code | Meaning |
---|---|
100 | Request not properly formatted as JSON |
101 | No requestId found in the message |
102 | No type found in the message |
103 | Unknown type |
104 | No accessToken found in the message |
105 | No subscribeRequestId found in the message |
199 | Server could not process the request |
200 | All OK |
201 | Duplicated Request ID |
202 | Invalid subscription symbol |
203 | Invalid subscription type |
204 | Another subscription already exists |
205 | Not authorized |
206 | Subscription limit reached |
207 | Invalid symbol type |
208 | Invalid number of levels |
209 | Symbol type not currently supported |
300 | All OK |
301 | Subscription not found |
302 | Duplicated requestId |
400 | Bad Request |
401 | Unauthorized |
500 | Internal Server Error |
3000 | Access token not found |
3001 | Supplied token is not valid |
3002 | Token has expired |
3003 | The handler for this session was not found |
3004 | Internal issue |
3006 | Pong message not received |
3007 | Message queue limit reached |
4000 | Request is not properly formatted |
4001 | Authentication type not found |
4002 | Authentication details not found |
4003 | Unsupported authentication type |