tigusigalpa / bitget-php
A production-grade PHP/Laravel SDK for the Bitget Unified Trading Account (UTA) API v3.
Requires
- php: ^8.2
- guzzlehttp/guzzle: ^7.15.2
- phrity/websocket: ^3.7.3
- psr/log: ^3.0
Requires (Dev)
- laravel/framework: ^10.0|^11.0|^12.0|^13.0
- phpunit/phpunit: ^11.0
README
A production-grade PHP SDK for the Bitget Unified Trading Account (UTA) API v3, with seamless Laravel 10-13 integration. Phase 1 covers Market, Account, and Trade REST services plus a reconnecting WebSocket client with a pluggable transport.
Package: a matching Go SDK is available at tigusigalpa/bitget-go.
What's inside
- PHP 8.2+,
declare(strict_types=1)everywhere, readonly constructor properties - Strings for every price/quantity/PnL/fee field — no float rounding errors
- Guzzle-based HTTP transport with an injectable
GuzzleHttp\Clientfor tests/proxies - PSR-3 logging (defaults to a no-op
NullLogger); credentials are never logged - A typed exception hierarchy (
AuthenticationException,RateLimitException,InvalidParameterException,InsufficientFundsException,OrderNotFoundException) carrying Bitget's raw error code - A
WebsocketClientwith pluggable transport (ConnectionInterface) — ships with a synchronoustextalk/websocketadapter; implement the interface yourself to run under ReactPHP, Amp, or Laravel Octane's event loop - Laravel service provider, publishable config, and
Bitgetfacade — auto-discovered, but the SDK has no hardilluminate/*dependency outside Laravel apps
Install
composer require tigusigalpa/bitget-php
Laravel setup
The service provider and Bitget facade are auto-discovered. Publish the config file:
php artisan vendor:publish --tag=bitget-config
BITGET_API_KEY=your-api-key BITGET_SECRET_KEY=your-secret-key BITGET_PASSPHRASE=your-passphrase BITGET_DEMO=false
use Tigusigalpa\Bitget\Facades\Bitget; $tickers = Bitget::market()->getTickers('SPOT', 'BTCUSDT');
Plain PHP (no Laravel)
use Tigusigalpa\Bitget\Client; $client = new Client( apiKey: getenv('BITGET_API_KEY'), secretKey: getenv('BITGET_SECRET_KEY'), passphrase: getenv('BITGET_PASSPHRASE'), ); $tickers = $client->market()->getTickers('SPOT', 'BTCUSDT');
Configuration
config/bitget.php key |
Env var | Default |
|---|---|---|
api_key |
BITGET_API_KEY |
'' |
secret_key |
BITGET_SECRET_KEY |
'' |
passphrase |
BITGET_PASSPHRASE |
'' |
demo |
BITGET_DEMO |
false |
base_url |
BITGET_BASE_URL |
https://api.bitget.com |
locale |
BITGET_LOCALE |
en-US |
REST API coverage (Phase 1)
| Category | Methods | Docs |
|---|---|---|
| Market (public) | getInstruments, getTickers, getOrderBook |
Instruments · Tickers · OrderBook |
| Account (private) | getAssets, getSettings, setLeverage |
Get-Account · Get-Account-Setting · Change-Leverage |
| Trade (private) | placeOrder, modifyOrder, cancelOrder, getOpenOrders, getOrderHistory, getPositions |
Place-Order · Modify-Order · Cancel-Order · Get-Order-Pending · Get-Order-History · Get-Position |
Full mapping with HTTP methods and paths: docs/endpoints.md.
WebSocket
use Tigusigalpa\Bitget\WebsocketClient; $ws = new WebsocketClient(WebsocketClient::DEFAULT_PUBLIC_URL); $ws->connect(); $ws->subscribe(['instType' => 'SPOT', 'topic' => 'ticker', 'symbol' => 'BTCUSDT']); $ws->listen(function (array $push) { echo json_encode($push), PHP_EOL; });
For private channels (e.g. order fills), pass credentials to the constructor — connect() authenticates automatically:
$ws = new WebsocketClient( url: WebsocketClient::DEFAULT_PRIVATE_URL, apiKey: config('bitget.api_key'), secretKey: config('bitget.secret_key'), passphrase: config('bitget.passphrase'), ); $ws->connect(); $ws->subscribe(['instType' => 'UTA', 'topic' => 'fast-fill', 'symbol' => 'default']); $ws->listen(fn (array $push) => /* handle fill */ null);
listen() blocks the current process, answers Bitget's text-frame ping/pong heartbeat, and — on an unexpected disconnect — reconnects with exponential backoff (1s → 60s cap) and resubscribes every previously active channel. The default transport (TextalkConnection) is synchronous; to run under a non-blocking event loop (ReactPHP, Amp, Laravel Octane), implement Tigusigalpa\Bitget\WebSocket\ConnectionInterface and pass it as WebsocketClient's $connection constructor argument.
Implemented private channel: fast-fill. Other channels work through the same subscribe()/listen() API; see docs/endpoints.md.
Demo trading
Set demo: true (or BITGET_DEMO=true) together with a Demo API key from the Bitget console to send paptrading: 1 on every REST request, or use WebsocketClient::DEMO_PUBLIC_URL/DEMO_PRIVATE_URL for WebSocket. Always validate new code against demo credentials before pointing it at a live account:
$client = new Client( apiKey: config('bitget.api_key'), secretKey: config('bitget.secret_key'), passphrase: config('bitget.passphrase'), demoTrading: true, ); // Guard order placement behind an explicit opt-in — never wire this to // production credentials without removing the gate deliberately. if (getenv('BITGET_ENABLE_TRADING') === '1') { $client->trade()->placeOrder([ 'category' => 'SPOT', 'symbol' => 'BTCUSDT', 'side' => 'buy', 'orderType' => 'limit', 'price' => '10000', // deliberately far below market so it won't fill 'qty' => '0.001', ]); }
Errors
use Tigusigalpa\Bitget\Exceptions\AuthenticationException; use Tigusigalpa\Bitget\Exceptions\InsufficientFundsException; use Tigusigalpa\Bitget\Exceptions\RateLimitException; use Tigusigalpa\Bitget\Exceptions\BitgetException; try { $client->trade()->placeOrder([...]); } catch (AuthenticationException $e) { // invalid API key/secret/passphrase } catch (InsufficientFundsException $e) { // not enough balance/margin } catch (RateLimitException $e) { // back off and retry } catch (BitgetException $e) { // anything else; $e->bitgetCode / $e->rawResponse are available }
Tests
composer install vendor/bin/phpunit
Unit tests run fully offline against a mocked Guzzle transport (MockHandler) — no network access or credentials required.
Contributing
- Fork and branch off
main. - Add/update tests for any behavior change (
vendor/bin/phpunitmust pass). - Every public method must include a
Docs:line in its docblock linking to the exact Bitget API documentation page it implements. - Update docs/endpoints.md for new endpoints.
Security
Found a vulnerability? Email sovletig@gmail.com directly — please don't open a public issue.
License
MIT. See LICENSE.
Author
Igor Sazonov — @tigusigalpa — sovletig@gmail.com
Links
Not affiliated with Bitget. Test on demo before going live.