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
Related Documentation
- IBKR Integration Guide - Overview of IBKR flow
- Bearer Token API - Token generation
- IBKR Trading APIs - Trading endpoints
- IBKR Session Management - Session lifecycle