Skip to main content

Research

A research run collects the stored data for one listed company and has the model write a sectioned report that ends in a decision line (a model-sampled view, not advice). For a short request about the stored data, use the copilot; for model calls with your own messages and tools, use model inference.

Routes​

taskrouteentitlement
start a run and stream itPOST /v1/research/agentic/analyzeai
list your runsGET /v1/research/runsai
read a run's status and usageGET /v1/research/runs/{run_id}ai
stop a runPOST /v1/research/runs/{run_id}/cancelai
read or delete a run's stored reportGET / DELETE /v1/research/runs/{run_id}/reportai
read the shared daily report for a securityGET /v1/securities/{symbol}/researchdata

Entitlements come with your tier (entitlements); a streamed example is in Python examples.

Start a run​

POST /v1/research/agentic/analyze takes symbol (the company's ticker, or MIC:SYMBOL to name the venue), date (the analysis date, YYYY-MM-DD), and optionally context. Every field is described in the API reference.

Any other field is refused, and so is a date that is not a real date or is in the future (422 invalid_request), before the stream starts. A symbol that does not name a maintained listing is refused with a typed error before the stream starts, for example 404 not_registered, 404 not_maintained, or 409 for a bare ticker listed on two venues.

A run is AI work, charged as set out in charges for AI work.

The research stream​

The stream sends server-sent events in this order:

eventwhenwhat it carries
runfirstthe run object: its id (run_…), status, report_available, and usage
progresswhile data is collectedone source at a time: step of total, source, and status (collecting, then read, absent, or failed)
inputswhen collection endsthe report's inputs
model_startedonce, when the model call startsstarted_at, reserved_credits, and charge_if_interrupted
reasoningwhile the model reasons before answering{"status": "in_progress"}, at most one every 5 seconds
unnamed data: frameswhile the model answersthe report text, as OpenAI chat-completion deltas
evidencewhen the model's stream endsthe report's evidence and verified_at (RFC 3339 UTC), when it was verified present
completionlastthe API's verdict on the report, and the run's settled usage

When the model's stream reached its end, data: [DONE] follows completion as the last frame. It says only that the transport ended; the verdict is completion. The model's reasoning is never streamed.

Source outcomes and missing values​

Each source ends read, absent, or failed. absent means no data is available for that source: the data is missing, and the read did not fail.

In the report text, the financial statements mark a line with no value as NaN (a placeholder in the text, not a JSON value). A NaN is never zero and never an estimate. missing_values.fields lists every such line with its statement, periods, and reason:

reasonmeaning
not_heldno value is available for that line in that period
no_longer_publishedthe company stopped reporting the line's concept
conflicting_assertions, unreliablethe period is held, but its value is withheld

The verdict​

completion has complete, reason, and message. complete is true only when the model finished normally and the answer is a whole report with its conclusion and exactly one decision line. Otherwise reason says why, for example length_limit, no_conclusion, no_decision, model_timeout, cancelled, or report_unavailable. Treat the report as complete only when a received completion event has complete: true.

A run that cannot finish sends a typed error frame before completion: {"error": …, "message": …} with error model_timeout, model_unavailable, or model_error; or an event: error frame with evidence_withdrawn when an article the report was being written from is withdrawn, or evidence_unverified when its evidence could not be verified in time (no unverified text is delivered). The error frame carries the run's settled usage too.

A stream that ends with neither completion nor error was dropped. Read the run to see how it settled.

Charging fields​

model_started marks the instant the model call started, which decides how an interrupted run settles (settlement); charge_if_interrupted gives the charge of an interruption after it. Every terminal frame carries the settled usage; charged_credits is the charge, final once settled is true.

Follow or stop a run​

GET /v1/research/runs lists your runs, newest first, by limit (default 20, at most 100) and after (lists). GET /v1/research/runs/{run_id} reads a run's status and settled usage.

POST /v1/research/runs/{run_id}/cancel stops a run that is still in progress. The stream ends with completion {"complete": false, "reason": "cancelled", …}. The route answers with the run: 200 once it is settled, 202 while the stop is still settling (read it again). A run that already ended is returned unchanged. Closing the connection also stops the run. The run's status depends on what stopped it:

the model when the stop arrivedthe run's status
still working, stopped by a cancelcancelled
still working, stopped by a disconnectfailed
already finishedits own verdict: completed with the report stored, or incomplete

The run and report routes count as data requests and serve only your account's runs: another account's run id is 404 not_found, like an unknown one.

The stored report​

complete: true confirms that the complete report and its settlement are stored. A storage failure returns complete: false, reason: report_unavailable. report_available on the run says whether there is a report to read.

GET /v1/research/runs/{run_id}/report returns the report and its decision, the completion verdict the stream ended with, known_at (the evidence cutoff), and the report fields. validity is judged each time you read the report.

A run without a stored report is 404 no_report: one that failed, was canceled, disconnected, or ended incomplete, a run the copilot started as a tool, or a report you deleted.

DELETE /v1/research/runs/{run_id}/report deletes the report (204); the run's record and usage stay. A stored report is kept until you delete it. Reports belong to your account: any of its keys can read and delete them, and revoking a key does not remove them.

Runs started by the copilot​

When the copilot runs research as a tool, that research is its own run, charged separately. Its run object names the copilot run in copilot_run ({"id": …}; null for a run you started). Stop it by canceling the copilot run (POST /v1/agents/copilot/runs/{run_id}/cancel): the research cancel route answers 409 conflict while such a run is in progress. A copilot-started run stores no report.

Shared daily research​

GET /v1/securities/{symbol}/research returns the newest stored report for one security in the research cohort. It is a data request: it needs the data entitlement, draws on your data pool, uses no AI credits, and never starts a run. A shared report is the same for every caller. For a fresh report, or one on a date of your choosing, start your own run.

data_session is the trading session whose close the evidence runs through, and prepared_for the next session. decision and report are model output, not advice. freshness.stale is true when a later session has completed and its report is not stored yet (latest_completed_session names it).

A security outside the cohort is 404 not_supported. A cohort member whose first report is not prepared yet is 503 temporarily_unavailable.

Report fields​

A run's stored report and the shared daily report carry evidence, inputs, validity, and method. Every field is described in the API reference.

  • inputs.sources has one entry per source with its state (read, absent, or failed); inputs.missing_values lists every line marked with the placeholder (missing values).
  • validity.state is valid, withdrawn (an article or the thesis has been withdrawn or changed since), or unverifiable; in the last two cases report and decision are null and reason and message say why. A later correction of an input named in validity.unverified_inputs does not change the state.
  • method.input_id: two reports with the same value were written from the same input and configuration. method.decision_status is sampled: another run can reach a different decision.

Research over MCP​

Over the hosted MCP server, a research run is the run_agentic_research tool, and list_research_runs, retrieve_research_run, cancel_research_run, and retrieve_research_report list, read, and stop runs (the research tool). Deleting a stored report is HTTP only.