File a run under a project (or unfile it)
const url = 'https://api.hyperresearch.ai/v1/runs/example';const options = { method: 'PATCH', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"project_id":"example"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request PATCH \ --url https://api.hyperresearch.ai/v1/runs/example \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "project_id": "example" }'Sets project_id; null unfiles the run. Allowed while the run is queued or terminal; a run that is running, paused or blocked is a 409 run_not_filable. Filing a run also RETAGS the notes it wrote: project:<id> is added (and the previous project’s tag removed), so the run’s evidence appears under the project’s Sources and Vault and is reusable by that project’s later runs. notes_retagged on the response says how many notes moved; 0 means the run wrote none, or the vault could not be reached — the run itself is filed either way.
Authorizations
Section titled “Authorizations”Parameters
Section titled “ Parameters ”Path Parameters
Section titled “Path Parameters”Request Bodyrequired
Section titled “Request Bodyrequired”object
Examplegenerated
{ "project_id": "example"}Responses
Section titled “ Responses ”Run
object
True when an included (trial) run covered this run, so it metered at $0. The server’s answer to “Included in trial” — never inferred from price_cents. Alias of included_in_trial.
Same value as included, spelled the way the console reads it.
Which included-run allowance was claimed (light/full), or null.
True when an operator grant comped this run (0041). The same field and the same value GET /v1/runs/{id} publishes, so a list row can print “Complimentary” beside the price.
What the billing ledger metered for this run, refunds included. 0 for a trial-covered run; null when no ledger row exists yet — which is NOT the same as zero.
The same number the run detail reports in progress.sources_fetched. Null until the run has reported one. Also in counters.
Everything a list row counts, in one place, cached from the RunAgent: the same numbers GET /v1/runs/:id reports in progress, a few seconds behind at most, so a list card never has to fetch the run to show them (E2E2-13/E2E2-24). sources_fetched/notes_written above are the same numbers, kept flat for existing clients.
object
Sources this run KEPT; the same number progress.sources_fetched and the counters stream event report (E2E4-02).
Candidates considered, kept or not. Always >= sources_fetched when both are known.
Physical fetch attempts — requests that actually went out. A vault lookup is not one, so this can be lower than candidates_seen (E2E7-02).
DEPRECATED spelling of candidates_seen, emitted in step with it. Read candidates_seen.
Steps finished. Step progress lives in the run’s Durable Object and this list will not open one per row (E2E2-24), so the RunAgent writes it through to the control row on every step transition (0026). NULL for a run that has not reported one yet — a client that finds it null can still derive the scale from the tier.
Steps this run’s tier executes, from the same write-through. NULL when the run has not reported one yet.
The step this run is on, cached from the RunAgent; null when it is not running.
That step in human words (the shared step → name map), or null.
The unit inside that step, in customer words: “Chapter 2 of 4 · Depth investigation”, “Writing section 3 of 9”. The same string GET /v1/runs/{id} reports as step.detail, cached from the RunAgent (0035). Null on a flat run and once the step stops.
How many chapters this run’s plan has. A count of the PLAN, so it outlives the run and a finished Deep row still says how many chapters the customer got. Null means the run is not chaptered (or settled before the column existed) — never zero.
Word count of the finished report; null while there is no report.
One customer-safe sentence saying what a blocked run is waiting for a person to do, and null on every other status. The same value GET /v1/runs/{id} reports, so a list row can prompt for a resume without fetching the run.
The machine gate id behind blocked_on — step:<id>:<check>, verify:<check>, fetch_budget, model_budget or provider:<name>. Branch on this; print blocked_on.
Why a blocked run is waiting on US rather than on a person: it is clearing the condition by itself and will carry on with no action from the caller, and nothing has been charged. Present only while a run is waiting; absent or null on every other run, including a block that does need the customer to act. Branch on its PRESENCE, not on the class.
Present, non-null, while a running/blocked run is being RECOVERED: our infrastructure interrupted it and we are resuming it from where it stopped, on the same run id, at no extra charge (Deep automatic recovery). Absent or null on every other run. While set, wait_reason is null and blocked_on is not a gate: the run needs nothing from anyone. Branch on its PRESENCE.
object
Which automatic recovery this is (1, 2, 3), or null while a stalled run is being handed over and the attempt is not yet claimed.
Why this run ended badly, in one customer-safe sentence; null for a healthy run. For a blocked run this is blocked_on, matching the run status view. The raw text is failure_detail on the run detail, owner/admin only.
The user id that asked for the abort, or null for a run nobody stopped, a run stopped by an unattributed API key, or one stopped before this field existed. Published so a client can say “Stopped by you.” on its own terms rather than inferring it from the sentence; failure_reason is already narrowed for the caller.
True when this run was a DRY RUN: the orchestration was real but the model provider and the fetch/search vendors were mocked, so the report is synthetic and the price is $0. Server truth (the run’s dry_run channel), never inferred from a zero price — a trial run and a fixture run are also $0 and are not dry. Always false in production, where dry runs cannot be created.
Wall time from start (or creation) to finish; null while the run is unfinished. Settled in the same statement that writes finished_at, and carried on the terminal stream event, so a watching page and a reloaded one never differ (E2E8-13).
The newest run asking the same question, or null when this run IS that run. Label a row “Earlier version” if and only if this is set. Grouped by normalised question text, or by an explicit rerun parent — never by project (E2E8-10).
Stable key for the version group, so a client can bucket a page in one pass.
What this report’s own verification receipt came to, in four counts — so a row or a card can show that a report needs a second look without opening it (E2E10-07). Null means no receipt is known for this run (it did not produce one, or it finished before the counts were stored); null is NOT a pass.
object
Checks that ran and met their bar. A warning is NOT a pass (E2E8-01).
Checks that ran and recorded a finding below our own target. Informational; see attention for what a reader should act on.
Checks that ran and did not meet their bar.
Checks with nothing to judge (“not applicable”). Counted apart from the three above.
Findings a reader should act on before relying on the report: cited statements that say more than their sources support (above 3 and 3% of those checked), a chapter without its full research pass, a retracted source, or final checks that did not run. Absent on a summary cached before this field existed.
Vault notes moved to the new project scope by this call.
Example
{ "wait_reason": "provider_billing"}Headers
Section titled “Headers”Example
"reads";q=60;w=60The quota policy this request was counted against (draft-ietf-httpapi-ratelimit-headers): "<bucket>";q=<requests>;w=<window seconds>, e.g. "reads";q=60;w=60. Buckets: reads 60/min, status 600/min, creates 10/min, writes 20/min per credential; public 300/min per network on keyless routes.
Example
"reads";r=57;t=41Remaining quota in the current window: "<bucket>";r=<remaining>;t=<seconds until reset>, e.g. "reads";r=57;t=41.
Requests allowed per window in this bucket (legacy form of RateLimit-Policy).
Requests left in this window (legacy form of RateLimit).
Unix time (seconds) when the window resets.
Which bucket counted the request: reads, status, creates, writes or public.
Invalid request
object
object
Example
{ "error": { "type": "invalid_request", "code": "missing_api_key", "request_id": "req_01J9ZQ7V6H0000000000000000" }}Authentication failed
object
object
Example
{ "error": { "type": "invalid_request", "code": "missing_api_key", "request_id": "req_01J9ZQ7V6H0000000000000000" }}Insufficient scope or plan
object
object
Example
{ "error": { "type": "invalid_request", "code": "missing_api_key", "request_id": "req_01J9ZQ7V6H0000000000000000" }}Not found
object
object
Example
{ "error": { "type": "invalid_request", "code": "missing_api_key", "request_id": "req_01J9ZQ7V6H0000000000000000" }}The run is mid-flight, or the target project is archived
object
object
Example
{ "error": { "type": "invalid_request", "code": "missing_api_key", "request_id": "req_01J9ZQ7V6H0000000000000000" }}Rate limited or over quota
object
object
Example
{ "error": { "type": "invalid_request", "code": "missing_api_key", "request_id": "req_01J9ZQ7V6H0000000000000000" }}Headers
Section titled “Headers”Seconds to wait before retrying. Always present on a 429.
Example
"reads";q=60;w=60The quota policy this request was counted against (draft-ietf-httpapi-ratelimit-headers): "<bucket>";q=<requests>;w=<window seconds>, e.g. "reads";q=60;w=60. Buckets: reads 60/min, status 600/min, creates 10/min, writes 20/min per credential; public 300/min per network on keyless routes.
Example
"reads";r=57;t=41Remaining quota in the current window: "<bucket>";r=<remaining>;t=<seconds until reset>, e.g. "reads";r=57;t=41.
Requests allowed per window in this bucket (legacy form of RateLimit-Policy).
Requests left in this window (legacy form of RateLimit).
Unix time (seconds) when the window resets.
Which bucket counted the request: reads, status, creates, writes or public.
Internal error
object
object
Example
{ "error": { "type": "invalid_request", "code": "missing_api_key", "request_id": "req_01J9ZQ7V6H0000000000000000" }}