@apiclient.xyz/ibkr
A read-only client for the Interactive Brokers Flex Web Service: it fetches the report of an Activity Flex Query with IBKR's request protocol, its error codes and its rate limits, reads the report's XML into typed records, and checks a query has what a booking of the account needs. The Flex Web Service gives reports and nothing else: a token for it cannot place, change or cancel an order, nor move money or securities.
Issue Reporting and Security
For reporting bugs, issues, or security vulnerabilities, please visit community.foss.global/. This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a code.foss.global/ account to submit Pull Requests directly.
Install
pnpm install @apiclient.xyz/ibkr
Setting up the account
- A user with the Reporting rights "Activity Flex Queries" and "Flex Web Services", and no trading right, creates an
Activity Flex Query in Client Portal (Performance & Reports › Flex Queries) as
FLEX_QUERY_TEMPLATElists it: the sections to tick with their options and fields, and the settings (XML; datesyyyyMMdd, timesHHmmss, separated by;; cancelled trades and currency rates included). A query belongs to the user who made it. - The same user enables the Flex Web Service (Flex Queries › Flex Web Service Configuration) and creates the token, valid for 6 hours to a year, optionally for one IP address. A new token ends the old one.
- The query id and the token go to the application, the token as a secret.
Usage
import { FlexClient, flexQueryProblemsOf, flexRowsOf } from '@apiclient.xyz/ibkr';
const client = new FlexClient({ token: process.env.IBKR_FLEX_TOKEN!, userAgent: 'acme-books/1.0' });
const report = await client.fetchReport({ queryId: '800969', fromDate: '2026-05-04', toDate: '2026-05-05' });
const problems = flexQueryProblemsOf(report); // [] where the query has what a booking needs
for (const statement of report.statements) {
for (const trade of flexRowsOf(statement, 'Trades', 'Trade')) {
trade.tradeDate; // '2026-05-04'
trade.netCash; // '-1828' — decimal text, never a binary number
trade.notes; // ['C', 'P']
}
}
fetchReportsendsSendRequestand thenGetStatementwith the reference it gives, every request with the token, version 3 and a User-Agent ("all requests must include a User-Agent header", IBKR's Flex Web Service guide). Ask with a period (fromDate,toDate, ISO days, at most 365 days apart): a query of "the last N days" runs through the service with the most days it allows.- One request a second and ten a minute per token, kept across the clients of a process. A report in generation
(1019) or not yet ready (1001, 1004–1009, 1021), or a service it could not reach (no connection, HTTP 5xx), is
asked for again after 2, 4, 8, 15 and then 30 seconds while the waits stay within
maxWaitMs(5 minutes by default; a request's own time, up torequestTimeoutMs, comes on top); too many requests (1018) waits a minute.fetchReportXmlgives the XML as IBKR sends it. - Everything else is a
FlexErrorat once, withcode, IBKR'sibkrCodeandibkrMessage, and never the token:
code |
IBKR | What to do |
|---|---|---|
not_ready |
1001, 1004–1009, 1019, 1021 | ask again later |
rate_limited |
1018 | ask again later |
token_expired, token_invalid, ip_restricted |
1012, 1015, 1013 | the user renews the token or its IP address in Client Portal |
query_invalid, legacy_query, service_inactive |
1014, 1010, 1011 | the user fixes the query or the service |
statement_unavailable, account_invalid, reference_invalid, request_invalid |
1003, 1016, 1017, 1020 | — |
unknown_error |
any other | — |
response_invalid, http_error |
— | an answer that is no report (a query in CSV), an HTTP status other than 200 |
Reading a report
parseFlexQueryResponse(xml) gives a statement per account with the sections the query includes, each with its rows
(TFlexRecord: the element's XML name and its attributes). A value is read by its kind: text as IBKR writes it, a
decimal as decimal text, a day as an ISO day, a day with its time as ISO local time, a list as its items, a yes or no
as a boolean; undefined where IBKR writes nothing ("", -, --, N/A, and MULTI for a day or a number of a
summary row). A field the query selects is a key of the row even where it is empty; one it does not select is none.
flexRowsOf(statement, section, element) gives the rows typed by their element (IFlexTrade, IFlexCashTransaction,
…, IFlexElements).
The parser is lenient: an unknown section, element or attribute, or a value it cannot read, is reported in
findings and does not fail the report, so a report whose format IBKR extends still reads. A text that is no
well-formed <FlexQueryResponse> is refused (response_invalid).
Checking the query
flexQueryProblemsOf(report) names each gap against FLEX_QUERY_TEMPLATE in a sentence a person can act on: a
section the query does not include, a field its rows do not carry, a value in another format than the template's
settings give, a report without a statement. Each says whether a booking cannot do without it (required) or a
check or a view does (recommended).
The format's catalogue
FLEX_ELEMENTS and FLEX_SECTIONS hold the elements of a statement, the attributes each carries with the kind of
value, and the elements each section holds. They are generated from the element and attribute annotations of the
MIT-licensed ibflex parser (tools/generate-catalogue.ts, from ibflex commit
45de3b53), which follow IBKR's Activity Flex Query reference: names and kinds only, no ibflex code. The test
fixture is constructed from that reference and catalogue, with invented values, until a real account's first
statement replaces it.
Third-party notices
The catalogue is derived from ibflex:
Copyright (c) 2017 Christopher Singley
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
License and Legal Information
This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the license file.
Please note: The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
Trademarks
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH or third parties, and are not included within the scope of the MIT license granted herein.
Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.
Company Information
Task Venture Capital GmbH Registered at District Court Bremen HRB 35230 HB, Germany
For any legal inquiries or further information, please contact us via email at hello@task.vc.
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.