# Perps REST API

## Perps Market Endpoints

### Query symbols

`GET ${PERPS_ENDPOINT}/markets/symbols`

*Get perpetual contract information for all symbols.*

```bash
curl -X GET ${PERPS_ENDPOINT}/markets/symbols \
  -H 'Accept: application/json'
```

#### Query Parameters

| Name     | Type     | Required | Description                 |
| -------- | -------- | -------- | --------------------------- |
| `symbol` | `string` | `false`  | Symbol name, e.g. `BTC-USD` |

#### Response

| Field  | Type                 | Description                                                                                                                                                                 |
| ------ | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data` | `Array<PerpsSymbol>` | Response data when code is `0`. See [`PerpsSymbol`](https://sodex.com/documentation/api/schema#perpssymbol) in [Schema](https://sodex.com/documentation/api/rest-v1/schema) |

### Query coins

`GET ${PERPS_ENDPOINT}/markets/coins`

*Get information for all coins.*

```bash
curl -X GET ${PERPS_ENDPOINT}/markets/coins \
  -H 'Accept: application/json'
```

#### Query Parameters

| Name   | Type     | Required | Description             |
| ------ | -------- | -------- | ----------------------- |
| `coin` | `string` | `false`  | Coin name, e.g. `vUSDC` |

#### Response

| Field  | Type               | Description                                                                                                                                                             |
| ------ | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data` | `Array<PerpsCoin>` | Response data when code is `0`. See [`PerpsCoin`](https://sodex.com/documentation/api/schema#perpscoin) in [Schema](https://sodex.com/documentation/api/rest-v1/schema) |

### Query tickers

`GET ${PERPS_ENDPOINT}/markets/tickers`

*Get 24hr rolling window price change statistics for all perpetual symbols.*

```bash
curl -X GET ${PERPS_ENDPOINT}/markets/tickers \
  -H 'Accept: application/json'
```

#### Query Parameters

| Name     | Type     | Required | Description                 |
| -------- | -------- | -------- | --------------------------- |
| `symbol` | `string` | `false`  | Symbol name, e.g. `BTC-USD` |

#### Response

| Field  | Type                 | Description                                                                                                                                                                 |
| ------ | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data` | `Array<PerpsTicker>` | Response data when code is `0`. See [`PerpsTicker`](https://sodex.com/documentation/api/schema#perpsticker) in [Schema](https://sodex.com/documentation/api/rest-v1/schema) |

### Query mini tickers

`GET ${PERPS_ENDPOINT}/markets/miniTickers`

*Get 24hr rolling window price change statistics for all perpetual symbols.*

```bash
curl -X GET ${PERPS_ENDPOINT}/markets/miniTickers \
  -H 'Accept: application/json'
```

#### Query Parameters

| Name     | Type     | Required | Description                 |
| -------- | -------- | -------- | --------------------------- |
| `symbol` | `string` | `false`  | Symbol name, e.g. `BTC-USD` |

#### Response

| Field  | Type                | Description                                                                                                                                                               |
| ------ | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data` | `Array<MiniTicker>` | Response data when code is `0`. See [`MiniTicker`](https://sodex.com/documentation/api/schema#miniticker) in [Schema](https://sodex.com/documentation/api/rest-v1/schema) |

### Query mark prices

`GET ${PERPS_ENDPOINT}/markets/mark-prices`

*Mark price information for symbols.*

```bash
curl -X GET ${PERPS_ENDPOINT}/markets/mark-prices \
  -H 'Accept: application/json'
```

#### Query Parameters

| Name     | Type     | Required | Description                 |
| -------- | -------- | -------- | --------------------------- |
| `symbol` | `string` | `false`  | Symbol name, e.g. `BTC-USD` |

#### Response

| Field  | Type                     | Description                                                                                                                                                                         |
| ------ | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data` | `Array<MarkPriceTicker>` | Response data when code is `0`. See [`MarkPriceTicker`](https://sodex.com/documentation/api/schema#markpriceticker) in [Schema](https://sodex.com/documentation/api/rest-v1/schema) |

### Query book tickers

`GET ${PERPS_ENDPOINT}/markets/bookTickers`

*Best price/qty on the order book for symbols.*

```bash
curl -X GET ${PERPS_ENDPOINT}/markets/bookTickers \
  -H 'Accept: application/json'
```

#### Query Parameters

| Name     | Type     | Required | Description                 |
| -------- | -------- | -------- | --------------------------- |
| `symbol` | `string` | `false`  | Symbol name, e.g. `BTC-USD` |

#### Response

| Field  | Type                | Description                                                                                                                                                               |
| ------ | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data` | `Array<BookTicker>` | Response data when code is `0`. See [`BookTicker`](https://sodex.com/documentation/api/schema#bookticker) in [Schema](https://sodex.com/documentation/api/rest-v1/schema) |

### Query order book

`GET ${PERPS_ENDPOINT}/markets/{symbol}/orderbook`

*Get order book depth for a perpetual symbol.*

```bash
curl -X GET "${PERPS_ENDPOINT}/markets/BTC-USD/orderbook?limit=20" \
  -H 'Accept: application/json'
```

#### Path Parameters

| Name     | Type     | Required | Description                 |
| -------- | -------- | -------- | --------------------------- |
| `symbol` | `string` | `true`   | Symbol name, e.g. `BTC-USD` |

#### Query Parameters

| Name    | Type     | Required | Description                             |
| ------- | -------- | -------- | --------------------------------------- |
| `limit` | `uint32` | `false`  | Depth limit. Default: `10`, Max: `1000` |

#### Response

| Field  | Type        | Description                                                                                                                                                             |
| ------ | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data` | `OrderBook` | Response data when code is `0`. See [`OrderBook`](https://sodex.com/documentation/api/schema#orderbook) in [Schema](https://sodex.com/documentation/api/rest-v1/schema) |

### Query candles/klines

`GET ${PERPS_ENDPOINT}/markets/{symbol}/klines`

*Get candlestick/kline data for a perpetual symbol.*

```bash
curl -X GET "${PERPS_ENDPOINT}/markets/BTC-USD/klines?interval=1h&limit=100" \
  -H 'Accept: application/json'
```

#### Path Parameters

| Name     | Type     | Required | Description                 |
| -------- | -------- | -------- | --------------------------- |
| `symbol` | `string` | `true`   | Symbol name, e.g. `BTC-USD` |

#### Query Parameters

| Name        | Type     | Required | Description                                                            |
| ----------- | -------- | -------- | ---------------------------------------------------------------------- |
| `interval`  | `string` | `true`   | Kline interval: `1m`, `5m`, `15m`, `30m`, `1h`, `4h`, `1D`, `1W`, `1M` |
| `startTime` | `uint64` | `false`  | Start time in milliseconds                                             |
| `endTime`   | `uint64` | `false`  | End time in milliseconds                                               |
| `limit`     | `uint32` | `false`  | Number of klines to return. Default: `500`, Max: `1000`                |

#### Response

| Field  | Type              | Description                                                                                                                                                           |
| ------ | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data` | `Array<RPCKline>` | Response data when code is `0`. See [`RPCKline`](https://sodex.com/documentation/api/schema#rpckline) in [Schema](https://sodex.com/documentation/api/rest-v1/schema) |

### Query recent trades

`GET ${PERPS_ENDPOINT}/markets/{symbol}/trades`

*Get recent public trades for a perpetual symbol.*

```bash
curl -X GET "${PERPS_ENDPOINT}/markets/BTC-USD/trades?limit=50" \
  -H 'Accept: application/json'
```

#### Path Parameters

| Name     | Type     | Required | Description                 |
| -------- | -------- | -------- | --------------------------- |
| `symbol` | `string` | `true`   | Symbol name, e.g. `BTC-USD` |

#### Query Parameters

| Name    | Type     | Required | Description                                           |
| ------- | -------- | -------- | ----------------------------------------------------- |
| `limit` | `uint32` | `false`  | Number of trades to return. Default: `50`, Max: `500` |

#### Response

| Field  | Type           | Description                                                                                                                                                     |
| ------ | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data` | `Array<Trade>` | Response data when code is `0`. See [`Trade`](https://sodex.com/documentation/api/schema#trade) in [Schema](https://sodex.com/documentation/api/rest-v1/schema) |

## Perps Account Endpoints

### Query balances

`GET ${PERPS_ENDPOINT}/accounts/{userAddress}/balances`

*Get current account balance.*

```bash
curl -X GET ${PERPS_ENDPOINT}/accounts/0x0123456789070ce8f0d6bab722103d12674bc257/balances \
  -H 'Accept: application/json'
```

#### Path Parameters

| Name          | Type        | Required | Description      |
| ------------- | ----------- | -------- | ---------------- |
| `userAddress` | `HexString` | `true`   | User EVM address |

#### Query Parameters

| Name        | Type     | Required | Description                                                            |
| ----------- | -------- | -------- | ---------------------------------------------------------------------- |
| `accountID` | `uint64` | `false`  | The sub-account ID of the user. Primary account ID is used by default. |

#### Response

| Field  | Type                  | Description                                                                                                                                                                                 |
| ------ | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data` | `PerpsAccountBalance` | Response data when code is `0`. See [`PerpsAccountBalance`](https://sodex.com/documentation/api/schema#perpsaccountbalance) in [Schema](https://sodex.com/documentation/api/rest-v1/schema) |

### Query open orders

`GET ${PERPS_ENDPOINT}/accounts/{userAddress}/orders`

*Get all open orders for an account.*

```bash
curl -X GET "${PERPS_ENDPOINT}/accounts/0x0123456789070ce8f0d6bab722103d12674bc257/orders?symbol=BTC-USD" \
  -H 'Accept: application/json'
```

#### Path Parameters

| Name          | Type        | Required | Description      |
| ------------- | ----------- | -------- | ---------------- |
| `userAddress` | `HexString` | `true`   | User EVM address |

#### Query Parameters

| Name        | Type     | Required | Description                                                            |
| ----------- | -------- | -------- | ---------------------------------------------------------------------- |
| `symbol`    | `string` | `false`  | Filter by symbol name                                                  |
| `accountID` | `uint64` | `false`  | The sub-account ID of the user. Primary account ID is used by default. |

#### Response

| Field  | Type                    | Description                                                                                                                                                                                     |
| ------ | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data` | `PerpsAccountOpenOrder` | Response data when code is `0`. See [`PerpsAccountOpenOrder`](https://sodex.com/documentation/api/schema#perpsaccountopenorder) in [Schema](https://sodex.com/documentation/api/rest-v1/schema) |

### Query open positions

`GET ${PERPS_ENDPOINT}/accounts/{userAddress}/positions`

*Get all open positions for an account.*

```bash
curl -X GET "${PERPS_ENDPOINT}/accounts/0x0123456789070ce8f0d6bab722103d12674bc257/positions" \
  -H 'Accept: application/json'
```

#### Path Parameters

| Name          | Type        | Required | Description      |
| ------------- | ----------- | -------- | ---------------- |
| `userAddress` | `HexString` | `true`   | User EVM address |

#### Query Parameters

| Name        | Type     | Required | Description                                                            |
| ----------- | -------- | -------- | ---------------------------------------------------------------------- |
| `accountID` | `uint64` | `false`  | The sub-account ID of the user. Primary account ID is used by default. |

#### Response

| Field  | Type                       | Description                                                                                                                                                                                           |
| ------ | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data` | `PerpsAccountOpenPosition` | Response data when code is `0`. See [`PerpsAccountOpenPosition`](https://sodex.com/documentation/api/schema#perpsaccountopenposition) in [Schema](https://sodex.com/documentation/api/rest-v1/schema) |

### Query state for frontend

`GET ${PERPS_ENDPOINT}/accounts/{userAddress}/state`

*Get comprehensive account state for UI initialization. Includes balances, positions, open orders, and sync metadata.*

```bash
curl -X GET ${PERPS_ENDPOINT}/accounts/0x0123456789070ce8f0d6bab722103d12674bc257/state \
  -H 'Accept: application/json'
```

#### Path Parameters

| Name          | Type        | Required | Description      |
| ------------- | ----------- | -------- | ---------------- |
| `userAddress` | `HexString` | `true`   | User EVM address |

#### Query Parameters

| Name        | Type     | Required | Description                                                            |
| ----------- | -------- | -------- | ---------------------------------------------------------------------- |
| `accountID` | `uint64` | `false`  | The sub-account ID of the user. Primary account ID is used by default. |

#### Response

| Field  | Type           | Description                                                                                                                                                                   |
| ------ | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data` | `WsPerpsState` | Response data when code is `0`. See [`WsPerpsState`](https://sodex.com/documentation/api/schema#wsperpsstate) in [Schema](https://sodex.com/documentation/api/rest-v1/schema) |

### Query API Keys

`GET ${PERPS_ENDPOINT}/accounts/{userAddress}/api-keys`

*Get list of API keys.*

```bash
curl -X GET "${PERPS_ENDPOINT}/accounts/0x0123456789070ce8f0d6bab722103d12674bc257/api-keys" \
  -H 'Accept: application/json'
```

#### Path Parameters

| Name          | Type        | Required | Description      |
| ------------- | ----------- | -------- | ---------------- |
| `userAddress` | `HexString` | `true`   | User EVM address |

#### Query Parameters

| Name        | Type     | Required | Description                                                            |
| ----------- | -------- | -------- | ---------------------------------------------------------------------- |
| `accountID` | `uint64` | `false`  | The sub-account ID of the user. Primary account ID is used by default. |
| `name`      | `string` | `false`  | The name of the API key.                                               |

#### Response

| Field  | Type            | Description                                                                                                                                                       |
| ------ | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data` | `Array<APIKey>` | Response data when code is `0`. See [`APIKey`](https://sodex.com/documentation/api/schema#apikey) in [Schema](https://sodex.com/documentation/api/rest-v1/schema) |

### Query fee rate

`GET ${PERPS_ENDPOINT}/accounts/{userAddress}/fee-rate`

*Get the current maker/taker fee rates for the account, including fee tier, staking tier, and maker rebate tier. Optionally pass a symbol to include the symbol-level fee discount.*

```bash
curl -X GET "${PERPS_ENDPOINT}/accounts/0x0123456789070ce8f0d6bab722103d12674bc257/fee-rate?symbol=BTC-USD" \
  -H 'Accept: application/json'
```

#### Path Parameters

| Name          | Type        | Required | Description      |
| ------------- | ----------- | -------- | ---------------- |
| `userAddress` | `HexString` | `true`   | User EVM address |

#### Query Parameters

| Name        | Type     | Required | Description                                                                           |
| ----------- | -------- | -------- | ------------------------------------------------------------------------------------- |
| `accountID` | `uint64` | `false`  | The sub-account ID of the user. Primary account ID is used by default.                |
| `symbol`    | `string` | `false`  | Symbol name, e.g. `BTC-USD`. When provided, the symbol-level fee discount is applied. |

#### Response

| Field  | Type      | Description                                                                                                                                                         |
| ------ | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data` | `FeeRate` | Response data when code is `0`. See [`FeeRate`](https://sodex.com/documentation/api/schema#feerate) in [Schema](https://sodex.com/documentation/api/rest-v1/schema) |

### Query order history

`GET ${PERPS_ENDPOINT}/accounts/{userAddress}/orders/history`

*Get historical orders (filled, canceled, expired) for an account.*

```bash
curl -X GET "${PERPS_ENDPOINT}/accounts/0x0123456789070ce8f0d6bab722103d12674bc257/orders/history?symbol=BTC-USD" \
  -H 'Accept: application/json'
```

#### Path Parameters

| Name          | Type        | Required | Description      |
| ------------- | ----------- | -------- | ---------------- |
| `userAddress` | `HexString` | `true`   | User EVM address |

#### Query Parameters

| Name        | Type     | Required | Description                                                            |
| ----------- | -------- | -------- | ---------------------------------------------------------------------- |
| `accountID` | `uint64` | `false`  | The sub-account ID of the user. Primary account ID is used by default. |
| `symbol`    | `string` | `false`  | Filter by symbol name                                                  |
| `startTime` | `uint64` | `false`  | Start time in milliseconds                                             |
| `endTime`   | `uint64` | `false`  | End time in milliseconds                                               |
| `limit`     | `uint32` | `false`  | Number of orders to return. Default: `50`, Max: `500`                  |

#### Response

| Field  | Type                | Description                                                                                                                                                               |
| ------ | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data` | `Array<PerpsOrder>` | Response data when code is `0`. See [`PerpsOrder`](https://sodex.com/documentation/api/schema#perpsorder) in [Schema](https://sodex.com/documentation/api/rest-v1/schema) |

### Query position history

`GET ${PERPS_ENDPOINT}/accounts/{userAddress}/positions/history`

*Get historical positions (closed) for an account.*

```bash
curl -X GET "${PERPS_ENDPOINT}/accounts/0x0123456789070ce8f0d6bab722103d12674bc257/positions/history?symbol=BTC-USD" \
  -H 'Accept: application/json'
```

#### Path Parameters

| Name          | Type        | Required | Description      |
| ------------- | ----------- | -------- | ---------------- |
| `userAddress` | `HexString` | `true`   | User EVM address |

#### Query Parameters

| Name        | Type     | Required | Description                                                            |
| ----------- | -------- | -------- | ---------------------------------------------------------------------- |
| `accountID` | `uint64` | `false`  | The sub-account ID of the user. Primary account ID is used by default. |
| `symbol`    | `string` | `false`  | Filter by symbol name                                                  |
| `startTime` | `uint64` | `false`  | Start time in milliseconds                                             |
| `endTime`   | `uint64` | `false`  | End time in milliseconds                                               |
| `limit`     | `uint32` | `false`  | Number of positions to return. Default: `50`, Max: `500`               |

#### Response

| Field  | Type              | Description                                                                                                                                                           |
| ------ | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data` | `Array<Position>` | Response data when code is `0`. See [`Position`](https://sodex.com/documentation/api/schema#position) in [Schema](https://sodex.com/documentation/api/rest-v1/schema) |

### Query trades

`GET ${PERPS_ENDPOINT}/accounts/{userAddress}/trades`

*Get historical trade executions for an account.*

```bash
curl -X GET "${PERPS_ENDPOINT}/accounts/0x0123456789070ce8f0d6bab722103d12674bc257/trades?symbol=BTC-USD&limit=100" \
  -H 'Accept: application/json'
```

#### Path Parameters

| Name          | Type        | Required | Description      |
| ------------- | ----------- | -------- | ---------------- |
| `userAddress` | `HexString` | `true`   | User EVM address |

#### Query Parameters

| Name        | Type     | Required | Description                                                            |
| ----------- | -------- | -------- | ---------------------------------------------------------------------- |
| `accountID` | `uint64` | `false`  | The sub-account ID of the user. Primary account ID is used by default. |
| `symbol`    | `string` | `false`  | Filter by symbol name                                                  |
| `orderID`   | `uint64` | `false`  | Filter by order ID                                                     |
| `startTime` | `uint64` | `false`  | Start time in milliseconds                                             |
| `endTime`   | `uint64` | `false`  | End time in milliseconds                                               |
| `limit`     | `uint32` | `false`  | Number of trades to return. Default: `100`, Max: `1000`                |

#### Response

| Field  | Type               | Description                                                                                                                                                             |
| ------ | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data` | `Array<UserTrade>` | Response data when code is `0`. See [`UserTrade`](https://sodex.com/documentation/api/schema#usertrade) in [Schema](https://sodex.com/documentation/api/rest-v1/schema) |

### Query funding history

`GET ${PERPS_ENDPOINT}/accounts/{userAddress}/fundings`

*Get historical funding payments (paid or received) for an account.*

```bash
curl -X GET "${PERPS_ENDPOINT}/accounts/0x0123456789070ce8f0d6bab722103d12674bc257/fundings?symbol=BTC-USD" \
  -H 'Accept: application/json'
```

#### Path Parameters

| Name          | Type        | Required | Description      |
| ------------- | ----------- | -------- | ---------------- |
| `userAddress` | `HexString` | `true`   | User EVM address |

#### Query Parameters

| Name         | Type     | Required | Description                                                            |
| ------------ | -------- | -------- | ---------------------------------------------------------------------- |
| `accountID`  | `uint64` | `false`  | The sub-account ID of the user. Primary account ID is used by default. |
| `symbol`     | `string` | `false`  | Filter by symbol name                                                  |
| `positionID` | `uint64` | `false`  | Filter by position ID                                                  |
| `startTime`  | `uint64` | `false`  | Start time in milliseconds                                             |
| `endTime`    | `uint64` | `false`  | End time in milliseconds                                               |
| `limit`      | `uint32` | `false`  | Number of trades to return. Default: `100`, Max: `1000`                |

#### Response

| Field  | Type                      | Description                                                                                                                                                                           |
| ------ | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data` | `Array<PerpsUserFunding>` | Response data when code is `0`. See [`PerpsUserFunding`](https://sodex.com/documentation/api/schema#perpsuserfunding) in [Schema](https://sodex.com/documentation/api/rest-v1/schema) |

### Transfer asset to spot

`POST ${PERPS_ENDPOINT}/accounts/transfers`

*Transfer assets between accounts.*

* Auth: signed write

```bash
curl -X POST ${PERPS_ENDPOINT}/accounts/transfers \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  -H 'X-API-Key: <API-Key>' \
  -H 'X-API-Sign: <API-Sign>' \
  -H 'X-API-Nonce: <API-Nonce>' \
  -d <TransferAssetRequest>
```

#### Request Body

See [`TransferAssetRequest`](https://sodex.com/documentation/api/schema#transferassetrequest) in [Schema](https://sodex.com/documentation/api/rest-v1/schema)

Additional Information:

* Number of decimal places of `transfer.amount` should not exceed coin precision. That is `transfer.amount % 10^{-coin.precision} = 0`.
* The `transfer.amount` must be a positive value.
* Number of decimal places of `transfer.amount` should not exceed coin precision.
* Transfer asset to spot chain: `transfer.toAccountID=999`, `transfer.type=SPOT_WITHDRAW`
* Transfer assets to the EVM chain is not supported yet.
* Internal transfer between perps chains is not supported yet.
* The request is rejected when margin check failed.

#### Response

| Field  | Type           | Description                     |
| ------ | -------------- | ------------------------------- |
| `data` | `ResponseData` | Response data when code is `0`. |

* `ResponseData`

  | Name | Type     | Required | Description                                                                   |
  | ---- | -------- | -------- | ----------------------------------------------------------------------------- |
  | `id` | `uint64` | `true`   | Identifier for this transfer request. Same as `id` in `TransferAssetRequest`. |

## Perps Trading Endpoints

### Place multiple orders

`POST ${PERPS_ENDPOINT}/trade/orders`

*Submit one or more perpetual orders in a single signed payload.*

* Auth: signed write

```bash
curl -X POST ${PERPS_ENDPOINT}/trade/orders \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  -H 'X-API-Key: <API-Key>' \
  -H 'X-API-Sign: <API-Sign>' \
  -H 'X-API-Nonce: <API-Nonce>' \
  -d <PerpsNewOrderRequest>
```

#### Request Body

Find `PerpsNewOrderRequest` and `PerpsOrderItem` in [Schema](https://sodex.com/documentation/api/rest-v1/schema)

Additional Information:

* Basic Validation
  * The batch cannot be empty.
  * The length of batch should less than or equals to `100`.
  * The `order[i].clOrdID` must match `^[0-9a-zA-Z_-]{1,36}$`.
  * The `order[i].clOrdID` must be unique among open orders. Reuse is allowed only after the previous order is filled.
  * For limit order
    * `order[i].timeInForce` can be `GTC`, `IOC`, `GTX`.
    * provide both `order[i].price` and `order[i].quantity`, do not send `order[i].funds`.
  * For Market order
    * `order[i].timeInForce` must be `IOC`.
    * Provide either `order.quantity` or `order[i].funds`, not both. `order[i].funds` only available for market buy orders.
    * `order[i].price` optional for slippage protection.
  * The order will be rejected if basic validation failed.
* Price filter
  * The decimal precision of order price should not exceed `symbol.pricePrecision`. That is `order[i].price % 10^{-symbol.pricePrecision} = 0`.
  * The order price must be multiple of `symbol.tickSize`. That is `order[i].price % symbol.tickSize = 0`.
  * If `symbol.minPrice` is not `0`, the order price should greater than or equals to `symbol.minPrice`.
  * If `symbol.maxPrice` is not `0`, the order price should less than or equals to `symbol.maxPrice`.
  * The decimal precision of order stop price should not exceed `symbol.pricePrecision`. That is `order[i].stopPrice % 10^{-symbol.pricePrecision} = 0`.
  * The order stop price must be multiple of `symbol.tickSize`. That is `order[i].stopPrice % symbol.tickSize = 0`.
  * If `symbol.minPrice` is not `0`, the order stop price should greater than or equals to `symbol.minPrice`.
  * If `symbol.maxPrice` is not `0`, the order stop price should less than or equals to `symbol.maxPrice`.
  * The order will be rejected if price filter check failed.
* Lot size filter
  * The decimal precision of order quantity should not exceed `symbol.quantityPrecision`. That is `order[i].quantity % 10^{-symbol.quantityPrecision} = 0`.
  * The order quantity must be multiple of `symbol.stepSize`. That is `order[i].quantity % symbol.stepSize = 0`.
  * If `symbol.minQuantity` is not `0`, the order quantity should greater than or equals to `symbol.minQuantity`.
  * If `symbol.maxQuantity` is not `0`, the order quantity should less than or equals to `symbol.maxQuantity`.
  * The order will be rejected if lot size filter check failed.
* Market lot size filter
  * This is an additional check for market order.
  * If `symbol.marketMinQuantity` is not `0`, the order quantity should greater than or equals to `symbol.marketMinQuantity`.
  * If `symbol.marketMaxQuantity` is not `0`, the order quantity should less than or equals to `symbol.marketMaxQuantity`.
  * The order will be rejected if market lot filter check failed.
* Notional filter
  * For limit order, the order notional is `order[i].price * order[i].quantity`.
  * For market order with `order[i].funds` provided, the order notional is `order[i].funds`.
  * For market order without `order[i].funds`, the order notional is estimated as `symbol.lastTradePrice * order[i].quantity`.
  * If `symbol.minNotional` is not `0`, the order notional should greater than or equals to `symbol.minNotional`.
  * If `symbol.maxNotional` is not `0`, the order notional should less than or equals to `symbol.maxNotional`.
  * The order will be rejected if notional filter check failed.
* Margin check
  * The order will be rejected if account margin is not enough to place the order.
* Other price limitation for non-TP/SL orders.
  * for limit buy orders, the order price should less than or equal to `symbol.markPrice * (1 + symbol.buyLimitUpRatio)`. Otherwise, the order is rejected.
  * for limit sell orders, the order price should greater than or equal to `symbol.markPrice * (1 - symbol.sellLimitDownRatio)`. Otherwise, the order is rejected.
  * for market buy orders without price, the final execution price is bounded by `symbol.indexPrice * (1 + symbol.marketDeviationRatio)`. If price is provided, the final execution price is bounded by `min(order[i].price, symbol.indexPrice * (1 + symbol.marketDeviationRatio))`
  * for market sell orders without price, the final execution price is bounded by `symbol.indexPrice * (1 - symbol.marketDeviationRatio)`. If price is provided, the final execution price is bounded by `max(order[i].price, symbol.indexPrice * (1 - symbol.marketDeviationRatio))`
* For order with TP/SL
  * The length of batch should be `2` or `3`.
  * The `orders[0].modifier = BRACKET`, `orders[1 or 2].modifier = ATTACHED_STOP`.
  * The `orders[0].reduceOnly = false`, `orders[1 or 2].reduceOnly = true`.
  * The `orders[1 or 2].stopPrice`, `orders[1 or 2].stopType`, `orders[1 or 2].triggerType` are provided.
  * Only one of `orders[1]` and `orders[2]` is take profit order.
  * Only one of `orders[1]` and `orders[2]` is stop loss order.
* For Position with TP/SL
  * The user has a position with this symbol.
  * The `orders[i].modifier = STOP`.
  * The `orders[i].reduceOnly = true`.
  * The `orders[i].stopPrice`, `orders[i].stopType`, `orders[i].triggerType` are provided.
  * For TP/SL without quantity, it is treated as global TP/SL. When triggered, generated order will have full position size as quantity.
* For TP/SL without order and position (standalone TP/SL)
  * `orders[i].modifier = STOP`
  * `orders[i].reduceOnly = false`
  * The `orders[i].stopPrice`, `orders[i].stopType`, `orders[i].triggerType` are provided.

#### Response

| Field  | Type                  | Description                     |
| ------ | --------------------- | ------------------------------- |
| `data` | `Array<ResponseData>` | Response data when code is `0`. |

* `ResponseData`

  | Name      | Type     | Required | Description                                                                 |
  | --------- | -------- | -------- | --------------------------------------------------------------------------- |
  | `code`    | `int32`  | `true`   | Response status code, `0` for success and other code for failure.           |
  | `clOrdID` | `string` | `true`   | Client order id; same as `clOrdID` in `PerpsNewOrderRequest`.               |
  | `error`   | `string` | `false`  | Error description for individual order. Only provided when code is not `0`. |
  | `orderID` | `uint64` | `false`  | Order id. Only provided when the code is `0`.                               |

The length of the response result array is usually the same as the length of batched request.

**Important**: Some errors are a deterministic function of the payload itself, and these are instead returned earlier as part of pre-validation. In this case, only one error is returned for the entire payload, as some of these errors do not apply to a specific order.

For API users that use batching, it's recommended to handle the case where a single error is returned for a batch of multiple orders. In this case, the response could be duplicated n times before being sent to the callback function, as the whole batch was rejected for this same reason.

### Cancel multiple orders

`DELETE ${PERPS_ENDPOINT}/trade/orders`

*Cancel one or more orders by order ID or client order ID.*

* Auth: signed write

```bash
curl -X DELETE ${PERPS_ENDPOINT}/trade/orders \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  -H 'X-API-Key: <API-Key>' \
  -H 'X-API-Sign: <API-Sign>' \
  -H 'X-API-Nonce: <API-Nonce>' \
  -d <PerpsCancelOrderRequest>
```

#### Request Body

Find `PerpsCancelOrderRequest` and `PerpsCancelItem` in [Schema](https://sodex.com/documentation/api/rest-v1/schema)

Additional Information:

* The batch cannot be empty.
* The length of batch should less than or equals to `100`.
* The `cancel[i].clOrdID` should match `^[0-9a-zA-Z_-]{1,36}$`, if provided.
* Provide either `cancel[i].orderID` or `cancel[i].clOrdID`, but not both.

#### Response

| Field  | Type                  | Description                     |
| ------ | --------------------- | ------------------------------- |
| `data` | `Array<ResponseData>` | Response data when code is `0`. |

* `ResponseData`

  | Name      | Type     | Required | Description                                                                 |
  | --------- | -------- | -------- | --------------------------------------------------------------------------- |
  | `code`    | `int32`  | `true`   | Response status code, `0` for success and other code for failure.           |
  | `clOrdID` | `string` | `true`   | Client order id; same as `clOrdID` in `PerpsCancelOrderRequest`.            |
  | `error`   | `string` | `false`  | Error description for individual order. Only provided when code is not `0`. |
  | `orderID` | `uint64` | `false`  | Order id. Only provided when the code is `0`.                               |

The length of the response result array is usually the same as the length of batched request.

**Important**: Some errors are a deterministic function of the payload itself, and these are instead returned earlier as part of pre-validation. In this case, only one error is returned for the entire payload, as some of these errors do not apply to a specific order.

For API users that use batching, it's recommended to handle the case where a single error is returned for a batch of multiple orders. In this case, the response could be duplicated n times before being sent to the callback function, as the whole batch was rejected for this same reason.

### Replace multiple orders

`POST ${PERPS_ENDPOINT}/trade/orders/replace`

*Replace/modify existing orders atomically.*

* Auth: signed write

```bash
curl -X POST ${PERPS_ENDPOINT}/trade/orders/replace \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  -H 'X-API-Key: <API-Key>' \
  -H 'X-API-Sign: <API-Sign>' \
  -H 'X-API-Nonce: <API-Nonce>' \
  -d <ReplaceOrderRequest>
```

#### Request Body

See [`ReplaceOrderRequest`](https://sodex.com/documentation/api/schema#replaceorderrequest) in [Schema](https://sodex.com/documentation/api/rest-v1/schema)

Additional Information:

* Basic Validation
  * The batch cannot be empty.
  * The length of batch should less than or equals to `100`.
  * Only limit `GTC` and limit `GTX` can be replaced.
  * Only non-TP/SL order with status `NEW` and `PARTIALLY_FILLED` can be replaced.
  * Either `replace.origOrderID` or `replace.origClOrdID` should be provided, but not both.
  * At least one of `replace.price` and `replace.quantity` should be provided.
* Price filter
  * The decimal precision of replacement price should not exceed `symbol.pricePrecision`, if provided. That is `replace.price % 10^{-symbol.pricePrecision} = 0`.
  * The replacement price must be multiple of `symbol.tickSize`. That is `replace.price % symbol.tickSize = 0`.
  * If `symbol.minPrice` is not `0`, the replacement price should greater than or equals to `symbol.minPrice`.
  * If `symbol.maxPrice` is not `0`, the replacement price should less than or equals to `symbol.maxPrice`.
  * The replacement will be rejected if price filter check failed.
* Lot size filter
  * The decimal precision of replacement quantity should not exceed `symbol.quantityPrecision`. That is `replace.quantity % 10^{-symbol.quantityPrecision} = 0`.
  * The replacement quantity must be multiple of `symbol.stepSize`. That is `replace.quantity % symbol.stepSize = 0`.
  * If `symbol.minQuantity` is not `0`, the replacement quantity should greater than or equals to `symbol.minQuantity`.
  * If `symbol.maxQuantity` is not `0`, the replacement quantity should less than or equals to `symbol.maxQuantity`.
  * The replacement will be rejected if lot size filter check failed.
* Notional filter
  * The replacement notional is `replace.price * replace.quantity`. If `replace.price` not provided, `order.price` is used. If `replace.quantity` not provided, `order.quantity` is used.
  * If `symbol.minNotional` is not `0`, the replacement notional should greater than or equals to `symbol.minNotional`.
  * If `symbol.maxNotional` is not `0`, the replacement notional should less than or equals to `symbol.maxNotional`.
  * The replacement will be rejected if notional filter check failed.
* Margin check
  * The replacement will be rejected if account margin is not enough to replace the order.

#### Response

| Field  | Type                  | Description                     |
| ------ | --------------------- | ------------------------------- |
| `data` | `Array<ResponseData>` | Response data when code is `0`. |

* `ResponseData`

  | Name      | Type     | Required | Description                                                                 |
  | --------- | -------- | -------- | --------------------------------------------------------------------------- |
  | `code`    | `int32`  | `true`   | Response status code, `0` for success and other code for failure.           |
  | `clOrdID` | `string` | `true`   | Client order id; same as `clOrdID` in `ReplaceParams`.                      |
  | `error`   | `string` | `false`  | Error description for individual order. Only provided when code is not `0`. |
  | `orderID` | `uint64` | `false`  | Order id of the replaced order. Only provided when the code is `0`.         |

The length of the response result array is usually the same as the length of batched request.

**Important**: Some errors are a deterministic function of the payload itself, and these are instead returned earlier as part of pre-validation. In this case, only one error is returned for the entire payload, as some of these errors do not apply to a specific order.

For API users that use batching, it's recommended to handle the case where a single error is returned for a batch of multiple orders. In this case, the response could be duplicated n times before being sent to the callback function, as the whole batch was rejected for this same reason.

### Modify TP/SL order

`POST ${PERPS_ENDPOINT}/trade/orders/modify`

*Replace/modify an existing TP/SL order.*

* Auth: signed write

```bash
curl -X POST ${PERPS_ENDPOINT}/trade/orders/modify \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  -H 'X-API-Key: <API-Key>' \
  -H 'X-API-Sign: <API-Sign>' \
  -H 'X-API-Nonce: <API-Nonce>' \
  -d <ModifyOrderRequest>
```

#### Request Body

See [`ModifyOrderRequest`](https://sodex.com/documentation/api/schema#modifyorderrequest) in [Schema](https://sodex.com/documentation/api/rest-v1/schema)

Additional Information:

* The order must be a TP/SL order.
* Provide either `modify.orderID` or `cmodify.lOrdID`, but not both.
* Provide at least one of `modify.price`, `modify.quantity`, or `modify.stopPrice`.
* The `modify.price` and `modify.stopPrice` must pass price filter.
* The `modify.quantity` must pass lot size filter and market lot size filter.
* The `modify.price` and `modify.quantity` must pass notional filter.

#### Response

* No endpoint-specific `data` payload.

### Schedule cancel orders

`POST ${PERPS_ENDPOINT}/trade/orders/schedule-cancel`

*Schedule a cancel-all operation at a future time. Omitting the time clears the scheduled cancel.*

* Auth: signed write

```bash
curl -X POST ${PERPS_ENDPOINT}/trade/orders/schedule-cancel \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  -H 'X-API-Key: <API-Key>' \
  -H 'X-API-Sign: <API-Sign>' \
  -H 'X-API-Nonce: <API-Nonce>' \
  -d <ScheduleCancelRequest>
```

#### Request Body

See [`ScheduleCancelRequest`](https://sodex.com/documentation/api/schema#schedulecancelrequest) in [Schema](https://sodex.com/documentation/api/rest-v1/schema)

| Name                 | Type     | Required | Description                                                             |
| -------------------- | -------- | -------- | ----------------------------------------------------------------------- |
| `accountID`          | `uint64` | `true`   | Account identifier.                                                     |
| `scheduledTimestamp` | `uint64` | `false`  | Unix timestamp in milliseconds when the cancel-all should be triggered. |

Additional Information:

* The scheduled time must be at least `5` seconds after the current time.
* When triggered, all open orders are canceled and a trigger count increments (max `10` per day, resets at `00:00 UTC`).
* Omitting `scheduledTimestamp` removes the scheduled cancel.

#### Response

* No endpoint-specific `data` payload.

### Update leverage

`POST ${PERPS_ENDPOINT}/trade/leverage`

*Update leverage and margin mode for a symbol.*

* Auth: signed write

```bash
curl -X POST ${PERPS_ENDPOINT}/trade/leverage \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  -H 'X-API-Key: <API-Key>' \
  -H 'X-API-Sign: <API-Sign>' \
  -H 'X-API-Nonce: <API-Nonce>' \
  -d <UpdateLeverageRequest>
```

#### Request Body

See [`UpdateLeverageRequest`](https://sodex.com/documentation/api/schema#updateleveragerequest) in [Schema](https://sodex.com/documentation/api/rest-v1/schema)

Additional Information:

* The leverage must less than or equals to `symbol.maxLeverage`.
* The request is rejected when this account has open orders or open positions on this symbol.

#### Response

* No endpoint-specific `data` payload.

### Update isolated margin

`POST ${PERPS_ENDPOINT}/trade/margin`

*Add or remove margin from an isolated position.*

* Auth: signed write

```bash
curl -X POST ${PERPS_ENDPOINT}/trade/margin \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  -H 'X-API-Key: <API-Key>' \
  -H 'X-API-Sign: <API-Sign>' \
  -H 'X-API-Nonce: <API-Nonce>' \
  -d <UpdateMarginRequest>
```

#### Request Body

See [`UpdateMarginRequest`](https://sodex.com/documentation/api/schema#updatemarginrequest) in [Schema](https://sodex.com/documentation/api/rest-v1/schema)

Additional Information:

* Number of decimal places of `transfer.amount` should not exceed coin (`vUSDC`) precision. That is `transfer.amount % 10^{-coin.precision} = 0`.
* The `transfer.amount` must be a non-zero value.
* The request is rejected when margin check failed.

#### Response

* No endpoint-specific `data` payload.
