Skip to main content

Request and retrieve a Flex report

Flex Web Service version 3 uses two HTTPS requests with different identifiers:

  1. SendRequest accepts the token and saved Query ID, starts one report instance, and returns a ReferenceCode.
  2. GetStatement accepts the same token and that ReferenceCode, then returns either the generated report or a Flex failure envelope.

This is a protocol contract, not yet the production polling policy. The later ingestion guide will add deadlines, capped backoff with jitter, cancellation, persistence, concurrency ownership, and unresolved-outcome handling. Do not turn the sequence below into an unbounded loop.

Use the current primary endpoints

The current official generation guide and retrieval guide use this base URL:

https://ndcdyn.interactivebrokers.com/AccountManagement/FlexWebService

Append /SendRequest or /GetStatement; both operations use GET. The official two-step workflow requires a User-Agent header on every request.

Build query parameters through the HTTP client's parameter encoder. Never concatenate the token into a logged string, include the complete request URL in an exception, or persist the token-bearing URL.

Step 1: submit SendRequest

Use these required query parameters:

NameMeaningVersion 3 rule
tCurrent Flex Web Service tokenRequired; secret.
qQuery ID of the saved Flex Query templateRequired; sensitive configuration.
vFlex Web Service versionRequired; set to 3.

The official SendRequest parameter page says versions 2 and 3 are accepted but instructs clients to use version 3. It also documents a limit of one SendRequest per second and ten per minute. That is a submission limit, not permission to create another report whenever retrieval is delayed.

Optional date overrides

The newer general request page lists only t, q, and v. A separate current official Advisor Portal guide documents these optional forms for SendRequest:

ModeAdditional parametersDocumented boundary
Saved template periodNoneUse the Flex configuration saved in Client Portal.
Explicit date rangefd=yyyymmdd and td=yyyymmddRange up to 365 days.
Period overridep=<days>Period up to 365 days.

The override evidence is published in the Advisor Portal guide, so its documented applicability is advisor configuration. Do not silently claim the same account-role coverage elsewhere without verification. Put overrides only on SendRequest; GetStatement identifies the already-created instance by reference code.

Validate the SendRequest XML envelope

Version 3 returns a FlexStatementResponse XML envelope for the submission outcome. Do not accept a reference code before checking Status.

For success, require:

<FlexStatementResponse timestamp="SYNTHETIC_TIMESTAMP">
<Status>Success</Status>
<ReferenceCode>SYNTHETIC_REFERENCE_CODE</ReferenceCode>
<url>LEGACY_URL_VALUE</url>
</FlexStatementResponse>

The structure is based on the official success response; every value above is synthetic. Retain ReferenceCode as the identity of this report instance. The current official page explicitly calls the lower-case <url> element legacy and says to ignore it. Do not use that value as the retrieval host.

:::warning Pinned ib_async incompatibility

ib_async 2.1.0 FlexReport.download looks for an upper-case Url, asserts that it exists, and uses its value as the polling base. That pinned library behavior conflicts with the current official lower-case legacy element and ignore instruction. Do not treat the helper as a conforming implementation of this current endpoint contract without a reviewed wrapper or upstream fix.

:::

For failure, expect the same root with a failed status and explicit error elements:

<FlexStatementResponse timestamp="SYNTHETIC_TIMESTAMP">
<Status>Fail</Status>
<ErrorCode>SYNTHETIC_ERROR_CODE</ErrorCode>
<ErrorMessage>SYNTHETIC_ERROR_MESSAGE</ErrorMessage>
</FlexStatementResponse>

The element contract comes from the official failure response. Classify by ErrorCode; never use the human-readable message as the sole machine key. The complete retry and terminal-error table is a later slice.

Step 2: retrieve with GetStatement

Use the primary base URL with /GetStatement and these required query parameters:

NameMeaningVersion 3 rule
tThe same access tokenRequired; secret.
qReferenceCode from the successful submissionRequired; it is not the saved Query ID.
vFlex Web Service versionRequired; set to 3.

The official GetStatement parameter page explains that one saved query can generate many report instances and that the reference code selects a particular instance. Keep the Query ID and ReferenceCode in separate typed fields; reusing a variable named only q across both steps hides this critical change in meaning.

Generation may not be finished when the first retrieval is attempted. The current retrieval guide says larger requests may need a longer wait, and the official error table identifies 1019 as statement generation in progress. A FlexStatementResponse failure with 1019 means this reference is still pending; it is not a completed report and not a reason to issue another SendRequest.

The current official Advisor Portal guide shows a failed version 3 retrieval as FlexStatementResponse with Status=Fail, ErrorCode, and ErrorMessage. Its documented account-role applicability is advisor configuration. The general error table assigns its error codes to both endpoints, but does not separately define a broader failure-envelope schema.

When GetStatement returns the report, its serialization follows the saved query's output configuration. This documentation's automated path requires XML, while the official template controls also offer CSV and delimited text. For XML completion, require a FlexQueryResponse root rather than FlexStatementResponse. That root is corroborated here by the pinned ibflex v1.1 library source, not asserted as a current official protocol guarantee; the later XML-model slice will add the complete envelope/cardinality evidence.

Repository validation policy: do not treat one HTTP Content-Type value as sufficient proof of success. The reviewed current request pages define XML outcome elements and configured report formats but no normative response MIME mapping. The later XML-safety slice will require bounded size, header checks, root validation, and safe parsing together.

Keep the identities and states distinct

StateDurable identityValid next action
Template configuredQuery ID plus template revisionSubmit one SendRequest.
Submission succeededQuery ID plus returned ReferenceCodeRetrieve that reference with GetStatement.
Generation pendingSame ReferenceCodeRetry retrieval under the later bounded polling policy.
Report returnedSame ReferenceCode plus response-body hashValidate and parse; do not submit a duplicate request.
Flex failure returnedReferenceCode when available, plus error codeApply the later retry/terminal classification.
Transport outcome unknownQuery identity and attempt recordTreat as unresolved; do not infer that no report was created.

The final two rows state repository lifecycle policy, not additional IBKR guarantees. They prevent transport uncertainty from being mistaken for a safe duplicate submission.

Contract checklist

  • Every request uses HTTPS, the primary ndcdyn base, and a non-secret User-Agent header.
  • SendRequest receives token + Query ID + v=3 through an encoder.
  • Optional fd/td or p overrides are used only where their documented applicability is accepted.
  • The submission body must be FlexStatementResponse with a recognized Status.
  • Success requires a ReferenceCode; the legacy <url> value is ignored.
  • Failure records ErrorCode without logging the token-bearing URL.
  • GetStatement receives token + ReferenceCode + v=3, never the Query ID as q.
  • A pending reference is retrieved again later; it does not cause a duplicate SendRequest.
  • A returned body is not trusted solely because of HTTP status or Content-Type.

Next, the registry and error guide will classify polling, retry, throttling, expiration, completion, and terminal-error relationships before the production polling policy is implemented.