I’m integrating MEXC’s WebSocket stream for Spot Account Orders in a NestJS project. I'm using protobufjs to decode messages from the spot@private.orders.v3.api.pb topic.
Below is the relevant NestJS code I’m using to connect and decode messages:
import { Injectable, OnModuleInit, OnModuleDestroy, Logger } from '@nestjs/common';
import { MexcService } from 'src/services/mexc.service';
import * as WebSocket from 'ws';
import * as protobuf from 'protobufjs';
let PrivateOrdersV3Api: protobuf.Type;
protobuf.load('proto/PrivateOrdersV3Api.proto').then((root) => {
PrivateOrdersV3Api = root.lookupType('PrivateOrdersV3Api');
});
@Injectable()
export class StreamService implements OnModuleInit, OnModuleDestroy {
private readonly logger = new Logger(StreamService.name);
private listenKey: string;
private ws: WebSocket;
private renewInterval: NodeJS.Timeout;
constructor(
private readonly mexcService: MexcService,
) {
this.mexcService = mexcService
}
async onModuleInit() {
this.logger.log('Initializing MEXC WebSocket...');
await this.connectWebSocket();
}
async onModuleDestroy() {
this.logger.warn('Cleaning up MEXC WebSocket...');
if (this.ws) this.ws.terminate();
clearInterval(this.renewInterval);
await this.mexcService.closeListenKey()
}
private async connectWebSocket() {
try {
const { listenKey } = await this.mexcService.createListenKey();
this.listenKey = listenKey
this.logger.log(`🔑 listenKey: ${this.listenKey}`);
this.ws = new WebSocket(`wss://wbs-api.mexc.com/ws?listenKey=${this.listenKey}`);
this.ws.on('open', async () => {
this.logger.log('✅ WebSocket connected');
const payload = {
method: 'SUBSCRIPTION',
"params": [
"spot@private.orders.v3.api.pb"
]
};
this.ws.send(JSON.stringify(payload));
await this.mexcService.keepListenKey()
});
this.ws.on('message', (data) => {
try {
const decode = PrivateOrdersV3Api.decode(data);
const decodeObj = PrivateOrdersV3Api.toObject(decode);
console.log('🌐 Decode:',decode, decodeObj);
} catch (err) {
console.error(data)
this.logger.error('❌ Message error:', err.message);
}
});
this.ws.on('error', (err) => {
this.logger.error('❌ WebSocket error:', err.message);
this.reconnect();
});
this.ws.on('close', () => {
this.logger.warn('🔌 WebSocket closed');
this.reconnect();
});
// Renew listenKey every 30 minutes
clearInterval(this.renewInterval);
this.renewInterval = setInterval(() => this.mexcService.keepListenKey(), 1000 * 60 * 60);
} catch (err) {
this.logger.error('❌ Failed to connect WebSocket', err.message);
setTimeout(() => this.connectWebSocket(), 5000);
}
}
private async reconnect() {
this.logger.warn('🔁 Reconnecting WebSocket...');
if (this.ws) {
this.ws.removeAllListeners();
this.ws.terminate();
this.ws = null;
}
clearInterval(this.renewInterval);
await this.mexcService.closeListenKey()
await this.connectWebSocket();
}
}
The .proto file I'm using is named PrivateOrdersV3Api.proto and contains the following definition:
// spot@private.orders.v3.api.pb
syntax = "proto3";
option java_package = "com.mxc.push.common.protobuf";
option optimize_for = SPEED;
option java_multiple_files = true;
option java_outer_classname = "PrivateOrdersV3ApiProto";
message PrivateOrdersV3Api {
string id = 1;
string clientId = 2;
string price = 3;
string quantity = 4;
string amount = 5;
string avgPrice = 6;
int32 orderType = 7;
int32 tradeType = 8;
bool isMaker = 9;
string remainAmount = 10;
string remainQuantity= 11;
optional string lastDealQuantity = 12;
string cumulativeQuantity = 13;
string cumulativeAmount = 14;
int32 status = 15;
int64 createTime = 16;
optional string market = 17;
optional int32 triggerType = 18;
optional string triggerPrice= 19;
optional int32 state = 20;
optional string ocoId = 21;
optional string routeFactor = 22;
optional string symbolId = 23;
optional string marketId = 24;
optional string marketCurrencyId = 25;
optional string currencyId = 26;
}
❗️Issues Encountered

WebSocket connection closes after a few minutes :
→ Possibly due to listenKey expiration or incorrect keep-alive handling.
Protobuf decoding returns invalid or malformed data
Example decoded output:
🌐 Decode: PrivateOrdersV3Api {
status: 34,
cumulativeQuantity: '":0,"code":0,"msg":"spot@private.orders.v3.api.pb"}'
} {
cumulativeQuantity: '":0,"code":0,"msg":"spot@private.orders.v3.api.pb"}',
status: 34
}
→ It seems the incoming message is not a valid protobuf buffer, or perhaps there is an outer wrapper message structure that I’m missing.
I’m integrating MEXC’s WebSocket stream for Spot Account Orders in a NestJS project. I'm using protobufjs to decode messages from the spot@private.orders.v3.api.pb topic.
Below is the relevant NestJS code I’m using to connect and decode messages:
The .proto file I'm using is named PrivateOrdersV3Api.proto and contains the following definition:
❗️Issues Encountered
WebSocket connection closes after a few minutes :
→ Possibly due to listenKey expiration or incorrect keep-alive handling.
Protobuf decoding returns invalid or malformed data
Example decoded output:
→ It seems the incoming message is not a valid protobuf buffer, or perhaps there is an outer wrapper message structure that I’m missing.