tigusigalpa/kucoin-php

An idiomatic PHP client for KuCoin's UTA and Classic REST/WebSocket APIs, with optional Laravel 10-13 integration.

Maintainers

Package info

github.com/tigusigalpa/kucoin-php

pkg:composer/tigusigalpa/kucoin-php

Transparency log

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 3

dev-main 2026-08-09 13:36 UTC

This package is auto-updated.

Last update: 2026-08-09 13:43:42 UTC


README

KuCoin PHP SDK

PHP Version License Laravel

A PHP client for KuCoin's UTA (Unified Trading Account) and Classic (Spot/Margin/Futures) REST and WebSocket APIs, written from scratch against KuCoin's current docs-new documentation — not a wrapper around the official Universal SDK. PSR-18/PSR-17 based (no hardcoded Guzzle), with optional Laravel 10–13 integration.

Package: a matching Go SDK is available at tigusigalpa/kucoin-go.

Status

This is an early, honest checkpoint, not a finished library. Only UTA public market data (plus the one endpoint in that group that turns out to require auth — see below) is implemented and tested so far. Everything else described in this project's roadmap — UTA Account/Orders/Positions/Leverage/Transfers, Classic Spot/Margin/Futures trading, and every WebSocket channel — is not yet implemented. See docs/ENDPOINTS.md for the exact, generated list of what's covered, with a direct KuCoin documentation link per method.

Phase Scope Status
1 — reliable core Shared HTTP/auth/error/retry infra; UTA market/account/orders; Classic Spot market/orders; Classic Futures market/order/position; UTA + Classic WS core channels Partial — shared infra + UTA Market done; the rest is not started
2 — trading breadth Classic Margin; advanced Spot/Margin orders; UTA positions/leverage; more WS channels Not started
3 — specialty domains Account/funding/subaccounts/deposits/withdrawals, Earn, VIP Lending, Convert, Broker, Affiliate, Copy Trading Not started

What's inside (so far)

  • PHP 8.1+, declare(strict_types=1) everywhere, readonly constructor properties, a backed TradeType enum
  • No hardcoded HTTP clientClient takes any PSR-18 ClientInterface + PSR-17 factories; guzzlehttp/guzzle is require-dev/suggest only, never a hard dependency
  • Strings for every price/quantity/PnL/fee field — no float rounding errors
  • Independent HMAC-SHA256 signer (KC-API-SIGN and the HMAC-signed KC-API-PASSPHRASE), verified against known-answer fixture vectors shared with kucoin-go
  • A shared Http\RequestExecutor: response envelope decoding, Http\ResponseMeta (HTTP status, KuCoin business code/message, request ID, gw-ratelimit-*, x-in-time/x-out-time), and a typed exception hierarchy
  • A conservative retry policy — GET requests only, exponential backoff with jitter, bounded max-elapsed time; POST/DELETE (place/cancel/amend orders, transfers, withdrawals) are never auto-retried
  • Optional Laravel 10–13 integration (Laravel\KucoinServiceProvider, Laravel\Facades\Kucoin) — kept entirely separate from the core; the core never calls a Laravel helper
  • A manifest-driven docs/ENDPOINTS.md, regenerated by php bin/gendocs.php from resources/endpoints.yaml; CI fails if they drift apart

Install

composer require tigusigalpa/kucoin-php

Plain PHP apps also need a PSR-18 client + PSR-17 factories — e.g.:

composer require guzzlehttp/guzzle guzzlehttp/psr7

Laravel setup

The service provider and Kucoin facade are auto-discovered. If guzzlehttp/guzzle + guzzlehttp/psr7 are installed, a default PSR-18/17 binding is wired up automatically; otherwise the container throws a clear error naming what to install or bind yourself.

php artisan vendor:publish --tag=kucoin-config
KUCOIN_API_KEY=your-api-key
KUCOIN_API_SECRET=your-api-secret
KUCOIN_API_PASSPHRASE=your-passphrase
KUCOIN_API_KEY_VERSION=3
use Tigusigalpa\Kucoin\Client;
use Tigusigalpa\Kucoin\Uta\Market\TradeType;

class MarketController
{
    public function __construct(private readonly Client $kucoin) {}

    public function index()
    {
        return $this->kucoin->uta->market->getTickers(TradeType::Spot->value, 'BTC-USDT');
    }
}

Because services are exposed as typed public readonly properties ($client->uta->market) rather than facade methods, prefer constructor injection of Client over the facade; the facade mainly helps for quick artisan tinker usage via Kucoin::getFacadeRoot().

Plain PHP (no Laravel)

use GuzzleHttp\Client as GuzzleClient;
use GuzzleHttp\Psr7\HttpFactory;
use Tigusigalpa\Kucoin\Client;
use Tigusigalpa\Kucoin\Uta\Market\TradeType;

$factory = new HttpFactory();
$client = new Client(
    httpClient: new GuzzleClient(),
    requestFactory: $factory,
    streamFactory: $factory,
);

$tickers = $client->uta->market->getTickers(TradeType::Spot->value, 'BTC-USDT');
echo $tickers['list'][0]['lastPrice'];

Runnable example (verified against the live API — read-only, no credentials): examples/uta_market.php.

Credentials and security

Read KUCOIN_API_KEY/KUCOIN_API_SECRET/KUCOIN_API_PASSPHRASE from environment variables or Laravel config — never hardcode them:

use Tigusigalpa\Kucoin\Config\Credentials;

$credentials = new Credentials(
    apiKey: getenv('KUCOIN_API_KEY'),
    apiSecret: getenv('KUCOIN_API_SECRET'),
    apiPassphrase: getenv('KUCOIN_API_PASSPHRASE'),
    apiKeyVersion: getenv('KUCOIN_API_KEY_VERSION'), // per-key metadata, not a constant
);
  • Create keys with the minimum permission needed (read-only for market/account calls).
  • Restrict the key to specific IPs where KuCoin allows it.
  • This library never logs KC-API-KEY, KC-API-SIGN, KC-API-PASSPHRASE, or full private request bodies.
  • It never places live trading, transfer, or withdrawal calls in its own tests, examples, or CI.
  • A published config/kucoin.php reads secrets from env() — it never contains actual secret values.

See SECURITY.md to report a vulnerability.

UTA versus Classic

KuCoin exposes two distinct account models with different permissions, hosts, and data shapes. This SDK keeps them as explicit, separate properties$client->uta today, $client->classic once implemented — rather than merging them into one type, since doing so would misrepresent which fields/permissions actually apply.

REST examples

Market data (public, no credentials):

$tickers = $client->uta->market->getTickers(TradeType::Spot->value, 'BTC-USDT');

The one authenticated exception in this servicegetOrderBook looked public in KuCoin's docs but a live test confirmed it requires credentials:

$book = $client->uta->market->getOrderBook(TradeType::Spot->value, 'BTC-USDT', limit: 20);

Error and rate-limit inspection:

use Tigusigalpa\Kucoin\Exception\RateLimitException;
use Tigusigalpa\Kucoin\Exception\KucoinException;

try {
    $client->uta->market->getOrderBook(TradeType::Spot->value, 'BTC-USDT');
} catch (RateLimitException $e) {
    // back off
} catch (KucoinException $e) {
    echo $e->httpStatus, ' ', $e->kucoinCode, ' ', $e->getMessage();
}

$meta = $client->uta->executor->getLastResponseMeta();
echo $meta->rateLimitRemaining, '/', $meta->rateLimitLimit;

Authenticated account/order examples aren't shown here because that domain isn't implemented yet — see Status above.

WebSocket examples

Not yet implemented. No WebSocket client exists in this checkpoint. Token acquisition, subscription ACKs, heartbeat, reconnect/re-subscribe, and typed message dispatch are all planned for a later phase — see CONTRIBUTING.md.

Configuration

config/kucoin.php key Env var Default
api_key KUCOIN_API_KEY ''
api_secret KUCOIN_API_SECRET ''
api_passphrase KUCOIN_API_PASSPHRASE ''
api_key_version KUCOIN_API_KEY_VERSION ''
uta_base_url KUCOIN_UTA_BASE_URL https://api.kucoin.com
site_type KUCOIN_SITE_TYPE global
enable_ns KUCOIN_ENABLE_NS false

Outside Laravel, pass the equivalent constructor arguments to Client/Config\RetryPolicy directly — see src/Client.php.

Endpoint reference

Full, generated coverage map with direct KuCoin doc links: docs/ENDPOINTS.md. Source manifest: resources/endpoints.yaml. Official docs map: KuCoin llms.txt.

Laravel section

  • Auto-discovery: no manual provider/facade registration needed on Laravel 10–13.
  • Publishing config: php artisan vendor:publish --tag=kucoin-config.
  • Dependency injection: constructor-inject Tigusigalpa\Kucoin\Client — the recommended pattern, since services are typed properties, not facade methods.
  • Config caching: config/kucoin.php only reads env() at merge time (standard Laravel config-cache-safe pattern) — safe with php artisan config:cache.
  • Worker lifecycle: the Client singleton is safe to reuse across queue-worker jobs or Octane requests today (every call is a stateless REST request). This will need re-evaluation once a WebSocket client exists — see the note in src/Laravel/KucoinServiceProvider.php.

Testing and development

composer install
vendor/bin/phpunit       # or: composer test
php bin/gendocs.php      # or: composer gendocs — regenerate docs/ENDPOINTS.md after editing the manifest

Unit tests run fully offline against a mocked Guzzle/PSR-18 transport (MockHandler) — no network access or credentials required. No test, example, or CI job in this repository places a live trading, transfer, or withdrawal call.

Compatibility and migration

Pre-1.0: breaking changes may happen between minor versions while Phase 1 is being built out; see CHANGELOG.md. This library is not a drop-in replacement for the official KuCoin Universal SDK — method names, types, and error handling are intentionally different.

Security, risk and legal notice

This is an unofficial, community-maintained client. It is provided as is, with no warranty. Nothing here is financial advice. You are solely responsible for complying with the laws and regulations of your jurisdiction and for the safety of your API credentials and funds. Always test against a small amount / read-only permissions before trusting new code with a funded account.

Contributing and roadmap

See CONTRIBUTING.md for the workflow and the phase-by-phase roadmap.

License

MIT. See LICENSE.

Author

Igor Sazonov — @tigusigalpasovletig@gmail.com

Links

Not affiliated with KuCoin. This is an early checkpoint — verify coverage in docs/ENDPOINTS.md before relying on any endpoint.