Complete IBKR Flow Example

This is a complete, production-ready example showing the entire IBKR integration flow: authentication, session management, order preview, placement, and status checking.

Architecture

The example follows this flow:

1. Generate PiTrade JWT Token
2. Request Bearer Token from PiTrade
3. Initialize IBKR Session
4. Validate & Maintain Session
5. Preview Order (what-if)
6. Place Actual Order
7. Check Order Status

Code Example

Below is a complete Node.js script that demonstrates the entire flow:

const jwt = require("jsonwebtoken");

// ============= GLOBAL CONSTANTS =============
const CONSTANTS = {
  // Interactive Brokers API endpoints
  IBKR_BASE_URL: "https://api.ibkr.com",
  PLACE_ORDER_ENDPOINT: "/v1/api/iserver/account",

  // PiTrade Partner API
  BEARER_TOKEN_API_URL: "https://api.pitrade.com/partner/brokerage-bearer-token",
  USER_IP: "USER_IP_V4_ADDRESS",

  // Session endpoints
  SSODH_INIT_ENDPOINT: "/v1/api/iserver/auth/ssodh/init",
  TICKLE_ENDPOINT: "/v1/api/tickle",
  VALIDATE_SESSION_ENDPOINT: "/v1/api/sso/validate",
  AUTH_STATUS_ENDPOINT: "/v1/api/iserver/auth/status",
  SUPPRESS_MESSAGES_ENDPOINT: "/v1/api/iserver/questions/suppress",
  SESSION_SETTLE_MS: 5000,

  // Order settings
  ORDER_TYPE: "MKT", // MKT or LMT
  TIF: "DAY", // Time in force
  OUTSIDE_RTH: false, // Outside regular trading hours

  // Test data
  TEST_ACCOUNT_ID: "<TEST_ACCOUNT_ID>",
  TEST_CONID: 265598, // AAPL
  TEST_TICKER: "AAPL",
  PARTNER: "<PARTNER_ID>",
  PARTNER_API_KEY: "<PARTNER_API_KEY>",
};

function generateToken(clientId, apiKey) {
  const now = Math.floor(Date.now() / 1000);
  const payload = {
    clientId: clientId,
    iat: now,
    exp: now + 900, // 15 minutes expiration
  };

  return jwt.sign(payload, apiKey);
}

// ============= UTILITY FUNCTIONS =============

async function makeRequest(url, method, bearerToken = null, body = null) {
  const options = {
    method,
    headers: {
      "Content-Type": "application/json",
      "User-Agent": "node/22.x",
      ...(bearerToken && { Authorization: bearerToken }),
    },
    ...(body && { body: JSON.stringify(body) }),
  };

  const response = await fetch(url, options);
  const data = await response.json();

  return {
    statusCode: response.status,
    body: data,
  };
}

// ============= SESSION MANAGER =============

class SessionManager {
  constructor() {
    this.bearerToken = null;
  }

  /**
   * Get bearer token from PiTrade
   * @returns {Promise<string>} Bearer token for IBKR API
   */
  async fetchBearerToken() {
    console.log("🔐 Fetching Bearer Token...");

    try {
      const token = generateToken(CONSTANTS.PARTNER, CONSTANTS.PARTNER_API_KEY);
      const response = await makeRequest(
        CONSTANTS.BEARER_TOKEN_API_URL,
        "POST",
        "Bearer " + token,
        { ip: CONSTANTS.USER_IP },
      );

      if (!response.body || !response.body.bearerToken) {
        throw new Error("No bearer token in response");
      }

      this.bearerToken = response.body.bearerToken;
      console.log(
        "✅ Bearer Token acquired:",
        this.bearerToken.substring(0, 20) + "...",
      );
      return this.bearerToken;
    } catch (error) {
      console.error("❌ Fetch Bearer Token Error:", error.message);
      throw error;
    }
  }

  /**
   * Validate the current session
   * @returns {Promise<boolean>} True if session is valid
   */
  async validateSession() {
    if (!this.bearerToken) {
      console.log("❌ No bearer token available");
      return false;
    }

    console.log("✅ Validating session...");

    try {
      const response = await makeRequest(
        `${CONSTANTS.IBKR_BASE_URL}${CONSTANTS.VALIDATE_SESSION_ENDPOINT}`,
        "GET",
        "Bearer " + this.bearerToken,
      );

      return response.statusCode === 200;
    } catch (error) {
      console.error("❌ Validate Session Error:", error.message);
      return false;
    }
  }

  /**
   * Get authentication status
   * @returns {Promise<Object>} Auth status with authenticated, competing, connected flags
   */
  async getAuthStatus() {
    if (!this.bearerToken) {
      throw new Error("Bearer token not available");
    }

    console.log("✅ Checking authentication status...");

    try {
      const response = await makeRequest(
        `${CONSTANTS.IBKR_BASE_URL}${CONSTANTS.AUTH_STATUS_ENDPOINT}`,
        "GET",
        "Bearer " + this.bearerToken,
      );

      return (
        response.body || {
          authenticated: false,
          competing: false,
          connected: false,
        }
      );
    } catch (error) {
      console.error("❌ Get Auth Status Error:", error.message);
      return {
        authenticated: false,
        competing: false,
        connected: false,
      };
    }
  }

  /**
   * Initialize the brokerage session (ssodh/init)
   * @returns {Promise<Object>} Init response
   */
  async initializeSession() {
    if (!this.bearerToken) {
      throw new Error("Bearer token not available");
    }

    console.log("Initializing brokerage session (ssodh/init)...");

    try {
      const response = await makeRequest(
        `${CONSTANTS.IBKR_BASE_URL}${CONSTANTS.SSODH_INIT_ENDPOINT}`,
        "POST",
        "Bearer " + this.bearerToken,
        { publish: true, compete: true },
      );

      console.log(
        "✅ Session Initialized:",
        JSON.stringify(response.body, null, 2),
      );

      console.log(
        `⏳ Waiting ${CONSTANTS.SESSION_SETTLE_MS}ms for session to settle...`,
      );
      await new Promise((resolve) =>
        setTimeout(resolve, CONSTANTS.SESSION_SETTLE_MS),
      );

      return response.body;
    } catch (error) {
      console.error("❌ Initialize Session Error:", error.message);
      throw error;
    }
  }

  /**
   * Tickle (keep-alive) the session
   * @returns {Promise<string>} Session info
   */
  async tickleSession() {
    if (!this.bearerToken) {
      throw new Error("Bearer token not available");
    }

    console.log("Tickling session (keep-alive)...");

    try {
      const response = await makeRequest(
        `${CONSTANTS.IBKR_BASE_URL}${CONSTANTS.TICKLE_ENDPOINT}`,
        "GET",
        "Bearer " + this.bearerToken,
      );

      console.log("✅ Session Tickled:", response.body?.session || "OK");
      return response.body?.session;
    } catch (error) {
      console.error("❌ Tickle Session Error:", error.message);
      throw error;
    }
  }

  /**
   * Suppress IBKR confirmation messages
   * @returns {Promise<Object>} Suppress response
   */
  async suppressMessages() {
    if (!this.bearerToken) {
      throw new Error("Bearer token not available");
    }
    console.log("Suppressing confirmation messages...");

    try {
      const response = await makeRequest(
        `${CONSTANTS.IBKR_BASE_URL}${CONSTANTS.SUPPRESS_MESSAGES_ENDPOINT}`,
        "POST",
        "Bearer " + this.bearerToken,
        {
          messageIds: [
            "o163",
            "o354",
            "o382",
            "o383",
            "o403",
            "o451",
            "o2136",
            "o2137",
            "o2165",
            "o10082",
            "o10138",
            "o10151",
            "o10152",
            "o10153",
            "o10164",
            "o10223",
            "o10288",
            "o10331",
            "o10332",
            "o10333",
            "o10334",
            "o10335",
            "o10336",
            "p6",
            "p12",
          ],
        },
      );

      console.log("✅ Messages Suppressed");
      return response.body;
    } catch (error) {
      console.error("❌ Suppress Messages Error:", error.message);
      throw error;
    }
  }

  /**
   * Ensure valid session with fallback to new bearer token generation
   */
  async ensureValidSession() {
    console.log(`\nEnsuring Valid Session...\n`);

    try {
      // Step 1: Validate existing session
      if (this.bearerToken && (await this.validateSession())) {
        console.log("✅ Existing bearer token is valid");

        // Step 2: Check authentication status
        const authStatus = await this.getAuthStatus();
        if (authStatus.connected && authStatus.authenticated) {
          console.log("✅ Session authenticated and connected");
          await this.tickleSession();
          return;
        }
      } else {
        await this.fetchBearerToken();
      }

      await this.initializeSession();
      await this.tickleSession();
      await this.suppressMessages();
      console.log("\n✅ Session Ensured with New Bearer Token\n");
    } catch (error) {
      console.error("❌ Ensure Valid Session Error:", error.message);
      throw error;
    }
  }
}

// ============= TRADING FUNCTIONS =============

/**
 * Create a what-if order (validation without execution)
 */
async function create_whatif_order(sessionManager, orderParams) {
  console.log("Creating Preview Order...");

  if (!orderParams) {
    throw new Error("orderParams is required");
  }

  const { orderSide, amount, quantity, price } = orderParams;

  if (!orderSide) {
    throw new Error("orderSide is required");
  }

  const order = {
    conid: CONSTANTS.TEST_CONID,
    orderType: CONSTANTS.ORDER_TYPE,
    side: orderSide,
    tif: CONSTANTS.TIF,
    ticker: CONSTANTS.TEST_TICKER,
    acctId: CONSTANTS.TEST_ACCOUNT_ID,
    ...(orderSide === "BUY" && amount ? { cashQty: amount } : {}),
    ...(orderSide === "SELL" || CONSTANTS.ORDER_TYPE === "LMT"
      ? { quantity }
      : {}),
    outsideRTH: CONSTANTS.OUTSIDE_RTH,
    ...(CONSTANTS.ORDER_TYPE === "LMT" && price ? { price } : {}),
  };

  const payload = {
    orders: [order],
    outsideRegularHours: CONSTANTS.OUTSIDE_RTH,
  };

  console.log("Preview Order Payload:", JSON.stringify(payload, null, 2));

  try {
    const response = await makeRequest(
      `${CONSTANTS.IBKR_BASE_URL}${CONSTANTS.PLACE_ORDER_ENDPOINT}/${CONSTANTS.TEST_ACCOUNT_ID}/orders/whatif`,
      "POST",
      "Bearer " + sessionManager.bearerToken,
      payload,
    );

    if (!response.body) {
      throw new Error("No response body");
    }

    if (response.statusCode !== 200) {
      throw new Error(`Status ${response.statusCode}`);
    }

    console.log(
      "✅ Preview Order Response:",
      JSON.stringify(response.body, null, 2),
    );
    return response.body;
  } catch (error) {
    console.error("❌ Preview Order Error:", error.message);
    throw error;
  }
}

/**
 * Create and place an actual order
 */
async function create_order(sessionManager, orderParams) {
  console.log("Creating Order...");

  if (!orderParams) {
    throw new Error("orderParams is required");
  }

  const { orderSide, amount, quantity, price } = orderParams;

  if (!orderSide) {
    throw new Error("orderSide is required");
  }

  const order = {
    conid: CONSTANTS.TEST_CONID,
    orderType: CONSTANTS.ORDER_TYPE,
    side: orderSide,
    tif: CONSTANTS.TIF,
    ticker: CONSTANTS.TEST_TICKER,
    acctId: CONSTANTS.TEST_ACCOUNT_ID,
    ...(orderSide === "BUY" && amount ? { cashQty: amount } : {}),
    ...(orderSide === "SELL" || CONSTANTS.ORDER_TYPE === "LMT"
      ? { quantity }
      : {}),
    outsideRTH: CONSTANTS.OUTSIDE_RTH,
    ...(CONSTANTS.ORDER_TYPE === "LMT" && price ? { price } : {}),
  };

  const payload = {
    orders: [order],
    outsideRegularHours: CONSTANTS.OUTSIDE_RTH,
  };

  console.log("Order Payload:", JSON.stringify(payload, null, 2));

  try {
    const response = await makeRequest(
      `${CONSTANTS.IBKR_BASE_URL}${CONSTANTS.PLACE_ORDER_ENDPOINT}/${CONSTANTS.TEST_ACCOUNT_ID}/orders`,
      "POST",
      "Bearer " + sessionManager.bearerToken,
      payload,
    );

    if (!response.body) {
      throw new Error("No response body");
    }

    if (response.statusCode !== 200) {
      throw new Error(`Status ${response.statusCode}`);
    }

    console.log("✅ Order Response:", JSON.stringify(response.body, null, 2));
    return response.body;
  } catch (error) {
    console.error("❌ Order Error:", error.message);
    throw error;
  }
}

/**
 * Get order status
 */
async function get_order_status(sessionManager, orderId) {
  console.log("Fetching Order Status...");

  if (!orderId) {
    throw new Error("Order ID is required");
  }

  console.log(`Checking status for Order ID: ${orderId}`);

  try {
    const response = await makeRequest(
      `${CONSTANTS.IBKR_BASE_URL}/v1/api/iserver/account/order/status/${orderId}`,
      "GET",
      "Bearer " + sessionManager.bearerToken,
    );

    return response.body;
  } catch (error) {
    console.error("❌ Get Order Status Error:", error.message);
    throw error;
  }
}

// ============= MAIN EXECUTION =============

async function main() {
  try {
    const sessionManager = new SessionManager();

    await sessionManager.ensureValidSession();

    // Parse optional parameters
    const orderParams = {
      orderSide: "BUY",
      amount: 2,
      quantity: 1,
      price: null,
    };

    const whatIfResult = await create_whatif_order(sessionManager, orderParams);
    console.log("What-If Result:", whatIfResult);

    // Place actual order
    console.log("\nPlacing Actual Order...\n");
    const orderResult = await create_order(sessionManager, orderParams);
    console.log("Order Result:", orderResult);

    // Get order ID from response
    const orderId = orderResult?.[0].order_id;

    if (orderId) {
      console.log("\n⏳ Waiting 2 seconds before checking order status...\n");
      await new Promise((resolve) => setTimeout(resolve, 2000));

      const orderStatus = await get_order_status(sessionManager, orderId);
      console.log("Order Status:", orderStatus);
    }

    console.log("\n✅ Completed Successfully!\n");
  } catch (error) {
    console.error("❌ Fatal Error:", error);
  }
}

main();

Configuration

Before running, update these constants:

TEST_ACCOUNT_ID: "TEST_ACCOUNT_ID"
PARTNER: "YOUR_PARTNER_ID",
PARTNER_API_KEY: "YOUR_PARTNER_API_KEY",
USER_IP: "YOUR_CLIENT_IP_ADDRESS",
BEARER_TOKEN_API_URL: "https://your-pitrade-api.com/brokerage-bearer-token",

Running the Script

Prerequisites

npm install jsonwebtoken

Execution

node ibkr-trading-flow.js

Output Example

🔐 Fetching Bearer Token...
✅ Bearer Token acquired: U4472-1c88d8c0-9912...

Ensuring Valid Session...

Initializing brokerage session (ssodh/init)...
✅ Session Initialized: {...}

⏳ Waiting 5000ms for session to settle...

Creating Preview Order...
Preview Order Payload: {...}
✅ Preview Order Response: {...}
What-If Result: [...]

Placing Actual Order...
Creating Order...
✅ Order Response: {...}
Order Result: [...]

⏳ Waiting 2 seconds before checking order status...

Fetching Order Status...
✅ Order Status: {...}

✅ Completed Successfully!

Key Features

  • Session Management: Automatic initialization, validation, and recovery
  • Error Handling: Comprehensive error checking at each step
  • Preview Orders: Validate before execution
  • Status Tracking: Monitor order execution
  • Flexible Orders: Support for market, limit, and advanced orders
  • Keep-Alive: Maintains session across multiple operations

Next Steps

  • Integrate into your application
  • Implement retry logic for production
  • Add proper logging and monitoring
  • Handle various order types
  • Implement session persistence

Was this page helpful?