The py3cw library likely follows this logic (based on community reports and reverse-engineering the source):
Send the POST /v2/smart_trades request.
Receive 204 No Content response.
Immediately fetch the latest trades using:
GET /v2/smart_trades?account_id=XXX&limit=1
or
GET /v2/smart_trades?account_id=XXX&pair=YYY
Optionally filter by status=created or check timestamps to get the most recent.
The trade ID is then extracted from that result.
Recommended Solution in Your Node.js Code
After receiving the 204, immediately fetch the latest smart trades and extract the newest one:
const axios = require('axios');
const crypto = require('crypto');
class ThreeCommasClient {
  constructor(apiKey, apiSecret) {
    this.apiKey = apiKey;
    this.apiSecret = apiSecret;
    this.baseUrl = 'https://api.3commas.io/v2';
  }
  _generateSignature(timestamp, path, data = '') {
    return crypto
      .createHmac('sha256', this.apiSecret)
      .update(timestamp + path + data)
      .digest('hex');
  }
  _buildPath(entity, actionId = null, subId = null) {
    let path = `/${entity}`;
    if (actionId) path += `/${actionId}`;
    if (subId) path += `/${subId}`;
    return path;
  }
  async _sendRequest(method, path, payload = null, query = '') {
    const timestamp = Date.now().toString();
    const dataStr = payload ? JSON.stringify(payload) : '';
    const fullPath = path + query;
    const signature = this._generateSignature(timestamp, fullPath, dataStr);
    try {
      const response = await axios({
        method,
        url: `${this.baseUrl}${path}${query}`,
        headers: {
          'APIKEY': this.apiKey,
          'Signature': signature,
          'Nonce': timestamp,
          'Content-Type': 'application/json'
        },
        ...(payload && ['POST', 'PUT'].includes(method) && { data: dataStr }),
        validateStatus: status => status === 204 || status < 400
      });
      return [null, response.status === 204 ? null : response.data];
    } catch (error) {
      const message = error.response?.data || error.message;
      return [{ error: true, msg: message }, {}];
    }
  }
  async request(entity, action, actionId = null, subId = null, payload = null) {
    const path = this._buildPath(entity, actionId, subId);
    // Special case: smart_trades new (204 response handling)
    if (entity === 'smart_trades' && action === 'new') {
      const [postErr] = await this._sendRequest('POST', path, payload);
      if (postErr) return [postErr, {}];
      // Immediately fetch the latest smart trade to get the ID
      const query = `?account_id=${payload.account_id}&limit=1`;
      const [getErr, getData] = await this._sendRequest('GET', '/smart_trades', null, query);
      if (getErr) return [getErr, {}];
      return getData?.length ? [null, getData[0]] : [null, { success: true, message: 'Trade created, but ID not retrieved' }];
    }
    // Generic handler
    const methodMap = {
      get: 'GET',
      post: 'POST',
      put: 'PUT',
      delete: 'DELETE',
      new: 'POST',
      update: 'PUT'
    };
    const method = methodMap[action.toLowerCase()] || 'GET';
    return this._sendRequest(method, path, payload);
  }
}
// Usage Example
const client = new ThreeCommasClient('my_api_key', 'my_api_secret');
async function createSmartTrade() {
  const payload = {
    account_id: 12345678,
    pair: 'ADA_USDT',
    instant: true,
    position: {
      type: 'buy',
      units: { value: '10' },
      order_type: 'market'
    },
    take_profit: { enabled: false },
    stop_loss: { enabled: false },
    demo: true
  };
  const [error, data] = await client.request('smart_trades', 'new', null, null, payload);
  if (error) {
    console.error('❌ Failed to create smart trade:', error.msg);
  } else {
    console.log('✅ Smart trade created:', data);
  }
}
Optional Improvement: Add Retry with Delay
Since the trade may take a few hundred milliseconds to appear, you can add a short retry delay loop (e.g., check up to 3 times with 500ms intervals) if your app needs better reliability.
Answers to Your Specific Questions
1. How does
py3cwget the trade ID when the API returns a 204?
By immediately querying/v2/smart_tradesfor the most recent trade.
2. Is there a way to get the trade ID immediately in Node.js?
Yes — use the same workaround: fetch latest smart trade after 204 response.
3. Are there special headers or parameters I should be including?
No extra headers required beyond what's already there. Just make the follow-up GET request.
4. Is there an alternative endpoint or approach?
Not really. 3Commas chose 204 for smart trade creation. The only workaround is fetching the most recent trade from/v2/smart_trades.