# API coverage Source: https://docs.itoflow.ai/api-reference/coverage Find every documented product operation by feature. This reference covers **156 operations** across **13 feature areas**. Each endpoint page includes its parameters, request body, response schemas, authentication, and registered response codes. 5 read-only operations have a **Send** button so you can try them with your access token; the others show copyable examples. See [Try requests in these docs](/authentication#try-requests-in-these-docs). ## Account | Operation | Operation ID | Authentication | Try it | | - | - | - | - | | [`GET /auth/client-config`](/api-reference/endpoints/getauthclientconfig) | `getAuthClientConfig` | public | Send | | [`GET /auth/user`](/api-reference/endpoints/getauthuser) | `getAuthUser` | bearer | Send | | [`GET /codex-subscription`](/api-reference/endpoints/get__codex_subscription) | `get__codex_subscription` | bearer | | | [`POST /codex-subscription/start`](/api-reference/endpoints/post__codex_subscription_start) | `post__codex_subscription_start` | bearer | | | [`POST /codex-subscription/poll`](/api-reference/endpoints/post__codex_subscription_poll) | `post__codex_subscription_poll` | bearer | | | [`DELETE /codex-subscription`](/api-reference/endpoints/delete__codex_subscription) | `delete__codex_subscription` | bearer | | | [`GET /account/billing-costs`](/api-reference/endpoints/get__account_billing_costs) | `get__account_billing_costs` | bearer | | | [`GET /account/preferences`](/api-reference/endpoints/get__account_preferences) | `get__account_preferences` | bearer | | | [`PATCH /account/display-currency`](/api-reference/endpoints/patch__account_display_currency) | `patch__account_display_currency` | bearer | | ## Chat | Operation | Operation ID | Authentication | Try it | | - | - | - | - | | [`GET /chats`](/api-reference/endpoints/get__chats) | `get__chats` | bearer | | | [`GET /chat/{id}`](/api-reference/endpoints/get__chat_id_) | `get__chat_id_` | bearer | | | [`GET /chat-runtime/chats/{chatId}/workspace`](/api-reference/endpoints/listchatworkspacedirectory) | `listChatWorkspaceDirectory` | bearer | | | [`GET /chat-runtime/chats/{chatId}/downloads/workspace/{relativePath}`](/api-reference/endpoints/downloadchatworkspacefile) | `downloadChatWorkspaceFile` | bearer | | | [`GET /chat/{id}/events`](/api-reference/endpoints/get__chat_id_events) | `get__chat_id_events` | bearer | | | [`GET /chat/{id}/sync`](/api-reference/endpoints/get__chat_id_sync) | `get__chat_id_sync` | bearer | | | [`GET /dataframes/{chatId}/{dfName}`](/api-reference/endpoints/get__dataframes_chatid_dfname_) | `get__dataframes_chatId_dfName_` | bearer | | | [`POST /chat-shares`](/api-reference/endpoints/post__chat_shares) | `post__chat_shares` | bearer | | | [`GET /chat-shares/public/{slug}`](/api-reference/endpoints/get__chat_shares_public_slug_) | `get__chat_shares_public_slug_` | public | | | [`GET /chat-shares/public/{slug}/runtime-token`](/api-reference/endpoints/get__chat_shares_public_slug_runtime_token) | `get__chat_shares_public_slug_runtime_token` | public | | | [`GET /chat-shares/public/{slug}/dataframes/{dfId}`](/api-reference/endpoints/get__chat_shares_public_slug_dataframes_dfid_) | `get__chat_shares_public_slug_dataframes_dfId_` | public | | | [`GET /chat-shares/public/{slug}/plots/{plotId}`](/api-reference/endpoints/get__chat_shares_public_slug_plots_plotid_) | `get__chat_shares_public_slug_plots_plotId_` | public | | | [`DELETE /chat-runtime/chats/{chatId}`](/api-reference/endpoints/chat_delete) | `chat_delete` | bearer | | ## Portfolios | Operation | Operation ID | Authentication | Try it | | - | - | - | - | | [`GET /portfolios`](/api-reference/endpoints/get__portfolios) | `get__portfolios` | bearer | | | [`POST /portfolios`](/api-reference/endpoints/post__portfolios) | `post__portfolios` | bearer | | | [`GET /portfolios/{id}`](/api-reference/endpoints/get__portfolios_id_) | `get__portfolios_id_` | bearer | | | [`PUT /portfolios/{id}/benchmark`](/api-reference/endpoints/put__portfolios_id_benchmark) | `put__portfolios_id_benchmark` | bearer | | | [`DELETE /portfolios/{id}`](/api-reference/endpoints/delete__portfolios_id_) | `delete__portfolios_id_` | bearer | | | [`GET /portfolios/{id}/performance`](/api-reference/endpoints/get__portfolios_id_performance) | `get__portfolios_id_performance` | bearer | | | [`GET /portfolios/{id}/holdings/history`](/api-reference/endpoints/get__portfolios_id_holdings_history) | `get__portfolios_id_holdings_history` | bearer | | | [`GET /portfolios/{id}/trades`](/api-reference/endpoints/get__portfolios_id_trades) | `get__portfolios_id_trades` | bearer | | | [`GET /portfolios/{id}/decisions`](/api-reference/endpoints/get__portfolios_id_decisions) | `get__portfolios_id_decisions` | bearer | | | [`GET /portfolios/approvals/pending`](/api-reference/endpoints/get__portfolios_approvals_pending) | `get__portfolios_approvals_pending` | bearer | | | [`GET /portfolios/{id}/pending-trades`](/api-reference/endpoints/get__portfolios_id_pending_trades) | `get__portfolios_id_pending_trades` | bearer | | | [`DELETE /portfolios/{id}/pending-trades`](/api-reference/endpoints/delete__portfolios_id_pending_trades) | `delete__portfolios_id_pending_trades` | bearer | | | [`POST /portfolios/{id}/sync-live-state`](/api-reference/endpoints/post__portfolios_id_sync_live_state) | `post__portfolios_id_sync_live_state` | bearer | | | [`POST /portfolios/{id}/pending-trades/approve`](/api-reference/endpoints/post__portfolios_id_pending_trades_approve) | `post__portfolios_id_pending_trades_approve` | bearer | | | [`GET /portfolios/{id}/broker-status`](/api-reference/endpoints/get__portfolios_id_broker_status) | `get__portfolios_id_broker_status` | bearer | | | [`POST /portfolios/import/validate`](/api-reference/endpoints/post__portfolios_import_validate) | `post__portfolios_import_validate` | bearer | | | [`POST /portfolios/import`](/api-reference/endpoints/post__portfolios_import) | `post__portfolios_import` | bearer | | | [`POST /portfolios/{id}/liquidate`](/api-reference/endpoints/post__portfolios_id_liquidate) | `post__portfolios_id_liquidate` | bearer | | | [`GET /transition/{taskId}`](/api-reference/endpoints/get__transition_taskid_) | `get__transition_taskId_` | bearer | | | [`PATCH /portfolios/{id}/auto-execute`](/api-reference/endpoints/patch__portfolios_id_auto_execute) | `patch__portfolios_id_auto_execute` | bearer | | | [`POST /portfolios/{id}/reconcile`](/api-reference/endpoints/post__portfolios_id_reconcile) | `post__portfolios_id_reconcile` | bearer | | | [`POST /portfolios/{id}/go-paper`](/api-reference/endpoints/post__portfolios_id_go_paper) | `post__portfolios_id_go_paper` | bearer | | | [`GET /portfolios/{id}/trades/{tradeId}/attempts`](/api-reference/endpoints/get__portfolios_id_trades_tradeid_attempts) | `get__portfolios_id_trades_tradeId_attempts` | bearer | | ## Strategies | Operation | Operation ID | Authentication | Try it | | - | - | - | - | | [`PUT /portfolios/{id}/link`](/api-reference/endpoints/put__portfolios_id_link) | `put__portfolios_id_link` | bearer | | | [`DELETE /portfolios/{id}/link`](/api-reference/endpoints/delete__portfolios_id_link) | `delete__portfolios_id_link` | bearer | | | [`GET /strategies/public`](/api-reference/endpoints/get__strategies_public) | `get__strategies_public` | public | | | [`GET /strategies`](/api-reference/endpoints/get__strategies) | `get__strategies` | bearer | | | [`POST /strategies`](/api-reference/endpoints/post__strategies) | `post__strategies` | bearer | | | [`GET /strategies/eligible`](/api-reference/endpoints/get__strategies_eligible) | `get__strategies_eligible` | bearer | | | [`GET /strategies/{id}`](/api-reference/endpoints/get__strategies_id_) | `get__strategies_id_` | bearer | | | [`PUT /strategies/{id}`](/api-reference/endpoints/put__strategies_id_) | `put__strategies_id_` | bearer | | | [`POST /strategies/live`](/api-reference/endpoints/post__strategies_live) | `post__strategies_live` | bearer | | | [`POST /strategies/{id}/control`](/api-reference/endpoints/post__strategies_id_control) | `post__strategies_id_control` | bearer | | | [`POST /strategies/{id}/execute`](/api-reference/endpoints/post__strategies_id_execute) | `post__strategies_id_execute` | bearer | | | [`GET /strategies/{id}/active-execution`](/api-reference/endpoints/get__strategies_id_active_execution) | `get__strategies_id_active_execution` | bearer | | | [`GET /strategies/{id}/stream/{executionId}`](/api-reference/endpoints/get__strategies_id_stream_executionid_) | `get__strategies_id_stream_executionId_` | bearer | | | [`GET /strategies/{id}/executions/{executionId}/events`](/api-reference/endpoints/get__strategies_id_executions_executionid_events) | `get__strategies_id_executions_executionId_events` | bearer | | | [`GET /strategies/{id}/decisions/{decisionId}/events`](/api-reference/endpoints/get__strategies_id_decisions_decisionid_events) | `get__strategies_id_decisions_decisionId_events` | bearer | | | [`GET /strategies/{id}/executions`](/api-reference/endpoints/get__strategies_id_executions) | `get__strategies_id_executions` | bearer | | | [`GET /paper-trading/summaries`](/api-reference/endpoints/get__paper_trading_summaries) | `get__paper_trading_summaries` | bearer | | | [`GET /paper-trading/{strategyId}/status`](/api-reference/endpoints/get__paper_trading_strategyid_status) | `get__paper_trading_strategyId_status` | bearer | | | [`GET /paper-trading/{strategyId}/trades`](/api-reference/endpoints/get__paper_trading_strategyid_trades) | `get__paper_trading_strategyId_trades` | bearer | | | [`GET /paper-trading/{strategyId}/decisions`](/api-reference/endpoints/get__paper_trading_strategyid_decisions) | `get__paper_trading_strategyId_decisions` | bearer | | | [`GET /paper-trading/{strategyId}/approvals`](/api-reference/endpoints/get__paper_trading_strategyid_approvals) | `get__paper_trading_strategyId_approvals` | bearer | | | [`GET /paper-trading/{strategyId}/pending-trades`](/api-reference/endpoints/get__paper_trading_strategyid_pending_trades) | `get__paper_trading_strategyId_pending_trades` | bearer | | ## Sharing and data | Operation | Operation ID | Authentication | Try it | | - | - | - | - | | [`POST /artifacts`](/api-reference/endpoints/post__artifacts) | `post__artifacts` | bearer | | | [`GET /artifacts/public/{slug}`](/api-reference/endpoints/get__artifacts_public_slug_) | `get__artifacts_public_slug_` | public | | | [`GET /artifacts/public/{slug}/dataframes/{dfId}`](/api-reference/endpoints/get__artifacts_public_slug_dataframes_dfid_) | `get__artifacts_public_slug_dataframes_dfId_` | public | | | [`DELETE /artifacts/{slug}`](/api-reference/endpoints/delete__artifacts_slug_) | `delete__artifacts_slug_` | bearer | | ## Market data | Operation | Operation ID | Authentication | Try it | | - | - | - | - | | [`GET /symbols/resolve`](/api-reference/endpoints/getsymbolsresolve) | `getSymbolsResolve` | bearer | Send | | [`POST /symbols/resolve/batch`](/api-reference/endpoints/post__symbols_resolve_batch) | `post__symbols_resolve_batch` | bearer | | | [`GET /symbols/search`](/api-reference/endpoints/getsymbolssearch) | `getSymbolsSearch` | bearer | Send | | [`POST /symbols/quotes`](/api-reference/endpoints/post__symbols_quotes) | `post__symbols_quotes` | bearer | | | [`GET /symbols/baseline`](/api-reference/endpoints/get__symbols_baseline) | `get__symbols_baseline` | bearer | | | [`GET /symbols/analytics`](/api-reference/endpoints/get__symbols_analytics) | `get__symbols_analytics` | bearer | | | [`GET /symbols/exchanges`](/api-reference/endpoints/getsymbolsexchanges) | `getSymbolsExchanges` | bearer | Send | | [`GET /symbols/cache-status`](/api-reference/endpoints/get__symbols_cache_status) | `get__symbols_cache_status` | bearer | | | [`POST /factor-risk/covariance`](/api-reference/endpoints/post__factor_risk_covariance) | `post__factor_risk_covariance` | bearer | | | [`GET /news`](/api-reference/endpoints/get__news) | `get__news` | bearer | | | [`GET /benchmarks`](/api-reference/endpoints/get__benchmarks) | `get__benchmarks` | bearer | | | [`GET /fx-rates`](/api-reference/endpoints/get__fx_rates) | `get__fx_rates` | public | | | [`GET /leaderboard`](/api-reference/endpoints/get__leaderboard) | `get__leaderboard` | bearer | | | [`GET /fx-rate`](/api-reference/endpoints/get__fx_rate) | `get__fx_rate` | public | | ## Billing | Operation | Operation ID | Authentication | Try it | | - | - | - | - | | [`GET /pricing/config`](/api-reference/endpoints/get__pricing_config) | `get__pricing_config` | public | | | [`POST /pricing/get-plans`](/api-reference/endpoints/post__pricing_get_plans) | `post__pricing_get_plans` | bearer | | | [`POST /pricing/get-subscription`](/api-reference/endpoints/post__pricing_get_subscription) | `post__pricing_get_subscription` | bearer | | | [`POST /pricing/update-subscription`](/api-reference/endpoints/post__pricing_update_subscription) | `post__pricing_update_subscription` | bearer | | | [`POST /pricing/billing-portal`](/api-reference/endpoints/post__pricing_billing_portal) | `post__pricing_billing_portal` | bearer | | | [`GET /pricing/payment-methods`](/api-reference/endpoints/get__pricing_payment_methods) | `get__pricing_payment_methods` | bearer | | | [`POST /pricing/payment-methods/setup-intent`](/api-reference/endpoints/post__pricing_payment_methods_setup_intent) | `post__pricing_payment_methods_setup_intent` | bearer | | | [`DELETE /pricing/payment-methods/{paymentMethodId}`](/api-reference/endpoints/delete__pricing_payment_methods_paymentmethodid_) | `delete__pricing_payment_methods_paymentMethodId_` | bearer | | | [`POST /pricing/payment-methods/default`](/api-reference/endpoints/post__pricing_payment_methods_default) | `post__pricing_payment_methods_default` | bearer | | | [`GET /pricing/invoices`](/api-reference/endpoints/get__pricing_invoices) | `get__pricing_invoices` | bearer | | | [`GET /pricing/customer-balance`](/api-reference/endpoints/get__pricing_customer_balance) | `get__pricing_customer_balance` | bearer | | | [`GET /pricing/billing-summary`](/api-reference/endpoints/get__pricing_billing_summary) | `get__pricing_billing_summary` | bearer | | | [`POST /pricing/refund-balance`](/api-reference/endpoints/post__pricing_refund_balance) | `post__pricing_refund_balance` | bearer | | | [`POST /pricing/preview-upgrade`](/api-reference/endpoints/post__pricing_preview_upgrade) | `post__pricing_preview_upgrade` | bearer | | | [`POST /pricing/confirm-payment`](/api-reference/endpoints/post__pricing_confirm_payment) | `post__pricing_confirm_payment` | bearer | | | [`POST /pricing/spending-cap`](/api-reference/endpoints/post__pricing_spending_cap) | `post__pricing_spending_cap` | bearer | | | [`GET /pricing/credit-tiers`](/api-reference/endpoints/get__pricing_credit_tiers) | `get__pricing_credit_tiers` | bearer | | | [`GET /pricing/catalog`](/api-reference/endpoints/get__pricing_catalog) | `get__pricing_catalog` | public | | | [`GET /pricing/model-access`](/api-reference/endpoints/get__pricing_model_access) | `get__pricing_model_access` | bearer | | ## Monitors | Operation | Operation ID | Authentication | Try it | | - | - | - | - | | [`POST /watchlists`](/api-reference/endpoints/post__watchlists) | `post__watchlists` | bearer | | | [`GET /watchlists`](/api-reference/endpoints/get__watchlists) | `get__watchlists` | bearer | | | [`GET /watchlists/{id}`](/api-reference/endpoints/get__watchlists_id_) | `get__watchlists_id_` | bearer | | | [`PUT /watchlists/{id}`](/api-reference/endpoints/put__watchlists_id_) | `put__watchlists_id_` | bearer | | | [`DELETE /watchlists/{id}`](/api-reference/endpoints/delete__watchlists_id_) | `delete__watchlists_id_` | bearer | | | [`POST /watchlists/{id}/fork`](/api-reference/endpoints/post__watchlists_id_fork) | `post__watchlists_id_fork` | bearer | | | [`POST /watchlists/{id}/control`](/api-reference/endpoints/post__watchlists_id_control) | `post__watchlists_id_control` | bearer | | | [`GET /watchlists/{id}/analytics/latest`](/api-reference/endpoints/get__watchlists_id_analytics_latest) | `get__watchlists_id_analytics_latest` | bearer | | | [`GET /watchlists/{id}/quotes`](/api-reference/endpoints/get__watchlists_id_quotes) | `get__watchlists_id_quotes` | bearer | | | [`GET /watchlists/{id}/reports`](/api-reference/endpoints/get__watchlists_id_reports) | `get__watchlists_id_reports` | bearer | | | [`GET /watchlists/{id}/active-execution`](/api-reference/endpoints/get__watchlists_id_active_execution) | `get__watchlists_id_active_execution` | bearer | | | [`GET /watchlists/{id}/executions/{executionId}/results`](/api-reference/endpoints/get__watchlists_id_executions_executionid_results) | `get__watchlists_id_executions_executionId_results` | bearer | | | [`GET /watchlists/{id}/reports/latest`](/api-reference/endpoints/get__watchlists_id_reports_latest) | `get__watchlists_id_reports_latest` | bearer | | | [`POST /watchlists/{id}/reports/run`](/api-reference/endpoints/post__watchlists_id_reports_run) | `post__watchlists_id_reports_run` | bearer | | | [`GET /watchlists/{id}/reports/{reportId}`](/api-reference/endpoints/get__watchlists_id_reports_reportid_) | `get__watchlists_id_reports_reportId_` | bearer | | | [`GET /watchlists/{id}/news`](/api-reference/endpoints/getmonitornews) | `getMonitorNews` | bearer | | | [`POST /watchlists/{id}/news/fetch`](/api-reference/endpoints/fetchmonitornews) | `fetchMonitorNews` | bearer | | ## Notifications | Operation | Operation ID | Authentication | Try it | | - | - | - | - | | [`GET /notifications/preferences`](/api-reference/endpoints/get__notifications_preferences) | `get__notifications_preferences` | bearer | | | [`PUT /notifications/preferences`](/api-reference/endpoints/put__notifications_preferences) | `put__notifications_preferences` | bearer | | | [`POST /notifications/unsubscribe`](/api-reference/endpoints/post__notifications_unsubscribe) | `post__notifications_unsubscribe` | bearer | | | [`GET /notifications/logs`](/api-reference/endpoints/get__notifications_logs) | `get__notifications_logs` | bearer | | ## Brokers | Operation | Operation ID | Authentication | Try it | | - | - | - | - | | [`GET /brokers/connections`](/api-reference/endpoints/get__brokers_connections) | `get__brokers_connections` | bearer | | | [`POST /brokers/connect`](/api-reference/endpoints/post__brokers_connect) | `post__brokers_connect` | bearer | | | [`GET /brokers/{connectionId}/status`](/api-reference/endpoints/get__brokers_connectionid_status) | `get__brokers_connectionId_status` | bearer | | | [`POST /brokers/{connectionId}/reconnect`](/api-reference/endpoints/post__brokers_connectionid_reconnect) | `post__brokers_connectionId_reconnect` | bearer | | | [`POST /brokers/trading212/connect-manual`](/api-reference/endpoints/post__brokers_trading212_connect_manual) | `post__brokers_trading212_connect_manual` | bearer | | | [`POST /brokers/{connectionId}/trading212/reconnect`](/api-reference/endpoints/post__brokers_connectionid_trading212_reconnect) | `post__brokers_connectionId_trading212_reconnect` | bearer | | | [`POST /brokers/{connectionId}/trading212/reconnect-stored`](/api-reference/endpoints/post__brokers_connectionid_trading212_reconnect_stored) | `post__brokers_connectionId_trading212_reconnect_stored` | bearer | | | [`GET /brokers/{connectionId}/holdings`](/api-reference/endpoints/get__brokers_connectionid_holdings) | `get__brokers_connectionId_holdings` | bearer | | | [`GET /brokers/{connectionId}/margins`](/api-reference/endpoints/get__brokers_connectionid_margins) | `get__brokers_connectionId_margins` | bearer | | | [`DELETE /brokers/{connectionId}`](/api-reference/endpoints/delete__brokers_connectionid_) | `delete__brokers_connectionId_` | bearer | | ## GitHub | Operation | Operation ID | Authentication | Try it | | - | - | - | - | | [`GET /integrations/github/availability`](/api-reference/endpoints/githubavailability) | `githubAvailability` | bearer | | | [`POST /integrations/github/getConnection`](/api-reference/endpoints/github_getconnection) | `github_getConnection` | bearer | | | [`POST /integrations/github/connect`](/api-reference/endpoints/github_connect) | `github_connect` | bearer | | | [`POST /integrations/github/disconnect`](/api-reference/endpoints/github_disconnect) | `github_disconnect` | bearer | | | [`POST /integrations/github/listRepositories`](/api-reference/endpoints/github_listrepositories) | `github_listRepositories` | bearer | | ## Connected MCP servers | Operation | Operation ID | Authentication | Try it | | - | - | - | - | | [`GET /integrations/remote-mcp/availability`](/api-reference/endpoints/remotemcpavailability) | `remoteMcpAvailability` | bearer | | | [`POST /integrations/remote-mcp/list`](/api-reference/endpoints/remotemcp_list) | `remoteMcp_list` | bearer | | | [`POST /integrations/remote-mcp/add`](/api-reference/endpoints/remotemcp_add) | `remoteMcp_add` | bearer | | | [`POST /integrations/remote-mcp/rename`](/api-reference/endpoints/remotemcp_rename) | `remoteMcp_rename` | bearer | | | [`POST /integrations/remote-mcp/connect`](/api-reference/endpoints/remotemcp_connect) | `remoteMcp_connect` | bearer | | | [`POST /integrations/remote-mcp/getStatus`](/api-reference/endpoints/remotemcp_getstatus) | `remoteMcp_getStatus` | bearer | | | [`POST /integrations/remote-mcp/listTools`](/api-reference/endpoints/remotemcp_listtools) | `remoteMcp_listTools` | bearer | | | [`POST /integrations/remote-mcp/disconnect`](/api-reference/endpoints/remotemcp_disconnect) | `remoteMcp_disconnect` | bearer | | | [`POST /integrations/remote-mcp/remove`](/api-reference/endpoints/remotemcp_remove) | `remoteMcp_remove` | bearer | | ## Risk runs | Operation | Operation ID | Authentication | Try it | | - | - | - | - | | [`POST /risk/runs`](/api-reference/endpoints/startriskrun) | `startRiskRun` | bearer | | | [`GET /risk/runs/{run_id}`](/api-reference/endpoints/getriskrun) | `getRiskRun` | bearer | | | [`GET /risk/runs/{run_id}/artifact`](/api-reference/endpoints/getriskrunartifact) | `getRiskRunArtifact` | bearer | | | [`POST /risk/runs/{run_id}/cancel`](/api-reference/endpoints/cancelriskrun) | `cancelRiskRun` | bearer | | | [`POST /risk/measure`](/api-reference/endpoints/startriskmeasure) | `startRiskMeasure` | bearer | | | [`GET /risk/measure/{measure_id}`](/api-reference/endpoints/getriskmeasure) | `getRiskMeasure` | bearer | | | [`POST /risk/measure/{measure_id}/cancel`](/api-reference/endpoints/cancelriskmeasure) | `cancelRiskMeasure` | bearer | | ## Coverage boundaries This reference leaves out service callbacks, provider webhooks, health and debug endpoints, and sign-in redirect handlers. Some response objects can contain fields beyond those listed. See [authentication](/authentication) and [SDKs](/sdk/overview). # Stop a risk measure Source: https://docs.itoflow.ai/api-reference/endpoints/cancelriskmeasure /openapi/itoflow-public.openapi.json post /risk/measure/{measure_id}/cancel Stop a measure by its measure_id. cancelled is false when it had already ended. Operation ID: cancelRiskMeasure. # Stop a risk run Source: https://docs.itoflow.ai/api-reference/endpoints/cancelriskrun /openapi/itoflow-public.openapi.json post /risk/runs/{run_id}/cancel Stop a run by its run_id. cancelled is false when no run is going. Requires itoflow-engine-results. Operation ID: cancelRiskRun. # Permanently delete a chat Source: https://docs.itoflow.ai/api-reference/endpoints/chat_delete /openapi/itoflow-public.openapi.json delete /chat-runtime/chats/{chatId} Permanently delete one of your chats and the files in its workspace. Account integrations stay connected. If the response is lost, retry the same delete for the same chat ID. Operation ID: chat_delete. # Archive a shareable artifact Source: https://docs.itoflow.ai/api-reference/endpoints/delete__artifacts_slug_ /openapi/itoflow-public.openapi.json delete /artifacts/{slug} Archives an artifact owned by the authenticated user. Archived artifacts disappear from public access immediately. Operation ID: delete__artifacts_slug_. # Disconnect broker Source: https://docs.itoflow.ai/api-reference/endpoints/delete__brokers_connectionid_ /openapi/itoflow-public.openapi.json delete /brokers/{connectionId} Operation ID: delete__brokers_connectionId_. # Disconnect the subscription and revoke it at the provider Source: https://docs.itoflow.ai/api-reference/endpoints/delete__codex_subscription /openapi/itoflow-public.openapi.json delete /codex-subscription Operation ID: delete__codex_subscription. # Delete portfolio Source: https://docs.itoflow.ai/api-reference/endpoints/delete__portfolios_id_ /openapi/itoflow-public.openapi.json delete /portfolios/{id} Operation ID: delete__portfolios_id_. # Remove strategy from portfolio Source: https://docs.itoflow.ai/api-reference/endpoints/delete__portfolios_id_link /openapi/itoflow-public.openapi.json delete /portfolios/{id}/link Removes a removable strategy relationship and cancels any pending trades from the previous strategy. Operation ID: delete__portfolios_id_link. # Cancel pending trades Source: https://docs.itoflow.ai/api-reference/endpoints/delete__portfolios_id_pending_trades /openapi/itoflow-public.openapi.json delete /portfolios/{id}/pending-trades Operation ID: delete__portfolios_id_pending_trades. # Delete payment method Source: https://docs.itoflow.ai/api-reference/endpoints/delete__pricing_payment_methods_paymentmethodid_ /openapi/itoflow-public.openapi.json delete /pricing/payment-methods/{paymentMethodId} Operation ID: delete__pricing_payment_methods_paymentMethodId_. # Delete monitor Source: https://docs.itoflow.ai/api-reference/endpoints/delete__watchlists_id_ /openapi/itoflow-public.openapi.json delete /watchlists/{id} Operation ID: delete__watchlists_id_. # Download a file a chat saved in its workspace Source: https://docs.itoflow.ai/api-reference/endpoints/downloadchatworkspacefile /openapi/itoflow-public.openapi.json get /chat-runtime/chats/{chatId}/downloads/workspace/{relativePath} Downloads one file a chat saved in its workspace, such as a report, chart or CSV file. List the chat's workspace first to find the file's path. Operation ID: downloadChatWorkspaceFile. # Fetch news for a monitor Source: https://docs.itoflow.ai/api-reference/endpoints/fetchmonitornews /openapi/itoflow-public.openapi.json post /watchlists/{id}/news/fetch Asks Itoflow to judge the last 24 hours of news for a monitor's subjects that are behind: the companies it holds and its mandate. It returns at once; judging runs in the background, usually within a few minutes. Then call `getMonitorNews` every few seconds until `feed.coverage.current` equals `feed.coverage.subjects`. A paused monitor fetches too. Calling again while judging runs is safe: a subject being judged is skipped, and one judged since is not judged again. A missing monitor, one you do not own, and one being deleted all return the same 404. Operation ID: fetchMonitorNews. # Get billing costs Source: https://docs.itoflow.ai/api-reference/endpoints/get__account_billing_costs /openapi/itoflow-public.openapi.json get /account/billing-costs Agent usage and credits for the current billing period. Operation ID: get__account_billing_costs. # Get account display preferences Source: https://docs.itoflow.ai/api-reference/endpoints/get__account_preferences /openapi/itoflow-public.openapi.json get /account/preferences Operation ID: get__account_preferences. # Read a public artifact Source: https://docs.itoflow.ai/api-reference/endpoints/get__artifacts_public_slug_ /openapi/itoflow-public.openapi.json get /artifacts/public/{slug} Returns a public shareable dashboard artifact by slug. Operation ID: get__artifacts_public_slug_. # Read a public artifact dataframe snapshot Source: https://docs.itoflow.ai/api-reference/endpoints/get__artifacts_public_slug_dataframes_dfid_ /openapi/itoflow-public.openapi.json get /artifacts/public/{slug}/dataframes/{dfId} Returns paginated rows for a dataframe snapshot embedded in a public artifact. Operation ID: get__artifacts_public_slug_dataframes_dfId_. # List benchmark index prices to compare performance Source: https://docs.itoflow.ai/api-reference/endpoints/get__benchmarks /openapi/itoflow-public.openapi.json get /benchmarks Lists prices and returns over time for the market benchmarks Itoflow tracks, such as the S&P 500 and NASDAQ 100, so you can compare a strategy or portfolio against the market. Returns are measured from the first price in the range. Operation ID: get__benchmarks. # Get broker holdings Source: https://docs.itoflow.ai/api-reference/endpoints/get__brokers_connectionid_holdings /openapi/itoflow-public.openapi.json get /brokers/{connectionId}/holdings Operation ID: get__brokers_connectionId_holdings. # Get broker margins Source: https://docs.itoflow.ai/api-reference/endpoints/get__brokers_connectionid_margins /openapi/itoflow-public.openapi.json get /brokers/{connectionId}/margins Operation ID: get__brokers_connectionId_margins. # Get broker connection status Source: https://docs.itoflow.ai/api-reference/endpoints/get__brokers_connectionid_status /openapi/itoflow-public.openapi.json get /brokers/{connectionId}/status Operation ID: get__brokers_connectionId_status. # List broker connections Source: https://docs.itoflow.ai/api-reference/endpoints/get__brokers_connections /openapi/itoflow-public.openapi.json get /brokers/connections Operation ID: get__brokers_connections. # Get chat Source: https://docs.itoflow.ai/api-reference/endpoints/get__chat_id_ /openapi/itoflow-public.openapi.json get /chat/{id} Read one of your chats and its saved messages. Saved history can trail a turn that is still running; use MCP agent.getTurn for live turn state. Operation ID: get__chat_id_. # Get chat events Source: https://docs.itoflow.ai/api-reference/endpoints/get__chat_id_events /openapi/itoflow-public.openapi.json get /chat/{id}/events Returns the same saved chat history as GET /chat/{id}. This is not a live event stream. Operation ID: get__chat_id_events. # Sync chat state Source: https://docs.itoflow.ai/api-reference/endpoints/get__chat_id_sync /openapi/itoflow-public.openapi.json get /chat/{id}/sync Read the saved task count, status and event sequence for one of your chats. This does not resume a live stream. Operation ID: get__chat_id_sync. # Read a public chat share Source: https://docs.itoflow.ai/api-reference/endpoints/get__chat_shares_public_slug_ /openapi/itoflow-public.openapi.json get /chat-shares/public/{slug} Returns a read-only public chat transcript snapshot by slug. Operation ID: get__chat_shares_public_slug_. # Read a public chat share dataframe snapshot Source: https://docs.itoflow.ai/api-reference/endpoints/get__chat_shares_public_slug_dataframes_dfid_ /openapi/itoflow-public.openapi.json get /chat-shares/public/{slug}/dataframes/{dfId} Returns paginated rows for a dataframe snapshot embedded in a public chat share. Operation ID: get__chat_shares_public_slug_dataframes_dfId_. # Read a public chat share plot snapshot Source: https://docs.itoflow.ai/api-reference/endpoints/get__chat_shares_public_slug_plots_plotid_ /openapi/itoflow-public.openapi.json get /chat-shares/public/{slug}/plots/{plotId} Returns immutable Plotly JSON for a plot snapshot embedded in a public chat share. Operation ID: get__chat_shares_public_slug_plots_plotId_. # Refresh a public chat share viewing token Source: https://docs.itoflow.ai/api-reference/endpoints/get__chat_shares_public_slug_runtime_token /openapi/itoflow-public.openapi.json get /chat-shares/public/{slug}/runtime-token Returns a short-lived read-only token for viewing a public chat share. Operation ID: get__chat_shares_public_slug_runtime_token. # List chats Source: https://docs.itoflow.ai/api-reference/endpoints/get__chats /openapi/itoflow-public.openapi.json get /chats Lists your own chats, most recently active first, with the id and title of each chat. Use it to find an earlier chat, then read that chat or its files. Set runtime=cloudflare for current chats or runtime=api for older archived chats; omit runtime to list both. Operation ID: get__chats. # Get the current user Codex subscription connection Source: https://docs.itoflow.ai/api-reference/endpoints/get__codex_subscription /openapi/itoflow-public.openapi.json get /codex-subscription Operation ID: get__codex_subscription. # Get dataframe data Source: https://docs.itoflow.ai/api-reference/endpoints/get__dataframes_chatid_dfname_ /openapi/itoflow-public.openapi.json get /dataframes/{chatId}/{dfName} Operation ID: get__dataframes_chatId_dfName_. # Get the exchange rate between two currencies Source: https://docs.itoflow.ai/api-reference/endpoints/get__fx_rate /openapi/itoflow-public.openapi.json get /fx-rate Returns the current exchange rate between two currencies, for example USD to GBP. Multiply an amount in the from currency by rate to convert it to the to currency. Returns 503 when no rate is available. Operation ID: get__fx_rate. # Get current exchange rates for all supported currencies Source: https://docs.itoflow.ai/api-reference/endpoints/get__fx_rates /openapi/itoflow-public.openapi.json get /fx-rates Returns current exchange rates for every supported currency against the US dollar, for example how many euros or pounds one dollar buys. Use it to convert amounts between currencies. stale is true when the latest refresh failed and older rates are returned. Operation ID: get__fx_rates. # Get anonymous strategy leaderboard Source: https://docs.itoflow.ai/api-reference/endpoints/get__leaderboard /openapi/itoflow-public.openapi.json get /leaderboard Returns anonymized strategy performance rankings and weekly/monthly champions. Only the requesting user can see which rows are theirs. Operation ID: get__leaderboard. # Search stored news by query, symbol or monitor Source: https://docs.itoflow.ai/api-reference/endpoints/get__news /openapi/itoflow-public.openapi.json get /news Searches the company, market and economic news and SEC filings Itoflow has stored. It selects possible matches by similarity, including items without a vector, then a model judges those candidates by meaning in any language. With `q`, the route returns one row per story, most important first. With `symbols` or `monitor_id`, a model rates matching candidates for each company, counting news about its rivals, customers, suppliers, inputs and market; then the route returns the rated items, newest first. With `monitor_id`, results are limited to that monitor’s current holdings and carry their weights. With `q`, the model judges the most important candidates first and stops once the rest could not change the rows. Judging stops after about 25 seconds; `coverage.complete` says whether the reply is final. Operation ID: get__news. # List notification logs Source: https://docs.itoflow.ai/api-reference/endpoints/get__notifications_logs /openapi/itoflow-public.openapi.json get /notifications/logs Operation ID: get__notifications_logs. # Get notification preferences Source: https://docs.itoflow.ai/api-reference/endpoints/get__notifications_preferences /openapi/itoflow-public.openapi.json get /notifications/preferences Operation ID: get__notifications_preferences. # Get strategy approvals history Source: https://docs.itoflow.ai/api-reference/endpoints/get__paper_trading_strategyid_approvals /openapi/itoflow-public.openapi.json get /paper-trading/{strategyId}/approvals Returns historical live approval proposals for a strategy. Operation ID: get__paper_trading_strategyId_approvals. # Get strategy decision history Source: https://docs.itoflow.ai/api-reference/endpoints/get__paper_trading_strategyid_decisions /openapi/itoflow-public.openapi.json get /paper-trading/{strategyId}/decisions Returns decision history with pagination for a specific strategy. Operation ID: get__paper_trading_strategyId_decisions. # Get strategy pending trades Source: https://docs.itoflow.ai/api-reference/endpoints/get__paper_trading_strategyid_pending_trades /openapi/itoflow-public.openapi.json get /paper-trading/{strategyId}/pending-trades Operation ID: get__paper_trading_strategyId_pending_trades. # Get strategy performance snapshot Source: https://docs.itoflow.ai/api-reference/endpoints/get__paper_trading_strategyid_status /openapi/itoflow-public.openapi.json get /paper-trading/{strategyId}/status Returns the latest strategy performance, holdings, scorecard, and performance history. Operation ID: get__paper_trading_strategyId_status. # Get strategy trade history Source: https://docs.itoflow.ai/api-reference/endpoints/get__paper_trading_strategyid_trades /openapi/itoflow-public.openapi.json get /paper-trading/{strategyId}/trades Returns executed trade history for a specific strategy. Operation ID: get__paper_trading_strategyId_trades. # Get paper trading portfolio summaries Source: https://docs.itoflow.ai/api-reference/endpoints/get__paper_trading_summaries /openapi/itoflow-public.openapi.json get /paper-trading/summaries Returns strategy summaries without trade or decision history. Operation ID: get__paper_trading_summaries. # List user portfolios Source: https://docs.itoflow.ai/api-reference/endpoints/get__portfolios /openapi/itoflow-public.openapi.json get /portfolios Returns all active portfolios for the authenticated user with holdings value, cumulative return, and strategy linking info. Operation ID: get__portfolios. # List pending approval summaries Source: https://docs.itoflow.ai/api-reference/endpoints/get__portfolios_approvals_pending /openapi/itoflow-public.openapi.json get /portfolios/approvals/pending Returns one aggregate pending-approval summary across owned portfolios without fetching full per-portfolio trade detail. Operation ID: get__portfolios_approvals_pending. # Get portfolio detail Source: https://docs.itoflow.ai/api-reference/endpoints/get__portfolios_id_ /openapi/itoflow-public.openapi.json get /portfolios/{id} Returns portfolio with full holdings, P&L, linked strategy details, performance metrics, and agent scorecard. Operation ID: get__portfolios_id_. # Get broker validation status Source: https://docs.itoflow.ai/api-reference/endpoints/get__portfolios_id_broker_status /openapi/itoflow-public.openapi.json get /portfolios/{id}/broker-status Returns live broker connection and portfolio validation status for a live portfolio mirror. Operation ID: get__portfolios_id_broker_status. # Get AI trading decisions Source: https://docs.itoflow.ai/api-reference/endpoints/get__portfolios_id_decisions /openapi/itoflow-public.openapi.json get /portfolios/{id}/decisions Returns AI trading decisions for the portfolio's linked strategy. Empty array if not linked. Operation ID: get__portfolios_id_decisions. # Get historical holdings snapshot Source: https://docs.itoflow.ai/api-reference/endpoints/get__portfolios_id_holdings_history /openapi/itoflow-public.openapi.json get /portfolios/{id}/holdings/history Returns holdings at a point in time. Requires the "at" query parameter (ISO 8601 timestamp). Operation ID: get__portfolios_id_holdings_history. # List pending trades Source: https://docs.itoflow.ai/api-reference/endpoints/get__portfolios_id_pending_trades /openapi/itoflow-public.openapi.json get /portfolios/{id}/pending-trades Returns pending trades awaiting approval for a portfolio, with current prices, net change, and auto-execute status. Operation ID: get__portfolios_id_pending_trades. # Get portfolio performance history Source: https://docs.itoflow.ai/api-reference/endpoints/get__portfolios_id_performance /openapi/itoflow-public.openapi.json get /portfolios/{id}/performance Returns performance history with timestamps, total value, daily/cumulative returns, and strategy attribution periods. Operation ID: get__portfolios_id_performance. # Get trade history Source: https://docs.itoflow.ai/api-reference/endpoints/get__portfolios_id_trades /openapi/itoflow-public.openapi.json get /portfolios/{id}/trades Returns paginated trade history for a portfolio. Supports paper and live (broker) trades with optional pending trade inclusion. Operation ID: get__portfolios_id_trades. # Get trade execution attempts Source: https://docs.itoflow.ai/api-reference/endpoints/get__portfolios_id_trades_tradeid_attempts /openapi/itoflow-public.openapi.json get /portfolios/{id}/trades/{tradeId}/attempts Operation ID: get__portfolios_id_trades_tradeId_attempts. # Get billing summary Source: https://docs.itoflow.ai/api-reference/endpoints/get__pricing_billing_summary /openapi/itoflow-public.openapi.json get /pricing/billing-summary Operation ID: get__pricing_billing_summary. # Get current public plan prices, usage allowances and model access Source: https://docs.itoflow.ai/api-reference/endpoints/get__pricing_catalog /openapi/itoflow-public.openapi.json get /pricing/catalog Operation ID: get__pricing_catalog. # Get pricing configuration Source: https://docs.itoflow.ai/api-reference/endpoints/get__pricing_config /openapi/itoflow-public.openapi.json get /pricing/config Operation ID: get__pricing_config. # List credit tiers Source: https://docs.itoflow.ai/api-reference/endpoints/get__pricing_credit_tiers /openapi/itoflow-public.openapi.json get /pricing/credit-tiers Operation ID: get__pricing_credit_tiers. # Get customer balance Source: https://docs.itoflow.ai/api-reference/endpoints/get__pricing_customer_balance /openapi/itoflow-public.openapi.json get /pricing/customer-balance Operation ID: get__pricing_customer_balance. # List invoices Source: https://docs.itoflow.ai/api-reference/endpoints/get__pricing_invoices /openapi/itoflow-public.openapi.json get /pricing/invoices Operation ID: get__pricing_invoices. # Get configured agent models and current model access Source: https://docs.itoflow.ai/api-reference/endpoints/get__pricing_model_access /openapi/itoflow-public.openapi.json get /pricing/model-access Operation ID: get__pricing_model_access. # List payment methods Source: https://docs.itoflow.ai/api-reference/endpoints/get__pricing_payment_methods /openapi/itoflow-public.openapi.json get /pricing/payment-methods Operation ID: get__pricing_payment_methods. # List strategies visible to user Source: https://docs.itoflow.ai/api-reference/endpoints/get__strategies /openapi/itoflow-public.openapi.json get /strategies Returns Itoflow-created strategies plus user-owned strategies. Supports filtering by active status, Itoflow-only, or user-only. Operation ID: get__strategies. # List strategies that can go live at a broker Source: https://docs.itoflow.ai/api-reference/endpoints/get__strategies_eligible /openapi/itoflow-public.openapi.json get /strategies/eligible Lists the strategies you can see that are ready to go live and trade with real money at a broker, such as Trading 212 or Robinhood. Pass broker_connection_id for brokers that check each symbol, such as Trading 212. A strategy is listed when the broker supports every symbol in its latest target allocation and every non-cash holding in its paper portfolio. Books that hold a short are excluded because live short sales are not supported. Operation ID: get__strategies_eligible. # Get strategy detail Source: https://docs.itoflow.ai/api-reference/endpoints/get__strategies_id_ /openapi/itoflow-public.openapi.json get /strategies/{id} Returns a single strategy with full detail. User must own the strategy or it must be an Itoflow-created strategy. Operation ID: get__strategies_id_. # Get the strategy run in progress Source: https://docs.itoflow.ai/api-reference/endpoints/get__strategies_id_active_execution /openapi/itoflow-public.openapi.json get /strategies/{id}/active-execution Returns the strategy run that is in progress right now, if any, with its execution_id and status. Returns 204 when no run is in progress. Use the execution_id to stream or read the events of that run. Operation ID: get__strategies_id_active_execution. # Get strategy decision events Source: https://docs.itoflow.ai/api-reference/endpoints/get__strategies_id_decisions_decisionid_events /openapi/itoflow-public.openapi.json get /strategies/{id}/decisions/{decisionId}/events Operation ID: get__strategies_id_decisions_decisionId_events. # List strategy executions Source: https://docs.itoflow.ai/api-reference/endpoints/get__strategies_id_executions /openapi/itoflow-public.openapi.json get /strategies/{id}/executions Operation ID: get__strategies_id_executions. # Get strategy execution events Source: https://docs.itoflow.ai/api-reference/endpoints/get__strategies_id_executions_executionid_events /openapi/itoflow-public.openapi.json get /strategies/{id}/executions/{executionId}/events Operation ID: get__strategies_id_executions_executionId_events. # Stream strategy execution events Source: https://docs.itoflow.ai/api-reference/endpoints/get__strategies_id_stream_executionid_ /openapi/itoflow-public.openapi.json get /strategies/{id}/stream/{executionId} Operation ID: get__strategies_id_stream_executionId_. # List public strategy showcase Source: https://docs.itoflow.ai/api-reference/endpoints/get__strategies_public /openapi/itoflow-public.openapi.json get /strategies/public Operation ID: get__strategies_public. # Get latest analytics for a list of symbols Source: https://docs.itoflow.ai/api-reference/endpoints/get__symbols_analytics /openapi/itoflow-public.openapi.json get /symbols/analytics Returns analytics for any 1 to 12 symbols: per-symbol returns, risk, signals and fundamentals, plus analytics for the symbols as one list, such as market regime, breadth and sector mix. Nothing is saved. The server caches results for up to 10 minutes, or 1 minute when some symbols or data sources failed. Operation ID: get__symbols_analytics. # Get latest symbol baseline cards Source: https://docs.itoflow.ai/api-reference/endpoints/get__symbols_baseline /openapi/itoflow-public.openapi.json get /symbols/baseline Returns the latest symbol cards. The server caches results for up to 10 minutes. Operation ID: get__symbols_baseline. # Get symbol cache status Source: https://docs.itoflow.ai/api-reference/endpoints/get__symbols_cache_status /openapi/itoflow-public.openapi.json get /symbols/cache-status Operation ID: get__symbols_cache_status. # Get portfolio transition status Source: https://docs.itoflow.ai/api-reference/endpoints/get__transition_taskid_ /openapi/itoflow-public.openapi.json get /transition/{taskId} Operation ID: get__transition_taskId_. # List monitors Source: https://docs.itoflow.ai/api-reference/endpoints/get__watchlists /openapi/itoflow-public.openapi.json get /watchlists Operation ID: get__watchlists. # Get monitor Source: https://docs.itoflow.ai/api-reference/endpoints/get__watchlists_id_ /openapi/itoflow-public.openapi.json get /watchlists/{id} Operation ID: get__watchlists_id_. # Get the Monitor run in progress Source: https://docs.itoflow.ai/api-reference/endpoints/get__watchlists_id_active_execution /openapi/itoflow-public.openapi.json get /watchlists/{id}/active-execution Returns the Monitor run that is queued or in progress right now, if any, with its execution_id and status. Returns 204 when no run is in progress. Operation ID: get__watchlists_id_active_execution. # Get latest monitor analytics snapshot Source: https://docs.itoflow.ai/api-reference/endpoints/get__watchlists_id_analytics_latest /openapi/itoflow-public.openapi.json get /watchlists/{id}/analytics/latest Operation ID: get__watchlists_id_analytics_latest. # Get the results a Monitor run has shown so far Source: https://docs.itoflow.ai/api-reference/endpoints/get__watchlists_id_executions_executionid_results /openapi/itoflow-public.openapi.json get /watchlists/{id}/executions/{executionId}/results Returns the engine results (symbol cards, symbol analytics, risk engine panels) that a Monitor run has shown so far, oldest first, so a page can show them while the run is in progress. Runs on the legacy runtime record none and return an empty list. Operation ID: get__watchlists_id_executions_executionId_results. # Get cached live quotes for a monitor Source: https://docs.itoflow.ai/api-reference/endpoints/get__watchlists_id_quotes /openapi/itoflow-public.openapi.json get /watchlists/{id}/quotes Operation ID: get__watchlists_id_quotes. # List monitor reports Source: https://docs.itoflow.ai/api-reference/endpoints/get__watchlists_id_reports /openapi/itoflow-public.openapi.json get /watchlists/{id}/reports Operation ID: get__watchlists_id_reports. # Get the latest completed Monitor report Source: https://docs.itoflow.ai/api-reference/endpoints/get__watchlists_id_reports_latest /openapi/itoflow-public.openapi.json get /watchlists/{id}/reports/latest Returns the most recent completed Monitor report, including its report and dashboard. Returns 204 when the Monitor has no completed report yet. Operation ID: get__watchlists_id_reports_latest. # Get monitor report Source: https://docs.itoflow.ai/api-reference/endpoints/get__watchlists_id_reports_reportid_ /openapi/itoflow-public.openapi.json get /watchlists/{id}/reports/{reportId} Operation ID: get__watchlists_id_reports_reportId_. # Get public sign-in configuration Source: https://docs.itoflow.ai/api-reference/endpoints/getauthclientconfig /openapi/itoflow-public.openapi.json get /auth/client-config Operation ID: getAuthClientConfig. # Get authenticated user Source: https://docs.itoflow.ai/api-reference/endpoints/getauthuser /openapi/itoflow-public.openapi.json get /auth/user Operation ID: getAuthUser. # Read news for a monitor Source: https://docs.itoflow.ai/api-reference/endpoints/getmonitornews /openapi/itoflow-public.openapi.json get /watchlists/{id}/news Returns news from the last 24 hours that reaches one monitor's holdings or matches its mandate, and the state of the news reader. Without `since`, items come ranked by materiality and holding size, the top first; with `since`, items with a match judged after that time come newest first. `feed.coverage` says how many of the monitor's subjects are judged through the last 24 hours. When `current` is below `subjects`, call `fetchMonitorNews` once, then call this again every few seconds, passing `judged_through` as `since`, until `current` equals `subjects`. A missing monitor, one you do not own, and one being deleted all return the same 404. Operation ID: getMonitorNews. # Read a risk measure Source: https://docs.itoflow.ai/api-reference/endpoints/getriskmeasure /openapi/itoflow-public.openapi.json get /risk/measure/{measure_id} Read a measure until its status is not running. running gives progress: dates_done of dates_total. ok gives the answer: model (the version, its publications and base currency), units, factors (every factor any date has; each per-factor array follows this order, null where a date's publication lacks one), dates (one per date: ok with publication_date, the benchmark and each book, or missing with nearest_before and nearest_after), and warnings. Volatility and tracking error are annual decimals; shares are percent of variance; modelled_share_of_gross is a share of the book's gross weight, not of net assets. failed gives failure_code and reason: model_version_not_found (leave model.version out), answer_too_large or timed_out (split the books or the range), cancelled, or engine_fault (start again with a new request_key; if it fails again, the measure cannot run). Answers stay 24 hours after the measure ends. Names the model lacks stay out of this result. To add them, run the risk engine on the book: it adds each name it can score to the model's publications from the last two years. Then call this again. A name the run could not add comes back with its reason; not_added_in_time means the run stopped waiting first, so run it again later. Operation ID: getRiskMeasure. # Read a risk run Source: https://docs.itoflow.ai/api-reference/endpoints/getriskrun /openapi/itoflow-public.openapi.json get /risk/runs/{run_id} Read the run until it ends. A running run may carry progress: waiting_for_coverage while the factor model scores names_asked names (waited_seconds so far, expected_seconds the likely total, at_most_seconds the longest wait before the run measures what it has), then measuring. Finished results stay for 24 hours. A result with figures includes summary, view, component and the verified analytics reference. A failed run returns 200 with failure_code and reason: engine_refused means change the request; rate_limited and provider_unavailable mean the price provider failed, so start again later with a new request_key; timed_out and cancelled also end a run. Requires itoflow-engine-results. Operation ID: getRiskRun. # Read the full risk run output Source: https://docs.itoflow.ai/api-reference/endpoints/getriskrunartifact /openapi/itoflow-public.openapi.json get /risk/runs/{run_id}/artifact Read the complete schema-version-2 analytics document for a finished run. Default application/json gives raw bytes. Accept application/gzip selects stored bytes; Range requests of at most 4 MiB return 206 with Content-Range. Both representations expose exact Content-Length and SHA-256 ETag. Before ready returns 409; invalid ranges 416; unknown, foreign and expired runs share 404. Output remains available 24 hours after completion, including after the engine container stops. Requires itoflow-engine-results. Operation ID: getRiskRunArtifact. # List symbol exchanges Source: https://docs.itoflow.ai/api-reference/endpoints/getsymbolsexchanges /openapi/itoflow-public.openapi.json get /symbols/exchanges Operation ID: getSymbolsExchanges. # Resolve canonical instrument identifiers Source: https://docs.itoflow.ai/api-reference/endpoints/getsymbolsresolve /openapi/itoflow-public.openapi.json get /symbols/resolve Resolve an instrument identifier for portfolio import. This canonical symbol lookup accepts Itoflow symbol, ticker, broker symbol, ISIN, Itoflow exchange code, ISO 10383 MIC, and currency evidence. Conflicting, incomplete or unsupported evidence is rejected rather than guessed. Operation ID: getSymbolsResolve. # Search or resolve symbols Source: https://docs.itoflow.ai/api-reference/endpoints/getsymbolssearch /openapi/itoflow-public.openapi.json get /symbols/search Search symbols by ticker/company with fuzzy matching, or resolve one fully qualified SYMBOL.EXCHANGE with mode=exact. Operation ID: getSymbolsSearch. # Connect Source: https://docs.itoflow.ai/api-reference/endpoints/github_connect /openapi/itoflow-public.openapi.json post /integrations/github/connect Acts on the signed-in user’s own GitHub connection. Available only when GitHub integration is enabled; check GET /integrations/github/availability. Request bodies are limited to 128 KiB. Objects passed through from GitHub, such as branches, commits and pull requests, can include more fields than listed. Operation ID: github_connect. # Disconnect Source: https://docs.itoflow.ai/api-reference/endpoints/github_disconnect /openapi/itoflow-public.openapi.json post /integrations/github/disconnect Acts on the signed-in user’s own GitHub connection. Available only when GitHub integration is enabled; check GET /integrations/github/availability. Request bodies are limited to 128 KiB. Objects passed through from GitHub, such as branches, commits and pull requests, can include more fields than listed. Operation ID: github_disconnect. # Get Connection Source: https://docs.itoflow.ai/api-reference/endpoints/github_getconnection /openapi/itoflow-public.openapi.json post /integrations/github/getConnection Acts on the signed-in user’s own GitHub connection. Available only when GitHub integration is enabled; check GET /integrations/github/availability. Request bodies are limited to 128 KiB. Objects passed through from GitHub, such as branches, commits and pull requests, can include more fields than listed. Operation ID: github_getConnection. # List Repositories Source: https://docs.itoflow.ai/api-reference/endpoints/github_listrepositories /openapi/itoflow-public.openapi.json post /integrations/github/listRepositories Acts on the signed-in user’s own GitHub connection. Available only when GitHub integration is enabled; check GET /integrations/github/availability. Request bodies are limited to 128 KiB. Objects passed through from GitHub, such as branches, commits and pull requests, can include more fields than listed. Operation ID: github_listRepositories. # Availability Source: https://docs.itoflow.ai/api-reference/endpoints/githubavailability /openapi/itoflow-public.openapi.json get /integrations/github/availability Operation ID: githubAvailability. # List files a chat saved in its workspace Source: https://docs.itoflow.ai/api-reference/endpoints/listchatworkspacedirectory /openapi/itoflow-public.openapi.json get /chat-runtime/chats/{chatId}/workspace Lists the files and folders a chat saved in its workspace, such as reports, charts and data files. Pass path to list a folder below the workspace root. List your chats to find an earlier chat, then download a file from it. Operation ID: listChatWorkspaceDirectory. # Update account display currency Source: https://docs.itoflow.ai/api-reference/endpoints/patch__account_display_currency /openapi/itoflow-public.openapi.json patch /account/display-currency Operation ID: patch__account_display_currency. # Update portfolio auto-execute Source: https://docs.itoflow.ai/api-reference/endpoints/patch__portfolios_id_auto_execute /openapi/itoflow-public.openapi.json patch /portfolios/{id}/auto-execute Operation ID: patch__portfolios_id_auto_execute. # Create or reuse a shareable artifact Source: https://docs.itoflow.ai/api-reference/endpoints/post__artifacts /openapi/itoflow-public.openapi.json post /artifacts Creates a public artifact snapshot from a retained dashboard in the authenticated user's chat. A retained dashboard remains shareable if its run later fails. If the same private chat source was already shared, returns the existing published artifact instead. Operation ID: post__artifacts. # Start broker connection Source: https://docs.itoflow.ai/api-reference/endpoints/post__brokers_connect /openapi/itoflow-public.openapi.json post /brokers/connect Operation ID: post__brokers_connect. # Reconnect broker connection Source: https://docs.itoflow.ai/api-reference/endpoints/post__brokers_connectionid_reconnect /openapi/itoflow-public.openapi.json post /brokers/{connectionId}/reconnect Operation ID: post__brokers_connectionId_reconnect. # Reconnect Trading 212 with supplied credentials Source: https://docs.itoflow.ai/api-reference/endpoints/post__brokers_connectionid_trading212_reconnect /openapi/itoflow-public.openapi.json post /brokers/{connectionId}/trading212/reconnect Operation ID: post__brokers_connectionId_trading212_reconnect. # Reconnect Trading 212 with stored credentials Source: https://docs.itoflow.ai/api-reference/endpoints/post__brokers_connectionid_trading212_reconnect_stored /openapi/itoflow-public.openapi.json post /brokers/{connectionId}/trading212/reconnect-stored Operation ID: post__brokers_connectionId_trading212_reconnect_stored. # Connect Trading 212 manually Source: https://docs.itoflow.ai/api-reference/endpoints/post__brokers_trading212_connect_manual /openapi/itoflow-public.openapi.json post /brokers/trading212/connect-manual Operation ID: post__brokers_trading212_connect_manual. # Create or reuse a public chat share Source: https://docs.itoflow.ai/api-reference/endpoints/post__chat_shares /openapi/itoflow-public.openapi.json post /chat-shares Creates a read-only public snapshot of a private chat transcript. If the same chat and message boundary were already shared, returns the existing published share. Operation ID: post__chat_shares. # Check whether the user has approved the device authorization Source: https://docs.itoflow.ai/api-reference/endpoints/post__codex_subscription_poll /openapi/itoflow-public.openapi.json post /codex-subscription/poll Operation ID: post__codex_subscription_poll. # Start a device authorization the user approves in a browser Source: https://docs.itoflow.ai/api-reference/endpoints/post__codex_subscription_start /openapi/itoflow-public.openapi.json post /codex-subscription/start Operation ID: post__codex_subscription_start. # Compute a point-in-time factor risk covariance matrix Source: https://docs.itoflow.ai/api-reference/endpoints/post__factor_risk_covariance /openapi/itoflow-public.openapi.json post /factor-risk/covariance Returns the asset covariance matrix for the requested symbols as of a historical date, built from the point-in-time factor model snapshot resolved at or before that date. Operation ID: post__factor_risk_covariance. # Unsubscribe notification recipient Source: https://docs.itoflow.ai/api-reference/endpoints/post__notifications_unsubscribe /openapi/itoflow-public.openapi.json post /notifications/unsubscribe Operation ID: post__notifications_unsubscribe. # Create portfolio Source: https://docs.itoflow.ai/api-reference/endpoints/post__portfolios /openapi/itoflow-public.openapi.json post /portfolios Operation ID: post__portfolios. # Convert portfolio to paper mode Source: https://docs.itoflow.ai/api-reference/endpoints/post__portfolios_id_go_paper /openapi/itoflow-public.openapi.json post /portfolios/{id}/go-paper Operation ID: post__portfolios_id_go_paper. # Liquidate portfolio Source: https://docs.itoflow.ai/api-reference/endpoints/post__portfolios_id_liquidate /openapi/itoflow-public.openapi.json post /portfolios/{id}/liquidate Operation ID: post__portfolios_id_liquidate. # Approve pending trades Source: https://docs.itoflow.ai/api-reference/endpoints/post__portfolios_id_pending_trades_approve /openapi/itoflow-public.openapi.json post /portfolios/{id}/pending-trades/approve Approves trades with status "awaiting_approval" and changes their status to "pending" so they can execute. Operation ID: post__portfolios_id_pending_trades_approve. # Reconcile live portfolio Source: https://docs.itoflow.ai/api-reference/endpoints/post__portfolios_id_reconcile /openapi/itoflow-public.openapi.json post /portfolios/{id}/reconcile Operation ID: post__portfolios_id_reconcile. # Sync live portfolio state Source: https://docs.itoflow.ai/api-reference/endpoints/post__portfolios_id_sync_live_state /openapi/itoflow-public.openapi.json post /portfolios/{id}/sync-live-state Checks a live portfolio against its broker and takes the next recovery step: report that a reconnect is required, prepare approvals, reconcile, or do nothing. Operation ID: post__portfolios_id_sync_live_state. # Commit an approved paper portfolio import Source: https://docs.itoflow.ai/api-reference/endpoints/post__portfolios_import /openapi/itoflow-public.openapi.json post /portfolios/import Commit the normalized draft returned by preflight only after explicit user approval. Set draft.approved_at, use the reviewed output id with an :approved suffix, and pass the current approval token. If pricing or any material input changed, revalidate and review again. Operation ID: post__portfolios_import. # Validate uploaded paper portfolio import Source: https://docs.itoflow.ai/api-reference/endpoints/post__portfolios_import_validate /openapi/itoflow-public.openapi.json post /portfolios/import/validate Validate holdings and cash for a managed paper-portfolio import. This preflight returns the complete review result and an approval token but does not create a portfolio. Operation ID: post__portfolios_import_validate. # Create billing portal session Source: https://docs.itoflow.ai/api-reference/endpoints/post__pricing_billing_portal /openapi/itoflow-public.openapi.json post /pricing/billing-portal Operation ID: post__pricing_billing_portal. # Confirm payment Source: https://docs.itoflow.ai/api-reference/endpoints/post__pricing_confirm_payment /openapi/itoflow-public.openapi.json post /pricing/confirm-payment Operation ID: post__pricing_confirm_payment. # Get pricing plans Source: https://docs.itoflow.ai/api-reference/endpoints/post__pricing_get_plans /openapi/itoflow-public.openapi.json post /pricing/get-plans Operation ID: post__pricing_get_plans. # Get subscription Source: https://docs.itoflow.ai/api-reference/endpoints/post__pricing_get_subscription /openapi/itoflow-public.openapi.json post /pricing/get-subscription Operation ID: post__pricing_get_subscription. # Set default payment method Source: https://docs.itoflow.ai/api-reference/endpoints/post__pricing_payment_methods_default /openapi/itoflow-public.openapi.json post /pricing/payment-methods/default Operation ID: post__pricing_payment_methods_default. # Create payment method setup intent Source: https://docs.itoflow.ai/api-reference/endpoints/post__pricing_payment_methods_setup_intent /openapi/itoflow-public.openapi.json post /pricing/payment-methods/setup-intent Operation ID: post__pricing_payment_methods_setup_intent. # Preview subscription upgrade Source: https://docs.itoflow.ai/api-reference/endpoints/post__pricing_preview_upgrade /openapi/itoflow-public.openapi.json post /pricing/preview-upgrade Operation ID: post__pricing_preview_upgrade. # Refund customer balance Source: https://docs.itoflow.ai/api-reference/endpoints/post__pricing_refund_balance /openapi/itoflow-public.openapi.json post /pricing/refund-balance Operation ID: post__pricing_refund_balance. # Set spending cap Source: https://docs.itoflow.ai/api-reference/endpoints/post__pricing_spending_cap /openapi/itoflow-public.openapi.json post /pricing/spending-cap Operation ID: post__pricing_spending_cap. # Update subscription Source: https://docs.itoflow.ai/api-reference/endpoints/post__pricing_update_subscription /openapi/itoflow-public.openapi.json post /pricing/update-subscription Operation ID: post__pricing_update_subscription. # Create a paper strategy Source: https://docs.itoflow.ai/api-reference/endpoints/post__strategies /openapi/itoflow-public.openapi.json post /strategies Creates a paper strategy, optionally linked to an existing managed paper portfolio. Provide constraints.min_position_pct, max_position_pct, and max_positions; select at least one market, asset class, sector, or included symbol through allocationGuidance or universe. Omitted optional controls receive server defaults returned as effectiveConstraints and effectiveRules. activateImmediately=false creates a paused strategy even though isActive=true means it exists. Operation ID: post__strategies. # Control strategy execution Source: https://docs.itoflow.ai/api-reference/endpoints/post__strategies_id_control /openapi/itoflow-public.openapi.json post /strategies/{id}/control Resume, pause, or deactivate a strategy. Users can only control their own strategies. Operation ID: post__strategies_id_control. # Queue a manual strategy execution Source: https://docs.itoflow.ai/api-reference/endpoints/post__strategies_id_execute /openapi/itoflow-public.openapi.json post /strategies/{id}/execute Queues a one-off manual strategy rebalance and returns an execution id for tracking. Operation ID: post__strategies_id_execute. # Create a live-linked strategy Source: https://docs.itoflow.ai/api-reference/endpoints/post__strategies_live /openapi/itoflow-public.openapi.json post /strategies/live Creates a strategy attached to an existing live portfolio mirror. Provide constraints.min_position_pct, max_position_pct, and max_positions; select at least one market, asset class, sector, or included symbol through allocationGuidance or universe. Omitted optional controls receive server defaults returned as effectiveConstraints and effectiveRules. activateImmediately=false creates a paused strategy even though isActive=true means it exists. Operation ID: post__strategies_live. # Get cached live quotes for symbols Source: https://docs.itoflow.ai/api-reference/endpoints/post__symbols_quotes /openapi/itoflow-public.openapi.json post /symbols/quotes Returns cached quotes only; symbols without a cached quote are omitted. Operation ID: post__symbols_quotes. # Resolve canonical instrument identifiers in bulk Source: https://docs.itoflow.ai/api-reference/endpoints/post__symbols_resolve_batch /openapi/itoflow-public.openapi.json post /symbols/resolve/batch Resolve up to 3,000 instruments in one call, for example every name in a holdings file before pricing it. Each item takes the evidence `GET /symbols/resolve` takes, and each row answers as that route would, in request order with `index`. A row that cannot be resolved fails alone; the call still answers 200. A row with `resolution_unavailable` was not finished within this call: send those rows again. A fault that sending a row again would not fix, such as a database failure, fails the call. Operation ID: post__symbols_resolve_batch. # Create monitor Source: https://docs.itoflow.ai/api-reference/endpoints/post__watchlists /openapi/itoflow-public.openapi.json post /watchlists Operation ID: post__watchlists. # Control monitor agent Source: https://docs.itoflow.ai/api-reference/endpoints/post__watchlists_id_control /openapi/itoflow-public.openapi.json post /watchlists/{id}/control Operation ID: post__watchlists_id_control. # Fork a readable monitor Source: https://docs.itoflow.ai/api-reference/endpoints/post__watchlists_id_fork /openapi/itoflow-public.openapi.json post /watchlists/{id}/fork The fork does not copy row overrides (thresholds.metrics): a new monitor has no report to key them by, so set them after its first report. Operation ID: post__watchlists_id_fork. # Manually regenerate the current monitor report Source: https://docs.itoflow.ai/api-reference/endpoints/post__watchlists_id_reports_run /openapi/itoflow-public.openapi.json post /watchlists/{id}/reports/run Operation ID: post__watchlists_id_reports_run. # Update notification preferences Source: https://docs.itoflow.ai/api-reference/endpoints/put__notifications_preferences /openapi/itoflow-public.openapi.json put /notifications/preferences Operation ID: put__notifications_preferences. # Set portfolio benchmark comparison basis Source: https://docs.itoflow.ai/api-reference/endpoints/put__portfolios_id_benchmark /openapi/itoflow-public.openapi.json put /portfolios/{id}/benchmark Declares what this portfolio is measured against for benchmark-relative factor risk: another portfolio on the platform, a provider index, or both. Both body keys are required; null clears that side of the comparison. Operation ID: put__portfolios_id_benchmark. # Assign strategy to portfolio Source: https://docs.itoflow.ai/api-reference/endpoints/put__portfolios_id_link /openapi/itoflow-public.openapi.json put /portfolios/{id}/link Assigns a strategy to a portfolio. Supported live broker portfolios become the strategy primary portfolio. Operation ID: put__portfolios_id_link. # Update a strategy Source: https://docs.itoflow.ai/api-reference/endpoints/put__strategies_id_ /openapi/itoflow-public.openapi.json put /strategies/{id} Updates an existing user-owned strategy. Operation ID: put__strategies_id_. # Update monitor Source: https://docs.itoflow.ai/api-reference/endpoints/put__watchlists_id_ /openapi/itoflow-public.openapi.json put /watchlists/{id} Operation ID: put__watchlists_id_. # Add Source: https://docs.itoflow.ai/api-reference/endpoints/remotemcp_add /openapi/itoflow-public.openapi.json post /integrations/remote-mcp/add Manage your remote MCP connections, which all your Itoflow chats share. Send the latest connection version. If a connect response is lost, check status before retrying. Operation ID: remoteMcp_add. # Connect Source: https://docs.itoflow.ai/api-reference/endpoints/remotemcp_connect /openapi/itoflow-public.openapi.json post /integrations/remote-mcp/connect Manage your remote MCP connections, which all your Itoflow chats share. Send the latest connection version. If a connect response is lost, check status before retrying. Operation ID: remoteMcp_connect. # Disconnect Source: https://docs.itoflow.ai/api-reference/endpoints/remotemcp_disconnect /openapi/itoflow-public.openapi.json post /integrations/remote-mcp/disconnect Manage your remote MCP connections, which all your Itoflow chats share. Send the latest connection version. If a connect response is lost, check status before retrying. Operation ID: remoteMcp_disconnect. # Get Status Source: https://docs.itoflow.ai/api-reference/endpoints/remotemcp_getstatus /openapi/itoflow-public.openapi.json post /integrations/remote-mcp/getStatus Manage your remote MCP connections, which all your Itoflow chats share. Send the latest connection version. If a connect response is lost, check status before retrying. Operation ID: remoteMcp_getStatus. # List Source: https://docs.itoflow.ai/api-reference/endpoints/remotemcp_list /openapi/itoflow-public.openapi.json post /integrations/remote-mcp/list Manage your remote MCP connections, which all your Itoflow chats share. Send the latest connection version. If a connect response is lost, check status before retrying. Operation ID: remoteMcp_list. # List Tools Source: https://docs.itoflow.ai/api-reference/endpoints/remotemcp_listtools /openapi/itoflow-public.openapi.json post /integrations/remote-mcp/listTools Manage your remote MCP connections, which all your Itoflow chats share. Send the latest connection version. If a connect response is lost, check status before retrying. Operation ID: remoteMcp_listTools. # Remove Source: https://docs.itoflow.ai/api-reference/endpoints/remotemcp_remove /openapi/itoflow-public.openapi.json post /integrations/remote-mcp/remove Manage your remote MCP connections, which all your Itoflow chats share. Send the latest connection version. If a connect response is lost, check status before retrying. Operation ID: remoteMcp_remove. # Rename Source: https://docs.itoflow.ai/api-reference/endpoints/remotemcp_rename /openapi/itoflow-public.openapi.json post /integrations/remote-mcp/rename Manage your remote MCP connections, which all your Itoflow chats share. Send the latest connection version. If a connect response is lost, check status before retrying. Operation ID: remoteMcp_rename. # Availability Source: https://docs.itoflow.ai/api-reference/endpoints/remotemcpavailability /openapi/itoflow-public.openapi.json get /integrations/remote-mcp/availability Operation ID: remoteMcpAvailability. # Measure Source: https://docs.itoflow.ai/api-reference/endpoints/startriskmeasure /openapi/itoflow-public.openapi.json post /risk/measure Start measuring factor risk for 1 to 10 books over 1 to 60 dates of the factor model, on one model version: the one named, or the one live at the start. A book is a saved portfolio or a list of weights. model.as_of measures one date; model.range measures the last day of each month in it and its end (step month_end, the default) or each weekday (step daily); neither measures the newest publication. Each date reads the newest publication on or before it. Before the version's daily publications begin (model.dates.daily_from in an answer), a daily grid reads month-end publications, so use month_end for older history. A saved book without holdings_at follows its snapshots date by date; with holdings_at it stays the same book. Funds in a book, and the benchmark, are read through their stored holdings on or before each publication's model date. Answers 202 with a measure_id: read it until its status is not running. Keep the request_key: the same request with it joins the measure until 24 hours after it ends; another request with it is 409. A measure counts toward the 3 risk runs and measures an owner may have going, and stops if it runs past its time limit, at most 60 minutes; 429 and 503 carry Retry-After. For today's full report, start a risk run instead. Operation ID: startRiskMeasure. # Runs Source: https://docs.itoflow.ai/api-reference/endpoints/startriskrun /openapi/itoflow-public.openapi.json post /risk/runs Measure a saved portfolio or a what-if book against a benchmark and peer funds. Keep the request_key: retrying the same request joins its run for 24 hours after it ends. Another request with that key returns 409. At most three runs may run at once; none runs past 60 minutes. A run whose books hold names the model has not scored first waits up to 10 more minutes while they are scored. Requires itoflow-engine-results. Operation ID: startRiskRun. # HTTP API overview Source: https://docs.itoflow.ai/api-reference/overview Base URL, the OpenAPI file, and which endpoints you can try in the browser. **Experimental:** all Itoflow APIs may change without notice. > [!TIP] > > Using an AI assistant? [Itoflow MCP](/mcp/install) gives it the same operations without tokens or code. The API base URL is `https://api.itoflow.ai`. The [API coverage index](/api-reference/coverage) lists every endpoint by feature, and each endpoint page shows its parameters, request body, responses and authentication. The feature guides explain how the endpoints fit together. You can also [download the OpenAPI file](/openapi/itoflow-public.openapi.json) to generate a client or load the API into a tool such as Postman. ## Try it in the browser These five read-only endpoints have a **Send** button. [Get an access token](/authentication#get-an-access-token), paste it into the bearer field, and send. The others show the request and copyable examples; run those from your own code. | Method and path | Operation ID | Authentication | | - | - | - | | `GET /auth/client-config` | `getAuthClientConfig` | None | | `GET /auth/user` | `getAuthUser` | Bearer token | | `GET /symbols/exchanges` | `getSymbolsExchanges` | Bearer token | | `GET /symbols/search` | `getSymbolsSearch` | Bearer token | | `GET /symbols/resolve` | `getSymbolsResolve` | Bearer token | # Risk measure Source: https://docs.itoflow.ai/api-reference/risk-measure Measure volatility, tracking error, beta, factor exposures and the names that drive risk for up to ten books, at one date or over up to 60 dates, and split a change in risk into what trades did and what the market did. A risk measure gives factor risk for 1 to 10 books on one version of the factor model, at one date or over a range of up to 60 dates. You start it, read it until it ends, and stop it if you no longer want it. Send your usual [bearer token](/authentication). The credential sets the owner. Do not send an owner in the body. No account flag is needed. Use a [risk run](/api-reference/risk-runs) for today's full report on one book: attribution, profit and loss, scenarios and peers. Use a measure for the figures at past dates, over a range of dates, or for several books side by side. ```mermaid theme={null} flowchart LR Start[Start a measure] --> Read[Read by measure id] Read -->|running| Read Read -->|ok| Answer[One entry per date] Read -->|failed| Code[Failure code and reason] Start --> Stop[Stop by measure id] ``` | Operation | Body | Success | | - | - | - | | [`POST /risk/measure`](/api-reference/endpoints/startriskmeasure) | `{ request_key, request }` | 202 `{ measure_id, status, joined_existing_measure, dates_total }` | | [`GET /risk/measure/{measure_id}`](/api-reference/endpoints/getriskmeasure) | None | 200 with the measure's state | | [`POST /risk/measure/{measure_id}/cancel`](/api-reference/endpoints/cancelriskmeasure) | None | 200 `{ cancelled }` | ## Request | Field | What it takes | | - | - | | `model.as_of` | One date, `YYYY-MM-DD`, not after today in New York. The newest publication on or before it counts. Not with `range`. | | `model.range` | `{ from, to, step }`: a range of dates, at most 60. `from` is on or before `to`, and `to` is not after today in New York. | | `model.version` | A factor model version. Left out: the version live when the measure starts. Every date uses it. | | `benchmark` | A fund, such as `SPY.US`. Each book gets active risk against it. | | `books` | 1 to 10 books. Each has a `label`, unique in the call and at most 80 characters, and either `portfolio` or `holdings`. | | `top_names` | How many names to list by their share of each book's risk, 0 to 50. Default 10. | With neither `as_of` nor `range`, the measure takes the version's newest publication. `step` is `month_end`, the default, or `daily`: | `step` | Dates | | - | - | | `month_end` | The last day of each month in the range, and `to` when it is not one. | | `daily` | Each weekday in the range. | Each date reads the newest publication of the version on or before it. Dates that share one read the same books, but each date checks the age of inputs carried forward, so their figures can differ. The answer's `model.dates` says which publications exist: month-end ones from `month_ends_from`, daily ones from `daily_from`. A daily range before `daily_from` reads month-end publications, so use `month_end` for older history. A saved book is `{ "label", "portfolio": { "portfolio_id", "holdings_at" } }`. It is the portfolio's newest saved snapshot on or before `holdings_at`, a time with its offset. With no `holdings_at`, `as_of` or range, it reads the newest snapshot at the measure's start time. Every book uses that same time. A dated request, including `as_of` today, uses the end of the publication's model date in New York, so a range follows the portfolio as it was saved. `holdings_as_of` may be later than `publication_date` for an undated request. A book of weights is `{ "label", "holdings": [{ "symbol", "weight" }] }`, with 1 to 3,000 lines. Weights are fractions of the book's net assets; a short is below zero. With a `CASH` line, weights add to 1, within 0.01. Without one, the rest is cash; a book that borrows lists `CASH` below zero. Nothing is rescaled, and a symbol may appear once. A bare ticker is read as a US listing, so `QQQ` becomes `QQQ.US`. Funds in a book, and the benchmark, are read through their stored holdings on or before each publication's model date. ```json theme={null} { "request_key": "9b0f6f0e-3c1a-4d2e-8f51-6a7c2b9d4e10", "request": { "model": { "range": { "from": "2025-10-31", "to": "2026-09-30" } }, "benchmark": "SPY.US", "books": [ { "label": "growth", "holdings": [{ "symbol": "QQQ.US", "weight": 0.9 }, { "symbol": "CASH", "weight": 0.1 }] }, { "label": "saved", "portfolio": { "portfolio_id": "4f1c2a9e-7b3d-4e8a-9c61-2d5b8f0a6e17" } } ] } } ``` Keep one `request_key` for each measure. A retry with the same key and request joins the measure it started. Within 24 hours of its end, a changed request with that key returns 409. After 24 hours, the key starts a new measure. ## What moved risk To split a change in risk between two dates D0 and D1, start one measure with `model.range` from D0 to D1 and the portfolio twice: `held`, at `holdings_at` D0, and `live`, with `holdings_at` left out. On D1, `live` against `held` is the trades. `held` on D1 against `held` on D0 is the market and the model. With `step: "month_end"`, D0 is on the grid only when it is a month end; otherwise use `daily`. ## Reading a measure A 30 October 2026 check took about 30 seconds per date for ten books. Time varies with book size and load. Each request covers at most 60 dates; split longer ranges into more requests. Each newly launched background job has a 60-minute budget for all its phases. Initial validation, startup and stopping a timed-out job can add time before a terminal status is available. Jobs already running retain their original deadline. A measure that runs past its budget stops and reads `failed` with `timed_out`. Read `running` again in a few seconds. A running measure may carry `progress: { dates_done, dates_total }`. An `ok` measure has `answer`: | Field | What it holds | | - | - | | `requested` | The request as the measure read it: defaults filled and symbols written in full. | | `model` | `version`, `dates` and `base_currency`. | | `units` | Volatility and tracking error are annual decimals: 0.21 is 21%. Weights are fractions of net assets. Shares are percent of variance. | | `factors` | Each factor's `id`, `name` and `group`, across every date. Every per-factor list follows this order. | | `dates` | One entry per date, oldest first. | | `warnings` | Sentences about gaps across the measure, such as names left out on any date. | | `provenance` | `classification_inputs` and `factor_count`. | A date the model has comes back with `status: "ok"`: | Field | What it holds | | - | - | | `as_of` | The date on the grid. | | `publication_date` | The publication this date read. Dates that share one read the same books, but each date checks the age of inputs carried forward, so their figures can differ. | | `benchmark` | The benchmark's `symbol`, the date of its stored book in `holdings_as_of`, and its own `coverage`. Null with no benchmark, or when no book for it is stored. | | `books` | One entry for each book sent, in the same order. | | `warnings` | Sentences about gaps on this date, such as a book with no active risk. | | `provenance` | `snapshot_instant`. | A date with no publication of the version in the 45 days up to it comes back with `status: "missing"`, `reason_code: "model_date_unavailable"`, a `reason`, and `nearest_before` and `nearest_after`: the nearest model dates on each side, or null. A measured book has `status: "ok"` and these fields: | Field | What it holds | | - | - | | `holdings_as_of` | When the saved snapshot was taken. Null for a book of weights. | | `exposure` | `long_weight`, `short_weight`, `gross_weight` and `net_weight`. | | `coverage` | What the model covers. See below. | | `risk` | `total_volatility`, `factor_share`, `specific_share`, `exposures` and `factor_shares`. Null when no risky name in the book is modelled. | | `active` | `tracking_error`, `beta`, `modelled_share_of_gross_active`, `factor_share`, `specific_share`, `exposures` and `factor_shares`. Null with no benchmark, when no book for it is stored, or when the book or the benchmark holds no name the model covers; a warning says which. | | `top_names` | The names with the largest share of the book's risk, with `symbol`, `weight` and `share`. | `active.modelled_share_of_gross_active` is the share of the gross active weight the model covers, 0 to 1. Gaps in the book and the benchmark net out by name. A null figure was not computed; it does not mean zero. A book the measure could not read on a date has `status: "omitted"` and a `reason`: | `reason` | Meaning | | - | - | | `no_holdings_at_date` | The portfolio has no saved snapshot on or before `holdings_at`. | | `holdings_valuation_unknown` | No line has a usable value, or the valued lines have no positive net value. | ## Coverage `coverage.modelled_share_of_gross` is the share of the book's gross weight the model covers, 0 to 1: not a share of net assets. Cash in the model's currency counts in neither part. `lookthrough_weight` is the gross weight of funds measured through their own holdings. `unmodelled_count` counts every line the model left out. `unmodelled` lists at most 100 lines, each with `symbol`, signed `weight`, `reason_code` and `reason`. Weighted gaps come first, largest by size. A holding with no value has `weight: null`, code `invalid_inputs`, and reason "This holding could not be valued; its risk is excluded." Null means its weight is not known. Unvalued lines sort after all weighted gaps and count in `unmodelled_count`. A saved book with unvalued lines measures its valued lines. Their weights divide each value by the sum of valued values, cash included and shorts negative. A warning states how many lines have no value and that shares and exposures, including the modelled share of gross, describe the valued lines. | `reason_code` | Meaning | | - | - | | `unmodelled` | The model has no score for the name at this publication. A risk run can add it. | | `no_equity_listing` | A line with no confirmed equity listing, such as a bill or bond. No risk run can add it. | | `no_fund_book` | A fund the measure could not look through. | | `invalid_inputs` | A holding that could not be valued. | | `not_listed` | A symbol absent from the instrument catalogue, with its unique catalogue match named when known; `symbol` is the caller's symbol. For the part of a fund its source does not list, `symbol` is null. | | `cash_currency` | Cash in a currency other than the model's. `symbol` is `CASH`. | The engine may add codes; `reason` says each one in words. A measure does not add names to the model. To add them, start a risk run on the book: it adds each name it can score to the model's publications from the last two years. Then measure again. A name the run could not add comes back with its reason; `not_added_in_time` means the run stopped waiting first, so run it again later. ## Failed measures A failed measure returns 200 with `failure_code`, `reason` and `details`: | `failure_code` | What to do | | - | - | | `model_version_not_found` | Leave `model.version` out, or send a version an earlier answer gave. | | `answer_too_large` | The answer passed 8 MiB; `details` gives `size_bytes` and `limit_bytes`. Split the books or the range across measures. | | `timed_out` | The measure did not finish within its job budget, 60 minutes for newly launched jobs. Split the books or the range. | | `cancelled` | You stopped the measure. Start again with a new `request_key`. | | `engine_fault` | The engine hit an internal error. `details.exception_type` names the failure class; `details.publication_date` gives the selected publication's date when known, or null when it is not available. If a process stops without a fault record, the class is `UnknownError`. The detail contains no exception message. | Finished answers stay for 24 hours after the measure ends, even after the sandbox sleeps. This store holds the result, a request hash and the end time. Cancelled and timed-out measures have no stored result. ## Limits and errors A measure counts toward the three runs an owner may have going, with risk runs, while it runs. Responses carry `Cache-Control: no-store`. An error body is `{ "error": { "code", "message" } }`. | Status | Meaning | | - | - | | 400 | `invalid_request` names the field, such as a range over 60 dates or a date after today. | | 401 | No valid session or bearer token. | | 404 | `portfolio_not_found` at the start, or `measure_not_found` on a read or stop: the portfolio or measure is missing or not yours. Both share one body. | | 409 | `risk_measure_request_key_conflict`: the key started a measure of another request. | | 429 | `risk_engine_busy`: three runs or measures are going. | | 503 | `risk_engine_unavailable`: the risk engine did not answer, or its answer could not be read. | 429 and 503 carry `Retry-After` in seconds. Call again after it; on 503, retry the start with the same key, which joins the measure it may have started. # Risk runs Source: https://docs.itoflow.ai/api-reference/risk-runs Run Itoflow's risk engine on a saved portfolio or a what-if book: current factor risk, attribution, risk change and scenarios against a benchmark and up to 10 peer funds, with every gap named. Start, read and stop a run. > [!WARNING] > > Experimental: these operations may change. Risk runs need to be enabled for your account. All operations take your usual [bearer token](/authentication). The credential sets the owner. Do not send an owner in the body. ```mermaid theme={null} flowchart LR Start[Start a run] --> Read[Read by run id] Read -->|running| Read Read -->|ok or partial| Figures[Summary, view and full panel] Start --> Stop[Stop by run id] ``` | Operation | Body | Success | | - | - | - | | `POST /risk/runs` | `{ request_key, request }` | 202 `{ run_id, status, joined_existing_run }` | | `GET /risk/runs/{run_id}` | None | 200 with the run state | | `GET /risk/runs/{run_id}/artifact` | None | 200 complete analytics JSON; 206 gzip byte range | | `POST /risk/runs/{run_id}/cancel` | None | 200 `{ cancelled }` | Send a saved portfolio you own with `portfolio: { portfolio_id }`, or a what-if with `portfolio: { holdings: [{ symbol, weight }] }`. Set `benchmark` and, if needed, `peers`. See the [portfolio guide](/features/portfolios#measure-risk-through-mcp) for weights and limits. Attribution and factor profit and loss use the latest book dated on or before each period's start. All saved portfolios, including one fund beside cash, use their dated holdings snapshots, with the latest snapshot on or before each start and known by the report date. Each start uses the last edit by the end of that day in New York. A saved book with unknown values remains the opening book and withholds unsupported figures; an older book never replaces it. The first saved date supplies history coverage even when that first book has no known values. Today's holdings never stand in for those snapshots. A later book never fills a gap. If there is no such book, the period is not covered: the section and tool reply say `History starts .` The requested period is kept and marked partial or unavailable. Start and end books also exclude holdings dated after the report date, including reads with a separate knowledge cutoff. See [Monitor attribution](/features/monitors) for how period starts and forward weight carries are measured. Row kinds and diagnostics use report-date knowledge in both runtimes. A listed fund ends at its own last supported close, even when its constituents have newer prices. The saved portfolio period starts on its first saved date and reads `since first saved `; a standalone listed fund uses its first available price and reads `since inception`. An unlisted basket without dated history withholds this period with a reason. Missing factor returns, opening exposures or listing closes do not hide a known first supported book date from the section or reply. Figures stay withheld when their price endpoints are missing. Keep one `request_key` for each run. Retry with the same key and request to join that run. Within 24 hours of its end, a changed request with that key returns 409. After 24 hours, the key starts a new run. At most three runs may run at once. A [risk measure](/api-reference/risk-measure) counts as one while it runs. Each newly launched background job has a 60-minute budget, including data reads, coverage, computation and output. Initial validation, startup and stopping a timed-out job can add time before a terminal status is available. A run whose books hold names the model has not scored first waits up to 10 minutes while they are scored, within the same budget. Jobs already running retain their original deadline. Read `running` again in a few seconds. A running run may carry `progress`: | Stage | Meaning | | - | - | | `waiting_for_coverage` | The factor model is scoring `names_asked` names. `waited_seconds` is the time so far, `expected_seconds` the likely total and `at_most_seconds` the longest wait before the run measures what it has. | | `measuring` | The run is computing figures from the coverage it has. | An `ok` or `partial` result includes `summary`, `view`, `component` and top-level `analytics`. The `analytics` reference gives schema version, artifact identity, raw and compressed sizes and SHA-256 hashes, and the exact expiry time. The share-count check never changes which rows are valued, their weights, the weight basis or whether the book is usable. The one count it sets aside is a whole book's: when that book's counts disagree with its stated weights by more than 10%, the engine stops using them, as described below. The engine looks for the source's valuation session before checking provider share counts. Zero or missing market values supply no evidence against a share count. For each listing currency with at least three distinct securities, it compares the last five sessions at or before the holdings date, using each listing's price history and the exchange rate from the same session. A match needs a median ratio within 0.5% of one and more than half its rows within 2%. The closest median wins. Sessions within 0.1 percentage point are ambiguous; the engine uses the later session and reports that ambiguity. Other currency rows use their own qualifying session, or the book's match where available. At a matched session, a count that differs from its own market value in the book's currency by more than 2% becomes unverified. A foreign-currency group with at least three rows clustered at its exchange rate also makes those clustered counts unverified. Rows outside that cluster keep their own check results. The receipt gives their count and stated weight with the reason **share count disagrees with market value in the book's currency**. The weight test uses the share counts as given. The engine never repairs a count. If no session matches, the engine uses a 25% gross-error filter at the holdings-date close. The receipt says **the source's valuation date was not found** and **Counts passing that filter remain unverified.** Disagreement, gross-error filter and ambiguous-session receipts say **The weight test uses the share counts as given.** Missing comparison data preserves existing behavior. The currency-group check has gaps for fewer than three rows and currencies within about 5% of the book's currency. If priced rows have share counts but the source states no value currency for the book, those counts cannot be checked. The receipt says "Share counts were not checked: the source states no value currency for this book." The same line adds "The stated weights were tested against these unchecked counts." when the counts were compared with the weights. No count-check line is added when the counts did not affect the weight result, or when there are no priced share-count rows. Row market values are not needed for this unchecked-count receipt. The engine does not infer the book's value currency from the fund's listing, net asset value currency or holding rows. This does not change how values or weights are calculated. The matched session checks counts only. Book values and the weight test still use the holdings-date close; the weights themselves are the ones the book states. An earlier match does not prove the count across a later split or holdings change; a marked break in the price history makes the row fall back to the gross-error filter. A fund book keeps the weights its source states. When its share counts and closes are more than 10% from those weights, the book stays in use and the receipt says **share counts disagree with stated weights by X%; stated weights kept.** The engine never rebuilds weights from share counts, and uses that book's counts for nothing else, such as splitting a holdings change into trade and price drift. Results from earlier runs may still carry `weights: "rebuilt_from_shares"` and `total_basis` in `component.receipt.books[]`; new results never do. A zero share count with a nonzero stated weight counts as missing and does not enter the comparison; zero shares with zero weight still means valued zero. `total_value` is the source's own total when the engine can use it. A book whose counts agree with its weights can instead report the sum of its valued holdings, unless a short holding could not be valued; a book whose counts disagree reports only the source's total. A parent book's optional `fund_total_notes` lists each distinct held fund book with a note as `{symbol, holdings_date, note}`. Older results omit these fields. A book can carry `total_note` when its exposure basis is not known. A derivative without a proven contra offset never causes a book to be refused. Every row remains visible. The receipt carries `exposure_unknown_reason: "a derivative's exposure is not known"` with `total_note`, which labels every stated weight **% of the provider's total**. A negative derivative figure has unknown direction; it is not a short position. Valuation coverage excludes these derivative figures from its denominator, because share counts and prices cannot value them. They keep their stated weights. For such a book, exposure, long and short sides, net exposure and leverage are not known. The note bounds gross exposure below by the other rows' sizes. Factor and risk sections, including attribution and factor profit and loss, are unavailable with that reason. Book-level liquidity aggregates are null; measured days to sell each holding remain. Position-limit figures remain, with no bands, passes or trim plans; a breach is shown only when the figure alone exceeds the limit. Prices, the fund's own performance, valued-share multiples and share sector and country weights remain available. Proven future/contra pairs keep their existing treatment. Historical risk measurement keeps an accepted book with an unsettled basis. Its `exposure`, `risk` and `active` are null, its gross coverage and look-through weights are null, and a warning gives the reason. Counts and fund-book provenance remain; no numeric zero substitutes for missing exposure. When either book has an unsettled derivative basis, active share and weight in common are null with the same reason. Row weights and share classifications remain available. If only a benchmark or peer has this unknown basis, the subject's own total volatility and absolute risk measures remain available. The risk section is partial: active risk, tracking error and active exposures against that book are withheld with the reason. An unsettled subject still has no exposure-dependent risk figures. Issuer limits include bonds and other issuer-bearing holdings alongside shares. A derivative's stated figure also appears in position limits: a 60% figure against a 50% limit proves a breach of 10 percentage points, while its unknown exposure basis still prevents a band, pass verdict or trim plan. `view.unmodelled[]` lists the subject's gaps by size, with `symbol` and `weight`; `unmodelled_count` counts all of them. Both read the current model, which only the `risk` analysis does: a run without it has an empty list, a null count and no `coverage`. `view.coverage[]` names gaps in the subject, benchmark and peers, with `book`, `symbol`, signed `weight`, `reason_code` and `reason`. A holding with no usable value has `weight: null`, code `invalid_inputs`, and reason "This holding could not be valued; its risk is excluded." Null means its weight is not known. Weighted gaps sort before unvalued gaps in the subject list. Depositary receipts count as equity, priced on their own listing. If a holding's own listing has no reference type, the engine uses other listings with the same checked ISIN only when every available type agrees. It keeps the holding's original listing. Missing or conflicting evidence keeps the holding's existing classification fallback. An accounting balance needs its own stated currency to earn a known zero return. Without one, it stays a named source gap with its signed weight in uncovered or unmodelled coverage. History and attribution give it no zero-return leg. The engine does not fill its currency from the book or the report. The `trust` and `risk_change` sections check the last stated holdings list dated on or before each past model publication against that publication's model, looking through held funds where their holdings are available. A list may predate the publication by several months and serve more than one publication. Their receipt lines use `past_unmodelled` for names that a past publication's model did not cover, whether held directly or through a fund. These gaps do not add names to today's `view.unmodelled` or its count. Gaps with a specific cause, such as `cash_currency` or `no_fund_book`, keep that reason code and name the past holdings list in their reason. A saved book with unvalued lines returns a partial risk section and measures its valued lines. Each valued weight is its value over valued net assets, cash included and shorts negative. The book's warning gives the number of unvalued lines and says that shares and exposures, including the modelled share of gross, describe the valued lines. A book with no valued line or no positive valued net assets is refused. The valuation section lists trailing price to earnings first, then forward price to earnings. Its headline is **Trailing P/E premium**, keyed by `valuation.premium.trailing_pe`. Trailing earnings cover the last twelve months. Forward earnings and expected earnings growth use the twelve-month blends in MSCI's Fundamental Data Methodology. Losses keep their sign; growth has no figure when the book's summed backward earnings are zero or negative. The data receipt names missing inputs and per-share figures whose currency cannot be matched to the price. For example, in the complete analytics, `sections.valuation.data.books` holds one entry per book; the subject book's entry has a null `comparator_key`, and its `measures.trailing_pe` gives the trailing multiple and coverage. A book with no consensus estimates can still publish trailing price to earnings and its premium. A null figure was not computed; it does not mean zero. A failed run returns 200 with `failure_code` and `reason`, plus `details` for an engine fault: | `failure_code` | What to do | | - | - | | `engine_refused` | Change the request as `reason` says. | | `analytics_publication_failed` | The complete analytics could not be built, validated or retained. | | `engine_fault` | The engine hit an internal error. `details.exception_type` names the failure class; `details.publication_date` gives the selected publication's date when known, or null when it is not available. If a process stops without a fault record, the class is `UnknownError`. The detail contains no exception message. | | `rate_limited`, `provider_unavailable` | The price provider failed. Start again later with a new `request_key`. | | `timed_out` | The run did not finish within its job budget, 60 minutes for newly launched jobs. | | `cancelled` | You stopped the run. Start again with a new `request_key`. | Finished results and complete analytics stay available for 24 hours after the run ends, including after the sandbox sleeps. `GET /risk/runs/{run_id}/artifact` returns the schema-version-2 document itself as `application/json`, with its exact `Content-Length` and raw SHA-256 as a quoted `ETag`. Unknown, foreign and expired runs share a 404 response. Before publication finishes, the route returns 409 `{ "status": "not_ready" }`. To copy large documents, send `Accept: application/gzip`. This selects the stored gzip bytes, their length and their SHA-256 `ETag`. Add `Range: bytes=0-4194303` to request at most 4 MiB; a valid range returns 206 with `Content-Range`. Continue through the compressed length in `analytics.stored.size_bytes`, then verify the compressed size and hash, decompress, and verify the raw size and hash from `analytics`. Invalid ranges, ranges outside the stored bytes and ranges over 4 MiB return 416. Each range rechecks the owner and expiry. To resume a copy you started earlier, send its `ETag` in `If-Range`; when the stored bytes have changed, the route returns 200 with the whole gzip file instead of a range, so start that copy again. Publication accepts at most 256 MiB raw and 64 MiB compressed. The engine calculates once, writes immutable files and uploads 5 MiB parts. It verifies both stored and decompressed hashes and lengths before publishing a reference. A build, validation, size or storage failure fails the run with `analytics_publication_failed`; it does not return a successful summary without complete output. Retries reuse those files and never repeat the calculation. Old retained results and old artifact bodies keep their earlier format until they expire; readers must deploy before new writers, and rollback must stop new writers before rolling back readers. Cancellation, timeout and container loss leave a known terminal outcome. A late result cannot replace a cancellation or a newer attempt. Store outages return an unavailable error rather than pretending the run does not exist. Owner-scoped storage expires reads after 24 hours. The bucket keeps its two-day deletion rule, allowing up to one more day for provider deletion, and aborts unfinished multipart uploads after one day. Completed data deletes within three days. | Status | Meaning | | - | - | | 403 | `feature_not_enabled`: risk runs aren't enabled for your account | | 404 | The portfolio or run is unknown, or you do not own it; all share one body | | 409 | `risk_engine_request_key_conflict`, or artifact `not_ready` | | 416 | Invalid or oversized gzip byte range | | 422 | `invalid_risk_engine_request` (a malformed request, more than 10 peers, or a saved portfolio with more than 3,000 securities) or `portfolio_has_no_holdings` | | 429 | `risk_engine_busy`: three runs or measures are going | | 503 | The risk engine did not answer, or its answer could not be read | On 503, retry the same call with the same key. If cancellation could not stop the process, retry the cancellation call with the same `run_id`; a retained cancellation does not prevent another stop attempt. See the generated endpoint reference for the full request and response schemas. ### Issuer bounds and country provenance Compliance groups equal registered issuer identifiers and uses unique shared filer numbers to bridge legal entity identifiers. Provider identifiers must be dated on or before the report. Unresolved lines carry their absolute weight in the receipt. Unequal concentration bounds show **at least** and an upper bound; the verdict is unknown when the bounds straddle the limit. Mixed longs and shorts with unresolved weight have no verdict, and trim plans require exact positions. Issuers are legal entities; consolidated group limits need parent links. For a QQQ subject with SPY as comparator, each book's country receipt states how much weight used the listing venue's country because the company stated none. # Authentication Source: https://docs.itoflow.ai/authentication Sign in with device authorization to get an access token, send it as a bearer token, and refresh it. Most API requests need an access token for your Itoflow account, sent in the `Authorization` header: ```http theme={null} Authorization: Bearer ACCESS_TOKEN ``` Replace `ACCESS_TOKEN` with your access token. Some routes need no token, such as `GET /auth/client-config`, `GET /pricing/catalog`, `GET /fx-rates`, `GET /strategies/public` and the public share routes. The [API coverage index](/api-reference/coverage) shows the authentication for every endpoint. > [!TIP] > > **Most people don't need a token.** If you use Claude, Codex or another AI assistant, [connect Itoflow MCP](/mcp/install) and sign in once in your browser. Your client handles authentication for you. ## Get an access token Itoflow uses the OAuth 2.0 device authorization flow. Your program asks for a short code, you approve that code in your browser, and the program receives an access token and a refresh token. ```mermaid theme={null} sequenceDiagram participant C as Your program participant I as Itoflow sign-in participant U as You in a browser participant A as Itoflow API C->>A: GET /auth/client-config A-->>C: Client ID and sign-in endpoints C->>I: Request a device code I-->>C: Code and approval URL U->>I: Sign in and approve the code C->>I: Poll for the token I-->>C: Access token and refresh token C->>A: Request with bearer token ``` This Python script uses only the standard library. It prints the approval link to the terminal, waits while you approve, then prints the access token. It saves the refresh token to `~/.config/itoflow/credentials.json`, readable only by you, and never prints it. ```python get_token.py theme={null} import json import os import sys import time from pathlib import Path from urllib.error import HTTPError from urllib.parse import urlencode from urllib.request import Request, build_opener, install_opener, urlopen CREDENTIALS = Path.home() / ".config" / "itoflow" / "credentials.json" # The API rejects Python's default User-Agent, so send a named one. opener = build_opener() opener.addheaders = [("User-Agent", "itoflow-get-token/1.0")] install_opener(opener) def post(url, fields): request = Request( url, data=urlencode(fields).encode(), headers={"Content-Type": "application/x-www-form-urlencoded"}, ) try: with urlopen(request, timeout=30) as response: return json.load(response) except HTTPError as error: try: return json.load(error) except ValueError: sys.exit(f"Sign-in service error: HTTP {error.code}") def save_and_print(config, token): # Keep the refresh token in a file only you can read; print only the access token. if "refresh_token" not in token: print("No refresh token returned; sign in again when this one expires.", file=sys.stderr) print(token["access_token"]) return CREDENTIALS.parent.mkdir(mode=0o700, parents=True, exist_ok=True) # Write a new owner-only file, then swap it in, so an older file's permissions never apply. temporary = CREDENTIALS.with_name(f".credentials-{os.getpid()}.tmp") fd = os.open(temporary, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600) with os.fdopen(fd, "w") as file: json.dump( { "refresh_token": token["refresh_token"], "client_id": config["clientId"], "token_endpoint": config["tokenEndpoint"], }, file, ) os.replace(temporary, CREDENTIALS) print(token["access_token"]) def refresh(): if not CREDENTIALS.exists(): sys.exit("No saved sign-in. Run the script without --refresh first.") saved = json.loads(CREDENTIALS.read_text()) token = post( saved["token_endpoint"], { "grant_type": "refresh_token", "refresh_token": saved["refresh_token"], "client_id": saved["client_id"], }, ) if "access_token" not in token: sys.exit(f"Refresh failed: {token.get('error')}. Sign in again.") config = {"clientId": saved["client_id"], "tokenEndpoint": saved["token_endpoint"]} save_and_print(config, token) def sign_in(): with urlopen("https://api.itoflow.ai/auth/client-config", timeout=30) as response: config = json.load(response) fields = {"client_id": config["clientId"]} if config.get("scopes"): fields["scope"] = " ".join(config["scopes"]) device = post(config["deviceAuthorizationEndpoint"], fields) link = device.get("verification_uri_complete", device["verification_uri"]) print(f"Open {link} and approve code {device['user_code']}", file=sys.stderr) interval = device.get("interval", 5) deadline = time.time() + device["expires_in"] while time.time() < deadline: time.sleep(interval) token = post( config["tokenEndpoint"], { "grant_type": "urn:ietf:params:oauth:grant-type:device_code", "device_code": device["device_code"], "client_id": config["clientId"], }, ) if "access_token" in token: save_and_print(config, token) return if token.get("error") == "slow_down": interval += 5 elif token.get("error") != "authorization_pending": sys.exit(f"Sign-in failed: {token.get('error')}") sys.exit("The code expired before it was approved. Run the script again.") if "--refresh" in sys.argv: refresh() else: sign_in() ``` Put the token straight into an environment variable, so it stays out of your shell history: ```bash theme={null} export ITOFLOW_ACCESS_TOKEN="$(python3 get_token.py)" ``` If sign-in fails, the script prints the reason and the variable is left empty, so check it before you continue. The code expires after a few minutes. Poll no faster than the `interval` the sign-in service returns; if it answers `slow_down`, wait longer between polls. ## Refresh an expired token Access tokens are short-lived. When a request returns `401`, get a new one without signing in again: ```bash theme={null} export ITOFLOW_ACCESS_TOKEN="$(python3 get_token.py --refresh)" ``` The script sends the saved refresh token to the sign-in service, saves the new refresh token it gets back, and prints the new access token. Each refresh returns a new refresh token and the old one may stop working, so always use the newest. If the refresh fails, run `python3 get_token.py` again to sign in. To refresh from your own code, send these form fields to the `tokenEndpoint` from `GET /auth/client-config`: ```text theme={null} grant_type=refresh_token refresh_token=REFRESH_TOKEN client_id=CLIENT_ID ``` Replace the following: * `REFRESH_TOKEN`: the newest refresh token you saved. * `CLIENT_ID`: the `clientId` from `GET /auth/client-config`. ## Keep tokens safe * Keep tokens out of source files, URLs, logs, screenshots and bug reports. * Keep the refresh token inside the program that manages the session; the script stores it in `~/.config/itoflow/credentials.json` with owner-only permissions. Only the access token goes to the API. * The client ID, an ID token and a refresh token are not API tokens. The API rejects them. * Don't copy tokens out of browser cookies or another app's credential files. The API checks the token's issuer, audience and expiry on every request, then checks that your account may use the resource you asked for. See [Security at Itoflow](https://itoflow.ai/security) for how we protect your data. ## Try requests in these docs Read-only endpoints have a **Send** button in the API reference; the [reference overview](/api-reference/overview) lists them. [Get an access token](#get-an-access-token) and paste it into the bearer field. Requests go straight from your browser to `https://api.itoflow.ai`. The docs site sends no cookies and does not proxy the request. Clear the field when you finish, and don't use a shared browser. ## Errors * `401`: the token is missing, expired or not an Itoflow access token. Refresh it or sign in again. Don't retry the same token in a loop. * `403`: the token is valid, but your account can't use this resource, or your plan doesn't include it. # Billing and credits Source: https://docs.itoflow.ai/features/billing Choose a plan and the model your agents use, see what each run cost in credits, set a spending cap, and manage invoices and your subscription. Itoflow never switches your model silently. > [!TIP] > > **The easiest way: ask your AI assistant.** With [Itoflow MCP](/mcp/install) connected to Claude or Codex, paste: > > ```text theme={null} > Use Itoflow to show my usage this billing period, my remaining credits, and > which models my plan includes. > ``` > > > [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%20show%20my%20usage%20this%20billing%20period%2C%20my%20remaining%20credits%2C%20and%20which%20models%20my%20plan%20includes.) > > > > 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%20show%20my%20usage%20this%20billing%20period%2C%20my%20remaining%20credits%2C%20and%20which%20models%20my%20plan%20includes.) > > > > 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/account/billing). The rest of this page covers the HTTP API. Itoflow charges for AI usage in **credits**. Each plan includes a monthly amount of usage; paid plans can also allow pay-as-you-go overage up to a spending cap you set. Invoices and balances are in **money**. Keep the two apart: credits are not cents. ```mermaid theme={null} flowchart LR Usage[Agent runs] --> Credits[Credits used] Plan[Plan] --> Credits Credits --> Cap[Overage up to your spending cap] Cap --> Billing[Invoices and balance] ``` ## Plans There are three plan families: Free, Pro and Max. Pro and Max include monthly AI usage worth more than their fee, and the same advanced models. Free includes a small allowance on the basic model. Prices and allowances are on the [pricing page](https://itoflow.ai/pricing) and in `GET /pricing/catalog`; read them from there rather than hard-coding them. **How usage is counted.** Each model call in an agent run costs what the model provider charges, times a usage multiplier. For example, at a multiplier of 1.25, a provider charge of 1 US dollar uses 1.25 dollars of your included usage. Both the agent and its independent review count. Included usage resets each month and doesn't roll over. Pay-as-you-go overage, when enabled, isn't subsidized the way included usage is. News searches and matching news to companies or monitor mandates do not spend your AI credits. Requests use the existing rate limits, and judging has time limits. Agent runs that read or summarize news still spend credits. **Bonus credits** are one-off grants. They last across months until used, revoked or expired. Each month uses included credits first, then bonus credits. Bonus credits don't give access to paid models. ## Models and plans Chats, monitors and strategies each save their own model choice. Pro and Max unlock advanced models while their subscription is active or in a trial and the current billing period is valid. Trials use the plan's existing usage allowance and budget checks. A fusion mode chooses the main agent and its independent Guardian together: | Key | Main agent | Guardian | Plans | | - | - | - | - | | `fusion_deep` | Sol | Opus | Pro and Max | | `fusion_quick` | Terra | Sonnet | Pro and Max | | `fusion_light` | Luna | Haiku | All plans | You can also choose a single model. Its Guardian uses that same model: | Key | Model | Plans | | - | - | - | | `luna` | GPT-6 Luna | All plans | | `sol61` | GPT-6.1 Sol | Pro and Max | | `terra61` | GPT-6.1 Terra | Pro and Max | | `sol` | GPT-6 Sol | Pro and Max | | `astra` | GPT-6 Astra | Pro and Max | | `sonnet55` | Claude Sonnet 5.5 | Pro and Max | | `opus55` | Claude Opus 5.5 | Pro and Max | Haiku reviews fusion runs; you cannot choose it as a single main agent. Read `GET /pricing/model-access` for the current choices. Its `models` entries add `short_name` and `main_agent`; only entries with `main_agent: true` can run on their own. Its `modes` entries name both model keys and give their combined `requires_paid` and `enabled` values. The returned `default_mode` is your plan's default for new resources. The older `default_model` field keeps its single-model meaning. Pass a returned choice key, never a provider's model version. ```mermaid theme={null} flowchart LR Choice[Saved choice] --> Snapshot[Run settings] Snapshot --> Main[Main agent] Snapshot --> Guardian[Guardian review] Main --> Rates[Model rates] Guardian --> Rates ``` * **Default.** Without a choice, a new chat, monitor or strategy uses your plan's default mode. Existing ones keep their saved choice. * **Pinned settings.** Both agents keep the models and reasoning settings admitted when the run starts, including retries and recovery. Changing a saved choice affects the next run. * **Provider and cost.** Fusion reviews send review context to Anthropic, including on Free. Each agent bills at its own model's rates, including context-length tiers. Prompt-cache writes use their cache lifetime. * **No silent switching.** If your paid plan ends, saved paid choices stay selected, but new runs stop with “Choose the Free model or upgrade” until you change the choice or upgrade. * A payment method, a balance, or bonus credits don't give access to paid choices. A [connected ChatGPT subscription](/features/chat#connect-your-own-chatgpt-subscription) unlocks single OpenAI models for Chat and monitors. Fusion modes always use your plan's access and Itoflow keys for both agents; they never use that connection. Strategies use plan access. If Itoflow can't read your plan, it returns `503` rather than assume you're on Free. ## Read usage and billing | Endpoint | Returns | | - | - | | `GET /pricing/catalog` | Plans, prices, included usage and models. No token needed. | | `GET /pricing/config` | Public billing settings. No token needed. | | `GET /pricing/model-access` | Models your account can use | | `GET /account/billing-costs` | This period's usage, limits and spending cap | | `GET /pricing/billing-summary` | Balance, unpaid invoices, subscription and amount owed | | `GET /pricing/invoices` | Invoices | | `GET /pricing/customer-balance` | Account balance and currency | | `GET /pricing/credit-tiers` | Credit tiers | | `POST /pricing/get-plans` | Plans and the overage rate | | `POST /pricing/get-subscription` | Your subscription | `get-subscription` creates a Free subscription if you don't have one yet, so it isn't a pure read. Call these endpoints from your server. Browsers block calls from other websites, even to the public catalog. ### Usage this period `GET /account/billing-costs` returns `period_start`, `period_end`, `total_credits_used`, `invocation_count` and token counts. Depending on your plan, it also returns: | Field | Meaning | | - | - | | `credits_included`, `bonus_credits`, `effective_credits_included` | Credits available this period | | `credits_remaining`, `overage_credits`, `percentage_used` | Where you are now | | `current_tier` | `free`, `included` or `overage` | | `is_within_limit`, `block_reason` | Whether new runs can start, and if not, why | `block_reason` is one of `free_tier_exhausted`, `spending_cap_reached`, `subscription_inactive` or `not_configured`. ### Money fields In the billing summary: | Field | Meaning | | - | - | | `balance`, `balanceCurrency` | Balance in cents and its currency. A negative balance is credit in your favor. | | `unpaidInvoices` | Count, total due and invoice details | | `subscription` | Status, period end, whether it cancels at period end, plan and credits; may be `null` | | `upcomingInvoice` | Next invoice amount and period; may be `null` | | `totalOwed` | Amount owed, in cents | | `hasPaymentIssue` | Whether a payment needs attention | Fields ending in `_cents`, invoice amounts and the cent fields above are whole cents. Some dates are Unix timestamps and others ISO strings; check each field's schema. ## Change your plan 1. Read `GET /pricing/catalog`. Each entry has a `price_id`, a plan `key` (`free`, `pro` or `max`) and an `offer_key` such as `pro100` or `pro300`. Pick by `price_id`: one `key` can have several offers. 2. `POST /pricing/preview-upgrade` with the `planId` shows what the change will cost. Show it to the account owner. 3. `POST /pricing/update-subscription` with the `planId` and the `catalogRevision` you showed. If the terms changed in between, step 3 returns `409 PLAN_TERMS_CHANGED`. Read the catalog again and confirm the new terms. A successful response means the change was accepted; follow the payment status to see that it was paid. Paid upgrades keep the current renewal date. The preview and payment invoice cover the remaining-period price difference. Your purchased plan and included usage change only after payment succeeds. A nonempty `subscription.pending_update` means the requested upgrade still awaits payment; it does not grant its allowance. ```mermaid theme={null} flowchart LR Request[Request upgrade] --> Pending[One pending invoice, purchased plan stays active] Pending --> Paid[Payment succeeds] Paid --> Active[New plan and allowance apply] Pending --> Expired[Payment expires, purchased plan stays active] ``` Repeat the same target to resume the existing pending invoice. Choosing another plan while it is pending returns `409 SUBSCRIPTION_PAYMENT_PENDING`. An earlier unpaid plan-change invoice returns `409 SUBSCRIPTION_PAYMENT_REQUIRED`; resolve that invoice before changing plans. A simultaneous request returns `409 SUBSCRIPTION_UPDATE_IN_PROGRESS`; refresh before retrying. `409 SUBSCRIPTION_UPDATE_UNSUPPORTED` means the subscription cannot use this payment-gated flow, for example when it collects invoices manually. For saved Link, confirm through `POST /pricing/confirm-payment`. If it returns `requires_action` with no redirect URL, call Stripe.js `handleNextAction({clientSecret})` with the owned invoice's confirmation secret. Follow an explicit redirect URL when one is present and return to `/account/billing`. `processing` remains pending. After `succeeded`, refresh `POST /pricing/get-subscription` and check the paid invoice and effective plan before announcing that the upgrade is active. Billing shows the pending upgrade and a **Complete payment** action after reload. If your subscription uses a price no longer in the catalog, you keep its terms. Read them from your subscription and billing summary. Payment methods, the billing portal (`POST /pricing/billing-portal`) and payment confirmation have their own endpoints; see the reference. ## Spending cap and refunds `POST /pricing/spending-cap` with `spending_cap_cents` sets a monthly overage cap in cents. `0` or `null` turns overage off. A positive cap needs a paid plan; on Free it returns `PAID_PLAN_REQUIRED`. `POST /pricing/refund-balance` asks for a refund of your credit balance. It can return `NO_CREDIT_BALANCE`, `NO_REFUNDABLE_PAYMENT` or `REFUND_IN_PROGRESS`. ## ChatGPT subscription usage With a [connected ChatGPT subscription](/features/chat#connect-your-own-chatgpt-subscription), OpenAI model calls that your subscription pays for use no Itoflow credits. Other calls in the same run still do, and your spending cap still applies. When the subscription can't be used, for example because it needs reconnecting or has hit its own limit, calls run on Itoflow credits at normal rates. A run on a paid model that only your subscription gave you stops instead of being charged. An independent review that the subscription refuses part-way finishes on credits, so the work is still checked. Itoflow records who paid for each call when it happens. Reconnecting or disconnecting later doesn't change past records. To see what you were charged, check your usage, not the connection status or what the model says about itself. If a charge looks wrong, email [support@itoflow.ai](mailto:support@itoflow.ai) with the chat or task it belongs to. To see your usage, invoices and plan in the app, open [Billing](https://app.itoflow.ai/account/billing). See the [billing](/api-reference/coverage#billing) and [account](/api-reference/coverage#account) endpoint references for every field. # Broker connections Source: https://docs.itoflow.ai/features/brokers Connect a Trading 212 account, check its status and holdings, and disconnect it. > [!TIP] > > **The easiest way: ask your AI assistant.** With [Itoflow MCP](/mcp/install) connected to Claude or Codex, paste: > > ```text theme={null} > Use Itoflow to show my broker connections and tell me if any needs reconnecting. > ``` > > > [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%20show%20my%20broker%20connections%20and%20tell%20me%20if%20any%20needs%20reconnecting.) > > > > 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%20show%20my%20broker%20connections%20and%20tell%20me%20if%20any%20needs%20reconnecting.) > > > > Start this in ChatGPT with the Itoflow plugin. > > Using another client? Copy the prompt with the button on the code block. > > To connect a broker, use the [app](https://app.itoflow.ai/settings/brokers); never paste broker keys into a chat. The rest of this page covers the HTTP API. A broker connection links your brokerage account to Itoflow so a live portfolio can read holdings and, after your approval, place trades. Itoflow supports **Trading 212**. Connecting any other broker returns `400 UNSUPPORTED_BROKER`. ```mermaid theme={null} flowchart LR Connect[Start connection] --> Provider[Supply broker API keys] Provider --> Status[Connection status] Status --> Holdings[Holdings and margins] Status --> Reconnect[Reconnect when needed] ``` We recommend connecting a broker in the [Itoflow app](https://app.itoflow.ai/settings/brokers), which guides you through each broker's steps. The endpoints below do the same thing. ## Connect `POST /brokers/connect` with `"broker_type": "trading212"`. Send your API key and secret as `api_key` and `api_secret`, and a `permissions` object. The key needs all eight permissions set to `true`: `metadata`, `account_data`, `portfolio`, `orders_execute`, `orders_read`, `history_orders`, `history_transactions` and `history_dividends`. If any is missing, you get `400 MISSING_REQUIRED_PERMISSIONS` with the missing ones in `details`. The call connects straight away and returns `connection_id`, `sync_status` and `portfolio_id`. Treat the key and secret like passwords: load them from a secret store, never from source code, and don't log them. Then poll `GET /brokers/{connectionId}/status` until the connection is ready. A successful connect doesn't mean holdings have synced yet. ## Read | Endpoint | Returns | | - | - | | `GET /brokers/connections` | Your broker connections | | `GET /brokers/{connectionId}/status` | Connection state | | `GET /brokers/{connectionId}/holdings` | Holdings at the broker, with currencies and sync times | | `GET /brokers/{connectionId}/margins` | Cash and margin | ## Reconnect When the status says a reconnect is needed, call `POST /brokers/{connectionId}/reconnect`. Trading 212 also has: * `POST /brokers/{connectionId}/trading212/reconnect` to reconnect with a new key and secret. * `POST /brokers/{connectionId}/trading212/reconnect-stored` to retry with the key Itoflow already holds. * `POST /brokers/trading212/connect-manual`, another way to connect with an API key. ## Disconnect `DELETE /brokers/{connectionId}` disconnects the account. The response doesn't tell you what happened to open positions or orders, so first check any live portfolio that uses the connection and cancel its pending trades. A connection ID only works for the account that owns it. See the [broker endpoint reference](/api-reference/coverage#brokers) for each broker's fields and errors. # Chat Source: https://docs.itoflow.ai/features/chat Start research from your AI assistant over MCP and follow it to the end, read conversations and their results, download and share what a chat made, and run chats on your own ChatGPT subscription instead of Itoflow credits. > [!TIP] > > **The easiest way: ask your AI assistant.** With [Itoflow MCP](/mcp/install) connected to Claude or Codex, paste: > > ```text theme={null} > Use Itoflow to compare SPY and VTI diversification. Explain the method, include > sources, and wait for the research to finish before summarizing 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%20compare%20SPY%20and%20VTI%20diversification.%20Explain%20the%20method%2C%20include%20sources%2C%20and%20wait%20for%20the%20research%20to%20finish%20before%20summarizing%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%20compare%20SPY%20and%20VTI%20diversification.%20Explain%20the%20method%2C%20include%20sources%2C%20and%20wait%20for%20the%20research%20to%20finish%20before%20summarizing%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/chat). The rest of this page covers the HTTP API. Chat is Itoflow's research agent. You ask a question; it writes and runs code against market and portfolio data, then answers with a dashboard of results and evidence. [Open Chat](https://app.itoflow.ai/chat) to try it. From your own tools you can: * **Start research** through [MCP](#run-research-through-mcp). The HTTP API doesn't start research turns. The old `POST /chat` endpoint and `siq` command-line tool are retired; use your Model Context Protocol connection for programmatic research. * **Read conversations** and their results with the HTTP API or MCP. * **Download files** a chat created. * **Share** a read-only copy of a chat. For research requests to start from, each with a published result, see [Use cases](/use-cases/overview). ## Choose reasoning depth In the app's composer, choose how much reasoning the agent spends on a turn: **Low**, **Medium**, **High** or **Extra High**. The choices depend on the model, and the selector shows the level the selected one runs at. If the model you switch to lacks your current level, the composer picks the nearest one. A change applies to the next run; a running or resumed task keeps the settings it started with. Your plan sets which [models](/features/billing#models-and-plans) you can choose. ## What a finished turn contains | Part | What it is | | - | - | | Dashboard | The final answer: text, tables, charts, formulas and method diagrams. It stands on its own. | | Progress updates | Short messages during the run, such as “I'm fetching price history.” They stay in the transcript. | | Working steps | What the agent did, one plain line per step: its reasoning, tool calls and delegate replies. While the agent works, the steps show open. When it finishes, they fold into one line above the answer, such as “Analyzed symbols, ran a command · 1 failed”. Open a step to see what the tool did: the command it ran and what it printed, the file it wrote, or the lines an edit changed. | | Independent review | A check of the agent's work at key steps, when the agent builds a workflow. | | Files | Code, data and reports the agent wrote, kept in the chat's private workspace. | The agent keeps working toward the result you asked for and shares progress updates along the way. Answering a clarification lets it resume that work. You can ask it to make reasonable research assumptions and state them. That instruction carries forward as it works; it still needs evidence for source facts and your authority for actions beyond the request. Send follow-up requests in the same chat to continue with its earlier results and saved files. Reopening the chat keeps its earlier conversation available; you do not need to paste earlier answers into a follow-up. After a connection failure, retry or ask the agent to continue from its saved work, then check the resulting dashboard and files. If the model provider can no longer find its saved response, Chat makes one recovery attempt using the stored conversation and completed tool results. It does not rerun those completed tools. Other failures still surface in the chat for retry or investigation. After an interrupted turn, Chat sends the saved conversation and completed tool results to the model, without relying on that turn's incomplete provider response. Long turns 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 recovery and show an error; check the saved result before retrying. The final dashboard contains the requested result and files, or explains a concrete blocker, what the agent tried, and what is needed to proceed. When one part is blocked, the agent continues other required work that remains possible; it does not ask permission to carry on with your existing request. The agent asks about preferences and constraints when they could materially change the work; optional refinements do not prevent a useful answer. If a core data or tool dependency prevents reliable analysis, it stops that analysis and explains the blocker. Peripheral data defects can be excluded when the remaining analysis stays reliable, with material coverage limits stated in the answer. If you ask for a status update or methodology alone, that can be the final answer. Material choices about your objective, risk, capital or permissions still need your answer before dependent research begins. Where user-context retention is enabled, long conversations keep the original request, later amendments and answered questions alongside compacted working context. This also applies when the agent resumes after a restart. If those user inputs exceed the supported context budget, the agent reports a context limit instead of silently removing requirements. Availability depends on the configured runtime. For a complex comparison, give the question, the data or portfolio to use, and any limits that matter, and ask for the method as well as the result. For example, paste this into your assistant: ```text theme={null} Use Itoflow to compare monthly rebalancing with a 5% drift-band rule for my largest portfolio after trading costs. Explain each rule with a small example, define realized tracking error, and chart the account against its benchmark. State which dates and holdings you used, and wait for the research to finish before summarizing 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%20compare%20monthly%20rebalancing%20with%20a%205%25%20drift-band%20rule%20for%20my%20largest%20portfolio%20after%20trading%20costs.%20Explain%20each%20rule%20with%20a%20small%20example%2C%20define%20realized%20tracking%20error%2C%20and%20chart%20the%20account%20against%20its%20benchmark.%20State%20which%20dates%20and%20holdings%20you%20used%2C%20and%20wait%20for%20the%20research%20to%20finish%20before%20summarizing%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%20compare%20monthly%20rebalancing%20with%20a%205%25%20drift-band%20rule%20for%20my%20largest%20portfolio%20after%20trading%20costs.%20Explain%20each%20rule%20with%20a%20small%20example%2C%20define%20realized%20tracking%20error%2C%20and%20chart%20the%20account%20against%20its%20benchmark.%20State%20which%20dates%20and%20holdings%20you%20used%2C%20and%20wait%20for%20the%20research%20to%20finish%20before%20summarizing%20it.) > > Start this in ChatGPT with the Itoflow plugin. Using another client? Copy the prompt with the button on the code block. ## Shared agent memory Agents can remember information across your chats. Your Monitors and delegates share the same memory. Agents choose what to save and when to look it up. You can ask an agent to remember a preference, or to forget one when it changes. Memory is private to your account. Public shares cannot read or add to it. Deleting a chat keeps your memory; deleting your account deletes it. Do not ask agents to remember credentials. ## Read conversations | Task | Endpoint | | - | - | | List your chats | `GET /chats` | | Read a chat and its messages | `GET /chat/{id}` | | Read a chat's task count and status | `GET /chat/{id}/sync` | | Read a table a chat produced | `GET /dataframes/{chatId}/{dfName}` | | Delete a chat and its files | `DELETE /chat-runtime/chats/{chatId}` | `GET /chats` lists your ordinary Chats only. Each item includes nullable `resource_type`: `chat` for a classified Cloudflare Chat, or `null` for a compatible legacy API Chat. Monitor sessions and Cloudflare rows without a proven type stay out of the list. Pass `runtime=cloudflare` for current Chats only, or `runtime=api` for Chats from the previous chat system. `GET /chat/{id}` and its `/events` alias read ordinary Chat history; a Monitor session is read through its Monitor owner. The events alias returns saved history, not a live stream. Saved history updates as a turn progresses but can trail it. To follow a turn while it runs, use `agent.getTurn` through MCP. If saving a previous turn has not finished, a new research run can remain blocked even when its answer is visible. Wait and check the existing turn before submitting another request. Retrying a turn with the same `message_id` does not start the research again. > [!WARNING] > > Deleting a chat is permanent and removes its workspace files. Your connected integrations stay connected. If you lose the response, send the same delete again. ## Download files from a chat In the app, open **Files** in a chat to browse and download what the agent wrote. From code: 1. `GET /chat-runtime/chats/{chatId}/workspace` lists one folder. Pass `path` to open a subfolder, and `limit` and the returned `cursor` to page through a large folder. Paths are relative to the workspace root, such as `results/report.csv`. 2. `GET /chat-runtime/chats/{chatId}/downloads/workspace/{relativePath}` downloads one file. ```bash theme={null} curl --fail-with-body --silent --show-error --output report.csv \ 'https://api.itoflow.ai/chat-runtime/chats/3f2b8c1e-7a4d-4e5f-9b6a-2c8d1e0f4a7b/downloads/workspace/results/report.csv' \ --header "Authorization: Bearer $ITOFLOW_ACCESS_TOKEN" ``` * Listings leave out the agent's own runtime files and dependency caches. * Downloads can't resume part-way. A retry starts the file from the beginning. * Downloads don't wait for the agent's work. A file the agent is still writing can download part-written, so download results after the agent has finished with them. * A `409` means two other downloads or reads from this chat's workspace are in progress. Retry when one finishes. * Shared copies of a chat show that a file exists but never let readers download it. Through MCP, your assistant lists files with `workspace_list` and reads them, up to 32 MiB each, with the MCP `resources/read` method. Use the download endpoint for anything larger. ## Connected services and actions Chat can combine data from Itoflow and your [connected services](/features/integrations) with files in its workspace. Your permissions and required reviews and approvals still apply. * When a question concerns one of your connected services, Chat checks that service before searching the web. * If a connected service needs you to sign in again, Chat says so and names it. Reconnect it under **Integrations**. * Chat can find files that your earlier chats saved, such as a report or CSV file. It can only see your own chats. * Chat can start new chats and send messages to your other chats, then read their answers. Ask it, for example, to research two funds in two separate chats and compare the results. The chats it starts appear in your chat list, and you can open and continue them. Each chat has its own workspace, so Chat includes what the other chat needs in its message. The chat that receives a message sees which chat sent it and can reply. If a run fails after completing an action, that action is not undone. Check the current state before asking Chat to repeat a change. ## Run research through MCP [Connect your assistant](/mcp/install) first. Four methods, called through the MCP `execute` tool, run research: | Method | What it does | | - | - | | `agent.runTurn` | Sends a message to a new or existing chat and starts the research, or queues it while the chat is busy. | | `agent.getTurn` | Returns the turn's status, and its result when finished. | | `agent.cancelTurn` | Asks the turn to stop, or removes a message still waiting in the queue. | | `agent.listQueue` | Lists the messages waiting in the chat's queue. | ```javascript theme={null} const turn = await agent.runTurn({ chat_id: "chat-research-1", message_id: "message-research-1", message: "Compare SPY and VTI diversification.", model_key: "astra", }); ``` `runTurn` returns as soon as Itoflow accepts the turn. The research then runs for minutes; poll `getTurn` until it finishes, rather than sending the message again. Chat can assign part of a research task to a background analyst. The analyst sends its saved result back automatically, and the main agent can ask the same analyst follow-up questions with its earlier conversation intact. The main turn stays in progress while required results are pending. Keep polling the same `getTurn` until that turn returns its final result or a terminal error; clients cannot control internal delegates through the public API. Cancelling the main turn also stops its outstanding delegate work. The main agent and its background analysts share the chat's workspace. They can run commands in it at the same time, with no fixed limit. Running commands never block file reads or downloads. To retry after a lost response, send the same `message_id`, `message` and `model_key`; Itoflow treats it as the same turn. A new `message_id` starts a new turn. After reconnecting, use `agent.getTurn` with the same `chat_id` and `message_id` to read the saved result or failure. If the agent needs to ask you something mid-run, or wants your approval to create a portfolio, clients that can show forms display it. Other clients get the question, or a short summary of the portfolio, as text with a link to the Itoflow chat where you answer or approve. Text never approves a portfolio. A new message doesn't answer the question or the review: it waits in the queue until you do. A portfolio review lists the holdings with current prices, the cash and the amount to allocate. Choose **Create portfolio**, **Send changes to agent** (with a note) or **Reject import**. On **Create portfolio**, Itoflow creates the portfolio and the agent carries on with the result. If prices change before you choose, the form asks you to check again; if an earlier approval already created the portfolio, the form says so and won't create it twice. Declining or closing the form rejects the import; ask the agent if you want a new review. The review stays with the chat, so reloading the page shows the same rows. Later turns give the agent the review's counts, not every row, so a review of 3,000 holdings leaves room for the rest of the conversation. ### Queue messages while a turn runs Each chat has one queue, shared by the Itoflow app and MCP. While a turn runs, the agent waits for an answer, or messages are already waiting, `runTurn` adds your message to the queue and returns status `queued` with a `queue_position`: ```javascript theme={null} const queued = await agent.runTurn({ chat_id: "chat-research-1", message_id: "message-research-2", message: "Also compare their expense ratios.", }); // { accepted: true, status: "queued", queue_position: 1, ... } ``` Queued messages start one at a time, oldest first, when the current turn finishes. While the agent waits for an answer or a review, they keep waiting, with no time limit. * `agent.listQueue({ chat_id })` lists every waiting message, including ones queued in the app or by your other chats, with its `message_id`, `position`, a short `preview` and `paused_reason` (`awaiting_input` or `null`). * `getTurn` reports a waiting message as `queued` with its `queue_position`. * `cancelTurn` removes a waiting message before it starts, whichever side queued it. Once a message has started, `cancelTurn` stops it only if it came from MCP or from another chat; stop an app message in the app. A chat holds at most 10 waiting messages. ### Choose a model `model_key` accepts a fusion mode or a single model and saves it as the chat's choice. Later turns keep it unless you pass another. A new chat without a choice uses the plan's `default_mode` from `/pricing/model-access`. Fusion pins a main model and a separate Guardian; a single choice uses the same model for both. Retries keep both admitted routes. See [models and plans](/features/billing#models-and-plans). A paid choice on Free returns `403 model_subscription_required`; an unknown or disabled choice returns `409 model_unavailable`. On the Free plan, `/pricing/model-access` returns an `advisory` with `code: "free_plan_model_limitations"`, a `message` and an `upgrade_url`. MCP results that start research or create a monitor or strategy add the same notice as text. If you build a client, show it to the user once per conversation. Paid plans never receive it. ## Connect your own ChatGPT subscription Chat and monitor runs can use your ChatGPT subscription instead of Itoflow credits. Connect it in the app at [**Integrations → Codex (ChatGPT subscription)**](https://app.itoflow.ai/integrations#codex-subscription) (in the sidebar, or under **More** on mobile), or with these endpoints: ```mermaid theme={null} flowchart LR Start[Start connection] --> Approve[Approve the code with OpenAI] Approve --> Poll[Poll until connected] Poll --> Turn[Run research on your subscription] ``` | Endpoint | Returns | | - | - | | `POST /codex-subscription/start` | A code, the OpenAI approval URL, a polling `interval_seconds` and an expiry | | `POST /codex-subscription/poll` | `pending`, `connected`, `denied` or `expired` | | `GET /codex-subscription` | Whether the feature is on for you (`rollout`), and whether you're connected or have an approval in progress | | `DELETE /codex-subscription` | Disconnects | Itoflow turns this on for each account. Before you start, check that `GET /codex-subscription` returns `rollout: "enabled"`. If it's `disabled`, start returns `403 subscription_disabled`; ask [support@itoflow.ai](mailto:support@itoflow.ai) to turn it on. Open the approval URL, approve the code with OpenAI, then poll no faster than `interval_seconds`. If a previous disconnect is still being cleaned up, start, poll and disconnect return `503 disconnect_cleanup_pending`; try again shortly. **What it covers.** Chat and monitor runs, including their independent reviews, on a single OpenAI model choice. Fusion modes always use Itoflow keys for both agents and need plan access. A connected subscription gives you those models even on Itoflow's Free plan. It does not give you the Claude models: those need Pro or Max. Strategy runs still use Itoflow credits. **When the subscription can't be used.** If the connection needs signing in again or your ChatGPT plan refuses a request, for example because you reached its usage limit, the run continues on Itoflow credits at normal rates. The exception is a paid model that only your subscription gave you: that run stops and asks you to reconnect or choose another model, so you're never charged for a model your plan doesn't include. A very long turn can fail if its OpenAI access token expires part-way. See [billing](/features/billing#chatgpt-subscription-usage) for how this shows in your usage. **Security.** These endpoints never return OpenAI tokens. Itoflow keeps your refresh credential out of the agent's environment; the agent gets only a short-lived access token for its run. Disconnecting stops new runs from using the subscription straight away and asks OpenAI to revoke Itoflow's tokens. Deleting your Itoflow account removes the saved credential. ## More * [Sharing](/features/sharing): publish a read-only copy of a chat. * [Connect GitHub and MCP servers](/features/integrations): give Chat access to your repositories and other MCP servers. * [Chat endpoint reference](/api-reference/coverage#chat). * [What our quant-research agent actually does — and where it still needs a human](https://itoflow.ai/blog/what-our-quant-research-agent-actually-does): a worked research run, step by step. # Connect GitHub and MCP servers Source: https://docs.itoflow.ai/features/integrations Let Itoflow's research agent read and change your GitHub repositories, open draft pull requests, and call tools on your own MCP servers. Tokens never reach the model or the sandbox. > [!TIP] > > **The easiest way: ask your AI assistant.** With [Itoflow MCP](/mcp/install) connected to Claude or Codex, paste: > > ```text theme={null} > Use Itoflow to list my MCP server connections and their status, and show the > tools each ready connection offers. > ``` > > > [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%20list%20my%20MCP%20server%20connections%20and%20their%20status%2C%20and%20show%20the%20tools%20each%20ready%20connection%20offers.) > > > > 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%20list%20my%20MCP%20server%20connections%20and%20their%20status%2C%20and%20show%20the%20tools%20each%20ready%20connection%20offers.) > > > > 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/integrations). The rest of this page covers the HTTP API. Connections give Itoflow's research agent extra tools: your GitHub repositories, or any remote MCP server you use. Once connected, they are available in all your chats. This page is about connecting other services *to* Itoflow. To connect your own assistant to Itoflow, see [Itoflow MCP](/mcp/overview). You can manage connections in three ways: in the app under [**Integrations**](https://app.itoflow.ai/integrations) (in the sidebar, or under **More** on mobile), with the HTTP endpoints below, or by asking your assistant through Itoflow MCP. All three change the same saved connections. ## GitHub | Endpoint | What it does | | - | - | | `GET /integrations/github/availability` | Whether GitHub connections are enabled for your account | | `POST /integrations/github/getConnection` | Your connection status | | `POST /integrations/github/connect` | Starts connecting or reconnecting; returns a `url` | | `POST /integrations/github/listRepositories` | Repositories Itoflow can see | | `POST /integrations/github/disconnect` | Disconnects | The `POST` endpoints take a JSON body; send `{}` when there are no inputs. To connect, call `connect`, open the returned `url` in a browser and approve access on GitHub, then call `getConnection` to confirm. If a write returns `outcome_unknown`, check the connection before you retry. The status response also has an `installUrl`, where you choose which repositories Itoflow can see. `listRepositories` takes `page` and `perPage` and returns `items` and `nextPage`. Keep `perPage` the same while you follow `nextPage`. ```bash theme={null} curl --fail-with-body --silent --show-error \ 'https://api.itoflow.ai/integrations/github/listRepositories' \ --header "Authorization: Bearer $ITOFLOW_ACCESS_TOKEN" \ --header 'Content-Type: application/json' \ --data '{"page": 1, "perPage": 30}' ``` ## Remote MCP servers You can connect any MCP server that has a public HTTPS URL and supports Streamable HTTP. ```text theme={null} Add server URL → Sign in with OAuth or a bearer token → Tools appear in your chats ``` In the app, open [**Integrations → MCP servers**](https://app.itoflow.ai/integrations#connections) (in the sidebar, or under **More** on mobile), select **Add MCP server**, enter the URL, then choose **Connect**. With the API, first call `GET /integrations/remote-mcp/availability` to check the feature is on for you; `POST /integrations/remote-mcp/list` lists your connections. Then: 1. `POST /integrations/remote-mcp/add` with `endpoint` and an optional `name`. It returns the new `connection`, including its ID and `version`. 2. `POST /integrations/remote-mcp/connect` with `connectionId` and `expectedVersion`. If the server uses OAuth, open the returned `authorizationUrl` and sign in. 3. `POST /integrations/remote-mcp/getStatus` with `connectionId` and the returned `attemptId` until the connection is ready. ```bash theme={null} curl --fail-with-body --silent --show-error \ 'https://api.itoflow.ai/integrations/remote-mcp/add' \ --header "Authorization: Bearer $ITOFLOW_ACCESS_TOKEN" \ --header 'Content-Type: application/json' \ --data '{"endpoint": "SERVER_URL", "name": "Research tools"}' ``` Replace `SERVER_URL` with the MCP server's HTTPS URL. Other endpoints rename a connection, list its tools, disconnect it, or remove it. Removing also deletes the saved credential. Each change takes the connection's current `expectedVersion`; if another change got there first, you get `connection_changed`. Read the list again and retry with the new version. If a `connect` response is lost, call `getStatus` before you try again. ### Servers that use a bearer token If the server gives you a token instead of OAuth, pass it as `bearerToken` to `add` or `connect`, or paste it in the app. Send only the token, without the `Bearer ` prefix: at most 8,192 characters, with no spaces or control characters. Itoflow keeps the token exactly as issued, including punctuation, and stores it encrypted. It is sent only to that server, and Itoflow never passes on your own Itoflow credentials. When you use MCP, your assistant's inputs can end up in its conversation history. Don't paste server tokens into a chat; add them in the app or with the API instead. ### If connecting fails * After a failed OAuth sign-in, choose **Connect** again to start a fresh one. * If a server changes its OAuth sign-in settings, connecting again deletes the old saved sign-in and starts a new one. You don't need to disconnect or remove the server first. * If Itoflow says the server rejected the OAuth discovery request, Itoflow couldn't fetch the server's sign-in details. Try again; if it keeps failing, email [support@itoflow.ai](mailto:support@itoflow.ai). * `POST /integrations/remote-mcp/listTools` shows every tool a connected server offers. * A connected server can be temporarily absent from a research turn when catalog discovery fails. Missing tools alone do not mean your OAuth sign-in expired; reconnect when the connection reports that sign-in is required. For a worked example, see [Research with your own code and tools](/use-cases/research-with-your-code). [How we connected customers' MCP servers and GitHub repos to our research agent](https://itoflow.ai/blog/how-we-connected-mcp-servers-and-github), October 7, 2026, explains how tokens stay out of the model and the sandbox. See the [GitHub](/api-reference/coverage#github) and [MCP connection](/api-reference/coverage#connected-mcp-servers) endpoint references for every field. # Market data and risk Source: https://docs.itoflow.ai/features/market-data Read quotes and prices, per-symbol analytics against a benchmark, FX rates and a factor-risk covariance matrix, and search stored news and SEC filings by meaning or by company, including news that never names the company. > [!TIP] > > **The easiest way: ask your AI assistant.** With [Itoflow MCP](/mcp/install) connected to Claude or Codex, paste: > > ```text theme={null} > Use Itoflow to get the factor-risk covariance for AAPL.US, MSFT.US and SPY.US as > of 2026-06-30, and explain which pair moves most together. > ``` > > > [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%20get%20the%20factor-risk%20covariance%20for%20AAPL.US%2C%20MSFT.US%20and%20SPY.US%20as%20of%202026-06-30%2C%20and%20explain%20which%20pair%20moves%20most%20together.) > > > > 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%20get%20the%20factor-risk%20covariance%20for%20AAPL.US%2C%20MSFT.US%20and%20SPY.US%20as%20of%202026-06-30%2C%20and%20explain%20which%20pair%20moves%20most%20together.) > > > > 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/chat). The rest of this page covers the HTTP API. Start by turning a ticker or company name into an Itoflow symbol such as `AAPL.US`; see [Find and resolve symbols](/guides/symbols). Every endpoint that takes an instrument expects that form; FX, benchmark, leaderboard and cache-status reads take no symbol. ```mermaid theme={null} flowchart LR Query[Ticker or company] --> Resolve[Itoflow symbol] Resolve --> Quotes[Quotes and symbol cards] Resolve --> Analytics[Symbol analytics] Resolve --> Risk[Factor risk] Resolve --> News[Stored news] ``` ## Quotes and prices | Endpoint | Returns | | - | - | | `POST /symbols/quotes` | Recent quotes for up to 60 symbols, sent as `{"symbols": ["AAPL.US", "MSFT.US"]}` | | `GET /symbols/baseline` | Summary cards for the `symbols` you pass | | `GET /symbols/cache-status` | How fresh the stored quotes are | | `GET /benchmarks` | Benchmark performance for comparisons | | `GET /fx-rates` | Current exchange rates | | `GET /fx-rate` | One exchange rate | | `GET /leaderboard` | Anonymous strategy rankings, by `period` | `POST /symbols/quotes` returns only quotes Itoflow already holds and leaves out symbols it has none for. A missing quote doesn't mean the symbol is invalid. For supported listing markets, the price reader uses FMP intraday bars. A latest price comes from the newest completed one-minute bar available, with no extra 15-minute delay imposed by Itoflow. The provider's feed may itself be delayed, and a closed market may retain an earlier session's price. The bar keeps its actual source time; a successful fetch does not make an older price current. The reader accepts bars within a 14-day lookup window. The last minute bar can differ from the official daily closing price, including after the session ends. Use daily history when you need the daily close. Intraday history retains its requested interval and price and volume basis. Each listing still needs a verified provider link; missing coverage remains unavailable rather than switching providers. Paper trades accept a positive converted price without checking whether its source time belongs to the current session. A market whose feed has not published today's bars can therefore fill a paper trade at an earlier session's price. The trade records when it executes, which can be later than the price observation. Check source time separately when deciding whether an observation is suitable for a current-session trade. For symbol cards, a name with no linked price history is unresolved; other names can still return cards. Provider timeouts and connection or upstream faults follow the [read rule](#symbol-analytics). If a second attempt fails without an answer from the same provider since it began, the request fails. Overlapping final attempts can instead return partial data. Eligible public source replies can be shared across callers until their refresh deadline, even if the original calculation failed. A cache hit does not certify identity, coverage or point-in-time eligibility. Historical reads preserve the provider's row order and include announced future events within the requested window. Each historical reader applies its own cutoff and validates the records it consumes. A quote's `price` is in US dollars; `native_price` and `currency` give the price in the currency it trades in. Holdings and trades keep their own currency, and your display-currency setting doesn't change it. Convert with the FX endpoints when you need to. Daily history and corporate actions select a provider by the listing's market and the requested data. A listing needs a verified link to the provider's exact exchange, securities identifier, share class and quoted currency. Missing or conflicting identity can leave that listing unavailable; an exchange appearing in a provider directory does not prove full coverage. Pence (`GBp`/`GBX`), rand cents (`ZAc`/`ZAC`) and agorot (`ILA`) retain their units in native daily prices and dividends. Share volume counts shares and never scales with currency. Symbol discovery uses the same units: a pence listing returns `GBX`, rather than `GBP`. The exchange directory includes the markets served by these daily routes and the four held German floors. In markets that require ISIN evidence, Python and TypeScript discovery check the exact provider profile when a search row lacks it, whether you search one market or all markets. The profile must confirm the same listing, exchange and quoted currency before the candidate or its currency can be used. Missing or conflicting evidence leaves the candidate out. An older link missing that evidence cannot supply daily prices. Frankfurt (`F`), Dusseldorf (`DU`), Munich (`MU`) and Stuttgart (`STU`) keep EODHD daily history and actions because FMP serves a different price stream on those floors. FMP can restate earlier raw closes after rights issues, spin-offs and demergers; its raw history may differ from prices recorded before those events. ```mermaid theme={null} flowchart LR Listing[Verified listing] --> Route[Market and requested data] Route --> History[Daily history and actions] ``` The leaderboard never shows whose strategy is whose; you can see only which rows are your own. ## Historical index research For a historical index in Chat, specify the listing market, selection dates, implementation lag, liquidity rule, weighting, costs and required files. For a thematic index, Chat builds a versioned, cited research universe, then applies dated listing, liquidity and capitalization rules at each rebalance. The report states the universe's research date, discovery sources and hindsight limits. Current classifications can inform that research universe. Reconstructing how thematic membership changed over time is a separate method to request explicitly; a current description cannot establish past membership. SEC filing availability uses a stated proxy: the later of acceptance or 06:00 New York time on its official filing date. This excludes late submissions before their assigned day. Exact website-publication times are unavailable; the report states this timing limit. The US calendar uses NYSE session dates as an aggregate market convention. This does not assign NYSE identity to a Nasdaq or other US listing; primary listing and quoted-security identity need their own dated evidence. The historical dataset reader's `price_session_coverage()` checks retained bars against the publication's declared market calendar. It reports missing, extra and duplicate sessions with source pins, separately from identity and action qualification. Optional `start` and `end` dates restrict the check to an acquired window. Calendar failures propagate; the check never fills missing bars or upgrades the bundle's other coverage. Calendar functions take platform market codes such as `US`, rather than a provider's venue labels. For a verified same-security ticker change, historical acquisition queries each FMP ticker within its effective date range. Raw bars retain one security ID, the actual provider symbol and source pins. Matching identity and a unique dated transition are required; an ambiguous change never fills an ended price series. Check session coverage and corporate actions separately. `prepare_historical_equity_dataset` reads a bundle from the shared market-data cache and builds it in the Chat sandbox when the cache has none. A large request takes minutes. Request smaller date windows with their decision cutoffs, retain each bundle and reconcile overlapping observations. The function makes no automatic retries or substitutions. Strict historical calculations need validated datasets with dated identity, prices, quoted-class shares and corporate-action terms. The library's source adapters own acquisition and validation; the agent must not fill missing financial records with web search or hand-written observations. Missing data can prevent an exact reconstruction. When the request allows estimates, use a disclosed proxy with a dated source and test whether reasonable alternatives change selection, weights or conclusions. Keep estimated results distinct from observed facts. Statement readers fill a blank reporting currency only when statement rows available by that row's own availability date agree on one whole-unit currency. The read cutoff also applies. Later filings cannot supply or veto that currency. A section-wide currency counts only through its dated rows. Subdivision units such as pence can block agreement but never fill a blank. A stated currency keeps its unit. Listing and price currencies do not fill statement gaps. Ordinary shares outstanding and EPS weighted-average shares are different inputs. Retain measurement time, actual publication time, accession and source. An ADR price needs shares on that receipt's quoted-unit basis. Current ticker metadata cannot establish a retired security's identity, and a named subset does not establish a complete historical market universe. A successful source request or a diagnostic coverage report does not establish a completed index. Research qualifies each consumed input and can combine supported readers with checked original documents. An incomplete bundle does not make every input unavailable; unresolved facts still need evidence before dependent calculations. Historical capitalization can use the latest actual share count published by each cutoff, carried forward on the price's physical share basis. Disclose its measurement date, publication date, age and known intervening capital changes. This estimates capitalization; it does not assert that the exact cutoff-day count was public. Verified price history for the same identified security establishes that it traded by that date, without a separate IPO-completion announcement. Price history alone supplies neither share counts nor past business eligibility. The dated report reader selects original annual/interim or admission reports known at each declared decision time and returns readable text with publication times and source pins. It keeps retained amendments separately and removes attributes and explicitly hidden markup. The underlying originals remain available for source checks and event research. This aids business research; it does not establish thematic eligibility or primary-listing history. An eligible original interim remains readable when no earlier annual or admission report exists. Its interim role does not imply complete business history; assess whether its actual content supports the research decision. Reports also retain unambiguous registered symbol, security title and exchange facts from the same issuer and filing context in `registered_securities`. Publication times and original source hashes remain attached. These records support dated listing research; they do not certify a global primary venue, continuous listing history or a binding to today's identifier. Incomplete or conflicting registration facts remain unqualified. The library reads original SEC reports and their declared share-fact attachments. Receipt conversion terms must appear in the report or its linked securities exhibit. It retains separate sources for the share count and quoted-unit terms; rounded share aggregates cannot establish a receipt ratio. An inline cover count without a class dimension can qualify only when its own explicit declaration identifies the registered class and agrees with the fact's date, issuer and share units. Nearby class names cannot qualify an aggregate. This applies to common-stock titles with or without a lettered class; a cover's navigation link alone does not make the count a financial-statement fact. Historical registered ticker/class counts remain available as separate source observations. They require dated legal continuity evidence before research can assign them to a current listing; a shared issuer alone does not prove that link. Requests for documents and actions also retain original material-event filings and their declared event exhibits, with source hashes and actual publication times. Research can derive exact action terms from this governed corpus and retain the supporting evidence. A price factor or an empty action table cannot substitute for that evidence. For a newly listed company with no annual report public at the decision cutoff, the library can retain its final IPO prospectus or latest registration as dated listing-admission research. Offering and pro-forma quantities remain research evidence until actual issuance and quoted-class units have been established. The research agent calls `prepare_historical_equity_dataset` with one US listed company's share, such as `AAPL.US`, and historical dates and decision cutoffs; funds are out of scope. FMP's profile fixes the listing's identity, the library acquires fixed-source evidence, and the agent receives a verified, versioned bundle. Bundles stay in the shared cache for 72 hours under a daily write limit; once that limit is reached, a new bundle stays in the calling process only. The function accepts no financial observations or source URLs. A publication's coverage describes its observed records; estimated research must declare any additional proxy convention. For several listings, acquisition can reuse a fresh market directory while retaining its original source hashes and retrieval times. Each listing still needs its own identity, price, report and event evidence. Directory reuse does not establish historical eligibility. The universe table also retains bounded current FMP descriptions, classifications and listing flags as `current_profile_observation` rows. Their `current_discovery_only` scope, retrieval time and source hash identify them as discovery metadata; they do not prove past business or primary-listing status. The same table retains paged FMP sector/industry/venue leads as `current_screen_observation` rows alongside separate retired-directory leads. Discovery does not filter by current market cap or issuer domicile. The dated report and share-count readers validate the requested cutoff: a missing early report or share fact does not hide usable later observations. An unavailable requested cutoff still fails, and full-history coverage remains unchanged. `overview()` shows retained input counts and coverage without dumping source documents. Exact `request_id` and `bundle_id` properties pin later reads. The `discovery_leads()`, `raw_price_observations()` and `action_observations()` views retain source fields and explicitly remain observations. A failed convenience reader does not discard that acquired data. Research must still qualify dated identity, currency, expected sessions and physical action terms before using it in calculations; these views never promote incomplete coverage or fill a missing price tape. Historical index workflows can declare the acquisition or reader helper as the source of their price, volume and fundamental inputs. The source declaration identifies the route; the calculation must still qualify its consumed records. A listing's identity comes only from FMP's exact profile for its ticker. Caller-provided identity overrides are refused. When ISIN discovery returns several US quotations, an exact canonical ticker still needs matching profile identity, currency and venue; a conflicting profile cannot redirect the request to another quotation. For public fund filings, an equity row in USD that has no usable listing keeps its stated weight and its match failure: historical and retired US leads from its ISIN, derived CUSIP or ticker are matched by listing currency and price. A row that already names a USD listing keeps that listing unchanged. The match failure remains part of the fund-book evidence rather than being treated as a zero weight. A quarterly filing book with an unread line is not stored; the next run reads that quarter again. Name-based recovery requires a readable share class or series designator to match the candidate's exactly. An explicit `class`, `cls` or `cl` followed by an unreadable token (`CLASS AA`, `CL.AA`) leaves the row unresolved even when a candidate's price matches. `series` and `ser` are ordinary words unless a readable designator follows (`Series A`, `Series 2`). A class word at the end of a name (`Share Class`) states no designator. For a retired quote with a missing price tail, a request can include the `aliases` family. The library qualifies a forward ticker change only when dated provider transitions and exact security, issuer, currency and venue evidence agree. Alias rows retain effective dates and source identities. Use those epochs with the normal price reader and raw units; a pure rename changes neither shares nor cash. Ambiguous chains remain unresolved. Qualified aliases alone do not establish historical primary status, legal action terms or complete price-session coverage. The normal dividend reader preserves declaration, record and payment dates when supplied by the provider. An absent payment date does not imply payment on the ex-date. For source reconciliation, requesting actions retains FMP's original dividend observations in the bundle's universe table, including declaration, record and payment dates when supplied. Qualify amounts against the exact quoted units and currency, and keep receivables until the sourced payment date. A corporate-action price factor does not always change the parent's shares. Spin-offs require separate child entitlements at the issuer's stated ratio. Historical portfolios should retain source evidence and reconcile physical shares, cash, dividends, trades and fees. An index capped at each daily close does not establish full UCITS or intraday compliance. For capitalization weighting, the Chat library's `proportional_weights` helper preserves the actual positive market-cap amounts and supports proportional cap redistribution. Score-ranking weights follow a different rule. Physical trades, fees and daily compliance still require a portfolio replay. These are Chat research capabilities, not a historical market-cap HTTP endpoint. The quote and analytics routes below retain their stated contracts. ## Symbol analytics `GET /symbols/analytics` returns the analytics a research monitor computes before it writes a report, for any 1 to 12 symbols. You don't need a monitor, and Itoflow saves nothing to one. Symbol analytics is rolling out: until it is turned on for your account, this route returns `404`. ```bash theme={null} curl --fail-with-body --silent --show-error \ 'https://api.itoflow.ai/symbols/analytics?symbols=AAPL.US,MSFT.US,NVDA.US' \ --header "Authorization: Bearer $ITOFLOW_ACCESS_TOKEN" ``` | Query parameter | Meaning | | - | - | | `symbols` | 1 to 12 comma-separated symbols; a repeated symbol counts once. A ticker without an exchange, such as `AAPL`, means its US listing. A symbol may use letters, digits and `.` `-` `^` `=` `_` `&`; anything else returns `400 invalid_symbols`. | | Response field | Meaning | | - | - | | `as_of` | The date of the latest close used, as `YYYY-MM-DD` | | `computed_at` | When Itoflow computed the analytics | | `cache.hit` | `true` when the result is one Itoflow computed earlier and kept | | `cache.ttl_seconds` | How long Itoflow keeps the result: 600, or 60 when some symbols or data sources failed, so a retry soon gets fresh figures | | `snapshot.symbols` | Each symbol's returns, volatility, beta against `snapshot.benchmark` (`SPY.US`), 52-week range, signal z-scores, fundamentals, valuation, analyst views and sector percentiles. A symbol without price data has only `error`, such as `no_price_data`. | | `snapshot.watchlist` | The symbols taken together: an equal-weight index against the benchmark, sector mix, market regime, correlation and highlights | | `snapshot.computed_for_symbols` | The symbols that had price data | | `snapshot.data_receipt` | Which inputs Itoflow fetched and which failed | A figure Itoflow can't compute is left out or `null`, never zero. Itoflow keeps each result for `cache.ttl_seconds`, so asking again within that time returns the same `computed_at`. It keeps no error, so the next request computes again. Analyst views and forward valuation depend on the symbol's data provider. US listings and listings on LSE, XETRA, PA, AS, SW, TO, AU, OL, KO, KQ, SHE, ST, CO, BR, MC, WAR and HE take point fundamentals, financial statements and earnings from FMP. It states trailing figures and no analyst forecasts. For those symbols `analyst.covered` is `false` with a `note`, and the forward P/E, PEG ratio and target price are `null`. Itoflow never fills them with a trailing figure or zero. Market-wide fundamentals snapshots and fund holdings keep their existing routes. SHG, TSX Venture (`V`), London IOB (`IL`) and Frankfurt (`F`) retain EODHD fundamentals. A listing without a verified provider binding has no point fundamentals; Itoflow reports them as not known. Non-US statement rows use results-release dates when valid filing dates are absent; a period end alone never establishes when the market could have known a figure. When a symbol's price history times out, loses its connection or meets an upstream error that waiting may clear, Itoflow waits 5 seconds and reads again. If it still fails, it waits 30 seconds and reads once more. An answer ends the retries. If the last read still fails this way, Itoflow leaves the symbol without volume figures only if the same provider answered another request after that last read began. `snapshot.data_receipt` names the unread symbol; other symbols keep their figures. A failed last read without an answered request in that interval fails the whole read. If several last reads overlap the provider's last answer before it stops responding, they can all be left out and the read can return the rest. Rate limits, spent quotas, refused keys, unsupported routes, unavailable snapshots, unknown faults and calendar faults still fail the read. Daily factor fits and month-end fills fail before storing results when read faults leave out more than 1% of the distinct names asked for prices or metadata. Exactly 1% is allowed. Observed gaps, such as no coverage or no currency rate, do not count. A failed fit keeps the last publication. Factor-model publications and return receipts use Monday through Friday. Daily fits and month-end fills remove weekend price bars before computing returns, including listings without exchange metadata. A weekend session's move enters the return of the next weekday its venue trades. Historical publications use the latest weekday price on or before the requested cutoff; live publications use their latest weekday price. | Status | `error` | Meaning | | - | - | - | | `400` | `invalid_symbols` | You passed no symbols or more than 12. | | `422` | `symbol_analytics_unavailable` | None of the symbols has price data. `unresolved` lists them. | | `503` | `symbol_analytics_compute_failed` | Itoflow couldn't compute the analytics. Try again later. | A token with limited scopes, such as one issued to an AI agent, needs `symbols.read`. ## Factor-risk covariance For a portfolio's factor card and factor-risk read, an open holding with no current price is left out, with no value or weight; the rest use the net asset value without it, with a `missing_price_symbols` warning. `POST /factor-risk/covariance` returns a covariance matrix for a set of symbols from Itoflow's factor risk model, as it stood on a past date. It uses the model snapshot from that date, so you can use it in backtests. Check `provenance.classification_inputs`: when it is `current_static`, the sector and country labels are today's rather than that date's. Country factors group companies by the provider's stated country: EODHD gives its listing venue's country; FMP gives its head-office country. The separate head-office country fact drives the [oversight country split](/features/monitors). Adding that fact does not change any country-factor assignment. Funds have no loadings of their own, so this endpoint refuses funds with status `422`. For a book that holds funds, use [risk measure](/api-reference/risk-measure) (`POST /risk/measure`); it reads through their stored holdings. Live model price inputs use completed venue sessions. A venue that is closed for the day uses its last completed trading bar; an open session waits for its close and closing auction. Historical requests retain their stated cutoff. ```bash theme={null} curl --fail-with-body --silent --show-error \ 'https://api.itoflow.ai/factor-risk/covariance' \ --header "Authorization: Bearer $ITOFLOW_ACCESS_TOKEN" \ --header 'Content-Type: application/json' \ --data '{"as_of": "2026-06-30", "symbols": ["AAPL.US", "MSFT.US", "JPM.US"]}' ``` | Request field | Meaning | | - | - | | `as_of` | The date, as `YYYY-MM-DD`. Itoflow uses the latest model snapshot on or before it. | | `symbols` | Up to 1,000 distinct symbols | | `model_version` | Optional. Pin a model version; defaults to the current one. | | Response field | Meaning | | - | - | | `symbols`, `covariance` | The matrix, with rows and columns in the order of `symbols` | | `snapshot_as_of` | The snapshot date actually used | | `base_currency` | The currency the returns are measured in | | `return_convention` | `simple_daily` or `log_daily` returns | | `annualization_factor` | Trading days per year, for scaling: 252 | | `warnings`, `symbol_warnings` | Data-quality notes, overall and per symbol | | `provenance` | How the snapshot was built, including whether the matrix needed a small correction to stay valid (`psd_repaired`) | Before a fit reads returns, it drops zero-volume flat bars before a listing's first trade. This check affects new fits and later reads; it does not rewrite stored publications. Daily venue limits are checked as described below. Keep `snapshot_as_of` and `base_currency` with any numbers you store. Don't compare matrices from different dates or currencies. To learn how the model works, read [How we built a cross-asset factor risk model](https://itoflow.ai/blog/factor-risk-models-for-agentic-portfolios) and [how it compares with Barra](https://itoflow.ai/blog/factor-risk-model-vs-institutional-providers). ## Search stored news `GET /news` searches the public news and SEC filings that Itoflow has stored. It returns headlines, links and ratings, not article text. Each call works in one of four ways: * **By query.** With `q`, Itoflow selects possible matches by similarity, then a model judges whether those candidates bear on your words, by meaning and in any language. Items without a vector also reach the judge. This can find items that never name the subject. Each row is a story: other matches that repeat it fold into it, and `repeats` counts them. Stories come most important first. The model judges the most important candidates first and stops once the rest could not change the rows, so a search can judge far fewer items than it selected. * **By company.** With `symbols` or `monitor_id`, a model first rates the window's news for each company, counting news about its rivals, customers, suppliers, inputs and market. The call then returns the rated items, newest first. * **As a list.** With none of these, the call lists the stored items, newest first, and judges nothing. * **As stories.** With `order=stories` or `order=stories_newest` and none of `q`, `symbols` or `monitor_id`, the call lists stories and judges nothing. Repeats fold into one row per story, shown by the story's highest-impact article in the window. With `stories`, stories come by the UTC day of their first report, newest first, then by impact, then by `published_at`. With `stories_newest`, the same stories come by the shown row's `published_at` descending, then `id` descending. A story keeps the day of its first report, even when that report was stored before the window. With either story order, `hide_commentary=true` drops stories whose shown row has `is_event_p < 0.5`, before the call applies `limit`; a row at exactly 0.5 stays. A model call takes time, so judging stops after about 25 seconds. `coverage.complete` says whether the reply is final: for companies, the model judged every selected candidate in the window; for a query, more judging could not change the rows. It does not mean every stored item reached the judge. Ratings for companies are kept, so a company search that stopped early goes further when you call again with the same input. A query search keeps nothing; call again with fewer `days`. | Query parameter | Meaning | | - | - | | `q` | What the news should be about, in plain words, up to 200 characters. Can't be combined with `symbols` or `monitor_id`. | | `symbols` | Up to 20 comma-separated symbols in `TICKER.EXCHANGE` form. Companies are rated in the order you give. | | `monitor_id` | Search the current holdings of one of your monitors, heaviest first, with each holding's weight. With `symbols` as well, only the holdings named. | | `days` | How many days back to search, by when Itoflow stored the item. From 1 to 90, default 7. With `q`, from 1 to 3, default 1. | | `order` | `newest` (default), `stories`, or `stories_newest`. Neither story order can be combined with `q`, `symbols` or `monitor_id`. | | `hide_commentary` | Boolean, default `false`. With `true`, keep only stories whose shown row has `is_event_p >= 0.5`, before `limit`. Requires `order=stories` or `order=stories_newest`. | | `country` | Only with a story order: keep the stories with an article in the window that names this country, as an ISO 3166-1 alpha-2 code such as `JP`. | | `sector` | Only with a story order: keep the stories whose shown article has this sector, one of the `sector` values below. Combines with `country`. | | `min_level` | `minor` (default), `notable`, or `material`. With `symbols` or `monitor_id`, it applies to the company rating; otherwise to the item's `impact`. With either story order, it applies to each article before repeats fold. | | `limit` | Rows to return, from 1 to 50. Default 20. With `q` or either story order, it counts stories. The response has no next page. | ```bash theme={null} curl --fail-with-body --silent --show-error \ 'https://api.itoflow.ai/news?q=chip%20export%20rules&days=2' \ --header "Authorization: Bearer $ITOFLOW_ACCESS_TOKEN" ``` A `200` response, trimmed to one story without its `url` and `publisher`: ```json theme={null} { "items": [ { "id": "8d0f3a52-6c1b-4e9a-b7d4-1f2e3a4b5c6d", "source": "gdelt_translingual", "title": "Den Haag scherpt exportregels voor chipmachines aan", "title_en": "The Hague tightens export rules for chip machines", "language": "nl", "published_at": "2026-09-25T13:45:00.000Z", "sec_form": null, "level": "notable", "impact": 2.1, "is_event_p": 0.93, "repeat_of": null, "symbols": [], "countries": ["NL", "US", "CN"], "sector": "information_technology", "match_p": 0.97, "repeats": 4 } ], "coverage": { "sources": ["gdelt", "gdelt_translingual", "sec_edgar"], "searched_from": "2026-09-23T14:00:00.000Z", "complete": true, "stored_through": "2026-09-25T14:00:00.000Z", "judged_from": "2026-09-23T14:00:00.000Z", "judged_items": 812 }, "unknown_symbols": [] } ``` | Field | Meaning | | - | - | | `source`, `language`, `title_en`, `is_event_p`, `repeat_of` | As in the [monitor news feed](/features/monitors#news-feed) | | `sec_form` | The SEC form, such as `8-K`, for a filing; `null` for news | | `impact` | How much the item could move the companies or markets it concerns, from 0 (none) to 3 (material) | | `level` | With `symbols` or `monitor_id`, the level of the top company rating; otherwise the level of `impact`. `material` from 2.5, `notable` from 1.5, `minor` from 1. | | `symbols` | The item's ratings for the symbols you asked for, or with `monitor_id` for that monitor's holdings, highest `materiality` first. Empty when you pass neither. | | `weight` | With `monitor_id`, the holding's current share of the portfolio's net assets, a short counted by its size; `null` for research monitors, for a portfolio worth nothing or less, and for a portfolio whose value is not known because an open holding lacks a usable price, currency or exchange rate. Always `null` without `monitor_id`. | | `countries` | Up to three countries the article names, as ISO 3166-1 alpha-2 codes, most named first. Empty for SEC filings and for articles that name no country. | | `sector` | The sector the article is about: one of the 11 GICS sectors (`energy`, `materials`, `industrials`, `consumer_discretionary`, `consumer_staples`, `health_care`, `financials`, `information_technology`, `communication_services`, `utilities`, `real_estate`), or `economy` for the economy as a whole. `null` when the article has not been sorted. | | `match_p` | With `q`, the model's chance that the item bears on your query; `null` otherwise. Stories rank by `match_p` × `impact` ÷ 3, newest first on ties. | | `repeats` | With `q`, how many other matches repeat this story. With `order=stories` or `order=stories_newest`, how many other articles of the story are in the window. 0 otherwise. | | `story_day` | Only with `order=stories` or `order=stories_newest`: the UTC day of the story's first report, as `YYYY-MM-DD`. It can be earlier than the day of `published_at`, which belongs to the shown article. | | `coverage.searched_from` | The start of the window, by when Itoflow stored the item | | `coverage.complete` | `true` when the reply is final: for every company, the model judged every selected candidate in the window; for a query, more judging could not change the rows | | `coverage.stored_through` | The oldest last successful read across the sources; news after it may not be stored yet. `null` before the first read. | | `coverage.judged_from` | For companies, the time from which every selected candidate is judged to the end of the window; `null` when one company has nothing judged there. For a query, the start of the window when the reply is final, else `null`. | | `coverage.judged_items` | Items the model judged during this call. A query search can judge far fewer items than it selected. | | `unknown_symbols` | Symbols you asked for, or with `monitor_id` holdings, that Itoflow has no company name for. They are skipped; search for them another way. | Results never name a monitor or its owner, and carry weights only for your own monitor through `monitor_id`. Itoflow keeps an item for 90 days when its `impact` is at least 2 or it rated the item notable or above for some company, and for 14 days otherwise. A minor company rating goes after 14 days. A token with limited scopes, such as one issued to an AI agent, needs `symbols.read`. A monitor you don't own returns `404`, the same as a missing one. An invalid parameter returns `400`; so does `q` with `symbols` or `monitor_id` (`query_with_symbols`), either story order with `q`, `symbols` or `monitor_id` (`order_with_query`), `hide_commentary=true`, `country` or `sector` without a story order (`filter_without_stories`), and `q` with more than 3 `days` (`days_exceeds_query_window`). When a model the search needs fails after its retries, the call returns `503` with `news_judge_unavailable` and no partial result; retry later. See the [market-data endpoint reference](/api-reference/coverage#market-data) for every field. ## Fund books used by risk measurement Risk measurement asks the factor worker to score missing names only when they have not joined its fitting universe. Each finished request adds every asked name permanently, including names it could not cover. Daily fits try the whole universe again. An immediate second run reports the coverage add's refusal reason at the same publication without asking again or waiting. Daily fit refusals use the same results. A name with no recorded reason at the pinned publication reports `not_covered`. If no worker claims a request within 60 seconds, a final status check confirms the result before measurement continues with those names unscored. When the service cannot report claim state, the wait keeps its ten-minute cap. A claimed request can use up to ten minutes in total, subject to the run's remaining time. A coverage gap does not by itself fail measurement. `POST /risk/measure` reads the newest eligible stored fund book for each model date. Each measured book and benchmark reports `fund_books`: the selected book's `book_id`, `fund_symbol`, `holdings_date` (the filing period), `as_of`, and `accepted_at`. For an N-PORT filing, `accepted_at` is its recorded filing acceptance instant; for provider or uploaded books it is `null`. The filing period is not its publication date or its latest fetch time. It remains the stored row's own period even if it is later than the model date. That metadata does not change the existing calculation rule: fund expansion is still bounded by the model date. A what-if book still has `holdings_as_of: null`: its weights came from your request, not a saved portfolio snapshot. Use `fund_books` to identify the funds looked through, not `holdings_as_of`. Empty `fund_books` means no identified stored fund book was used. Older saved answers without the field read as an empty array; that does not retroactively establish their book provenance. A later repair and rebuild may change a new answer for an old model date. Keep the book identifiers with the result when comparing runs; do not assume a model date alone fixes the holdings input. The measurement endpoint does not repair catalogue identifiers or rebuild books. Factor price inputs also check sourced daily venue limits in native prices, with one price tick of room for rounding. The check needs a dated listing record and enough observed traded sessions to prove the listing has left its exempt opening sessions. Missing age proof or native prices leave that bar unchecked. Only sourced venues with checked tick bands take this check; other venues and those with no daily limit hold nothing under this rule. A share split the provider records within seven calendar days of the bar excuses it, and each weekday without a bar adds one limit of room on each side. Stored prices and published rows stay unchanged. # Monitors Source: https://docs.itoflow.ai/features/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](/mcp/install) 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](/features/billing#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`](/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 .` 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 .` 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](/features/billing#models-and-plans). See the [monitor endpoint reference](/api-reference/coverage#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. # Notifications Source: https://docs.itoflow.ai/features/notifications Choose which emails Itoflow sends you, and check what was sent. > [!TIP] > > **The easiest way: ask your AI assistant.** With [Itoflow MCP](/mcp/install) connected to Claude or Codex, paste: > > ```text theme={null} > Use Itoflow to show my email notification settings, then turn off emails for > finished strategy runs. > ``` > > > [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%20show%20my%20email%20notification%20settings%2C%20then%20turn%20off%20emails%20for%20finished%20strategy%20runs.) > > > > 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%20show%20my%20email%20notification%20settings%2C%20then%20turn%20off%20emails%20for%20finished%20strategy%20runs.) > > > > 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/account). The rest of this page covers the HTTP API. Itoflow emails you about events on your account, such as a finished strategy run or a trade waiting for approval. You choose which ones you get, in your [account settings](https://app.itoflow.ai/account) or with the API. ## Preferences `GET /notifications/preferences` returns your `preferences`: one entry per event, each with an `email` true or false. `PUT /notifications/preferences` changes only the events you send; the rest keep their settings. | Event key | Sent when | | - | - | | `strategy_execution` | A strategy run finishes | | `pending_approval` | Trades are waiting for your approval | | `broker_reconnect_required` | A broker connection needs reconnecting | | `welcome` | The founder check-in, scheduled for the next day | There are also billing events for usage warnings, running out of credits, overage and reaching your spending cap. `GET /notifications/preferences` lists their keys. ## Strategy emails Strategy emails use the recorded decision total, including cash reserved for pending buys. A holding without a stored weight uses its value divided by that total. An open line without a usable price, currency or exchange rate makes the total, each weight and each holding's value read as a dash (—). A decision notification still arrives when a figure is not known: today's return, the cumulative return or the portfolio value. The email shows a dash (—) for that figure. It never reports zero, and it does not give the reason, because you cannot act on it. Itoflow records a short reason code for support. The decision's other metrics, holdings and trades are unchanged. Strategy-run, approval and reminder notices all follow this rule. Today's return is the decision's own day only. When the portfolio's last recorded value is from an earlier day, the field shows a dash. A reminder sent on a later day labels the return with the day it belongs to, not “Today”. A decision also gets its notice when a holding has no usable price or no performance has been calculated yet; the value or returns then show a dash. ## Delivery history `GET /notifications/logs` lists emails Itoflow tried to send, with a status and time for each. Check the status: an entry can be a failed attempt, and even a sent email may not have arrived or been read. The founder’s “Checking in” email waits 24 hours after the email provider accepts its schedule. A `queued` entry with a provider message ID records an accepted schedule, not delivery. You do not need to sign in again to receive it. `POST /notifications/unsubscribe` turns off all optional emails for your account. It needs an access token. See the [notification endpoint reference](/api-reference/coverage#notifications). # Portfolios and trade approvals Source: https://docs.itoflow.ai/features/portfolios Read holdings and performance, import a portfolio, measure its risk, link a strategy, and approve trades. Paper portfolios can trade on their own; a live portfolio's trades always wait for your approval. > [!TIP] > > **The easiest way: ask your AI assistant.** With [Itoflow MCP](/mcp/install) connected to Claude or Codex, paste: > > ```text theme={null} > Use Itoflow to list my portfolios and summarize the holdings, cash and > performance of the one I choose. Don't change anything. > ``` > > > [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%20list%20my%20portfolios%20and%20summarize%20the%20holdings%2C%20cash%20and%20performance%20of%20the%20one%20I%20choose.%20Don't%20change%20anything.) > > > > 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%20list%20my%20portfolios%20and%20summarize%20the%20holdings%2C%20cash%20and%20performance%20of%20the%20one%20I%20choose.%20Don't%20change%20anything.) > > > > 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/portfolios). The rest of this page covers the HTTP API. A portfolio holds positions and cash. It can be **paper** (simulated) or **live** (linked to a [broker account](/features/brokers)). A [strategy](/features/strategies) can manage a portfolio, or a [fund-oversight monitor](/features/monitors#create-a-fund-oversight-monitor) can watch it, but not both. You can see your portfolios and approve trades in the [app](https://app.itoflow.ai/portfolios) too. Proposing a trade, approving it, sending it to the broker and the trade filling are separate steps. Check each one; one doesn't imply the next. ```mermaid theme={null} flowchart LR Strategy[Strategy decision] --> Pending[Pending trades] Pending --> Approval[Your approval] Approval --> Attempts[Orders sent to the broker] Attempts --> Holdings[Updated holdings] ``` ## Read portfolios | Endpoint | Returns | | - | - | | `GET /portfolios` | Your portfolios | | `GET /portfolios/{id}` | One portfolio and its holdings | | `GET /portfolios/{id}/performance` | Performance over time | | `GET /portfolios/{id}/holdings/history` | Past holdings | | `GET /portfolios/{id}/trades` | Trade history | | `GET /portfolios/{id}/decisions` | Strategy decisions for this portfolio | Performance returns chain observed portfolio values after taking out external deposits and withdrawals. Each flow is placed at the preceding reading, an approximation to valuation at the time of the flow. The first reading starts at zero. Daily return runs from the last reading at or before midnight UTC; a baseline older than the preceding UTC day makes it `null` (not known). Unknown returns stay `null`; readers must not fill them with zero, carry an older day's return, or infer a gain from a change in portfolio value. Owner performance points include `daily_return_reason` and `cumulative_return_reason`. These fields are null for measured returns and explain unknown ones. Status and detail use `dailyReturnReason` and `cumulativeReturnReason`. A metric without enough measured returns is null, with an insufficient-data message. Public strategy summaries use `totalReturn: null` with `totalReturnReason`; their history points use a null `value` with `reason`. Cumulative and daily fields use ratios: `0.01` means 1%. Trades and commissions remain in returns. Paper portfolios do not record dividends. Holdings and trades carry their own currency; don't guess it from the ticker or exchange. Many amounts are decimal strings, but some are numbers, and a portfolio's `total_value` is in US dollars. Check each field's schema. For a live broker account with cash in several currencies, `live_broker_state` reports available, reserved, and total cash for the whole account in the account currency, beside their dollar values. For example, USD 150 available and EUR 200 available at \$1.20 per euro give 390 available in a USD account. Older snapshots get these whole-account native totals on their next sync. A short holding has a negative `quantity` and `current_value_usd`, and `total_value` is cash plus the signed value of every holding. `unrealized_pnl_pct` is the holding's P\&L as a share of its cost, so a short whose price falls shows a gain. In a paper portfolio, a holding moves to `exited_holdings` once the absolute value of its quantity is below 0.0001, so a long or short of 0.00009 shares has exited. In a live portfolio, it moves only when its quantity is zero. For a portfolio valued from its holdings, an open holding without a usable current price makes the current total and all weights unknown. A live mirror keeps the non-null total from its latest broker snapshot even when a local holding lacks a price. A price placeholder, a holding imported without a price that the starting capital leaves out, is not funded, so it stays out of the total, the weights and the P\&L totals. When the current total is unknown, the list returns `total_value: null`; detail returns `metrics.totalValue: null`. Both include `valuation_unavailable_reason` and `valuationError` with a `code` and `message`. Detail does not use older metrics in place of an unknown current total. Paper status and summaries return `current: null`, empty `holdings`, and `valuationError` with code `PORTFOLIO_VALUE_UNKNOWN` and a reason. Historical rows keep their own dates and values. Holdings history records the book each time it changes: on import, on each fill, when cash is reserved or released, on broker sync and when the portfolio is liquidated. It also records the book every 15 minutes during market hours. A change and its record are saved together, so a past date reads the book as it stood then. Holdings history keeps every open line in an unpriced snapshot. All weights are null, and `valuation_unavailable_reason` names the lines that lack a usable price, currency or exchange rate. Those lines also have null prices and values. A price placeholder is the exception: it stays in each record with a null value, weight and price and its own reason, and the other lines keep their values and weights. A live mirror's broker total does not prove that each local holding has a usable price. Detail and portfolio tools keep that total and name any missing local valuation in `valuation_unavailable_reason`. Priced holdings keep their values; unpriced holdings have `current_value_usd: null`. Portfolio status includes this reason even when it does not include holding rows. Public strategy holdings keep priced weights against the broker total and return a null weight with the price reason for each unpriced line. Trading status and summaries require all local prices, so they return the whole-book refusal above even with a known broker total. If any open holding lacks a current value because its price is missing or not above zero, its currency is missing, or its exchange rate is missing or invalid, its `unrealized_pnl` and `unrealized_pnl_pct` are `null`. Detail also returns `null` for `pnl_metrics.total_unrealized_pnl`, `total_pnl`, and `total_pnl_pct`, with the same valuation reason. Recorded realized gains and losses stay available. A dollar holding needs an exchange rate of exactly 1; a holding in another currency needs a positive rate. A known net asset value of zero or less also has no current valuation or weights. The list returns `total_value: null`; detail returns `metrics: null`. Both include `valuationError` with code `PORTFOLIO_VALUE_NOT_POSITIVE` and a message giving the value, plus the same message in `valuation_unavailable_reason`. They do not substitute older stored metrics. Transitions refuse zero net asset value while any non-cash position has a nonzero quantity, including offsetting longs and shorts. With no open positions, a zero-value transition queues no trades and retires open intent. Paper status and summaries apply this check even when the portfolio has no open holdings. An empty book worth \$0 returns `current: null`, empty `holdings`, and `PORTFOLIO_VALUE_NOT_POSITIVE`, with or without older stored metrics. Position returns need an entry cost. When that cost is zero, `unrealized_pnl_pct` (or `pnl_pct` in paper status and summaries) is `null`, because the return is not known. The dollar gain or loss still uses the signed quantity. For a portfolio valued from its holdings, an open holding without a usable current price or exchange rate makes its net asset value and weights unknown. Factor cards use a separate rule: that line counts as zero, gets no weight, and appears in `missing_price_symbols::`. The other factor-card weights use the valued lines, including cash. For example, $100 cash, one AAPL share at $100 and an unpriced MSFT short give AAPL and cash weights of 0.5 each on the factor card. A missing exchange rate for a line in another currency has the same effect. Forecast backtests leave all weights unavailable and name the unvalued lines; they never use entry cost as a current price. A price placeholder isn't funded: factor cards and backtests leave it out of the figures and name it in `missing_price_symbols`, and a backtest keeps the other weights. Zero and negative prices are unusable. A dollar cash unit must have a price of exactly one; another currency's cash unit must match its dollar rate within 0.000001. Cash with an unusable price follows the same missing-price rule as any other holding. A portfolio created by import includes `portfolio_value`: the amount, currency, date, basis and source you accepted at import. It is the value you confirmed then, not a live price. Older portfolios may return `null`. When a portfolio response includes `factorScorecard`, its `coverage` reports `longWeight`, `shortWeight`, `grossWeight` and `netWeight` as decimal strings. They exclude cash: long is the sum of positive weights, short the sum of negative weights, gross is long minus short, and net is long plus short. A neutral book with long `"1.00000000"` and short `"-1.00000000"` has gross `"2.00000000"` and net `"0.00000000"`. Each field is `null` when the stored scorecard lacks it. A factor card holds two dates. `factorScorecard.asOf` is the model date: prices and the risk model end on it. The worker calculated the card later, from the holdings, fund books, peers and benchmark constituents on file at that time, so a book uploaded after the model date can be in it. A request with `factor_as_of` returns the newest card whose model date is on or before that date, and its book can be newer than the date you asked for. The response gives the calculation time in `scorecard_input_dates.holdings_fund_books_peers_and_benchmark_read_by` and says what each date covers in `scorecard_input_dates.meaning`. That time is `null` for the current card, which stores none. A response with no card has no `scorecard_input_dates`. After import or a holdings change, the queued factor refresh adds missing names to the active model before it builds the scorecard, including names in held funds, the benchmark and the peer portfolio. It fetches a held or peer fund's book when none is stored. Scorable names need no further action or daily model run. A name with too little new data stays covered while its older model rows remain fresh, then becomes uncovered. If adding names fails, the scorecard uses the covered names and carries a warning. An expired model or stale stored fund book can still delay the scorecard. Live model inputs expire after 48 weekday hours, counted in UTC. Saturdays and Sundays add no age; holidays still count. A Friday model stays fresh all Monday and expires just after Tuesday 00:00 UTC if no newer inputs replace it. Stored fund books expire 48 calendar hours after fetch; weekend runs renew them too. Historical model reads keep their 45-calendar-day limit. A held fund's derivative counts at its notional, the size of the position it stands for, and only for risk. A contract for difference on a share the same fund holds adds its notional to that share. A small future the fund offsets itself rides on the fund's own returns: at most half a percent of the fund, on the same side as its other holdings. The scorecard names every other derivative with its reason, such as "a derivative's underlying is not mapped to a listing", counts its share as uncovered and prices the rest of the fund. Where a fund's rows add to one with the derivatives inside, each line is restated over the fund's net assets, its rows other than derivatives. A fund's contra rows only offset its derivatives and carry no exposure. A fund whose weights are shares of a total its rows cannot size is not priced. The scorecard names the fund with "a derivative's exposure is not known", counts its weight as uncovered and measures the rest of the book. A comparison treats such a fund in a benchmark or peer book the same way. A name the model covers but whose prices the day's read could not get keeps its modelled risk when nothing else in the book is priced from returns. Otherwise the scorecard names it with the read's cause and counts its weight as uncovered, because its link to the returns-priced holdings is not known. When a holding priced from its own returns needs another holding's link to it, and a series is too short or the two share too few dates, the scorecard names the holding whose series causes the gap, with that cause, and counts its weight as uncovered; the rest of the book is measured. A holding priced from its own returns with no series at all is named the same way. A modelled name whose link a returns-priced holding needs is set aside the same way when it has no series or too few shared dates. Held directly, it is named with that cause and its weight counts as uncovered. Held through a fund, it is priced with the rest of the fund from the fund's own returns, and the scorecard names it; if the fund has no usable series either, the fund is named instead. The fund's other modelled holdings keep their risk, and only the part of the fund they do not cover counts as uncovered. An unread name stays outside the new additions without a missing-data reason; other names can still be added, and the scorecard carries a warning. The model trusts prices as they arrive and leaves no name out for the size of a move. A bad price that comes back costs that day's price, not the name's rows. An earlier model run recorded the reason `prices_not_usable` for a name whose price rose a hundredfold or more in one day: "Its price rose more than a hundredfold in one day, so its risk is not known." The model keeps that answer for the dates it covers, and older model rows for such a name are not carried forward. When a held fund holds such a name, the scorecard names it under the fund with its share of the fund, and the fund's own returns measure that weight. Closed residues below 0.0001 shares on either sign do not block performance refreshes or affect the inferred benchmark. This holds even when the residue has no current price or currency evidence. An open short still needs usable valuation evidence and counts when choosing the benchmark. Stock splits preserve a paper position's direction. A two-for-one split changes a short of 100 shares at a $100 entry cost per share to a short of 200 shares at $50 per share. The same adjustment applies when a missed split is backfilled. Live holdings follow the broker's split records. ## Create a portfolio `POST /portfolios` takes `name` and `allocated_amount`, plus optional `description` and `strategy_id`. Allocations must be between 1 and 1 billion US dollars, or the equivalent. It returns `202`. > [!WARNING] > > **New paper portfolios execute automatically.** `POST /portfolios` turns on automatic execution, so a linked strategy's paper trades run without an approval step. To review each trade, turn it off with `PATCH /portfolios/{id}/auto-execute`. To link a strategy later, use `PUT /portfolios/{id}/link`; `DELETE` on the same path unlinks it. To turn automatic execution on or off for a paper portfolio, use `PATCH /portfolios/{id}/auto-execute`. Live portfolios ignore this setting: their trades always wait for your approval. Linking to a live broker portfolio returns `400 SHORT_TRADE_UNSUPPORTED` if the strategy's latest decision target has any negative non-cash weight or its current book holds an open short. An open short has a negative quantity with an absolute value of at least 0.0001. The response says: “Live short sales are not supported. A strategy whose book or latest target holds a short cannot link to a broker.” The strategy remains unassigned. ## Import holdings Importing turns a list of holdings into a new paper portfolio in two steps: A draft accepts up to 3,000 holding rows. Both steps use this limit, including rows left out of the import. 1. **Validate.** `POST /portfolios/import/validate` matches each holding to an instrument, prices it and returns a draft with an `approval_token`. 2. **Commit.** After a person has reviewed the draft, `POST /portfolios/import` saves it. Send the `normalized_draft` from step 1 with `approved_at` set to when it was approved, the `approval_token`, and the output ID with `:approved` added to the end. Check the body, not only the status code: validation problems come back as `200` with `ok: false` and a list of issues. If the token expires, prices move, or you change the draft, validate again. An invalid row does not stop the review from pricing valid rows. A failed validation can return `holding_prices` and `row_warnings` beside `row_errors`. When `valuation_scope` is `valid_rows`, `book_summary` covers only those valid rows. It is not the full book's exposure. No approval token is issued while errors remain; fix them and validate again before importing. In the draft, check `valuation_coverage`. When it is `partial`, some holdings had no current USD price; they are listed in `unvalued_holding_row_ids`. Without a stated `portfolio_value` they are also left out of `allocated_amount_usd`; a stated value already counts them. Check and import responses also return `row_warnings` for holdings with missing valuation inputs. Each issue has `severity: "warning"` and the holding's `row_id`. Missing-price warnings use `field: "price"`; a missing exchange rate uses `field: "currency"`. A warning does not block confirmation. The codes mean: | Code | Meaning | Example message | | - | - | - | | `price_not_fetched` | The price vendor refused, failed or did not answer. Retry the check. | AAPL.US: the price vendor did not answer; try again. | | `no_recent_close` | The vendor omitted the name, returned a different or missing exchange, or has no usable positive close in the last 14 days. | BRK-B.US: no close in the last 14 days. | | `holding_fx_unavailable` | The holding has a native price, but its rate to US dollars is unavailable. | VOD.LSE: exchange rate from GBP to USD is unavailable. | Pricing adds no missing-close warning when a holding already has a validated usable unit value. Uploaded `unit_value` fields remain ignored; they do not replace provider prices. These warnings leave the existing unknown book value and weight rules below in place. When the upload states no `portfolio_value`, a holding imported without a price becomes a price placeholder: the starting capital leaves it out, so it is not funded, and the price refresh never prices it. A stated `portfolio_value` already counts every holding, so a US dollar holding imported without a price stays funded, and the next price refresh prices it. A holding in another currency becomes a placeholder either way, because it has no rate to US dollars without a price. A paper `BUY` or `SELL_SHORT` fill replaces a placeholder's quantity, even when the imported quantity has the opposite sign, and clears the placeholder flag. A `SELL` or `BUY_TO_COVER` cannot close that row because it has no funded position. A short is a holding with a negative `quantity`. A row can instead keep a positive quantity and set `side` to `short` or `S`; validation makes the quantity negative. Cash can be negative, for borrowed cash. When every holding has a current value, cash plus holdings at current prices must be above zero. `book_summary` in the validate response gives the long, short, gross and net value in US dollars and as a share of net asset value; cash counts in net asset value but not in exposure. If any included holding has no current US dollar value, `book_summary.nav` and all four weights are `null`. The affected leg's value is `null`; `gross_value` and `net_value` are also `null`. A leg with no holdings has value `"0"`. Show `valuation_unavailable_reason` with these unknown values. Keep `valuation_coverage` and the unvalued row list; `allocated_amount_usd` is the stated `portfolio_value`, or without one the partial allocated amount; it does not establish net asset value. Validation refuses a known net asset value at or below zero. When some holdings have no current value, it refuses a book whose cash plus priced holdings is below zero, because that sum becomes the starting capital. Both validation and import check the current priced total even when `portfolio_value` declares a positive amount for an earlier date. ```text theme={null} Unvalued holding → affected leg, gross and net value unknown → net asset value and every weight unknown ``` Importing creates a portfolio only, not a monitor or strategy. Repeating a commit returns the same portfolio. Paper portfolios can open, add to and cover shorts without a separate setting. A trade keeps a positive quantity and names its side: `BUY`, `SELL`, `SELL_SHORT` or `BUY_TO_COVER`. The planner splits a change across zero: selling 150 shares from a holding of 100 queues `SELL 100`, then `SELL_SHORT 50`. Buying 80 against a short of 50 queues `BUY_TO_COVER 50`, then `BUY 30`. Once the whole change meets the minimum trade amount, the planner keeps the closing leg even below that minimum. It drops an opening leg below the minimum, so the trade only closes the old position. A short sale adds its proceeds to cash, less fees. The planner funds covers, including fees, from current cash plus net long-sale proceeds after fees in the same basket. Starting cash may be negative if those sales repay the debt and fund the covers. Short-sale proceeds cannot fund a cover in that basket. For opening buys, current cash less any cover cost not funded by net long sales must exceed buy notional times 1.10. Each fill debits its fees. Fills run in this order: `SELL`, `BUY_TO_COVER`, `SELL_SHORT`, then `BUY`. Closing legs keep their share quantity through price changes; opening legs use their target dollar amount at the fill price. A closing fill cannot exceed the held quantity. A cash refusal fails only that leg while the rest continue, so a basket can settle in part. A cover that lacks cash stays queued while a long sale in its basket is still queued, such as one on a closed exchange, and fails once none is. Live broker trades and mirror sync still refuse shorts. Live rebalance validation and submission return `SHORT_TRADE_UNSUPPORTED` if any non-cash target weight is negative or the portfolio holds an open short (negative quantity with an absolute value of at least 0.0001). This check runs before the minimum trade amount and no-trade handling, so an unchanged short or a target worth less than \$1 still refuses the rebalance. The refusal includes: “Itoflow cannot yet open, add to or cover a short.” Trade history returns those four sides and `SPLIT` for a corporate action adjustment. `SPLIT` is a history record, not an order side. ## Compare with a benchmark `PUT /portfolios/{id}/benchmark` needs both `peer_portfolio_id` and `benchmark_index_id` every time; send `null` to clear one. A peer must be another of your active portfolios. The comparison updates in the background, so new results appear a little later. ## Measure risk through MCP Through [MCP](/mcp/install), your assistant calls the public [risk run operations](/api-reference/risk-runs) to measure a saved portfolio or a what-if book against a benchmark and up to 10 peer funds. The result covers risk, exposures, attribution, factor profit and loss, bets, sizing, scenarios and valuation, the same breakdown chat shows. A fund held beside other holdings is measured through its holdings at the line's signed weight. Cash the fund holds counts as the book's cash. Factor risk excludes shared-specific factors. Specific risk includes each name's own variance and shared-specific factors: residual moves several names share. Those shared moves can link separate books, so their specific variances need not add. Factor and specific variances add to total variance; the squares of their reported volatilities add to the square of total volatility. An unresolved fund holding stays outside the model at its signed weight and does not change a direct holding of the same name. If no usable fund book is available, the run measures the other names and gives the fund line's reason. A failed request stays distinct from an absent or expired book. A held fund's book passes the same weight check as a fund measured on its own: when its stated weights differ from what its share counts and prices are worth, the run rebuilds them from those values, or refuses the book and names the refusal as the fund line's reason. A fund inside a held fund is looked through the same way, at the product of the signed weights, down to three funds. A fund that holds itself, or sits below the third, stays one gap at its weight with the reason code `no_fund_book`. | Method in `execute` | What it does | | - | - | | `api.startRiskRun` | Starts a run and returns its `run_id`. | | `api.getRiskRun` | Reads the run: `running` until it ends, with `progress` once the run reports it, then a short summary and the full panel. | | `api.cancelRiskRun` | Stops a run by its `run_id`. | | `api.startRiskMeasure` | Starts a measure of 1 to 10 books on one factor model version, at one date or over up to 60 dates, and returns its `measure_id`. | | `api.getRiskMeasure` | Reads the measure: `running` with `progress` until it ends, then one entry per date. | | `api.cancelRiskMeasure` | Stops a measure by its `measure_id`. | ```js theme={null} const started = await api.startRiskRun({ body: { request_key: "4f1c2a9e-7b3d-4e8a-9c61-2d5b8f0a6e17", request: { portfolio: { holdings: [{ symbol: "QQQ", weight: 0.9 }, { symbol: "CASH", weight: 0.1 }] }, benchmark: "SPY", peers: [], include_forecast_quality: false, }, }, }); // In a later call: const run = await api.getRiskRun({ run_id: started.run_id }); ``` `include_forecast_quality` defaults to `false`, as in the example. Set it to `true` to request the historical forecast-quality check and its factor snapshots. Current risk, coverage checks, attribution, risk change and scenarios remain included, with the history each needs. The `trust` section says “Forecast quality not requested.” and appears in `missing_by_design`, not `missing_sections`. This omission alone does not make the run partial. Monitor runs retain the full report. Use a new `request_key` when changing this option; omitted and `false` mean the same request. `analyses` chooses what the run computes: `["risk"]`, `["performance"]` or both, the default. Risk covers risk, risk change, bets, sizing, scenarios, drivers, trust, exposures, liquidity and valuation. Performance covers performance, attribution and factor P\&L. A run of one analysis skips the factor and price reads its sections do not use, so a performance-only run skips covariance reads. Every run reads the same holdings books, so a section gives the same figures as in a run of both. Only risk reads the current model, so without it `unmodelled_count` is null and `coverage` is absent. The other sections appear in `missing_by_design` with the reason `not_requested`, and they alone do not make the run partial. Compliance and changes come only with both. Omitting `analyses` and listing both mean the same request; listing one is a new request and needs a new `request_key`. When performance is requested, a saved portfolio reads its stored return series, unless the run looks through it as one listed fund; that path uses the fund's prices. Empty or unknown stored readings put `performance` in `missing_sections`, which makes the run `partial`. A risk-only request still lists unrequested performance in `missing_by_design`. An unlisted what-if has no stored return series, so its performance remains missing by design. ```mermaid theme={null} flowchart LR Request[Risk run] --> Current[Current risk and other sections] Request --> Option{Include forecast quality?} Option -->|Yes| History[Historical snapshots and forecast check] Option -->|No, default| Omitted[Forecast quality not requested] ``` A what-if holds 1 to 3,000 lines. A saved portfolio may hold up to 3,000 securities. A run refuses more with `invalid_risk_engine_request`. Weights are fractions of the book's net assets; a short is below zero. With a `CASH` line, weights add to 1. Without one, the rest is cash; a book that borrows lists `CASH` below zero. At most three runs may run at once. Each newly launched background job has a 60-minute budget, including coverage and output. Initial validation, startup and stopping a timed-out job can add time before its terminal status is available. For figures at past dates, over a range of dates, or for several books side by side, your assistant starts a [risk measure](/api-reference/risk-measure) instead. One measure covers a single date or a range of up to 60, month ends by default; a year of month ends on a few books takes a minute or two. It reads a saved portfolio at its newest snapshot by the end of each date, unless you name another time, and funds and the benchmark through their stored holdings on or before that date. A measure counts toward the three runs while it runs, and its answer stays for 24 hours after it ends. It does not add names to the model; a risk run on the book does. For a worked example, see [Measure a book's factor risk](/use-cases/measure-factor-risk). Before measuring, the engine asks for names missing from the selected model publication, including holdings inside fund lines and the benchmark and peers. It checks every five seconds for up to ten minutes. A tool run leaves five minutes of its remaining deadline for measurement, so a retry can wait less. Submission, status reads and polling all share this wait budget. Names already covered need no wait. The run measures available coverage when a request fails or times out; fresh older rows can still cover a name under the model's freshness rule. A name the model refused to add at that publication stays outside current measurements even when fresh older rows exist. Its signed weight and refusal reason appear in each book that holds it; those older rows still serve history. A run whose books hold names the model has not scored first waits up to 10 minutes for coverage within the same job budget. While it waits, `api.getRiskRun` returns `running` with a `progress` object: `{ stage: "waiting_for_coverage", names_asked, waited_seconds, expected_seconds, at_most_seconds }`, then `{ stage: "measuring" }`. `expected_seconds` is about 2 seconds for each name asked, never more than `at_most_seconds`, the most this run waits before it measures what it has. `measuring` means the run is computing figures from the coverage it has. A retry shows plain `running` until it reports fresh progress. A run that asks for no names goes straight to `measuring`. When a run that asked for names ends, its risk section says so in one sentence, for example "Asked the factor model to score 233 names and waited 7 min 0 s." The sentence counts requests and wait time across all attempts. A run that asked for none adds no sentence. Monitor runs add the same sentence. The result's `coverage` list holds every gap in the subject, benchmark and each peer, with `book`, `symbol`, signed `weight`, `reason_code` and `reason`. `unmodelled` remains a view of the subject's 20 largest gaps by absolute weight, and `unmodelled_count` counts all subject gaps. The receipt groups the full list by book and reason, with each group's share of the book. Reasons include the model's refusal to add a name, `not_added_in_time`, `coverage_failed`, `no_fund_book`, `no_equity_listing`, `cash_currency`, `not_listed` and `invalid_inputs`. A failed provider read is `coverage_failed`, not a model refusal. A held fund with no usable holdings book keeps one gap at its signed outer weight and gives the fetch's reason. A row with no confirmed equity listing stays a separate signed gap even when its label matches a covered holding in another book. | Reason code | What the run says | | - | - | | `not_added_in_time` | The model had not scored this holding before the wait ended. | | `prices_short_of_tail` | Its prices do not cover the dates the model needs. | | `prices_not_usable` | Its price rose more than a hundredfold in one day, so its risk is not known. | | `specific_risk_out_of_range` | Its stored specific risk is too large to use, so its risk is not known. | | `no_stored_state` | The model lacks the saved inputs needed to score this holding. | | `earlier_specific_risk_rule` | The model's saved inputs for this date use an earlier risk method, so this date cannot score the holding. A later date can, if the model's daily run covers the holding or a new request asks for it at that date. | | `invalid_inputs` | This holding could not be valued; its risk is excluded. | | `no_equity_listing` | A line with no confirmed equity listing, such as a bill or bond; no run can add it. | A dropped peer's reason states the cause. For example: "Its holdings book is dated 2026-09-17, after the report date 2026-09-16." A provider answer with only sector or region totals says so; it does not count as a holdings book. Current fund holdings use the book's own date, even when the factor publication is older. A short fund line therefore measures the same risk as its holdings written out at that signed weight. A source row with no confirmed listing has the reason code `no_equity_listing`; the run does not ask the worker to score its bare ticker. Each `reason` explains the gap in plain words and names the subject as the portfolio or fund. The `book` and `reason_code` fields retain their machine identifiers. A peer whose holdings book cannot be read after fetching is dropped from comparisons and named in `dropped_peers` with the fetch's reason. The remaining peers still take part. A benchmark with no required book keeps the existing refusal rule. Monitor runs use this same measurement and receipt. Keep one `request_key` for each new run. The same key and request join that run for 24 hours after it ends. Another request with that key returns 409. Finished results and full artifacts stay available for 24 hours even after the sandbox sleeps. Successful runs include a top-level `analytics` reference to the complete schema-version-2 document. Read it with `GET /risk/runs/{run_id}/artifact`; use gzip ranges and verify both hashes for a large copy. All three groups of exposure sides, sizing modelled-book scope and valuation comparisons remain present. A publication failure fails the run. See the [risk-run transport contract](/api-reference/risk-runs). Cancellation, timeout and container loss leave a known terminal outcome. A failed run returns 200 and says why in `failure_code` and `reason`. `engine_refused` means change the request. `rate_limited` and `provider_unavailable` mean the price provider failed: start the run again later, with a new `request_key`. Risk runs need to be enabled for your account. When they aren't, all three operations return 403 with `feature_not_enabled`. Through `api.*`, a refused call returns `{ ok: false, status, body }`. If the runtime does not answer, the operation returns 503; retry with the same key. ## Approve trades `GET /portfolios/approvals/pending` lists everything waiting for your approval. For one portfolio: 1. `GET /portfolios/{id}/pending-trades` returns the proposed trades. 2. Show them to the person who will approve them. 3. `POST /portfolios/{id}/pending-trades/approve` approves them. 4. `GET /portfolios/{id}/trades/{tradeId}/attempts` shows what happened at the broker. To cancel pending trades, `DELETE /portfolios/{id}/pending-trades`. **Live portfolios.** Approve the exact proposal you reviewed. Copy `metadata.approvalProposal.id` and `metadata.approvalProposal.hash` from the pending-trades response and send `{ approvalProposal: { id, hash } }` in the approve request. If the proposal has changed since you read it, the approval fails. Read it again and get a fresh approval. Paper portfolios accept `{ decisionId? }`. Live portfolios always need this approval; automatic execution can only be turned on for paper portfolios. An approval is not a fill. Check the attempts and the portfolio afterward. ## Live portfolio operations These endpoints act on a live portfolio and its broker account: | Endpoint | What it does | | - | - | | `GET /portfolios/{id}/broker-status` | The broker connection's state | | `POST /portfolios/{id}/sync-live-state` | Refreshes holdings and cash from the broker | | `POST /portfolios/{id}/reconcile` | Reconciles Itoflow's records with the broker account | | `POST /portfolios/{id}/go-paper` | Switches the portfolio to paper trading | | `POST /portfolios/{id}/liquidate` | Creates sell trades for every position. On a live portfolio they wait for your approval. | | `DELETE /portfolios/{id}` | Deletes a live portfolio. Its strategy is deactivated, and the broker is disconnected if this was its last live portfolio. | The liquidation response includes `total_value_usd` and `valuation_unavailable_reason`. If any open holding lacks a usable price, currency or exchange rate, the total is `null` and the reason explains why. The response never gives a partial sum. A queued task still has to pass trade sizing; follow its status to check whether liquidation finishes. `liquidate` and `DELETE` are refused while trades are pending or executing (`TRADES_IN_PROGRESS`). `DELETE` can't be undone. Some of these return a task ID; follow it with `GET /transition/{taskId}` until it finishes. See the [portfolio endpoint reference](/api-reference/coverage#portfolios) for every field. # Sharing Source: https://docs.itoflow.ai/features/sharing Publish a read-only snapshot of a dashboard or a whole chat, and read shared content. > [!TIP] > > **The easiest way: ask your AI assistant.** With [Itoflow MCP](/mcp/install) connected to Claude or Codex, paste: > > ```text theme={null} > Use Itoflow to share the dashboard from my latest research chat and give me the > public link. Tell me what the snapshot includes before you share 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%20share%20the%20dashboard%20from%20my%20latest%20research%20chat%20and%20give%20me%20the%20public%20link.%20Tell%20me%20what%20the%20snapshot%20includes%20before%20you%20share%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%20share%20the%20dashboard%20from%20my%20latest%20research%20chat%20and%20give%20me%20the%20public%20link.%20Tell%20me%20what%20the%20snapshot%20includes%20before%20you%20share%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/chat). The rest of this page covers the HTTP API. You can share a single dashboard or a whole chat. Either way, Itoflow publishes a **snapshot**: a read-only copy that anyone with the link can open, without an account. Later changes to the chat don't appear in the snapshot. Check what it contains before you share it. ```mermaid theme={null} flowchart LR Chat[Your private chat] --> Review[Choose what to share] Review --> Artifact[Public snapshot with a link] ``` ## Share a dashboard `POST /artifacts` with `chat_id` and a `source_locator` that identifies the dashboard. You can share a dashboard that was saved even if its run later failed. The response contains the `artifact` and its public `url`. It returns `201` when it creates a new snapshot, or `200` when it reuses an existing snapshot of the same dashboard. Readers use `GET /artifacts/public/{slug}` and `GET /artifacts/public/{slug}/dataframes/{dfId}`. No token is needed. `DELETE /artifacts/{slug}` takes the snapshot down. Copies someone already saved, or that a search engine cached, can't be recalled. ## Share a chat `POST /chat-shares` publishes a read-only copy of a chat you own: its messages, working steps, dashboards, tool details and questions. It returns `201` when it creates a new snapshot, or `200` with your existing share when the chat hasn't changed since you last shared it. Readers use `GET /chat-shares/public/{slug}`, plus its `dataframes`, `plots` and `runtime-token` endpoints, which need no token. The runtime token only lets the page show the shared copy; it can't change the chat. A shared chat shows that its files exist, but readers can't download them. A portfolio review in a shared message shows its rows as they were when you shared the chat; readers can't create the portfolio. See the [sharing endpoint reference](/api-reference/coverage#sharing-and-data) for every field. # Strategies Source: https://docs.itoflow.ai/features/strategies Write a mandate and position limits, and an Itoflow agent runs a paper or live portfolio under them on a schedule. Version the strategy, run it on demand, and read each decision with its reasoning and trades. A person approves every live trade. > [!TIP] > > **The easiest way: ask your AI assistant.** With [Itoflow MCP](/mcp/install) connected to Claude or Codex, paste: > > ```text theme={null} > Use Itoflow to draft a paper strategy that holds 5 to 10 large US quality > companies, with no position above 15%. Show me the full strategy before creating > it, and create it paused. > ``` > > > [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%20draft%20a%20paper%20strategy%20that%20holds%205%20to%2010%20large%20US%20quality%20companies%2C%20with%20no%20position%20above%2015%25.%20Show%20me%20the%20full%20strategy%20before%20creating%20it%2C%20and%20create%20it%20paused.) > > > > 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%20draft%20a%20paper%20strategy%20that%20holds%205%20to%2010%20large%20US%20quality%20companies%2C%20with%20no%20position%20above%2015%25.%20Show%20me%20the%20full%20strategy%20before%20creating%20it%2C%20and%20create%20it%20paused.) > > > > 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/strategies/new). The rest of this page covers the HTTP API. A strategy runs a portfolio under a mandate you write. Each **run** (an execution) reads the mandate, researches, and records a **decision**: the trades it proposes. **Trades** record what then happened to each order. Keep execution, decision and trade IDs apart; they are different things. ```mermaid theme={null} flowchart TD Draft[Mandate and constraints] --> Strategy[Versioned strategy] Strategy --> Run[Run] Run --> Decision[Decision] Decision --> Approval[Your approval, when required] Approval --> Trades[Trade outcomes] ``` Creating a strategy for an existing portfolio needs a known current value. If an open holding has no usable current price, creation returns `400 PORTFOLIO_VALUE_UNKNOWN` with a reason that names each such holding, and leaves the portfolio unlinked. Public showcase holding weights use signed market value divided by net asset value (NAV), including cash. Holdings rank by absolute value and keep their signs. For example, a $1,000 portfolio with $600 and $300 holdings and $100 cash shows 60% and 30%. If value is unknown, each weight is `null` with `valuation_unavailable_reason`. ## Create a strategy `POST /strategies` creates a paper strategy, which trades a simulated portfolio. You can also [create one in the app](https://app.itoflow.ai/strategies/new). ```json theme={null} { "name": "Example research strategy", "strategyContent": "Research the listed companies and explain proposed changes before execution.", "constraints": { "min_position_pct": 0.02, "max_position_pct": 0.15, "max_positions": 5 }, "universe": ["AAPL.US", "MSFT.US"], "initialCapital": "10000", "currency": "USD", "rules": { "model_key": "luna" }, "activateImmediately": false } ``` | Field | Rules | | - | - | | `strategyContent` | Required. The mandate, in plain language. | | `constraints` | Required: `min_position_pct` and `max_position_pct` as fractions of NAV (`0.02` = 2%), and `max_positions`. The position limits apply to a position's size, long or short. | | `universe` or `allocationGuidance` | One is required: a list of `TICKER.EXCHANGE` symbols, or guidance on what to invest in. | | `initialCapital`, `currency` | Starting cash for a new paper portfolio, as a decimal string. Between 1 and 1 billion US dollars, or the equivalent. Required without `portfolioId`. | | `portfolioId` | Optional. Use an existing portfolio instead of a new one. | | `rules` | Optional extra rules, including `model_key`. | | `activateImmediately` | `false` creates the strategy paused. | `max_position_pct` stays a ratio from `0.001` to `1`, and `min_cash_pct` stays from `0` to `1`. Margin and financing are out of scope. A target may hold more than 100% gross across names: thirteen longs at 10% each and three shorts at 10% each make a 130/30 book, and each position stays within its size limit. Trades are paid for from cash already held. A run's buys need cash above 110% of their value; a cover may also use what the run's long sales raise. A short sale's proceeds reach cash once it fills, so they pay for buys in later runs, not in the run that sells short. A paper book therefore builds a 130/30 position over several runs, and after each run its cash stays above a tenth of that run's buys. `name` is required without `portfolioId`. Other optional fields are `description` and `sourceChatId`. The `201` response includes `id`, `portfolioId`, `isActive`, `executionStatus`, and `effectiveConstraints` and `effectiveRules`. The effective fields include the defaults Itoflow filled in, so check them rather than assume an omitted control is off. A portfolio watched by a fund-oversight monitor can't also have a strategy. Choosing one returns `409 PORTFOLIO_HAS_MONITOR`. ## Read strategies * `GET /strategies` lists strategies you can see, which may include some you don't own. * `GET /strategies/{id}` returns one strategy: mandate, whether you own it, portfolio, constraints, run state and version. * `GET /strategies/public` lists the public showcase. * `GET /strategies/eligible` lists strategies that can be linked to a broker. A strategy whose book or latest target holds a short is excluded because live short sales are not supported. A paper book whose current value is not known is also excluded. The response lists these books in `ineligibleStrategies`, with `strategyId`, `currentValue: null` and a `reason`. It never returns a partial sum as an eligible book’s value. Only the owner can change a strategy. ## Change a mandate `PUT /strategies/{id}` takes the fields you want to change. When you change the mandate, constraints, rules, universe or allocation guidance, also send `changeDescription`, or you get `400 CHANGE_DESC_REQUIRED`. Each change creates a new version; the response returns `versionId` and `versionNumber`. > [!WARNING] > > **Editing cancels pending trades.** A new version cancels the strategy's pending trades, including approved live trades not yet sent to the broker. You can't edit a running strategy (`400 CANNOT_EDIT_RUNNING`) unless you change only the model; pause it first. To avoid overwriting someone else's edit, send the `expectedVersion` you last read. If a newer version exists, the request fails; reload the strategy and decide again. ## Run a strategy and follow it | Endpoint | What it does | | - | - | | `POST /strategies/{id}/control` | `action`: `pause`, `resume` or `deactivate`. Pausing or deactivating cancels unapproved trades; trades you already approved can still run. | | `POST /strategies/{id}/execute` | Queues a run: `execution_type: "manual_rebalance"`, with optional `custom_message` and `trading_date` | | `GET /strategies/{id}/active-execution` | The run in progress, if any | | `GET /strategies/{id}/executions` | Run history | | `GET /strategies/{id}/stream/{executionId}` | Live events from a run | | `GET /strategies/{id}/executions/{executionId}/events` | Saved events from a run | | `GET /strategies/{id}/decisions/{decisionId}/events` | Saved events for one decision | `execute` returns `202` with `execution_id`, `strategy_id`, `status`, `estimated_duration_seconds` and `stream_url`. The run has been queued, nothing more, and a `202` is never a fill. Follow it, then check its decision and trades. Each request queues a new run, so if you lose the response, check `active-execution` before you try again. For strategies on the legacy execution path, each failed automatic run makes the trigger chain wait before it re-arms: 5 minutes, 30 minutes, 2 hours, then 24 hours for each later failure. A real decision from an automatic run clears the count. The first failure on a new strategy version starts at one. Manual runs, cancelled runs, blocked runs, completed runs with no decision, and skips leave the count unchanged. Re-arming checks the trigger rules again; it does not promise a run at that time. The failure wait also holds after a scheduler restart or a change to the trigger rules. A new strategy version does not inherit the old version's wait. On the legacy execution path, if the model provider rejects saved session content, the run can retry in a fresh session within its three-attempt limit. The agent keeps its saved workspace and states that it lost its prior session context. Follow the run through its final decision or failure. The live stream stays open through retries while the same run remains active, including runs longer than 65 minutes. It sends the final status when the run completes, fails or is cancelled. If the run is no longer marked active, the normal stream timeout applies; check `active-execution` and the saved events. A manual run queued behind an active run keeps its stream open while its own task state is queued. It does not replace the active run's marker. ## Results `/paper-trading/{strategyId}/status`, `/trades`, `/decisions`, `/approvals` and `/pending-trades` return a strategy's state and history. `/paper-trading/summaries` lists **portfolios**, each with its trading mode, broker sync status and the strategy that manages it. `strategy` is `null` for a broker portfolio no strategy manages. A summary's `decisionType` says what the strategy decided, not whether an order filled. A holding's `weight` is its signed value divided by the portfolio's net asset value. A book worth zero or less has no weights, so its `status` returns empty `holdings` and a `valuationError` with code `PORTFOLIO_VALUE_NOT_POSITIVE` and a message that gives the net asset value. Otherwise `valuationError` is `null`. Each summary's `status` follows the same rule. Both routes include available and reserved cash in net asset value: $100 stock, $100 available cash and \$100 reserved for a pending buy give a stock weight of 33.33%. The agent's history file and day-start returns count the cash a pending buy held at the time. Before a paper-trading agent receives its input tables, preparation checks the price, currency and exchange rate of every open holding. If any line cannot be valued, the decision still runs. The files keep that line with a null value and a reason naming the symbols. Portfolio value, cash weight, all holding weights and returns that need the missing value remain null. Pending-trade projections preserve these null weights. Trade sizing refuses when a stored open holding cannot be valued; a missed live quote in the input files alone does not refuse sizing. Historical reports and emails also check stored marks and show unknown values when the evidence is unusable. An import price placeholder stays out of the input tables, as it does from trade sizing. The agent's history file uses a stored daily return only from the holdings snapshot's own UTC date. A missing reading on that date gives a null daily return. Cumulative return uses the latest reading at or before the snapshot; portfolio value comes from that snapshot's holdings. For holdings and trade approvals, see [Portfolios](/features/portfolios). ## Live strategies `POST /strategies/live` creates a strategy for a live portfolio linked to a [broker connection](/features/brokers). It takes the same body as a paper strategy, but `portfolioId` must name a live portfolio. Its starting capital is the broker account's total value when you link it. Every live trade needs your approval before Itoflow sends it to the broker. See [Approve trades](/features/portfolios#approve-trades). ## Models Set `rules.model_key` to a fusion mode or a single model when you create or edit a strategy; edits without it keep the saved choice. New strategies without a choice use the plan's `default_mode` from `/pricing/model-access`. Each run 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. A connected ChatGPT subscription does not fund strategies. See [models and plans](/features/billing#models-and-plans). For a walk-through, see [Run a strategy under a mandate](/use-cases/run-a-strategy). To design and test one first, see [Build and stress-test a strategy idea](/use-cases/stress-test-a-strategy-idea). See the [strategy endpoint reference](/api-reference/coverage#strategies) for every field. # Read the docs with AI tools Source: https://docs.itoflow.ai/guides/ai-tools Give your AI assistant public Itoflow documentation as Markdown, a page index, or an OpenAPI contract. These docs are public. Any tool that can read a URL can use them without an Itoflow account. | Content | URL | Use it for | | - | - | - | | Page index | [llms.txt](https://docs.itoflow.ai/llms.txt) | Find the guide or endpoint page you need. | | Full text | [llms-full.txt](https://docs.itoflow.ai/llms-full.txt) | Load every guide and endpoint page at once, if your tool has room. | | One page as Markdown | [Quickstart Markdown](https://docs.itoflow.ai/quickstart/http.md) | Add `.md` to any page URL. | | OpenAPI contract | [OpenAPI JSON](https://docs.itoflow.ai/openapi/itoflow-public.openapi.json) | Generate a client or check exact parameters and response schemas. | Start your assistant at the index, then let it open the pages it needs: ```text theme={null} Read https://docs.itoflow.ai/llms.txt, then use the HTTP quickstart and authentication guide to explain how to make my first Itoflow API request. ``` Every page's menu also has **Open in ChatGPT** and **Open in Claude**, which start a conversation about that page in your assistant, plus **Copy page** and **View as Markdown**. Tools can request a page with `Accept: text/markdown` to get the same text. Reading the docs does not connect your assistant to your account. To let it act in Itoflow, [connect it through MCP](/mcp/install). # API conventions Source: https://docs.itoflow.ai/guides/api-conventions Access checks, pagination, retries, asynchronous work, status codes and units. These rules apply across the API. Each endpoint page in the reference gives its exact parameters, schemas and status codes. ## Access Itoflow works out who you are from your access token, never from the request. Putting a user ID, email, portfolio ID or strategy ID in a body doesn't give you access to it. Knowing an ID doesn't either: every request checks that your account owns the resource or that it has been shared with you. Shared and public resources are read-only. Some endpoints answer `404` rather than `403` for a resource you can't access, so they don't reveal that it exists. ## Pagination There is no single paging scheme. Use the fields each endpoint documents: * Most lists take `limit` and `offset`. `GET /chats` also returns `pagination.hasMore`. * Shared tables take `page` and `pageSize`. * Chat workspace listings take `limit` and return a `cursor` for the next page. * GitHub repository lists take `page` and `perPage` and return `nextPage`. * Some lists, such as the news feeds, return one page only and say so. Keep the same filters and page size while you page through a list. ## Retries On `429`, wait for the number of seconds in `Retry-After`, then try again. Retry other reads that fail with `5xx` a few times, waiting longer each time. Through MCP, direct `api.*` calls return `{ ok: false, status, body }` for all `4xx` responses and for any `5xx` status listed for the operation in its published OpenAPI document. A whole number of seconds in `Retry-After` adds `retry_after_seconds`; other header forms are omitted. Redirects and undocumented server failures return a generic error. MCP calls must use the exact path parameter names in the operation. For example, `api.get_chatid({ id: "chat-1" })` uses `id`. Calling it with `{ chat_id: "chat-1" }` throws an error naming the missing `id` parameter before sending a request. Don't automatically repeat a request that changes something, such as creating a strategy or approving a trade, after you lose its response. It may have worked. Read the current state first, using the ID it returned or the relevant list endpoint. Some writes are safe to repeat and say so: | Request | Repeating it | | - | - | | Run a monitor report | Joins the run already queued or running | | Delete a monitor or chat | Confirms or finishes the same deletion. A `404` on a repeated monitor delete means it's already gone. | | Start an MCP research turn with the same `message_id`, message and `model_key` | Counts as the same turn, not a new one | Running a strategy is not safe to repeat: each `POST /strategies/{id}/execute` queues a new run. Check `active-execution` first. ## Work that finishes later Reports and strategy runs take minutes. Their endpoints return `202 Accepted` with an ID, and the work continues after the response. Some portfolio changes, such as creating or linking a portfolio, also return `202`. Follow the work with the status or event endpoint for that feature. Research turns through MCP work the same way: the call returns once the turn is accepted. `202` means the work was accepted, not that it succeeded. For trades, an accepted order is not a fill: check the trade's attempts and the portfolio afterward. ## Status codes | Code | Meaning | | - | - | | `200` | Success | | `201` | Created | | `202` | Accepted; the work finishes later | | `204` | Success with no body | | `400`, `422` | The request is invalid; the body says why | | `401` | The access token is missing, expired or not an Itoflow access token | | `403` | Your account may not do this, or your plan doesn't include it | | `404` | Not found, or not visible to you | | `409` | Conflicts with the current state, such as a newer version, a duplicate name or a changed proposal | | `410` | Gone, such as a deleted chat's workspace | | `413` | The request body is too large | | `429` | Rate limited | | `502`, `503` | Temporarily unavailable; retry | The gateway returns `400` with `error.code: "bad_request"` when the first resource identifier in a route is malformed, including an unfilled placeholder such as `/chat/{id}`. After URL decoding, that identifier must contain 1–256 characters from `A–Z`, `a–z`, `0–9`, `.`, `_`, `:`, and `-`. The body also includes `error.message` and `error.requestId`. Correct the identifier before retrying. Most errors return a JSON body with a readable `error` message and, where the endpoint defines one, a stable `code`. For example, editing a strategy's mandate without saying why returns `400`: ```json theme={null} { "error": "changeDescription is required when updating strategy behavior fields (strategyContent, allocationGuidance, constraints, rules, universe). Please provide a brief summary of what changed and why.", "code": "CHANGE_DESC_REQUIRED" } ``` Match on `code`, not on the message text, which can change. A few endpoints put the code in `error` instead, such as the monitor news feed's `"error": "NOT_FOUND"`; each endpoint page lists its responses. ## Units and formats * **Money** is often a decimal string, such as `"10000.50"`; parse it as a decimal, not a float. Some fields are plain numbers. Keep the currency field with each amount. Fields ending in `_usd`, a portfolio's `total_value`, and quote `price` are in US dollars. * **Cents:** fields ending in `_cents` are whole numbers of the currency's smallest unit. * **Credits** measure usage. They are not money. * **Percentages:** some fields take `4` to mean 4%; others take fractions such as `0.04`. The feature guide or field description says which. * **Times** are usually ISO 8601 strings. Some fields, mostly in billing, are Unix seconds or milliseconds instead. Check the field's schema before you parse it. * **Schedules** use a local time such as `09:00` plus an IANA time zone such as `America/New_York`, so they follow daylight-saving changes. * **Symbols** are `TICKER.EXCHANGE`, such as `AAPL.US`. See [Find and resolve symbols](/guides/symbols). Some response objects can contain more fields than the schema lists. Ignore fields you don't recognize. # Design principles Source: https://docs.itoflow.ai/guides/design-principles The rules Itoflow keeps everywhere: a person approves every live trade, your token decides access, only data that existed at the time, the engine computes and the agent explains, no silent model changes, safe retries, versioned mandates, and credentials that never reach the model. What each means for your code, plus security and data handling. A few rules shape the whole product. Each one below says what Itoflow does and what it means when you build on it. For the layers these rules sit in, see [How Itoflow works](/platform/how-itoflow-works), [The agent harness](/platform/agent-harness) and [Quant engine and risk model](/platform/quant-engine). ## A person approves every live trade Agents propose trades; they never send live orders on their own. Automatic execution can be switched on for paper portfolios only, and the API refuses it for live ones. An approval covers one exact proposal. The pending-trades response carries a proposal ID and a hash of its contents, and the approval must send both back. If the proposal changed after you reviewed it, even slightly, the approval fails and you review it again. Nobody can approve one set of trades and have another go to the broker. ```mermaid theme={null} flowchart LR Read[Read proposal] --> Review[Owner reviews it] Review --> Submit[Send proposal ID and hash] Submit --> Check{Proposal unchanged?} Check -->|Yes| Broker[Order goes to the broker] Check -->|No| Read ``` **For your code:** show the owner the proposal you read, and send that proposal's ID and hash. See [Approve trades](/features/portfolios#approve-trades). ## Your token decides what you can reach Itoflow takes your identity from your access token, never from the request. An ID in a URL or body is only a label; every request checks that your account owns the resource or that it was shared with you. Where it helps privacy, Itoflow answers `404` for resources you can't see, so it doesn't reveal that they exist. **For your code:** you can't reach another account's data by guessing or passing IDs, and you don't need to send user IDs at all. ## Only data that existed at the time A backtest that uses data from after its own date gives results you can't trust. Itoflow avoids this: * Factor-risk results come from the model snapshot saved on or before the date you ask for. The response's `provenance` says if any input, such as sector labels, reflects today's values instead. * A fund's quarterly SEC holdings filings count from the day the SEC accepted them, not the quarter they describe. * A report's date is fixed when its run starts, and retries keep it. **For your code:** use [factor-risk covariance](/features/market-data#factor-risk-covariance) in backtests, check its `provenance`, and store `snapshot_as_of` with each result. ## The engine starts the report; the agent's analysis finishes it A fund-oversight report starts from the figures Itoflow's risk engine computes. The agent decides what matters, explains it, and may correct a figure or add its own from further analysis. When the engine has evidence a figure is wrong, the report leaves out that figure and anything that depends on it, rather than estimating. Missing trading volume is never filled in. Research that builds a research contract also gets an independent review of the plan and the answer. If the review can't run, or concerns are still open after 10 rounds, the work continues and Itoflow records why. See [Independent review](/platform/agent-harness#independent-review). ## No silent model changes Each chat, monitor and strategy saves its own model. A run uses the model saved when it starts, for the agent and its review, through every retry. If your plan stops covering that model, runs stop and ask you to choose; Itoflow never switches model without telling you. If it can't check your plan, it returns `503` rather than assume you're on Free. **For your code:** the results you read were produced by the model you chose. See [models and plans](/features/billing#models-and-plans). ## Safe to retry Networks drop responses. Where repeating a request could cause harm, Itoflow makes the repeat harmless: * Running a monitor report while one is queued joins that run instead of starting a second. * Sending a research turn again with the same `message_id`, `message` and `model_key` replays the same turn. * Deleting a monitor or chat again confirms the same deletion. Long work returns an ID you can follow, and `202` means accepted, not finished. Strategy runs are the exception to safe repeats: each request queues a new run. **For your code:** see [API conventions](/guides/api-conventions#retries). ## Every change is versioned Each edit to a monitor's or strategy's mandate creates a new version and keeps the old one. Reports record the version they ran under, and strategy edits can require the version you last read, so two people can't overwrite each other's changes unnoticed. ## Money keeps its currency Holdings, cash and trade amounts carry their own currency, and many amounts are decimal strings rather than floating-point numbers. Itoflow never infers a currency from a ticker or exchange. Credits, which measure AI usage, are kept apart from money. Schedules use a local time and an IANA time zone, so a 09:00 report stays at 09:00 when clocks change. ## Credentials stay where they belong * **MCP:** your AI client signs in through OAuth and stores the result. The assistant never sees a token. * **ChatGPT subscription:** the long-lived credential stays outside the agent's environment. A run gets only a short-lived access token. * **Remote MCP servers:** a token you add is stored encrypted and sent only to that server. Itoflow never passes on your own Itoflow credentials. * **GitHub:** the token never enters the sandbox. A service outside it adds the token to each call after checking that you own the connection. * **Brokers:** broker credentials are stored encrypted and never enter the agent's environment. * **These docs:** the in-browser request tool sends no cookies and no proxy sits in between. Your request goes straight to the API. ## Security and data handling * **Isolated sandboxes.** Agent code runs in an isolated sandbox for each chat. The sandbox holds no database credentials and no tokens, and reaches data only through fixed operations, scoped to the owner, that Itoflow runs outside the sandbox. * **Least access for GitHub.** The GitHub app asks only for code, pull requests and CI results. It gets no access to Actions, workflows, admin settings or secrets. Branch protection still applies, and a merge must name the commit it expects. * **Outside text is data.** Text from your repositories counts as untrusted input, not as instructions to the agent. * **Remote MCP calls stay narrow.** Itoflow reaches your MCP servers over HTTPS on public addresses only, follows no redirects and sends no cookies. * **No blind repeats.** If a write to GitHub or a connected server may or may not have happened, Itoflow reports the outcome as unknown and doesn't send it again on its own. * **Encryption.** Connections use encrypted transport. Broker and ChatGPT-subscription credentials are encrypted at rest with AES-256-GCM. GitHub and MCP server tokens are held by our identity provider and never enter the sandbox. * **No customer money.** Itoflow is not a broker or custodian and holds no customer funds. Live orders go to your own broker account, and only after a person approves them. * **Assurance.** Our SOC 2 assurance work is in progress. The [security overview](https://itoflow.ai/security) has the current state. ## Further reading * [How we connected customers' MCP servers and GitHub repos to our research agent](https://itoflow.ai/blog/how-we-connected-mcp-servers-and-github): how credentials stay out of the model and the sandbox. * [Governed AI investment agents in practice](https://itoflow.ai/blog/governed-agents-in-practice): two unedited research sessions, repairs included. * [AI agent review for investment research](https://itoflow.ai/blog/workflow-guardian-agentic-review): how the independent review works. * [Machine-checked contracts for AI agents](https://itoflow.ai/blog/from-conversation-to-commitment): turning investment intent into a checked workflow. * [Market-aware trade execution](https://itoflow.ai/blog/async-trades-architecture): how trades wait for market hours. * [How we built a cross-asset factor risk model](https://itoflow.ai/blog/factor-risk-models-for-agentic-portfolios) * [Security at Itoflow](https://itoflow.ai/security) # Find and resolve symbols Source: https://docs.itoflow.ai/guides/symbols List exchanges, search by ticker or company, and resolve broker symbols, ISINs and MICs to Itoflow symbols. > [!TIP] > > **The easiest way: ask your AI assistant.** With [Itoflow MCP](/mcp/install) connected to Claude or Codex, paste: > > ```text theme={null} > Use Itoflow to find the Itoflow symbol for ASML on Euronext Amsterdam and for > the ISIN US0378331005. > ``` > > > [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%20find%20the%20Itoflow%20symbol%20for%20ASML%20on%20Euronext%20Amsterdam%20and%20for%20the%20ISIN%20US0378331005.) > > > > 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%20find%20the%20Itoflow%20symbol%20for%20ASML%20on%20Euronext%20Amsterdam%20and%20for%20the%20ISIN%20US0378331005.) > > > > 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/chat). The rest of this page covers the HTTP API. An Itoflow symbol is a ticker and an exchange code joined by a dot, such as `AAPL.US` or `ASML.AS`. Every endpoint that takes an instrument expects this form. `GET /symbols/exchanges` lists the exchange codes. ```mermaid theme={null} flowchart TD Input[What you have] --> Choice{Which kind?} Choice -->|Ticker or company name| Search[Search] Choice -->|Full Itoflow symbol| Exact[Search with mode exact] Choice -->|ISIN, MIC or broker symbol| Resolve[Resolve] Resolve --> Result{Evidence agrees?} Result -->|Yes| Canonical[One Itoflow symbol] Result -->|No| Failure[422 with the reason] ``` ## Search by ticker or company `GET /symbols/search` returns ranked matches. Pass the ticker or company name in `q`, and optionally an `exchange` code: ```bash theme={null} curl --fail-with-body --silent --show-error --get \ 'https://api.itoflow.ai/symbols/search' \ --header "Authorization: Bearer $ITOFLOW_ACCESS_TOKEN" \ --data-urlencode 'q=AAPL' \ --data-urlencode 'exchange=US' ``` To check that a full symbol exists, pass it with `mode=exact`: ```bash theme={null} curl --fail-with-body --silent --show-error --get \ 'https://api.itoflow.ai/symbols/search' \ --header "Authorization: Bearer $ITOFLOW_ACCESS_TOKEN" \ --data-urlencode 'q=AAPL.US' \ --data-urlencode 'mode=exact' ``` ## Resolve identifiers `GET /symbols/resolve` turns other identifiers into an Itoflow symbol. Give it whatever you know, using these query parameters: `siq_symbol` (an Itoflow symbol), `ticker`, `broker_symbol`, `isin`, `company_name`, `currency`, `exchange` and `mic`. `exchange` takes an Itoflow code such as `US` or `LSE`; put a venue such as XNAS in `mic` (an ISO 10383 code), not in `exchange`. The more you give, the more it can check. If the pieces disagree, are incomplete, or name an exchange Itoflow doesn't cover, it returns `422` with one of these codes: `identifier_evidence_missing`, `exchange_or_mic_required`, `canonical_currency_missing`, `instrument_identifier_conflict`, `instrument_identity_unresolved`, `unsupported_exchange` or `unsupported_mic`. The last two include the values Itoflow does support. Show that list to your user rather than guessing another exchange or currency. Both resolve routes accept common share-class spellings in `ticker` or an unqualified `broker_symbol`. With `exchange: "US"`, `BRK.B`, `BRK/B` and `BRK B` resolve to `BRK-B.US` only when that dashed listing exists. This rule applies on every supported exchange: letters, one dot, slash or space, then one or two letters. Other shapes, such as `BAC.PRL`, are looked up as written. `BRKB` and `UHALB` stay unresolved; the resolver does not guess where to split them. Any supplied security identifier, currency or company name must still match the listing. ### Resolve many identifiers at once `POST /symbols/resolve/batch` resolves up to 3,000 instruments in one call, such as every row of a holdings file. Each item takes the same fields as the `GET /symbols/resolve` query: ```bash theme={null} curl --fail-with-body --silent --show-error \ 'https://api.itoflow.ai/symbols/resolve/batch' \ --header "Authorization: Bearer $ITOFLOW_ACCESS_TOKEN" \ --header 'Content-Type: application/json' \ --data '{"items": [{"ticker": "AAPL", "exchange": "US"}, {"isin": "US5949181045"}, {"ticker": "QQQ", "mic": "XNAS"}]}' ``` The answer has one row per item, in the order you sent them, each with its `index`. A row answers as `GET /symbols/resolve` would: `ok: true` with the `instrument`, or `ok: false` with one of the codes above. One bad row does not fail the others. A row with `resolution_unavailable` was not finished within this call, for example because a data provider was slow; send those rows again. A fault that sending a row again would not fix, such as a database failure, fails the whole call. Search and resolve may look up a data provider. If the provider is down they can fail with `5xx`; retry a few times with a growing wait. # Itoflow developer docs Source: https://docs.itoflow.ai/index Itoflow takes an investment idea from research to live trading in one place, with agents doing the work: research, agents that watch ideas and portfolios around the clock, paper strategies, then live trading with a person approving every trade. Itoflow supplies the market data and compute. Start with one part, such as the risk engine, from your AI assistant over MCP or from code over HTTP. ```mermaid theme={null} flowchart LR Research[Research an idea] --> Watch[Agents watch it] Watch --> Paper[Paper strategies] Paper --> Live[Live trading] Live -->|watched 24/7| Watch ``` 1. **Research.** Ask in plain English from Claude, ChatGPT, Codex or your own code. An agent plans the work, writes and runs Python on Itoflow's engine, and a second agent reviews it. You get the result with the code behind it: signal tests, walk-forward backtests, portfolio construction, and a factor risk model that looks through ETFs to their holdings. 2. **Watch.** Hand an idea, a list of stocks or a portfolio to a monitor: an agent that checks it on a schedule, under a mandate you write, and reports what changed. 3. **Paper trade.** Once you settle on a strategy, run as many paper versions of it as you want. Paper trades fill only while the market is open, at the latest available price, after a 0.10% commission and currency conversion. That price can come from an earlier session; see [price timing](/features/market-data#quotes-and-prices). Each strategy records why it made every decision. 4. **Go live.** When a strategy is ready, move it to a live portfolio through Itoflow's execution engine. A person approves every list of trades, and monitors keep watching the portfolio. Every step happens in one place, so each starts from what came before: a live strategy carries its research, its paper record and its mandate. Itoflow also supplies what the agents need to run: prices, fundamentals, filings and news for stocks and ETFs on 24 exchanges in 22 markets, plus crypto (`GET /symbols/exchanges` lists them), and the compute. **Start with one part.** You don't need the whole platform on day one. The risk engine works on its own over the API, so you can start by monitoring the portfolios you already hold, then add research and strategies. ## What you can do | Job | What you get | Start here | | - | - | - | | Test a signal or dataset | Information coefficients, out-of-sample results and overfitting checks, or a plain "no edge found" | [Test a signal](/use-cases/test-a-signal) | | Build and stress-test a strategy idea | A walk-forward backtest with costs, turnover and stress periods, saved as a paused strategy you can review | [Stress-test a strategy idea](/use-cases/stress-test-a-strategy-idea) | | Decide whether a name improves a book | Its effect on the book's return and risk, beside its fundamentals | [Improve a book](/use-cases/add-a-name-to-a-book) | | Measure a book's factor risk | Market, country, industry and style exposures, risk by holding and ETF look-through, with dated model snapshots for backtests | [Measure factor risk](/use-cases/measure-factor-risk), [Interactive Brokers portfolio](/use-cases/interactive-brokers-risk) | | Bring in your holdings | Up to 3,000 rows matched to instruments and priced, saved only after a person reviews the draft | [Import holdings](/features/portfolios#import-holdings) | | Watch a portfolio or fund | Scheduled reports on exposure, risk, liquidity and performance against a benchmark and peer funds you choose | [Monitor a portfolio](/use-cases/portfolio-monitoring) | | Get a daily news brief | News and filings rated for each holding, even when the headline doesn't name it | [Daily news brief](/use-cases/daily-news-brief) | | Run a strategy under a mandate | A portfolio that decides on schedule, records why, and waits for your approval before any live trade | [Run a strategy](/use-cases/run-a-strategy) | | Compare tax-loss harvesting rules | The after-tax result and tracking error of each rule on the same lots | [Compare harvesting rules](/use-cases/compare-tax-loss-harvesting) | | Work in your own code and tools | Agents that read and change your GitHub repositories, open draft pull requests, and call your own MCP servers | [Research with your code](/use-cases/research-with-your-code) | | Build Itoflow into your software | An HTTP API for portfolios, strategies, monitors, market data and risk | [First API request](/quickstart/http) | ## Published results Each result states its conditions. The linked posts give the method and the limits. * **Factor risk model.** Scored with the bias statistic and its 95% band as MSCI defines it, 0.82 to 1.18 for 59 month-ends: all 9 portfolio-family means and 107 of 116 portfolios fell inside the band, over 59 month-ends from September 2021 to July 2026 on a point-in-time S\&P MidCap 400. On optimized portfolios the model came within 4% of realized volatility, where a plain sample covariance fell 17% to 26% short. One universe, one period. [How our factor risk model measures up](https://itoflow.ai/blog/factor-risk-model-vs-institutional-providers), September 8, 2026. * **Independent review.** On 7 matched synthetic research tasks, one run each, review raised the mean score from 0.568 to 0.693 on a 0 to 1 scale. Six tasks improved and one got worse. [How we use a second AI agent to review investment research](https://itoflow.ai/blog/workflow-guardian-agentic-review), July 30, 2026. * **A run that found no edge.** Asked to find a signal in US equities, the agent fixed a 12-stock large-cap universe before seeing any results, tested momentum and mean reversion out of sample, found no validated edge, and said so rather than invert the signals or switch universes. [What our quant-research agent actually does — and where it still needs a human](https://itoflow.ai/blog/what-our-quant-research-agent-actually-does), July 9, 2026. * **Two sessions, end to end.** Asked for a stock-bond strategy with a 10% volatility target and a 15% drawdown limit, the agent picked the only one of three designs that stayed inside the limit, which ran at about 7% volatility, and stress-tested it on the Covid crash. In the second, review sent a fossil-free MSCI World tracker back once before it passed. Both end in a paused paper strategy. [Governed agents in practice](https://itoflow.ai/blog/governed-agents-in-practice), July 9, 2026. * **Tax-loss harvesting.** Eight harvesting approaches and a no-harvest baseline on one modeled $10M S&P MidCap 400 account over five years: optimized sales with ETF replacement ended $1.08M (7.3%) ahead of no harvesting, with tracking error against the index of 1.56% a year, against 1.19% with no harvesting. Fixed rules and modeled fills; not tax advice. [Finding tax alpha with Itoflow](https://itoflow.ai/blog/how-to-measure-tax-alpha), September 29, 2026. * **News for each holding.** On one test day of 25 stories, judged by an AI, rating news through the industries it could move found all 58 company-story pairs that rating every company found, at about a third of the cost. Matching company names found 4. It measured recall only: about one link in seven that it showed was one the judge marked. [How we used Jev to find the news that moves a company without naming it](https://itoflow.ai/blog/how-we-used-jev-to-route-news-to-stocks), October 1, 2026. [BuySideBench](https://itoflow.ai/benchmark) is our public benchmark of buy-side tasks, with its method, conditions and results. ## How the work is checked * **A checked plan before any work.** Itoflow turns your request into a research contract: the question, the data, the dates, and the evidence the answer must carry. The system checks the plan before work starts. Each number the agent reports needs a proof the system checks: a computed value, a comparison, a saved file, or an out-of-sample choice that the system works out again itself. * **Overfitting checks in the engine.** The engine computes the probability of backtest overfitting, the deflated Sharpe ratio and false-discovery-rate control, and the research contract can require them as evidence. The checks are code, not a prompt. * **A second agent reviews the work.** Itoflow starts an independent reviewer on the plan before research and on the answer before it reaches you. The reviewer is a separate agent on the same model as the run. It reads the actual files, not the research agent's summary, and either accepts the work or sends it back with what to fix. The research agent can't skip the review or narrow it. If the review itself fails, or concerns are still open after 10 rounds, the work goes on, and the system's own checks still apply. * **The engine starts the report; the agent's analysis finishes it.** A monitor report starts from the risk engine's figures, and the agent may correct a figure or add its own from further analysis. A figure no one can produce shows as "not known", never as a guess. * **Only data that existed at the time.** A past-date risk read uses the factor model snapshot saved on or before that date, and Itoflow refuses a date or symbol the snapshot doesn't cover rather than fill the gap. Fund holdings count from the day the SEC accepted the filing. Company statements count from when they became public, such as the results announcement, and the history reports any statement it couldn't date that way. * **A person approves every live trade.** Agents propose trades; they never send live orders on their own. Each approval covers one exact proposal, named by ID and a hash of its contents, so nobody can approve one list and send another. * **Every decision keeps its record.** Chats keep their code, files and reasoning. Strategies store each decision with its weights, reasoning and confidence. [The agent harness](/platform/agent-harness) explains how the checks work, and [Design principles](/guides/design-principles) says what they mean for your code. ## What Itoflow doesn't do yet * **Stocks, ETFs and crypto only.** Futures, options and individual bonds aren't covered. * **One live broker.** Live trading runs through Trading 212. Other brokers, such as Interactive Brokers, connect through their own MCP server, so agents can read your positions there. * **No live short sales.** Long-short books, such as a 130/30, run on paper portfolios. Margin and financing are out of scope. * **No automatic live trading.** Automatic execution works on paper portfolios only. * **Experimental APIs.** All Itoflow APIs may change without notice. There is no official SDK: use any HTTP client, or generate one from the [OpenAPI file](/openapi/itoflow-public.openapi.json). ## Ways to use Itoflow * **From your AI assistant.** Install the Itoflow plugin in Claude, ChatGPT, Codex, Gemini, GitHub Copilot or Cursor, sign in, and ask in plain English. Your assistant reaches the product through the Itoflow MCP server and never sees a token. [Connect your assistant](/mcp/install). * **In the Itoflow app.** Run the same research, monitors and strategies in your browser at [app.itoflow.ai](https://app.itoflow.ai). * **From your code.** Sign in with device authorization and call the HTTP API with cURL, JavaScript, Python or any other client. [Make your first request](/quickstart/http). * **With your own code, tools and models.** Connect GitHub so agents can read, run and change your research code and open draft pull requests. Connect your own remote MCP servers so agents can call your tools. Tokens never reach the model or the sandbox. Chat and monitors can also run on your own ChatGPT subscription. [Connect GitHub and MCP servers](/features/integrations). Your code, your data and your research stay yours. Itoflow sells no signals and imposes no investment view. **Security.** Connections use encrypted transport. Broker and ChatGPT-subscription credentials are encrypted at rest with AES-256-GCM. GitHub and MCP server tokens are held by our identity provider and never enter the sandbox. Itoflow is not a broker or custodian and holds no customer funds. Our SOC 2 assurance work is in progress. See the [security overview](https://itoflow.ai/security). **Plans.** The free plan is enough to start. Pro and Max add advanced models and more included usage. AI usage counts in credits at the model provider's cost times a stated multiplier. See [Billing and credits](/features/billing) and the [pricing page](https://itoflow.ai/pricing). Itoflow is built by quants from J.P. Morgan and Tower Research and engineers from Google, Apple and Microsoft. > [card] [Use Itoflow in your AI assistant](/mcp/install) > > Install the Itoflow plugin in Claude, ChatGPT, Codex, Gemini, GitHub Copilot or Cursor and sign in. > [card] [Use cases](/use-cases/overview) > > Step-by-step guides with prompts you can paste into your assistant. > [card] [Make your first API request](/quickstart/http) > > Get an access token and call the API with cURL, JavaScript or Python. > [card] [How Itoflow works](/platform/how-itoflow-works) > > The agent harness, the quant engine and the factor risk model, and how they fit together. > [card] [Find a symbol](/guides/symbols) > > Search by ticker or company, or resolve a broker symbol or ISIN. > [card] [Open the Itoflow app](https://app.itoflow.ai) > > Do the same jobs by hand in your browser. The [API coverage index](/api-reference/coverage) lists every endpoint by feature. To ask an assistant about any page, choose **Open in ChatGPT** or **Open in Claude** from the page menu. To give it the whole docs, use the [Markdown pages and `llms.txt` index](/guides/ai-tools). # Connect your AI assistant Source: https://docs.itoflow.ai/mcp/install Install the Itoflow plugin in Claude, ChatGPT, Codex, Gemini, GitHub Copilot or Cursor and sign in to Itoflow. The Itoflow plugin connects your assistant to Itoflow at `https://mcp.itoflow.ai/mcp` and adds two skills: the Itoflow skill for research and account tasks, and the worker skill for [local analysis](/mcp/usage#work-with-your-local-agent). Install it from the public [itoflow/skills](https://github.com/itoflow/skills) repository, then sign in with your Itoflow account. ```text theme={null} Install the plugin → Sign in to Itoflow → Check the connection → Read and make changes ``` ## Install the plugin > [tab] Claude Code > > ```bash theme={null} > claude plugin marketplace add itoflow/skills > claude plugin install itoflow@itoflow > ``` > > Open Claude Code, enter `/mcp`, select the Itoflow server, choose **Authenticate** and sign in. Then use `/itoflow:itoflow` for the Itoflow skill or `/itoflow:worker` for local analysis. > > These are terminal commands; in JetBrains, run them in the IDE's terminal. The Claude desktop app's Code tab and the VS Code extension share the same settings, so the marketplace you add here shows up there too. In VS Code you can also type `/plugins` and add `itoflow/skills` on the **Marketplaces** tab. > [tab] Claude web or desktop > > This works for chat on claude.ai in a browser, chat in the Claude desktop app, and Cowork. > > 1. Open **Customize → Plugins**, select **Add**, then **Add marketplace**. > 2. Enter `itoflow/skills` and install **Itoflow**. > 3. Open the plugin's **Connectors** tab, add the Itoflow connector, then connect it and sign in. Adding a plugin does not connect its server. > > The plugin is then on your Claude account, so it also works in the Claude mobile app and syncs to Claude Code. On Team and Enterprise plans, an Owner decides whether members can add marketplaces and adds the connector for the organization. > [tab] Codex > > ```bash theme={null} > codex plugin marketplace add itoflow/skills > codex plugin add itoflow@itoflow > codex mcp login itoflow > ``` > > Start a new task, then pick the Itoflow skill or the worker skill. These are Codex CLI commands; Codex in the ChatGPT desktop app then installs Itoflow from its **Plugins** tab. > > The Codex IDE extension doesn't install plugins, so add the two parts yourself. Open the gear menu, choose **MCP servers → Add server**, select **Streamable HTTP**, enter `https://mcp.itoflow.ai/mcp` and select **Authenticate**. Then add the skills with `npx skills add itoflow/skills -a codex`. > [tab] ChatGPT > > 1. Download [`itoflow-openai.zip`](https://github.com/itoflow/skills/releases/latest/download/itoflow-openai.zip) from the latest release. > 2. On chatgpt.com, open [Plugins](https://chatgpt.com/plugins), select **Add**, then **Upload plugin archive**, and choose the ZIP. > 3. Find **Itoflow** in your personal plugins and install it. Connect it and sign in when ChatGPT asks. > 4. In a chat, type `@` and pick Itoflow. > > The upload option appears only when your plan or workspace allows it. A workspace admin can instead import `https://github.com/itoflow/skills` under **Admin Console → Plugins → Add → Import marketplace**, which keeps the plugin up to date. ChatGPT can label a plugin that declares an MCP server **Desktop only**; if it labels Itoflow that way, use it in the ChatGPT desktop app. See [Plugins in ChatGPT](https://help.openai.com/en/articles/20001256-plugins-in-chatgpt). > [tab] Gemini > > In Gemini CLI: > > ```bash theme={null} > gemini extensions install https://github.com/itoflow/skills > ``` > > Gemini CLI opens your browser to sign in the first time it uses an Itoflow tool. > > In the Gemini app, add the two parts yourself. On gemini.google.com, open **Settings → Connected Apps**, choose **Add a custom app** under **Custom apps**, enter `https://mcp.itoflow.ai/mcp` and sign in. Then upload [`itoflow-skill-itoflow.zip`](https://github.com/itoflow/skills/releases/latest/download/itoflow-skill-itoflow.zip) and [`itoflow-skill-worker.zip`](https://github.com/itoflow/skills/releases/latest/download/itoflow-skill-worker.zip) under **Settings → Skills → Upload**. Both also work in the Gemini mobile app. Custom apps need a personal Google account, age 18 or over, a location in the US, and Keep Activity turned on. > [tab] GitHub Copilot > > In the Copilot CLI: > > ```bash theme={null} > copilot plugin marketplace add itoflow/skills > copilot plugin install itoflow@itoflow > ``` > > In VS Code, with the `chat.plugins.enabled` setting on, run **Chat: Install Plugin From Source** from the Command Palette and enter `https://github.com/itoflow/skills`. Sign in when your browser opens. > > In Visual Studio and JetBrains, add the server URL from Copilot Chat's MCP settings, then copy the `skills/` folders to `~/.copilot/skills/`. Skills need Visual Studio 18.5 or later; in JetBrains, turn them on under **Settings → GitHub Copilot → Chat → Agent**. On Business and Enterprise plans, an admin must turn on the **MCP servers in Copilot** policy. > [tab] Cursor > > Cursor loads plugins from `~/.cursor/plugins/local/`. Clone the repository there, so `git pull` brings updates: > > ```bash theme={null} > git clone https://github.com/itoflow/skills ~/.cursor/plugins/local/itoflow > ``` > > Then restart Cursor, or run **Developer: Reload Window**, and sign in when Cursor asks. On Teams and Enterprise plans, an admin controls local plugins, or imports the repository under **Dashboard → Plugins & MCPs → Add Marketplace → Import from Repo**. > [tab] Other clients > > Add the two parts yourself. > > 1. Add the skills with `npx skills add itoflow/skills`, copy the `skills/` folders into `.agents/skills/`, which many clients read, or upload both skill ZIPs from the [latest release](https://github.com/itoflow/skills/releases/latest). > > 2. Add the server with these settings: > > | Setting | Value | > | - | - | > | Server name | `itoflow` | > | Server URL | `https://mcp.itoflow.ai/mcp` | > | Transport | Streamable HTTP (often labeled HTTP) | > | Authentication | OAuth, through the client's browser sign-in | > > 3. Sign in when the client asks. > > The skills need the server connection. If you install the plugin and added the server by hand earlier, remove the older entry so you have one Itoflow connection. Your client stores the sign-in for you. Never paste a token or browser cookie into the conversation. If the sign-in expires, reconnect from the client's MCP settings. ## Make your first request Check that your client lists three Itoflow tools: `search`, `execute` and `workspace_list`. Your first request only reads, so nothing changes while you test. Paste this into your assistant: ```text theme={null} Use Itoflow to list my portfolios. Do not create or change anything. ``` > [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%20list%20my%20portfolios.%20Do%20not%20create%20or%20change%20anything.) > > 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%20list%20my%20portfolios.%20Do%20not%20create%20or%20change%20anything.) > > Start this in ChatGPT with the Itoflow plugin. Using another client? Copy the prompt with the button on the code block. Any list, even an empty one, means the connection works. A "connected" badge alone doesn't prove that requests work. After that, your assistant can also make changes, such as creating monitors, editing strategies and importing portfolios. See [what you can ask for](/mcp/overview#what-you-can-ask-for). Next, try the [usage examples](/mcp/usage). If something fails, see [MCP troubleshooting](/mcp/troubleshooting). ## Use Itoflow in Claude Code's auto mode In auto mode, Claude Code has a classifier review each tool call before it runs. It can block an `execute` call that sends holdings or weights to Itoflow and label it "Data Exfiltration", because it doesn't know you send that data to Itoflow on purpose. Tell it in your user settings, `~/.claude/settings.json`: ```json theme={null} { "autoMode": { "environment": [ "$defaults", "Trusted external service: Itoflow (mcp.itoflow.ai), where I send portfolio holdings and weights for analysis" ] } } ``` * Keep `"$defaults"`. Without it, your entry replaces Claude Code's built-in list, including its own data rules. * Claude Code reads `autoMode` from your user settings or your organization's managed settings, not from a project's `.claude/settings.json`. * Run `claude auto-mode config` to check what it loaded. * The classifier still reviews every call. The entry tells it that sending portfolio data to Itoflow is expected. You can also let the read-only `search` tool run without review. With the plugin, its name is `mcp__plugin_itoflow_itoflow__search`; with a server you added by hand as `itoflow`, it is `mcp__itoflow__search`. Enter `/mcp` and select the tool to see its full name. ```json theme={null} { "permissions": { "allow": ["mcp__plugin_itoflow_itoflow__search"] } } ``` Don't pre-approve `execute`. It is the tool that sends your data, so keep auto mode reviewing it. If a call is still blocked as "Data Exfiltration", run `claude auto-mode config` and check that your entry is there. Pressing `r` under **Recently denied** in `/permissions` doesn't approve the call: it only lets your assistant try again, and the classifier reviews it again. Approving in chat doesn't clear this rule either. If your entry is loaded and calls are still blocked, leave auto mode while you work with Itoflow and approve each `execute` call yourself. Your assistant should tell you when a call is blocked. It should never split, encode or rename data to get past the check. Your assistant's program carries the data it sends, such as instrument names and weights. Itoflow keeps a risk run's book only in your account's risk sandbox, and doesn't save it as a portfolio. The sandbox sleeps about two minutes after your last risk call, once none of your runs is going, and its files go with it. A finished run's figures and full engine output stay available for 24 hours in owner-scoped storage. Use `getRiskRunArtifact` for the full output. The request itself stays in the sandbox. Stored outputs expire from storage within three days; cancellation and timeout retain their terminal outcomes. Resolving an identifier can add the instrument it finds to Itoflow's shared symbol list, as any lookup does. ## Releases and archives Each new plugin version publishes a [GitHub release](https://github.com/itoflow/skills/releases). Installing from `itoflow/skills` gives you the latest one. To install without Git, download [`itoflow.zip`](https://github.com/itoflow/skills/releases/latest/download/itoflow.zip), unzip it into a folder named `itoflow` and add that folder as a marketplace, for example `claude plugin marketplace add ./itoflow`. Keep the folder in place. The same ZIP works with Claude's **Upload plugin**. Risk-run results include a top-level `analytics` reference. Copy the complete document through the owner-authorized artifact route, using gzip byte ranges for large files, and verify its compressed and raw sizes and hashes. Select needed records in your workspace; do not print or parse the entire document inside a chat worker. See [risk runs](/api-reference/risk-runs). # Itoflow MCP Source: https://docs.itoflow.ai/mcp/overview Install the Itoflow plugin in Claude, ChatGPT, Codex, Gemini, GitHub Copilot or Cursor for research, portfolios, strategies and chat files. **Experimental:** Itoflow MCP may change without notice. The Model Context Protocol (MCP) lets your AI assistant use Itoflow for you. Install the Itoflow plugin from the public [itoflow/skills](https://github.com/itoflow/skills) repository in Claude, ChatGPT, Codex, Gemini, GitHub Copilot or Cursor, then sign in to your Itoflow account. The plugin connects your assistant to the Itoflow MCP server and adds two skills: * **Itoflow skill:** guidance that helps your assistant run research and account tasks well. * **Worker skill:** lets Itoflow direct an analysis that needs files, databases or tools on your own machine. See [Work with your local agent](/mcp/usage#work-with-your-local-agent). The [connection guide](/mcp/install) has the steps for each client. ```mermaid theme={null} flowchart LR You[You] --> Client[Claude, ChatGPT, Codex, Gemini, Copilot or Cursor] Client -->|Itoflow plugin and sign-in| Itoflow[Itoflow] Itoflow --> Research[Research and results] Itoflow --> Product[Portfolios, strategies and monitors] ``` ## What you can ask for | Goal | Example request | | - | - | | Research an investment question | “Use Itoflow to compare SPY and VTI, with sources and key differences.” | | Review holdings | “List my Itoflow portfolios, then summarize the holdings in the one I choose.” | | Import a portfolio | “Validate these holdings and show me the proposed import before saving it.” | | Check strategies and monitors | “Show my strategies and monitors, and summarize their latest results.” | | Get research files | “Find the CSV this Itoflow chat produced and read it.” | | Check connections | “Show my saved integrations and their status.” | Your assistant can make changes as well as read: it can create monitors, edit strategies and import portfolios. Your plan's limits apply, and live trades still need your approval in Itoflow. Connecting MCP does not connect a brokerage account. See [billing](/features/billing) for which models your plan includes. This page covers connecting your assistant to Itoflow. To connect another MCP server to Itoflow's own chat, see [Connect GitHub and MCP servers](/features/integrations). # MCP troubleshooting Source: https://docs.itoflow.ai/mcp/troubleshooting Fix connection, sign-in, missing-tool, plugin, research and file problems. Find the step that failed: ```text theme={null} Plugin installed → Signed in → Tools loaded → Request returned a result ``` ## Connection and sign-in | Problem | What to do | | - | - | | The server URL doesn't connect | Use `https://mcp.itoflow.ai/mcp` with Streamable HTTP and OAuth. Check that your client supports remote servers and that your workspace allows plugins or custom MCP servers. | | Sign-in didn't finish or has expired | Authenticate again from the client's MCP settings: `/mcp` in Claude Code, or `codex mcp login itoflow` in Codex. Restarting the client doesn't finish a sign-in. | | Codex keeps asking you to sign in | You may have more than one Codex installed. Sign in with the CLI that belongs to the Codex app running your task. | | Tools don't appear | Start a new task or restart the client. If you use the plugin, check that it finished installing. | | Permission denied | Check which Itoflow account you signed in with and whether it can use that resource. Reinstalling doesn't change access. | After you reconnect, repeat the [first request](/mcp/install#make-your-first-request). Never paste tokens or browser cookies into the conversation. ## Plugin | Problem | What to do | | - | - | | No worker skill | Install the [plugin](/mcp/install#install-the-plugin), or add the skills as the guide describes for your client. | | Marketplace not found | Add `itoflow/skills`, or for an archive, the extracted `itoflow` folder. Keep that folder in place. | | Marketplace name already in use | You already added the `itoflow` marketplace, for example from an archive. Remove it, then add `itoflow/skills`. | | Plugin not found | Check that the marketplace step succeeded, then install `itoflow@itoflow` again. | | You don't get the latest skills | Update the marketplace and plugin from your client, for example `claude plugin update itoflow@itoflow`, then start a new task. Check the version against the [latest release](https://github.com/itoflow/skills/releases). | ## Research and account tasks | Problem | What to do | | - | - | | `search` finds nothing | Try a short phrase such as `list portfolios`. No match doesn't mean you lack access. | | Claude Code blocks a call as "Data Exfiltration" | Auto mode doesn't know you send portfolio data to Itoflow. [Tell it](/mcp/install#use-itoflow-in-claude-codes-auto-mode). Approving the call in chat or retrying it under `/permissions` → **Recently denied** doesn't clear this check. | | Research stays pending or running | Ask your assistant to check the same run again later. Don't send the question again; that starts a second run. | | Research stopped with an error | Ask your assistant for any partial results first, then decide whether to run it again. | | The result has no text | Ask your assistant to read the returned dashboard and its sources. The answer is often there. | | Itoflow asks a question your client can't show | Use a client that can display forms, or answer in the Itoflow chat. Replying in a new message doesn't answer the question. | | A change is rejected because of a version conflict | Ask your assistant to reload the current state and try the change again. | | A direct API call returns `ok: false` | Read `status` and `body`. All 4xx responses and any 5xx status listed for that operation in its published OpenAPI document return `{ ok: false, status, body }`. If `Retry-After` is a whole number of seconds, the result also gives `retry_after_seconds`; wait that long before retrying. Other header forms are omitted. Redirects and undocumented server failures return a generic error. | | An operation you expect is missing | Not every Itoflow feature is available through MCP. Use the [HTTP API](/api-reference/overview) or the app. | ## Local worker and files | Problem | What to do | | - | - | | The worker can't read a file or database | Check that your local session can reach it. The plugin doesn't add access or credentials. | | Itoflow asks about a local file | Let your local agent read and analyze it, then report back. Itoflow can't open paths on your machine. | | Itoflow hands the whole task to the worker | Ask Itoflow to plan the research and give the worker one specific step at a time. | | A chat file is too large | MCP reads files up to 32 MiB. Use the [download endpoint](/features/chat#download-files-from-a-chat) for larger files. | | A file read says the workspace is busy | Two other downloads or reads from that chat's workspace are in progress. Try again when one finishes. Running research doesn't block reads. | | You want to upload a file | MCP can't upload files. Use the Itoflow app, or let the worker analyze the file locally. | ## Ask for help Email [support@itoflow.ai](mailto:support@itoflow.ai) with your client and its version, how you connected (URL or plugin, and the plugin version), which step failed, and the error text. Leave out tokens, account details and private file contents. For HTTP API errors, see [Troubleshooting](/troubleshooting). # Use Itoflow from your assistant Source: https://docs.itoflow.ai/mcp/usage Example requests for research, portfolios and chat files, the local worker, and the MCP tools. After you [connect and sign in](/mcp/install), ask your assistant to use Itoflow. It finds the right Itoflow operation and checks its inputs before calling it, so you can ask in plain language. ## Research Paste this into your assistant: ```text theme={null} Use Itoflow to compare SPY and VTI diversification. Explain the differences, include sources, and wait for the research to finish before summarizing 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%20compare%20SPY%20and%20VTI%20diversification.%20Explain%20the%20differences%2C%20include%20sources%2C%20and%20wait%20for%20the%20research%20to%20finish%20before%20summarizing%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%20compare%20SPY%20and%20VTI%20diversification.%20Explain%20the%20differences%2C%20include%20sources%2C%20and%20wait%20for%20the%20research%20to%20finish%20before%20summarizing%20it.) > > Start this in ChatGPT with the Itoflow plugin. Using another client? Copy the prompt with the button on the code block. The research runs in Itoflow, not in your assistant, and can take several minutes. Your assistant starts it, checks on it and fetches the result with sources when it finishes. Ask it to wait rather than send the question again; a second request starts a second, separately billed run. See [Chat](/features/chat#run-research-through-mcp) for choosing a model and handling questions Itoflow asks mid-run. ## Portfolios, strategies and monitors | Try this | What happens | | - | - | | “List my portfolios and summarize the one I choose.” | Reads your portfolios and holdings. | | “Validate this holdings CSV for import. Show me the full draft before saving.” | Your assistant reads the file; Itoflow matches each instrument and returns a draft. Nothing is saved until you confirm. | | “Measure the risk of my portfolio against SPY and VTI.” | Calls the public [risk run operations](/api-reference/risk-runs) through `api.*` for a saved portfolio or a what-if, then summarizes the figures. | | “How did my portfolio's factor risk against SPY change over the last year of month-ends?” | Starts one [risk measure](/api-reference/risk-measure) over the range, on one model version, and reads it until it ends. A measure takes up to 60 dates and 10 books, so it can also compare books side by side. | | “Explain my strategy's mandate and latest results.” | Reads the strategy and its recent runs. | | “Show my monitors and summarize the latest report.” | Reads your monitors and their reports. | Before you confirm an import, check the holdings, quantities, currencies, cash and totals in the draft. If you change the draft, your assistant validates it again. If a file's tickers don't say which market they trade on, your assistant asks you once: one market for all of them, or one with exceptions. When Itoflow can't match a row from the file alone, such as a share class written `BRK/B` or a company that changed its name, your assistant can ask Itoflow's agent to propose a match. It asks you first, since each request uses Itoflow credits and stays in your account as a chat. It shows you each proposal, with the name Itoflow has for it, and uses it only once you accept it. It measures the file's risk or imports it only after you answer. Live trades always need your approval in Itoflow. A broker accepting an order doesn't mean it filled. See the [portfolio](/features/portfolios), [strategy](/features/strategies), [monitor](/features/monitors) and [broker](/features/brokers) guides. ## Risk of a weight book Your file can hold weights only, with shorts as negative weights and several legs side by side. Paste this into your assistant: ```text theme={null} Use Itoflow to measure the risk of the book in weights.csv against SPY, with QQQ and VTI as peers. The weights are fractions of NAV and shorts are negative. Tell me what the run sends before you start 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%20measure%20the%20risk%20of%20the%20book%20in%20weights.csv%20against%20SPY%2C%20with%20QQQ%20and%20VTI%20as%20peers.%20The%20weights%20are%20fractions%20of%20NAV%20and%20shorts%20are%20negative.%20Tell%20me%20what%20the%20run%20sends%20before%20you%20start%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%20measure%20the%20risk%20of%20the%20book%20in%20weights.csv%20against%20SPY%2C%20with%20QQQ%20and%20VTI%20as%20peers.%20The%20weights%20are%20fractions%20of%20NAV%20and%20shorts%20are%20negative.%20Tell%20me%20what%20the%20run%20sends%20before%20you%20start%20it.) > > Start this in ChatGPT with the Itoflow plugin. Using another client? Copy the prompt with the button on the code block. Your assistant resolves the names, up to 3,000 a call, starts a [risk engine run](/features/portfolios#measure-risk-through-mcp) and reads it until it ends, which takes minutes. It reports gross and net weight, the weight of names it couldn't resolve or the model doesn't cover, total, factor and specific risk, tracking error and beta against SPY and each peer, and the largest exposures with their signs. It doesn't need a NAV in money, and the book isn't saved as a portfolio. Risk engine runs aren't on for every account yet; on an account without them, the start is refused with `feature_not_enabled` and nothing runs. In Claude Code's auto mode, [tell auto mode about Itoflow](/mcp/install#use-itoflow-in-claude-codes-auto-mode) first. ## Work with your local agent Sometimes the data lives on your machine: a returns file, a local database, an internal tool. The **worker skill** in the [Itoflow plugin](/mcp/install#install-the-plugin) lets Itoflow direct an analysis that your local Codex or Claude Code session carries out. In Claude Code: ```text theme={null} /itoflow:worker Use my local returns file to compare SPY and VTI drawdowns. ``` In Codex, pick the worker skill, or ask: > Use the Itoflow worker skill to analyze my local returns file. ```mermaid theme={null} sequenceDiagram participant You as You participant Local as Your local agent participant Itoflow as Itoflow You->>Local: Ask for the analysis Local->>Itoflow: Describe the goal, data and tools available Itoflow-->>Local: Ask for a sample or a calculation Local->>Local: Run it on your machine Local->>Itoflow: Send back results and how they were made Itoflow-->>Local: Next step or final conclusion Local-->>You: Result and file links ``` Itoflow plans the research and writes the conclusion. Your local agent runs each step on your machine and reports what it did. It may suggest a better source or method; Itoflow decides whether to change course. What stays on your machine: * Your files. Itoflow sees only the results your local agent sends back, not the files themselves. * Your credentials. The worker uses the access your session already has, and the skill tells it not to send credentials or unrelated files to Itoflow. The plugin doesn't add database access or install tools. If the work needs nothing from your machine, Itoflow does it in the cloud instead. ## Read files from an Itoflow chat Paste this into your assistant: ```text theme={null} Use Itoflow to find the CSV produced by my latest research chat and read 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%20find%20the%20CSV%20produced%20by%20my%20latest%20research%20chat%20and%20read%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%20find%20the%20CSV%20produced%20by%20my%20latest%20research%20chat%20and%20read%20it.) > > Start this in ChatGPT with the Itoflow plugin. Using another client? Copy the prompt with the button on the code block. Your assistant lists the chat's files and reads the one you want. It can read files up to 32 MiB. For bigger files, use the [download endpoint](/features/chat#download-files-from-a-chat) with an [API access token](/authentication). You can't upload files to Itoflow through MCP. To work with a local file, use the worker skill, or upload it in the Itoflow app. ## MCP tools Itoflow exposes three tools. Your assistant uses them for you; you don't call them yourself. | Tool | Purpose | | - | - | | `search` | Find Itoflow operations and read their inputs. | | `execute` | Run operations, including starting, checking and queueing research. | | `workspace_list` | List files in one of your chats. Files are then read with the MCP `resources/read` method. | Itoflow can also serve these skills from the server, and will turn this on for accounts gradually. Once your account has it, an assistant that supports the MCP Skills extension can list and load the `itoflow` and `worker` skills from Itoflow, without installing the [plugin](/mcp/install#install-the-plugin). Until then, or if your assistant doesn't support the extension, install the plugin to get the skills. `search` looks through Itoflow's operation list, not the web. Short phrases such as `list portfolios` work best. No match means the wording didn't fit, not that you lack access. Itoflow returns every result in full, including long research answers and every `search` match. Your assistant may still shorten a very large result to fit its own limits. # The agent harness Source: https://docs.itoflow.ai/platform/agent-harness How Itoflow's agents do research you can check: a research agent that writes and runs Python in an isolated sandbox, a research contract fixed before work starts, a check that each reported number matches what the code produced, an independent reviewer the agent can't skip, and monitors and strategies that keep working on their own schedule. The harness is everything around the model: what it may do, what it must prove, who checks it, and when it runs again. It exists so that you can trust the work without redoing it. ```mermaid theme={null} sequenceDiagram participant You as You participant Agent as Research agent participant Checks as Contract checks participant Reviewer as Independent reviewer You->>Agent: Question or mandate Agent->>Checks: Research contract Checks-->>Agent: Plan accepted or sent back Agent->>Reviewer: Plan Reviewer-->>Agent: Accept, or send back with fixes Agent->>Agent: Write and run code in the sandbox Agent->>Checks: Proof for each number Agent->>Reviewer: Answer and files Reviewer-->>Agent: Accept, or send back with fixes Agent-->>You: Answer, code and evidence ``` ## The research agent The research agent plans the work, writes Python against Itoflow's quant library, runs it in an isolated sandbox, and answers with the code behind each result. * **Code, not a menu of tools.** The agent writes one script that can fetch data, run a test and measure risk together, rather than pick from a long list of separate tools. You can read and rerun the code afterward. * **An isolated sandbox.** Each chat has its own private workspace. The sandbox holds no database credentials and no tokens; it reaches data only through fixed operations, scoped to the owner, that Itoflow runs outside the sandbox. * **A full record.** A finished turn holds a dashboard (text, tables, charts, formulas and method diagrams), progress updates, the agent's working notes, the review, and every file it wrote. [What a finished turn contains](/features/chat#what-a-finished-turn-contains). * **It asks before it assumes.** Choices about your objective, risk, capital or permissions need your answer before the research that depends on them starts. * **It says what it couldn't do.** If a core data source fails, the agent stops that analysis and explains why. If a minor input is missing, it leaves it out and states the gap in the answer. * **You stay in control of the turn.** From your assistant you can start a turn, follow it, cancel it, or send it again safely: the same message ID is the same turn. [What our quant-research agent actually does — and where it still needs a human](https://itoflow.ai/blog/what-our-quant-research-agent-actually-does) shows two real runs, including one where the agent tested two signals out of sample, found no edge, and said so rather than invert the signals or switch universes. ## The research contract Before any research runs, the agent turns your request into a research contract: the question, the universe, the data and dates, the methods it will try, how it will choose between them, and the evidence the answer must carry. The system checks the contract and sends back one that is incomplete or badly formed, before any work starts. While it works, each number the agent reports needs a proof that the system checks: | Proof | What the system checks | | - | - | | A computed value | The number matches what the code produced. | | A comparison | A stated relation holds, such as one Sharpe ratio above another. | | A saved file | The file the answer cites exists in the workspace. | | An out-of-sample choice | The system works out the out-of-sample winner again itself. The agent can't just assert it. | Proofs cover numbers and files. Judgement, such as whether a method suits the question or a result is plausible, is the reviewer's job. Overfitting checks are part of the engine: the probability of backtest overfitting, the deflated Sharpe ratio and false-discovery-rate control. The contract can require them as evidence. If the agent needs a method the library doesn't offer, it may declare a custom method with a short description, and the reviewer checks that no library method fits. The contract has limits, and we say so: it moves ambiguity to the start of the work rather than remove it, and a portfolio that passes every check is not therefore a profitable one. [How Itoflow turns investment intent into a machine-checked contract](https://itoflow.ai/blog/from-conversation-to-commitment) explains the design. ## Independent review When the agent builds a research contract, Itoflow starts a second agent to review the work at two points: the plan, before research begins, and the answer, before it reaches you. * **Itoflow starts it, not the research agent.** The research agent can't skip the review or narrow what it covers. * **It reads the work itself.** The reviewer reads the actual files and results, not the research agent's summary of them. * **It doesn't change the work.** In chat research it has read-only access to the workspace and approved research tools; a strategy's reviewer may also keep its own notes. It can't edit the research agent's files, trade, ask you questions or start other agents. * **It gives a verdict.** It accepts the work or sends it back with what to fix. The reviewer normally follows repairs in the same conversation. If a strategy review runs out of context, Itoflow retries with the current request and work; the strategy's saved review notes remain. * **It runs on your model.** The reviewer uses the model you chose for the run, so it can share that model's blind spots. That is why exact rules, such as the contract checks, position limits and trade approval, sit in code rather than with either agent. * **When work goes on without acceptance.** If the review itself keeps failing, or concerns are still open after 10 rounds, Itoflow records which and the work continues, and the system's own checks and portfolio limits still apply. In published examples, review caught a position cap the agent had made up, survivorship and look-ahead bias in a historical test, and a call to a function that doesn't exist. On 7 matched synthetic research tasks, with one run each, review raised the mean score from 0.568 to 0.693 on a 0 to 1 scale; six tasks improved and one got worse. [How we use a second AI agent to review investment research](https://itoflow.ai/blog/workflow-guardian-agentic-review), July 30, 2026, gives the method, the failure and an earlier design that didn't work. ## Agents that keep working Monitors and strategies are agents that run for weeks or months. Each wakes, does its work, records what it found or decided, and sleeps until the next run. **Monitors** watch a list of holdings or a whole fund, such as IVV, and report what changed on a schedule you set. * The engine computes the figures before the agent starts. The agent picks what matters, writes the findings and explains them. * Before a report goes out, its figures are checked against the engine's output. A figure the engine can't produce shows as "not known". * Asking for a report while one is queued joins that run rather than start a second. **Strategies** run a paper or live portfolio under a mandate you write. * At each run the agent works as of that date and reads only data that existed then. * It decides when to wake next: on a date, on a move in a held name, or when a drawdown limit is hit. * It records each decision with its weights, its reasoning and its own stated confidence. * A strategy the agent drafts starts paused, and you turn it on. Paper portfolios can then trade automatically. Live portfolios wait until a person approves the exact list of trades, named by its ID and a hash of its contents. * Strategy agents meet the same evidence standard as chat. They decide within a standing mandate rather than ask you each time. [Monitors](/features/monitors) and [Strategies](/features/strategies) cover setup and the API. ## Skills, instructions and memory Agents don't start from nothing. * **Skills.** Agents read written procedures for the job, such as how to run a strategy, design wake conditions, research an allocation or read historical factor risk. Skills are plain files, reviewed and changed like code, so a change in behavior is a change you can read. * **Guidance when it applies.** Help arrives in tool results at the moment it is needed, rather than in one long prompt at the start. * **Memory.** Strategy agents keep notes between runs, such as lessons, research and hand-off notes, and read them each time they wake. ## Models You choose the model for each chat, monitor and strategy. A run uses the model saved when it starts, for the agent and its review, through every retry. If your plan stops covering that model, runs stop and ask you to choose; Itoflow never switches model without telling you. Chat and monitors can also run on your own ChatGPT subscription. See [Models and plans](/features/billing#models-and-plans). ## Further reading * [Governed agents in practice](https://itoflow.ai/blog/governed-agents-in-practice): two unedited sessions, end to end, including a draft the reviewer sent back. * [Why agentic investing is hard](https://itoflow.ai/blog/why-agentic-investing-is-hard): why portfolio agents need schedules and recorded decisions. * [How Itoflow works](/platform/how-itoflow-works): where the harness sits among the other layers. * [Quant engine and risk model](/platform/quant-engine): what the agent's code runs on. # How Itoflow works Source: https://docs.itoflow.ai/platform/how-itoflow-works Itoflow's five layers: your request or mandate, an agent harness that plans, codes and checks research, a quant engine, an independent factor risk model, and a person who approves every live trade. What each layer does, why it is there, and how your own code, tools and models plug in. Itoflow has five layers. Each does one job and hands the next a record it can check: the plan, the code, the figures, the decision and the approval. ```mermaid theme={null} flowchart LR Intent[Your request or mandate] --> Harness[Agent harness] Harness --> Engine[Quant engine] Engine --> Risk[Factor risk model and risk engine] Risk --> Record[Decision record] Record --> Approval[A person approves live trades] Approval --> Broker[Paper book or broker] ``` | Layer | What it does | Read more | | - | - | - | | Your request or mandate | A question in chat, a mandate for a strategy, or a list of holdings or a fund for a monitor. Each edit to a mandate makes a new version, and every report names the version it ran under. | [Strategies](/features/strategies), [Monitors](/features/monitors) | | Agent harness | A research agent writes Python and runs it in an isolated sandbox. A research contract fixes the question, data, dates and evidence before work starts. A second agent reviews the plan and the answer. Monitors run on a schedule, and strategies also wake on conditions they set, so the work goes on without a person present. | [The agent harness](/platform/agent-harness) | | Quant engine | Point-in-time market data, signal tests, walk-forward and out-of-sample backtests with overfitting checks, and portfolio construction with costs and turnover. Agents and Itoflow's own scheduled jobs call the same library. | [Quant engine and risk model](/platform/quant-engine) | | Factor risk model and risk engine | A model of stocks and ETFs, built daily and published apart from the agents that read it. The engine computes the risk figures a report starts from; the agent picks what matters, explains it, and may take the analysis further. | [Factor risk model](/platform/quant-engine#factor-risk-model) | | Approval and execution | Each decision keeps its weights, reasoning and confidence. Paper portfolios can trade automatically. Live portfolios wait until a person approves the exact list of trades. Paper trades wait for their market to open, and an accepted order is never reported as filled. | [Design principles](/guides/design-principles), [Approve trades](/features/portfolios#approve-trades) | ## Why a chat loop is not enough Coding agents run a task until it's done. Investing differs in four ways, and each one shaped a layer above. * **Time matters.** Every fact has a date. A backtest that reads data from after its own date gives results you can't trust, so the engine reads data as it stood at the time, the risk model is stored as dated snapshots, and a response says when an input, such as sector labels, reflects today instead. * **A portfolio is never done.** Prices move, news arrives and holdings drift. Monitors run again on a schedule, and strategies wake on a date or a market event they chose, rather than stop when one answer is written. * **A portfolio keeps no reasons.** Holdings don't say why they are there. Itoflow stores each decision with its weights, reasoning and confidence, and each chat with its code and files. * **Mistakes cost money.** Exact rules sit in code the agent can't change: the research contract, the overfitting checks, position limits, cash checks and human approval of live trades. Judgement goes to a second agent that reads the work. [Why agentic investing is hard](https://itoflow.ai/blog/why-agentic-investing-is-hard) sets out the problem in more depth. ## One engine, three ways in The app, your AI assistant and your own code all reach the same agents, engine and data, and see the same portfolios, monitors and strategies. * **Your AI assistant.** Claude, ChatGPT, Codex, Gemini, GitHub Copilot and Cursor connect to the Itoflow MCP server. It has three tools: search, execute and list workspaces. Your assistant finds what it needs with search and acts by writing a short script, rather than loading every tool definition up front. It signs in with OAuth and never sees a token. [Connect your assistant](/mcp/install). * **The Itoflow app.** Research, monitors and strategies in your browser at [app.itoflow.ai](https://app.itoflow.ai). * **Your code.** An HTTP API for portfolios, strategies, monitors, market data and factor risk. [Make your first request](/quickstart/http). ## Your code, your data, your models Itoflow works with what you already have. * **Your GitHub repositories.** Agents can check out your research code, run it, change it and open a draft pull request. The GitHub app asks only for code, pull requests and CI results, branch protection still applies, and text from a repository counts as untrusted input. [Connect GitHub](/features/integrations#github). * **Your own MCP servers.** Add any remote MCP server by its URL, and agents can call its tools in research, such as a broker's server that reads your positions. Tokens are stored encrypted, sent only to that server, and never reach the model or the sandbox. [Connect an MCP server](/features/integrations#remote-mcp-servers). * **Files on your machine.** With the worker skill, Itoflow plans an analysis and your local Codex or Claude Code session runs each step on your machine. Itoflow sees the results, not your files or credentials. [Work with your local agent](/mcp/usage#work-with-your-local-agent). * **Your own ChatGPT subscription.** Chat and monitors can run on it. A run gets only a short-lived access token. [Connect your ChatGPT subscription](/features/chat#connect-your-own-chatgpt-subscription). [How we connected customers' MCP servers and GitHub repos to our research agent](https://itoflow.ai/blog/how-we-connected-mcp-servers-and-github) explains the design: why a URL is enough, how dozens of tools stay out of the model's context, and why a write with an unknown outcome is never sent twice. Your code, data and research stay yours. Itoflow sells no signals and imposes no investment view. ## Next > [card] [The agent harness](/platform/agent-harness) > > The research agent, the research contract, independent review, and agents that run 24/7. > [card] [Quant engine and risk model](/platform/quant-engine) > > Data, backtests, portfolio construction and the factor risk model, with the evidence behind it. > [card] [Design principles](/guides/design-principles) > > The rules behind approvals, access, point-in-time data, retries and security. > [card] [Use cases](/use-cases/overview) > > Jobs you can start today, with prompts to paste into your assistant. # Quant engine and risk model Source: https://docs.itoflow.ai/platform/quant-engine What Itoflow's engine computes: point-in-time data for stocks, ETFs and crypto on 24 exchanges, signal tests, walk-forward and out-of-sample backtests with overfitting checks, portfolio construction, and a factor risk model with ETF look-through that also covers gold, Treasury and cash-like funds, published as dated snapshots. In a published test against realized risk, 107 of 116 portfolios fell inside the band MSCI uses for Barra models. The engine is Itoflow's own Python quant library and the data services that feed it. Agents call it from their sandbox, and Itoflow's own scheduled jobs call the same library, so an agent can do anything the system does. It is production code with its own tests, not a folder of scripts. ```mermaid theme={null} flowchart LR Data[Point-in-time data] --> Signals[Signal tests and backtests] Data --> Model[Factor risk model] Signals --> Build[Portfolio construction] Model --> Build Model --> Risk[Risk engine] Build --> Risk Risk --> Reports[Reports, monitors and strategies] ``` ## Data Prices, fundamentals, filings, news and exchange rates for stocks and ETFs on 24 exchanges in 22 markets, plus crypto. `GET /symbols/exchanges` lists the exchanges, and [Find a symbol](/guides/symbols) resolves a ticker, company name, broker symbol or ISIN. Four rules keep the data honest: * **One named source for each kind of data and market.** If that source fails, the request fails or the gap is reported. Itoflow never switches silently to another source. * **Currency comes from the data provider.** Itoflow never infers it from a ticker or exchange. * **Only what was known at the time.** Fund holdings count from the day the SEC accepted the filing. Company statements count from when they became public, such as the results announcement, and the history reports any statement it couldn't date that way. Historical datasets keep their retrieval times and source hashes, so you can check what a backtest saw. One known exception: for older dates, the risk model may use today's sector and country labels, and the response's `provenance` says so. * **Missing stays missing.** A missing price, volume or factor input stays empty and is reported. It is never filled with zero or a guess. Point-in-time history matters. In our factor-model study, holding today's S\&P MidCap 400 members back in time, equal-weight and rebalanced monthly, returned 14.3% a year, against 9.3% for the names actually in the index on each date: 177 of today's 400 names weren't yet in the index when the test began. For a historical index, the research agent applies dated listing, liquidity and size rules at each rebalance, and states how far its universe relies on hindsight. Your own data comes in through files in the app, your [GitHub repositories](/features/integrations#github), your own [MCP servers](/features/integrations#remote-mcp-servers), or the [local worker](/mcp/usage#work-with-your-local-agent), which runs steps on your machine. See [Market data](/features/market-data) for the endpoints. ## Signal tests and backtests * **Signal tests.** Information coefficients across the cross-section, chronological train and test splits, and multiple-testing control. * **Walk-forward and out-of-sample backtests,** with trading costs, turnover and position limits. * **Overfitting checks in code:** the probability of backtest overfitting, the deflated Sharpe ratio and false-discovery-rate control. The research contract can require them, and the system works out an out-of-sample choice again itself rather than trust the agent's claim. See [the research contract](/platform/agent-harness#the-research-contract). * **Stress tests,** such as the Covid crash, an inflation shock or a jump in rates. Stress scenarios on the risk model are overlays; they never change the base model. ## Portfolio construction * Mean-variance, minimum variance, risk parity and hierarchical risk parity. * Covariance shrinkage, and covariance from the factor model when a sample would be too short or noisy. * Trading costs, turnover limits and position limits. * Long and short books, with long, short, gross and net kept apart rather than summed into one figure. Long-short books, such as a 130/30, run on paper portfolios. * Volatility forecasts, including conditional volatility models. [Combining fundamental quality with quantitative optimization: GOOGL vs AAPL](https://itoflow.ai/blog/googl-wins-aapl-loses-integrated-analysis) shows one request that weighs two stocks for a diversified book on both fundamentals and their effect on the book's risk and return. ## Factor risk model Itoflow's factor risk model splits each holding's risk into what it shares with others and what is its own: ```text theme={null} Sigma = X F X' + D ``` `X` holds each stock's exposures to the factors, `F` is the factor covariance, and `D` is each stock's specific risk. * **Factors.** Market, country, industry and style factors such as size, value, momentum, quality and liquidity. Each style input is cleaned of outliers and standardized. * **Fitted daily.** Factor returns are fitted across stocks each day. Each stock uses its own exchange's calendar, so a holiday is never counted as a zero return. An exchange counts as shut on a day when under 40% of its stocks have a price that differs from their last one and under half of its active stocks traded (a day on which no price moved is shut whatever the volume; a small exchange is shut when under half of its active stocks have a price that traded). A shut day leaves out that exchange's prices, and the next return spans the gap. A stock counts toward its exchange from its first price until 21 weekdays after its last. The same happens to the placeholder prices a new listing carries before its first trade (a stock whose price never changes has none left). Every price counts on its own date, whatever its size: a large move is as likely real as wrong. A price that jumps or falls tenfold for up to three of the stock's own prices and then comes back is dropped once the later price shows it came back, and later fits leave it out; a fit already stored stays as it was. While such a jump is the latest price, nothing has shown yet whether it lasts, so the fit leaves it out until the next prices decide, and the stock's specific risk says which close it waits on. A move that lasts becomes the new level. The fit counts each company once, on its main listing, when it can tell the lines are one company: of two lines with one ISIN, one leads, and a depositary receipt carries no weight only when the data provider gives the same registry number for it and for another line of its company in the model. It never matches by name, so a receipt with no such number stays in the fit beside its company's share. A stock that traded on under 80% of its exchange's open days, one with a median daily turnover under $100,000 (dollars that traded as they traded, which a later dividend adjustment does not change), and one with a market cap under $100 million carry no weight in the fit. Each is still scored, and its warnings state the reason. A country or industry factor is not estimated on a day when stocks with under half of its weight traded: its return is zero that day, and the stocks that traded keep their own moves. * **Specific risk** for each stock, with a floor and shrinkage toward similar stocks. * **ETF look-through.** An equity ETF's exposures are the weighted sum of its holdings' exposures, read from the holdings on file at that date. Funds held inside a book, and the benchmark, are read through the same way. * **Beyond equities.** Gold, Treasury and cash-like funds are modeled from their own return history, with their covariance to the equity factors. That is as far as the model reaches beyond stocks today: futures, options and individual bonds aren't covered. * **Gaps are named.** A missing input is never set to zero. A risk run lists each name the model doesn't cover, with its weight and the reason. * **Published apart from the agents.** A daily build publishes dated snapshots. Agents and the API read published snapshots; they never refit the model. * **Point in time.** A past date reads the newest snapshot on or before it. Itoflow refuses a date or symbol the snapshot doesn't cover rather than fill the gap, and the response's `provenance` says when an input, such as sector labels, reflects today. A risk measure's answer lists from which date month-end and daily snapshots exist. ### How the model measures up [How our factor risk model measures up against institutional providers](https://itoflow.ai/blog/factor-risk-model-vs-institutional-providers), September 8, 2026, scored the model with the bias statistic and its 95% band as MSCI defines it, which is 0.82 to 1.18 for 59 month-ends. The test forecast risk at each month-end from September 2021 to July 2026 on a point-in-time S\&P MidCap 400 and scored it against the next 21 trading days. All 9 portfolio families had a mean bias inside the band, from 0.94 to 1.03, and so did 107 of the 116 single portfolios. The bias of specific-risk forecasts sat between 0.93 and 1.03 in every decile, over 23,069 stock-months. Against a plain sample covariance: | Test | Factor model | Sample covariance | | - | - | - | | Volatility of optimized portfolios | Within 4% of realized | 17% to 26% too low | | Tightest-tracking optimized book: tracking error forecast, then realized (medians) | 3.2%, then 3.0% | 2.0%, then 3.1% | | Months realized tracking error exceeded the forecast | 21 of 59 | 57 of 59 | | QLIKE loss on the cap-weighted index, lower is better | 0.24 | 0.29 over 252 days; 0.26 with decay weights | | The post states its limits: one universe and one period, a different yardstick and different data from MSCI's, and three named shortcuts: weights set by market capitalization, today's industry and country labels, and a covariance estimated on a wider universe. It also lists the estimation choices, including the adjustments we tested and dropped. [How we built a cross-asset factor risk model](https://itoflow.ai/blog/factor-risk-models-for-agentic-portfolios) explains the design. | ## The engine computes; the agent explains Every figure in a risk report or monitor report comes from the engine. The agent decides which figures matter, writes the findings and explains them. Before a monitor report goes out, its figures are checked against the engine's output, and a figure the engine can't produce shows as "not known". When the engine has evidence that a figure is wrong, the report drops it and anything built on it. ## Use the engine from your code | Endpoint | What you get | | - | - | | [Risk measure](/api-reference/risk-measure) | Factor risk for 1 to 10 books of up to 3,000 lines each, at one date or up to 60 dates, against a benchmark. Shorts and borrowing are allowed. It can split a change in risk into what your trades did and what the market and model did. | | [Risk runs](/api-reference/risk-runs) | One book's full report against a benchmark and up to 10 peer funds: exposures, risk by holding, attribution, factor profit and loss, scenarios and coverage. | | [Factor-risk covariance](/features/market-data#factor-risk-covariance) | A covariance matrix for up to 1,000 symbols as the model stood on a past date, for your own backtests. | | [Symbol analytics](/features/market-data#symbol-analytics) | Returns, volatility, beta, signals, fundamentals and valuation for up to 12 symbols, with a receipt of which inputs failed. | Use a risk run for today's full report on one book, and a risk measure for past dates, a range of dates, or several books side by side. Agents use the same engine in [chat research](/features/chat), [monitors](/features/monitors) and [strategies](/features/strategies). # Make your first API request Source: https://docs.itoflow.ai/quickstart/http Get an access token, then list supported exchanges with cURL, JavaScript or Python. > [!TIP] > > **You may not need the API.** To use Itoflow from Claude, Codex or another assistant, [connect Itoflow MCP](/mcp/install) instead: no tokens, no code, and your assistant finds the right operation for you. The API lives at `https://api.itoflow.ai`. You need an [Itoflow account](https://app.itoflow.ai) and cURL, Node.js 22 or later, or Python 3. **1. Get an access token** Run the sign-in script in [Authentication](/authentication#get-an-access-token). It prints a link; open it, approve the code, and the script stores the token for you: ```bash theme={null} export ITOFLOW_ACCESS_TOKEN="$(python3 get_token.py)" ``` **2. List supported exchanges** ```bash cURL theme={null} curl --fail-with-body --silent --show-error \ 'https://api.itoflow.ai/symbols/exchanges' \ --header "Authorization: Bearer $ITOFLOW_ACCESS_TOKEN" ``` ```javascript JavaScript theme={null} const token = process.env.ITOFLOW_ACCESS_TOKEN; if (!token) throw new Error('Set ITOFLOW_ACCESS_TOKEN first'); const response = await fetch('https://api.itoflow.ai/symbols/exchanges', { headers: { Authorization: `Bearer ${token}` }, }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); const { exchanges } = await response.json(); console.log(exchanges); ``` ```python Python theme={null} import json import os from urllib.request import Request, urlopen request = Request( "https://api.itoflow.ai/symbols/exchanges", headers={ "Authorization": f"Bearer {os.environ['ITOFLOW_ACCESS_TOKEN']}", # The API rejects Python's default User-Agent, so send a named one. "User-Agent": "itoflow-quickstart/1.0", }, ) with urlopen(request, timeout=30) as response: exchanges = json.load(response)["exchanges"] print(exchanges) ``` A `200` response contains an `exchanges` array. Each entry has a `code`, a `name` and the instrument `types` it lists. Shortened: ```json theme={null} { "exchanges": [ { "code": "US", "name": "United States", "types": ["stock", "etf"] }, { "code": "CC", "name": "Cryptocurrency", "types": ["crypto"] } ] } ``` Use these codes to build symbols such as `AAPL.US`. See [Find and resolve symbols](/guides/symbols). **3. Check which account you're using** ```bash theme={null} curl --fail-with-body --silent --show-error \ 'https://api.itoflow.ai/auth/user' \ --header "Authorization: Bearer $ITOFLOW_ACCESS_TOKEN" ``` The response contains your account's personal details, so keep it out of shared logs. ## If it fails * `401`: the token expired or is wrong. [Refresh it](/authentication#refresh-an-expired-token) or sign in again. * `429`: you hit a rate limit. Wait for the time in `Retry-After`, then try again. See [Troubleshooting](/troubleshooting) for other errors. ## Next steps > [card] [API conventions](/guides/api-conventions) > > Retries, pagination, units and status codes. > [card] [Portfolios](/features/portfolios) > > Read holdings, import a portfolio and approve trades. > [card] [Monitors](/features/monitors) > > Watch holdings or a fund and get scheduled reports. > [card] [Strategies](/features/strategies) > > Run a portfolio under a mandate you write. # SDKs and client libraries Source: https://docs.itoflow.ai/sdk/overview Itoflow has no official SDK. Use any HTTP client, or generate one from the OpenAPI file. Itoflow doesn't publish an official SDK. The API is plain HTTPS and JSON, so any HTTP client works: the [quickstart](/quickstart/http) shows cURL, JavaScript's built-in `fetch` and Python's standard library, and every endpoint page in the reference has examples in all three. To generate a typed client, point your generator at the [OpenAPI file](/openapi/itoflow-public.openapi.json). A generated client still needs an access token from the [sign-in flow](/authentication#get-an-access-token). To use Itoflow from an AI assistant instead of code, see [Itoflow MCP](/mcp/overview). # API troubleshooting Source: https://docs.itoflow.ai/troubleshooting Fix authentication, permission, input, rate-limit and browser errors from the HTTP API. For problems connecting an AI assistant, see [MCP troubleshooting](/mcp/troubleshooting). ## Status codes | Status | Usual cause | What to do | | - | - | - | | `400` | A missing or invalid field, such as a malformed symbol | Read the error body and fix the request. | | `401` | The token is missing, expired or not an Itoflow access token | [Refresh the token](/authentication#refresh-an-expired-token) or sign in again. | | `403` with `error code: 1010` | The request uses Python's default `User-Agent` (`Python-urllib`), which the API rejects | Set your own `User-Agent` header, such as `my-app/1.0`. | | `403` | Your account can't use this resource, your plan doesn't cover it, or the request's `Origin` header names a site the API doesn't accept | Check the account you signed in with and your plan or credits. If you call from a server, don't forward the browser's `Origin` header. | | `404` | The resource doesn't exist, or isn't yours | Check the ID and the account. | | `409` | The request conflicts with the current state: a newer version, a duplicate name, a pending deletion, a monitor moving to its new runtime, changed plan terms or a changed trade proposal | Read the error `code` and the current state. If a person approved the old state, show them the new one before you retry. | | `422` | Identifiers that disagree or aren't supported | Read the reason and the supported values it returns. | | `429` | Rate limited | Wait for `Retry-After` seconds, then retry. | | `5xx` | A temporary problem at Itoflow or a data provider | Retry reads a few times, waiting longer each time. Check the state before retrying a write. | ## Errors in the browser If your web page calls the API and the browser reports a network or CORS error, but the same request works from cURL, the browser blocked it. The API accepts browser requests only from Itoflow's own websites, so requests from your site's front end will fail. Call the API from your server instead and keep the token there. Your code must send an access token in the `Authorization` header. The Itoflow app's sign-in cookie isn't available to other sites, and these docs never send it. ## Feature-specific problems * **Chat:** a dropped connection doesn't stop a research turn. Check the turn's status before you send the message again. * **Strategies:** a `409` on an edit means someone saved a newer version. Reload it. After a `202` from a run, follow that run instead of starting another. * **Monitors:** check `report_scheduling` after you enable a schedule. Follow the `execution_id` you got back; an older completed report doesn't mean the new one finished. * **Billing:** a positive spending cap needs a paid plan. After a plan change, follow the payment status. * **Portfolios and brokers:** approval, sending to the broker, and the fill are separate steps. Check the trade's attempts. ## Asking for help Email [support@itoflow.ai](mailto:support@itoflow.ai), or see the [help center](https://itoflow.ai/help). Include the method and path, the status code, the time, and the error body. Remove the `Authorization` header, cookies and personal details first. See [API conventions](/guides/api-conventions) for retries and units. # Decide whether a name improves a book Source: https://docs.itoflow.ai/use-cases/add-a-name-to-a-book Ask Itoflow which of several stocks would do more for a portfolio. The research agent weighs each name's fundamentals beside its effect on the book's return, volatility, drawdown and Sharpe ratio, tested on a holdout period, and names the trade-offs. A stock can look good alone and do little for your book. Ask Itoflow to weigh each candidate's fundamentals beside what it does to the whole portfolio, in one request. **What you'll get:** a side-by-side of the candidates on growth, margins, valuation and quality, their effect on the book's risk and return, and the trade-offs between them. ## Try it > [tab] Ask your AI assistant > > With [Itoflow connected to your assistant](/mcp/install), paste this into your assistant: > > ```text theme={null} > Use Itoflow to decide which of GOOGL.US and AAPL.US would do more for a book > that is 70% SPY.US, if added as a 30% sleeve. Compare the two companies on > growth, margins, valuation and quality. Then measure what each does to the > book: return, volatility, worst drawdown, Sharpe ratio and correlation with > the S&P 500, using a shrinkage covariance and a holdout period. Name the > trade-offs rather than only a winner. Wait for the research to finish, then > summarize 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%20decide%20which%20of%20GOOGL.US%20and%20AAPL.US%20would%20do%20more%20for%20a%20book%20that%20is%2070%25%20SPY.US%2C%20if%20added%20as%20a%2030%25%20sleeve.%20Compare%20the%20two%20companies%20on%20growth%2C%20margins%2C%20valuation%20and%20quality.%20Then%20measure%20what%20each%20does%20to%20the%20book%3A%20return%2C%20volatility%2C%20worst%20drawdown%2C%20Sharpe%20ratio%20and%20correlation%20with%20the%20S%26P%20500%2C%20using%20a%20shrinkage%20covariance%20and%20a%20holdout%20period.%20Name%20the%20trade-offs%20rather%20than%20only%20a%20winner.%20Wait%20for%20the%20research%20to%20finish%2C%20then%20summarize%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%20decide%20which%20of%20GOOGL.US%20and%20AAPL.US%20would%20do%20more%20for%20a%20book%20that%20is%2070%25%20SPY.US%2C%20if%20added%20as%20a%2030%25%20sleeve.%20Compare%20the%20two%20companies%20on%20growth%2C%20margins%2C%20valuation%20and%20quality.%20Then%20measure%20what%20each%20does%20to%20the%20book%3A%20return%2C%20volatility%2C%20worst%20drawdown%2C%20Sharpe%20ratio%20and%20correlation%20with%20the%20S%26P%20500%2C%20using%20a%20shrinkage%20covariance%20and%20a%20holdout%20period.%20Name%20the%20trade-offs%20rather%20than%20only%20a%20winner.%20Wait%20for%20the%20research%20to%20finish%2C%20then%20summarize%20it.) > > > > Start this in ChatGPT with the Itoflow plugin. > > Using another client? Copy the prompt with the button on the code block. > > To test against your own book, replace the 70% SPY.US core with the name of one of your saved portfolios. > [tab] In the Itoflow app > > 1. Open [Chat](https://app.itoflow.ai/chat). > 2. Name the candidates and the book: a saved portfolio, or a mix such as 70% SPY. > 3. Ask for fundamentals and the effect on the book's risk and return, tested on a holdout period. ## What a result looks like We ran the prompt above on October 28, 2026. The agent fitted the covariance on three years to October 2024 and held out the two years after. Over the holdout, the GOOGL sleeve raised the book's return by 17.8 points over SPY alone, and AAPL by 4.6. The AAPL book was less volatile and led in the second year. Neither sleeve lowered the book's volatility or worst drawdown against SPY alone. The answer said so, and called its pick of GOOGL a conditional preference, not a forecast. An earlier run, published in [Combining fundamental quality with quantitative optimization: GOOGL vs AAPL](https://itoflow.ai/blog/googl-wins-aapl-loses-integrated-analysis) on July 9, 2026, ran a similar request with a 30% sleeve on a 70% S\&P 500 core. The S\&P 500 alone had a Sharpe ratio of 1.40. With a GOOGL sleeve it rose to 2.54, and with AAPL to 1.92. GOOGL also led on valuation (27.6 times earnings against 35.6) and margins (37.9% against 27.2%). The answer named the trade-off too: the AAPL book had the shallower worst drawdown, 9.1% against 12.4%. The post covers two candidates over a few years of daily data, with an index standing in for real holdings. It is not a stock call. ## How it's checked * **The figures come from code.** The agent writes the code that measures each book, and the system checks that each number in the answer matches what the code produced. See [the research contract](/platform/agent-harness#the-research-contract). * **A holdout period.** The comparison is tested on data the choice didn't use. * **A second agent reviews it.** The [independent reviewer](/platform/agent-harness#independent-review) reads the files, not a summary. ## Limits * The answer rests on past data and one covariance estimate. It is research, not investment advice. * Fundamentals come from filings, counted from the day the regulator accepted them. ## Next steps * [Measure a book's factor risk](/use-cases/measure-factor-risk) to see which factors a new name adds. * [Quant engine and risk model](/platform/quant-engine): the portfolio construction methods behind the answer. # Compare tax-loss harvesting rules Source: https://docs.itoflow.ai/use-cases/compare-tax-loss-harvesting Ask Itoflow to compare tax-loss harvesting rules on the same lots and inputs, so the gap between them reflects the rule. See each rule's after-tax result beside the tracking error it costs. A research study, not tax advice. Harvesting rules differ a lot in what they save and in how far they pull a book from its index. Ask Itoflow to run several rules on the same lots, prices and tax rates, so the gap between them comes from the rule and not the data. **What you'll get:** each rule's ending value after tax, the tax it saved, its trading costs and its tracking error against the index, with the code that produced them. ## Try it > [tab] Ask your AI assistant > > With [Itoflow connected to your assistant](/mcp/install), paste this into your assistant: > > ```text theme={null} > Use Itoflow to compare tax-loss harvesting rules for a newly invested > $10 million account that tracks the S&P MidCap 400, from the end of November > 2025 to today, reviewed monthly. Compare no harvesting; selling any lot down > 5%; a loss threshold scaled to each stock's volatility; and sales chosen by > an optimizer. Hold every rule to the same 1% active risk budget. For each > rule, try both cash and IJH.US as the replacement. Use a 40.8% short-term > and a 23.8% long-term tax rate, a 30-day wash-sale window and a 0.10% > trading cost. Assume no outside gains: losses offset gains inside the > account and unused losses carry forward. Report each rule's ending value > after tax, the tax saved and the realized tracking error against the index, > and say what drives the differences. Wait for the research to finish. > ``` > > > [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%20compare%20tax-loss%20harvesting%20rules%20for%20a%20newly%20invested%20%2410%20million%20account%20that%20tracks%20the%20S%26P%20MidCap%20400%2C%20from%20the%20end%20of%20November%202025%20to%20today%2C%20reviewed%20monthly.%20Compare%20no%20harvesting%3B%20selling%20any%20lot%20down%205%25%3B%20a%20loss%20threshold%20scaled%20to%20each%20stock's%20volatility%3B%20and%20sales%20chosen%20by%20an%20optimizer.%20Hold%20every%20rule%20to%20the%20same%201%25%20active%20risk%20budget.%20For%20each%20rule%2C%20try%20both%20cash%20and%20IJH.US%20as%20the%20replacement.%20Use%20a%2040.8%25%20short-term%20and%20a%2023.8%25%20long-term%20tax%20rate%2C%20a%2030-day%20wash-sale%20window%20and%20a%200.10%25%20trading%20cost.%20Assume%20no%20outside%20gains%3A%20losses%20offset%20gains%20inside%20the%20account%20and%20unused%20losses%20carry%20forward.%20Report%20each%20rule's%20ending%20value%20after%20tax%2C%20the%20tax%20saved%20and%20the%20realized%20tracking%20error%20against%20the%20index%2C%20and%20say%20what%20drives%20the%20differences.%20Wait%20for%20the%20research%20to%20finish.) > > > > 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%20compare%20tax-loss%20harvesting%20rules%20for%20a%20newly%20invested%20%2410%20million%20account%20that%20tracks%20the%20S%26P%20MidCap%20400%2C%20from%20the%20end%20of%20November%202025%20to%20today%2C%20reviewed%20monthly.%20Compare%20no%20harvesting%3B%20selling%20any%20lot%20down%205%25%3B%20a%20loss%20threshold%20scaled%20to%20each%20stock's%20volatility%3B%20and%20sales%20chosen%20by%20an%20optimizer.%20Hold%20every%20rule%20to%20the%20same%201%25%20active%20risk%20budget.%20For%20each%20rule%2C%20try%20both%20cash%20and%20IJH.US%20as%20the%20replacement.%20Use%20a%2040.8%25%20short-term%20and%20a%2023.8%25%20long-term%20tax%20rate%2C%20a%2030-day%20wash-sale%20window%20and%20a%200.10%25%20trading%20cost.%20Assume%20no%20outside%20gains%3A%20losses%20offset%20gains%20inside%20the%20account%20and%20unused%20losses%20carry%20forward.%20Report%20each%20rule's%20ending%20value%20after%20tax%2C%20the%20tax%20saved%20and%20the%20realized%20tracking%20error%20against%20the%20index%2C%20and%20say%20what%20drives%20the%20differences.%20Wait%20for%20the%20research%20to%20finish.) > > > > Start this in ChatGPT with the Itoflow plugin. > > Using another client? Copy the prompt with the button on the code block. > > The prompt settles the choices the agent would otherwise ask about: how the account starts, which gains the losses can offset, and which rules the risk budget limits. To use your own lots, attach them as a file in the Itoflow app and name the file in the prompt. > [tab] In the Itoflow app > > 1. Open [Chat](https://app.itoflow.ai/chat). > 2. Attach your lots as a file, or describe a model account as in the prompt on the other tab. > 3. Name the rules to compare, the tax rates, the wash-sale window, trading costs and the replacement. ## What a result looks like [Finding tax alpha with Itoflow](https://itoflow.ai/blog/how-to-measure-tax-alpha), September 29, 2026, compared eight harvesting approaches and a no-harvest baseline on one modeled $10M account that tracked the S&P MidCap 400 from September 2021 to September 2026. Its assumptions differ from the prompt above: $100,000 of short-term and \$50,000 of long-term gains a year outside the account, and a 15% one-way turnover limit. * Optimized sales with IJH as the replacement ended \$1.08M (7.3%) ahead of no harvesting: 4.85 points from lower modeled tax and 2.49 points from returns after costs. * That gain came with more tracking error against the index: 1.56% a year, against 1.19% with no harvesting. * In each threshold rule, replacing sold lots with the ETF beat holding the proceeds in cash. The study measures fixed rules, not an agent's choices. It uses fills at the close, one period and simplified corporate events. It is not tax advice. We ran the prompt above on October 28, 2026, and it didn't finish. The agent rebuilt the index's holdings at the start, then stopped: one change of security in the index had no verified price and identity history. It reported no result rather than drop that security, use today's members or shorten the period, and it saved the setup for a rerun. ## How it's checked * **Same inputs for every rule.** The [research contract](/platform/agent-harness#the-research-contract) fixes the lots, prices, rates and costs before the comparison runs. * **You get the code.** The agent writes the harvesting and wash-sale logic in Python in its sandbox, so you can read the rules it applied and run them again. * **A second agent reviews it.** The [independent reviewer](/platform/agent-harness#independent-review) reads the files before the answer reaches you. ## Limits * A replay needs the index's dated holdings and full price and identity history for every security in them. Itoflow rebuilds past holdings from a fund that tracks the index, and for several funds those start in late 2025. Where history is missing, the agent stops and says so. * Results are modeled. Real fills, tax lots and corporate events will differ. * Itoflow doesn't give tax advice or file anything. Check rules for your own account with a tax adviser. * A strategy can act on a harvesting rule on a paper portfolio. On a live portfolio, a person approves each list of trades. ## Next steps * [Run a strategy under a mandate](/use-cases/run-a-strategy) to apply a rule on a paper portfolio. * [Measure a book's factor risk](/use-cases/measure-factor-risk) to see what a replacement does to your exposures. # Get a daily news brief Source: https://docs.itoflow.ai/use-cases/daily-news-brief Have a research monitor summarize the news and filings that affect your holdings every weekday morning, and read the rated news feed from code. A research monitor can read the news and SEC filings for a list of companies every morning and tell you what matters. Itoflow rates each story for each company it could affect, from minor to material, so the brief leads with what could move your holdings. **What you'll get:** a short report every weekday before the market opens, plus a feed of rated news you can read from your own code. ```mermaid theme={null} flowchart LR News[News and SEC filings] --> Rated[Rated for each company] Rated --> Monitor[Your research monitor] Monitor --> Brief[Weekday morning brief] Rated --> Feed[News feed API] ``` ## Before you start * An Itoflow account. The free plan is enough. * Your companies as Itoflow symbols. See [Find and resolve symbols](/guides/symbols). ## Quick start > [tab] Ask your AI assistant > > With [Itoflow connected to Codex or Claude](/mcp/install), paste this into your assistant: > > ```text theme={null} > Use Itoflow to create a research monitor named "Morning brief" for NVDA.US, > ASML.AS and TSM.US. Mandate: each morning, summarize the news and filings from > the last 24 hours that could change the value of these companies, lead with > anything rated material, say what happened and why it matters, skip routine > items, and keep it under 300 words. Schedule it on weekdays at 07:30 > Europe/London. Show me the monitor before creating it, then create it, enable > it, run one report now, and summarize what it found. > ``` > > > [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%20named%20%22Morning%20brief%22%20for%20NVDA.US%2C%20ASML.AS%20and%20TSM.US.%20Mandate%3A%20each%20morning%2C%20summarize%20the%20news%20and%20filings%20from%20the%20last%2024%20hours%20that%20could%20change%20the%20value%20of%20these%20companies%2C%20lead%20with%20anything%20rated%20material%2C%20say%20what%20happened%20and%20why%20it%20matters%2C%20skip%20routine%20items%2C%20and%20keep%20it%20under%20300%20words.%20Schedule%20it%20on%20weekdays%20at%2007%3A30%20Europe%2FLondon.%20Show%20me%20the%20monitor%20before%20creating%20it%2C%20then%20create%20it%2C%20enable%20it%2C%20run%20one%20report%20now%2C%20and%20summarize%20what%20it%20found.) > > > > 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%20named%20%22Morning%20brief%22%20for%20NVDA.US%2C%20ASML.AS%20and%20TSM.US.%20Mandate%3A%20each%20morning%2C%20summarize%20the%20news%20and%20filings%20from%20the%20last%2024%20hours%20that%20could%20change%20the%20value%20of%20these%20companies%2C%20lead%20with%20anything%20rated%20material%2C%20say%20what%20happened%20and%20why%20it%20matters%2C%20skip%20routine%20items%2C%20and%20keep%20it%20under%20300%20words.%20Schedule%20it%20on%20weekdays%20at%2007%3A30%20Europe%2FLondon.%20Show%20me%20the%20monitor%20before%20creating%20it%2C%20then%20create%20it%2C%20enable%20it%2C%20run%20one%20report%20now%2C%20and%20summarize%20what%20it%20found.) > > > > Start this in ChatGPT with the Itoflow plugin. > > Using another client? Copy the prompt with the button on the code block. > [tab] In the Itoflow app > > 1. Open [Monitors](https://app.itoflow.ai/watchlists) and select **New monitor → Research**. > 2. Add your symbols, such as `NVDA.US`, `ASML.AS` and `TSM.US`. > 3. Write the mandate: what to cover each morning, such as material news and filings from the last 24 hours, in under 300 words. > 4. Set a weekday schedule, such as 07:30 in your time zone, and save. > 5. On the monitor's page, turn on **Agent reports** so the schedule runs. > 6. To see a brief straight away, select **Run report**. It appears on the monitor's page when it finishes. > [tab] With the API > > You need an [access token](/authentication#get-an-access-token) in `ITOFLOW_ACCESS_TOKEN`. > > **1. Create the monitor** > > ```bash theme={null} > curl --fail-with-body --silent --show-error \ > 'https://api.itoflow.ai/watchlists' \ > --header "Authorization: Bearer $ITOFLOW_ACCESS_TOKEN" \ > --header 'Content-Type: application/json' \ > --data '{ > "name": "Morning brief", > "mandate": "Each morning, summarize the news and filings from the last 24 hours that could change the value of these companies. Lead with anything rated material, say what happened and why it matters, and skip routine items. Keep it under 300 words.", > "symbols": ["NVDA.US", "ASML.AS", "TSM.US"], > "recurrence": { "kind": "weekdays", "local_time": "07:30", "timezone": "Europe/London" } > }' > ``` > > The response contains the monitor's `id`. It starts paused. > > **2. Enable it** > > `POST /watchlists/{id}/control` with `{"action": "enable"}`. Check that the response doesn't say `report_scheduling: "unavailable"`; if it does, try again. > > **3. Run a first brief** > > To check it works without waiting for the morning, `POST /watchlists/{id}/reports/run`. `GET /watchlists/{id}/active-execution` shows the run in progress; when it finishes, `GET /watchlists/{id}/reports/latest` returns the brief. > > **4. Read the brief and the news feed** > > Each morning, `GET /watchlists/{id}/reports/latest` returns the newest brief. For the rated stories behind it, ask for the latest news, then read the news feed: > > ```bash theme={null} > curl --fail-with-body --silent --show-error --request POST \ > 'https://api.itoflow.ai/watchlists/MONITOR_ID/news/fetch' \ > --header "Authorization: Bearer $ITOFLOW_ACCESS_TOKEN" > > curl --fail-with-body --silent --show-error \ > 'https://api.itoflow.ai/watchlists/MONITOR_ID/news?limit=20' \ > --header "Authorization: Bearer $ITOFLOW_ACCESS_TOKEN" > ``` > > Replace `MONITOR_ID` with the monitor's `id`. The fetch returns `202` at once, and news is judged in the background, usually within a few minutes. Until you fetch, a new monitor's feed stays empty. While `feed.coverage.current` is below `feed.coverage.subjects`, judging is still running: read the feed again every few seconds until they match. See [Fetch, then poll](/features/monitors#fetch-then-poll). > > To fetch only new stories later, pass the last response's `feed.judged_through` as `since`, with two safeguards: > > * If a response returns exactly `limit` items, some stories didn't fit. Read the feed again without `since` and with a higher `limit`, up to 200, before you move your watermark on. > * If `feed.judged_through` is `null`, nothing matched. Keep your previous watermark. > > See [News feed](/features/monitors#news-feed) for every field. ## Limits * Up to 100 symbols per monitor. * The news feed covers the last 24 hours and returns one page of up to 200 items. * Items rated notable or above are kept for 90 days, others for 14. * News is judged for a monitor when it fetches, paused or not. ## Next steps * [Search stored news](/features/market-data#search-stored-news) across any symbols, up to 90 days back. * [Monitor a portfolio](/use-cases/portfolio-monitoring): get a weighted news feed for a whole portfolio's holdings. # Analyze your Interactive Brokers portfolio Source: https://docs.itoflow.ai/use-cases/interactive-brokers-risk Connect Interactive Brokers' MCP server to Itoflow, then ask Itoflow for risk, factor and concentration analysis of your real positions. Interactive Brokers (IBKR) runs an official MCP server that lets an AI assistant read your account. Connect it to Itoflow, and Itoflow can pull your positions and analyze them with its factor risk model. **What you'll get:** a dashboard in Itoflow Chat with your exposures by holding, sector, country and currency, factor exposures, the biggest contributors to risk, and anything that breaks the limits you set. ```mermaid theme={null} flowchart LR IBKR[IBKR account] -->|MCP, read access| Chat[Itoflow Chat] Chat --> Engine[Factor risk model] Engine --> Dashboard[Risk dashboard] ``` ## Before you start * An Itoflow account with MCP connections enabled. Check under **Integrations → MCP servers** (in the sidebar, or under **More** on mobile) in the [app](https://app.itoflow.ai/integrations#connections). * An Interactive Brokers account. IBKR doesn't offer its AI integration in India or Japan. ## Quick start > [tab] Ask your AI assistant > > With [Itoflow connected to Codex or Claude](/mcp/install), paste this into your assistant: > > ```text theme={null} > Use Itoflow for this. First check my Itoflow MCP server connections. If > Interactive Brokers isn't connected, add https://api.ibkr.com/v1/api/mcp-public > as a connection named "Interactive Brokers", connect it, and give me the sign-in > link; wait until I confirm I've signed in and the connection is ready. Then > start an Itoflow research turn that uses that connection to read my positions > and cash, shows my long, short, gross and net exposure and my weights by > holding, sector, country and currency, estimates my factor exposures and > portfolio volatility with Itoflow's factor risk model, lists the five biggest > contributors to risk, and flags any position above 10% of net asset value, > long or short. Wait for it to finish and summarize the result with the date of > the positions used. > ``` > > > [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%20for%20this.%20First%20check%20my%20Itoflow%20MCP%20server%20connections.%20If%20Interactive%20Brokers%20isn't%20connected%2C%20add%20https%3A%2F%2Fapi.ibkr.com%2Fv1%2Fapi%2Fmcp-public%20as%20a%20connection%20named%20%22Interactive%20Brokers%22%2C%20connect%20it%2C%20and%20give%20me%20the%20sign-in%20link%3B%20wait%20until%20I%20confirm%20I've%20signed%20in%20and%20the%20connection%20is%20ready.%20Then%20start%20an%20Itoflow%20research%20turn%20that%20uses%20that%20connection%20to%20read%20my%20positions%20and%20cash%2C%20shows%20my%20long%2C%20short%2C%20gross%20and%20net%20exposure%20and%20my%20weights%20by%20holding%2C%20sector%2C%20country%20and%20currency%2C%20estimates%20my%20factor%20exposures%20and%20portfolio%20volatility%20with%20Itoflow's%20factor%20risk%20model%2C%20lists%20the%20five%20biggest%20contributors%20to%20risk%2C%20and%20flags%20any%20position%20above%2010%25%20of%20net%20asset%20value%2C%20long%20or%20short.%20Wait%20for%20it%20to%20finish%20and%20summarize%20the%20result%20with%20the%20date%20of%20the%20positions%20used.) > > > > 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%20for%20this.%20First%20check%20my%20Itoflow%20MCP%20server%20connections.%20If%20Interactive%20Brokers%20isn't%20connected%2C%20add%20https%3A%2F%2Fapi.ibkr.com%2Fv1%2Fapi%2Fmcp-public%20as%20a%20connection%20named%20%22Interactive%20Brokers%22%2C%20connect%20it%2C%20and%20give%20me%20the%20sign-in%20link%3B%20wait%20until%20I%20confirm%20I've%20signed%20in%20and%20the%20connection%20is%20ready.%20Then%20start%20an%20Itoflow%20research%20turn%20that%20uses%20that%20connection%20to%20read%20my%20positions%20and%20cash%2C%20shows%20my%20long%2C%20short%2C%20gross%20and%20net%20exposure%20and%20my%20weights%20by%20holding%2C%20sector%2C%20country%20and%20currency%2C%20estimates%20my%20factor%20exposures%20and%20portfolio%20volatility%20with%20Itoflow's%20factor%20risk%20model%2C%20lists%20the%20five%20biggest%20contributors%20to%20risk%2C%20and%20flags%20any%20position%20above%2010%25%20of%20net%20asset%20value%2C%20long%20or%20short.%20Wait%20for%20it%20to%20finish%20and%20summarize%20the%20result%20with%20the%20date%20of%20the%20positions%20used.) > > > > Start this in ChatGPT with the Itoflow plugin. > > Using another client? Copy the prompt with the button on the code block. > [tab] In the Itoflow app > > 1. Open [MCP servers](https://app.itoflow.ai/integrations#connections) and select **Add MCP server**. > 2. Enter `https://api.ibkr.com/v1/api/mcp-public`, select **Add server**, then select **Connect** on the new row. > 3. Sign in to Interactive Brokers when asked and approve access. Itoflow never sees your IBKR password. When the connection shows **Ready**, its tools are available in all your chats. > 4. Open [Chat](https://app.itoflow.ai/chat) and ask for a risk analysis of your Interactive Brokers positions: long, short, gross and net exposure, weights by holding, sector, country and currency, factor exposures, the biggest contributors to risk, and any position above 10% of net asset value, long or short. ## Check it worked The dashboard should list the same positions you see in IBKR, with the date Itoflow read them. It also states its method and any data it couldn't get. If Itoflow says it can't read your positions or find the IBKR tools, open [MCP servers](https://app.itoflow.ai/integrations#connections). IBKR sign-ins expire; when the connection shows **Sign-in expired**, select **Reconnect**, sign in to Interactive Brokers again, then ask again. ## Ideas for follow-up questions Ask these in the same conversation with your assistant, or in Chat. * "Which of my holdings move most with interest rates, and how big is that exposure?" * "How would my portfolio have done in the 2022 sell-off, based on today's weights?" * "Show my currency exposure and the effect of a 10% fall in the US dollar." * "Which positions add the most risk for the return they've delivered?" ## Limits * The connection works in Chat research turns, whether you start them in the app or from your assistant. Scheduled monitors and strategies can't use it. * Itoflow reads your positions when you ask. They don't sync to Itoflow by themselves. * Itoflow doesn't place orders at Interactive Brokers. IBKR's server can draft trade instructions, but they never become orders until you review and submit them in an IBKR platform. * Analysis isn't investment advice. Check the figures before you act on them. ## Next steps * [Connect GitHub and MCP servers](/features/integrations): manage the connection, and what to do if it fails. * [Chat](/features/chat): how research turns, files and models work. * [Interactive Brokers: AI integrations](https://www.interactivebrokers.com/en/trading/ai-integrations.php): IBKR's own guide to its MCP server. # Measure a book's factor risk Source: https://docs.itoflow.ai/use-cases/measure-factor-risk Measure a portfolio's factor risk against a benchmark with Itoflow's factor risk model: volatility, tracking error, beta, factor exposures and the names that drive risk, at one date or month by month, looking through ETFs to their holdings and naming every gap. Itoflow's [factor risk model](/platform/quant-engine#factor-risk-model) splits a book's risk into market, country, industry and style factors and each name's own risk. It looks through ETFs to their holdings and reads the model as it stood on each past date, so you can see how a book's risk changed over a year and why. **What you'll get:** for each date, the book's volatility, tracking error and beta against the benchmark, how much of its risk comes from factors and how much from single names, its factor exposures, the names that drive the most risk, and what the model couldn't cover. When a fund holds derivatives, their value weights remain named gaps in the equity factor model. Coverage counts gains and losses by size: a +1% contract value and a −1% contract value leave 2% unmodelled, with 0% net value shown separately. A negative contract value is a loss; it does not establish a short exposure. Accounting balances, such as pending income, carry their stated value with a known zero return and do not count as unpriced holdings. For provider fund books, the rounding bound is the number of rows times half the finest stated weight unit in the book. A single finer row narrows the bound for all rows. The bound has a floor of one billionth and no cap: a book stated only to 0.1% can treat a 0.1% leftover as rounding. Owner and filing books keep the one-billionth bound. ```mermaid theme={null} flowchart LR Book[Your book or a list of weights] --> Model[Factor risk model at each date] Benchmark[Benchmark holdings] --> Model Model --> Answer[Risk, exposures and gaps by date] ``` ## Before you start * An Itoflow account. Risk measures need no extra account flag. * A book: one of your saved portfolios, or a list of up to 3,000 symbols and weights. ## Quick start > [tab] Ask your AI assistant > > With [Itoflow connected to your assistant](/mcp/install), paste this into your assistant: > > ```text theme={null} > Use Itoflow to measure the factor risk of a book that holds 60% QQQ.US, > 30% IWM.US and 10% cash, against SPY.US, at each month-end from November 2025 > to September 2026. For each date, give total volatility, tracking error, > beta, the share of risk from factors and from single names, the five largest > factor exposures, the five names that drive the most risk, and anything the > model left out. Then tell me in which month the risk changed most, and why. > Wait for the measure to finish before you answer. > ``` > > > [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%20measure%20the%20factor%20risk%20of%20a%20book%20that%20holds%2060%25%20QQQ.US%2C%2030%25%20IWM.US%20and%2010%25%20cash%2C%20against%20SPY.US%2C%20at%20each%20month-end%20from%20November%202025%20to%20September%202026.%20For%20each%20date%2C%20give%20total%20volatility%2C%20tracking%20error%2C%20beta%2C%20the%20share%20of%20risk%20from%20factors%20and%20from%20single%20names%2C%20the%20five%20largest%20factor%20exposures%2C%20the%20five%20names%20that%20drive%20the%20most%20risk%2C%20and%20anything%20the%20model%20left%20out.%20Then%20tell%20me%20in%20which%20month%20the%20risk%20changed%20most%2C%20and%20why.%20Wait%20for%20the%20measure%20to%20finish%20before%20you%20answer.) > > > > 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%20measure%20the%20factor%20risk%20of%20a%20book%20that%20holds%2060%25%20QQQ.US%2C%2030%25%20IWM.US%20and%2010%25%20cash%2C%20against%20SPY.US%2C%20at%20each%20month-end%20from%20November%202025%20to%20September%202026.%20For%20each%20date%2C%20give%20total%20volatility%2C%20tracking%20error%2C%20beta%2C%20the%20share%20of%20risk%20from%20factors%20and%20from%20single%20names%2C%20the%20five%20largest%20factor%20exposures%2C%20the%20five%20names%20that%20drive%20the%20most%20risk%2C%20and%20anything%20the%20model%20left%20out.%20Then%20tell%20me%20in%20which%20month%20the%20risk%20changed%20most%2C%20and%20why.%20Wait%20for%20the%20measure%20to%20finish%20before%20you%20answer.) > > > > Start this in ChatGPT with the Itoflow plugin. > > Using another client? Copy the prompt with the button on the code block. > > To measure your own book, replace the weights with the name of one of your saved portfolios. > [tab] In the Itoflow app > > 1. Open [Chat](https://app.itoflow.ai/chat). > 2. Name the book, such as one of your saved portfolios, the benchmark, and the dates. > 3. Ask for volatility, tracking error, beta, factor exposures and the names that drive risk. The answer shows the engine's figures with the agent's notes. > > To get the same figures on a schedule, [monitor the portfolio](/use-cases/portfolio-monitoring). > [tab] With the API > > You need an [access token](/authentication#get-an-access-token) in `ITOFLOW_ACCESS_TOKEN`. > > **1. Start the measure** > > ```bash theme={null} > curl --fail-with-body --silent --show-error \ > 'https://api.itoflow.ai/risk/measure' \ > --header "Authorization: Bearer $ITOFLOW_ACCESS_TOKEN" \ > --header 'Content-Type: application/json' \ > --data '{ > "request_key": "7d2e4b18-5c3a-4f6e-9a21-0b8c7e5d3f42", > "request": { > "model": { "range": { "from": "2025-11-30", "to": "2026-09-30" } }, > "benchmark": "SPY.US", > "top_names": 5, > "books": [ > { "label": "growth tilt", "holdings": [ > { "symbol": "QQQ.US", "weight": 0.6 }, > { "symbol": "IWM.US", "weight": 0.3 }, > { "symbol": "CASH", "weight": 0.1 } > ] } > ] > } > }' > ``` > > Use a new UUID as `request_key` for each measure. The response is `202` with a `measure_id`. To measure a saved portfolio, send `{ "label": "my book", "portfolio": { "portfolio_id": "PORTFOLIO_ID" } }` as the book, with your portfolio's ID. > > **2. Read it until it ends** > > ```bash theme={null} > curl --fail-with-body --silent --show-error \ > 'https://api.itoflow.ai/risk/measure/MEASURE_ID' \ > --header "Authorization: Bearer $ITOFLOW_ACCESS_TOKEN" > ``` > > Replace `MEASURE_ID` with the `measure_id`. While `status` is `running`, read again every few seconds; `progress` counts the dates done. Eleven month-ends take a few minutes. A failed measure returns `status: "failed"` with a `failure_code` and a `reason`. > > **3. Read the answer** > > An `ok` answer has one entry in `dates` for each month-end, with its `as_of` date. For each date, `books[0]` holds: > > | Field | What it tells you | > | - | - | > | `risk.total_volatility` | Forecast annual volatility, as a decimal: 0.21 is 21%. | > | `risk.factor_share`, `risk.specific_share` | The percent of the book's variance from factors and from single names. They add to 100. | > | `active.tracking_error`, `active.beta` | Against the benchmark. | > | `risk.exposures` | Exposure to each factor, in the order of the answer's `factors` list. | > | `top_names` | The names with the largest share of the book's risk. | > | `coverage` | The share of the book the model covers, and each line it left out, with a reason. | > > A null figure was not computed; it never means zero. A date the model has no publication for comes back as `missing`, with the nearest model dates on each side. > > To split a change in a saved portfolio's risk into what your trades did and what the market did, measure it twice in one request. See [What moved risk](/api-reference/risk-measure#what-moved-risk). ## What a result looks like We ran the measure above on October 28, 2026. From November 2025 to September 2026: * Forecast volatility ran from 16% to 22%, highest at the end of December 2025. * Tracking error against SPY ran from 4.5% to 5.1%, and beta from 0.89 to 0.94. * Factors explained 89% to 94% of the book's variance. * Looking through the two funds, the model covered 98% to 99% of the book. Each month it left out 49 to 108 small lines and listed up to 100 of them, each with a reason, such as fund cash with no stated currency. Figures change as the model publishes new dates. ## How it's checked * **The model is published, not fitted on demand.** A daily build publishes dated snapshots, and each date reads the newest one on or before it. Agents and the API never refit it. * **Gaps are named.** A name the model doesn't cover stays out at its weight, with its reason. It is never filled with a guess. * **The model is scored against what happened.** It was tested with the bias statistic and the 95% band MSCI defines for it, which is 0.82 to 1.18 over 59 month-ends. On the S\&P MidCap 400 from September 2021 to July 2026, 107 of 116 test portfolios fell inside it. The volatility of optimized portfolios came within 4% of what followed, where a plain sample covariance was 17% to 26% too low. See [How the model measures up](/platform/quant-engine#how-the-model-measures-up). ## Limits * 1 to 10 books per measure, up to 3,000 lines each, and up to 60 dates. * A measure reads the names the model already covers. A [risk run](/api-reference/risk-runs) on the book adds names the model can score. * Bonds, futures and options held directly stay outside the model and are listed with their reason. * Looking through a fund needs its holdings dated on or before each date. Before the first holdings Itoflow has for a fund, the fund is listed as not covered. * Three risk runs or measures can run at once. A finished answer stays for 24 hours. ## Next steps * [Risk measure](/api-reference/risk-measure): every field and error. * [Risk runs](/api-reference/risk-runs): today's full report on one book, with attribution, scenarios and peer funds. * [Monitor a portfolio](/use-cases/portfolio-monitoring): the same figures on a schedule, with a written report. # Use cases Source: https://docs.itoflow.ai/use-cases/overview Jobs you can do with Itoflow today, each with a prompt to paste into your AI assistant: test a signal, build and stress-test a strategy, measure a book's factor risk, monitor a portfolio, run a strategy under a mandate, compare tax-loss harvesting rules, and research with your own code and tools. Each guide walks through one job, with a prompt you can paste into your AI assistant over [Itoflow MCP](/mcp/install). Short guides show one research request and a published result for the same job. Longer guides add the app and the API. Research requests share one set of checks: the agent fixes its method before it starts, the engine computes the figures, and a second agent reviews the plan and the answer. Every live trade waits for a person to approve it. See [the agent harness](/platform/agent-harness). ## Research > [card] [Test a signal or dataset](/use-cases/test-a-signal) > > Information coefficients, an out-of-sample split and overfitting checks, or a plain "no edge found". > [card] [Build and stress-test a strategy idea](/use-cases/stress-test-a-strategy-idea) > > Compare designs walk-forward with costs, test them on a crash, and draft the winner as a paused paper strategy. > [card] [Decide whether a name improves a book](/use-cases/add-a-name-to-a-book) > > A candidate's fundamentals beside its effect on the whole book's risk and return. > [card] [Compare tax-loss harvesting rules](/use-cases/compare-tax-loss-harvesting) > > Each rule's after-tax result and the tracking error it costs, on the same lots. ## Risk > [card] [Measure a book's factor risk](/use-cases/measure-factor-risk) > > Volatility, tracking error, beta and factor exposures, month by month, looking through ETFs. > [card] [Analyze your Interactive Brokers portfolio](/use-cases/interactive-brokers-risk) > > Read your IBKR positions through its MCP server and measure them with Itoflow's risk model. > [card] [Monitor a portfolio](/use-cases/portfolio-monitoring) > > Scheduled reports against a benchmark and peer funds, starting from the risk engine's figures. ## Run portfolios > [card] [Run a strategy under a mandate](/use-cases/run-a-strategy) > > An agent runs a paper portfolio on its own schedule and records why it made each decision. > [card] [Get a daily news brief](/use-cases/daily-news-brief) > > News and filings rated for each holding, summarized every weekday morning. ## Build on Itoflow > [card] [Research with your own code and tools](/use-cases/research-with-your-code) > > Run your GitHub code on Itoflow's data, open pull requests, and call your own MCP servers. > [card] [Make your first API request](/quickstart/http) > > Portfolios, strategies, monitors, market data and factor risk over HTTP. Results quoted in these guides come from published runs, each with its conditions and date. Have a job you'd like covered? Email [support@itoflow.ai](mailto:support@itoflow.ai). # Monitor a portfolio Source: https://docs.itoflow.ai/use-cases/portfolio-monitoring Set up a monitor that checks your portfolio against a benchmark, peer funds and your tracking-error, sector and single-name limits, and writes a report on a schedule. A portfolio monitor watches your portfolio the way an oversight committee would: what it holds, how it differs from its benchmark and peers, how easily it could be sold down, and whether it stays inside the limits you set. Itoflow's risk engine computes the figures; the agent explains what changed and why. **What you'll get:** a scheduled report on the portfolio, with numbered findings, its tracking error and active weights against the benchmark, comparisons with peers, and liquidity at different portfolio sizes. Use any portfolio you keep in Itoflow: one you imported, a paper portfolio, or one connected to your broker. This guide compares it with the S\&P 500 and a minimum-volatility peer fund. Swap in the benchmark, peers and limits that fit your portfolio. ```mermaid theme={null} flowchart LR Portfolio[Your portfolio] --> Monitor[Fund-oversight monitor] Monitor --> Engine[Risk engine figures] Engine --> Report[Scheduled report] ``` ## Before you start * An Itoflow account. * A portfolio in Itoflow that no strategy runs. If you don't have one yet, [import your holdings](/features/portfolios#import-holdings) or [connect a broker](/features/brokers). The assistant and the app can also help you build one along the way. ## Quick start > [tab] Ask your AI assistant > > With [Itoflow connected to Codex or Claude](/mcp/install), paste this into your assistant: > > ```text theme={null} > Use Itoflow to set up oversight of one of my portfolios. List my portfolios and > ask me which one to monitor. If I don't have one yet, help me import my > holdings and show me the full import draft before saving it. Then propose a > fund-oversight monitor on that portfolio: benchmark S&P 500 (index GSPC.INDX, > basket SPY.US), peer fund USMV.US, a 4% tracking-error budget against the > benchmark, sector limits of 15 points and single-name limits of 6 points either > side of the benchmark, and a weekly report every Monday at 08:00 > America/New_York. If the S&P 500 is a poor fit for what the portfolio holds, > suggest a better benchmark first. Show me the monitor before creating it. Once > I approve, create it, enable it, run the first report, and summarize its > findings. > ``` > > > [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%20set%20up%20oversight%20of%20one%20of%20my%20portfolios.%20List%20my%20portfolios%20and%20ask%20me%20which%20one%20to%20monitor.%20If%20I%20don't%20have%20one%20yet%2C%20help%20me%20import%20my%20holdings%20and%20show%20me%20the%20full%20import%20draft%20before%20saving%20it.%20Then%20propose%20a%20fund-oversight%20monitor%20on%20that%20portfolio%3A%20benchmark%20S%26P%20500%20\(index%20GSPC.INDX%2C%20basket%20SPY.US\)%2C%20peer%20fund%20USMV.US%2C%20a%204%25%20tracking-error%20budget%20against%20the%20benchmark%2C%20sector%20limits%20of%2015%20points%20and%20single-name%20limits%20of%206%20points%20either%20side%20of%20the%20benchmark%2C%20and%20a%20weekly%20report%20every%20Monday%20at%2008%3A00%20America%2FNew_York.%20If%20the%20S%26P%20500%20is%20a%20poor%20fit%20for%20what%20the%20portfolio%20holds%2C%20suggest%20a%20better%20benchmark%20first.%20Show%20me%20the%20monitor%20before%20creating%20it.%20Once%20I%20approve%2C%20create%20it%2C%20enable%20it%2C%20run%20the%20first%20report%2C%20and%20summarize%20its%20findings.) > > > > 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%20set%20up%20oversight%20of%20one%20of%20my%20portfolios.%20List%20my%20portfolios%20and%20ask%20me%20which%20one%20to%20monitor.%20If%20I%20don't%20have%20one%20yet%2C%20help%20me%20import%20my%20holdings%20and%20show%20me%20the%20full%20import%20draft%20before%20saving%20it.%20Then%20propose%20a%20fund-oversight%20monitor%20on%20that%20portfolio%3A%20benchmark%20S%26P%20500%20\(index%20GSPC.INDX%2C%20basket%20SPY.US\)%2C%20peer%20fund%20USMV.US%2C%20a%204%25%20tracking-error%20budget%20against%20the%20benchmark%2C%20sector%20limits%20of%2015%20points%20and%20single-name%20limits%20of%206%20points%20either%20side%20of%20the%20benchmark%2C%20and%20a%20weekly%20report%20every%20Monday%20at%2008%3A00%20America%2FNew_York.%20If%20the%20S%26P%20500%20is%20a%20poor%20fit%20for%20what%20the%20portfolio%20holds%2C%20suggest%20a%20better%20benchmark%20first.%20Show%20me%20the%20monitor%20before%20creating%20it.%20Once%20I%20approve%2C%20create%20it%2C%20enable%20it%2C%20run%20the%20first%20report%2C%20and%20summarize%20its%20findings.) > > > > Start this in ChatGPT with the Itoflow plugin. > > Using another client? Copy the prompt with the button on the code block. > [tab] In the Itoflow app > > 1. Open [New monitor](https://app.itoflow.ai/watchlists/new) and choose **Use an existing portfolio**, then pick your portfolio. If you don't have one, choose **Search symbols** or **Upload a holdings file** and Itoflow helps you build it. > 2. Under **What should this monitor track?**, set a benchmark, such as `SPY.US`, any peer funds, and your limits, such as a 4% tracking-error band. Select **Continue to chat**. The chat opens with your message filled in. If you chose a holdings file, attach it in the chat box. Then send the message. > 3. If you started without a saved portfolio, check the portfolio the agent prepares and confirm it. > 4. The agent asks for anything it still needs, then saves the monitor paused and starts its first report. It tells you what it saved. Ask for any changes in the same chat. > 5. On the monitor's page, select **Edit** and set a schedule, such as weekly on Monday at 08:00. > 6. Turn on **Agent reports** so the schedule runs. Without a schedule, this sets a daily 08:00 report in your time zone. > 7. The first report appears on the monitor's page when it finishes. > > Check **Report history** for each scheduled date. If a previous date is still > running, the new date shows a failure that names it, while the older report > continues. Select a failed run to read the reason. An outage may delay the > history update, but schedule history keeps each due date. A run still open at > its next scheduled time becomes a visible failure. Pausing keeps dates already > due and stops future dates; resuming skips the paused gap. A waiting report uses > the configuration current when it starts and keeps its original local date. > [tab] With the API > > You need an [access token](/authentication#get-an-access-token) in `ITOFLOW_ACCESS_TOKEN`. > > **1. Find your portfolio** > > ```bash theme={null} > curl --fail-with-body --silent --show-error \ > 'https://api.itoflow.ai/portfolios' \ > --header "Authorization: Bearer $ITOFLOW_ACCESS_TOKEN" | > jq '.portfolios[] | { portfolio_id, name, linked_strategy }' > ``` > > Pick a portfolio whose `linked_strategy` is `null` and note its `portfolio_id`. To create one from your holdings first, see [Import holdings](/features/portfolios#import-holdings). > > **2. Create the monitor** > > ```bash theme={null} > curl --fail-with-body --silent --show-error \ > 'https://api.itoflow.ai/watchlists' \ > --header "Authorization: Bearer $ITOFLOW_ACCESS_TOKEN" \ > --header 'Content-Type: application/json' \ > --data '{ > "name": "Portfolio oversight", > "mandate": "Lead with material changes against the benchmark and explain what caused them.", > "profile": "fund_oversight", > "profile_config": { > "subject": { "name": "My portfolio", "portfolio_id": "PORTFOLIO_ID" }, > "comparators": { > "benchmark": { "name": "S&P 500", "index_symbol": "GSPC.INDX", "basket_symbol": "SPY.US" }, > "peer_funds": [{ "name": "Minimum volatility peer", "symbol": "USMV.US" }] > }, > "thresholds": { > "relative_weight": { "sector": 15, "single_name": 6 }, > "tracking_error_budget": 4 > } > }, > "recurrence": { "kind": "weekly", "weekdays": ["monday"], "local_time": "08:00", "timezone": "America/New_York" } > }' > ``` > > Replace `PORTFOLIO_ID` with the ID from the previous step. The monitor starts paused. See [fund-oversight monitors](/features/monitors#create-a-fund-oversight-monitor) for every limit and its unit. > > **3. Enable it and run the first report** > > `POST /watchlists/{id}/control` with `{"action": "enable"}` arms the weekly schedule. To get a report now, `POST /watchlists/{id}/reports/run`. > > **4. Read the report** > > `GET /watchlists/{id}/active-execution` shows the run in progress. When it finishes, `GET /watchlists/{id}/reports/latest` returns the report. ## Limits * A strategy can't run the portfolio you monitor. * Reports use the portfolio's current positions, so you can't run a report for an earlier date. * Risk figures measure a fund held beside other holdings through its dated holdings at the line's signed weight. Holdings lists, concentration and liquidity keep the fund line. * Each peer fund needs published holdings; a symbol with price history alone isn't enough. * A plain index with no basket fund is compared by returns only. ## Next steps * [Monitors](/features/monitors): every limit, warning level and report field. * [Get a daily news brief](/use-cases/daily-news-brief): add news on the portfolio's holdings. # Research with your own code and tools Source: https://docs.itoflow.ai/use-cases/research-with-your-code Connect your GitHub repositories and your own MCP servers, then ask Itoflow's research agent to run your code on Itoflow's data, change it and open a pull request, or call your own tools in its research. Tokens never reach the model or the sandbox. Itoflow's research agent can work in your GitHub repositories and call tools on your own MCP servers, beside Itoflow's engine and data. Your models stay in your code, your tools stay on your servers, and the agent brings the data, the tests and the review. **What you'll get:** research that runs your own code or calls your own tools, and, when you ask, a draft pull request in your repository with the change and its results. ## Before you start * [Connect GitHub](/features/integrations#github) and choose which repositories Itoflow can see, or [add an MCP server](/features/integrations#remote-mcp-servers) by its URL. ## Try it > [tab] Ask your AI assistant > > With [Itoflow connected to your assistant](/mcp/install), paste this into your assistant: > > ```text theme={null} > Use Itoflow with my GitHub repository OWNER/REPO. Check out the default > branch, read the README, and run the backtest in PATH on Itoflow's daily > prices for the same symbols and dates. Compare its results with a > walk-forward test on Itoflow's engine with trading costs, and explain any > gap. Then change the backtest to read Itoflow's prices, run the repository's > tests, and draft a pull request with the change and a summary of the > results. Show me the diff before you open the pull request, and wait for the > research to finish. > ``` > > > [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%20with%20my%20GitHub%20repository%20OWNER%2FREPO.%20Check%20out%20the%20default%20branch%2C%20read%20the%20README%2C%20and%20run%20the%20backtest%20in%20PATH%20on%20Itoflow's%20daily%20prices%20for%20the%20same%20symbols%20and%20dates.%20Compare%20its%20results%20with%20a%20walk-forward%20test%20on%20Itoflow's%20engine%20with%20trading%20costs%2C%20and%20explain%20any%20gap.%20Then%20change%20the%20backtest%20to%20read%20Itoflow's%20prices%2C%20run%20the%20repository's%20tests%2C%20and%20draft%20a%20pull%20request%20with%20the%20change%20and%20a%20summary%20of%20the%20results.%20Show%20me%20the%20diff%20before%20you%20open%20the%20pull%20request%2C%20and%20wait%20for%20the%20research%20to%20finish.) > > > > 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%20with%20my%20GitHub%20repository%20OWNER%2FREPO.%20Check%20out%20the%20default%20branch%2C%20read%20the%20README%2C%20and%20run%20the%20backtest%20in%20PATH%20on%20Itoflow's%20daily%20prices%20for%20the%20same%20symbols%20and%20dates.%20Compare%20its%20results%20with%20a%20walk-forward%20test%20on%20Itoflow's%20engine%20with%20trading%20costs%2C%20and%20explain%20any%20gap.%20Then%20change%20the%20backtest%20to%20read%20Itoflow's%20prices%2C%20run%20the%20repository's%20tests%2C%20and%20draft%20a%20pull%20request%20with%20the%20change%20and%20a%20summary%20of%20the%20results.%20Show%20me%20the%20diff%20before%20you%20open%20the%20pull%20request%2C%20and%20wait%20for%20the%20research%20to%20finish.) > > > > Start this in ChatGPT with the Itoflow plugin. > > Using another client? Copy the prompt with the button on the code block. > > Replace `OWNER/REPO` with your repository and `PATH` with the backtest's path in it. > [tab] In the Itoflow app > > 1. Under [Integrations](https://app.itoflow.ai/integrations), connect GitHub or add your MCP server. > 2. Open [Chat](https://app.itoflow.ai/chat) and name the repository, file or tool to use, and what to do with it. > 3. To review the change first, ask the agent to show the diff before it opens the pull request, and to open it as a draft. To keep code and data on your own machine instead, use the [local worker](/mcp/usage#work-with-your-local-agent): Itoflow plans the analysis and your local Codex or Claude Code session runs each step. ## What you get back The finished turn holds the code the agent ran, its output and the files it changed, with a link to the pull request. Asked for a draft, the agent opens one. Your branch protection still applies. With your own MCP server, the agent finds the tools it needs in the server's catalog, calls them, and uses what they return in its research. [Analyze your Interactive Brokers portfolio](/use-cases/interactive-brokers-risk) walks through one: IBKR's own server reads your positions, and Itoflow's risk model measures them. ## How it's kept safe [How we connected customers' MCP servers and GitHub repos to our research agent](https://itoflow.ai/blog/how-we-connected-mcp-servers-and-github), October 7, 2026, explains the design: * **Tokens stay out.** The model and the sandbox never see a token. Credentials are added outside the sandbox after Itoflow checks you own the connection. * **Narrow GitHub access.** The GitHub app asks only for code, pull requests and CI results: no workflows, admin rights or secrets. * **Outside text is data.** Text from a repository or a tool counts as untrusted input, not as instructions. * **Merges only when you ask.** The agent merges a pull request only when you ask it to merge that one, and GitHub's required checks still apply. * **No blind repeats.** A write whose outcome is unknown is reported as unknown and never sent twice. * **Tools stay out of the way.** A server's tools sit in a catalog the agent searches, so a server with dozens of tools doesn't crowd the model's context. ## Limits * An MCP server needs a public HTTPS URL and Streamable HTTP. It signs in with OAuth or a bearer token. * If a server's tool catalog can't be read, its tools may be missing from a turn. Reconnect when the connection says sign-in is required. ## Next steps * [Connect GitHub and MCP servers](/features/integrations): every endpoint. * [How Itoflow works](/platform/how-itoflow-works#your-code-your-data-your-models): how your code, data and models plug in. # Run a strategy under a mandate Source: https://docs.itoflow.ai/use-cases/run-a-strategy Write a mandate and position limits, and an Itoflow agent runs a paper portfolio under them on its own schedule, recording each decision with its weights, reasoning and confidence. A live portfolio trades only after a person approves the exact list of trades. A strategy is an agent that runs a portfolio under a mandate you write. At each run it reads data as of that date, decides, records why, and sets when to wake next: on a date, on a move in a held name, or when a drawdown limit is hit. A paper portfolio can trade on its own. A live portfolio waits for you to approve each list of trades. **What you'll get:** a paper portfolio run by an agent, with each decision's target weights, reasoning and stated confidence, and the trades that followed. ```mermaid theme={null} flowchart LR Mandate[Mandate and limits] --> Strategy[Strategy, created paused] Strategy --> Run[Run as of each date] Run --> Decision[Decision with reasoning] Decision --> Paper[Paper trades] Decision --> Approval[Your approval of live trades] ``` ## Before you start * An Itoflow account. * For a live portfolio, a [connected broker](/features/brokers). Start on paper first. ## Quick start > [tab] Ask your AI assistant > > With [Itoflow connected to your assistant](/mcp/install), paste this into your assistant: > > ```text theme={null} > Use Itoflow to draft a paper strategy with $100,000 that holds 10 to 20 large > US companies with high returns on capital and low debt. Mandate: review the > portfolio monthly, keep each position between 2% and 10% of the portfolio, > and halve the stock exposure if the portfolio falls 15% from its peak. Show > me the full strategy, including the limits Itoflow fills in, before you create > it, and create it paused. When I agree, turn it on, run it once now, wait for > the run to finish, and show me the decision, its reasoning and the trades. > ``` > > > [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%20draft%20a%20paper%20strategy%20with%20%24100%2C000%20that%20holds%2010%20to%2020%20large%20US%20companies%20with%20high%20returns%20on%20capital%20and%20low%20debt.%20Mandate%3A%20review%20the%20portfolio%20monthly%2C%20keep%20each%20position%20between%202%25%20and%2010%25%20of%20the%20portfolio%2C%20and%20halve%20the%20stock%20exposure%20if%20the%20portfolio%20falls%2015%25%20from%20its%20peak.%20Show%20me%20the%20full%20strategy%2C%20including%20the%20limits%20Itoflow%20fills%20in%2C%20before%20you%20create%20it%2C%20and%20create%20it%20paused.%20When%20I%20agree%2C%20turn%20it%20on%2C%20run%20it%20once%20now%2C%20wait%20for%20the%20run%20to%20finish%2C%20and%20show%20me%20the%20decision%2C%20its%20reasoning%20and%20the%20trades.) > > > > 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%20draft%20a%20paper%20strategy%20with%20%24100%2C000%20that%20holds%2010%20to%2020%20large%20US%20companies%20with%20high%20returns%20on%20capital%20and%20low%20debt.%20Mandate%3A%20review%20the%20portfolio%20monthly%2C%20keep%20each%20position%20between%202%25%20and%2010%25%20of%20the%20portfolio%2C%20and%20halve%20the%20stock%20exposure%20if%20the%20portfolio%20falls%2015%25%20from%20its%20peak.%20Show%20me%20the%20full%20strategy%2C%20including%20the%20limits%20Itoflow%20fills%20in%2C%20before%20you%20create%20it%2C%20and%20create%20it%20paused.%20When%20I%20agree%2C%20turn%20it%20on%2C%20run%20it%20once%20now%2C%20wait%20for%20the%20run%20to%20finish%2C%20and%20show%20me%20the%20decision%2C%20its%20reasoning%20and%20the%20trades.) > > > > Start this in ChatGPT with the Itoflow plugin. > > Using another client? Copy the prompt with the button on the code block. > [tab] In the Itoflow app > > 1. Open [New strategy](https://app.itoflow.ai/strategies/new) and start from a template, or describe your idea in [Chat](https://app.itoflow.ai/chat). > 2. Give the mandate, the position limits, what to invest in, and the starting capital. Answer the agent's questions about anything you left open. > 3. The agent drafts the strategy, paused. Open it under [Strategies](https://app.itoflow.ai/strategies), check its limits, and turn it on. > 4. Each decision appears on the strategy's page with its reasoning, and each trade with what happened to it. > [tab] With the API > > You need an [access token](/authentication#get-an-access-token) in `ITOFLOW_ACCESS_TOKEN`. > > **1. Create the strategy, paused** > > ```bash theme={null} > curl --fail-with-body --silent --show-error \ > 'https://api.itoflow.ai/strategies' \ > --header "Authorization: Bearer $ITOFLOW_ACCESS_TOKEN" \ > --header 'Content-Type: application/json' \ > --data '{ > "name": "US quality", > "strategyContent": "Hold 10 to 20 large US companies with high returns on capital and low debt. Review the portfolio monthly. Halve the stock exposure if the portfolio falls 15% from its peak.", > "constraints": { "min_position_pct": 0.02, "max_position_pct": 0.10, "max_positions": 20 }, > "allocationGuidance": { "markets": ["US"], "asset_classes": ["stocks"] }, > "initialCapital": "100000", > "currency": "USD", > "activateImmediately": false > }' > ``` > > `allocationGuidance` says what the strategy may invest in. It needs at least one market, asset class, sector or symbol, or creation returns `400 VALIDATION_ERROR`; to name the stocks yourself, send `universe` instead. The `201` response holds the strategy's `id` and `portfolioId`. Check `effectiveConstraints` and `effectiveRules`: they include the defaults Itoflow filled in. > > **2. Turn it on** > > `POST /strategies/STRATEGY_ID/control` with `{"action": "resume"}`, where `STRATEGY_ID` is the strategy's `id`. From now on the strategy wakes on its own. > > **3. Run it once now** > > ```bash theme={null} > curl --fail-with-body --silent --show-error \ > 'https://api.itoflow.ai/strategies/STRATEGY_ID/execute' \ > --header "Authorization: Bearer $ITOFLOW_ACCESS_TOKEN" \ > --header 'Content-Type: application/json' \ > --data '{"execution_type": "manual_rebalance"}' > ``` > > The `202` response means the run is queued, nothing more. `GET /strategies/STRATEGY_ID/active-execution` shows it while it runs. Each request queues a new run, so if you lose the response, check `active-execution` before you send it again. > > **4. Read the decision and trades** > > When the run ends: > > * `GET /paper-trading/STRATEGY_ID/decisions` lists each decision with its target weights, reasoning and confidence. > * `GET /paper-trading/STRATEGY_ID/trades` lists the trades that filled. A decision that wasn't filled doesn't appear there. > * `GET /paper-trading/STRATEGY_ID/status` shows the portfolio's holdings and weights. > > **5. Change the mandate** > > `PUT /strategies/STRATEGY_ID` with the new fields and a `changeDescription`. Each change makes a new version. Pause the strategy first, and note that a new version cancels its pending trades. > > To run a live portfolio, create the strategy with `POST /strategies/live` and the live portfolio's `portfolioId`, then approve each list of trades. See [Approve trades](/features/portfolios#approve-trades). ## How it's checked * **Each run sees only its own date.** The agent works as of the run's date and reads only data that existed then. * **Each decision keeps its record:** its weights, its reasoning and its own stated confidence, so you can see why the portfolio holds what it holds. * **Limits sit in code.** Position limits and cash checks are enforced outside the agent; a run's buys need cash above 110% of their value. * **A person approves every live trade.** Each approval covers one exact list of trades, named by its ID and a hash of its contents. ## Limits * Paper portfolios can trade automatically. Live trades always wait for approval, and Trading 212 is the one live broker today. * Long-short books, such as a 130/30, run on paper only. Margin and financing are out of scope. * Editing a mandate cancels pending trades, including approved live trades not yet sent. You can't edit a running strategy, except to change its model; pause it first. * A portfolio a fund-oversight monitor watches can't also have a strategy. ## Next steps * [Build and stress-test a strategy idea](/use-cases/stress-test-a-strategy-idea) before you run it. * [Strategies](/features/strategies): every endpoint and field. * [The agent harness](/platform/agent-harness#agents-that-keep-working): how strategies wake, decide and keep notes between runs. # Build and stress-test a strategy idea Source: https://docs.itoflow.ai/use-cases/stress-test-a-strategy-idea Describe a strategy and its risk targets, and Itoflow's research agent compares designs walk-forward with trading costs, holds back an out-of-sample period, stress-tests them on crashes such as Covid, and drafts the winner as a paused paper strategy for you to review. Describe a strategy and the risk you'll accept. The research agent designs a few candidates, tests them walk-forward with costs, keeps recent years out of sample, and stress-tests them on a crash. If one meets your targets, it drafts it as a paper strategy that starts paused. **What you'll get:** a comparison of the candidate designs with returns, volatility and drawdowns in and out of sample, a stress test, the code, and a draft strategy you can turn on. ## Try it > [tab] Ask your AI assistant > > With [Itoflow connected to your assistant](/mcp/install), paste this into your assistant: > > ```text theme={null} > Use Itoflow to build a US stock and bond strategy that targets 10% annual > volatility and a maximum drawdown of 15%. Compare at least three designs, > including a static 60/40 mix. Test each one walk-forward with trading costs, > keep the years from 2019 out of sample, and stress-test each on the Covid > crash of 2020. Ask me before you assume anything I haven't said. Show me the > evidence for the design you pick. If it meets both targets, draft it as a > paper strategy with $100,000, show it to me, and create it paused only when I > agree. Wait for the research to finish. > ``` > > > [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%20build%20a%20US%20stock%20and%20bond%20strategy%20that%20targets%2010%25%20annual%20volatility%20and%20a%20maximum%20drawdown%20of%2015%25.%20Compare%20at%20least%20three%20designs%2C%20including%20a%20static%2060%2F40%20mix.%20Test%20each%20one%20walk-forward%20with%20trading%20costs%2C%20keep%20the%20years%20from%202019%20out%20of%20sample%2C%20and%20stress-test%20each%20on%20the%20Covid%20crash%20of%202020.%20Ask%20me%20before%20you%20assume%20anything%20I%20haven't%20said.%20Show%20me%20the%20evidence%20for%20the%20design%20you%20pick.%20If%20it%20meets%20both%20targets%2C%20draft%20it%20as%20a%20paper%20strategy%20with%20%24100%2C000%2C%20show%20it%20to%20me%2C%20and%20create%20it%20paused%20only%20when%20I%20agree.%20Wait%20for%20the%20research%20to%20finish.) > > > > 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%20build%20a%20US%20stock%20and%20bond%20strategy%20that%20targets%2010%25%20annual%20volatility%20and%20a%20maximum%20drawdown%20of%2015%25.%20Compare%20at%20least%20three%20designs%2C%20including%20a%20static%2060%2F40%20mix.%20Test%20each%20one%20walk-forward%20with%20trading%20costs%2C%20keep%20the%20years%20from%202019%20out%20of%20sample%2C%20and%20stress-test%20each%20on%20the%20Covid%20crash%20of%202020.%20Ask%20me%20before%20you%20assume%20anything%20I%20haven't%20said.%20Show%20me%20the%20evidence%20for%20the%20design%20you%20pick.%20If%20it%20meets%20both%20targets%2C%20draft%20it%20as%20a%20paper%20strategy%20with%20%24100%2C000%2C%20show%20it%20to%20me%2C%20and%20create%20it%20paused%20only%20when%20I%20agree.%20Wait%20for%20the%20research%20to%20finish.) > > > > Start this in ChatGPT with the Itoflow plugin. > > Using another client? Copy the prompt with the button on the code block. > [tab] In the Itoflow app > > 1. Open [Chat](https://app.itoflow.ai/chat), or start from a template under [New strategy](https://app.itoflow.ai/strategies/new). > 2. Describe the strategy, its volatility and drawdown targets, the designs to compare, and the crash to test. > 3. Answer the agent's questions about anything you left open. > 4. Review the evidence. If you agree, the agent drafts a paused paper strategy, which you open under [Strategies](https://app.itoflow.ai/strategies) and turn on. ## What a result looks like [Governed agents in practice](https://itoflow.ai/blog/governed-agents-in-practice), July 9, 2026, publishes this session unedited. Asked for a US stock and bond strategy with a 10% volatility target and a 15% maximum drawdown, the agent compared three designs: | Design | Result | | - | - | | Static 60/40 | Worst drawdown about 21% | | Trend only | Worst drawdown about 19.5% | | Trend, momentum and volatility targeting | 5.2% a year at 6.9% volatility over the full sample; 3.7% at 7.4% in the holdout from 2019; worst drawdown 13.8% | In the Covid test, SPY fell about 34% and the 60/40 mix about 20%. The crash falls inside the holdout from 2019, so the holdout figures include it. The session ended in a paused paper strategy. These are backtests and paper results, not live profit and loss. ## How it's checked * **Targets become checked limits.** The volatility and drawdown targets go into a [research contract](/platform/agent-harness#the-research-contract) before any test runs. * **The holdout stays out.** The system recomputes the out-of-sample choice itself, and the deflated Sharpe ratio and the probability of backtest overfitting are part of the engine. * **A second agent reviews it.** In the same post, a second session's first draft was sent back by the [independent reviewer](/platform/agent-harness#independent-review) and repaired before it passed. * **Nothing trades until you say so.** The draft starts paused. A live portfolio also waits for you to approve each list of trades. ## Limits * Backtests use modeled fills and trading costs. * Bond exposure comes through ETFs. Futures, options and individual bonds aren't covered. * Long-short books run on paper portfolios only. ## Next steps * [Run a strategy under a mandate](/use-cases/run-a-strategy): turn the draft on, run it and read its decisions. * [Test a signal or dataset](/use-cases/test-a-signal) before you build a strategy on it. * [Strategies](/features/strategies): the full API. # Test a signal or dataset Source: https://docs.itoflow.ai/use-cases/test-a-signal Ask Itoflow whether a signal or your own dataset predicts returns. The research agent tests it on point-in-time data with information coefficients, a chronological out-of-sample split, multiple-testing control and the deflated Sharpe ratio, and says so plainly when it finds no edge. Give Itoflow a signal idea, or a dataset of your own, and a universe. The research agent writes the test in Python, runs it on data as it stood at each date, and tells you whether the signal held up out of sample. When it finds no edge, it says so. **What you'll get:** information coefficients by month, in-sample and out-of-sample results, overfitting checks, a long-short backtest with costs, and the code behind each number. ## Try it > [tab] Ask your AI assistant > > With [Itoflow connected to your assistant](/mcp/install), paste this into your assistant: > > ```text theme={null} > Use Itoflow to test whether 12-month momentum, skipping the latest month, > predicts next-month returns for today's 100 largest US stocks from 2015 to > today. Report the monthly rank information coefficient, its t-statistic and > the share of positive months, for a chronological 70/30 train and test split. > Then test a long-short decile portfolio with trading costs and give its > deflated Sharpe ratio. Fix the method before you look at the test period. If > the signal fails out of sample, say so rather than change it. Because today's > largest stocks were picked with hindsight, say how that could bias the > result. Wait for the research to finish, then summarize the result and its > limits. > ``` > > > [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%20test%20whether%2012-month%20momentum%2C%20skipping%20the%20latest%20month%2C%20predicts%20next-month%20returns%20for%20today's%20100%20largest%20US%20stocks%20from%202015%20to%20today.%20Report%20the%20monthly%20rank%20information%20coefficient%2C%20its%20t-statistic%20and%20the%20share%20of%20positive%20months%2C%20for%20a%20chronological%2070%2F30%20train%20and%20test%20split.%20Then%20test%20a%20long-short%20decile%20portfolio%20with%20trading%20costs%20and%20give%20its%20deflated%20Sharpe%20ratio.%20Fix%20the%20method%20before%20you%20look%20at%20the%20test%20period.%20If%20the%20signal%20fails%20out%20of%20sample%2C%20say%20so%20rather%20than%20change%20it.%20Because%20today's%20largest%20stocks%20were%20picked%20with%20hindsight%2C%20say%20how%20that%20could%20bias%20the%20result.%20Wait%20for%20the%20research%20to%20finish%2C%20then%20summarize%20the%20result%20and%20its%20limits.) > > > > 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%20test%20whether%2012-month%20momentum%2C%20skipping%20the%20latest%20month%2C%20predicts%20next-month%20returns%20for%20today's%20100%20largest%20US%20stocks%20from%202015%20to%20today.%20Report%20the%20monthly%20rank%20information%20coefficient%2C%20its%20t-statistic%20and%20the%20share%20of%20positive%20months%2C%20for%20a%20chronological%2070%2F30%20train%20and%20test%20split.%20Then%20test%20a%20long-short%20decile%20portfolio%20with%20trading%20costs%20and%20give%20its%20deflated%20Sharpe%20ratio.%20Fix%20the%20method%20before%20you%20look%20at%20the%20test%20period.%20If%20the%20signal%20fails%20out%20of%20sample%2C%20say%20so%20rather%20than%20change%20it.%20Because%20today's%20largest%20stocks%20were%20picked%20with%20hindsight%2C%20say%20how%20that%20could%20bias%20the%20result.%20Wait%20for%20the%20research%20to%20finish%2C%20then%20summarize%20the%20result%20and%20its%20limits.) > > > > Start this in ChatGPT with the Itoflow plugin. > > Using another client? Copy the prompt with the button on the code block. > > To test your own dataset, keep it in a [connected GitHub repository](/features/integrations#github) and name the file in the prompt, or attach it in the Itoflow app. > [tab] In the Itoflow app > > 1. Open [Chat](https://app.itoflow.ai/chat). > 2. To test your own dataset, attach it to your message: up to 5 files of up to 5 MB each. > 3. Ask for the test in plain words: the signal, the universe, the dates, how to split them, and what to report. > 4. The answer appears as a dashboard, with the code and files under the turn. ## What a result looks like We ran the prompt above on October 28, 2026. The agent fixed the method first: 98 months to train, from January 2015, and 43 months to test, from March 2023 to September 2026. Its answer: * In the test months, the mean rank information coefficient was +0.034, with a t-statistic of 1.28. Its 95% interval ran from -0.018 to +0.087, so it included zero. 53.5% of test months were positive. * After costs, the long-short decile portfolio returned 30.7% over the test months, with a Sharpe ratio of 0.39 and a deflated Sharpe ratio of 0.77. It gained 42% in June 2026 and lost 35% in July. * Only 89 to 98 of the stocks had a full year of prices, so each decile held 8 or 9 stocks. The agent said so rather than fill the gap. * It judged momentum not confirmed out of sample and did not retune the signal after seeing the test. It named the hindsight in the universe: today's largest stocks leave out the large caps that failed or shrank, so the test months are held out for the signal but not for the choice of stocks. [What our quant-research agent actually does — and where it still needs a human](https://itoflow.ai/blog/what-our-quant-research-agent-actually-does), July 9, 2026, shows an open request: find and validate a signal for 12 US large caps. Out of sample, neither 6-month momentum nor short-term mean reversion passed, and the agent reported no validated edge. It didn't flip the signals or switch to a universe where they looked better. ## How it's checked * **The method is fixed first.** The agent writes a [research contract](/platform/agent-harness#the-research-contract) with the universe, dates, split and evidence before the test runs, and the system checks it. * **The out-of-sample result is worked out again.** The system recomputes the out-of-sample choice itself rather than trust the agent's claim. * **Overfitting checks are code.** The deflated Sharpe ratio, the probability of backtest overfitting and false-discovery-rate control run in the engine. * **A second agent reviews it.** An [independent reviewer](/platform/agent-harness#independent-review) reads the plan and the files, and can send the work back. ## Limits * No tool returns an index's past members, and the agent can't yet pick a universe from data known at each past date, such as the 500 largest stocks then. Asked for one, it says it can't build that universe rather than use today's list. With a fixed list, as in the prompt above, it states how hindsight in that choice could bias the result. * Data covers stocks and ETFs on 24 exchanges, plus crypto. Futures, options and individual bonds aren't covered. * A file attached in the app can be up to 5 MB. Keep larger datasets in GitHub or serve them from your own [MCP server](/features/integrations#remote-mcp-servers). * A signal that passes is a research result, not a forecast. ## Next steps * [Build and stress-test a strategy idea](/use-cases/stress-test-a-strategy-idea) from a signal that passed. * [Quant engine and risk model](/platform/quant-engine): the tests and data behind the answer. * [Chat](/features/chat): run research through MCP and read the results.