@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

  1. 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_TEMPLATE lists it: the sections to tick with their options and fields, and the settings (XML; dates yyyyMMdd, times HHmmss, separated by ;; cancelled trades and currency rates included). A query belongs to the user who made it.
  2. 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.
  3. 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']
  }
}
  • fetchReport sends SendRequest and then GetStatement with 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 to requestTimeoutMs, comes on top); too many requests (1018) waits a minute. fetchReportXml gives the XML as IBKR sends it.
  • Everything else is a FlexError at once, with code, IBKR's ibkrCode and ibkrMessage, 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.

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.

S
Description
No description provided
Readme
146 KiB
Languages
TypeScript 100%