Overview
Signing requests yourself, then keeping a WebSocket alive, is where most exchange integrations start to rot. Each venue uses a different signature, a different clock or nonce rule, and a different shape for the same idea of "place an order". The Siebly SDKs are separate Node.js clients, one package per exchange, written in TypeScript. They sign the request and keep the socket up. They do not throttle you. That part stays in your process.
Key Takeaways
- Request signing is not one HMAC recipe. Kraken, Gate, Binance, and Coinbase Advanced Trade do not sign the same way.
- Bybit's current client is V5 (
RestClientV5).SpotClientV3is deprecated. - Awaitable order calls over WebSocket exist on some of these packages, and not on Coinbase or BitMart.
- None of these SDKs queue or slow your requests to stay under an exchange rate limit. binance does record the weight headers Binance sends back.
Signing is different on every venue
Exchange docs describe the HTTP API. They are not a client. If you sign by hand, the bugs show up as rejected private calls, and the reason is usually the signature string, not the order itself.
These are the schemes the current packages implement:
- binance signs REST with HMAC-SHA256, RSA, or Ed25519. A PEM private key is detected and switches the algorithm. The default
recvWindowis 5000 ms. Time sync exists, and it is off unless you setdisableTimeSync: false. - bybit-api V5 signs with HMAC-SHA256, or RSA-SHA256 when the secret is a PEM private key. Time sync is off unless you set
enable_time_sync. - okx-api, bitget-api, and kucoin-api use HMAC-SHA256 plus the API passphrase. That passphrase is not your login password.
- gateio-api uses HMAC-SHA512.
- @siebly/kraken-api hashes the payload with SHA-256, then signs with HMAC-SHA512. The API secret is base64. Spot signing uses a nonce.
- @siebly/htx-api uses HMAC-SHA256.
bitmart-apiuses HMAC-SHA256 overtimestamp#memo#params. You passapiMemofrom the key you created.- coinbase-api is split by product. Advanced Trade and the Coinbase App sign a JWT, and the client accepts ECDSA or Ed25519 keys. Coinbase Exchange, International, and Prime use HMAC-SHA256 plus a passphrase.
A clock that is off by a few hundred milliseconds is not a universal failure mode. Binance and Bybit reject a request when the timestamp falls outside recvWindow (5000 ms on the Binance client unless you change it). Kraken spot fails on a bad nonce, not on that same window. Sync the host clock first. If a Binance or Bybit call still reports a recvWindow error, both WebSocket API clients expose setTimeOffsetMs().
Bybit's old spot V3 client is still exported as SpotClientV3, and the source marks it deprecated. Those endpoints were scheduled to be turned off by the end of 2024. New code should use RestClientV5. The V5 methods take a category (spot, linear, inverse, option) because that is how Bybit's Unified Trading Account API is shaped. Calling that "Unified Margin" is the older account name, and it is the wrong one to use against this client.
What the SDK is responsible for
Each package splits stateless REST calls from the WebSocket client that holds the connection, heartbeats, and reconnect.
The SDK signs, stamps the timestamp or nonce, and parses the JSON into the typed method you called. It does not decide how fast you are allowed to call. A 404 is a missing path or resource. Rate limits come back as 429, or as an exchange error code in the body. Do not treat those as the same failure.
On binance, the REST client stores the weight and order-count headers from the last response on apiLimitTrackers (x-mbx-used-weight-1m, x-mbx-order-count-10s, and the other x-mbx-* counters). That is a reading, not a limiter. Nothing in that client waits, queues, or sheds a call when the weight gets high. If you need a queue, you write it.
binance and bybit-api publish a CommonJS build (main points at lib/index.js). Node can import that build, and the examples also show require(). The other packages publish both an ESM and a CJS entry (import and require in exports).
One package per exchange
A single wrapper that pretends every exchange has the same createOrder() will hide the parameters you actually need. Bybit V5 wants category. Binance Portfolio Margin is a separate client, PortfolioClient, next to MainClient (spot, cross margin, isolated margin, and the other main-site products), USDMClient, and CoinMClient. Vanilla options are not in the Binance REST clients yet.
Bitget's awaitable WebSocket orders are the V3 / Unified Trading Account API. RestClientV2 and WebsocketClientV2 are still in the package for the classic account. WebsocketAPIClient on Bitget expects V3 keys.
The npm names below are the ones in each package.json. Kraken and HTX are scoped. The others are not.
| Package | REST clients | Awaitable WebSocket API |
|---|---|---|
| binance | MainClient, USDMClient, CoinMClient, PortfolioClient | Yes, spot and futures. Ed25519 can log the session in once. HMAC and RSA sign every command. |
| bybit-api | RestClientV5 | Yes, V5. Demo trading can consume events. It does not support this WebSocket API. |
| okx-api | RestClient | Yes. Passphrase required. |
| bitget-api | RestClientV2, RestClientV3 | Yes, V3 / UTA only. Passphrase required. |
| gateio-api | RestClient | Yes, spot and futures. |
| kucoin-api | SpotClient, FuturesClient, UnifiedAPIClient, BrokerClient | Yes, spot, margin, and futures. Passphrase required. |
| @siebly/kraken-api | SpotClient, DerivativesClient, InstitutionalClient, PartnerClient | Spot only. |
| coinbase-api | CBAdvancedTradeClient, CBAppClient, CBExchangeClient, CBInternationalClient, CBPrimeClient, CBCommerceClient | No. Streams only, through WebsocketClient. |
bitmart-api | RestClient, FuturesClientV2 | No. Streams only, through WebsocketClient. |
| @siebly/htx-api | SpotClient, FuturesClient | Yes, spot and derivatives. |
Specialized clients are the right tool when you place or amend orders. A unified library is fine for a read-only screen that only needs last price from many venues. When Bybit or Binance changes a parameter, the matching package can ship that change on its own. A wrapper that maps ten exchanges through one method waits on every other venue first.
REST and WebSocket calls
Use REST for snapshots and for anything the venue does not expose as a request/response socket call. Use the WebSocket client for streams. Where the table above says the WebSocket API exists, WebsocketAPIClient returns a Promise for that call. You await the matching response. You do not have to correlate ids yourself.
Public REST needs no keys. This is the Bybit V5 ticker call from the SDK examples. category is required, and it is how you pick the V5 product:
Imported example
import { RestClientV5 } from "bybit-api";
const client = new RestClientV5();
const tickers = await client.getTickers({ category: "linear" });
console.log(tickers);
The same pattern on Binance spot uses MainClient. Credentials are optional until you call a private method:
Imported example
import { MainClient } from "binance";
const client = new MainClient();
const ticker = await client.get24hrChangeStatistics({
symbol: "BTCUSDT",
});
console.log(ticker);
Bybit's WebSocket API client is the same V5 surface, as a Promise. The snippet below is the SDK's own order example. With live keys this sends a real limit order. testnet: true is available on this client. Demo trading is not: as of the SDK example notes (Jan 2025), Bybit demo trading can consume events and does not accept WebSocket API orders.
Imported example
import { WebsocketAPIClient } from "bybit-api";
const wsClient = new WebsocketAPIClient({
key: process.env.API_KEY_COM,
secret: process.env.API_SECRET_COM,
// testnet: true,
});
const response = await wsClient.submitNewOrder({
category: "linear",
symbol: "BTCUSDT",
orderType: "Limit",
qty: "0.001",
side: "Buy",
price: "50000",
});
console.log(response);
Binance has the same style of client. HMAC and RSA work, and each command is signed on its own. Ed25519 is the one that can authenticate the socket up front, which is why the SDK examples call it the faster path for this API. Pass the Ed25519 private key as api_secret.
Imported example
import { WebsocketAPIClient } from "binance";
const wsClient = new WebsocketAPIClient({
api_key: process.env.API_KEY_COM,
api_secret: process.env.API_SECRET_COM,
});
const response = await wsClient.submitNewSpotOrder({
symbol: "BTCUSDT",
side: "SELL",
type: "LIMIT",
timeInForce: "GTC",
price: "23416.10000000",
quantity: "0.00847000",
});
console.log(response);
OKX will reject the call if you only pass a key and secret. The REST and WebSocket API clients expect the passphrase on the account object:
Imported example
import { WebsocketAPIClient } from "okx-api";
const wsClient = new WebsocketAPIClient({
accounts: [
{
apiKey: process.env.API_KEY_COM || "",
apiSecret: process.env.API_SECRET_COM || "",
apiPass: process.env.API_PASSPHRASE_COM || "",
},
],
});
const res = await wsClient.submitNewOrder({
instId: "BTC-USDT",
tdMode: "cash",
side: "buy",
ordType: "limit",
px: "10000",
sz: "0.001",
});
console.log(res);
The place-order type marks instId as deprecated since March 2026 in favor of instIdCode (a numeric instrument id, which wins if you send both). The SDK examples still pass instId. Check OKX's current instrument mapping before you rely on the string id.
Bitget's version of that call is submitNewOrder('spot', {... }) on WebsocketAPIClient, and it needs apiKey, apiSecret, and apiPass from a V3 key. KuCoin uses apiPassphrase and methods such as submitNewSpotOrder. Gate uses submitNewSpotOrder and also has futures methods on the same client. Kraken's submitSpotOrder is spot only. HTX's submitSpotOrder needs the spot account-id from your account.
Keep the process that places orders separate from the process that chews through order book diffs. The socket client can stay current and still be useless if your parser blocks the event loop. Public data and testnet or demo, where that venue actually supports it, should be the first place these calls run. See historical and live data pipelines if you are splitting ingest from execution.
Reconnects, and where await does not exist
The stream clients emit reconnect and reconnected and resubscribe after the socket returns. That covers Binance (including the 24 hour disconnect and listenKey refresh), Bybit, OKX, Bitget, Gate, KuCoin, Kraken, HTX, Coinbase, and BitMart. A reconnect does not rewind the trades you missed. Snapshot the book or the account over REST when the socket comes back, then continue from the stream.
Coinbase and BitMart do not have WebsocketAPIClient. You cannot await an order acknowledgement on those two. Coinbase Advanced Trade public data looks like this:
Imported example
import { WebsocketClient } from "coinbase-api";
const client = new WebsocketClient();
client.on("update", (data) => {
console.log(data);
});
client.on("reconnected", (data) => {
console.log("reconnected", data?.wsKey);
});
client.subscribe(
{
topic: "ticker",
payload: {
product_ids: ["BTC-USD"],
},
},
"advTradeMarketData",
);
Private Coinbase streams use the same subscribe() call with a user-data wsKey such as advTradeUserData. The client authenticates that connection when keys are present. Order placement for Coinbase stays on the REST client, for example CBAdvancedTradeClient.
BitMart is the same shape: new WebsocketClient(), listen for update, and subscribe. There is no promise wrapper for trading commands.
Typed clients and coding agents
The request objects you pass are the types checked by the compiler. That is what an editor, and a coding agent, can follow. coinbase-api types most requests and responses, not every field of every payload, so do not assume a missing property is a bug in your code before you check the type.
The Siebly AI Prompt Framework and the pattern notes are written against these clients. Point the agent at the package and the method, not at a generic "exchange" interface. When an API version moves, track it on releases for the package you actually depend on.
These clients are a signing and transport layer. They are not a trading system, and they are not a rate limiter. Build the throttle, the order state, and the kill switch yourself.
The packages in the table above are the current set: binance, bybit-api, okx-api, @siebly/kraken-api, coinbase-api, bitget-api, gateio-api, kucoin-api, bitmart-api, and @siebly/htx-api. Install docs and per-exchange tutorials start at siebly.io/sdk.
Frequently Asked Questions
Does the Siebly SDK handle exchange rate limits automatically?
No. None of these clients delay or queue calls to stay under a venue limit. On binance, read apiLimitTrackers if you want the latest x-mbx-used-weight-* and order-count headers. You still have to act on them. Other venues expect you to watch their own headers or error codes and back off in your own queue.
How do I securely sign API requests in a Node.js environment?
You don't sign them yourself. Construct the client with the key material for that venue and call the method. Load keys from the environment, keep them on the server, and create the key without withdraw permission unless you have a separate reason to move funds.
The algorithm depends on the package. See the list in Signing is different on every venue. OKX, Bitget, and KuCoin need the API passphrase. BitMart needs apiMemo. Coinbase Advanced Trade needs the key type the JWT signer expects (ECDSA or Ed25519), not a raw HMAC secret.
What is the advantage of an awaitable WebSocket for order placement?
On the packages that implement it, WebsocketAPIClient sends the command on the open socket and resolves when the matching response arrives. That is one round trip on the connection you already authenticated, instead of a separate REST call.
It is not available on coinbase-api or bitmart-api. On @siebly/kraken-api it is spot only. On bitget-api it is V3 / UTA only. On bybit-api it is V5, and it is not available in Bybit demo trading.
Can I use these SDKs for high-frequency trading (HFT)?
These are Node.js clients. They remove the signing and reconnect boilerplate. They do not colocate you, and they do not make the event loop free. If you are latency sensitive on Binance's WebSocket API, use an Ed25519 key so the session authenticates once. HMAC and RSA sign every command on that socket.
Which exchanges are currently supported by Siebly specialized SDKs?
binance, bybit-api, okx-api, @siebly/kraken-api, coinbase-api, bitget-api, gateio-api, kucoin-api, bitmart-api, and @siebly/htx-api.
Kraken and HTX are the scoped names. Installing kraken-api or htx-api without @siebly/ is the wrong package name.
How do I handle WebSocket reconnections without losing data?
The stream clients reconnect and resubscribe. They do not backfill. After reconnected, pull a REST snapshot of the book or the open orders, then follow the stream again.
Are Siebly SDKs compatible with TypeScript and modern Node.js versions?
Yes, they are TypeScript and ship declaration files. binance and bybit-api publish CommonJS, which both require() and Node's import can load. The other eight packages publish dedicated ESM and CJS builds. There is no engines field pinning a Node version in these packages. Binance's WebCrypto path assumes a Node release that still has it. Node 18 is end of life.
How does the Siebly AI framework assist in building trading bots?
The prompt framework and pattern notes are aimed at coding agents working against these typed clients. An agent does better when the package exports submitNewOrder with a real parameter type than when it is guessing a shared order schema. Treat anything it generates as a draft, run it against public data or testnet, and read the venue docs before it can send an order. The framework is not a strategy and not a signal service.
Related articles
Continue from here