-
Notifications
You must be signed in to change notification settings - Fork 0
Error Handling
Igor Sazonov edited this page Mar 15, 2026
·
1 revision
A guide to handling errors in the OKX PHP SDK.
The SDK provides a set of specialized exceptions for different error categories:
OKXException (base)
├── AuthenticationException
├── RateLimitException
├── InvalidParameterException
└── InsufficientFundsException
The base class for all OKX API exceptions.
use Tigusigalpa\OKX\Exceptions\OKXException;
try {
$balance = $client->account()->getBalance();
} catch (OKXException $e) {
echo "OKX error code: " . $e->okxCode;
echo "Message: " . $e->getMessage();
echo "Raw response: " . $e->rawResponse;
}Properties:
-
okxCode— OKX error code -
rawResponse— Full raw response from the API
Thrown for authentication failures (codes 50111, 50113).
use Tigusigalpa\OKX\Exceptions\AuthenticationException;
try {
$balance = $client->account()->getBalance();
} catch (AuthenticationException $e) {
// Invalid API key or signature
Log::error('OKX Authentication failed', [
'code' => $e->okxCode,
'message' => $e->getMessage()
]);
// Notify the administrator
Mail::to('admin@example.com')->send(new AuthFailedMail($e));
}Common causes:
- Invalid API key
- Invalid secret key
- Invalid passphrase
- Expired API key
- IP address not on the whitelist
Thrown when the request rate limit is exceeded (code 50011).
use Tigusigalpa\OKX\Exceptions\RateLimitException;
try {
$order = $client->trade()->placeOrder(...);
} catch (RateLimitException $e) {
// Wait and retry
sleep(1);
try {
$order = $client->trade()->placeOrder(...);
} catch (RateLimitException $e) {
Log::warning('Rate limit exceeded twice', [
'endpoint' => 'placeOrder'
]);
throw $e;
}
}Handling strategies:
- Exponential Backoff
function retryWithBackoff(callable $callback, int $maxRetries = 3): mixed
{
$attempt = 0;
while ($attempt < $maxRetries) {
try {
return $callback();
} catch (RateLimitException $e) {
$attempt++;
if ($attempt >= $maxRetries) {
throw $e;
}
sleep(pow(2, $attempt)); // 2, 4, 8 seconds
}
}
}
$order = retryWithBackoff(fn() => $client->trade()->placeOrder(...));- Queue
// Dispatch to a queue instead of executing immediately
PlaceOrderJob::dispatch($instId, $side, $amount)
->onQueue('okx-orders');Thrown when request parameters are invalid (codes 51000–51099).
use Tigusigalpa\OKX\Exceptions\InvalidParameterException;
try {
$order = $client->trade()->placeOrder(
instId: 'INVALID-PAIR',
tdMode: 'cash',
side: 'buy',
ordType: 'market',
sz: '0.001'
);
} catch (InvalidParameterException $e) {
// Validation failed
return response()->json([
'error' => 'Invalid order parameters',
'details' => $e->getMessage(),
'code' => $e->okxCode
], 400);
}Common errors:
- Invalid instrument symbol
- Order size below the minimum
- Invalid order type
- Missing required parameters
Thrown when the account has insufficient funds (codes 54000–54099).
use Tigusigalpa\OKX\Exceptions\InsufficientFundsException;
try {
$order = $client->trade()->placeOrder(...);
} catch (InsufficientFundsException $e) {
// Check the balance
$balance = $client->account()->getBalance();
return response()->json([
'error' => 'Insufficient funds',
'available_balance' => $balance[0]['details'][0]['availBal'],
'required' => $requestedAmount
], 400);
}use Tigusigalpa\OKX\Exceptions\{
OKXException,
AuthenticationException,
RateLimitException,
InvalidParameterException,
InsufficientFundsException
};
try {
$order = $client->trade()->placeOrder(
instId: 'BTC-USDT',
tdMode: 'cash',
side: 'buy',
ordType: 'market',
sz: '100'
);
return response()->json(['success' => true, 'order' => $order]);
} catch (AuthenticationException $e) {
Log::critical('OKX Authentication failed', ['error' => $e->getMessage()]);
return response()->json(['error' => 'Authentication failed'], 401);
} catch (RateLimitException $e) {
Log::warning('OKX Rate limit exceeded');
return response()->json(['error' => 'Too many requests, please try again later'], 429);
} catch (InvalidParameterException $e) {
Log::info('Invalid order parameters', ['error' => $e->getMessage()]);
return response()->json(['error' => 'Invalid parameters: ' . $e->getMessage()], 400);
} catch (InsufficientFundsException $e) {
Log::info('Insufficient funds for order');
return response()->json(['error' => 'Insufficient funds'], 400);
} catch (OKXException $e) {
Log::error('OKX API error', [
'code' => $e->okxCode,
'message' => $e->getMessage(),
'response' => $e->rawResponse
]);
return response()->json(['error' => 'API error: ' . $e->getMessage()], 500);
} catch (\Exception $e) {
Log::error('Unexpected error', ['error' => $e->getMessage()]);
return response()->json(['error' => 'Internal server error'], 500);
}namespace App\Exceptions;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Tigusigalpa\OKX\Exceptions\OKXException;
use Throwable;
class Handler extends ExceptionHandler
{
public function register(): void
{
$this->reportable(function (OKXException $e) {
Log::channel('okx')->error('OKX API Error', [
'code' => $e->okxCode,
'message' => $e->getMessage(),
'trace' => $e->getTraceAsString()
]);
});
$this->renderable(function (OKXException $e, $request) {
if ($request->expectsJson()) {
return response()->json([
'error' => 'OKX API Error',
'code' => $e->okxCode,
'message' => $e->getMessage()
], 500);
}
});
}
}class OKXRetryService
{
public function executeWithRetry(
callable $callback,
int $maxAttempts = 3,
int $delayMs = 1000
): mixed {
$attempt = 0;
$lastException = null;
while ($attempt < $maxAttempts) {
try {
return $callback();
} catch (RateLimitException $e) {
$lastException = $e;
$attempt++;
if ($attempt < $maxAttempts) {
usleep($delayMs * 1000 * $attempt);
continue;
}
} catch (OKXException $e) {
// Do not retry for other error types
throw $e;
}
}
throw $lastException;
}
}Usage:
$retryService = new OKXRetryService();
$order = $retryService->executeWithRetry(
fn() => $client->trade()->placeOrder(...)
);class OrderValidator
{
public function __construct(private Client $okx) {}
public function validateBalance(string $ccy, string $requiredAmount): bool
{
try {
$balance = $this->okx->account()->getBalance($ccy);
$available = (float) $balance[0]['details'][0]['availBal'];
return $available >= (float) $requiredAmount;
} catch (OKXException $e) {
Log::error('Failed to check balance', ['error' => $e->getMessage()]);
return false;
}
}
public function validateOrderBeforePlacing(array $orderParams): array
{
$errors = [];
// Validate the instrument
try {
$instruments = $this->okx->publicData()->getInstruments(
instType: 'SPOT',
instId: $orderParams['instId']
);
if (empty($instruments)) {
$errors[] = 'Invalid instrument';
}
} catch (OKXException $e) {
$errors[] = 'Failed to validate instrument';
}
// Validate balance for buy orders
if ($orderParams['side'] === 'buy') {
$quoteCcy = explode('-', $orderParams['instId'])[1];
if (!$this->validateBalance($quoteCcy, $orderParams['sz'])) {
$errors[] = 'Insufficient balance';
}
}
return $errors;
}
}use Sentry\Laravel\Integration;
try {
$order = $client->trade()->placeOrder(...);
} catch (OKXException $e) {
\Sentry\captureException($e);
\Sentry\configureScope(function ($scope) use ($e) {
$scope->setContext('okx', [
'code' => $e->okxCode,
'response' => $e->rawResponse
]);
});
throw $e;
}use Illuminate\Support\Facades\Cache;
class OKXMetrics
{
public static function recordError(string $type): void
{
$key = "okx_errors:{$type}:" . now()->format('Y-m-d-H');
Cache::increment($key, 1);
Cache::expire($key, 3600 * 24); // 24 hours
}
public static function getErrorStats(string $type, int $hours = 24): int
{
$total = 0;
for ($i = 0; $i < $hours; $i++) {
$key = "okx_errors:{$type}:" . now()->subHours($i)->format('Y-m-d-H');
$total += Cache::get($key, 0);
}
return $total;
}
}
// Usage
try {
$order = $client->trade()->placeOrder(...);
} catch (RateLimitException $e) {
OKXMetrics::recordError('rate_limit');
throw $e;
}| Code | Description | Exception |
|---|---|---|
| 50111 | Invalid API key | AuthenticationException |
| 50113 | Invalid signature | AuthenticationException |
| 50011 | Rate limit exceeded | RateLimitException |
| 51000–51099 | Invalid parameters | InvalidParameterException |
| 54000–54099 | Insufficient funds | InsufficientFundsException |
| 51008 | Order amount too small | InvalidParameterException |
| 51020 | Order price out of range | InvalidParameterException |
Full list: OKX Error Codes
- Always wrap API calls in try-catch
try {
$result = $client->trade()->placeOrder(...);
} catch (OKXException $e) {
// Handle the error
}- Log errors with context
catch (OKXException $e) {
Log::error('OKX Error', [
'code' => $e->okxCode,
'message' => $e->getMessage()
]);
}- Retry on rate limit errors
catch (RateLimitException $e) {
sleep(1);
// Retry
}- Validate before sending requests
if (!$validator->validateBalance(...)) {
throw new \Exception('Insufficient balance');
}- Track error frequency
OKXMetrics::recordError('rate_limit');Back: ← Laravel Integration | Next: Examples →