Close Navigation

Trading Web API

Introduction

Interactive Brokers (IBKR) RESTful Web API is designed to provide users with seamless, secure, and real-time access to their IBKR account. The Web API runs parallel to the IBKR hosted application, providing users with scalable, and efficient access to essential services. Our API is split into two key components:

  • Account Management: Provides solution for Introducing Brokers and Financial Advisors to preserve their current user experience and interface design while relying on IBKR’s brokerage services. Advisors and brokers can integrate with the Account Management API to manage Client Registration, Client Account Maintenance, User Authentication, Funding, and Reporting.
  • Trading: Our trading API is available to all IBKR clients free of cost and can be used to manage trades, view real-time portfolio information, access market data, view contract information, and authenticate for brokerage sessions.

Connectivity

IBKR’s Web API implementation follows standard HTTP verbs for communication. It employs a range of HTTP status codes and JSON-formatted messages to convey operation status and error information. To ensure secure communication, all API requests must use HTTPS. Authorization and Authentication for IBKR’s Web API is managed using OAuth 2.0.

Authentication

IBKR only supports private_key_jwt client authentication as described in RFC 7521 and RFC 7523.

  • Client authenticates against the authorization server by presenting a signed JWT token called a client_assertion which the authorization server validates against the public key(s) provided by the client during registration.
  • This scheme is considered safer than the standard client id/client secret authentication scheme used in early OAuth 2.0 integrations given that it prevents the client from having to pass the client secret in back-end requests.

Data Transmission

User requests will be sent to IBKR in JSON format using HTTPS.

References

We know that great documentation makes all the difference. In addition to IBKR’s dedicated API Integration team, IBKR provides documentation for both the developer AND project managers.

  • Documentation: Within our long form documentation we include best practices, flow charts, and descriptions to help users maximize the API’s potential.
  • Reference: Our API reference includes detailed endpoint references, schema requirements, authentication guides, and sample request and responses.

Getting Started

Retail

For retail and individual clients, Authentication to our WebAPI is managed using the Client Portal Gateway, a small java program used to route local web requests with appropriate authentication. Click here to get started.

Institutional or Third Party

We understand that enterprise integrations can be more complex. We have a designated API Solutions team that will help in creating solution that aligns with your business objectives. To get started, please contact our API Solutions (e-mail: api-solutions@interactivebrokers.com) with the following information:

  • Firm Name
  • Firm Type (ie. Introducing Broker, Financial Advisor OR Third Party Service Provider)
  • API Services which you are interested in using (ie. Registration, Funding, Single Sign On, View Portfolio Data, Trading, Reporting)
  • Describe intended usage (1-2 sentences)

Feedback

Have feedback on our Web API documentation or reference material?

Email us at API-Feedback@interactivebrokers.com.

We value your suggestions, ideas, and feedback in order to continuously improve our API solutions.

This is an automated feedback inbox and unfortunately, we will not be actively responding from this email. However, if you need a specific answer or additional support, please contact our API Support team or access our general support. Current or prospective institutional clients may also contact their sales representative.

Introduction

Interactive Brokers is merging our web-based API products into a single, comprehensive IBKR Web API, bringing the features of the Client Portal Web API, Digital Account Management, and the Flex Web Service together in a unified interface, accessible by a shared means of authorization and authentication: OAuth 2.0.

Existing endpoints and authentication schemes are not deprecated and will continue to receive features and updates. Rather, we look forward to providing our clients with a new, coordinated set of endpoints exposing the same backend resources. To support this orchestration, the documentation below addresses the functionality of the Client Portal Web API, Digital Account Management, and the Flex Web Service side by side under the Web API umbrella.

Additionally, we have reorganized our development resources into two sections:

  • Documentation: Long-form, workflow-oriented material located on this page.

  • Reference: Per-endpoint API definitions, presented in a Swagger interface. We apologize that not all endpoints in our Web API are currently included in this Reference. We are working to expand its contents, and they will be available shortly.

Feedback

Have feedback on our Web API documentation or reference material?

Email us at API-Feedback@interactivebrokers.com.

We value your suggestions, ideas, and feedback in order to continuously improve our API solutions.

This is an automated feedback inbox and unfortunately, we will not be actively responding from this email. However, if you need a specific answer or additional support, please contact our API Support team or access our general support. Current or prospective institutional clients may also contact their sales representative.

Getting Started

Clients with fully open and funded accounts may use our Web API to interact with their accounts immediately, without any onboarding or approval process.

However, our Web API offers several methods of authentication, some of which do require approval or configuration prior to use.

Additionally, certain sets of features of the Web API, such as Account Registration and Funds and Banking, are not available to all account types and also require configuration by our Sales Engineering team prior to use.

Web API Access for Organizations

Enterprise and Institutional clients have several methods of authorization and authentication at their disposal. All methods permit requests to be made directly to Interactive Brokers' infrastructure.

Please also note that our Web API consists of two broad feature sets, Trading and Account Management. While the Trading functionality is available to all accountholders, certain Account Management features may not be applicable or available to a given account structure, and they require require approval and onboarding before use.

Please contact your Sales Representative for an introduction to this onboarding process.

The list below outlines the general suitability of the available methods for various use-cases. For a more thorough discussion of these access methods, please contact our API Integrations team.

  • OAuth2.0 (beta)
    • Supports first-party (accessing one's own accounts) and third-party (accessing the accounts of unaffiliated IB clients with their authorization) usage
    • Offers access to account management and trading features
  • OAuth1.0a
    • Supports first-party (accessing one's own accounts) and third-party (accessing the accounts of unaffiliated IB clients with their authorization) usage
    • Offers access to trading features only
  • SSO
    • Available to Financial Advisors and Introducing Brokers
    • Supports the development of alternative UIs specifically for clients under your management
    • Offers access to account management and trading features

Web API Access for Individuals

Web API usage for individual clients involves an IBKR username and password.

Whether accessing a live account or its associated simulated paper account, the live account must be fully open and funded. The live account must also be of the "IBKR Pro" type.

If you do not already have an account, you can create one for free.

Web API Access for Third Parties

Interactive Brokers identifies third-party developers as vendors of software that would interact with IB client accounts to which the vendor has no formal relationship or access within IB. This is in contrast to an advisor or introducing broker who maintains an account structure with IB and formally manages client accounts.

Third-party vendors may currently only seek approval for the use of OAuth1.0a.

Third-party vendors must be receive Compliance approval for their product offerings before integration can proceed.

The third-party approval process begins with our third-party onboarding form, which can be submitted to webapionboarding@interactivebrokers.com. Please note that vendors are expected to have an established business entity and a public presence online with material describing their offering. Proof of concept builds to demonstrate intended functionality are strongly encouraged as well. The onboarding process typically proceeds as follows:

  1. Our onboarding team conducts the initial screening. Estimated time to complete this step is 2-3 weeks. If our onboarding team is able to proceed with your request for approval, they will send your application to our Compliance team for review.
  2. IBKR Compliance conducts an enhanced due diligence review on all third-party applicants, followed by a three-tier approval process. Estimated time to complete Compliance-related reviews and tasks is 3-6 weeks.
  3. If Compliance grants approval, our Legal team will generate a Web API agreement which will be relayed to you for review and signature. In parallel, our third-party onboarding team will ask you to provide public keys and a callback URL in support of the configuration of your OAuth1.0a consumer. Detailed instructions for this process will be provided once this stage is reached. Estimated time for IB complete our portions of the aforementioned process is 3-5 weeks.

The above timelines are estimates and can vary. We recommend providing as much information as possible up front. Not doing so can extend timelines.

During the enhanced due diligence reviews conducted by our Compliance teams, they will expect vendors to have a completed website with finalized details of the product offering. This typically includes a clear user workflow for all components and descriptions of their functionality and capabilities.

Should Compliance approval be reached for your product offering, any significant changes to the offering following approved (such as the addition of trading functionality) would require additional review and approval from our Compliance teams before being offered to IBKR clients.

Please be aware we expect third-party vendors offering automated trading solutions to hold applicable registration with financial authorities in all regions they plan to service, unless the vendor is able to provide support (i.e., a legal opinion) as to why the proposed service would not require registration in a given location. Additionally, the offering will need to be reviewed and approved by Compliance teams in all regions in which you intend to serve IBKR clients.

Usage and Support

Contacting API Support

Interactive Brokers always welcomes users to contact customer support in the event of API behavior issues. To help expedite the troubleshooting process for customers, it is encouraged to first consider the following:

  • Does this issue persist in other platforms? Am I receiving errors with an order even when performing the same action in Trader Workstation rather than through the API?
  • Did the request match the Required parameters from the documentation?
  • Were documentation or guides consulted on the matter prior?
  • How long has this issue been going on? Is the error on the first attempt, or has this request been working for days prior?
  • Do other, similar requests work as expected?

Interactive Brokers offers several contact methods based on your needs. The buttons below link directly to the associated channels.

Scheduled Server Maintenance

Interactive Brokers conducts scheduled maintenance on the infrastructure that serves the Web API. During maintenance windows, some features of the Web API are momentarily unavailable.

The timing of the Web API's maintenance windows vary slightly from the those observed in other platforms, such as Trader Workstation.

The Web API itself is accessible 24 hours a day during the week. It receives maintenance only on Saturday evenings.

Brokerage functionality (provided by /iserver endpoints) is briefly unavailable each evening at approximately 0100 local time by region.

Weekday IServer Reset Timing

| Region | Maintenance Onset | | :---------- | :--------- | | North America
(NY and Chicago) | 01:00 US/Eastern | | Europe | 01:00 CEST | | Asia | 01:00 HKT |

Pacing Limitations

Interactive Brokers currently enforces a global request rate limit of 10 requests per second for each authenticated username -- that is, each Web API session.

Users making requests via the CP Gateway tool are restricted to 10 requests per second.

Additionally, some endpoints are also subject to their own pacing limits as described in the table below.

When a rate limit is exceeded, the Web API will return a 429 Too Many Requests status code.

Violator IP addresses may be put in a penalty box for 10 minutes. After this period, the IP address is removed from the penalty box. Repeat violator IP addresses may be permanently blocked until the issue is resolved.

Per-Endpoint Request Rate Limits

| Endpoint | Method | Limit | | :---------------------------------- | :----: | :-------------------- | | /iserver/marketdata/snapshot | GET | 10 req/s | | /iserver/scanner/params | GET | 1 req/15 mins | | /iserver/scanner/run | POST | 1 req/sec | | /iserver/trades | GET | 1 req/5 secs | | /iserver/orders | GET | 1 req/5 secs | | /iserver/account/pnl/partitioned | GET | 1 req/5 secs | | /portfolio/accounts | GET | 1 req/5 secs | | /portfolio/subaccounts | GET | 1 req/5 secs | | /pa/performance | POST | 1 req/15 mins | | /pa/summary | POST | 1 req/15 mins | | /pa/transactions | POST | 1 req/15 mins | | /pa/allocation | POST | 1 req/15 mins | | /fyi/unreadnumber | GET | 1 req/sec | | /fyi/settings | GET | 1 req/sec | | /fyi/settings/{typecode} | POST | 1 req/sec | | /fyi/disclaimer/{typecode} | GET | 1 req/sec | | /fyi/disclaimer/{typecode} | PUT | 1 req/sec | | /fyi/deliveryoptions | GET | 1 req/sec | | /fyi/deliveryoptions/email | PUT | 1 req/sec | | /fyi/deliveryoptions/device | POST | 1 req/sec | | /fyi/deliveryoptions/{deviceId} | DELETE | 1 req/sec | | /fyi/notifications | GET | 1 req/sec | | /fyi/notifications/more | GET | 1 req/sec | | /fyi/notifications/{notificationId} | PUT | 1 req/sec | | /tickle | GET | 1 req/sec | | /sso/validate | GET | 1 req/min |

Additional Usage Limits

| Endpoint | Method | Limit | | :---------------------------------- | :----: | :-------------------- | | /trsv/secdef | POST | 200 conids/request | | /iserver/marketdata/history | GET | 5 concurrent requests |

Sessions in the Web API

Access to Trading functionality in the Web API entails the creation of a trading-enabled brokerage session.

A brokerage session is associated with an IB username (your credentials), which in turn has trading permissions for one or more accounts (the actual pools of equity).

A single username can only have one brokerage session active at a time across all IB platforms.

Permissions for trading in general, for specific asset classes, market data subscriptions (and thus access to the subscribed feeds), etc. are carried by IB usernames, not the underlying accounts. Hence references to brokerage sessions refer to a logged-in username that is in contact with IBKR's backend trading infrastructure.

Though Interactive Brokers permits a username only one brokerage session at any given time, some of the Web API's Trading functionality is accessible without a brokerage session. This allows a username's active brokerage session to continue elsewhere undisturbed.

We typically refer to these non-brokerage features as the "read-only" subset of the Trading portion of the Web API. Examples of read-only features include retrieval of portfolio data and certain instrument search tools. When trading with the Web API, sessions can therefore be thought of as two-tiered:

  1. An "outer" prerequisite read-only session that is required to be active/valid in order to make any CP Web API request, though by itself it only permits access to non-/iserver endpoints.
  2. The brokerage session, established after the read-only, that permits access to trading, consumption of market data, and all other functionality behind /iserver endpoints.

Session Status Indicators

The Web API provides several status flags to indicate the current state of your session:

  • 'connected': Indicates physical connection to the underlying brokerage infrastructure
  • 'authenticated': Set to 'true' when initial authentication passes, but the session may not yet be fully initialized (accounts may not be loaded)
  • 'established': Set to 'true' when the final login message is received from underlying brokerage infrastructure, indicating the session is authenticated and fully initialized with account information loaded
  • 'competing': Indicates whether another session is competing for the same username

Instrument Discovery

Documentation coming soon.

Market Data

In order to retrieve top-of-book, depth-of-book, or historical market data from the Web API, the following must be available:

  • Username with relevant live market data subscriptions and permission to trade the desired instruments
  • Authorized Web API session
  • Brokerage session (access to IServer endpoints)

Market Data Maximums

Market data lines dictate how much market data can be retrieved simultaneously from a given user. This includes all data pulled through the API.

All users at Interactive Brokers are given 100 market data lines by default.

Increasing Market Data Lines

After the first month of trading, the quantity of market data is allocated using the greater value of:

  • USD monthly commissions divided by 8
  • USD Equity divided by 10,000 (rounded down to the nearest integer)
  • 100

Example 1: In month two, your account shows monthly commissions of $16 and equity of $950,000. Given the calculations above:

  • Commission: $16 / 8 = 2
  • Equity: $950000 / 10,000 = 95

Because either commission or Equity is below the default, the user is permitted 100 market data lines.

Example 2: In month three, your account shows monthly commissions of $500 and equity of $1,245,000. Given the calculations above:

  • Commission: $500 / 8 = 62.5
  • Equity: $1,245,000 / 10,000 = 124.5

While commissions are not yet high enough, the equity allows the user to maintain more than the default at 124 market data lines.

Top-of-Book Snapshots

Top-of-book snapshots deliver up-to-date market data values sourced from the same streams as are displayed in Trader Workstation's watchlists.

Limitations

  • A maximum of 100 conids may be specified at once.
  • A maximum of 50 fields may be specified at once.

The total number of subscribed contracts is limited by the users Market Data Lines.

Assume a scenario where 200 contracts are needed by a user with 100 market data lines. In this scenario, the user must submit the preflight on all contracts after their first 100, and repeat the process for any new contracts to monitor.

The POST /iserver/marketdata/unsubscribe and GET /iserver/marketdata/unsubscribeall should be used to manage undesireable market data subscriptions.

Values needed:

  • Contract ID ("conid") for the desired instrument(s)
  • Tag identifiers for the desired data points ("fields")

A GET request to the /iserver/marketdata/snapshot [ref] endpoint is used to retrieve a snapshot of top-of-book market data for one or more instruments. This endpoint takes two required query parameters:

  • conids: A comma-separated list of instrument conids
  • fields: A comma-separated list of field tags. A comprehensive list of available tags can be found in our Reference material.

In order for the desired data to be available for snapshotting on request, a "pre-flight" request must be made to IServer to begin its consumption of the instrument's live data stream.

This initial request will not deliver any data, but rather makes the stream available for future snapshot requests. Snapshot market data is not cached and is extracted directly from these open streams.

This pre-flight request should include in its fields parameter all of the tags desired in the future:

GET https://api.ibkr.com/v1/api/iserver/marketdata/snapshot?conids=265598,8314&fields=31,7059,84,88,86,85

If this is the first time you've made a /iserver/marketdata/snapshot request for conids 265598 and 8314, you will not receive data in response. Instead you'll see the requested conids returned, indicating that IServer is now streaming data for these instruments.

[
  {
    "conid": 265598,
    "conidEx": "265598"
  },
  {
    "conid": 8314,
    "conidEx": "8314"
  }
]

Once a pre-flight request has been made for a given conid, all requested fields will be delivered with all future responses; future snapshot requests do not need to repeat the desired fields:

GET https://api.ibkr.com/v1/api/iserver/marketdata/snapshot?conids=265598,8314

Returns:

[
  {
    "31": "168.42",
    "6119": "q1",
    "6509": "RpB",
    "7059": "100",
    "84": "168.41",
    "85": "600",
    "86": "168.42",
    "88": "1,300",
    "_updated": 1712596911593,
    "conid": 265598,
    "conidEx": "265598",
    "server_id": "q1"
  },
  {
    "31": "189.60",
    "6119": "q2",
    "6509": "RpB",
    "7059": "100",
    "84": "189.56",
    "85": "500",
    "86": "189.61",
    "88": "200",
    "_updated": 1712596911593,
    "conid": 8314,
    "conidEx": "8314",
    "server_id": "q2"
  }
]

Certain fields that update less frequently, particularly those that are computed on an interval, maybe not be delivered immediately, and instead will be returned when updated.

Streaming Top-of-Book Data

To open a stream for live, top-of-book market data for an instrument, we write a message to the websocket in the following form:

smd+CONID+{"fields":["field_1","field_2",...,"field_n"]}

The values in the fields array are the same field tags used in the HTTP request to /iserver/marketdata/snapshot. These field tag values must be passed as JSON strings, wrapped in double-quotes.

For example, we may send the following message to obtain streaming data for IBM stock, conid 8314.

smd+8314+{"fields":["31","84","85","86","88","7059"]}

If successful, we will begin to receive response messages on websocket in the following format:

{
  "31": "189.60",
  "6119": "q2",
  "6509": "RpB",
  "7059": "100",
  "84": "189.56",
  "85": "500",
  "86": "189.61",
  "88": "200",
  "_updated": 1712596911593,
  "conid": 8314,
  "conidEx": "8314",
  "server_id": "q2",
  "topic": "smd+8314"
}

We may cancel a top-of-book stream on the websocket by sending:

umd+CONID+{}

For example:

umd+8314+{}

Orders

All order-related functionality described below assumes the following are available:

  • Username with relevant relevant trading permissions
  • Authorized Web API session
  • Brokerage session (access to IServer endpoints)
  • Account ID of an account that can receive the order, and for which your username has trading permissions

New Order Example

The following workflow describes the submission of a new order ticket.

Values needed:

  • Contract ID ("conid") for the desired instrument(s)
  • Your desired order handling instructions

A POST request to the /iserver/account/{accountId}/orders endpoint is used to submit a new order ticket to the account referenced by {accountId} in the path. This endpoint takes one required path parameter:

  • accountId: The account ID of the account to which the order will be placed.

This endpoint also requires a JSON body. The specific keys required to successfully submit a given order ticket will vary depending on a variety of factors, including order type. More information on the construction of order tickets can be found on our Order Types page.

However, at a minimum, any new order ticket submitted via the Web API will require in its body:

  • conid: The instrument's conid
  • orderType: The Order Type of the new order ticket
  • side: The side of the order being placed (e.g., "BUY" or "SELL")
  • tif: Time in force, the duration for which the order will work.
  • quantity: A number of units of the instrument

Please consult our Reference Material for a list of all JSON keys available when submitting new order tickets.

Suppose we have trading permissions for account DU123456. We'd like submit a new order to this account to buy 100 shares of AAPL, with a limit price of USD 165, to work for the remainder of today's regular trading hours (an unmodified "day" order).

First we must have obtained IB's conid for AAPL stock, trading in the US in USD, which is 265598. We must also know how to represent our desired handling instructions to the Web API:

  • A buy order is "side":"BUY"
  • A quantity of 100 shares is "quantity":100
  • A limit order is "orderType":"LMT"
  • A limit price of USD 165 is "price":165
  • A day order is "tif":"DAY"
  • And finally, AAPL's conid is "conid":265598

Note that both the keys and values above are case-sensitive.

Care must also be taken to ensure the correct JSON data types are used, as detailed in our Reference Material. We may then construct the following request:

POST https://api.ibkr.com/v1/api/iserver/account/DU123456/orders
[
  {
    "conid": 265598,
    "side": "BUY",
    "orderType": "LMT",
    "price": 165,
    "quantity": 100,
    "tif": "DAY"
  }
]

Note also that the body of this POST request requires a JSON array containing the order ticket object. This array is used to submit order brackets, as detailed below. For now, we will submit only a single order ticket by way of a single object element in this array.

If we are successful in submitting our order, we will receive a response that includes an order_id value that can be used to keep track of the status of the order, as well as an indication of its current status at the time of submission:

{
  "order_id": "987654",
  "order_status": "Submitted",
  "encrypt_message": "1"
}

Order Reply Messages

In some cases the response to an order submission request might not deliver an acknowledgment.

Instead, it might contain an "order reply message" -- essentially a notice -- which must be confirmed via a second request before our order ticket can go to work.

The receipt of such an "order reply message" does not indicate that the order is rejected or otherwise encountered a problem. Rather, IB requires explicit confirmation of some element of the order ticket, or some aspect of our subsequent handling, before we can seek the order's execution.

Very often these messages pertain to precautionary settings that are client-configurable for a given username -- effectively "fat finger" protections that you can adjust or remove if desired:

[
  {
    "id": "07a13a5a-4a48-44a5-bb25-5ab37b79186c",
    "message": [
      "The following order \"BUY 100 AAPL NASDAQ.NMS @ 165.0\" price exceeds \nthe Percentage constraint of 3%.\nAre you sure you want to submit this order?"
    ],
    "isSuppressed": false,
    "messageIds": [
      "o163"
    ]
  }
]

Aside from the content of the message, there are two important values delivered in such an "order reply" response.

First, we have an id, which uniquely identifies the emitted message. Via the /iserver/reply/{messageId} endpoint, we can use this id value to dismiss the message and put our order to work:

POST https://api.ibkr.com/v1/api/iserver/reply/a12b34c5-d678-9e012f-3456-7a890b12cd3e
{
  "confirmed": true
}

The above request requires a JSON body containing {"confirmed":true}, which is an instruction to IB that the message has been received, and you would like to continue with your order.

Provided the order can be accepted and put to work, the response to your /iserver/reply/{messageId} request will be an order acknowledgement response as shown above:

{
  "order_id": "1234567890",
  "order_status": "Submitted",
  "encrypt_message": "1"
}

Another important value (or set of values) to capture from order message response is messageIds, as in "messageIds": ["o163"] above.

These messageIds strings categorize varieties of order reply messages. You can use these IDs to suppress certain types of order reply messages for the remainder of your username's current Web API brokerage session.

Please see the Suppressing Order Reply Messages section for more detail.

Order Reply Suppression

The following response to an order ticket submission indicates that we must confirm some aspect of our order ticket before it will be accepted:

[
  {
    "id": "07a13a5a-4a48-44a5-bb25-5ab37b79186c",
    "message": [
      "The following order \"BUY 100 AAPL NASDAQ.NMS @ 165.0\" price exceeds \nthe Percentage constraint of 3%.\nAre you sure you want to submit this order?"
    ],
    "isSuppressed": false,
    "messageIds": [
      "o163"
    ]
  }
]

We call these messages "order reply messages".

The "messageIds" array contains identifiers that categorize the type of order reply message we've received. In this case, we've received "messageIds": ["o163"].

Certain types of order reply messages may be suppressed for the duration of your username's current Web API brokerage session.

When a category of order reply messages is suppressed, you will no longer be sent order reply message responses requiring confirmation. Instead, a valid order ticket will be accepted and acknowledged immediately. Invalid order tickets will be rejected.

The /iserver/questions/suppress endpoint provides this suppression mechanism. You may POST an array of messageIDs to suppress those order message types for the remainder of the Web API brokerage session:

POST https://api.ibkr.com/v1/api/iserver/questions/suppress
{
  "messageIds": [
    "o163"
  ]
}

The response will confirm their suppression:

{
  "status": "submitted"
}

You do not need to have received a given messageID value previously in order to suppress it.

We recommend that you submit this list of messages to be suppressed at the beginning of your brokerage session, prior to conducting any trading.

If you would like to suppress a new type of message while trading, please resend the complete array of messageIds.

You may also undo all suppression of messages within your current brokerage session:

POST https://api.ibkr.com/v1/api/iserver/questions/suppress/reset

And the response will confirm the restoration of delivery of all messages generated during order submission:

{
  "status": "submitted"
}

Order Rejections

Documentation coming soon.

Previewing Orders

Documentation coming soon.

Modifying Orders

The following example describes the submission of a request to modify an existing, unfilled order ticket.

Values needed:

  • All previously submitted order handling instructions, including the instrument's conid
  • The orderId of the order ticket to be modified

A POST request to the /iserver/account/{accountId}/order/{orderId} endpoint is used to submit a request to modify the order ticket referenced by {orderId} in the account {accountId}. This endpoint takes two required path parameters:

  • accountId: The account ID to which the unfilled order belongs.
  • orderId: The orderId of the order ticket to be modified.

This endpoint also requires a JSON body. This JSON body must be a single JSON object (note: not an array) containing all of the attributes and handling instructions of the original order ticket.

All JSON keys from the initial order submission must be present, and all JSON values must also be the same, except for the value(s) you seek to modify.

Note that order modification can be subject to different sets of market rules compared to new order submission. Our /iserver/secdef/rules endpoint can be used to inspect the ruleset enforced on a modification.

Suppose we have an active, unfilled order with orderId 987654 belonging to account DU123456, originally submitted with the following handling instructions:

[
  {
    "conid": 265598,
    "side": "BUY",
    "orderType": "LMT",
    "price": 165,
    "quantity": 100,
    "tif": "DAY"
  }
]

We'd like to change the limit price of this order from 165 to 170. To do so, we send the following request:

POST https://api.ibkr.com/v1/api/iserver/account/DU123456/order/987654
{
  "conid": 265598,
  "side": "BUY",
  "orderType": "LMT",
  "price": 170,
  "quantity": 100,
  "tif": "DAY"
}

Note first that order modification addresses only a single order per request. Therefore, this request does not use a JSON array as a container for the modified order ticket object. Instead, the modified order ticket object is the entirety of the request body.

Additionally, we must ensure that all other attributes of the order ticket, aside from the value being altered, are identical to the current, pre-modification attributes of the existing order ticket.

While it should be sufficient to store the contents of a successfully submitted new order ticket client-side, we may also inspect the contents of an existing order ticket with the Order Status endpoint, /iserver/account/{accountId}/order/status/{orderId}.

A successful order modification will return a response similar to a successful new order submission:

{
  "order_id": "987654",
  "order_status": "Submitted",
  "encrypt_message": "1"
}

Alternatively, we may also receive an order reply message, as described above.

Canceling Orders

Values needed:

  • The orderId of the order ticket to be canceled

A DELETE request to the /iserver/account/{accountId}/order/{orderId} endpoint is used to submit a request cancel the order ticket referenced by {orderId} in the account {accountId}. This endpoint takes two required path parameters:

  • accountId: The account ID to which the unfilled order belongs.
  • orderId: The orderId of the order ticket to be modified.

The DELETE method of this endpoint does not accept any JSON body. To cancel an order with orderId 987654, we send the following request:

DELETE https://api.ibkr.com/v1/api/iserver/account/DU123456/order/987654

A successful request for order cancellation returns a message that our request has been received:

{
    "msg": "Request was submitted",
    "order_id": 987654,
    "conid": 265598,
    "account": "DU123456"
}

Note that the above response indicates our request to cancel order 987654 was received, but not that the order ticket itself has been canceled. It is possible that an order working at an exchange or other external venue cannot be canceled, for instance, as a result of auction-related deadlines.

Submitting Bracket Orders

Documentation coming soon.

Orders for Combos/Spreads

Combo or spread orders may be submitted using the same /iserver/account/{accountId}/orders endpoint described above. In the case of combo orders, we must include the conidex field in our request body instead of conid. The conidex field is a string representation of our combo order's composition.

A combo order's conidex value takes the following form: {spread_conid};;;{leg_conid1}/{ratio},{leg_conid2}/{ratio}

The spread_conid value is a unique identifier associated with the currency in which the combo's legs trade. For US Stock Combos, the spread_conid value will the the USD conid integer by itself. For combo orders in all other currencies, spread_conid takes the form spread_conid@exchange.

Available currency spread conids:

|Currency|Spread ConID| |--- |--- | |AUD|61227077| |CAD|61227082| |CHF|61227087| |CNH|136000441| |GBP|58666491| |HKD|61227072| |INR|136000444| |JPY|61227069| |KRW|136000424| |MXN|136000449| |SEK|136000429| |SGD|426116555| |USD|28812380|

The spread_conid is followed by three semicolons, and then the first leg's leg_conid. Next, a forward slash /, followed by the ratio of the preceding leg.

The ratio value conveys two pieces of information. The first is the side, buy or sell, of the leg, indicated by the sign of the ratio value, positive or negative. A positive ratio integer indicates a Buy, while a negative ratio integer represents a Sell. The second piece of information is the relative size of the leg in the combo, indicated by the integer magnitude itself. This magnitude acts as a multiplier when placing an order for the overall combo instrument.

Additional legs are separated by commas, and follow the same pattern as above: {leg_conid}/{ratio}.

Please be aware that the number of legs permissible in a single combo order varies by exchange.

Combo orders are priced by summing the per-leg prices, taking into account the side of each leg: Combo order price = (Price_Leg1 * Ratio_Leg1) + (Price_Leg2 * Ratio_Leg2) + ... + (Cost_LegN * Ratio_LegN)

Monitoring Live Orders

The /iserver/account/orders endpoint is used to retrieve the status of all recently open orders in a given account. This includes orders currently working as well as those cancelled or filled within the same brokerage session.

Example request:

GET https://api.ibkr.com/v1/api/iserver/account/orders?filters=filled&force=true&accountId=U1234567

Successful response:

{
  "orders": [
    {
      "acct": "U1234567",
      "conidex": "265598",
      "conid": 265598,
      "account": "U1234567",
      "orderId": 1234568790,
      "cashCcy": "USD",
      "sizeAndFills": "5",
      "orderDesc": "Sold 5 Market, GTC",
      "description1": "AAPL",
      "ticker": "AAPL",
      "secType": "STK",
      "listingExchange": "NASDAQ.NMS",
      "remainingQuantity": 0.0,
      "filledQuantity": 5.0,
      "totalSize": 5.0,
      "companyName": "APPLE INC",
      "status": "Filled",
      "order_ccp_status": "Filled",
      "avgPrice": "192.26",
      "origOrderType": "MARKET",
      "supportsTaxOpt": "1",
      "lastExecutionTime": "231211180049",
      "orderType": "Market",
      "bgColor": "#FFFFFF",
      "fgColor": "#000000",
      "order_ref": "Order123",
      "timeInForce": "GTC",
      "lastExecutionTime_r": 1702317649000,
      "side": "SELL"
    }
  ],
  "snapshot": true
}

Monitoring Executions

Documentation coming soon.

Portfolio and Positions

Querying Your Accounts

In non-tiered account structures, the /portfolio/accounts endpoint returns a list of accounts for which the user can view position and account information.

This endpoint must be called prior to calling other /portfolio endpoints for those accounts.

For querying a list of accounts which the user can trade, see /iserver/accounts. For a list of subaccounts in tiered account structures (e.g. financial advisor or ibroker accounts) see /portfolio/subaccounts.

Example request:

GET https://api.ibkr.com/v1/api/portfolio/accounts

Successful response:

[
  {
    "id": "U1234567",
    "PrepaidCrypto-Z": false,
    "PrepaidCrypto-P": false,
    "brokerageAccess": true,
    "accountId": "U1234567",
    "accountVan": "U1234567",
    "accountTitle": "",
    "displayName": "U1234567",
    "accountAlias": null,
    "accountStatus": 1644814800000,
    "currency": "USD",
    "type": "DEMO",
    "tradingType": "PMRGN",
    "businessType": "IB_PROSERVE",
    "ibEntity": "IBLLC-US",
    "faclient": false,
    "clearingStatus": "O",
    "covestor": false,
    "noClientTrading": false,
    "trackVirtualFXPortfolio": true,
    "parent": {
      "mmc": [],
      "accountId": "",
      "isMParent": false,
      "isMChild": false,
      "isMultiplex": false
    },
    "desc": "U1234567"
  }
]

In multi-level account structures (such as Financial Advisor and IBroker accounts), the /portfolio/subaccounts endpoint returns a list of up to 100 subaccounts for which the user can view position and account-related information.

This endpoint must be called prior to calling other /portfolio endpoints for those subaccounts.

If you have more than 100 subaccounts use /portfolio/subaccounts2. To query a list of accounts the user can trade, see /iserver/accounts.

Example request:

GET https://api.ibkr.com/v1/api/portfolio/subaccounts

Successful response:

[
  {
    "id": "U1234567",
    "PrepaidCrypto-Z": false,
    "PrepaidCrypto-P": false,
    "brokerageAccess": false,
    "accountId": "U1234567",
    "accountVan": "U1234567",
    "accountTitle": "",
    "displayName": "U1234567",
    "accountAlias": null,
    "accountStatus": 1644814800000,
    "currency": "USD",
    "type": "DEMO",
    "tradingType": "PMRGN",
    "businessType": "IB_PROSERVE",
    "ibEntity": "IBLLC-US",
    "faclient": false,
    "clearingStatus": "O",
    "covestor": false,
    "noClientTrading": false,
    "trackVirtualFXPortfolio": true,
    "parent": {
      "mmc": [],
      "accountId": "",
      "isMParent": false,
      "isMChild": false,
      "isMultiplex": false
    },
    "desc": "U1234567"
  }
]

Querying Currency Balances

The /portfolio/{accountId}/ledger endpoint delivers information regarding cash balances, organized by currency.

Example request:

GET https://api.ibkr.com/v1/api/portfolio/{accountId}/ledger

Successful response:

{
  "USD": {
    "commoditymarketvalue": 0.0,
    "futuremarketvalue": -1051.0,
    "settledcash": 214716688.0,
    "exchangerate": 1,
    "sessionid": 1,
    "cashbalance": 214716688.0,
    "corporatebondsmarketvalue": 0.0,
    "warrantsmarketvalue": 0.0,
    "netliquidationvalue": 215335840.0,
    "interest": 305569.94,
    "unrealizedpnl": 39695.82,
    "stockmarketvalue": 314123.88,
    "moneyfunds": 0.0,
    "currency": "USD",
    "realizedpnl": 0.0,
    "funds": 0.0,
    "acctcode": "U1234567",
    "issueroptionsmarketvalue": 0.0,
    "key": "LedgerList",
    "timestamp": 1702582321,
    "severity": 0,
    "stockoptionmarketvalue": -2.88,
    "futuresonlypnl": -1051.0,
    "tbondsmarketvalue": 0.0,
    "futureoptionmarketvalue": 0.0,
    "cashbalancefxsegment": 0.0,
    "secondkey": "USD",
    "tbillsmarketvalue": 0.0,
    "endofbundle": 1,
    "dividends": 0.0
  },
  "BASE": {
    "commoditymarketvalue": 0.0,
    "futuremarketvalue": -1051.0,
    "settledcash": 215100080.0,
    "exchangerate": 1,
    "sessionid": 1,
    "cashbalance": 215100080.0,
    "corporatebondsmarketvalue": 0.0,
    "warrantsmarketvalue": 0.0,
    "netliquidationvalue": 215721776.0,
    "interest": 305866.88,
    "unrealizedpnl": 39907.37,
    "stockmarketvalue": 316365.38,
    "moneyfunds": 0.0,
    "currency": "BASE",
    "realizedpnl": 0.0,
    "funds": 0.0,
    "acctcode": "U1234567",
    "issueroptionsmarketvalue": 0.0,
    "key": "LedgerList",
    "timestamp": 1702582321,
    "severity": 0,
    "stockoptionmarketvalue": -2.88,
    "futuresonlypnl": -1051.0,
    "tbondsmarketvalue": 0.0,
    "futureoptionmarketvalue": 0.0,
    "cashbalancefxsegment": 0.0,
    "secondkey": "BASE",
    "tbillsmarketvalue": 0.0,
    "dividends": 0.0
  }
}

Querying Equity and Margin

The /portfolio/{accountId}/summary endpoint delivers a wide variety of values related to an account's equity, margin use, and accrued balances.

Values are presented in aggregate form for the entire U-account ("universal account"), as well as diasaggregated by the account's underlying regulatory segments (for instance, the securities segment versus commodities segment, which holds futures products).

Example request:

GET https://api.ibkr.com/v1/api/portfolio/{accountId}/summary

Successful response:

{
  "accountcode": {
    "amount": 0.0,
    "currency": null,
    "isNull": false,
    "timestamp": 1702582422000,
    "value": "U1234567",
    "severity": 0
  },
  ...,
  "indianstockhaircut": {
    "amount": 0.0,
    "currency": "USD",
    "isNone": false,
    "timestamp": 1702582422000,
    "value": null,
    "severity": 0
  }
}

Advisor Features

Documentation coming soon.

FYIs, Alerts, and Bulletins

Types of Notification Messages

  • FYIs
    • Disclaimers
  • Alerts
    • Mobile Trading Alerts
  • Bulletins

FYIs

Unread FYIs

To get number of un-read notifications/disclaimers next api should be called GET /fyi/unreadnumber which return integer number that can be display to make user aware. For example, let's assume we have 1 un-read and 3 in total notifications/disclaimers.

GET https://api.ibkr.com/v1/api/fyi/unreadnumber

Response:

{
  "BN":  1
}

All Recent FYIs

List of all recent notifications can be retrieved by calling GET /fyi/notifications which will provide list of all notifications. R in response indicate if notification/disclaimer was read or not.

So by using it, corresponding notification can be highlighted to user. Response also contains a title (MS), notification code "fyi code" (FC), unique identifier (ID) and detailed html formatted message (MD).

GET https://api.ibkr.com/v1/api/fyi/notifications

Returns:

[ 
  {
    "R": 0,
    "D": "1710847062.0",
    "MS": "FYI: Changes in Analyst Ratings",
    "MD": "<html>Some investors use analysts ratings to stay informed about their investments. Analysts have changed their ratings for one or more companies in which you hold positions.    <br />The following summary displays the affected companies, the current number of analysts by rating category and, in parentheses, the recent change in the number of analysts rating the company within each rating category.  <br /> - JWN@NYSE: Buy: 1(0), Outperform: 1(0), Hold: 12(-1), Underperform: 5(0), Sell: 0(0). Held in: D****000 <br /> - RF@NYSE: Buy: 4(+1), Outperform: 5(0), Hold: 17(-1), Underperform: 1(0), Sell: 0(0). Held in: D****000 <br /> <br />   Note: Current ratings are from Reuters and may not reflect all rating changes from other sources such as Street Insider and Briefing.</html>",
    "ID": "2024031947509444",
    "HT": 0,
    "FC": "PF"
},
  {
    "R": 1,
    "D": "1710761985.0",
    "MS": "FYI: Changes in Analyst Ratings",
    "MD": "<html>Some investors use analysts ratings to stay informed about their investments. Analysts have changed their ratings for one or more companies in which you hold positions.    <br />The following summary displays the affected companies, the current number of analysts by rating category and, in parentheses, the recent change in the number of analysts rating the company within each rating category.  <br /> - F@NYSE: Buy: 4(0), Outperform: 4(0), Hold: 15(+1), Underperform: 3(-1), Sell: 1(0). Held in: D****000 <br /> - RF@NYSE: Buy: 4(+1), Outperform: 5(0), Hold: 17(-1), Underperform: 1(0), Sell: 0(0). Held in: D****000 <br /> - TSLA@NASDAQ: Buy: 5(0), Outperform: 12(0), Hold: 21(0), Underperform: 7(+1), Sell: 4(0). Held in: D****000 <br /> - UAA@NYSE: Buy: 6(0), Outperform: 2(-1), Hold: 17(+1), Underperform: 2(0), Sell: 0(0). Held in: D****000 <br /> <br />   Note: Current ratings are from Reuters and may not reflect all rating changes from other sources such as Street Insider and Briefing.</html>",
    "ID": "2024031843829868",
    "HT": 0,
    "FC": "PF"
  },
  {
    "R": 1,
    "D": "1710501829.0",
    "MS": "FYI: Changes in Analyst Ratings",
    "MD": "<html>Some investors use analysts ratings to stay informed about their investments. Analysts have changed their ratings for one or more companies in which you hold positions.    <br />The following summary displays the affected companies, the current number of analysts by rating category and, in parentheses, the recent change in the number of analysts rating the company within each rating category.  <br /> - F@NYSE: Buy: 4(0), Outperform: 4(0), Hold: 14(+1), Underperform: 4(0), Sell: 1(0). Held in: D****000 <br /> - UAA@NYSE: Buy: 6(0), Outperform: 3(-1), Hold: 16(-1), Underperform: 2(+1), Sell: 0(0). Held in: D****000 <br /> <br />   Note: Current ratings are from Reuters and may not reflect all rating changes from other sources such as Street Insider and Briefing.</html>",
    "ID": "2024031537589663",
    "HT": 0,
    "FC": "PF"
  }
]

Marking FYIs Read

Specific FYI notifications can be marked as read via PUT /fyi/notifications/{notificationID}. Please note that you can have multiple notifications for the same group (grouped by fyi code)

Managing FYI Subscriptions

GET https://api.ibkr.com/v1/api/fyi/settings
[
  {
    "FC": "PF",
    "H": 0,
    "A": 1,
    "FD": "Notify me of recent activity affecting my portfolio holdings.",
    "FN": "Portfolio FYIs"
  },
  {
    "FC": "PT",
    "H": 0,
    "A": 1,
    "FD": "Notify me of potential account configuration changes needed and useful features based on my position transfers.",
    "FN": "Position Transfer"
  }  
]

FYI Disclaimers

Detailed message for notification must be shown to user only when user accept corresponding disclaimer.

Use GET /fyi/settings to see what disclaimers accepted and what not. H represents fact of disclaimer acceptance. More about fyi settings will be below.

[
  {
    "FC": "PF",
    "H": 0,
    "A": 1,
    "FD": "Notify me of recent activity affecting my portfolio holdings.",
    "FN": "Portfolio FYIs"
  },
  {
    "FC": "PT",
    "H": 0,
    "A": 1,
    "FD": "Notify me of potential account configuration changes needed and useful features based on my position transfers.",
    "FN": "Position Transfer"
  }  
]

Supplemental text for accept disclaimer can be retrieved by calling GET /fyi/disclaimer/{typecode}

{
  "FC": "PF",
  "DT": "This communication is provided for information purposes only and is not intended as a recommendation or a solicitation to buy, sell or hold any investment product. Customers are solely responsible for their own trading decisions."
}

And call PUT /fyi/disclaimer/{typecode} to accept disclaimer. Once disclaimer is acknowledged, it should not be forced on notifications of the same type.

FYI Delivery Options

TBD, This needs to be revisited. We should figure out if we need to should only email delivery option or others too.

Alerts

Creating and Modifying Alerts

Listing Configured Alerts

Retrieving Alert Details

Mobile Trading Alerts

Bulletins

Model Portfolio Invest / Divest / Rebalance API — Integration Guide

Audience: Client developers (Financial Advisor tooling) integrating with IBKR's Model Portfolio Web API.

Scope: This guide explains how the endpoints work together to create a model, invest client accounts into it, execute the resulting trades, and verify the result. It does not repeat field-level schemas — those live in the OpenAPI reference. Where useful, it calls out quirks, sequencing rules, and known issues that are not obvious from the schema alone.

Base URL: https://api.ibkr.com/v1/api/...

Common headers (all FA microservice calls):

Accept: application/json
Content-Type: application/json

Two distinct API surfaces are involved in a full Invest/Divest/Rebalance flow:

| Surface | Path prefix | Responsibility | |---|---|---| | FA Model microservice | /v1/api/fa/... | Model CRUD, target math, presets, computing which shares need to move (as transfers and/or orders) | | IServer trading API | /v1/api/iserver/... | Actually authenticating a trading session and submitting the resulting orders for the "allocation" leg of an invest/divest/rebalance |

Everything the FA microservice returns (transfers, allocations) is a plan. Nothing trades or moves cash until you explicitly (a) submit the cached transfers via /model/submit-transfers, and/or (b) submit orders via the IServer order endpoint.

1. Key Concepts

Before wiring the endpoints together, it helps to understand the domain model:

  • Independent / "Core" — the portion of an account's portfolio that is not allocated to any model. Every account effectively has account.Core plus account.<ModelName> for each model it participates in.
  • Model — a named target allocation (positionTargets + cashTargets, expressed as fractions of NLV, summing to 1.0). Models can be:
    • Dynamic (isStatic:false) — targets are percentages, driftable.
    • Static (isStatic:true) — must be bootstrapped to be recognized as static.
  • Bootstrapped — a model only has a real Model %/NLV once at least one account has invested. Before that, summary/positions return zeros and bootstrapped:false. invest-divest will silently bootstrap a dynamic model as part of handling the request if it isn't already.
  • Target % vs. Actual % (Model %) — Target % is what you want; Actual % (a.k.a. Model %, MI %) is what the model currently holds. instrumentImbalance is the (weighted) delta between them. See §8 for the imbalance formulas.
  • NLV — Net Liquidation Value, always expressed in the base currency of the entity in question (master, account, or model).
  • Full vs. Partial Master — some model actions (Invest/Divest/Rebalance) may be blocked for a partial master. Check with /is-full-master if unsure.
  • Single-currency constraint — a model's positionTargets + cashTargets must all trade/settle in one currency. Mixed-currency target sets are rejected.
  • transfersInstructionId — a server-side cache key. Any endpoint that computes a set of moves (invest-divest, tws-invest-divest, rebalance/*) returns this ID. It is not itself an execution — you must follow up with /model/submit-transfers (for the transfer leg) and/or an IServer order (for the allocation/order leg) to actually make it happen. Re-submitting the same transfersInstructionId is an error.

2. FA Presets — They Change What "Invest" Actually Does

GET/POST /fa-preset/get and /fa-preset/save control how the planning endpoints (invest-divest, tws-invest-divest, rebalance/*) decide to satisfy a target: buy new shares, transfer existing Independent shares into the model, cross trades, etc. Always fetch presets before planning an investment, and set them explicitly if the default behavior isn't what you want.

| Preset | Effect when true | |---|---| | preferTransferFromIndependent | If the account already holds the instrument in its Independent (Core) bucket, transfer those shares into the model instead of generating a BUY order. This is the difference between getting a positionTransfers entry vs. an allocations entry in the invest-divest response. | | closeDivestIndependentPosition | On divest, fully close out any matching Independent position rather than leaving a residual. | | preferCrossWithIndependent | Prefer internal crossing against the account's Independent side over external orders. | | fullyInvestExistingLongPositions | Treat existing long Independent positions as fully investable toward the target. | | avoidNegativeCashInIndependent | Avoid actions that would push Independent cash negative. | | useToleranceRange | Skip generating an allocation for an instrument whose imbalance is within tolerance (≈ target%/100 of target), rather than rebalancing every last share. | | useNonBaseCcy | Allow use of non-base-currency cash balances when funding an investment. | | keepModelOpen | UI/session hint — keep model in an "open" editing state. | | roundAllocationQuantityToExchangeBoardLot | Round share allocations to the exchange's board lot size. |

Workflow implication: In Case 1A, the first invest-divest call (with preferTransferFromIndependent:false) produced a BUY order allocation for CSCO. After flipping the preset to true and re-running the identical invest-divest request, the plan changed to a position transfer for CSCO from Independent into the model. Nothing about the invest-divest request itself changed — only the preset. Always treat presets as sticky, account-level configuration that silently reshapes the output of every subsequent planning call.


3. Endpoint Catalog (grouped by role)

| Category | Endpoint | Purpose | |---|---|---| | Model definition | POST /fa/model/save | Create or update a model's name/description/targets. If the model name exists, it's updated; otherwise created. | | | POST /fa/model/delete | Delete a model and its targets. | | | POST /fa/model/save-ccy | Change a model's base currency. | | Model discovery | POST /fa/model/list | List all models for the master, with lightweight status (bootstrapped, NLV, mismatch, etc.). | | | POST /fa/model/summary | Same lightweight status for a single named model. | | Model insight | POST /fa/model/positions | Per-instrument Target % / Actual % / imbalance / NLV for a model (model-level, not per-account). | | | POST /fa/model/accounts-details | Per-account breakdown (cost basis, NLV, imbalance, unrealized PnL) for accounts invested in a model. 50-account limit; see §9. | | | POST /fa/model/invest-divest-positions | Per-account view used to drive an Invest/Divest screen — shows how much of each account's NLV sits in Independent (position vs. cash), in this model, and in other models. | | | POST /fa/model/imbalance | Aggregate Model Imbalance % per model (computationally expensive; separate call from /model/list). Not supported if numAccounts > 50. | | Preferences | POST /fa/fa-preset/get / POST /fa/fa-preset/save | Read/write the FA presets described in §2. | | Plan an action | POST /fa/model/invest-divest | Compute the transfers/allocations needed to move an account to a target amount/% in one model (CP-style, single model per account per call). | | | POST /fa/model/tws-invest-divest | Same idea, but TWS-style: one account/group/list can target multiple models in a single call, and returns batchNumber to sequence execution. | | | POST /fa/model/rebalance/to-existing-targets | Recompute allocations to bring a model back to its currently saved targets. | | | POST /fa/model/rebalance/to-new-targets | Recompute allocations against a brand-new full target set (targets must sum to 1.0); also persists the new targets to the model, same as /model/save. | | | POST /fa/model/rebalance/to-specific-targets | Same shape as to-new-targets, but scoped to only the contracts you list — no "sum to 1.0" validation. Use this for "rebalance just these 1–2 rows." | | | POST /fa/model/cash-analyzer | Detect/plan cleanup of non-model-currency cash sitting in multi-currency models. | | Execute a plan | POST /fa/model/submit-transfers | Transmit the cash/position transfers cached under a transfersInstructionId to the back office. Does not submit orders. | | | POST /iserver/account/{modelCode}/orders | Submit the actual order(s) for the allocation leg of a plan (see §5). | | Utilities | POST /fa/is-full-master | Determine whether the calling master account is a full or partial master (some actions are blocked for partial masters). |


4. End-to-End Workflow: Invest a Single Account (Long-Only)

This is the reference flow from Case 1A. It composes the endpoints above into six logical phases.

1. Define the model -> 2. Verify creation -> 3. Presets check -> 4. Plan & execute the investment -> 5. Verify result 

Phase 1 — Define the model

POST /fa/model/save with positionTargets (by conid) and cashTargets (by ccy), all fractions summing to 1.0. Example: 45% CSCO / 45% INTC / 10% USD cash reserve.

  • If success:false, inspect error — common causes: mixed currencies among targets, targets not summing to 1.0, or model name reused the same day it was deleted.

Phase 2 — Verify creation

Use /fa/model/summary (single model) and/or /fa/model/list (all models) to confirm the model exists. Immediately after creation the model is not bootstrapped (bootstrapped:false, nlv:"0", numAccounts:0) — this is expected; bootstrapping happens automatically the first time money is invested.

Cross-check the targets landed correctly with /fa/model/positions (sortField:"", limit:-1 to get the full, unsorted list). Before any account has invested, actual will be 0 for every row and target will echo what you saved.

Phase 3 — Check/set FA Presets

Call /fa-preset/get and decide whether the defaults suit this investment. In the reference case, the default preferTransferFromIndependent:false would have generated a BUY order for CSCO even though the account's Independent bucket already held CSCO shares. To transfer those shares into the model instead of buying more, call /fa-preset/save with preferTransferFromIndependent:true.

You may also want /fa/model/invest-divest-positions here — it shows, per account, how much NLV currently sits in Independent positions vs. Independent cash vs. this model vs. other models. This is informational context for deciding how much to invest and whether a transfer-from-Independent makes sense.

Phase 4 — Plan and execute the investment

  1. POST /fa/model/invest-divest with accountList: [{account, amtToInvest}].

    • This is a polling endpoint — see §5. The final response (once subscriptionStatus:1) contains:
      • transfersInstructionId — the cache key for phase 4b/4c.
      • cashTransfers[] — cash moves from Core into the model.
      • positionTransfers[] — share transfers from Independent into the model (only populated when the relevant preset, e.g. preferTransferFromIndependent, causes a transfer instead of a trade).
      • allocations[] — instruments that instead require a new order to be placed (because no preset directed a transfer, or the account didn't hold the shares).
    • It is entirely normal for the same invest call to return one instrument as a positionTransfer and a different instrument as an allocation — the decision is made per instrument based on whether the account's Independent bucket already holds it and what the presets say.
  2. 4a — Submit the transfers. POST /fa/model/submit-transfers with the transfersInstructionId from step 1. This commits the cash + position transfers that don't require new market orders. It's a fire-and-forget commit — success means the base cash transfer succeeded (other transfers may still be checked individually via error).

  3. 4b — Submit the orders. For every entry in allocations[], an order must be placed through the IServer trading API, not the FA microservice. See Section #5 for the detailed sub-sequence (auth, suppress precautions, fetch model allocation codes, submit order). Wait for the order to fill before treating the investment as complete — partial fills will show up as imbalance in later verification calls.

Phase 5 — Verify the investment

  • /fa/model/accounts-details (with calcPnls:true) — per-account cost basis, NLV, unrealized PnL, and count of instruments outside target range.
  • /fa/model/summary — model is now bootstrapped:true, has a real NLV and numAccounts:1.
  • /fa/model/positions — per-instrument actual vs. target, now populated.
  • /fa/model/invest-divest-positions — confirms accountModelNlv reflects the new investment.

5. Order Submission via IServer (the "allocation" leg)

The FA microservice never talks to the exchange directly — for any allocations[] entries returned by invest-divest / tws-invest-divest / rebalance/*, you must submit real orders through the trading gateway. This is a separate authentication context (OAuth 2.0-based IServer session), and is the same order-submission surface used for all IBKR trading, with two additions specific to models:

  1. Authenticate the trading session: POST /iserver/auth/ssodh/init

  2. Suppress order precaution dialogs (required for unattended/API submission): POST /iserver/questions/suppress with the standard list of message IDs.

  3. Fetch the model→account allocation codes (prerequisite before any model order): GET /iserver/account/allocation/models Returns a map of model name → an internal allocation code string. You need this step once per session before placing model orders — it's how the trading gateway resolves isModel:true orders to the correct FA account groupings.

  4. Submit the order, targeting the model as the account context: POST /iserver/account/{modelCode}/orders Key fields that make this a "model order":

    • "acctId": "<model name>", "isModel": true
    • conidex = the instrument's conid to allocate
    • jsonPayload.allocation_profile — alloc_type: "SHARE" with a list of {account, amount} pairs (the quantity to allocate to each underlying account). The quantity you allocate here should match the quantity reported in the corresponding allocations[] entry from the planning call.

The response gives you an order_id / local_order_id and initial order_status (e.g. PreSubmitted). Wait for the fill before treating the invest/divest/rebalance as complete — subsequent verification calls (/model/positions, /model/accounts-details) reflect actual positions, not pending orders.


6. Polling Pattern (subscriptionKey / subscriptionStatus)

Several planning endpoints (invest-divest, rebalance/*, tws-invest-divest) can take longer than a single request/response round trip because they may need to bootstrap a model, fetch CCP snapshots, or compute large allocation sets. These use a simple polling contract:

  1. First call: either omit subscriptionKey entirely, or send it as an empty string "", to start the async computation.
  2. Immediate response may come back "not ready": subscriptionStatus: 0, with a subscriptionKey (e.g. "1") that identifies the in-flight job.
  3. Poll: re-send the identical request payload, but now with subscriptionKey set to the value you were given. Repeat until subscriptionStatus: 1, at which point the response body contains the full result (transfers, allocations, etc.).

Other endpoints not involved in heavy computation (/model/save, /model/summary, /fa-preset/get, /is-full-master, etc.) always return subscriptionStatus:1 immediately — there's nothing to poll.


7. Rebalancing — Three Flavors, One Response Shape

All three rebalance endpoints return the same response shape (allocations, allocationTotals, positionTransfers, miPositionTransfers, contractsAllocEnabled, contractsCashQtyEnabled, contractsFracEligible, accountsCanTradeFractions, errors, warnings) and a transfersInstructionId you feed to /model/submit-transfers / IServer order submission exactly like an invest-divest plan. They differ only in what targets they rebalance against:

| Endpoint | Targets used | Validation | |---|---|---| | /model/rebalance/to-existing-targets | Whatever is currently saved on the model | Model must already be bootstrapped | | /model/rebalance/to-new-targets | A brand-new full target set you supply in the request (and which gets persisted to the model, like /model/save) | Targets must sum to 1.0; at least one position target and one cash target required | | /model/rebalance/to-specific-targets | A partial target set — only the conids you list are touched | No "sum to 1.0" or completeness validation — this is the "rebalance just these rows" option |

Use to-specific-targets when a user selects one or two rows in a UI and wants to correct only those, without disturbing the rest of the model's allocation.


8. Multi-Model / Batch Invest (tws-invest-divest)

/model/tws-invest-divest exists for flows where a single account (or group/list of accounts) needs to invest into multiple models in one call — e.g., "put $10K into Model A and $20K into Model B for this account." Each entry in modelList[] can independently specify targetAmt, targetPercent (use 0.00 for full divest), or amtToInvest (negative to divest).

Who to invest — account, list, or group

tws-invest-divest accepts the invest target in one of three mutually exclusive shapes at the top level of the request:

| Shape | Field | Example | Semantics | |---|---|---|---| | Single U-account | account | "account": "DUXXXX123" | Invest just this one account. | | Explicit list of U-accounts | accountList | "accountList": ["DUXXXX123","DUXXXX124","DUXXXX125"] | Invest each account in the list. The investment amount for each model is split equally across the listed accounts. | | FA pre-trade allocation group | group | "group": "Group1" or "group": "All" | Invest every account in the named FA allocation group. "All" targets every account under the master. The amount for each model is split equally across the group's accounts. |

Whether you pass accountList or group, the invest amount for a given model is divided equally between the resolved set of accounts — you cannot specify per-account amounts on tws-invest-divest. If you need per-account amounts, use /invest-divest (see the comparison below).

tws-invest-divest vs. invest-divest

| Dimension | /fa/model/tws-invest-divest | /fa/model/invest-divest | |---|---|---| | Models per request | Multiple — modelList[] may target several models in one call | One — a single model per call | | Per-model amount specification | One of targetAmt / targetPercent / amtToInvest per entry in modelList[] | One amount per account in accountList[{account, amtToInvest}] | | Model currency | Instruments may span multiple currencies within a single model | Single-currency models only | | Per-account amount control | No — one amount per model is split equally across the account set (single account / accountList / group) | Yes — each account in accountList carries its own amtToInvest | | Group / "All" support | Yes — named FA allocation group or "All" | No — accounts must be listed individually |

Choosing between them:

  • Reach for tws-invest-divest when you need multi-currency instruments in a model, when you want a single account/list/group to invest into several models at once, or when you're already thinking in terms of FA allocation groups.
  • Reach for invest-divest when each account needs a different investment amount, since tws-invest-divest splits one amount equally across all target accounts when a list or group is used.

Batch ordering on the response

The response mirrors invest-divest but tags every cashTransfers / positionTransfers / allocations entry with a batchNumber. Respect batch ordering when submitting — batches are sequenced so that closing/freeing orders run before conversions, which run before opening/spending orders, matching how Multi Currency Model conversions must be sequenced to avoid transient negative cash.


9. Supporting / Maintenance Endpoints

  • /model/delete — deletes both the model and its targets. Note: a model cannot be re-created with the same name the same day it was deleted — you must wait at least one day.
  • /is-full-master — call this defensively before attempting Invest/Divest/Rebalance if you're unsure of the master account type; partial masters may have these actions blocked outright.
  • /model/cash-analyzer — for multi-currency models, detects undesired non-model-currency cash balances sitting in account.Model buckets and returns the cash transfers / FX-conversion orders needed to clean them up. Also surfaces marginWarning:true if a margined account has gone negative in a non-base currency. If accountList is omitted, it scans the master's entire book.

10. Limits & Constraints to Design Around

| Constraint | Detail | |---|---| | Query allocation codes first | Ensure GET /iserver/account/allocation/models is queried first, prior to interacting with model portfolios via the Web API. This should help reduce HTTP 400 errors from POST /iserver/account/{modelCode}/orders etc. | | 50-account cap | /model/imbalance and /model/accounts-details return reduced/blank data once numAccounts > 50 for the model (imbalance becomes unsupported; accounts-details drops Cost Basis/UnrPnL and just returns Code/Alias/NLV/Ind Cash). /model/positions does not have this restriction — it aggregates without holding per-account snapshots in memory. | | Single currency per model | All positionTargets + cashTargets on a model must share one trading currency. Violations are rejected both on /model/save and on rebalance actions. | | Targets must sum to 1.0 | Enforced on /model/save and /model/rebalance/to-new-targets; not enforced on /model/rebalance/to-specific-targets. | | One-time transfersInstructionId | Re-submitting the same transfersInstructionId to /model/submit-transfers is treated as an error (duplicate). | | Corporate-action / mismatched instruments | If a model's holdings have drifted from its saved target conids due to a corporate action, mismatch:true is surfaced on /model/list, /model/summary, and /model/positions (mismatchType: 1 = in Targets but not MI, 2 = in MI but not Targets). Plan/invest calls reject with a "Corporate Actions have changed instruments..." error until targets are reviewed. |

View our Web API Account Management documentation here.

IBKR Campus Newsletters

This website uses cookies to collect usage information in order to offer a better browsing experience. By browsing this site or by clicking on the "ACCEPT COOKIES" button you accept our Cookie Policy.