PHP client for the OKX v5 API. Covers the entire REST API (335 endpoints, 16 categories) and WebSocket API (53 channels). Works standalone or plugs into Laravel 11/12 via a Service Provider.
Go version: tigusigalpa/okx-go | Wiki
- 335 REST endpoints grouped into service classes (
account(),trade(),market(), etc.) - WebSocket client with auto-reconnect and ping/pong heartbeat
- HMAC-SHA256 request signing
- Demo trading mode (just flip a flag)
- Typed DTOs for requests and responses; all prices/amounts stay as
stringto avoid float rounding - Laravel Service Provider, Facade, publishable config
- PSR-3 logging, PSR-12 code style
- PHP 8.2+ (
readonlyclasses, named arguments)
- PHP 8.2+
- Composer
- Laravel 11 or 12 (optional)
composer require tigusigalpa/okx-phpPublish the config:
php artisan vendor:publish --tag=okx-configAdd credentials to .env:
OKX_API_KEY=your-api-key
OKX_SECRET_KEY=your-secret-key
OKX_PASSPHRASE=your-passphrase
OKX_DEMO=falseThen use the facade:
use Tigusigalpa\OKX\Facades\OKX;
$balance = OKX::account()->getBalance();
$order = OKX::trade()->placeOrder(
instId: 'BTC-USDT',
tdMode: 'cash',
side: 'buy',
ordType: 'limit',
sz: '0.01',
px: '50000'
);
$ticker = OKX::market()->getTicker('BTC-USDT');use Tigusigalpa\OKX\Client;
$client = new Client(
apiKey: 'your-api-key',
secretKey: 'your-secret-key',
passphrase: 'your-passphrase',
);
$balance = $client->account()->getBalance();
$order = $client->trade()->placeOrder(
instId: 'BTC-USDT',
tdMode: 'cash',
side: 'buy',
ordType: 'market',
sz: '100',
tgtCcy: 'quote_ccy'
);
$trades = $client->market()->getTrades('BTC-USDT', limit: 100);| Option | Env variable | Default | |
|---|---|---|---|
api_key |
OKX_API_KEY |
'' |
API key |
secret_key |
OKX_SECRET_KEY |
'' |
Secret key |
passphrase |
OKX_PASSPHRASE |
'' |
Passphrase |
demo |
OKX_DEMO |
false |
Use demo trading environment |
base_url |
OKX_BASE_URL |
https://www.okx.com |
Base URL |
335 endpoints across 16 categories:
| Category | # | Docs |
|---|---|---|
| Account | 53 | Trading Account |
| Trade | 32 | Order Book Trading |
| Market | 24 | Market Data |
| Public Data | 24 | Public Data |
| Asset | 26 | Funding Account |
| Finance | 33 | Financial Products |
| Copy Trading | 26 | Copy Trading |
| Trading Bot | 44 | Trading Bot |
| RFQ | 20 | Block Trading |
| Spread Trading | 13 | Spread Trading |
| Rubik | 15 | Trading Statistics |
| Fiat | 13 | Fiat |
| Users | 8 | Sub-account |
| Support | 2 | Announcements |
| System Status | 1 | Status |
| Affiliate | 1 | Affiliate |
Public channel:
use Tigusigalpa\OKX\WebsocketClient;
$ws = new WebsocketClient(
apiKey: 'your-api-key',
secretKey: 'your-secret-key',
passphrase: 'your-passphrase'
);
$ws->connectPublic();
$ws->subscribe('tickers', ['instId' => 'BTC-USDT'], function ($data) {
echo "BTC-USDT: " . $data['data'][0]['last'] . PHP_EOL;
});
$ws->run();Private channel (authenticated automatically on connect):
$ws->connectPrivate();
$ws->subscribe('account', ['ccy' => 'BTC'], function ($data) {
foreach ($data['data'] as $account) {
echo "Balance: {$account['bal']} {$account['ccy']}" . PHP_EOL;
}
});
$ws->run();Public channels include tickers, books, books5, trades, candle*, index-tickers, mark-price,
funding-rate, open-interest, liquidation-orders, and others.
Private channels include account, positions, orders, orders-algo, fills, balance_and_position,
liquidation-warning, deposit-info, withdrawal-info, and others.
Set OKX_DEMO=true in .env, or pass isDemo: true to the constructor. Same API, sandbox environment, no real money
involved.
$client = new Client(
apiKey: 'your-api-key',
secretKey: 'your-secret-key',
passphrase: 'your-passphrase',
isDemo: true
);Order with TP/SL:
$order = $client->trade()->placeOrder(
instId: 'BTC-USDT',
tdMode: 'cross',
side: 'buy',
ordType: 'limit',
sz: '0.1',
px: '50000',
tpTriggerPx: '55000',
tpOrdPx: '-1',
slTriggerPx: '48000',
slOrdPx: '-1'
);Batch orders:
$orders = $client->trade()->batchOrders([
[
'instId' => 'BTC-USDT',
'tdMode' => 'cash',
'side' => 'buy',
'ordType' => 'limit',
'sz' => '0.01',
'px' => '50000'
],
[
'instId' => 'ETH-USDT',
'tdMode' => 'cash',
'side' => 'buy',
'ordType' => 'limit',
'sz' => '0.1',
'px' => '3000'
]
]);Set leverage:
$client->account()->setLeverage(
lever: '10',
mgnMode: 'cross',
instId: 'BTC-USDT-SWAP'
);Historical candles:
$candles = $client->market()->getHistoryCandles(
instId: 'BTC-USDT',
bar: '1H',
limit: 100
);Withdrawal:
$withdrawal = $client->asset()->withdrawal(
ccy: 'USDT',
amt: '100',
dest: '4',
toAddr: 'your-wallet-address',
fee: '1',
chain: 'USDT-TRC20'
);Each error type has its own exception class. They all extend OKXException, which carries the raw OKX error code in
$e->okxCode.
use Tigusigalpa\OKX\Exceptions\AuthenticationException;
use Tigusigalpa\OKX\Exceptions\RateLimitException;
use Tigusigalpa\OKX\Exceptions\InvalidParameterException;
use Tigusigalpa\OKX\Exceptions\InsufficientFundsException;
use Tigusigalpa\OKX\Exceptions\OKXException;
try {
$balance = $client->account()->getBalance();
} catch (AuthenticationException $e) {
// bad credentials or signature
} catch (RateLimitException $e) {
// slow down
} catch (InvalidParameterException $e) {
// check your request params
} catch (InsufficientFundsException $e) {
// not enough balance
} catch (OKXException $e) {
// everything else from OKX
echo "OKX error [{$e->okxCode}]: " . $e->getMessage();
}Pass any PSR-3 logger to the constructor:
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
$logger = new Logger('okx');
$logger->pushHandler(new StreamHandler('okx.log', Logger::DEBUG));
$client = new Client(
apiKey: 'your-api-key',
secretKey: 'your-secret-key',
passphrase: 'your-passphrase',
logger: $logger
);Credentials are never written to logs.
Unit tests:
vendor/bin/phpunitIntegration tests (needs demo credentials):
export OKX_API_KEY=your-demo-api-key
export OKX_SECRET_KEY=your-demo-secret-key
export OKX_PASSPHRASE=your-demo-passphrase
vendor/bin/phpunit -c phpunit.integration.xml- Fork it
- Create a branch (
git checkout -b fix/something) - Make your changes, add tests
- Push and open a PR
Code must follow PSR-12. Tests must pass.
Found a vulnerability? Email sovletig@gmail.com directly. Don't open a public issue.
MIT. See LICENSE.
