> ## Documentation Index
> Fetch the complete documentation index at: https://docs.itoflow.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Monitors

> Create research and fund-oversight monitors, schedule and run reports, and read the news feed.

> [!TIP]
>
> **The easiest way: ask your AI assistant.** With [Itoflow MCP](https://docs.itoflow.ai/mcp/install.md) connected to Claude or Codex, paste:
>
> ```text theme={null}
> Use Itoflow to create a research monitor for NVDA.US and TSM.US that reports
> material news and filings every weekday at 07:30 Europe/London. Show me the
> monitor before creating it, then enable it.
> ```
>
> > [card] [Open in Claude](https://claude.ai/new?q=Use%20the%20Itoflow%20plugin%20\(https%3A%2F%2Fgithub.com%2Fitoflow%2Fskills\)%20for%20this.%20If%20it%20isn't%20installed%20yet%2C%20first%20tell%20me%20how%20to%20install%20it%20and%20sign%20in%20to%20Itoflow%2C%20and%20wait%20until%20I%20confirm.%20Then%3A%0A%0AUse%20Itoflow%20to%20create%20a%20research%20monitor%20for%20NVDA.US%20and%20TSM.US%20that%20reports%20material%20news%20and%20filings%20every%20weekday%20at%2007%3A30%20Europe%2FLondon.%20Show%20me%20the%20monitor%20before%20creating%20it%2C%20then%20enable%20it.)
> >
> > Start this in Claude with the Itoflow plugin.
>
> > [card] [Open in ChatGPT](https://chatgpt.com/?q=Use%20the%20Itoflow%20plugin%20\(https%3A%2F%2Fgithub.com%2Fitoflow%2Fskills\)%20for%20this.%20If%20it%20isn't%20installed%20yet%2C%20first%20tell%20me%20how%20to%20install%20it%20and%20sign%20in%20to%20Itoflow%2C%20and%20wait%20until%20I%20confirm.%20Then%3A%0A%0AUse%20Itoflow%20to%20create%20a%20research%20monitor%20for%20NVDA.US%20and%20TSM.US%20that%20reports%20material%20news%20and%20filings%20every%20weekday%20at%2007%3A30%20Europe%2FLondon.%20Show%20me%20the%20monitor%20before%20creating%20it%2C%20then%20enable%20it.)
> >
> > 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](https://app.itoflow.ai/watchlists). 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.

```mermaid theme={null}
flowchart LR
  Session[One Monitor session] --> RunA[Execution A]
  Session --> RunB[Execution B]
  RunA --> ReportA[Zero or one report]
  RunB --> ReportB[Zero or one report]
```

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](https://app.itoflow.ai/watchlists/new) 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.

```mermaid theme={null}
flowchart TD
  Create[Create, paused] --> Edit[Set mandate and schedule]
  Edit --> Enable[Enable]
  Enable --> Queued[Report queued]
  Queued --> Running[Running]
  Running --> Complete[Completed]
  Running --> Failed[Failed or superseded]
```

## Create a research monitor

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

```json theme={null}
{
  "name": "Company updates",
  "mandate": "Summarize new company filings and explain material changes.",
  "symbols": ["AAPL.US", "MSFT.US"],
  "symbol_notes": { "AAPL.US": "Focus on reported revenue." },
  "recurrence": {
    "kind": "weekdays",
    "local_time": "09:00",
    "timezone": "America/New_York"
  },
  "model_key": "luna"
}
```

| Field | Rules |
| - | - |
| `name` | Required, 1–100 characters |
| `mandate` | Required, 1–50,000 characters |
| `symbols` | Up to 100 symbols in `TICKER.EXCHANGE` form. Omit it, or send `[]`, when the mandate defines the universe. |
| `symbol_notes` | Optional notes for individual symbols |
| `recurrence` | Optional schedule; see below |
| `model_key` | Optional; see [models and plans](https://docs.itoflow.ai/features/billing.md#models-and-plans) |

### 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.

```json theme={null}
{
  "name": "Infrastructure fund oversight",
  "mandate": "Lead with material changes and explain what caused them.",
  "profile": "fund_oversight",
  "profile_config": {
    "subject": {
      "name": "Infrastructure fund",
      "portfolio_id": "550e8400-e29b-41d4-a716-446655440000"
    },
    "comparators": {
      "benchmark": {
        "name": "Mid-cap benchmark",
        "index_symbol": "MID.INDX",
        "basket_symbol": "MDY.US"
      },
      "peer_funds": [{ "name": "Industrial sector peer", "symbol": "XLI.US" }]
    },
    "thresholds": {
      "comparator": "XLI.US",
      "relative_weight": { "sector": 15, "single_name": 6 },
      "tracking_error_budget": 4,
      "liquidity": { "participation": 0.1, "adtv_window_months": 3 },
      "aum_scenarios": [250, 500, 1000]
    }
  }
}
```

**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:

| Status | Meaning |
| - | - |
| `ok` | The section measured its figures. |
| `partial` | A requested figure is missing or a gap could change a figure shown. |
| `unavailable` | The section could not measure anything; its reason names the gap. |
| `not_configured` | The owner left out a role or limit the section needs, and the section has no subject figure to show. |

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

| Field | Unit | Example |
| - | - | - |
| `relative_weight.sector`, `relative_weight.single_name` | Percentage points over or under the comparator's weight | `6` = 6 points either way |
| `tracking_error_budget` | Percent | `4` = 4% |
| `cash_pct`, `single_issuer_pct`, `irs_5pct_bucket_pct` | Percent | `5` = 5% |
| `warning_fraction` | Fraction of the limit | `0.8` = warn at 80% of the limit |
| `liquidity.participation` | Fraction of daily traded value | `0.1` = 10% |
| `liquidity.adtv_window_months` | Calendar months | `3` |
| `liquidity.illiquid_days` | Trading days | `5` |
| `aum_scenarios` | Fund sizes, in millions of the report currency | `500` = 500 million |

**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

| Endpoint | What it does |
| - | - |
| `GET /watchlists` | Lists monitors you can see |
| `GET /watchlists/{id}` | One monitor, with its versions |
| `PUT /watchlists/{id}` | Changes fields; requires `change_description` |
| `POST /watchlists/{id}/fork` | Copies a monitor you can read into a new paused monitor you own |
| `DELETE /watchlists/{id}` | Deletes a monitor you own |

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`](https://docs.itoflow.ai/features/market-data#symbol-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:

```json theme={null}
{ "custom_message": "Focus today's summary on liquidity." }
```

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:

| Field | Meaning |
| - | - |
| `execution_id` | The run to follow |
| `watchlist_version_id` | The monitor version the run uses |
| `status` | `queued` or `running` |
| `joined_existing_run` | Whether you joined a run already in progress |
| `custom_message_applied` | Whether this run got your instruction |
| `report_date` | The date the report covers |

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

| Endpoint | Returns |
| - | - |
| `GET /watchlists/{id}/active-execution` | The run in progress, if any |
| `GET /watchlists/{id}/executions/{executionId}/results` | The results a run has shown so far |
| `GET /watchlists/{id}/reports` | Report history |
| `GET /watchlists/{id}/reports/latest` | The latest completed report |
| `GET /watchlists/{id}/reports/{reportId}` | One run's details |
| `GET /watchlists/{id}/analytics/latest` | The latest analytics snapshot |
| `GET /watchlists/{id}/quotes` | Cached quotes for the monitor's symbols |

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`.

```ts theme={null}
const [latest] = reports;
const detail = await get(
  `/watchlists/${monitorId}/reports/${latest.execution_id}`,
);
```

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.

| Query parameter | Meaning |
| - | - |
| `limit` | Items to return, 1–200. Default 200. There is no next page. |
| `since` | Only items with a holding or mandate match judged after this ISO 8601 time, newest first, each with all its matches. Include a time zone, such as `Z`. |

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.

```bash theme={null}
curl --fail-with-body --silent --show-error --request POST \
  'https://api.itoflow.ai/watchlists/3f2b8c1e-7a4d-4e5f-9b6a-2c8d1e0f4a7b/news/fetch' \
  --header "Authorization: Bearer $ITOFLOW_ACCESS_TOKEN"
```

```json theme={null}
{ "subjects": 12, "queued": 4 }
```

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.

```bash theme={null}
curl --fail-with-body --silent --show-error \
  'https://api.itoflow.ai/watchlists/3f2b8c1e-7a4d-4e5f-9b6a-2c8d1e0f4a7b/news?limit=20' \
  --header "Authorization: Bearer $ITOFLOW_ACCESS_TOKEN"
```

A response for a fund-oversight monitor whose portfolio holds the VanEck Semiconductor ETF (SMH), shortened to one item without its `url` and `publisher`:

```json theme={null}
{
  "items": [
    {
      "id": "8d0f3a52-6c1b-4e9a-b7d4-1f2e3a4b5c6d",
      "source": "gdelt",
      "title": "Micron raises its memory price outlook",
      "title_en": null,
      "language": "en",
      "published_at": "2026-09-25T13:45:00.000Z",
      "materiality": 2.6,
      "level": "material",
      "direction": "good",
      "direction_p": 0.82,
      "holdings": [
        {
          "symbol": "MU.US",
          "weight": 0.055,
          "materiality": 2.6,
          "level": "material",
          "direction": "good",
          "direction_p": 0.82
        },
        {
          "symbol": "NVDA.US",
          "weight": 0.225,
          "materiality": 1.3,
          "level": "minor",
          "direction": "unclear",
          "direction_p": 0.55
        }
      ],
      "mandate_p": 0.91,
      "is_event_p": 0.93,
      "impact": 2.4,
      "repeat_of": null,
      "judged_at": "2026-09-25T14:02:11.000Z"
    }
  ],
  "feed": {
    "last_success_at": "2026-09-25T14:00:00.000Z",
    "paused": false,
    "window_hours": 24,
    "largest_weight": 0.225,
    "judged_through": "2026-09-25T14:06:40.000Z",
    "coverage": { "subjects": 32, "current": 32 }
  }
}
```

| Field | Meaning |
| - | - |
| `source` | `gdelt` for English news, `gdelt_translingual` for news in other languages, `sec_edgar` for SEC filings |
| `url`, `title`, `language`, `publisher`, `published_at` | The article or filing. `title` is in its original language; `language` is a BCP 47 tag. `publisher` can be `null`. |
| `title_en` | The title in English; `null` when it's already in English or couldn't be translated |
| `holdings` | The monitor's holdings this item affects, highest score first, each with the item's rating for that company. Empty when only the mandate matched. |
| `weight` | The holding's share of the portfolio's net assets; shorts count by their size. `null` for research monitors and a portfolio worth nothing or less. An open holding without usable price, currency or exchange-rate evidence makes every weight `null`; in a live mirror valued at its broker total, only the weights of the companies it carries. |
| `valuation_unavailable_reason` | Why the weight is `null`: net assets are unknown or not positive, or an open holding that carries the company has no usable price. Omitted otherwise. Entry cost never replaces a current price. |
| `materiality` | How much the item could change the company's value, from 1 (minor) to 3 (material). Top-level rating fields repeat the top holding's rating, or are `null` when only the mandate matched. |
| `level` | `material` from 2.5, `notable` from 1.5, otherwise `minor` |
| `direction`, `direction_p` | `good`, `bad`, `mixed` or `unclear`, and how likely that direction is |
| `mandate_p` | How likely the item bears on the monitor's mandate; `null` when it doesn't match the mandate |
| `is_event_p` | How likely the item reports an event rather than commentary |
| `impact` | How much the news could move the companies or markets it concerns, from 0 (none) to 3 (material) |
| `repeat_of` | An earlier item about the same event, or `null` |
| `judged_at` | When Itoflow stored the item; the 24-hour window counts from it |
| `feed.last_success_at` | When the least recently updated news source was last read; `null` before the first read |
| `feed.paused` | `true` while the monitor is paused. A paused monitor still shows stored news and can fetch. |
| `feed.window_hours` | Hours of news covered: 24 |
| `feed.largest_weight` | The largest holding's weight, used in the score; `null` when company weights are unknown or for research monitors |
| `feed.judged_through` | The newest time a match was judged among matching items, including any beyond `limit`. `null` when nothing matched; keep your earlier value. |
| `feed.coverage` | `subjects`: the companies the monitor holds, plus its mandate. `current`: those judged through the last 24 hours. |

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](https://docs.itoflow.ai/features/billing.md#models-and-plans).

See the [monitor endpoint reference](https://docs.itoflow.ai/api-reference/coverage.md#monitors) 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.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.