> This page is for Documentation.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://okx-demo.ferndocs.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://okx-demo.ferndocs.com/_mcp/server.

# Error Codes

## Overview

Every OKX v5 REST response — success or failure — uses the same JSON envelope:

```json
{
  "code": "0",
  "msg": "",
  "data": []
}
```

* `code` — a **string** status code. `"0"` means the request succeeded; any other value is an error.
* `msg` — a human-readable explanation. Empty on success, populated on failure.
* `data` — an array of result objects.

Compare `code` as a string (`"0"`), not the integer `0`. The `msg` / `sMsg` text is the authoritative, up-to-date explanation for any code — the tables below summarize the documented meaning, but always surface the returned message to callers.

> **Success**
>
> Code `"0"` is the only success value. On batch endpoints the top-level `code` can be `"0"` while individual items still fail, so treat a top-level `"0"` as "the request was accepted", not "every item succeeded". Always inspect per-item `sCode` as well.

### Per-item codes on batch endpoints

Batch endpoints — `POST /api/v5/trade/batch-orders`, `POST /api/v5/trade/cancel-batch-orders`, `POST /api/v5/trade/amend-batch-orders`, and others — can partially succeed. Each element of `data` carries its own status:

* `sCode` — the status code for that individual item (`"0"` = that item succeeded).
* `sMsg` — the message for that individual item.

```json
{
  "code": "1",
  "msg": "Operation failed.",
  "data": [
    { "clOrdId": "order-a", "ordId": "312269865356374016", "sCode": "0", "sMsg": "" },
    { "clOrdId": "order-b", "ordId": "", "sCode": "51008", "sMsg": "Order failed. Insufficient balance." }
  ]
}
```

The top-level `code` is `"1"` ("Operation failed") when any item fails, and `"2"` ("Bulk operation partially succeeded") when some succeed and some fail. Read both levels.

| Code | HTTP | Message / Meaning                                                                               |
| ---- | ---- | ----------------------------------------------------------------------------------------------- |
| `0`  | 200  | Success. The request (and, for batches, every item) succeeded.                                  |
| `1`  | 200  | Operation failed. Used at the top level of a batch when all items failed; inspect each `sCode`. |
| `2`  | 200  | Bulk operation partially succeeded. Some items succeeded, some failed; inspect each `sCode`.    |

---

## Public / General (50000–50999)

General request, routing, and system-level errors that apply across all endpoints.

| Code    | HTTP | Message / Meaning                                                                          |
| ------- | ---- | ------------------------------------------------------------------------------------------ |
| `50000` | 400  | Body for POST request cannot be empty.                                                     |
| `50001` | 503  | Service temporarily unavailable. Try again later.                                          |
| `50002` | 400  | JSON syntax error in the request body.                                                     |
| `50004` | 400  | API endpoint request timeout (does not mean the request succeeded or failed; check state). |
| `50005` | 410  | API endpoint is offline or unavailable.                                                    |
| `50006` | 400  | Invalid `Content-Type`. Use `application/json`.                                            |
| `50007` | 403  | Account blocked.                                                                           |
| `50008` | 401  | User does not exist.                                                                       |
| `50009` | 403  | Account is suspended (frozen).                                                             |
| `50010` | 400  | User ID is empty.                                                                          |
| `50011` | 429  | Rate limit reached. Throttle and retry.                                                    |
| `50012` | 400  | Account status invalid.                                                                    |
| `50013` | 429  | Systems are busy. Please try again later.                                                  |
| `50014` | 400  | Required parameter cannot be empty.                                                        |
| `50015` | 400  | Either parameter `x` or `y` is required.                                                   |
| `50016` | 400  | Parameter mismatch (paired parameters are inconsistent).                                   |
| `50017` | 400  | Position frozen due to ADL (auto-deleveraging). Operable after ADL finishes.               |
| `50018` | 400  | Currency is frozen due to ADL.                                                             |
| `50019` | 400  | Account is frozen due to ADL.                                                              |
| `50020` | 400  | Position frozen due to liquidation. Operable once liquidation completes.                   |
| `50021` | 400  | Currency is frozen due to liquidation.                                                     |
| `50022` | 400  | Account is frozen due to liquidation.                                                      |
| `50023` | 400  | Funding fee frozen. Operable once settlement completes.                                    |
| `50024` | 400  | Parameters `x` and `y` cannot be provided at the same time.                                |
| `50025` | 400  | Parameter `x` count exceeds the limit.                                                     |
| `50026` | 500  | System error. Try again later.                                                             |
| `50027` | 403  | This account is restricted from trading. Contact customer support.                         |
| `50028` | 400  | Unable to take the order; account is restricted from opening positions.                    |
| `50029` | 400  | This instrument is unavailable for this account (risk control).                            |
| `50030` | 403  | You do not have permission to use this API endpoint.                                       |
| `50032` | 403  | Account has been set to prohibit transactions for this currency.                           |
| `50033` | 403  | Account has been set to prohibit transactions for this business line.                      |
| `50035` | 400  | This endpoint requires that the API key be bound to an IP address.                         |
| `50036` | 400  | `expTime` cannot be earlier than the current system time.                                  |
| `50037` | 400  | Order has expired.                                                                         |
| `50038` | 400  | This feature is unavailable in demo trading.                                               |
| `50039` | 400  | The parameter `before` cannot be used with `begin`/`end`.                                  |
| `50040` | 400  | Too frequent operations. Please try again later.                                           |
| `50041` | 400  | User ID is not eligible for this feature (whitelist only).                                 |
| `50044` | 400  | Must select one broker type.                                                               |
| `50060` | 400  | For the security of your funds, a preset action is required. Please try again later.       |
| `50061` | 429  | Order requests have been rate-limited. Reduce request frequency.                           |
| `50062` | 400  | This feature is currently unavailable.                                                     |

---

## Rate limiting (50011, 50013, 50061)

Rate-limit responses arrive with HTTP `429`. Back off using exponential delay, batch where possible, and prefer WebSocket streams over REST polling.

| Code    | HTTP | Message / Meaning                                                                                  |
| ------- | ---- | -------------------------------------------------------------------------------------------------- |
| `50011` | 429  | Rate limit reached. Please refer to the API documentation and throttle requests accordingly.       |
| `50013` | 429  | Systems are busy. Please try again later. Server-side throttling under load.                       |
| `50061` | 429  | Order placement/amend/cancel requests exceeded the sub-account order rate limit. Reduce frequency. |

See [Rate limits](/docs/reference/rate-limits) for per-endpoint budgets and the `sub-account` order-count limits.

---

## API authentication & keys (50100–50119)

Authentication failures almost always trace back to the signature or the request headers. See [REST authentication](/docs/authentication/rest-authentication) for how `OK-ACCESS-SIGN` is computed.

| Code    | HTTP | Message / Meaning                                                                  |
| ------- | ---- | ---------------------------------------------------------------------------------- |
| `50100` | 400  | API frozen. Contact customer support.                                              |
| `50101` | 401  | APIKey does not match the current environment (e.g. live key used against demo).   |
| `50102` | 401  | Timestamp request expired. Clock skew exceeded 30 seconds; sync your clock.        |
| `50103` | 401  | Request header `OK-ACCESS-KEY` cannot be empty.                                    |
| `50104` | 401  | Request header `OK-ACCESS-PASSPHRASE` cannot be empty.                             |
| `50105` | 401  | Request header `OK-ACCESS-PASSPHRASE` is incorrect.                                |
| `50106` | 401  | Request header `OK-ACCESS-SIGN` cannot be empty.                                   |
| `50107` | 401  | Request header `OK-ACCESS-TIMESTAMP` cannot be empty.                              |
| `50108` | 401  | Broker ID does not exist.                                                          |
| `50109` | 401  | Matching broker ID does not exist.                                                 |
| `50110` | 401  | Your IP address is not in the allowlist bound to this API key.                     |
| `50111` | 401  | Invalid `OK-ACCESS-KEY`.                                                           |
| `50112` | 401  | Invalid `OK-ACCESS-TIMESTAMP` (format not ISO-8601 / not parseable).               |
| `50113` | 401  | Invalid signature. Recompute `OK-ACCESS-SIGN` from the pre-hash string and secret. |
| `50114` | 401  | Invalid authorization / authentication failed.                                     |
| `50115` | 405  | Invalid request method for this endpoint.                                          |
| `50116` | 401  | Fastapi cannot be used for this endpoint.                                          |
| `50118` | 400  | You must complete broker withdrawal-verification setup before using this feature.  |
| `50119` | 401  | API key does not exist.                                                            |

> **Warning**
>
> `50113` (invalid signature) and `50102` (expired timestamp) are the two most common auth failures. `50113` means the pre-hash string, HTTP method, path, query string, or body you signed does not match what was sent — re-serialize the body exactly once and sign the raw string. `50102` means clock drift; run NTP so your timestamp is within 30 seconds of OKX server time.

---

## Account (50000-range trade / 51000–51999 subset)

Errors returned when placing, amending, or cancelling orders — covering parameter validation, balance, leverage, and position-mode conflicts. These appear at the top level for single orders and as `sCode` on batch items.

| Code    | HTTP | Message / Meaning                                                                  |
| ------- | ---- | ---------------------------------------------------------------------------------- |
| `51000` | 400  | Parameter error. The parameter named in `msg` is missing or malformed.             |
| `51001` | 400  | Instrument ID (`instId`) does not exist.                                           |
| `51002` | 400  | Instrument ID does not match the underlying.                                       |
| `51003` | 400  | Either `clOrdId` or `ordId` is required.                                           |
| `51004` | 400  | Order amount exceeds the current tier's maximum position limit.                    |
| `51005` | 400  | Order amount exceeds the maximum order size.                                       |
| `51006` | 400  | Order price is outside the allowable price-limit range.                            |
| `51007` | 400  | Order placement failed: order value is below the minimum (`1 USDT`).               |
| `51008` | 400  | Order failed. Insufficient account balance.                                        |
| `51009` | 400  | Order placement blocked: account is in trading-suspended state.                    |
| `51010` | 400  | Account level too low. Current account mode does not support this instrument type. |
| `51011` | 400  | Duplicate order ID (`clOrdId` already used).                                       |
| `51012` | 400  | Token does not exist.                                                              |
| `51014` | 400  | Index does not exist.                                                              |
| `51015` | 400  | Instrument ID does not match the instrument type.                                  |
| `51016` | 400  | Duplicate `clOrdId`.                                                               |
| `51020` | 400  | Order amount must be greater than the minimum lot size.                            |
| `51023` | 400  | Position does not exist.                                                           |
| `51024` | 400  | Trading account is suspended.                                                      |
| `51025` | 400  | Order count exceeds the limit.                                                     |
| `51046` | 400  | Take-profit trigger price must be higher than the last price.                      |
| `51047` | 400  | Stop-loss trigger price must be lower than the last price.                         |
| `51119` | 400  | Order placement failed due to insufficient balance.                                |
| `51120` | 400  | Order quantity is less than the minimum available amount for closing.              |
| `51121` | 400  | Order count must be a multiple of the lot size.                                    |
| `51122` | 400  | Order price must be higher than or equal to the minimum price increment.           |

---

## Trade / order (51100–51999 subset)

Order-state and order-management errors — amend, cancel, close, and margin/leverage conflicts.

| Code    | HTTP | Message / Meaning                                                                |
| ------- | ---- | -------------------------------------------------------------------------------- |
| `51100` | 400  | Trading amount does not meet the minimum, or exceeds the maximum.                |
| `51103` | 400  | Number of pending orders for the instrument exceeds the limit.                   |
| `51108` | 400  | Positions exceed the limit for the market-maker/close-out operation.             |
| `51109` | 400  | No available offer to match the order (no counterparty).                         |
| `51115` | 400  | Cancellation failed: the order has already been filled or cancelled.             |
| `51116` | 400  | Order price or trigger price exceeds the allowable limit.                        |
| `51117` | 400  | Pending close-orders count exceeds the limit.                                    |
| `51121` | 400  | Order count must be a multiple of the lot size.                                  |
| `51124` | 400  | You can only place limit orders during the pre-market call-auction period.       |
| `51127` | 400  | Available balance is zero.                                                       |
| `51131` | 400  | Insufficient balance.                                                            |
| `51132` | 400  | Your position amount is negative and cannot be closed with this order.           |
| `51133` | 400  | Reduce-only cannot increase the position size.                                   |
| `51136` | 400  | Close-position amount exceeds available position amount.                         |
| `51201` | 400  | Value of per market order cannot exceed 1,000,000 USDT.                          |
| `51202` | 400  | Market order amount exceeds the maximum amount.                                  |
| `51203` | 400  | Order amount exceeds the limit for the instrument.                               |
| `51277` | 400  | TP trigger price cannot be higher than the last price.                           |
| `51278` | 400  | SL trigger price cannot be lower than the last price.                            |
| `51279` | 400  | TP trigger price cannot be lower than the last price.                            |
| `51280` | 400  | SL trigger price cannot be higher than the last price.                           |
| `51400` | 400  | Cancellation failed: the order does not exist.                                   |
| `51401` | 400  | Cancellation failed: the order is already cancelled.                             |
| `51402` | 400  | Cancellation failed: the order is already completed (filled).                    |
| `51403` | 400  | Cancellation failed: this order type does not support cancellation.              |
| `51404` | 400  | Order amendment unavailable: the order is in the pre-market call-auction period. |
| `51405` | 400  | Cancellation failed: you have no pending orders.                                 |
| `51406` | 400  | Cancellation failed: the number of orders exceeds the batch limit (max 20).      |
| `51408` | 400  | Pair and order do not match; cannot cancel across different instruments.         |
| `51410` | 400  | Cancellation already in progress; do not resubmit.                               |
| `51503` | 400  | Order amendment failed: the order does not exist or is already completed.        |
| `51506` | 400  | Order amendment unavailable for this order type.                                 |
| `51509` | 400  | Amendment failed: the requested change was not accepted.                         |
| `51603` | 400  | Order does not exist. Verify `ordId` / `clOrdId` before amend or cancel.         |

---

## Funding & withdrawal (58000–58999 subset)

Errors from the asset/funding endpoints: transfers, deposits, and withdrawals.

| Code    | HTTP | Message / Meaning                                                          |
| ------- | ---- | -------------------------------------------------------------------------- |
| `58002` | 400  | Please activate Options trading before transferring related assets.        |
| `58004` | 400  | Account is blocked from transfers (e.g. deferred settlement).              |
| `58005` | 400  | Transfer amount exceeds the maximum limit for the currency.                |
| `58006` | 400  | Service unavailable for this token in your region.                         |
| `58007` | 400  | Abnormal state of your account; transfer is not allowed.                   |
| `58100` | 400  | The trading account withdrawal function is disabled.                       |
| `58101` | 400  | Transfer suspended for the account.                                        |
| `58102` | 429  | Too frequent withdrawal requests. Try again later.                         |
| `58103` | 400  | Sub-account does not have transfer permissions.                            |
| `58104` | 400  | Withdrawal request rejected due to a risk-control review.                  |
| `58105` | 400  | The internal transfer amount exceeds the daily limit.                      |
| `58110` | 400  | Withdrawals are suspended for this currency due to instability.            |
| `58111` | 400  | Withdrawal is unsupported for the selected chain of this currency.         |
| `58112` | 400  | Withdrawal failed. Please check your account state and try again.          |
| `58115` | 400  | Sub-account transfers are not allowed for this currency.                   |
| `58116` | 400  | Transfer amount exceeds the maximum.                                       |
| `58120` | 400  | Withdrawal services are unavailable. Please try again later.               |
| `58121` | 400  | The withdrawal amount is below the minimum withdrawal threshold.           |
| `58124` | 400  | Withdrawal request has expired.                                            |
| `58125` | 400  | Non-tradable assets can only be withdrawn in full.                         |
| `58126` | 400  | Non-tradable assets can only be withdrawn to an OKX account.               |
| `58127` | 400  | The withdrawal address is not whitelisted.                                 |
| `58128` | 400  | Withdrawal address is invalid or not on the selected chain.                |
| `58129` | 400  | Insufficient balance to cover the withdrawal fee.                          |
| `58131` | 400  | Insufficient available balance for the withdrawal.                         |
| `58200` | 400  | Withdrawal from this account is not allowed.                               |
| `58207` | 400  | Withdrawal address is not on the address allowlist.                        |
| `58208` | 400  | Withdrawal failed: please add a withdrawal address in the security center. |
| `58350` | 400  | Insufficient balance.                                                      |

---

## WebSocket (60000–60999)

Returned on the WebSocket channel as `event: "error"` frames. Login, subscription, and channel errors dominate this range. See [WebSocket](/docs/realtime/web-socket) for connection and subscription details.

| Code    | HTTP | Message / Meaning                                                                   |
| ------- | ---- | ----------------------------------------------------------------------------------- |
| `60001` | —    | `OK-ACCESS-KEY` cannot be empty in the login request.                               |
| `60002` | —    | `OK-ACCESS-SIGN` cannot be empty.                                                   |
| `60003` | —    | `OK-ACCESS-PASSPHRASE` cannot be empty.                                             |
| `60004` | —    | Invalid `OK-ACCESS-TIMESTAMP`.                                                      |
| `60005` | —    | Invalid `OK-ACCESS-KEY`.                                                            |
| `60006` | —    | Timestamp request expired (clock skew). Resync and re-login.                        |
| `60007` | —    | Invalid sign (signature mismatch on login).                                         |
| `60008` | —    | This channel does not support subscription over this connection type.               |
| `60009` | —    | Login failed.                                                                       |
| `60010` | —    | Already logged in.                                                                  |
| `60011` | —    | Please log in before subscribing to private channels.                               |
| `60012` | —    | Illegal request. The message format or JSON is invalid.                             |
| `60013` | —    | Invalid `args`. The subscription arguments are malformed.                           |
| `60014` | —    | Requests too frequent. Slow down subscription/login attempts.                       |
| `60015` | —    | Connections too frequent. Reduce reconnection rate.                                 |
| `60016` | —    | Buffer is full. The connection is being closed; reconnect.                          |
| `60017` | —    | Invalid url path.                                                                   |
| `60018` | —    | Wrong channel: the requested channel does not exist, or `arg` fields are incorrect. |
| `60019` | —    | Invalid op. The `op` field must be one of `subscribe`, `unsubscribe`, or `login`.   |
| `60020` | —    | APIKey subscription limit has been reached.                                         |
| `60021` | —    | The connection has reached its subscription limit.                                  |
| `60022` | —    | Bulk login partially succeeded.                                                     |
| `60023` | —    | Bulk login requests too frequent.                                                   |
| `60024` | —    | Wrong passphrase in the login request.                                              |
| `60026` | —    | Batch login by APIKey and token cannot be used at the same time.                    |
| `60027` | —    | Parameter is empty in the request.                                                  |
| `60028` | —    | This operation is not supported by this URL.                                        |
| `60029` | —    | The `op` (operation) is not supported.                                              |
| `60030` | —    | The channel does not support this instrument type.                                  |
| `63999` | —    | Login failed due to an internal system error; reconnect and retry.                  |

> **Info**
>
> The WebSocket also returns transport-level close events. `4004` (no data received in 30s — send a `ping`), `4005` (buffer full), and `4008` (too many requests) are connection-level codes, distinct from the application-level `600xx` error frames above. Send a `ping` at least every 30 seconds to keep the socket alive.

---

## Handling pattern

Handle top-level and per-item codes uniformly:

```python
resp = request("POST", "/api/v5/trade/batch-orders", orders)

if resp["code"] != "0":
    # Overall failure (auth, rate limit, validation) or a partial batch failure.
    for item in resp.get("data", []):
        scode = item.get("sCode")
        if scode not in (None, "0"):
            print(f"item failed: {scode} {item['sMsg']}")
    print(f"request-level: {resp['code']} {resp['msg']}")
else:
    for item in resp["data"]:
        # Even when top-level code == "0", per-item sCode is authoritative for batches.
        if item.get("sCode", "0") != "0":
            print(f"item failed: {item['sCode']} {item['sMsg']}")
```

For a conceptual walkthrough of the envelope and a troubleshooting checklist, see [Error handling](/docs/reference/error-handling).