MeowQuant is an independent third-party information site, not OKX official. The sign-up button carries invite code OK30001, and we may earn a promotion fee from it. Full disclosure →

OKX · API Hands-On

OKX API Errors and Troubleshooting Checklist: Fix It With This Table

Nine times out of ten, people writing quant scripts get stuck not on the strategy but on a single line of red error text: the script starts up, the terminal spits out a string of incomprehensible codes and English, and you freeze. The good news is that OKX API errors come in just a handful of high-frequency flavors, and once you know what each looks like and what cause it maps to, troubleshooting gets a lot faster.

In this piece we (the MeowQuant desk) collect the errors we've hit ourselves, and the ones that come up over and over in the community, into one checklist. The heart of it is a single error-code reference table: when something breaks, find your error by code or keyword in the table, then read the matching item-by-item fix below. By the end you should be able to resolve most errors yourself in minutes, instead of staring blankly at red text.

Learn to read the error first: code + msg

Step one in debugging is reading the error itself. When an OKX endpoint errors out, it returns three pieces of information:

  • HTTP status code: the coarsest layer, like 401 (auth problem), 429 (too many requests), 400 (the request itself is wrong).
  • code: OKX's own numeric error code, pointing most precisely at the type of problem. This is your main basis for troubleshooting.
  • msg: a text description that helps confirm the direction, sometimes pointing out exactly which field is wrong.

If you use ccxt, it wraps these raw errors into more readable exception types—an auth problem throws AuthenticationError, a rate limit throws RateLimitExceeded, insufficient balance throws InsufficientFunds. The exception message generally carries OKX's original code and msg too. A good habit is to print them clearly with try/except:

import ccxt

okx = ccxt.okx({
    'apiKey':   'YOUR_apiKey',
    'secret':   'YOUR_secret',
    'password': 'YOUR_Passphrase',
    'enableRateLimit': True,
})

try:
    balance = okx.fetch_balance()
    print('USDT free:', balance['USDT']['free'])
except ccxt.AuthenticationError as e:
    print('Auth failed, check the three credentials and system time:', e)
except ccxt.RateLimitExceeded as e:
    print('Rate limited, slow down requests:', e)
except ccxt.BaseError as e:
    print('Other error, look at the raw code/msg:', e)

Note down that code and msg from the exception as-is, cross-check the table below, and you can basically pin down which class of problem it is.

High-frequency error reference table

The table below covers the errors beginners hit most. Go by whatever OKX's current API v5 docs publish for the error codes (OKX occasionally adjusts code values, so if one doesn't match, defer to the msg text and the official docs); the point is to line up "cause → fix."

Error (code / keyword)Likely causeFix
50011
Too Many Requests / rate limit
Requests too dense, tripping rate-limit protection Turn on enableRateLimit; if still hitting it, add exponential backoff retry—no delay-free while loops
Invalid sign
auth failed
Bad signature: usually a wrong Passphrase, a miscopied apiKey/secret, or an off system time Check each of the three credentials for spaces/missing chars; confirm password holds the Passphrase; calibrate system time
API key invalid
APIKey does not exist
apiKey miscopied, deleted, or used in the wrong environment (live Key as demo Key) Recopy the apiKey from the dashboard; confirm this Key still exists; confirm the sandbox toggle matches the environment
Passphrase error
passphrase incorrect
ccxt's password field holds the login password, not the Passphrase set at Key creation Change password to the Passphrase you set when creating that Key; if you can't recall it, delete and recreate the Key
Insufficient balance Order amount exceeds available balance, or funds are in another account (e.g. funding vs trading) Reduce the order size; confirm funds are in the trading account; on the demo, reset the virtual funds
timestamp expired Local system time is too far off; the signature timestamp exceeds OKX's tolerance Turn on NTP auto-sync to bring system time in sync; cloud servers usually have it on by default
permission denied This Key lacks the needed permission (commonly: only Read ticked, not Trade) Go to API management and add the "Trade" permission to this Key—no need to recreate
IP not allowed An IP whitelist is set on the Key, but the current outbound IP isn't on it (network change/proxy/broadband IP change) Add the current outbound IP to this Key's whitelist; if your IP changes often, consider skipping the whitelist for now
instrument does not exist Wrong symbol format, or a futures format used for a spot order Write spot as BTC/USDT (uppercase with slash); run load_markets() first to see available pairs
size too small Order amount below the pair's minimum order size, or wrong precision Use load_markets() to check the pair's limits and precision, and round per its requirements

How to fix each one

The table gives direction; this section gives detail. Read down from whichever one you hit.

Auth class (Invalid sign / invalid API key / Passphrase error)

This is the heaviest-traffic zone for beginners. Check in the order below for the highest hit rate:

  • Check the Passphrase first. The password field in ccxt must hold the Passphrase you set when creating the Key—not your login password, and not the secret. This one accounts for more than half of auth failures.
  • Then check whether apiKey / secret was miscopied. Commonly there's an extra space at the start or end when pasting, or a character or two dropped. Recopying from the dashboard is the safest move.
  • Also check the system time. An off clock makes the signature timestamp expire, which also shows up as auth failure. Turn on NTP sync.

Permission denied

The classic symptom is "can check the balance, can't place orders." Checking the balance uses the read permission; placing orders uses the trade permission, and they're granted separately. Go back to API management on OKX, find this Key, and add "Trade"—no need to recreate. And if you happened to tick withdrawal—don't leave it on; a quant Key should never have withdrawal permission.

Insufficient balance

Beyond the literal "not enough money," there's a sneaky cause: OKX has different accounts (funding, trading, etc.), and your money may not be in the one used for ordering. Confirm the funds have been transferred to the trading account. On the demo, if the virtual funds run out, just reset them on the demo interface—another upside of practicing on the demo first, where trial and error costs no real money.

Symbol / precision class

Spot pairs in ccxt are uniformly UPPER/UPPER with a forward slash, like BTC/USDT. Writing it as BTCUSDT, lowercase, or in a futures format all throws errors. If the amount is too small or the precision is off, use load_markets() to check the pair's minimum order size and precision and go by what it requires. There's a full order example for this in our API quant intro.

Halfway through debugging and you find it's an account problem itself? If you don't yet have a clean account dedicated to scripts, open a separate one. Register with OKX using our invite code OK30001 for a fee discount that applies to API orders too. Sign up for OKX and open the API here →

Rate limits and backoff retry

The rate limit (50011 / Too Many Requests) is the one script writers hit most and should defend against ahead of time. It's not that you did something wrong—your requests were just too dense and tripped the exchange's protection. Handle it in two layers:

Layer one: turn on ccxt's built-in rate limiter. Add 'enableRateLimit': True at init, and ccxt will automatically insert reasonable gaps between requests. For most cases this step alone is enough:

okx = ccxt.okx({
    'apiKey':   'YOUR_apiKey',
    'secret':   'YOUR_secret',
    'password': 'YOUR_Passphrase',
    'enableRateLimit': True,   # auto rate-limit, turn this on first
})

Layer two: add exponential backoff retry. If your strategy really does send dense requests at certain moments (like polling many pairs at once), auto rate-limiting alone may still occasionally hit. Wrap key requests in a retry layer then: wait 1 second on the first hit and retry, then 2, then 4, stretching it out, and give up with an error after enough hits.

import ccxt, time

def with_retry(fn, max_tries=5):
    delay = 1
    for i in range(max_tries):
        try:
            return fn()
        except ccxt.RateLimitExceeded:
            print(f'Rate limited, attempt {i+1}, waiting {delay}s before retry')
            time.sleep(delay)
            delay *= 2          # exponential backoff: 1 → 2 → 4 → 8 ...
    raise RuntimeError('Still rate limited after retries, giving up')

# Usage: drop the call that gets rate limited in here
ticker = with_retry(lambda: okx.fetch_ticker('BTC/USDT'))
print(ticker['last'])

A cautionary counter-example: don't write a while True: that hammers the endpoint immediately with no delay in between. That kind of loop fires off dozens to hundreds of requests a second, instantly hits the rate limit, and in bad cases the whole Key gets briefly restricted. Any high-frequency loop needs gaps.

Tested: a gotcha we hit

📋 Desk test · 2026-06-05
At 16:47 we were debugging a multi-pair scanning script on OKX Demo Trading, and right off the bat we called fetch_ticker on a dozen-odd pairs back-to-back in a loop, with no delay in between, and we'd forgotten to turn on enableRateLimit. Within a minute the terminal started spamming RateLimitExceeded (which maps to 50011), and nearly all the following requests were toast. We did two things: first added 'enableRateLimit': True at init, then wrapped each pair's request in that with_retry backoff function above. After the fix and a rerun, all dozen-odd pairs returned normally; once or twice it tripped a backoff and waited a second or two before passing, and the full scan finished without rate-limit errors. The lesson is direct: hammering an endpoint in a loop, rate-limiting and backoff are standard issue, not optional.

FAQ

How do I read an OKX API error?

When an OKX endpoint errors out, it returns a code (numeric error code) and a msg (text description), plus an HTTP status code. Look at the code first—it points most precisely at the type of problem; the msg helps you confirm the direction. In ccxt, errors are usually wrapped into matching exception types (like AuthenticationError, RateLimitExceeded, InsufficientFunds), and the exception message generally carries OKX's original code and msg too. Search that string as-is and you can usually pinpoint it.

Why do I keep getting auth failed / Invalid sign?

The three most common causes of auth errors: one, the password field in ccxt doesn't hold OKX's Passphrase (you entered your login password by mistake); two, the apiKey or secret has extra spaces or missing characters from copying; three, your system time is off, making the signature timestamp expire. Check in that order and the vast majority of Invalid sign errors resolve.

What do I do about a rate limit (50011 / Too Many Requests)?

A rate limit is protection triggered by requests being too dense. The easiest fix is to turn on enableRateLimit when initializing ccxt, which automatically inserts gaps between requests. If you still hit it, add exponential backoff retry in the code—wait 1 second on the first hit, then 2, then 4, stretching it out. Don't use a while True with no delay to hammer the endpoint.

I can check the balance but ordering says permission denied—why?

Checking the balance is a read permission; placing orders is a trade permission, and they're granted separately when you create the Key. Being able to check but not order basically means you only ticked Read and not Trade. Go back to API management on OKX and add the Trade permission to this Key—no need to recreate.

What does timestamp expired mean?

OKX has a tolerance for the timestamp in a request; if your computer's or server's system time is off and exceeds the tolerance, the signature gets rejected as an expired timestamp. The fix is to sync your system time to accurate network time and turn on NTP auto-sync. Cloud servers usually have it on by default; local machines occasionally drift.

What's going on when it says instrument does not exist?

Most likely the symbol format is wrong. In ccxt, spot pairs are uppercase with a forward slash, like BTC/USDT; writing it as BTCUSDT, btc/usdt, or using a futures format for a spot order all throw instrument does not exist. When in doubt, run print(okx.load_markets().keys()) first to see what the available pairs actually look like.

Clear the error-troubleshooting hurdle and your script stops freezing up at every turn. The next thing worth your time is writing risk control into the code—scarier than an error is a script that doesn't error but keeps placing the wrong orders. And don't forget to run new code on the demo account first—debugging there costs no real money.

Debugging smoothed out—ready to run a strategy for real?

Get your account and API ready, smooth out the flow and the errors on the demo, then switch to real money. A new account registered with the invite code gets a fee discount, and orders placed via the API get it too.

OK30001 Sign up for OKX with OK30001 →

Crypto asset prices swing violently, and futures and leverage can lead to a total loss of capital. Quant and automated trading don't guarantee profit—use only funds you can afford to lose.