├── .gitignore ├── assets ├── auth.jpg ├── results.png └── orderbooks.png ├── CHANGELOG.md ├── README.md ├── Public-RestAPI.md ├── Deadman-switch.md ├── example └── Private-RestAPI-php.md ├── Marketdata-websocket.md ├── Private-websocket.md └── Private-RestAPI.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | -------------------------------------------------------------------------------- /assets/auth.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/btcid/indodax-official-api-docs/HEAD/assets/auth.jpg -------------------------------------------------------------------------------- /assets/results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/btcid/indodax-official-api-docs/HEAD/assets/results.png -------------------------------------------------------------------------------- /assets/orderbooks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/btcid/indodax-official-api-docs/HEAD/assets/orderbooks.png -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG for Indodax's API (2019-10-14) 2 | --- 3 | ## 2019-10-14 4 | * New K-Line Web Socket. See `kline-websocket.md` for details. 5 | * New Public Rest API. See `Public-RestAPI.md` for details. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Official Documentation for the Indodax APIs and Streams. 2 | 3 | * Streams, endpoints, parameters, payloads, etc. described in the documents in this repository are considered **official** and **supported**. 4 | * The use of any other streams, endpoints, parameters, or payloads, etc. is **not supported**; **use them at your own risk and with no guarantees.** 5 | 6 | 7 | Name | Description | Example | Version 8 | ------------ | ------------ | ------------ | ------------ 9 | [Public REST API](./Public-RestAPI.md) | Public API Documentation | | 10 | [Private REST API](./Private-RestAPI.md) | Private API Documentation | [PHP](./example/Private-RestAPI-php.md) | v2.0.1 11 | [Market Data WebSocket](./Marketdata-websocket.md) | Market Data WebSocket Documentation | | 12 | [Private WebSocket](./Private-websocket.md) | Private WebSocket Documentation | | 13 | [Deadman Switch](./Deadman-switch.md) | Deadman Switch Documentation | | 14 | -------------------------------------------------------------------------------- /Public-RestAPI.md: -------------------------------------------------------------------------------- 1 | # Public REST API 2 | These are open data for public. It doesn't need an API key to call these methods. You can call simple GET request or open it directly from the browser. 3 | #### Table of Contents 4 | - [General API Information](#general-api-information) 5 | - [Limit](#limit) 6 | - [API](#api) 7 | - [/api/server_time](#server-time) 8 | - [/api/pairs](#pairs) 9 | - [/api/price_increments](#price-increments) 10 | - [/api/summaries](#summaries) 11 | - [/api/ticker/$pair_id](#ticker) 12 | - [/api/ticker_all](#ticker-all) 13 | - [/api/trades/$pair_id](#trades) 14 | - [/api/depth/$pair_id](#depth) 15 | 16 | 17 | ## General API Information 18 | - The base endpoint is: https://indodax.com 19 | - All endpoints return either a JSON object or array. 20 | - All time and timestamp related fields are in milliseconds. 21 | 22 | ## Limit 23 | Public API rate limited to 180request/minute. 24 | 25 | ## Server Time 26 | Provide server time on exchange 27 | #### Request 28 | ``` 29 | /api/server_time 30 | ``` 31 | #### Response 32 | ```json 33 | { 34 | "timezone": "UTC", 35 | "server_time": 1571205969552 36 | } 37 | ``` 38 | 39 | ## Pairs 40 | Provide available pairs on exchange 41 | #### Request 42 | ``` 43 | /api/pairs 44 | ``` 45 | #### Response 46 | ```json 47 | [ 48 | { 49 | "id": "btcidr", 50 | "symbol": "BTCIDR", 51 | "base_currency": "idr", 52 | "traded_currency": "btc", 53 | "traded_currency_unit": "BTC", 54 | "description": "BTC/IDR", 55 | "ticker_id": "btc_idr", 56 | "volume_precision": 0, 57 | "price_precision": 1000, 58 | "price_round": 8, 59 | "pricescale": 1000, 60 | "trade_min_base_currency": 50000, 61 | "trade_min_traded_currency": 0.0001, 62 | "has_memo": false, 63 | "memo_name": false, 64 | "url_logo": "https://indodax.com/v2/logo/svg/color/btc.svg", 65 | "url_logo_png": "https://indodax.com/v2/logo/png/color/btc.png" 66 | } 67 | ] 68 | ``` 69 | 70 | ## Price Increments 71 | Provide price increments of each pairs on exchange 72 | #### Request 73 | ``` 74 | /api/price_increments 75 | ``` 76 | #### Response 77 | ```json 78 | { 79 | "increments": { 80 | "btc_idr": "1000", 81 | "ten_idr": "1", 82 | "abyss_idr": "1", 83 | "act_idr": "1", 84 | "ada_idr": "1" 85 | } 86 | } 87 | ``` 88 | 89 | ## Summaries 90 | Provide summary information for the pairs 91 | #### Request 92 | ``` 93 | /api/summaries 94 | ``` 95 | #### Response 96 | ```json 97 | { 98 | "tickers": { 99 | "btc_idr": { 100 | "high": "120009000", 101 | "low": "116735000", 102 | "vol_btc": "218.31103295", 103 | "vol_idr": "25831203178", 104 | "last": "117136000", 105 | "buy": "116938000", 106 | "sell": "117136000", 107 | "server_time": 1571206340, 108 | "name": "Bitcoin" 109 | } 110 | }, 111 | "prices_24h": { 112 | "btcidr": "120002000", 113 | "tenidr": "521", 114 | "abyssidr": "148", 115 | "actidr": "125", 116 | "adaidr": "592" 117 | }, 118 | "prices_7d": { 119 | "btcidr": "116001000", 120 | "tenidr": "517", 121 | "abyssidr": "147", 122 | "actidr": "128", 123 | "adaidr": "580" 124 | }, 125 | } 126 | ``` 127 | 128 | ## Ticker 129 | Provide Single Ticker Price on each pair in exchange 130 | #### Request 131 | ``` 132 | /api/ticker/$pair_id 133 | ``` 134 | ##### Parameter 135 | | Type | Mandatory | Description | 136 | | ------ | ------ | ------ | 137 | | String | Optional| Example: `btdidr`, `tenidr`, `ethidr`. For specific pair id please use Response from API [`/api/pairs`](#pairs). Default `$pair_id` is `btcidr`. | 138 | 139 | #### Response 140 | ```json 141 | { 142 | "ticker": { 143 | "high": "523", 144 | "low": "505", 145 | "vol_ten": "153588.49847928", 146 | "vol_idr": "78884203", 147 | "last": "511", 148 | "buy": "511", 149 | "sell": "512", 150 | "server_time": 1571207668 151 | } 152 | } 153 | ``` 154 | 155 | ## Ticker All 156 | Provide All Ticker Prices in exchange 157 | #### Request 158 | ``` 159 | /api/ticker_all 160 | ``` 161 | #### Response 162 | ```json 163 | { 164 | "tickers": { 165 | "btc_idr": { 166 | "high": "120009000", 167 | "low": "116735000", 168 | "vol_btc": "218.13777777", 169 | "vol_idr": "25800033297", 170 | "last": "117088000", 171 | "buy": "117002000", 172 | "sell": "117078000", 173 | "server_time": 1571207881 174 | } 175 | } 176 | } 177 | ``` 178 | 179 | ## Trades 180 | Provide transaction Information from all pairs/selected pair 181 | #### Request 182 | ``` 183 | /api/trades/$pair_id 184 | ``` 185 | ##### Parameter 186 | | Type | Mandatory | Description | 187 | | ------ | ------ | ------ | 188 | | String | Optional| Example: `btdidr`, `tenidr`, `ethidr`. For specific pair id please use Response from API [`/api/pairs`](#pairs). Default `$pair_id` is `btcidr`. | 189 | 190 | #### Response 191 | ```json 192 | [ 193 | { 194 | "date": "1571207255", 195 | "price": "511", 196 | "amount": "123.19523759", 197 | "tid": "1623490", 198 | "type": "sell" 199 | }, 200 | { 201 | "date": "1571207236", 202 | "price": "512", 203 | "amount": "121.42187500", 204 | "tid": "1623489", 205 | "type": "buy" 206 | } 207 | ] 208 | ``` 209 | 210 | ## Depth 211 | Provide Volume price Buy and Sell on each pair in exchange 212 | #### Request 213 | ``` 214 | /api/depth/$pair_id 215 | ``` 216 | ##### Parameter 217 | | Type | Mandatory | Description | 218 | | ------ | ------ | ------ | 219 | | String | Optional| Example: `btdidr`, `tenidr`, `ethidr`. For specific pair id please use Response from API [`/api/pairs`](#pairs). Default `$pair_id` is `btcidr`. | 220 | #### Response 221 | ```json 222 | { 223 | "buy": [ 224 | [ 225 | 511, 226 | "176.61056751" 227 | ], 228 | [ 229 | 510, 230 | "100.00000000" 231 | ] 232 | ], 233 | "sell": [ 234 | [ 235 | 512, 236 | "1591.21213341" 237 | ], 238 | [ 239 | 513, 240 | "0.88109162" 241 | ] 242 | ] 243 | } 244 | ``` 245 | 246 | ## OHLC History 247 | Provide OHLC (Open, High, Low, Close) Charting History Information for pairs 248 | #### Request 249 | ``` 250 | /tradingview/history_v2?from=1698742200&symbol=$pair_id&tf=15&to=1699347009 251 | ``` 252 | ##### Parameter 253 | | Name | Type | Mandatory | Description | 254 | | ------ | ------ | ------ | ------ | 255 | | from | Int | Required| beginning of time frame (unixtimestamp), Example: 1698742200 | 256 | | to | Int | Required| end of time frame (unixtimestamp), Example: 1699347009 | 257 | | tf | String | Required| time frame range in minute, day, or week (see [`Timeframe List`](#timeframe-list)) | 258 | | symbol | String | Required| Example: `BTCIDR`, `ETHIDR`, `IDXIDR`. For specific pair id please use Response from API [`/api/pairs`](#pairs) | 259 | 260 | ##### Timeframe List 261 | | Value | Description | 262 | | ------ | ------ | 263 | | 1 | 1 minute time frame | 264 | | 15 | 15 minute time frame | 265 | | 30 | 30 minute time frame | 266 | | 60 | 60 minute / 1 Hour time frame | 267 | | 240 | 240 minute / 4 Hours time frame | 268 | | 1D | 1 Day time frame | 269 | | 3D | 3 Day time frame | 270 | | 1W | 1 Week time frame | 271 | 272 | #### Response 273 | ```json 274 | [ 275 | { 276 | "Time": 1699328700, 277 | "Open": 0.9999, 278 | "High": 0.9999, 279 | "Low": 0.9999, 280 | "Close": 0.9999, 281 | "Volume": "14814.00000000" 282 | }, 283 | { 284 | "Time": 1699329600, 285 | "Open": 0.9996, 286 | "High": 0.9996, 287 | "Low": 0.9996, 288 | "Close": 0.9996, 289 | "Volume": "12359.00000000" 290 | }, 291 | { 292 | "Time": 1699330500, 293 | "Open": 0.9996, 294 | "High": 0.9996, 295 | "Low": 0.9996, 296 | "Close": 0.9996, 297 | "Volume": "0" 298 | }, 299 | ] 300 | ``` 301 | -------------------------------------------------------------------------------- /Deadman-switch.md: -------------------------------------------------------------------------------- 1 | # Deadman Switch Documentation 2 | 3 | **Table of Contents** 4 | - [General Information](#general-information) 5 | - [Base URL](#base-url) 6 | - [Headers](#headers) 7 | - [API Endpoint](#api-endpoint) 8 | - [SIGN Endpoint Security ](#sign-endpoint-security) 9 | - [Example](#example) 10 | - [Using Query String + URL Encoded](#using-query-string--url-encoded) 11 | - [Using Request Body](#using-request-body) 12 | - [POST /countdownCancelAll](#post-countdowncancelall) 13 | - [Request Parameters](#request-parameters) 14 | - [Response](#response) 15 | - [Error Codes](#error-codes) 16 | 17 | ## General Information 18 | This rest endpoint means to ensure your open orders are canceled in case of an outage. The endpoint should be called repeatedly as heartbeats so that the existing countdown time can be canceled and replaced by a new one. 19 | 20 | Example, you call this endpoint at 30s intervals with an `countdownTime` of 120000 (120s). If this endpoint is not called within 120 seconds, all your orders of the specified symbol will be automatically canceled. If this endpoint is called with an `countdownTime` of 0, the countdown timer will be stopped. 21 | 22 | The system will check all countdowns **approximately every 10 milliseconds**, so please note that sufficient redundancy should be considered when using this function. We do not recommend setting the countdown time to be too precise or too small. 23 | 24 | **Additional Notes :** 25 | * All `recvWindow` and `timestamp` related fields are in **milliseconds**. 26 | * All endpoints return a JSON object. 27 | * URL Ratelimit 10 requests per 10 seconds per IP. 28 | 29 | ### Base URL 30 | | **Environment** | **Base URL** | **Description** | 31 | | ---------------- | ------------------------------ | --------------------------------------------------------------------------------------------------------- | 32 | | Production | https://indodax.com/tapi, https://btcapi.net/tapi | Access for production. | 33 | | Demo | https://demo-indodax.com/tapi | Access for demo. | 34 | 35 | ### Headers 36 | 37 | | Name | Value | Description | 38 | | ---------------| -------------------------------------- | ----------------------------------------------- | 39 | | `Key` | `{{tapi-key}}` | The API key for authentication. | 40 | | `Sign` | `{{sign}}` (using HMAC SHA512) | The signature for request validation. | 41 | | `Content-Type` | `text/plain` | The type of content being sent in the request. | 42 | 43 | ## API Endpoint 44 | 45 | ### SIGN Endpoint Security 46 | * `SIGNED` endpoints require an additional parameter `Sign`, to be 47 | sent in the `header`. 48 | * Endpoints use `HMAC SHA512` signatures. 49 | Use your `Key` as the key and `totalParams` as the value for the HMAC operation. 50 | * The `signature` is **not case sensitive**. 51 | * `totalParams` is defined as the `query string` concatenated with the 52 | `request body`. 53 | 54 | #### **Example** 55 | Here is a step-by-step example of how to send a vaild signed payload from the 56 | Linux command line using `curl`. 57 | 58 | | Key | Value 59 | |--|--| 60 | | `apiKey` | LSCE7NJG-JACRNTBX-D834R4UG-KMMTV8OP-PS1NHRBA 61 | | `secretKey` | da78a39e9dda31c399bcc293d997a347dc7fd0408cb5151931243a302b273ec3238510ea61e11f7c 62 | 63 | | Parameter | Value | Description | 64 | |--|--|--| 65 | |`pair`| btc_idr,eth_idr | To get available pairs, access the [api/pairs](./Public-RestAPI.md#pairs) endpoint and use the `ticker_id` values. 66 | |`countdownTime`| 10000| Field in milliseconds 67 | |`timestamp`| 1578304294001 | Field in milliseconds 68 | |`recvWindow`| 1578303937000 | Field in milliseconds 69 | 70 | #### **Using Query String + URL Encoded** 71 | 72 | Generate the HMAC SHA512 signature using the query string: 73 | 74 | ```bash 75 | ➜ echo -n "pair=btc_idr%2Ceth_idr&countdownTime=10000×tamp=1578304294001&recvWindow=1578303937000" | openssl dgst -sha512 -hmac "da78a39e9dda31c399bcc293d997a347dc7fd0408cb5151931243a302b273ec3238510ea61e11f7c" 76 | SHA2-512(stdin)= 29ff89378b9f33954b0f5319488190078f091c7723d886c5c2a4a0b06ef793d7d3b99155d63410203a21355e5e2757cb4e566adbd67ec37b8257a68d8c72877c 77 | ``` 78 | Perform the API request using curl: 79 | ```bash 80 | curl --location -X POST 'https://demo-indodax.com/tapi/countdownCancelAll?pair=btc_idr%2Ceth_idr&countdownTime=10000×tamp=1578304294001&recvWindow=1578303937000' \ 81 | --header 'Key: LSCE7NJG-JACRNTBX-D834R4UG-KMMTV8OP-PS1NHRBA' \ 82 | --header 'Sign: 29ff89378b9f33954b0f5319488190078f091c7723d886c5c2a4a0b06ef793d7d3b99155d63410203a21355e5e2757cb4e566adbd67ec37b8257a68d8c72877c' 83 | ``` 84 | 85 | #### **Using Request Body** 86 | Generate the HMAC SHA512 signature using the request body: 87 | ```bash 88 | ➜ echo -n "pair=btc_idr,eth_idr&countdownTime=10000×tamp=1578304294001&recvWindow=1578303937000" | openssl dgst -sha512 -hmac "da78a39e9dda31c399bcc293d997a347dc7fd0408cb5151931243a302b273ec3238510ea61e11f7c" 89 | SHA2-512(stdin)= b4f03574d264ffbaa37eadd8460f50dbb9ae6f12d4852a46d8654d472838aaa1de99248e958c904333e61738a00462d49f32bcd3258d8a3defca8c73b8d60d09 90 | ``` 91 | Perform the API request using curl: 92 | 93 | ```bash 94 | curl --location -X POST 'https://demo-indodax.com/tapi/countdownCancelAll' \ 95 | --header 'Key: LSCE7NJG-JACRNTBX-D834R4UG-KMMTV8OP-PS1NHRBA' \ 96 | --header 'Sign: b4f03574d264ffbaa37eadd8460f50dbb9ae6f12d4852a46d8654d472838aaa1de99248e958c904333e61738a00462d49f32bcd3258d8a3defca8c73b8d60d09' \ 97 | --header 'Content-Type: text/plain' \ 98 | --data 'pair=btc_idr,eth_idr&countdownTime=10000×tamp=1578304294001&recvWindow=1578303937000' 99 | ``` 100 | 101 | ### POST /countdownCancelAll 102 | Cancel all open orders of the specified pair at the end of the specified countdown. 103 | 104 | ### **Request Parameters** 105 | 106 | You can choose to fill either the `nonce` field or the `recvWindow` and `timestamp` fields. 107 | 108 | | Parameter | Type | Mandatory | Description | 109 | | --------------- | -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | 110 | | `countdownTime` | `integer` | Optional (default: `5000`) | Countdown time in milliseconds. Use `1000` for 1 second. Set to `0` to cancel the timer. | 111 | | `pair` | `string` | Required | Specifies the trading pair(s). Use a comma separator for multiple pairs. Example values: `btc_idr`, `btc_idr,eth_idr`, `btc_idr%2Ceth_idr` (URL encoded). | 112 | | `timestamp` | `integer` | Optional (required if `nonce` is empty) | The millisecond timestamp of when the request was created and sent. | 113 | | `recvWindow` | `integer` | Optional (required if `nonce` is empty) | Specifies how many milliseconds after the timestamp the request is valid. The request is valid between `timestamp` and `timestamp + recvWindow`. Default is `5000` ms. | 114 | | `nonce` | `integer` | Optional (required if `timestamp` and `recvWindow` are empty) | An incremental integer. For example, if the last request's `nonce` was `1000`, the next request should be `1001` or a larger number. 115 | 116 | ### **Response** 117 | Success 118 | ```json 119 | "HttpCode": 200 120 | "Response Body": 121 | { 122 | "success": 1 123 | } 124 | ``` 125 | Error 126 | ```json 127 | "HttpCode": 200 128 | "Response Body": 129 | { 130 | "success": 0, 131 | "error": "API key not found in header", 132 | "error_code": "key_not_found" 133 | } 134 | ``` 135 | ### **Error Codes** 136 | | Error Code | Error Message | 137 | | ----------------------- | ------------------------------------------ | 138 | | `internal_server_error` | Failed to process request | 139 | | `internal_server_error` | Validation signature failed. | 140 | | `bad_request` | Pair `btc_idr` disabled | 141 | | `bad_request` | Invalid pair | 142 | | `bad_request` | Invalid countdown time | 143 | | `bad_request` | Pair is empty | 144 | | `sign_not_found` | Sign not found in header. | 145 | | `key_not_found` | API key not found in header. | 146 | | `bad_sign` | Invalid credentials. Bad sign. | 147 | -------------------------------------------------------------------------------- /example/Private-RestAPI-php.md: -------------------------------------------------------------------------------- 1 | **Table of Contents** 2 | - [Get Info](#get-info) 3 | - [Transaction History](#transaction-history) 4 | - [Trade](#trade) 5 | - [Trade History](#trade-history) 6 | - [Open Orders](#open-orders) 7 | - [Order History](#order-history) 8 | - [Get Order](#get-order) 9 | - [Cancel Order](#cancel-order) 10 | - [Withdraw Fee](#withdraw-fee) 11 | - [Withdraw Coin](#withdraw-coin) 12 | 13 | # Example Request By PHP 14 | ## Get Info 15 | Sample code below : 16 | ```php 17 | 'getInfo', 26 | 'timestamp' => '1578304294000', 27 | 'recvWindow' => '1578303937000' 28 | ]; 29 | $post_data = http_build_query($data, '', '&'); 30 | $sign = hash_hmac('sha512', $post_data, $secretKey); 31 | 32 | $headers = ['Key:'.$key,'Sign:'.$sign]; 33 | 34 | $curl = curl_init(); 35 | 36 | curl_setopt_array($curl, array( 37 | CURLOPT_HTTPHEADER => $headers, 38 | CURLOPT_URL => $url, 39 | CURLOPT_POST => true, 40 | CURLOPT_POSTFIELDS => $data, 41 | CURLOPT_RETURNTRANSFER => true 42 | )); 43 | 44 | $response = curl_exec($curl); 45 | 46 | curl_close($curl); 47 | echo $response; 48 | ``` 49 | 50 | ## Transaction History 51 | Sample code below : 52 | ```php 53 | 'transHistory', 62 | 'timestamp' => '1578304294000', 63 | 'recvWindow' => '1578303937000' 64 | ]; 65 | $post_data = http_build_query($data, '', '&'); 66 | $sign = hash_hmac('sha512', $post_data, $secretKey); 67 | 68 | $headers = ['Key:'.$key,'Sign:'.$sign]; 69 | 70 | $curl = curl_init(); 71 | 72 | curl_setopt_array($curl, array( 73 | CURLOPT_HTTPHEADER => $headers, 74 | CURLOPT_URL => $url, 75 | CURLOPT_POST => true, 76 | CURLOPT_POSTFIELDS => $data, 77 | CURLOPT_RETURNTRANSFER => true 78 | )); 79 | 80 | $response = curl_exec($curl); 81 | 82 | curl_close($curl); 83 | echo $response; 84 | ``` 85 | 86 | ## Trade 87 | Sample code below : 88 | ```php 89 | 'trade', 98 | 'timestamp' => '1578304294000', 99 | 'recvWindow' => '1578303937000', 100 | 'pair' => 'btc_idr', 101 | 'type' => 'sell', 102 | 'price' => '107202000', 103 | 'idr' => '', 104 | 'btc' => '0.00313482' 105 | ]; 106 | $post_data = http_build_query($data, '', '&'); 107 | $sign = hash_hmac('sha512', $post_data, $secretKey); 108 | 109 | $headers = ['Key:'.$key,'Sign:'.$sign]; 110 | 111 | $curl = curl_init(); 112 | 113 | curl_setopt_array($curl, array( 114 | CURLOPT_HTTPHEADER => $headers, 115 | CURLOPT_URL => $url, 116 | CURLOPT_POST => true, 117 | CURLOPT_POSTFIELDS => $data, 118 | CURLOPT_RETURNTRANSFER => true 119 | )); 120 | 121 | $response = curl_exec($curl); 122 | 123 | curl_close($curl); 124 | echo $response; 125 | ``` 126 | 127 | ## Trade History 128 | Sample code below : 129 | ```php 130 | 'tradeHistory', 139 | 'timestamp' => '1578304294000', 140 | 'recvWindow' => '1578303937000', 141 | 'count' => '', 142 | 'from_id' => '', 143 | 'end_id' => '', 144 | 'order' => '', 145 | 'since' => '', 146 | 'end' => '', 147 | 'pair' => '' 148 | ]; 149 | $post_data = http_build_query($data, '', '&'); 150 | $sign = hash_hmac('sha512', $post_data, $secretKey); 151 | 152 | $headers = ['Key:'.$key,'Sign:'.$sign]; 153 | 154 | $curl = curl_init(); 155 | 156 | curl_setopt_array($curl, array( 157 | CURLOPT_HTTPHEADER => $headers, 158 | CURLOPT_URL => $url, 159 | CURLOPT_POST => true, 160 | CURLOPT_POSTFIELDS => $data, 161 | CURLOPT_RETURNTRANSFER => true 162 | )); 163 | 164 | $response = curl_exec($curl); 165 | 166 | curl_close($curl); 167 | echo $response; 168 | ``` 169 | 170 | ## Open Orders 171 | Sample code below : 172 | ```php 173 | 'openOrders', 182 | 'timestamp' => '1578304294000', 183 | 'recvWindow' => '1578303937000', 184 | 'pair' => 'btc_idr' 185 | ]; 186 | $post_data = http_build_query($data, '', '&'); 187 | $sign = hash_hmac('sha512', $post_data, $secretKey); 188 | 189 | $headers = ['Key:'.$key,'Sign:'.$sign]; 190 | 191 | $curl = curl_init(); 192 | 193 | curl_setopt_array($curl, array( 194 | CURLOPT_HTTPHEADER => $headers, 195 | CURLOPT_URL => $url, 196 | CURLOPT_POST => true, 197 | CURLOPT_POSTFIELDS => $data, 198 | CURLOPT_RETURNTRANSFER => true 199 | )); 200 | 201 | $response = curl_exec($curl); 202 | 203 | curl_close($curl); 204 | echo $response; 205 | ``` 206 | 207 | ## Order History 208 | Sample code below : 209 | ```php 210 | 'orderHistory', 219 | 'timestamp' => '1578304294000', 220 | 'recvWindow' => '1578303937000', 221 | 'pair' => 'btc_idr', 222 | 'count' => '', 223 | 'from' => '' 224 | ]; 225 | $post_data = http_build_query($data, '', '&'); 226 | $sign = hash_hmac('sha512', $post_data, $secretKey); 227 | 228 | $headers = ['Key:'.$key,'Sign:'.$sign]; 229 | 230 | $curl = curl_init(); 231 | 232 | curl_setopt_array($curl, array( 233 | CURLOPT_HTTPHEADER => $headers, 234 | CURLOPT_URL => $url, 235 | CURLOPT_POST => true, 236 | CURLOPT_POSTFIELDS => $data, 237 | CURLOPT_RETURNTRANSFER => true 238 | )); 239 | 240 | $response = curl_exec($curl); 241 | 242 | curl_close($curl); 243 | echo $response; 244 | ``` 245 | 246 | ## Get Order 247 | Sample code below : 248 | ```php 249 | 'getOrder', 258 | 'timestamp' => '1578304294000', 259 | 'recvWindow' => '1578303937000', 260 | 'pair' => 'btc_idr', 261 | 'order_id' => '59639504' 262 | ]; 263 | $post_data = http_build_query($data, '', '&'); 264 | $sign = hash_hmac('sha512', $post_data, $secretKey); 265 | 266 | $headers = ['Key:'.$key,'Sign:'.$sign]; 267 | 268 | $curl = curl_init(); 269 | 270 | curl_setopt_array($curl, array( 271 | CURLOPT_HTTPHEADER => $headers, 272 | CURLOPT_URL => $url, 273 | CURLOPT_POST => true, 274 | CURLOPT_POSTFIELDS => $data, 275 | CURLOPT_RETURNTRANSFER => true 276 | )); 277 | 278 | $response = curl_exec($curl); 279 | 280 | curl_close($curl); 281 | echo $response; 282 | ``` 283 | 284 | ## Cancel Order 285 | Sample code below : 286 | ```php 287 | 'cancelOrder', 296 | 'timestamp' => '1578304294000', 297 | 'recvWindow' => '1578303937000', 298 | 'pair' => 'btc_idr', 299 | 'order_id' => '59977301', 300 | 'type' => 'buy' 301 | ]; 302 | $post_data = http_build_query($data, '', '&'); 303 | $sign = hash_hmac('sha512', $post_data, $secretKey); 304 | 305 | $headers = ['Key:'.$key,'Sign:'.$sign]; 306 | 307 | $curl = curl_init(); 308 | 309 | curl_setopt_array($curl, array( 310 | CURLOPT_HTTPHEADER => $headers, 311 | CURLOPT_URL => $url, 312 | CURLOPT_POST => true, 313 | CURLOPT_POSTFIELDS => $data, 314 | CURLOPT_RETURNTRANSFER => true 315 | )); 316 | 317 | $response = curl_exec($curl); 318 | 319 | curl_close($curl); 320 | echo $response; 321 | ``` 322 | 323 | ## Withdraw Fee 324 | Sample code below : 325 | ```php 326 | 'withdrawFee', 335 | 'timestamp' => '1578304294000', 336 | 'recvWindow' => '1578303937000', 337 | 'currency' => 'eth' 338 | ]; 339 | $post_data = http_build_query($data, '', '&'); 340 | $sign = hash_hmac('sha512', $post_data, $secretKey); 341 | 342 | $headers = ['Key:'.$key,'Sign:'.$sign]; 343 | 344 | $curl = curl_init(); 345 | 346 | curl_setopt_array($curl, array( 347 | CURLOPT_HTTPHEADER => $headers, 348 | CURLOPT_URL => $url, 349 | CURLOPT_POST => true, 350 | CURLOPT_POSTFIELDS => $data, 351 | CURLOPT_RETURNTRANSFER => true 352 | )); 353 | 354 | $response = curl_exec($curl); 355 | 356 | curl_close($curl); 357 | echo $response; 358 | ``` 359 | 360 | ## Withdraw Coin 361 | Sample code below : 362 | ```php 363 | 'withdrawCoin', 372 | 'timestamp' => '1578304294000', 373 | 'recvWindow' => '1578303937000', 374 | 'currency' => 'doge', 375 | 'withdraw_address' => 'D9iCdBLBosJzGSvpQGMSobwtdgB2rS1zam', 376 | 'withdraw_amount' => '10', 377 | 'withdraw_memo' => 'memo', 378 | 'request_id' => 'trx002' 379 | ]; 380 | $post_data = http_build_query($data, '', '&'); 381 | $sign = hash_hmac('sha512', $post_data, $secretKey); 382 | 383 | $headers = ['Key:'.$key,'Sign:'.$sign]; 384 | 385 | $curl = curl_init(); 386 | 387 | curl_setopt_array($curl, array( 388 | CURLOPT_HTTPHEADER => $headers, 389 | CURLOPT_URL => $url, 390 | CURLOPT_POST => true, 391 | CURLOPT_POSTFIELDS => $data, 392 | CURLOPT_RETURNTRANSFER => true 393 | )); 394 | 395 | $response = curl_exec($curl); 396 | 397 | curl_close($curl); 398 | echo $response; 399 | ``` -------------------------------------------------------------------------------- /Marketdata-websocket.md: -------------------------------------------------------------------------------- 1 | 2 | # Market Data WebSocket Documentation 3 | 4 | ## Table of Contents 5 | 6 | - [General Information](#general-information) 7 | - [Authentication](#authentication) 8 | - [Ping/Pong](#pingpong) 9 | - [Subscribing to Channel](#subscribing-to-channel) 10 | - [Chart Data](#chart-data) 11 | - [Market Summary](#market-summary) 12 | - [Trade Activity](#trade-activity) 13 | - [Orderbook](#orderbook) 14 | - [Streaming Result](#streaming-result) 15 | - [Unsubscribing from Channel](#unsubscribing-from-channel) 16 | - [Get Data from Specific Offset and Subscribe](#get-data-from-specific-offset-and-subscribe) 17 | - [Troubleshooting](#troubleshooting) 18 | - [Disconnected Client Issue](#disconnected-client-issue) 19 | 20 | ## General Information 21 | 22 | | **Environment** | **Market Data Base URL** | **Static Token** | 23 | | ---------------- | ------------------------------ | --------------------------------------------------------------------------------------------------------- | 24 | | Production | wss://ws3.indodax.com/ws/ | eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE5NDY2MTg0MTV9.UR1lBM6Eqh0yWz-PVirw1uPCxe60FdchR8eNVdsskeo | 25 | | Demo | wss://ws.demo-indodax.com/ws/ | eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.OqWmyrtOvp_DvIdBnOgU9gyXhURkEOtu8brZtvwjYAw | 26 | 27 | After connected, you will have to **authenticate** yourself using request provided in [Authentication](#authentication) section below to make further request. 28 | 29 | The `id` field in request or response is used as an identifier to uniquely identify them. 30 | 31 | ## Authentication 32 | 33 | Connect to Postman using Market Data Base URL by clicking connect, until the connect button changes to disconnect. 34 | 35 | Send request after insert message field with `id` and `static token` as shown below 36 | 37 | ![auth and connect](https://github.com/btcid/indodax-official-api-docs/blob/b5c1f8f5fcc79469d3f790e417b9988ac7bd26bb/assets/auth.jpg) 38 | 39 | Request: 40 | 41 | ```json 42 | { 43 | "params": { 44 | "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE5NDY2MTg0MTV9.UR1lBM6Eqh0yWz-PVirw1uPCxe60FdchR8eNVdsskeo" 45 | }, 46 | "id": 1 47 | } 48 | ``` 49 | 50 | Response: 51 | 52 | ```json 53 | { 54 | "id": 1, 55 | "result": { 56 | "client": "9690f773-a529-4277-9b09-57fa3ddea251", 57 | "version": "2.8.6", 58 | "expires": true, 59 | "ttl": 311392452 60 | } 61 | } 62 | ``` 63 | 64 | ## Ping/Pong 65 | 66 | Provide a command to send a test signal to a server to check for its availability and response time. Use 7 as method. 67 | 68 | 69 | Request: 70 | 71 | ```json 72 | { 73 | "method": 7, 74 | "id": 3 75 | } 76 | ``` 77 | 78 | Response: 79 | 80 | ```json 81 | { 82 | "id": 3 83 | } 84 | ``` 85 | 86 | ## Subscribing to Channel 87 | 88 | You can **subscribe** to a **channel** to get live stream of events using a **single** WebSocket connection by using `1` as `method` in the request body. 89 | 90 | ### Chart Data 91 | 92 | Provide a visualization cryptocurrency price movements and trends for easy analysis. Use chart:tick- as channel. Change to the one that you want to subscribe to. 93 | 94 | Request: 95 | 96 | ```json 97 | { 98 | "method": 1, 99 | "params": { 100 | "channel": "chart:tick-usdtidr" 101 | }, 102 | "id": 2 103 | } 104 | ``` 105 | 106 | Response: 107 | 108 | ```json 109 | { 110 | "id": 2, 111 | "result": { 112 | "recoverable": true, 113 | "epoch": "1630401092", 114 | "offset": 814137 115 | } 116 | } 117 | ``` 118 | 119 | Received Message: 120 | 121 | ```json 122 | { 123 | "result": { 124 | "channel": "chart:tick-usdtidr", 125 | "data": { 126 | "data": [ 127 | [ 128 | 1632717721, // epoch timestamp in second 129 | 4087327, // sequence number 130 | 14340, // price 131 | "1063.73019525" // volume 132 | ] 133 | ], 134 | "offset": 266983 // offset of the data 135 | } 136 | } 137 | } 138 | ``` 139 | 140 | ### Market Summary 141 | 142 | Provides a quick overview of essential cryptocurrency market information in one place. Use market:summary-24h as channel. 143 | 144 | 145 | Request: 146 | 147 | ```json 148 | { 149 | "method": 1, 150 | "params": { 151 | "channel": "market:summary-24h" 152 | }, 153 | "id": 2 154 | } 155 | ``` 156 | 157 | Response: 158 | 159 | ```json 160 | { 161 | "id": 2, 162 | "result": { 163 | "recoverable": true, 164 | "epoch": "1633995795", 165 | "offset": 2820132 166 | } 167 | } 168 | ``` 169 | 170 | Received Message: 171 | 172 | ```json 173 | { 174 | "result": { 175 | "channel": "market:summary-24h", 176 | "data": { 177 | "data": [ 178 | [ 179 | "dogeidr", // pair 180 | 1635134109, // epoch timestamp in second 181 | 3810, // last price 182 | 3480, // lowest price in the last 24h 183 | 3980, // highest price in the last 24h 184 | 3523, // price at T-24h 185 | "112745093944.00000000", // IDR volume in the last 24h (DOGE/IDR) 186 | "30241791.15270789" // DOGE volume in the last 24h (DOGE/IDR) 187 | ], 188 | [ 189 | "usdtidr", 190 | 1635134410, 191 | 14124, 192 | 14076, 193 | 14130, 194 | 14123, 195 | "194798674207.00000000", // IDR volume in the last 24h (USDT/IDR) 196 | "13798116.12995762" // USDT volume in the last 24h (USDT/IDR) 197 | ] 198 | ], 199 | "offset": 2444948 200 | } 201 | } 202 | } 203 | ``` 204 | 205 | ### Trade Activity 206 | 207 | Provide real-time transactions and trading activity for cryptocurrencies, offering insights into market dynamics and trends. Use market:trade-activity- as channel. Change to the one that you want to subscribe to. 208 | 209 | Request: 210 | 211 | ```json 212 | { 213 | "method": 1, 214 | "params": { 215 | "channel": "market:trade-activity-btcidr" 216 | }, 217 | "id": 2 218 | } 219 | ``` 220 | 221 | Response: 222 | 223 | ```json 224 | { 225 | "id": 2, 226 | "result": { 227 | "recoverable": true, 228 | "epoch": "1633996541", 229 | "offset": 243555 230 | } 231 | } 232 | ``` 233 | 234 | Received Message: 235 | 236 | ```json 237 | { 238 | "result": { 239 | "channel": "market:trade-activity-btcidr", 240 | "data": { 241 | "data": [ 242 | [ 243 | "btcidr", // pair 244 | 1635274052, // epoch timestamp in second 245 | 21999427, // sequence number 246 | "buy", // side (buy/sell) 247 | 881991000, // filled price 248 | "29740", // IDR volume (BTC/IDR) 249 | "0.00003372" // BTC volume (BTC/IDR) 250 | ] 251 | ], 252 | "offset": 243556 253 | } 254 | } 255 | } 256 | ``` 257 | 258 | ### Orderbook 259 | 260 | Provide real-time buy and sell orders for cryptocurrencies, giving insights into market depth and trading liquidity. Use market:order-book- as channel. Change to the one that you want to subscribe to. 261 | 262 | Send request so it will give the following response. 263 | 264 | ![orderbook](https://github.com/btcid/indodax-official-api-docs/blob/e4ddf92cc75d0fca3bfe501d17c8d95f09423ffc/assets/orderbooks.png) 265 | 266 | Request: 267 | 268 | | **FIELD** | **TYPE** | **DESCRIPTION** | **MANDATORY** | **DEFAULT** | 269 | | --------- | ---------------- | ------------------------------------------------------------ | ------------- | ----------- | 270 | | method | string | specify the method you want to call | yes | | 271 | | params | application/json | data type of the received response | yes | | 272 | | channel | string | pair information to be subscribed `market:order-book-` | yes | ““ | 273 | | id | int | is a random request ID specified by WebSocket client | yes | ““ | 274 | 275 | ```json 276 | { 277 | "method": 1, 278 | "params": { 279 | "channel": "market:order-book-btcidr" 280 | }, 281 | "id": 4 // is a random request ID specified by WebSocket client 282 | } 283 | ``` 284 | 285 | Response: 286 | 287 | | **FIELD** | **TYPE** | **DESCRIPTION** | **MANDATORY** | **DEFAULT** | 288 | | -------------- | -------- | --------------------------------- | ------------- | ----------- | 289 | | result | json | result subscribe/streaming | yes | | 290 | | channel | string | pair information to be subscribed | yes | | 291 | | data | json | response data | yes | | 292 | | data.pair | string | btc / idr / coin name | yes | | 293 | | data.ask | json | required on limit order | yes | | 294 | | ask.btc_volume | float | trading volume | yes | | 295 | | ask.idr_volume | float | trading volume | yes | | 296 | | ask.price | numeric | order pice | yes | | 297 | | bid.btc_volume | float | trading volume | yes | | 298 | | bid.idr_volume | float | trading volume | yes | | 299 | | bid.price | numeric | order price | yes | | 300 | | offset | int | offset of the data | yes | | 301 | 302 | ```json 303 | { 304 | "result": { 305 | "channel": "market:order-book-btcidr", 306 | "data": { 307 | "data": { 308 | "pair": "btcidr", 309 | "ask": [{ 310 | "btc_volume": "0.11035661", 311 | "idr_volume": "35251984", 312 | "price": "319437000" 313 | }, 314 | { 315 | "btc_volume": "0.20000000", 316 | "idr_volume": "63950800", 317 | "price": "319754000" 318 | } 319 | ], 320 | "bid": [{ 321 | "btc_volume": "0.61427265", 322 | "idr_volume": "196220798", 323 | "price": "319436000" 324 | }, 325 | { 326 | "btc_volume": "0.00697822", 327 | "idr_volume": "2228655", 328 | "price": "319373000" 329 | } 330 | ] 331 | }, 332 | "offset": 67409 333 | } 334 | } 335 | } 336 | ``` 337 | 338 | #### Streaming Result 339 | 340 | By following the steps starting from connecting to Market Data & authenticate using [Authentication](#authentication) section, then following the streaming steps 341 | 342 | in the [Orderbook](#orderbook) section so you can get Market Data WebSocket as long as they are connected to the WS3. 343 | 344 | ![result](https://github.com/btcid/indodax-official-api-docs/blob/e4ddf92cc75d0fca3bfe501d17c8d95f09423ffc/assets/results.png) 345 | 346 | ## Unsubscribing from Channel 347 | 348 | To **unsubscribe** from a **channel**, use `2` as `method` in the request body. 349 | 350 | Request: 351 | 352 | ```json 353 | { 354 | "method": 2, 355 | "params": { 356 | "channel": "chart:tick-usdtidr" 357 | }, 358 | "id": 3 359 | } 360 | ``` 361 | 362 | Response: 363 | 364 | ```json 365 | { 366 | "id": 3, 367 | "result": {} 368 | } 369 | ``` 370 | 371 | ## Get Data from Specific Offset and Subscribe 372 | 373 | In case of connection problem, you can get data from specific **offset** and subscribe again. Use `true` as `recover` and specify the last `offset` that you already have. The **response** will contain data from the **next** offset and you will be subscribed again and receive messages. 374 | 375 | Request: 376 | 377 | ```json 378 | { 379 | "method": 1, 380 | "params": { 381 | "channel": "chart:tick-usdtidr", 382 | "recover": true, 383 | "offset": 820574 384 | }, 385 | "id": 2 386 | } 387 | ``` 388 | 389 | Response: 390 | 391 | ```json 392 | { 393 | "id": 2, 394 | "result": { 395 | "recoverable": true, 396 | "epoch": "1630401092", 397 | "publications": [ 398 | { 399 | "data": [ 400 | [ 401 | 1635245109, 402 | 4673347, 403 | 14130, 404 | "17.75166439" 405 | ] 406 | ], 407 | "offset": 820574 408 | }, 409 | { 410 | "data": [ 411 | [ 412 | 1635245114, 413 | 4673348, 414 | 14130, 415 | "10.00000000" 416 | ] 417 | ], 418 | "offset": 820575 419 | }, 420 | { 421 | "data": [ 422 | [ 423 | 1635245117, 424 | 4673349, 425 | 14131, 426 | "221.07734767" 427 | ] 428 | ], 429 | "offset": 820576 430 | }, 431 | { 432 | "data": [ 433 | [ 434 | 1635245127, 435 | 4673350, 436 | 14131, 437 | "3.24202108" 438 | ] 439 | ], 440 | "offset": 820577 441 | } 442 | ], 443 | "offset": 820577 444 | } 445 | } 446 | ``` 447 | # Troubleshooting 448 | ## Disconnected Client Issue 449 | ### Description 450 | WebSocket clients may get disconnected from the server due to internal rebalancing, potentially causing some messages to be missed. 451 | ### Solution 452 | If you experience this issue, you can add a handler to reconnect upon disconnection. 453 | ### Implementation 454 | #### Javascript Implementation 455 | ``` 456 | 457 | 479 | ``` 480 | #### Go Implementation 481 | Example below use `gorilla/websocket`. 482 | ``` 483 | type wsClient struct { 484 | conn *websocket.Conn 485 | } 486 | 487 | type wsError struct { 488 | Reason string `json:"reason"` 489 | Reconnect bool `json:"reconnect"` 490 | } 491 | 492 | func (c *wsClient) connectWS() { 493 | if c.conn != nil { 494 | c.conn.Close() 495 | } 496 | 497 | u := url.URL{Scheme: "wss", Host: "indodax.com", Path: "/ws/"} 498 | 499 | conn, _, err := websocket.DefaultDialer.Dial(u.String(), nil) 500 | if err != nil { 501 | log.Fatal("Dial:", err) 502 | } 503 | 504 | c.conn = conn 505 | } 506 | 507 | func (c *wsClient) handleMessages() { 508 | for { 509 | messageType, msg, err := c.conn.ReadMessage() 510 | if err != nil { 511 | errText := err.(*websocket.CloseError).Text 512 | 513 | var wsErr wsError 514 | 515 | errUnmarshal := json.Unmarshal([]byte(errText), &wsErr) 516 | if errUnmarshal != nil { 517 | log.Fatal("error unmarshal:", errUnmarshal) 518 | } 519 | 520 | if !wsErr.Reconnect { 521 | log.Println("Read error:", err) 522 | return 523 | } 524 | 525 | c.connectWS() 526 | continue 527 | } 528 | 529 | // Handle messages 530 | } 531 | } 532 | 533 | func main() { 534 | client := wsClient{} 535 | 536 | client.connectWS() 537 | defer client.conn.Close() 538 | 539 | go client.handleMessages() 540 | 541 | quit := make(chan os.Signal, 10) 542 | 543 | signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) 544 | 545 | <-quit 546 | log.Print("Shutdown client ...") 547 | } 548 | ``` 549 | #### Python Implementation 550 | ``` 551 | def on_close(ws, code, reason): 552 | // Handle on close event 553 | 554 | start_websocket() 555 | 556 | def on_error(ws, error): 557 | // Handle on error event 558 | 559 | // Trigger on close event 560 | ws.close() 561 | 562 | def start_websocket(): 563 | url = "wss://indodax.com/ws/" 564 | ws = websocket.WebSocketApp(url, 565 | on_message = on_message, 566 | on_error = on_error, 567 | on_close = on_close, 568 | on_open = on_open) 569 | ws.run_forever(suppress_origin=True) 570 | 571 | start_websocket() 572 | ``` -------------------------------------------------------------------------------- /Private-websocket.md: -------------------------------------------------------------------------------- 1 | # Private WebSocket Documentation 2 | 3 | ## Table of Contents 4 | 5 | - [Request Private Token and Private Channel](#request-private-token-and-private-channel) 6 | - [General Information](#general-information) 7 | - [Generate Private Token and Private Channel](#generate-private-token-and-private-channel) 8 | - [Private WebSocket](#private-websocket) 9 | - [Authentication](#authentication) 10 | - [Subscribing to Private Channel](#subscribing-to-private-channel) 11 | - [Order Update Event](#order-update-event) 12 | - [Troubleshooting](#troubleshooting) 13 | - [Establishing WebSocket Connection](#establishing-websocket-connection) 14 | - [Disconnected Client Issue](./Marketdata-websocket.md#disconnected-client-issue) 15 | - [Connection Expired](#connection-expired) 16 | 17 | 18 | 19 | ## Request Private Token and Private Channel 20 | 21 | ### General Information 22 | 23 | #### Base URL 24 | | **Environment** | **Base URL** | **Description** | 25 | | ----------------- | ------------------------------------------- | ------------------------------------------------------------------- | 26 | | Production | https://indodax.com/ , https://btcapi.net | Access for production. For https://btcapi.net need to be whitelist | 27 | | Demo | https://demo-indodax.com/ | Access for demo. | 28 | 29 | #### Request Header 30 | | **Parameter** | **Type** | **Mandatory** | **Description** | 31 | | -------------- | --------- | ------------- |-------------------- | 32 | | `Sign` | string | yes | `Sign` Encrypted with method `HMAC-SHA512` using `tapi secret key`. (Request body (?param=val¶m1=val1)) | 33 | 34 | ### Generate Private Token and Private Channel 35 | Provide private token and private channel to use in WebSocket 36 | 37 | #### PATH 38 | ``` 39 | POST {base_url}/api/private_ws/v1/generate_token 40 | ``` 41 | 42 | #### Request Body 43 | | **Parameter** | **Type** | **Mandatory** | **Description** | **Default** | 44 | | ---------------- | --------- | ------------- |------------------ | ----------- | 45 | | `client` | string | yes | `tapi` | `tapi` | 46 | | `tapi_key` | string | yes | API Key | | 47 | 48 | #### Response Body 49 | | **Parameter** | **Type** | **Description** | 50 | | ----------------- | --------- | ------------------------------------------------------------- | 51 | | success | int | if success=1 and failed=0 | 52 | | return | object | | 53 | | return.connToken | string | Use to established connection and verify user private channel | 54 | | return.channel | string | private channel to subscribe | 55 | | error | string | error message of request | 56 | | error_code | string | type of error | 57 | 58 | **Success Response** 59 | ```json 60 | { 61 | "success": 1, 62 | "return": { 63 | "connToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMTIifQ.D4YxclnNWCRH6w47MNV9XcbpKT4aLrMboLg6DzCwm1M", 64 | "channel": "pws:#c12d3ca099785ede15c37c9b7642ab89d19bc96e" 65 | } 66 | } 67 | ``` 68 | 69 | **Failed Response** 70 | ```json 71 | { 72 | "success": 0, 73 | "error": "Invalid TAPI key", 74 | "error_code": "invalid_tapi_key" 75 | } 76 | ``` 77 | #### Error Code 78 | | **error_code** | **Error** | **Description** | 79 | | ----------------- | ------------------------------- | --------------- | 80 | | invalid_tapi_key | Invalid TAPI key | `tapi_key` not properly sent or empty `tapi_key`. | 81 | | invalid_credentials | Invalid credentials. API not found or session has expired. | Invalid `tapi_key` or doesn't exist. | 82 | | bad_sign | Invalid credentials. Bad sign. | Invalid `tapi_secret` to Encrypt Sign request | 83 | 84 | 85 | 86 | ## Private WebSocket 87 | 88 | | **Environment** | **Base URL** | **Description** | 89 | | ----------------- | ------------------------------- | --------------- | 90 | | Production | wss://pws.indodax.com/ws/?cf_ws_frame_ping_pong=true | Access for production | 91 | | Demo | wss://pws.demo-indodax.com/ws/?cf_ws_frame_ping_pong=true | Access for staging | 92 | 93 | Connect using Environment Base URL. 94 | 95 | ### Authentication 96 | Send request message with field `id` and `token` you get from [Generate Private Token and Private Channel](#generate-private-token-and-private-channel). 97 | 98 | Request Message: 99 | 100 | ```json 101 | {"connect":{"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIzMWFlMGUzYjU1NzNlMzI1YTU1MGM1ZDg2MGM1YjQ3ZDQyYjdkZjMxIiwiZXhwIjoxNzA1NzE4NjEyfQ.T1dymQ7dGS4sASLlZC3VE4JTjdvdsasJSsadaK"},"id": 1} 102 | ``` 103 | 104 | #### Success Response 105 | 106 | ```json 107 | { 108 | "id": 1, 109 | "connect": { 110 | "client": "0f812879-fc64-482f-a220-eb1860c71189", 111 | "version": "5.2.0", 112 | "expires": true, 113 | "ttl": 86133 114 | } 115 | } 116 | ``` 117 | 118 | #### Expired Token Response 119 | 120 | ```json 121 | { 122 | "id": 1, 123 | "error": { 124 | "code": 109, 125 | "message": "token expired" 126 | } 127 | } 128 | ``` 129 | 130 | When your token has expired, you will need to generate a new token. 131 | 132 | ### Subscribing to Private Channel 133 | 134 | You can **subscribe** to **private channel** using `channel` you get from [Generate Private Token and Private Channel](#generate-private-token-and-private-channel). 135 | 136 | ### Order Update Event 137 | 138 | Request Message: 139 | 140 | ```json 141 | {"subscribe":{"channel":"pws:#c12d3ca099785ede15c37c9b7642ab89d19bc96e"},"id":2} 142 | ``` 143 | 144 | #### Success Response 145 | Response New Order: 146 | ```json 147 | { 148 | "push": { 149 | "channel": "pws:#c12d3ca099785ede15c37c9b7642ab89d19bc96e", 150 | "pub": { 151 | "data": [ 152 | { 153 | "eventType": "order_update", 154 | "order": { 155 | "orderId": "aaveidr-limit-3397", 156 | "symbol": "aaveidr", 157 | "side": "BUY", 158 | "origQty": "0.00996909", 159 | "unfilledQty": "0.00996909", 160 | "executedQty": "0", 161 | "price": "2000000", 162 | "description": "AAVE/IDR", 163 | "status": "NEW", 164 | "transactionTime": 1705635775203, 165 | "clientOrderId": "lendidr-limit-3397" 166 | } 167 | } 168 | ] 169 | } 170 | } 171 | } 172 | ``` 173 | 174 | Response Fills Order: 175 | ```json 176 | { 177 | "push": { 178 | "channel": "pws:#c12d3ca099785ede15c37c9b7642ab89d19bc96e", 179 | "pub": { 180 | "data": [ 181 | { 182 | "eventType": "order_update", 183 | "order": { 184 | "orderId": "aaveidr-limit-13525", 185 | "tradeId": "72057594037968281", 186 | "symbol": "aaveidr", 187 | "side": "BUY", 188 | "origQty": "0.0046462", 189 | "unfilledQty": "0", 190 | "executedQty": "0.0046462", 191 | "price": "4289899", 192 | "description": "AAVE/IDR", 193 | "status": "FILL", 194 | "transactionTime": 1734490232679, 195 | "fillInformation": { 196 | "participant": "TAKER", 197 | "filledQty": "0.0046462", 198 | "qty": "0.0046462", 199 | "feeAsset": "idr", 200 | "feeRate": 0.002, 201 | "fee": "39", 202 | "taxAsset": "idr", 203 | "taxRate": 0.0012, 204 | "tax": "23", 205 | "clearingAsset": "idr", 206 | "clearingRate": 2.22E-4, 207 | "clearing": "4" 208 | }, 209 | "clientOrderId": "lendidr-limit-13525" 210 | } 211 | } 212 | ] 213 | } 214 | } 215 | } 216 | ``` 217 | 218 | Response Cancel Order: 219 | ```json 220 | { 221 | "push": { 222 | "channel": "pws:#c12d3ca099785ede15c37c9b7642ab89d19bc96e", 223 | "pub": { 224 | "data": [ 225 | { 226 | "eventType": "order_update", 227 | "order": { 228 | "orderId": "aaveidr-limit-3399", 229 | "symbol": "aaveidr", 230 | "side": "SELL", 231 | "origQty": "0.05015045", 232 | "unfilledQty": "0.05015045", 233 | "executedQty": "0", 234 | "price": "2000000", 235 | "description": "AAVE/IDR", 236 | "status": "CANCELLED", 237 | "transactionTime": 1705636274643, 238 | "clientOrderId": "lendidr-limit-3399" 239 | } 240 | } 241 | ] 242 | } 243 | } 244 | } 245 | ``` 246 | 247 | Response Done Order: 248 | ```json 249 | { 250 | "push": { 251 | "channel": "pws:#c12d3ca099785ede15c37c9b7642ab89d19bc96e", 252 | "pub": { 253 | "data": [ 254 | { 255 | "eventType": "order_update", 256 | "order": { 257 | "orderId": "aaveidr-limit-3397", 258 | "symbol": "aaveidr", 259 | "side": "BUY", 260 | "origQty": "0.00996909", 261 | "unfilledQty": "0", 262 | "executedQty": "0.00996909", 263 | "price": "2000000", 264 | "description": "AAVE/IDR", 265 | "status": "DONE", 266 | "transactionTime": 1705635775203, 267 | "clientOrderId": "lendidr-limit-3397" 268 | } 269 | } 270 | ] 271 | } 272 | } 273 | } 274 | ``` 275 | 276 | Response Rejected (FOK) Order: 277 | ```json 278 | { 279 | "push": { 280 | "channel": "pws:#c12d3ca099785ede15c37c9b7642ab89d19bc96e", 281 | "pub": { 282 | "data": [ 283 | { 284 | "eventType": "order_update", 285 | "order": { 286 | "orderId": "aaveidr-limit-3397", 287 | "symbol": "aaveidr", 288 | "side": "BUY", 289 | "origQty": "0.00996909", 290 | "unfilledQty": "0", 291 | "executedQty": "0.00996909", 292 | "price": "2000000", 293 | "description": "AAVE/IDR", 294 | "status": "REJECTED", 295 | "transactionTime": 1705635775203, 296 | "clientOrderId": "lendidr-limit-3397" 297 | } 298 | } 299 | ] 300 | } 301 | } 302 | } 303 | ``` 304 | 305 | #### Failed Response 306 | When you subscribe to wrong `channel`, the response will failed as below. 307 | 308 | ```json 309 | { 310 | "id": 2, 311 | "error": { 312 | "code": 103, 313 | "message": "permission denied" 314 | } 315 | } 316 | 317 | ``` 318 | # Troubleshooting 319 | ## Establishing WebSocket Connection 320 | 321 | ### Issue Description 322 | When establishing a WebSocket connection, regardless of the programming language used (Python, Go, PHP, etc.), the default behavior of the client library often sets the `Origin` header to a value that doesn't match, resulting in the client receiving a 403 Forbidden error response. 323 | 324 | ### Solution 325 | To address this issue, it's essential to ensure that the `Origin` header sent during the WebSocket handshake matches the expected value or is removed altogether. 326 | 327 | #### Python Solution (as per provided code) 328 | For Python, using the `websocket-client` library, the solution involves setting the `suppress_origin=True` option when calling `pws.run_forever()`. This removes the `Origin` header from the WebSocket handshake request. Reference: [websocket-client](https://websocket-client.readthedocs.io/en/latest/examples.html#suppress-origin-header) 329 | 330 | 331 | #### Go Solution 332 | For Go, when using libraries like `gorilla/websocket`, you can set the `Origin` header manually or remove it altogether when establishing the WebSocket connection. 333 | 334 | #### PHP Solution 335 | For PHP, utilizing an unset() if isset() header origin exist. 336 | 337 | ### Implementation 338 | 339 | #### Python 340 | 341 | ```python 342 | def start_websocket(): 343 | global pws 344 | url = "wss://pws.indodax.com/ws/?cf_ws_frame_ping_pong=true" 345 | pws_instance = PWS() 346 | pws = websocket.WebSocketApp(url, 347 | on_message=pws_instance.on_message, 348 | on_error=pws_instance.on_error, 349 | on_close=pws_instance.on_close, 350 | on_open = pws_instance.on_open) 351 | pws.run_forever(suppress_origin=True) 352 | ``` 353 | #### Golang 354 | ```go 355 | func main() { 356 | u := url.URL{Scheme: "wss", Host: "pws.indodax.com", Path: "/ws/", RawQuery: "cf_ws_frame_ping_pong=true"} 357 | 358 | c, _, err := websocket.DefaultDialer.Dial(u.String(), nil) 359 | if err != nil { 360 | log.Fatal("Error connecting to WebSocket:", err) 361 | } 362 | defer c.Close() 363 | } 364 | ``` 365 | 366 | #### PHP 367 | ```php 368 | if (isset($options['headers']['Origin'])) { 369 | unset($options['headers']['Origin']); 370 | } 371 | ``` 372 | 373 | ## Connection Expired 374 | ### Description 375 | A token is required to connect to our private WebSocket and is valid for only 24 hours. Clients should request a new token each time they connect and continue to request it regularly. 376 | ### Solution 377 | This is sample to request a new token 378 | ### Implementation 379 | #### Javascript Implementation 380 | ``` 381 | const crypto = require("crypto"); 382 | 383 | function generateHMAC(requestBody, secret) { 384 | const key = Buffer.from(secret, "utf-8"); 385 | const hmac = crypto.createHmac("sha512", key); 386 | hmac.update(requestBody, "utf-8"); 387 | return hmac.digest("hex"); 388 | } 389 | 390 | async function RequestToken() { 391 | const url = "https://indodax.com/api/private_ws/v1/generate_token"; 392 | const secret = ; 393 | const key = ; 394 | 395 | const requestBody = `client=tapi&tapi_key=${key}`; 396 | 397 | const sign = generateHMAC(requestBody, secret); 398 | 399 | const opt = { 400 | method: "POST", 401 | headers: { 402 | "Content-Type": "application/x-www-form-urlencoded", 403 | Sign: sign, 404 | }, 405 | body: requestBody, 406 | }; 407 | 408 | let response; 409 | try { 410 | response = await fetch(url, opt); 411 | } catch (error) { 412 | throw new Error(error.message); 413 | } 414 | 415 | const responseData = await response.json() 416 | 417 | return responseData 418 | } 419 | 420 | RequestToken() 421 | .then((data) => { 422 | console.log("token:", data.return.connToken); 423 | console.log("channel:", data.return.channel) 424 | }) 425 | .catch((error) => { 426 | console.log(error); 427 | }); 428 | ``` 429 | #### Go Implementation 430 | ``` 431 | package main 432 | 433 | import ( 434 | "crypto/hmac" 435 | "crypto/sha512" 436 | "encoding/hex" 437 | "encoding/json" 438 | "fmt" 439 | "io/ioutil" 440 | "net/http" 441 | "strings" 442 | ) 443 | 444 | type PwsToken struct { 445 | ConnToken string `json:"connToken"` 446 | Channel string `json:"channel"` 447 | } 448 | 449 | type Response struct { 450 | Success int `json:"success"` 451 | Token PwsToken `json:"return"` 452 | } 453 | 454 | func generateHMAC(requestBody, secret string) string { 455 | key := []byte(secret) 456 | h := hmac.New(sha512.New, key) 457 | h.Write([]byte(requestBody)) 458 | return hex.EncodeToString(h.Sum(nil)) 459 | } 460 | 461 | func sendRequest(url, method, requestBody, sign string) (Response, error) { 462 | payload := strings.NewReader(requestBody) 463 | client := &http.Client{} 464 | req, err := http.NewRequest(method, url, payload) 465 | if err != nil { 466 | return Response{}, nil 467 | } 468 | 469 | req.Header.Add("Sign", sign) 470 | req.Header.Add("Content-Type", "application/x-www-form-urlencoded") 471 | 472 | res, err := client.Do(req) 473 | if err != nil { 474 | return Response{}, nil 475 | } 476 | defer res.Body.Close() 477 | 478 | body, err := ioutil.ReadAll(res.Body) 479 | if err != nil { 480 | return Response{}, err 481 | } 482 | 483 | var response Response 484 | 485 | err = json.Unmarshal(body, &response) 486 | if err != nil { 487 | return Response{}, nil 488 | } 489 | 490 | return response, nil 491 | } 492 | 493 | func main() { 494 | url := "https://indodax.com/api/private_ws/v1/generate_token" 495 | method := "POST" 496 | secret := 497 | key := 498 | 499 | requestBody := fmt.Sprintf("client=tapi&tapi_key=%s", key) 500 | 501 | sign := generateHMAC(requestBody, secret) 502 | 503 | res, err := sendRequest(url, method, requestBody, sign) 504 | if err != nil { 505 | fmt.Println(err) 506 | return 507 | } 508 | 509 | fmt.Println("token", res.Token.ConnToken) 510 | fmt.Println("channel", res.Token.Channel) 511 | } 512 | ``` 513 | #### Python Implementation 514 | ``` 515 | import hmac 516 | import hashlib 517 | import requests 518 | 519 | def generate_hmac(request_body, secret): 520 | key = secret.encode('utf-8') 521 | hmac_obj = hmac.new(key, request_body.encode('utf-8'), hashlib.sha512) 522 | return hmac_obj.hexdigest() 523 | 524 | def request_token(): 525 | url = 'https://indodax.com/api/private_ws/v1/generate_token' 526 | secret = 527 | key = 528 | 529 | request_body = f'client=tapi&tapi_key={key}' 530 | sign = generate_hmac(request_body, secret) 531 | 532 | headers = { 533 | 'Content-Type': 'application/x-www-form-urlencoded', 534 | 'Sign': sign 535 | } 536 | 537 | try: 538 | response = requests.post(url, headers=headers, data=request_body) 539 | response.raise_for_status() 540 | except requests.RequestException as e: 541 | raise SystemExit(e) 542 | 543 | response_data = response.json() 544 | return response_data 545 | 546 | try: 547 | data = request_token() 548 | print("token:", data['return']['connToken']) 549 | print("channel:", data['return']['channel']) 550 | except Exception as e: 551 | print("Error:", e) 552 | ``` -------------------------------------------------------------------------------- /Private-RestAPI.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | **Table of Contents** 5 | - [General API Information](#general-api-information) 6 | - [Error Codes](#error-codes) 7 | - [General Information on Endpoints](#general-information-on-endpoints) 8 | - [Endpoint security type](#endpoint-security-type) 9 | - [SIGNED (TRADE and USER_DATA) Endpoint security](#signed-trade-and-user_data-endpoint-security) 10 | - [Timing Security](#timing-security) 11 | - [SIGNED Endpoint](#signed-endpoint-examples-for-post-getinfo) 12 | - [Private API Endpoint](#private-api-endpoint) 13 | - [ENUM definitions](#enum-definitions) 14 | - [Private API endpoints](#private-api-endpoints) 15 | 16 | ## General API Information 17 | * The base endpoint is: **https://indodax.com/tapi** 18 | * All endpoints return either a JSON object or array. 19 | * Data is returned in **descending** order. newest first, oldest last. 20 | * All time and timestamp related fields are in **milliseconds**. 21 | 22 | ## Error Codes 23 | * Any endpoint can return an ERROR 24 | 25 | Sample Payload below: 26 | ```javascript 27 | { 28 | "success": 0, 29 | "error": "Invalid credentials. API not found or session has expired.", 30 | "error_code": "invalid_credentials" 31 | } 32 | ``` 33 | 34 | ## General Information on Endpoints 35 | * Parameters may be sent in any order. 36 | * All requests must be sent with POST. 37 | * For each request you need to include these variable to make the call valid: method and nonce or timestamp. 38 | 39 | | Parameter | Description | Optional | Example | 40 | |-|-|-|-| 41 | |`method`| Specify the method you want to call | no | getInfo| 42 | |`nonce`| An increment integer. For example if the last request's nonce is 1000, the next request should be 1001 or a larger number. To learn more about [nonce](http://en.wikipedia.org/wiki/Cryptographic_nonce) | no | 1000 43 | 44 | | Parameter | Description | Optional | Example | 45 | |-|-|-| - | 46 | |`method`| Specify the method you want to call | no | getInfo 47 | |`timestamp`| This parameter should be the millisecond timestamp of when the request was created and sent | no | 1578303960000 48 | |`recvWindow`| The value should specify the number of millisecond after timestamp where your request is valid. That mean your request still valid if it sent and processed within timestamp and timestamp + recvWindow. Default value is 5000 (milliseconds) | no | 1578303937000 49 | 50 | ## Endpoint Security Type 51 | * API-keys are passed into the Rest API via the `Key` 52 | header. 53 | * API-keys and secret-keys **are case sensitive**. 54 | * There are 3 different permissions that can be applied to API Key: view, trade and withdraw 55 | 56 | |Permission | Allowed Methods| 57 | |-|-| 58 | |view | getInfo, transHistory, tradeHistory, openOrders, orderHistory, getOrder, getOrderByClientOrderId | 59 | |trade | trade, cancelOrder, cancelByClientOrderId | 60 | |withdraw | withdrawFeee, withdrawCoin | 61 | 62 | ## Signed (TRADE and USER_DATA) Endpoint Security 63 | * `SIGNED` endpoints require an additional parameter, `Sign`, to be 64 | sent in the `header`. 65 | * Endpoints use `HMAC SHA512` signatures. 66 | Use your `secretKey` as the key and `totalParams` as the value for the HMAC operation. 67 | * The `signature` is **not case sensitive**. 68 | * `totalParams` is defined as the `query string` concatenated with the 69 | `request body`. example `*(?param=val¶m1=val1) encrypted with method HMAC-SHA512 using secret key*` 70 | 71 | ### Timing Security 72 | * A `SIGNED` endpoint also requires a parameter, `timestamp`, to be sent which 73 | should be the millisecond timestamp of when the request was created and sent. 74 | * An additional parameter, `recvWindow`, may be sent to specify the number of 75 | milliseconds after `timestamp` the request is valid for. If `recvWindow` 76 | is not sent, **it defaults to 5000**. 77 | * The logic is as follows: 78 | ```php 79 | if ($timestamp >= ($serverTime + 1000) || ($serverTime - $timestamp) > $recvWindow) { 80 | // reject request 81 | } else { 82 | // process request 83 | } 84 | ``` 85 | **Serious trading is about timing.** Networks can be unstable and unreliable, which can lead to requests taking varying amounts of time to reach the servers. With `recvWindow`, you can specify that the request must be processed within a certain number of milliseconds or be rejected by the server. 86 | 87 | ### SIGNED Endpoint Examples for POST getInfo 88 | Here is a step-by-step example of how to send a vaild signed payload from the 89 | Linux command line using. `curl` 90 | 91 | | Key | Value 92 | |-|- 93 | | `apiKey` | AEDHIGAT-QATEGWOX-OPCSCPQX-2E00B1L7-VJBXXKMA 94 | | `secretKey` | f60617a68fcce028f0a90bc9eb765d17379eb548cc935c01a7ee3186eecf870e9b68f27a31bcfe8d 95 | 96 | | Parameter | Value | 97 | |-|-| 98 | |`method`| getInfo | 99 | |`timestamp`| 1578304294000 | 100 | |`recvWindow`| 1578303937000 | 101 | 102 | #### Example : send parameter using request body 103 | * **requestBody:** method=getInfo×tamp=1578304294000&recvWindow=1578303937000 104 | * **HMAC SHA512 signature:** 105 | ``` 106 | [linux]$ echo -n "method=getInfo×tamp=1578304294000&recvWindow=1578303937000" | openssl dgst -sha512 -hmac "f60617a68fcce028f0a90bc9eb765d17379eb548cc935c01a7ee3186eecf870e9b68f27a31bcfe8d" 107 | (stdin)= bab004e5a518740d7a33b38b44dbebecd3fb39f40b42391af39fcce06edabff5233b3e8064a07c528d1c751a6923d5116026c7786e01b22e2d35277a098cae99 108 | ``` 109 | * **curl command:** 110 | ``` 111 | (HMAC SHA512) 112 | [linux]$ curl -H "Key: AEDHIGAT-QATEGWOX-OPCSCPQX-2E00B1L7-VJBXXKMA" -H "Sign: bab004e5a518740d7a33b38b44dbebecd3fb39f40b42391af39fcce06edabff5233b3e8064a07c528d1c751a6923d5116026c7786e01b22e2d35277a098cae99" -X POST 'https://indodax.com/tapi' -d 'method=getInfo×tamp=1578304294000&recvWindow=1578303937000' 113 | ``` 114 | ## Private API Endpoint 115 | ### ENUM Definitions 116 | **Parameter method (Method) :** 117 | * getInfo 118 | * transHistory 119 | * trade 120 | * tradeHistory 121 | * openOrders 122 | * orderHistory 123 | * getOrder 124 | * getOrderByClientOrderId 125 | * cancelOrder 126 | * cancelByClientOrderId 127 | * withdrawFee 128 | * withdrawCoin 129 | * listDownline 130 | * checkDownline 131 | * createVoucher (Partner Only) 132 | 133 | **Transaction type (type):** 134 | * buy 135 | * sell 136 | 137 | **Sort by (order):** 138 | * asc 139 | * desc 140 | 141 | **Pair to get the information from (pair):** 142 | * btc_idr 143 | * ltc_btc 144 | * doge_btc 145 | 146 | **Currency to withdraw (currency):** 147 | * btc 148 | * eth 149 | * doge 150 | * ltc 151 | 152 | ### Private API Endpoints 153 | All request sent to this endpoint 154 | 155 | POST https://indodax.com/tapi 156 | 157 | All request sent with Request header 158 | 159 | | Name | Type | Mandatory | Description | 160 | |-|-|-|-| 161 | |`Key`| string | yes | API Key| 162 | |`Sign`| string | yes | Encrypted with method HMAC-SHA512 using secret key. (Request body (?param=val¶m1=val1))| 163 | 164 | All request sent with Request body 165 | 166 | | Name | Type | Mandatory | Description | 167 | |-|-|-|-| 168 | |`method`| string |yes|Specify the method you want to call | 169 | |`timestamp`| timestamp in milisecond | optional when sending request using `nonce` | The millisecond timestamp of when the request was created and sent. Default value is 5000 (milliseconds).| 170 | |`recvWindow`| timestamp in milisecond | no | This parameter is optional when you sending request using timestamp. The value should specify the number of millisecond after timestamp where your request is valid. That mean your request still valid if it sent and processed within timestamp and timestamp + recvWindow. Default value is 5000 (milliseconds).| 171 | |`nonce`|int|optional when sending request using `timestamp`|An increment integer. For example if the last request's nonce is 1000, the next request should be 1001 or a larger number. 172 | 173 | #### Get Info Endpoint 174 | This method gives user balances and server's timestamp. 175 | 176 | Request Body 177 | 178 | | Name | Type | Mandatory | Description | Value | default | 179 | |-|-|-|-|-|-| 180 | |`method`| string |yes|Specify the method you want to call |getInfo| | 181 | 182 | Response 183 | ```json 184 | { 185 | "success": 1, 186 | "return": { 187 | "server_time": 1578638762, 188 | "balance": { 189 | "idr": 0, 190 | "btc": "0.00000000", 191 | ... 192 | }, 193 | "balance_hold": { 194 | "idr": 0, 195 | "btc": "0.00000000", 196 | ... 197 | }, 198 | "address": { 199 | "btc": "17wGZJCHfi1MJXY9V8NrbSwBYmUM2wXdER", 200 | "1inch": "0xaDF5bF5e8fa6966451D6cf43A9dbe3f142695362", 201 | "eth": "0xa6fd81330501442e8dff403f966b6e023a53763e" 202 | }, 203 | "network": { 204 | "btc": "mainnet", 205 | "1inch": "erc20", 206 | "eth": [ 207 | "eth", 208 | "arb", 209 | "op", 210 | "base" 211 | ] 212 | }, 213 | "memo_is_required": { 214 | "btc": { 215 | "mainnet": false 216 | }, 217 | "1inch": { 218 | "erc20": false 219 | }, 220 | "eth": { 221 | "eth": false, 222 | "arb": false, 223 | "op": false, 224 | "base": false 225 | } 226 | }, 227 | "user_id": "00001", 228 | "name": "Jhon Doe", 229 | "email": "jhonDoe@mail.com", 230 | "profile_picture": null, 231 | "verification_status": "verified", 232 | "gauth_enable": true, 233 | "withdraw_status" : 1 // 1 if user can withdraw, 0 if user can't withdraw 234 | } 235 | } 236 | ``` 237 | 238 | #### Transaction History Endpoints 239 | This method gives list of deposits and withdrawals of all currencies. 240 | 241 | > ℹ️ **Information** 242 | > 243 | > As per 21 August 2024, 244 | > 245 | > Fetch transaction history have a validation maximum 7 days, default: last 7 days 246 | > 247 | > Max limit per fetch is 500 records (per deposit coin, withdraw coin, deposit idr, withdraw idr) 248 | > 249 | > Order descending by submit_time 250 | > 251 | 252 | Request Body 253 | 254 | | Name | Type | Mandatory | Description | Value | Default | 255 | |-|-|-|-|-|-| 256 | |`method`| string |yes|Specify the method you want to call |transHistory|| 257 | |`start`| date |optional|Specify the start date of transaction history you want to search |Y-m-d (eg: 2021-07-17)|7 days ago from today| 258 | |`end` | date |optional|Specify the end date of transaction history you want to search |Y-m-d (eg: 2021-07-17)|today| 259 | 260 | #### Example payload 261 | ```json 262 | { 263 | "method": "transHistory", 264 | "nonce": 1735516800, 265 | "start": "2024-07-01", 266 | "end": "2024-07-07" 267 | } 268 | ``` 269 | 270 | ### Response 271 | #### Positive Case 272 | ```json 273 | { 274 | "success": 1, 275 | "return": { 276 | "withdraw": { 277 | "idr": [ 278 | { 279 | "status": "success", 280 | "type": "coupon", 281 | "rp": "115205", 282 | "fee": "500", 283 | "amount": "114705", 284 | "submit_time": "1539844166", 285 | "success_time": "1539844189", 286 | "withdraw_id": "1783717", 287 | "tx": "BTC-IDR-RDTVVO2P-ETD0EVAW-VTNZGMIR-HTNTUAPI-84ULM9OI" 288 | }, 289 | ... 290 | ], 291 | "btc": [], 292 | "abyss": [], 293 | ... 294 | }, 295 | "deposit": { 296 | "idr": [ 297 | { 298 | "status": "success", 299 | "type": "duitku", 300 | "rp": "393000", 301 | "fee": "5895", 302 | "amount": "387105", 303 | "submit_time": "1576555012", 304 | "success_time": "1576555012", 305 | "deposit_id": "3395438", 306 | "tx": "Duitku OVO Settlement" 307 | }, 308 | ... 309 | ], 310 | "btc": [ 311 | { 312 | "status": "success", 313 | "btc": "0.00118769", 314 | "amount": "0.00118769", 315 | "success_time": "1539529208", 316 | "deposit_id": "3602369", 317 | "tx": "c816aeb35a5b42f389970325a32aff69bb6b2126784dcda8f23b9dd9570d6573" 318 | }, 319 | ... 320 | ], 321 | "abyss": [], 322 | ... 323 | } 324 | } 325 | } 326 | ``` 327 | 328 | 329 | #### Negative Case 330 | - Invalid Format Date 331 | ```json 332 | { 333 | "success": 0, 334 | "error": "date format must be formatted yyyy-mm-dd", 335 | "error_code": "invalid_date" 336 | } 337 | ``` 338 | 339 | - Days greater than 7 days 340 | ```json 341 | { 342 | "success": 0, 343 | "error": "range date can't more than 7 days", 344 | "error_code": "invalid_date" 345 | } 346 | ``` 347 | 348 | - Start date greater then end date 349 | ```json 350 | { 351 | "success": 0, 352 | "error": "start date must be less then end date", 353 | "error_code": "invalid_date" 354 | } 355 | ``` 356 | 357 | #### Trade Endpoints 358 | Provides access to essential trading functionalities and data for seamless integration with trading platforms. 359 | 360 | > ℹ️ **Important Updates** 361 | > 362 | > As per 10 September 2022, 363 | > - You may experience under filled order if using `idr` parameter when create buy order. To solve this issue, simply send `btc` instead `idr` and use `order_type : "limit"`. 364 | > - You can create buy limit order using coin (eg: `btc`) as amount. 365 | > - You can use `order_type : "market"` to create market order. 366 | > - You can try the new API version by creating account in https://demo-indodax.com. You will receive balance for some coins, approximately 1 minute after successfully sign-up. 367 | > - These coins can be used for trade testing, but can't be withdrawn. You also can't deposit any coin to demo-indodax.com. 368 | > 369 | > As per January 2024, 370 | > - You can create order by adding infomartional `client_order_id` (eg: `client_order_id : "clientx-sj82ks82j"`) 371 | > 372 | > ℹ️ **Information** 373 | > 374 | > The trade API implements a `rate limit of 20 requests per second` per `account` and `pair`. Exceeding this triggers a `5-second trading block` for the affected account and pair. 375 | > 376 | > As per 28 August 2024, 377 | > - We update the response format for rate limit trade like bellow 378 | > ```json 379 | > "status code": 429 380 | > "Content-Type": "application/json" 381 | > "Response Body": 382 | > { 383 | > "success": 0, 384 | > "error": "Your User ID sent too many trade request for pair BTCIDR, please try again in 5 seconds", 385 | > "message": "Your User ID sent too many trade request for pair BTCIDR, please try again in 5 seconds", 386 | > "error_code": "too_many_requests" 387 | > } 388 | > ``` 389 | 390 | \ 391 | Request Body 392 | 393 | | Name | Type | Mandatory | Description | Value | default | 394 | |-|-|-|-|-|-| 395 | |`method`| string |yes|Specify the method you want to call |trade| | 396 | |`pair`|string|yes|Pair to get the information from| btc_idr, ltc_btc, doge_btc, etc| | 397 | |`type`|string|yes|transaction type (buy or sell)|buy/sell|| 398 | |`price`|numeric|required on limit order|order price|5000000|| 399 | |`idr`|numeric|required for (limit/market) buy order with amount in IDR|amount of rupiah to buy coin|1000000|| 400 | |`btc`|numeric|required for limit buy order with amount in coin or sell order|amount of coin to buy/sell|0.001|| 401 | |`order_type`|string|optional|type of order|limit/market|limit| 402 | |`client_order_id`|string|optional, max 36 character, allowed = alphanumeric _-|set your client order id|eg: clientx-sj82ks82j|| 403 | |`time_in_force`|string|optional|currently only valid for "limit" order type, defines how long an order remains working till it is expired by the system|GTC,MOC|GTC| 404 | 405 | **Notes** 406 | - Request will be rejected if you send BUY order request with both `idr` set & `order_type` set to LIMIT. 407 | - Currently MARKET BUY order only support amount in `idr`. 408 | - Trade Request from Trade API with `order_type = limit` and `time_in_force = MOC` specified will be rejected if price is better than top of book price. 409 | 410 | Sample Payload for limit order using idr amount: 411 | ```javascript 412 | { 413 | "method": "trade" 414 | "nonce": 4531235 415 | "idr": 100000, 416 | "price": 500000, 417 | "type": "buy", 418 | "client_order_id": "clientx-sj82ks82j", // New field (optional) 419 | "time_in_force": "MOC" // New field (GTC, MOC) 420 | } 421 | ``` 422 | 423 | *Sample Payload for limit order using coin amount: 424 | ```javascript 425 | { 426 | "method": "trade", 427 | "nonce": 4531235, 428 | "btc": 0.001, 429 | "order_type": "limit", 430 | "price": 500000, 431 | "type": "buy", 432 | "client_order_id": "clientx-sj82ks82j", // New field (optional) 433 | "time_in_force": "MOC" // New field (GTC, MOC) 434 | } 435 | ``` 436 | 437 | *Sample Payload for market order: 438 | ```javascript 439 | { 440 | "method": "trade", 441 | "nonce": 4531235, 442 | "idr": 200000, 443 | "order_type": "market", 444 | "type": "buy", 445 | "client_order_id": "clientx-sj82ks82j" // New field (optional) 446 | } 447 | ``` 448 | 449 | Positive case 450 | 451 | Response 452 | ```json 453 | { 454 | "success": 1, 455 | "return": { 456 | "receive_btc": "0.00000000", 457 | "spend_rp": 0, 458 | "fee": 0, 459 | "remain_rp": 5000000, 460 | "order_id": 59632813, 461 | "client_order_id": "clientx-sj82ks82j" 462 | } 463 | } 464 | ``` 465 | 466 | Negative case 467 | 468 | Response `order_type = limit` 469 | ```json 470 | { 471 | "success": 0, 472 | "error": "Order cancelled because it’s not maker." 473 | } 474 | ``` 475 | 476 | Response `time_in_force = MOC` 477 | ```json 478 | { 479 | "success": 0, 480 | "error": "Order cancelled because it’s not maker." 481 | } 482 | ``` 483 | 484 | Response `limit in the money` 485 | ```json 486 | { 487 | "success": 0, 488 | "error": "Order cancelled because it’s not maker." 489 | } 490 | ``` 491 | 492 | Response `client_order_id` 493 | ```json 494 | { 495 | "success": 0, 496 | "error": "client order id clientx-sj82ks82j already exists" 497 | } 498 | ``` 499 | 500 | #### Trade History Endpoints 501 | This method gives information about transaction in buying and selling history. 502 | 503 | Request Body 504 | 505 | | Name | Type | Mandatory | Description | Value | default | 506 | |-|-|-|-|-|-| 507 | |`method`| string |yes|Specify the method you want to call |tradeHistory|| 508 | |`count`|numeric|no|number of transaction which will be displayed||1000| 509 | |`from_id`|numeric|no|first trade ID||| 510 | |`end_id`|numeric|no|end trade ID||| 511 | |`order`|string|no|sort by|asc / desc|desc| 512 | |`since`|timestamp|no|start time||unix time| 513 | |`end`|timestamp|no|end time||unix time| 514 | |`pair`|string|yes|Pair to get the information from|btc_idr, ltc_btc, doge_btc, etc|btc_idr| 515 | |`order_id`|numeric|no|order id|59636253|| 516 | 517 | Response 518 | ```json 519 | { 520 | "success": 1, 521 | "return": { 522 | "trades": [ 523 | { 524 | "trade_id": "17393994", 525 | "order_id": "59636253", 526 | "type": "sell", 527 | "btc": "0.00313482", 528 | "price": "107202000", 529 | "fee": "0", 530 | "trade_time": "1578645297", 531 | "client_order_id": "clientx-sj82ks82j" 532 | }, 533 | ... 534 | ] 535 | } 536 | } 537 | ``` 538 | 539 | #### Open Orders Endpoints 540 | This method gives the list of current open orders (buy and sell). 541 | 542 | Request Body 543 | 544 | | Name | Type | Mandatory | Description | Value | default | 545 | |-|-|-|-|-|-| 546 | |`method`| string |yes|Specify the method you want to call |openOrders|| 547 | |`pair`|string|no|Pair to get the information from|btc_idr, ltc_btc, doge_btc, etc|| 548 | 549 | Response `pair btc_idr` 550 | ```json 551 | { 552 | "success": 1, 553 | "return": { 554 | "orders": [ 555 | { 556 | "order_id": "172", 557 | "client_order_id": "clientx-sj82ks82j", 558 | "submit_time": "1693226027", 559 | "price": "421004000", 560 | "type": "sell", 561 | "order_type": "limit", 562 | "order_btc": "0.02000000", 563 | "remain_btc": "0.00133450" 564 | }, 565 | { 566 | "order_id": "173", 567 | "client_order_id": "clientx-sj82ks83j", 568 | "submit_time": "1693280465", 569 | "price": "421003000.00000000", 570 | "type": "buy", 571 | "order_type": "stoplimit", 572 | "order_idr": "1266293.00000000", 573 | "remain_idr": "1266293.00000000" 574 | } 575 | ] 576 | } 577 | } 578 | ``` 579 | Response `if pair is not set` 580 | 581 | ```json 582 | { 583 | "success": 1, 584 | "return": { 585 | "orders": { 586 | "btc_idr": [ 587 | { 588 | "order_id": "172", 589 | "client_order_id": "clientx-sj82ks82j", 590 | "submit_time": "1693226027", 591 | "price": "421004000", 592 | "type": "sell", 593 | "order_type": "limit", 594 | "order_btc": "0.02000000", 595 | "remain_btc": "0.00133450" 596 | }, 597 | { 598 | "order_id": "173", 599 | "client_order_id": "clientx-sj82ks83j", 600 | "submit_time": "1693280465", 601 | "price": "421003000.00000000", 602 | "type": "buy", 603 | "order_type": "stoplimit", 604 | "order_idr": "1266293.00000000", 605 | "remain_idr": "1266293.00000000" 606 | } 607 | ] 608 | } 609 | } 610 | } 611 | ``` 612 | 613 | #### Order History 614 | This method gives the list of order history (buy and sell) 615 | 616 | Request Body 617 | 618 | | Name | Type | Mandatory | Description | Value | default | 619 | |-|-|-|-|-|-| 620 | |`method`| string |yes|Specify the method you want to call |orderHistory|| 621 | |`pair`|string|yes|Pair to get the information from|btc_idr, ltc_btc, doge_btc, etc|btc_idr| 622 | |`count`|int|no|number of transaction which will be displayed||1000| 623 | |`from`|int|no|||| 624 | 625 | Response 626 | ```json 627 | { 628 | "success": 1, 629 | "return": { 630 | "orders": [ 631 | { 632 | "order_id": "59639504", 633 | "client_order_id": "clientx-sj82ks82j", 634 | "type": "buy", 635 | "price": "100207000", 636 | "submit_time": "1578648363", 637 | "finish_time": "1578649332", 638 | "status": "cancelled", 639 | "order_idr": "336058", 640 | "remain_idr": "336058" 641 | }, 642 | { 643 | "order_id": "59636253", 644 | "client_order_id": "clientx-sj82ks83j", 645 | "type": "sell", 646 | "price": "107202000", 647 | "submit_time": "1578645288", 648 | "finish_time": "1578645297", 649 | "status": "filled", 650 | "order_btc": "0.00313482", 651 | "remain_btc": "0.00000000" 652 | }... 653 | ] 654 | } 655 | } 656 | ``` 657 | 658 | #### Get Order Endpoints 659 | Use getOrder to get specific order details. 660 | 661 | Request Body 662 | 663 | | Name | Type | Mandatory | Description | Value | default | 664 | |-|-|-|-|-|-| 665 | |`method`| string |yes|Specify the method you want to call |getOrder|| 666 | |`pair`|string|yes|Pair to get the information from|btc_idr, ltc_btc, doge_btc, etc|btc_idr| 667 | |`order_id`|int|yes|Order ID|59639504|| 668 | 669 | Response 670 | ```json 671 | { 672 | "success": 1, 673 | "return": { 674 | "order": { 675 | "order_id": "59639504", 676 | "price": "100207000", 677 | "type": "buy", 678 | "order_rp": "336058", 679 | "remain_rp": "336058", 680 | "submit_time": "1578648363", 681 | "finish_time": "1578649332", 682 | "status": "cancelled", 683 | "receive_idr": "336058", 684 | "client_order_id": "clientx-sj82ks82j" 685 | } 686 | } 687 | } 688 | ``` 689 | Response for `refund order done` 690 | ```json 691 | { 692 | "success": 1, 693 | "return": { 694 | "order": { 695 | "order_id": "59639504", 696 | "price": "100207000", 697 | "type": "buy", 698 | "order_rp": "336058", 699 | "remain_rp": "336058", 700 | "submit_time": "1578648363", 701 | "finish_time": "1578649332", 702 | "status": "cancelled", 703 | "receive_idr": "336058", 704 | "refund_idr": "3866", 705 | "client_order_id": "clientx-sj82ks82j" 706 | } 707 | } 708 | } 709 | ``` 710 | 711 | #### Get Order By Client Order ID Endpoints 712 | Use getOrderByClientOrderId to get specific order details by Client Order ID. 713 | 714 | Request Body 715 | 716 | | Name | Type | Mandatory | Description | Value | default | 717 | |-|-|-|-|-|-| 718 | |`method`| string |yes|Specify the method you want to call |getOrderByClientOrderId|| 719 | |`client_order_id`|string|yes|Client Order ID|clientx-sj82ks82j|| 720 | 721 | Response 722 | ```json 723 | { 724 | "success": 1, 725 | "return": { 726 | "order": { 727 | "order_id": "59639504", 728 | "client_order_id": "clientx-sj82ks82j", 729 | "price": "100207000", 730 | "type": "buy", 731 | "order_rp": "336058", 732 | "remain_rp": "336058", 733 | "submit_time": "1578648363", 734 | "finish_time": "1578649332", 735 | "status": "cancelled", 736 | "receive_idr": "336058", 737 | } 738 | } 739 | } 740 | ``` 741 | Response for `refund order done` 742 | ```json 743 | { 744 | "success": 1, 745 | "return": { 746 | "order": { 747 | "order_id": "59639504", 748 | "client_order_id": "clientx-sj82ks82j", 749 | "price": "100207000", 750 | "type": "buy", 751 | "order_rp": "336058", 752 | "remain_rp": "336058", 753 | "submit_time": "1578648363", 754 | "finish_time": "1578649332", 755 | "status": "cancelled", 756 | "receive_idr": "336058", 757 | "refund_idr": "3866" 758 | } 759 | } 760 | } 761 | ``` 762 | 763 | #### Cancel Order Endpoints 764 | This method is for canceling an existing open order. 765 | 766 | > ℹ️ **Information** 767 | > 768 | > As per 28 August 2024, 769 | > 770 | > The trade API implements a `rate limit of 30 requests per second` for cancel order. 771 | > ```json 772 | > "status code": 429 773 | > "Content-Type": "application/json" 774 | > "Response Body": 775 | > { 776 | > "success": 0, 777 | > "error": "Your User ID sent too many cancel order requests", 778 | > "error_code": "too_many_requests" 779 | > } 780 | > ``` 781 | 782 | Request Body 783 | 784 | | Name | Type | Mandatory | Description | Value | default | 785 | |-|-|-|-|-|-| 786 | |`method`| string |yes|Specify the method you want to call |cancelOrder|| 787 | |`pair`|string|yes|Pair to get the information from|btc_idr, ltc_btc, doge_btc, etc|btc_idr| 788 | |`order_id`|int|yes|Order ID|10.00000000|| 789 | |`type`|int|yes|Transaction type|buy / sell|| 790 | |`order_type`|string|optional|type of order|limit, stoplimit|limit| 791 | 792 | Response 793 | ```json 794 | { 795 | "success": 1, 796 | "return": { 797 | "order_id": 666883, 798 | "client_order_id": "clientx-sj82ks82j", 799 | "type": "sell", 800 | "pair": "btc_idr", 801 | "balance": { 802 | "idr": "33605800", 803 | "btc": "0.00000000", 804 | ... 805 | "frozen_idr": "0", 806 | "frozen_btc": "0.00000000", 807 | ... 808 | } 809 | } 810 | } 811 | ``` 812 | 813 | #### Cancel Order By Client Order ID Endpoints 814 | This method is for canceling an existing open order by client_order_id. 815 | 816 | > ℹ️ **Information** 817 | > 818 | > As per 28 August 2024, 819 | > 820 | > The trade API implements a `rate limit of 30 requests per second` for cancel order by Client Order ID. 821 | > ```json 822 | > "status code": 429 823 | > "Content-Type": "application/json" 824 | > "Response Body": 825 | > { 826 | > "success": 0, 827 | > "error": "Your User ID sent too many cancel order requests", 828 | > "error_code": "too_many_requests" 829 | > } 830 | > ``` 831 | 832 | Request Body 833 | 834 | | Name | Type | Mandatory | Description | Value | default | 835 | |-|-|-|-|-|-| 836 | |`method`| string |yes|Specify the method you want to call |cancelByClientOrderId|| 837 | |`client_order_id`|string|yes|Client Order ID|clientx-sj82ks82j|| 838 | 839 | Response 840 | ```json 841 | { 842 | "success": 1, 843 | "return": { 844 | "order_id": 666883, 845 | "client_order_id": "clientx-sj82ks82j", 846 | "type": "sell", 847 | "pair": "btc_idr", 848 | "balance": { 849 | "idr": "33605800", 850 | "btc": "0.00000000", 851 | ... 852 | "frozen_idr": "0", 853 | "frozen_btc": "0.00000000", 854 | ... 855 | } 856 | } 857 | } 858 | ``` 859 | 860 | #### Withdraw Fee Endpoints 861 | This method is for check withdraw fee 862 | 863 | To be able to use this method you need to enable withdraw permission when you generate the API Key. Otherwise you will get “No permission” error. 864 | 865 | Request Body 866 | 867 | | Name | Type | Mandatory | Description | Value | default | 868 | |-|-|-|-|-|-| 869 | |`method`| string |yes|Specify the method you want to call |withdrawFee|| 870 | |`currency`|string|yes|Currency for check withdraw fee |btc, ltc, doge, eth, etc|| 871 | |`network`|string|no|Set optional network to see withdrawFee on coin with multiple network |erc20, trc20, bep2, bep20, etc|| 872 | 873 | Response success 874 | ```json 875 | { 876 | "success": 1, 877 | "return": { 878 | "server_time": 1607923272, 879 | "withdraw_fee": 0.005, 880 | "currency": "eth" 881 | } 882 | } 883 | ``` 884 | 885 | Response with `invalid network` 886 | ```json 887 | { 888 | "success": 0, 889 | "error" : "Invalid network, please fill with one of this erc20, trc20, bep20", 890 | "error_code": "" 891 | } 892 | ``` 893 | 894 | #### Withdraw Coin Endpoints 895 | This method is for withdrawing assets (except IDR). You can use `address` and [username](https://github.com/btcid/indodax-official-api-docs/blob/master/Private-RestAPI.md#withdraw-coin-by-username) option when sending crypto via TAPI 896 | 897 | If client withdraw from TAPI by `internal address`, there’s no fee **(fee=0)**. 898 | 899 | To be able to use this method you need to enable withdraw permission when you generate the API Key. Otherwise you will get “No permission” error. 900 | 901 | You also need to prepare a Callback URL. Callback URL is a URL that our system will call to verify your withdrawal requests. Various parameters will be sent to Callback URL, make sure to check this information on your server side. If all the data is correct, print out a string “ok” (without quotes). We will continue the request if only we receive “ok” (without quotes) response, otherwise the request will be failed. 902 | 903 | Callback call will be sent through a POST request, with 5 seconds connection timeout. 904 | 905 | 906 | Request Body 907 | 908 | | Name | Type | Mandatory | Description | Value | default | 909 | |-|-|-|-|-|-| 910 | |`method`| string |yes|Specify the method you want to call |withdrawCoin|| 911 | |`currency`|string|yes|Currency to withdraw|btc, ltc, doge, eth, etc|| 912 | |`network`|string|yes|Currency network if exist|erc20, trc20, bep2, bep20|| 913 | |`withdraw_address`|string|yes|Receiver address|a valid address|| 914 | |`withdraw_amount`|numeric|yes|Amount to send|10.00000000|| 915 | |`withdraw_memo`|string|no|Memo to be sent to the receiver, if supported by the asset platform. Exchanges use this memo for accepting deposits for certain assets.Example: Destination Tag (for Ripple)Message (for NXT)Memo (for BitShares)|a valid memo/message/destination tag|| 916 | |`request_id`|alphanumeric max 255 char|yes|Custom string you need to provide to identify each withdrawal request.|request_id will be passed to callback call so your system can identify the request.d||| 917 | 918 | Response 919 | ```json 920 | { 921 | "success": 1, 922 | "status": "approved", 923 | "withdraw_currency": "doge", 924 | "withdraw_address": "D9iCdBLBosJzGSvpQGMSobwtdgB2rS1zam", 925 | "withdraw_amount": "10.00000000", 926 | "fee": "5.00000000", 927 | "amount_after_fee": "5.00000000", 928 | "submit_time": "1578909560", 929 | "withdraw_id": "doge-1941965", 930 | "txid": "" 931 | } 932 | ``` 933 | 934 | Response `Withdraw to Own Address` 935 | 936 | ```json 937 | { 938 | "success": 0, 939 | "error": "Please use recipient address other than your Indodax account address", 940 | "error_code": "" 941 | } 942 | ``` 943 | 944 | Callback Parameter Sent to Client 945 | 946 | |Parameter|Description| 947 | |-|-| 948 | |request_id|request_id from your request| 949 | |withdraw_currency|currency from your request| 950 | |withdraw_address|withdraw_address from your request| 951 | |withdraw_amount|withdraw_amount from your request| 952 | |withdraw_memo|withdraw_memo from your request (if any)| 953 | |requester_ip|requester_ip of the request| 954 | |request_date|time the request submitted | 955 | 956 | #### Withdraw Coin by Username 957 | 958 | Client can view and use `username` option when sending crypto via TAPI. If client withdraw from TAPI by Indodax `username`, there’s no fee **(fee=0)**. 959 | 960 | Request Body 961 | 962 | | Name | Type | Mandatory | Description | Value | default | 963 | |-|-|-|-|-|-| 964 | |`method`| string |yes|Specify the method you want to call |withdrawCoin|| 965 | |`currency`|string|yes|Currency to withdraw|btc, ltc, doge, eth, etc|| 966 | |`withdraw_amount`|numeric|yes|Amount to send|10.00000000|| 967 | |`withdraw_memo`|string|no|Memo to be sent to the receiver, if supported by the asset platform. Exchanges use this memo for accepting deposits for certain assets.Example: Destination Tag (for Ripple)Message (for NXT)Memo (for BitShares)|a valid memo/message/destination tag|| 968 | |`request_id`|alphanumeric max 255 char|yes|Custom string you need to provide to identify each withdrawal request.|request_id will be passed to callback call so your system can identify the request.d||| 969 | |`withdraw_input_method`| |yes|Withdraw using method username or address |username|| 970 | |`withdraw_username`|alphanumeric|yes|username withdraw from your request & followed by special character underscrore (_) or strip (-). Mandatory id withdraw_input_method = username ||| 971 | 972 | Response success `Withdraw Username (BNB)` 973 | ```json 974 | { 975 | "success": 1, 976 | "status": "wait", 977 | "withdraw_currency": "aave", 978 | "withdraw_address": "" 979 | "withdraw_amount": "0.05000000", 980 | "fee": "0.00000000", 981 | "amount_after_fee": "0.05000000", 982 | "submit_time": "1684723796", 983 | "withdraw_id": "aave-163", 984 | "txid": "", 985 | "withdraw_username": "User_13" 986 | } 987 | ``` 988 | 989 | Response `Withdraw Username (BNB) with invalid Username` 990 | ```json 991 | { 992 | "success": 1, 993 | "error" : "Username is not found!" 994 | "error_code": "" 995 | } 996 | ``` 997 | 998 | Response `Withdraw Username (AAVE) 0 Coin` 999 | ```json 1000 | { 1001 | "success": 1, 1002 | "error" : "Can't make withdrawal with amount 0, input a larger withdraw_amount value" 1003 | "error_code": "" 1004 | } 1005 | ``` 1006 | 1007 | Response `Withdraw Username (AAVE) > Maksimum Coin per Day` 1008 | ```json 1009 | { 1010 | "success": 1, 1011 | "error" : "Exceeded today's limit. Remain limit: 217.35817575 AAVE. To increase the limit, please contact customer service." 1012 | } 1013 | ``` 1014 | 1015 | Response `Withdraw to Own Username` 1016 | 1017 | ```json 1018 | { 1019 | "success": 0, 1020 | "error": "Please use recipient address other than your Indodax account address", 1021 | "error_code": "" 1022 | } 1023 | ``` 1024 | 1025 | Callback Parameter Sent to Client 1026 | 1027 | |Parameter|Description| 1028 | |-|-| 1029 | |request_id|request_id from your request| 1030 | |withdraw_currency|currency from your request| 1031 | |withdraw_address|| 1032 | |withdraw_amount|withdraw_amount from your request| 1033 | |withdraw_memo|withdraw_memo from your request (if any)| 1034 | |withdraw_username|username withdraw from your request| 1035 | |requester_ip|requester_ip of the request| 1036 | |request_date|time the request submitted | 1037 | 1038 | #### List Downline Endpoints 1039 | This method is for list all downline in current user 1040 | 1041 | Request Body 1042 | 1043 | | Name | Type | Mandatory | Description | Value | default | 1044 | |-|-|-|-|-|-| 1045 | |`method`| string |yes|Specify the method you want to call |listDownline|| 1046 | |`page`| int |yes|Set the page you want to show |1|| 1047 | |`limit`| int |yes|Set how many data you want to show |10|200| 1048 | 1049 | Response 1050 | ```json 1051 | { 1052 | "success": 1, 1053 | "return": { 1054 | "curr_page": 1, 1055 | "total_page": 102, 1056 | "total_data_per_page": 2, 1057 | "total": 203, 1058 | "data": [ 1059 | { 1060 | "name": "btc users", 1061 | "username": "btcusers", 1062 | "registration_date": "9-Jun-20 15:54", 1063 | "email_verified": true, 1064 | "id_verified": true, 1065 | "level": "n/a", 1066 | "end": "n/a", 1067 | "start": "n/a" 1068 | }, 1069 | { 1070 | "name": "idx users", 1071 | "username": "idxusers", 1072 | "registration_date": "8-Jun-20 15:51", 1073 | "email_verified": true, 1074 | "id_verified": false, 1075 | "level": "n/a", 1076 | "end": "n/a", 1077 | "start": "n/a" 1078 | } 1079 | ] 1080 | } 1081 | } 1082 | ``` 1083 | 1084 | #### Check Downline Endpoints 1085 | This method is for check wheter email exists in current user downline or not 1086 | return is 1 or 0. 1087 | 1 means this email is exists in current user downline 1088 | 0 means email doesn't exists in current user downline 1089 | 1090 | Request Body 1091 | 1092 | | Name | Type | Mandatory | Description | Value | default | 1093 | |-|-|-|-|-|-| 1094 | |`method`| string |yes|Specify the method you want to call |listDownline|| 1095 | |`email`|string|yes|Email want to check|btc@gmail.com, idx@yahoo.com|| 1096 | 1097 | Response 1098 | ```json 1099 | { 1100 | "success": "1", 1101 | "is_downline": "0" 1102 | } 1103 | ``` 1104 | 1105 | #### Create Voucher Endpoints 1106 | This method used to generate Indodax voucher programmatically. To be able to use this method you need to be a partner and sign official aggreement between you and Indodax. 1107 | 1108 | Request Body 1109 | 1110 | | Name | Type | Mandatory | Description | Value | default | 1111 | |-|-|-|-|-|-| 1112 | |`method`| string |yes|Specify the method you want to call |createVoucher|| 1113 | |`amount`|number|yes|The voucher value in rupiah|Minimum 1000|| 1114 | |`to_email`|strinng|yes|The recipient email address which registered in Indodax|e.g. idx@gmail.com|| 1115 | 1116 | Response 1117 | ```json 1118 | { 1119 | "success": 1, 1120 | "withdraw_id": 1234, 1121 | "rp": 10000, 1122 | "submit_time": "1578909560", 1123 | "voucher": "BTC-IDR-XXXX" 1124 | } 1125 | ``` 1126 | --------------------------------------------------------------------------------