Gateway notifications
Connect to the gateway WebSocket, authenticate with JWT or API key, and receive wallet, teller, identity, and loan events.
This socket pushes notifications for a logged-in account (wallet, teller, identity, loans). It is not the Spot Trading API WebSocket (wss://ws.bit2me.com/v1/trading).
You can only receive events after a successful authenticate. If authentication fails, the server closes with code 4000.
URL
wss://ws.bit2me.com/v1Do not use the Pro URL (wss://ws.bit2me.com/v1/trading) for these notifications.
Authenticate
After open, send one authenticate message. Pick JWT or API key, not both on the same send.
Option 1 — JWT (token)
- Sign
POST https://gateway.bit2me.com/v1/signin/apikeywith HMAC. See Authentication. - Read
accessToken.tokenfrom the 200 body. HonouraccessToken.expirationTimefrom that response. Do not invent a TTL. - For a subaccount, include
userIdin the sign-in body.
curl -X POST 'https://gateway.bit2me.com/v1/signin/apikey' \
-H 'Content-type: application/json' \
-H 'X-API-KEY: <api key>' \
-H 'api-signature: <hmac>' \
-H 'x-nonce: <nonce>'Subaccount session:
curl -X POST 'https://gateway.bit2me.com/v1/signin/apikey' \
-H 'Content-type: application/json' \
-H 'X-API-KEY: <api key>' \
-H 'api-signature: <hmac>' \
-H 'x-nonce: <nonce>' \
-d '{"userId":"<subaccount uuid>"}'Then on the socket:
{ "type": "authenticate", "payload": { "token": "<accessToken.token>" } }Option 2 — API key (apikey)
Send the public API key. The OpenAPI sample uses an array:
{ "type": "authenticate", "payload": { "apikey": ["<api-key>"] } }This is not HMAC. HMAC is only for REST (and for fetching a JWT in option 1).
Connect example (browser)
Replace jwt or apikey.
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
const jwt = "ACCESS_TOKEN"; // accessToken.token from POST /v1/signin/apikey
const apikey = "API_KEY"; // public key, if you authenticate with apikey instead
const ws = new WebSocket("wss://ws.bit2me.com/v1");
ws.addEventListener("error", (err) => {
console.error("websocket error:", err);
});
ws.addEventListener("open", () => {
console.debug("websocket connected");
// JWT
ws.send(JSON.stringify({ type: "authenticate", payload: { token: jwt } }));
// or API key (do not send both)
// ws.send(JSON.stringify({ type: "authenticate", payload: { apikey: [apikey] } }));
});
ws.addEventListener("message", (message) => {
const msg = JSON.parse(message.data);
console.debug(`websocket message: type: ${msg.type}, id: ${msg.id}, time: ${msg.time}`);
});
ws.addEventListener("close", (evt) => {
if (evt.code === 4000) {
console.log(`Error while authenticating: ${evt.code}/${evt.reason}`);
} else if (evt.code === 4001) {
console.log(`Error rate limit: ${evt.code}/${evt.reason}`);
}
// reconnect with backoff
});
</script>
</head>
<body></body>
</html>Connect example (Node.js)
const WebSocket = require("ws");
const jwt = process.env.BIT2ME_ACCESS_TOKEN; // accessToken.token
const ws = new WebSocket("wss://ws.bit2me.com/v1");
ws.on("error", (err) => {
console.error("websocket error:", err);
});
ws.on("open", () => {
console.debug("websocket connected");
ws.send(JSON.stringify({ type: "authenticate", payload: { token: jwt } }));
});
ws.on("message", (data) => {
const msg = JSON.parse(data.toString());
console.debug(`type: ${msg.type}, id: ${msg.id}, time: ${msg.time}`, msg.payload);
});
ws.on("close", (code, reason) => {
if (code === 4000) {
console.log(`Error while authenticating: ${code}/${reason}`);
} else if (code === 4001) {
console.log(`Error rate limit: ${code}/${reason}`);
}
});Limits (same family as HTTP)
| Condition | Result |
|---|---|
| More than 50 concurrent connections from one IP | Handshake 429 |
| More than 50 messages per second on one connection | Close 4001 |
Reconnect
Implement on disconnect: reconnect with backoff. Authenticate again after every new open. Check status.bit2me.com if reconnect loops during an incident.
Message envelope
Every notification has the same shape:
{
"channel": "notification",
"id": "string",
"time": 0,
"type": "wallet-transaction-v1",
"payload": {}
}payload depends on type. The notification channel is the public contract. Do not treat internal as a stable API.
Event catalog: Notification events.
Explorer sample (not the notification socket)
The OpenAPI also shows a BTC testnet explorer snippet. That path is not the account notification stream:
const ws = new WebSocket(`wss://${host}:${port}/v1/explorer/BTCTEST`);
ws.addEventListener("open", () => {
ws.send(JSON.stringify(["subscribe", "inv"]));
});
ws.addEventListener("message", (message) => {
const msg = JSON.parse(message.data);
if (msg[0] === "tx") {
console.debug("explorer tx:", msg[1]);
}
});Close 4002 on that sample means a wrong crypto explorer. Do not use this URL to receive wallet-transaction-v1 or KYC events.
Get order by ID GET
Returns one of your brokerage orders, wrapped in an `order` property. Use it to follow an order after `POST /v1/brokerage/draft/approve` until `status` reaches its final value. Orders of other users are reported as not found.
Notification events
Gateway WebSocket types from the public Crypto OpenAPI.