Skip to main content
The easiest way: ask your AI assistant. With Itoflow MCP connected to Claude or Codex, paste:

Open in Claude

Start this in Claude with the Itoflow plugin.

Open in ChatGPT

Start this in ChatGPT with the Itoflow plugin.
Using another client? Copy the prompt with the button on the code block.No tokens or code needed. You can also do this in the Itoflow app. The rest of this page covers the HTTP API.
A monitor watches a set of holdings and reports what changed, on a schedule or when you ask. Each monitor has a mandate: plain-language instructions saying what to watch and how to report it. There are two kinds:
  • Research monitors watch a list of symbols, or whatever universe the mandate describes.
  • Fund-oversight monitors watch one of your portfolios against a benchmark and peer funds, and check it against limits you set, such as tracking error or liquidity.
A Monitor keeps one standing session. Each run has a separate execution record, and each execution can have zero or one saved report. Repeated runs share the session but keep their own status and report. A nullable resource_type value classifies the session projection in storage; it does not grant access or change Monitor admission. Monitor reads and deletion use the Monitor’s owner. Research reports use shared guidance on evidence, uncertainty, and quantitative choices alongside the monitor mandate. This does not change the report format or the fund-oversight workflow. In the API, monitors live under /watchlists, their original name. To set one up with the agent’s help, start from New monitor in the app; the agent sets it up in chat. When you set up a monitor in chat, you can ask for a model. The agent creates the monitor with that choice. If you make no model choice, the usual default applies. Model access checks still apply.

Create a research monitor

POST /watchlists creates a monitor. New monitors start paused, and creating one doesn’t run a report.

Schedules

recurrence.kind is daily, weekdays or weekly. A weekly schedule also needs a weekdays list, such as ["monday", "friday"]. Give local_time as HH:MM and timezone as an IANA name. Don’t convert to UTC: the time zone keeps the report at the same local time when clocks change. Leave out recurrence, or send null, for a monitor you run by hand. When you edit a monitor, leaving out recurrence keeps the current schedule and sending null removes it.

Create a fund-oversight monitor

Set profile to fund_oversight and describe the fund in profile_config. The subject must be a portfolio you own that no strategy manages; a portfolio can’t have both. Fund-oversight creation and report execution depend on availability for your account and the runtime assigned to the saved Monitor. Creating a Monitor does not move an existing portfolio or Monitor to another runtime.
Subject. subject.name and subject.portfolio_id are required. The portfolio can hold one ETF or many securities:
  • For a single ETF, reports look through to the fund’s dated holdings.
  • Risk figures also measure funds held beside other holdings through their dated holdings at each line’s signed weight, down to three funds deep, and count the cash inside them as the book’s cash; holdings lists, concentration and liquidity keep the fund line.
  • For several securities, reports use the portfolio’s own dated positions. Changes and risk change use saved books at or before the requested dates.
  • An ETF inside a multi-security portfolio counts as one holding.
Portfolio performance uses the stored return index at the last recorded prices of each report-zone day. With a benchmark, returns run on the benchmark’s trading days: a trading day’s value is the newest reading from that day up to the next trading day, and returns end on the benchmark’s last trading day on or before the report date. A report made before the market opens, or at a weekend, therefore ends on the last close. 1D and 5D start one and five trading days earlier; calendar horizons start on the last trading day on or before their calendar start. A horizon that would start on its end day is left out. A run while a market is open takes the newest reading as the previous trading day’s value. Returns end on the report date when there is no benchmark, when the benchmark is an index or its last close is behind its exchange’s calendar, or when no reading covers its last trading day. A day with no reading remains missing; a horizon with a missing start or end is not known and names the day. Paper portfolio comparisons use price returns on both sides, adjusted for splits, and say “Price return; dividends not recorded”. Live comparisons include recorded cash income. Both sides are measured in US dollars. Realised beta needs at least twenty pairs of consecutive benchmark trading days with portfolio readings on both ends. Their recorded marks and the benchmark closes need not coincide. Benchmark. Returns come from index_symbol. A price index such as GSPC.INDX leaves dividends out; a fund that tracks it, such as SPY.US, includes them. For holdings comparisons, name a fund that holds the index in basket_symbol. If you leave the basket out and index_symbol is itself a fund, Itoflow uses that fund’s holdings. A plain index with no basket is compared by returns only. The comparator slots are benchmark and peers. Realised beta uses the benchmark’s price series: index_symbol when set, otherwise basket_symbol. Forecast beta uses its holdings book. They have separate metric keys, risk.realised_beta.benchmark and risk.beta.benchmark. With no benchmark, the report has no benchmark beta row and its receipt says: “This Monitor names no benchmark, so beta is not configured.” Peers keep their forecast beta rows. Missing benchmark prices are a data gap. Removing the separate beta reference preserves tracking-error history when the subject and comparator books stay the same. Changing the subject or benchmark starts new history. Earlier realised-beta values under the retired metric key are not carried into risk.realised_beta.benchmark. Detail, list and version history omit the retired comparators.beta_reference setting without changing stored versions. Scheduled runs and runs pinned to earlier settings ignore that key and measure beta against the benchmark. The reporting agent’s configuration brief also omits that comparator setting, while preserving other settings and custom context. Sending a configuration with the retired key is rejected. A metadata-only edit succeeds and omits it from the new version’s inherited settings; earlier versions remain unchanged. Each section carries one status: With no benchmark or peer, attribution, factor return, bets, forecast quality, drivers and risk change are not set up. With no limits, compliance is not set up. Risk, exposures and sizing keep their subject figures. Those comparator sections and compliance stay not set up even when the subject book is unusable; the receipt records the subject failure and subject-only sections report the data gap. Compliance rules compare cash, above-5% issuer bucket, single issuer and relative weights against configured limits. The illiquid-days cutoff enables a share measurement but adds no rule or ceiling. A tracking-error budget, row threshold overrides or liquidity tuning alone do not set up compliance. Named peers whose books could not be read remain data gaps. The panel lists sections that are not set up apart from failed sections, with their reasons and without section numbers. The receipt names them in sections_not_configured; older saved reports may omit that list. Peers. Name each peer fund by symbol, up to 10. Itoflow needs each peer’s holdings, so a symbol with price history alone won’t work. Holdings dated more than 183 days before the report date don’t count. A fund that closed or changed its ticker stops publishing them, so the run names the date of its last holdings; use the fund’s current ticker or another fund. Fund books. Itoflow reads a fund’s holdings from one market data provider for its market. When that provider states no holdings for a fund, Itoflow has no book for it and the run reports the book as missing. When a stored book has gone stale, the run fetches it again; if that fails, it uses the stored book and warns with the date it went stale. Sector or region weights alone don’t stand in for holdings. When Itoflow can’t confirm the currency of a fund’s holdings values, as for some funds listed outside the US, the report shows those values without a currency. Itoflow looks for the source’s valuation session within each listing currency’s last five sessions, all on or before the holdings date. At least three distinct securities must support a match: a median ratio within 0.5% of one and more than half the rows individually within 2%. A tie within 0.1 percentage point uses the later session and is reported as ambiguous. A matched count that disagrees with its own market value by more than 2% becomes unverified; the holding keeps its stated weight. The receipt gives affected count and weight with share count disagrees with market value in the book’s currency. The foreign-currency group check still catches groups clustered at their rate. When no session matches, the receipt says the source’s valuation date was not found. The 25% gross-error filter then rejects large disagreements, while passing counts remain unverified. Missing comparison data leaves existing behavior unchanged. Groups below three rows and currencies within about 5% of parity remain gaps in the group check. Matching a session never changes the book-date close used to value holdings and test weights; marked price breaks make a row fall back rather than verify an earlier count across that break. A fund book keeps the weights its source states. Itoflow tests them against the book’s share counts and closes. When the two are more than 10% apart, the book stays in use on its stated weights, and the receipt says share counts disagree with stated weights by X%; stated weights kept. A source can state the right weights beside wrong share counts, so Itoflow never rebuilds weights from the counts, and uses them for nothing else either: no weight move in that book is split into trade and price drift from them. Results from earlier runs may still say weights: rebuilt_from_shares and carry a total_basis; Itoflow no longer writes either. A book’s total is the one its source states; a book whose counts agree with its weights can also use the sum of its valued holdings. Each held fund’s dated note also appears in the parent’s receipt, prefixed by its symbol and holdings date. Mandate vs. limits. Put numeric limits in thresholds. Put objectives, exceptions and report preferences in the mandate. Don’t copy the portfolio’s current value into the mandate; it goes stale. The named fields reject unknown keys; put anything else under custom. For a US-listed fund, the first report can already show what changed since the last quarterly SEC filing (Form N-PORT). Itoflow uses each filing only from the day the SEC accepted it. It doesn’t yet use a filing that holds short positions, because the filing data it reads doesn’t state the fund’s net assets.

Limits

Which comparator. relative_weight and tracking_error_budget apply to one comparator, named in thresholds.comparator: "benchmark" or a peer fund’s symbol. It defaults to the benchmark. Reports still show every comparator. Warnings. By default a limit warns at warning_fraction of its value. To set one limit’s warning level, add it under thresholds.warnings in the limit’s own unit. {"tracking_error_budget": 8, "warnings": {"tracking_error_budget": 6}} warns at 6% and breaches above 8%. The warning must be inside the limit. Single report rows. thresholds.metrics overrides one row of the report, keyed by the metric_key shown in the latest report. The monitor needs at least one report first. An override stays saved even if a later report drops that row. The report brief calls compliance not configured when there are no comparison rules, not assessable when rules are configured but none can be fully assessed, and assessed when at least one rule can. Measurements stay visible in each state. Liquidity. By default Itoflow assumes you can sell 10% of each holding’s average daily traded value, averaged over the last 20 trading days. Days with zero volume count; missing volume is never filled in. Set liquidity.participation and liquidity.adtv_window_months to change this. Reports show the rate and window they used. If Itoflow can’t read a holding’s volume history after one retry, the report names that holding as a gap, with its weight, and still measures every other holding. Fund size scenarios. aum_scenarios re-runs the sell-down at other fund sizes. Give up to 50 sizes above zero. Two sizes equal to six significant figures count as one, so [500, 500.0000001] is rejected and [500, 500.001] is accepted. The API returns 400 for a comparator the monitor doesn’t have, a warning for a limit that isn’t set or a warning outside its limit, and a metric_key the latest report doesn’t contain.

Read, edit, copy and delete

Every saved change creates a new version and keeps the old one. Reports record which version they used. Being able to read a monitor doesn’t let you edit it; fork it instead. Pause a monitor before you edit it. Editing an enabled monitor returns 400 CANNOT_EDIT_RUNNING, unless you change only the model. Other 409 codes: DUPLICATE_NAME when you already have a monitor with that name, and PORTFOLIO_HAS_STRATEGY when a fund-oversight subject portfolio has a strategy. You can’t turn a research monitor into a fund-oversight monitor. Create a new one. If a read returns 503 with code: "MONITOR_LIFECYCLE_UNAVAILABLE", Itoflow couldn’t confirm whether the monitor is paused or running. Retry; Itoflow doesn’t fall back to a possibly stale status. DELETE stops new work and returns 204 once everything is removed. If cleanup takes longer, it returns 202 with code: "MONITOR_DELETE_PENDING". Send the same DELETE again to check. Meanwhile, reads return 404 and edits return MONITOR_DELETE_PENDING. While Itoflow moves a monitor to its new runtime, the monitor reads with runtime_move_pending: true. Edits, runs, schedule changes and DELETE then return 409 with code: "MONITOR_RUNTIME_MOVE_PENDING". Reads and reports stay available. Try again in a few minutes; the move keeps the monitor’s ID, versions and reports.

Run reports

During an update, manual runs may return 503. Retry in a few minutes. If a previous run is still finishing, a manual request may be refused. Wait briefly and retry. A refused request does not create another run in history. Cloudflare monitor reports can recover across repeated restarts while their start or latest resume is within 90 minutes. Repeated crashes on the same software version can still stop a run; check its status and saved report before starting it again.

Calculated inputs for Cloudflare monitors

When the Cloudflare runtime is enabled for your monitor, each run prepares its calculated inputs before writing the report. A research monitor with symbols saves a dated analytics snapshot. A monitor without fixed symbols follows its mandate without a symbol snapshot. Fund oversight prepares its books, risk and other figures, then uses those saved figures in the report. The saved runtime owner controls later runs; a creation setting does not change that assignment. A research snapshot’s as_of shows the latest price date used by the calculation. It can precede the report date, such as when a run starts before the market closes. That difference does not prevent the run from saving its analytics or publishing its report. If a run cannot prepare valid inputs, it can fail with a reason rather than publish unsupported figures. Partial data remains an explicit gap in the report. To get the same symbol analytics without a monitor, for any 1 to 12 symbols, use GET /symbols/analytics. It saves nothing to a monitor. The research analytics panel loads saved snapshots separately from report text. Creating or editing a monitor does not promise an immediate snapshot. Until a run saves one, the panel says no snapshot exists. After an edit, it labels a known earlier snapshot while waiting for new results. If a refresh fails, it keeps the last saved snapshot and shows a refresh warning. Without saved data, a failed read shows an unavailable state. A monitor without fixed symbols has no symbol analytics; fund oversight keeps its figures in the report.

Saved charts and tables

Cloudflare reports save their rendered chart figures and table snapshots with each execution, using the same output preparation and renderer as Chat. Reopening a report shows its saved data even after another run changes the workspace files. The optional dataframe_snapshots field on a report response holds those saved table rows and their paging and truncation metadata. Older reports without embedded figures or table snapshots remain unchanged.

Browse complete tables

When a report offers Show all, open it to browse the complete table inside its existing section, 25 rows per page. The page arrows move through the list. Short lists need no page controls. Search by a recorded name or ticker, set a minimum value with Filter, or select a column heading to sort. A figure sorts largest first and a name A to Z; select the heading again to reverse it. These apply to the whole list before the report selects a page. Changing the search, filter, or sort returns to the first page. A missing value reads Not known. Each table states its date, comparator, computed period and weight basis above its rows, and each figure column names its unit. Where a column has a definition, the information mark beside its heading shows it. A cell shows two decimals; hold the pointer over it for the exact stored value. Download exports every matching row, including rows beyond the visible page or the section’s cut. The file keeps the search, filter, order, dates, comparator, units, and stored precision. Show top N or Show summary returns to the section’s own cut. Attribution shows the best and worst contributors side by side. Each side is ranked over every recorded name by the sign of the measure, so a short side is never filled with names of the other sign. The complete contributor table opens below them.

Save how a report reads

Opening the full list, searching and paging never save anything. The cut (Top 10, Top 20, …, All rows), the order, a filter, the computed period, and Table or Chart are the section’s view. Changing one shows the result at once and raises Unsaved changes at the bottom of the report. Save view asks where the change applies: This report and future reports, This report only, or Future reports only. A save for this report keeps the original publication intact. A save for future reports applies when the next run starts and does not alter a run already in progress. Saving from an earlier report changes only what you changed there; newer settings for other sections stay as they are. Discard drops the unsaved change. After a save the report offers Undo. Report view lists the saved changes and can preview or restore the report’s published view. Each saved change also appears as a short line in the monitor conversation.

Ask the monitor about a report

Where a report offers its own chat, ask about the recorded figures or request a view change there. Chat uses the same settings as the controls. A new table or chart must pass a query against that report’s data before it can be saved. A message sent while a report is being generated waits until that work finishes; browsing and the view controls stay available. On a wide screen the chat keeps its own column beside the report and can be hidden; on a narrow one, use the Report and Chat tabs. These controls need the source kept for that report. When the source or a table’s rows are unavailable, the published report remains readable; the app does not substitute a newer report’s data.

Enable or pause

POST /watchlists/{id}/control with {"action": "enable"} or {"action": "disable"}.
  • An enabled monitor with a schedule runs on that schedule. Add the schedule before you enable it.
  • Some monitors can’t be enabled without a schedule and return 409 WATCHLIST_RECURRENCE_REQUIRED. You can still run their reports by hand while they’re paused.
  • If the response contains report_scheduling: "unavailable", Itoflow couldn’t set up the schedule, even if other changes saved. Try again.
  • A failed enable returns 503 and leaves the monitor paused. It’s safe to retry.

Run a report now

POST /watchlists/{id}/reports/run queues a report. You can send a one-off instruction of 1–500 characters:
The instruction applies to this report only. It doesn’t change the mandate. For a lasting change, edit the mandate. If a report is already queued or running, your request joins it instead of starting another. The joined report keeps its own instruction. A joined request returns custom_message_applied: false. Cloudflare Monitors apply nonempty instructions only to a newly admitted manual execution. Omit the field when no override is intended; Monitor Chat also treats a blank tool instruction as no override. The standing mandate, version and later runs stay unchanged. The 202 response: If Itoflow can’t confirm the run in time, the response is only { "status": "pending" }. The run may still start. Check GET /watchlists/{id}/active-execution before you try again. report_date is set when the run starts, in the schedule’s time zone, or UTC for a monitor without a schedule. You can’t choose it.

Read reports

Despite its name, {reportId} takes the execution_id from the history list, not the report_id field. For each live Cloudflare Monitor, each local date due while running ends in one report or one failed run in history. An outage may delay the update. The schedule history keeps due dates even if the Worker misses an alarm or restarts. A row still open at its next scheduled time becomes a visible failure. Manual runs have no fixed deadline. Itoflow retries recording an answer or failure up to three times. A manual run may stay open if those writes keep failing. A run that never started gets a visible failure after a short wait; a run still working stays open. If another run is active, the new date fails with a reason naming that run; the older run continues. Select a failed execution in history to read error_message. If an ended run is still finishing, Run now asks you to try again shortly. Pausing stops future scheduled runs. A run or repair already in progress finishes and publishes on its original row, including when its answer is still being saved after computation finishes; its deadline still applies. A due run that has not started becomes a visible failure. Resuming starts a new running interval; dates in the paused gap do not run. A timezone edit changes future dates and keeps each already-due date in its original timezone. A run uses the configuration current when it starts. If its subject portfolio or profile is no longer valid, a scheduled date records a failure with the reason; Run now returns the refusal directly. Completed reports cannot change. Deleting a Monitor removes its runs and reports and ends its date obligations. While a run is in progress, GET /watchlists/{id}/executions/{executionId}/results returns each result the run has shown so far, oldest first: symbol cards, symbol analytics or a risk engine panel. Each result has a view with its status (ok, partial or failed), its as_of date (null when the result failed) and, for a partial or failed result, a reason, and a component with the data, which is null when the result failed. Take executionId from active-execution. A run’s results are only ever added, so when you poll, pass after with the number of results you already have, and the response holds the new ones; keep each result by its view.result_id, because one can come again when the server skips a result it cannot read. Anything but a whole number from 0 to 999999 returns 400. A run that shows no results returns an empty list, and a run of another Monitor returns 404. Results so far are rolling out: until they are turned on for your account, this route returns 404.
A report published with view settings has view_settings: true in its report record; a report without them has no such field, and its page asks for no settings. A run’s status is queued, running, completed, failed or superseded. superseded marks a run that a newer one replaced. reports/latest returns the latest completed report, so it doesn’t tell you whether a newer run has finished. When the engine refuses invalid input, the failed run’s error_message explains what to change. A portfolio that holds only cash has no securities to monitor; add a holding and run it again. By default, a report tells you what matters now, including matters still open, and what changed since the last report sent to you. Failed and superseded runs don’t count as sent. Your mandate decides what a report covers and how it reads: for example, ask for a report that stands on its own if you read weekly, or for only the changes if you read every report.

What a fund-oversight report contains

Each name’s sector comes from its industry group in the published factor model used by the run. The report maps that group to its GICS sector, so the sector split uses the model’s classification. This also applies in FMP-routed markets, where the model derives the group from the provider’s industry through a checked-in table. A name without a published group keeps its stated sector. After coverage completes, one batch for the subject and comparators reads the same publication pinned for measurement, no later than the report date. Older held snapshot dates do not constrain the model read. The report opens with a summary and numbered findings (A1, A2 and so on), open issues and the most severe first. It then answers three questions: “How am I doing?”, “What is going on?” and “Are my decisions good?”. Each has numbered sections (1.1, 1.2 and so on) showing up to three key figures. The report starts from Itoflow’s risk engine’s figures. The agent explains them, and may correct a figure or add its own from further analysis. Names asked for coverage stay in the fitting universe permanently, including names a request could not cover. Each daily fit tries them again. Later runs report known uncovered names with the pinned fit’s reason and do not wait for them. When the engine asks for new names missing factor coverage, it waits at most 60 seconds for a worker to claim the request. A final status check confirms the result before it stops waiting. A claimed request, or one whose claim state the service cannot report, retains the ten-minute total cap. Measurement continues with any remaining names unscored. If a risk run’s full figures exceed the storage limit, the run keeps its result and panel, gives no artifact path, and states the size and limit; exact figures then come from the view and panel only. If the engine has evidence a figure is wrong, the report leaves out that figure and any conclusion that depends on it, rather than guessing. A risk comparison that needs a covariance repair carries a warning and is marked incomplete. If the covariance total is not finite, the output warns that it shows factor-only risk and leaves the returns weight unmeasured; a negative total makes risk unavailable. An analysis that couldn’t run appears only when you can fix the cause, for example by setting a participation rate. Books used lists the dated holdings sources behind the report. For attribution, the engine uses the latest holdings book dated on or before that period’s start, for both the subject and each comparator. It never uses a later book to fill a gap. The start is the last session close on or before the prior calendar period end, using the engine’s exchange calendar. A five-session window starts at the close before those five sessions. The engine publishes that start and carries the selected weights forward using price moves, assuming no intervening trades. There is no calendar-day distance limit for a start book. If no book exists on or before the requested start, that period is not covered. The report section and tool reply say History starts <date>. The engine keeps the requested period and marks the gap partial or unavailable; it never silently shortens the period. For a saved portfolio, the opening snapshot chooses whether to look through a fund. A mixed opening keeps its own lines, even if today’s portfolio holds only one fund. When the opening holds one fund plus cash, its constituent book passes the same weight check as the other books. It keeps its stated weights; a rejected book withholds that opening. Accepted constituent weights first move from their own date to the saved edit using prices. The saved fund/cash split applies on that edit date; the combined book then moves to the period start. Missing prices for the first move withhold the figures. Since inception starts at the subject’s first available price. The engine resolves that date before reading opening books, even when they fall outside recent history. A missing opening book keeps that full period uncovered. If factor returns, opening exposures or the fund’s ending close are also missing, the reason names both gaps. A resolved period start still gets its book-coverage check when prices cannot measure the period; its figures stay withheld. A filing can supply weights once the regulator has accepted it by the report date. A replay uses its own report date as that knowledge cutoff. Opening book row kinds and diagnostics use that cutoff, including corrections known after the holdings date but before the report date. Later corrections stay out. Both start and end reads exclude holdings dated after the report date, even if a later knowledge cutoff is supplied. Each attributed period names both books’ dates, the period start, and any forward carry in calendar days, beside the assumption of no intervening trades. For example: “Attribution is estimated using holdings dated 29 September, rolled forward 1 calendar day to 30 September assuming no intervening trades.” In the period values, subject_weights_roll_direction and comparator_weights_roll_direction are forward when weights move, or null when the book is dated at the start. For example, February 2026 ends on Saturday: a March month-to-date period starts at Friday 27 February’s close. A book dated 27 February has zero roll. A listed fund’s ending close comes from its own price history; current constituent prices cannot advance it. Only unlisted portfolios use constituent closes. A missing listing history withholds the period. Session-count periods end at the subject’s last available close. A five-session period reported on Monday 9 November 2026, with prices only through Friday 6 November, starts at Friday 30 October’s close. The start books and published dates use that same window. A window without enough price history is withheld; it is never published as a shorter period under the five-session label. The risk-change section’s prior-model book keeps its ordinary on-or-before read, including its existing current-book freshness rule. Saved engine reports retain their published contract. Readers accept versions 1 and 2 permanently without rewriting saved reports. Version 2 attribution figures and numeric details state their measure, actual common dates, comparator and basis_id. The embedded basis records the calculation definition, opening books, dated book path and price coverage, including reconstruction assumptions. A citation retains this context with its figure. A daily basis can also carry a compact gap summary for each side: distinct dated gap days, affected names, and the sum of their absolute period-average weights in percent. Unknown weight is null with a reason. Deploy these readers in every production unit before the writer starts emitting version 2. For attribution, the engine uses the latest holdings book dated on or before that period’s start, for both the subject and each comparator. It never uses a later book to fill a gap. The start is the last session close on or before the prior calendar period end, using the engine’s exchange calendar. A five-session window starts at the close before those five sessions. The engine publishes that start and carries the selected weights forward using price moves, assuming no intervening trades. There is no calendar-day distance limit for a start book. If no book exists on or before the requested start, that period is not covered. The report section and tool reply say History starts <date>. The engine keeps the requested period and marks the gap partial or unavailable; it never silently shortens the period. Since inception starts at the subject’s first available price. The engine resolves that date before reading opening books, even when they fall outside recent history. A missing opening book keeps that full period uncovered. If factor returns, opening exposures or the fund’s ending close are also missing, the reason names both gaps. A resolved period start still gets its book-coverage check when prices cannot measure the period; its figures stay withheld. A filing can supply weights once the regulator has accepted it by the report date. A replay uses its own report date as that knowledge cutoff. Opening book row kinds and diagnostics use that cutoff, including corrections known after the holdings date but before the report date. Later corrections stay out. Both start and end reads exclude holdings dated after the report date, even if a later knowledge cutoff is supplied. Each attributed period names both books’ dates, the period start, and any forward carry in calendar days, beside the assumption of no intervening trades. For example: “Attribution is estimated using holdings dated 29 September, rolled forward 1 calendar day to 30 September assuming no intervening trades.” In the period values, subject_weights_roll_direction and comparator_weights_roll_direction are forward when weights move, or null when the book is dated at the start. For example, February 2026 ends on Saturday: a March month-to-date period starts at Friday 27 February’s close. A book dated 27 February has zero roll. A listed fund’s ending close comes from its own price history; current constituent prices cannot advance it. Only unlisted portfolios use constituent closes. A missing listing history withholds the period. Session-count periods end at the subject’s last available close. A five-session period reported on Monday 9 November 2026, with prices only through Friday 6 November, starts at Friday 30 October’s close. The start books and published dates use that same window. A window without enough price history is withheld; it is never published as a shorter period under the five-session label. The risk-change section’s prior-model book keeps its ordinary on-or-before read, including its existing current-book freshness rule. Weight your portfolio or upload leaves unlisted is cash and stays outside gross exposure. Weight a provider or filing leaves unlisted is unknown. It counts in gross by its size, stays uncovered, and the return figures hold it at zero return under Not listed by the source. If a book’s net assets reach zero or below during a price drift, figures that need that drift read not known, with the book and day in the reason. A line the engine cannot value keeps its stated weight, stays uncovered, and earns zero return. It stays in gross exposure and never becomes cash. Cash sits outside gross in model, classification, valuation and liquidity coverage. Cash remains available in liquidation proceeds, and cash-limit checks include owner implied cash. A book of cash alone earns zero return. Attribution counts measured security returns separately from lines held at an assumed zero return. Cash-marked money-market funds and filing short-term investment vehicles count as cash, earn zero return, and stay outside gross and security price coverage. Their labels say they are money-market funds counted as cash. Cash-and-equivalents lines are cash too. A line named for a currency, by its code or its name, is cash only when ISO 4217 lists that currency as money. A stated cash currency code, including a cash identifier such as CASHUSD00, can establish its currency; reserve and accounting units, test codes, fund units and metals cannot. A line named for a metal holds the metal, not cash. Untagged cash can take the fund’s currency only with independent dated net assets: within one trading session, the book must agree within 0.05% with all untagged cash included and miss by more than 0.05% without it. On any read for a past date, cash proved by a net-assets figure dated after that date is not known. Multiple untagged cash rows are tested together. A failed proof states both percentage gaps; absent evidence leaves the gaps unknown. The current filing feed omits the needed net-assets figure, so its cash retains unknown currency unless the row states it. Provider books reuse the dated assets figure and currency from their existing profile reply. Missing currency or an unavailable calendar leaves the proof incomplete; no extra provider request fills the gap. Refreshes can update stored row kinds; existing saved reports retain their original data. Attribution coverage includes weight a third-party source leaves unlisted in eligible gross, with a separate gap from listed holdings that have no usable prices. Across periods, attribution states the dated book with the largest combined gap and that book’s split between unlisted and unpriced weight. A holding whose stored specific variance is above the bound the model caps it at stays outside the risk figures, with its signed weight and specific_risk_out_of_range in coverage. A name an earlier model run recorded as prices_not_usable carries that reason, and its older model rows are not carried forward. The model trusts prices as they arrive and leaves no name out for the size of a move. The factor split needs the model’s daily returns to reach the period’s last priced day. If they stop earlier, the report leaves that period unsplit and states both dates; the factors’ share of the gap is not known. Liquidity keeps unvalued and unlisted weight in its gap receipt even when volume reads succeed, and applies the same 0.5% materiality floor as exposures and compliance. Every section uses the same clock. A report reads today’s data when its date is today or later in the report’s own timezone. Today’s listing directory can explain retirement only on such a report. On today’s data, the engine keeps a retired holding’s observed closes through its last close in the loaded history. It states no value after that date, even when the requested window ends later or other holdings have newer closes. If a price drift reaches beyond that close, the holding keeps its book weight and the receipt names the last close and the unknown later value. A missing provider link or stated currency still prevents a price read, and the receipt keeps that reason. Trading listings take priority when a provider also lists the same code as retired. If a Monitor or risk run leaves a holding outside the factor model because its prices stop short, the shared price history can name retirement on today’s data. The line gives the last observed close date when known. Without shared price history, it keeps the general price-coverage reason and reads no directory to infer a cause. The holding stays unmodelled. On an earlier report date, prices use the ordinary tail check and close carry for every listing. No later-history probe runs. A series ending more than five weekdays early gets a price-gap receipt, including in a one-holding book. The cause stays unknown. Currency lookup still uses stated currencies from trading and retired listings on every date. A holding with a book weight that is not a finite number stays outside model coverage, even when the model covers its listing. Its coverage row has weight: null and reason code invalid_book_weight: “Its book weight is not a valid number, so its risk is not known.” On today’s data, liquidity leaves out a retired line unless it traded on the report date itself, even on a weekend or holiday. The receipt names retirement and the last observed trade date when known. A retired comparator has no realised beta on today’s data. If the retired directory cannot be read, the receipt names the affected venue and the count of listings with unknown status. On a replay, liquidity uses the observed readings without today’s listing status or retirement wording. Realised beta uses the paired returns like any comparator. Prices, drift, factor coverage, beta and liquidity all follow the same report-date rule. A portfolio without a dated return series keeps its forecast risk and beta. It publishes no realised-beta row, and the receipt explains the method limit without making risk partial. Missing benchmark prices for a listed-fund subject remain a data gap. Company listings use the company legal entity identifier mapped from their international securities identifier, then the provider key. Provider identifiers count only when their classification date is on or before the report date. A unique shared filer number joins a filer-only line to its legal entity identifier. Conflicting links stay unresolved. Equal registered keys group listings into one issuer; funds have no issuer key. The receipt names lines with no key and both sides of a possible unbridged filer-versus-legal-entity split. It states their book and total absolute weight, before longs and shorts can cancel. A settled position is an equal-key group with no named line. Unresolved weight includes every line in other groups, plus unlisted source weight. On one side, the largest issuer’s upper bound is the largest settled position plus unresolved weight. The above-5% bucket’s upper bound sums the settled positions above 5%, then the settled positions nearest 5%, taken while their summed gaps to 5% stay below the unresolved weight: each position it lifts uses up its own gap; it adds unresolved weight only if a settled issuer can exceed 5% or the unresolved weight alone exceeds 5%. When bounds differ, the report shows at least and the upper bound beside it. It reports a breach only when the lower bound reaches the owner’s limit, within only when the upper bound stays below it, and otherwise leaves the verdict not known. Longs and shorts with unresolved weight have no issuer verdict. Trim plans need zero unresolved weight. Issuers are legal entities; a consolidated group limit needs dated parent links. For example, settled positions of 6% and 3% and an unresolved 2% line give a largest-issuer range of 6% to 8%: within a 10% limit, unknown against 7%. The country split uses the listing venue’s country when the company states none; its receipt states the weight that used this fallback for each book. Funds, including exchange-traded funds, mutual funds and UCITS, receive no issuer key because an umbrella identifier can name several funds. Company holdings in a fund’s look-through book use the same company-key rule. The first map covers held-line identifiers from 3 November 2026; identifiers outside that snapshot use the stated provider key or count alone. Unlisted source weight remains a separate coverage gap. Valuation compares long names with long names and short names with short names within each sector. A derivative whose figure has no proven contra offset keeps the book usable. Every row remains, with stated weights labelled % of the provider’s total in the book note. The derivative’s exposure and direction are not known; a negative figure is never treated as a short. The receipt’s exposure_unknown_reason explains the gap beside total_note. Exposure-dependent book totals are not known: long and short sides, gross and net exposure, leverage, factor and risk totals, and book-level liquidity aggregates. Gross has a lower bound from the other rows’ sizes. Risk, scenarios, attribution and factor profit and loss sections explain why they are unavailable. Position-limit figures show without bands, passes or trim plans; a figure alone above its limit proves a breach. Per-holding days to sell, valued-share multiples, share sector and country weights, prices and the fund’s own performance stay available. A future with a proven contra keeps its usual treatment. Unknown or identified-security shorts that cannot be valued still require a usable total. If a listing has no declared quote currency, the receipt says that the full value cross-check could not run and why. When the comparable rows agree, the fund keeps the provider’s stated weights, which do not come from Itoflow’s quotes. The book note states when these refer to the provider’s total rather than confirmed net assets; the receipt does not describe the whole book as checked. Depositary receipts enter fund look-through as equity on their own listing. When that listing has no reference type, other listings with the same checked ISIN supply a type only when they agree. The engine keeps the original line. A portfolio that holds one fund alone at weight 1 uses the fund’s own book. When it also holds cash, or the fund’s weight differs from 1 beyond the 0.01 rounding band, the engine multiplies each fund holding by that weight and keeps the cash. For example, 90% IFRA and 10% cash becomes 54% CAT, 36% NUE and 10% cash if IFRA holds 60% CAT and 40% NUE. That book takes the date of the fund’s holdings. For an earlier date, such as the start of a change in risk, the engine applies today’s weights to the fund’s holdings on that date, because today’s positions can’t show what the portfolio held then. When a risk forecast check builds returns from holdings, a missing return contributes zero and keeps its weight. The check measures return coverage on the size of the risky holdings; cash adds no coverage. A session below the required coverage is left out. The forecast check reads the subject and comparator books on or before each model date, known by the report day. These dates come from the model itself; the check does not need the return-period calendar. Risk-only and exposures-only runs also avoid that calendar.

News feed

GET /watchlists/{id}/news returns news and SEC filings stored in the last 24 hours that bear on the monitor’s holdings or its mandate. For a fund-oversight monitor, the holdings are the portfolio’s current positions, long or short, with funds expanded into what they hold. A fund whose newest holdings are more than 183 days old counts as itself, not expanded. Cash doesn’t count, nor does an import price placeholder, since it isn’t funded. Company weights add across direct positions and fund holdings; a company drops out when its total is known to be zero. Companies with unknown weights stay. For a research monitor, the holdings are its symbols. Itoflow judges stored news for a monitor’s subjects when you ask: each company it holds, and its mandate where mandate matching is on. For a company, a model rates each item that could affect it from minor to material, with a direction. Company judgments are shared across monitors that hold the same symbol. Mandate judgments belong to one monitor: a model gives the chance that an item bears on what its mandate asks it to watch, and items at or above a fixed bar match. An item appears when it’s rated at least minor for one holding or matches the mandate. Without since, the feed returns the highest-scoring items. An item’s score for a holding is (m / 3) × (0.5 + 0.5 × w / w_max), where m is its materiality for that holding, w the holding’s weight, and w_max the largest holding’s weight (feed.largest_weight). A mandate match scores as a holding of weight 0 with materiality mandate_p × impact. The item’s score is its highest across its matches. For a research monitor, only materiality counts.

Fetch, then poll

feed.coverage says how many of the monitor’s subjects are judged through the last 24 hours. When current is below subjects, call POST /watchlists/{id}/news/fetch once. It returns 202 at once with the number of subjects and how many it sent to be judged; judging runs in the background, usually within a few minutes. A paused monitor fetches too, and calling again while judging runs is safe.
Then read the feed every few seconds, passing the previous response’s feed.judged_through as since, until feed.coverage.current equals feed.coverage.subjects. A poll reaches 5 minutes before since, to catch matches saved late, so it can return an item you already have: merge items by id. If a poll returns exactly limit items, some may not have fitted; read the feed again without since. After you edit a monitor’s mandate, the feed leaves out the old mandate’s matches and counts the mandate as not current until a fetch judges the new text.
A response for a fund-oversight monitor whose portfolio holds the VanEck Semiconductor ETF (SMH), shortened to one item without its url and publisher:
Itoflow keeps items of impact 2 or more for 90 days, and others for 14 days. A company rating of notable or more keeps an item for 90 days. A monitor that doesn’t exist, isn’t yours, is being deleted, or has a malformed ID returns 404 with error: "NOT_FOUND", from both routes. An invalid limit or since returns 400 with error: "INVALID_REQUEST".

Models

Set model_key to a fusion mode or a single model when you create or edit a monitor; edits without it keep the saved choice. New monitors without a choice use the plan’s default_mode from /pricing/model-access. Each report pins both the main model and Guardian when it starts; retries keep those routes. A single choice uses that model for both agents. If you lose access to a paid choice, new runs stop with “Choose the Free model or upgrade” until you change the choice or upgrade. Fusion modes do not use a connected ChatGPT subscription. See models and plans. See the monitor endpoint reference for every field and error code.

Valuation earnings periods

Valuation leads with trailing price to earnings and its premium to the comparator. Trailing earnings use twelve-month figures where available, then last reported fiscal-year income converted into the listing currency at the rate on the report date (an approximation: the year was earned at that year’s rates). A figure can mix both periods; its detail states the weight using fiscal-year earnings. Forward earnings blend the current and next fiscal-year estimates; expected earnings growth divides the aggregate forward blend by the aggregate backward blend, following MSCI’s Fundamental Data Methodology. Losses retain their sign. Missing estimates leave forward figures absent while trailing figures can still publish. Historical reports keep their original figures, so the change in earnings periods can create a step in the series after release.