Docs
On this page
Last updated 2026-07-07 API version v1

The Async Submit → Poll Model

Every stage of the InvesTeam pipeline that does real work is asynchronous. You submit work and get back a session_id and a status; you then poll a matching read route until it reaches a terminal state. One session_id threads the whole run — brief, orchestration, execution, and analysis all share it. Learn this one pattern and every endpoint reads the same way.

Why does InvesTeam submit then poll?

Because a committee run takes minutes, not milliseconds — a blocking call would hold a connection open for the length of the analysis. Instead, a submit returns immediately with an id, and you poll at your own cadence. Nothing on your side waits on a long-lived request, and a client that drops can re-attach to the run simply by polling the same id.

The spine is one pattern repeated across the pipeline:

text
POST /api/v1/briefs                → session_id + status
  poll GET /api/v1/briefs/{id}       until completed | rejected
    (if needs_clarification) POST /api/v1/briefs/{id}/answers → re-poll
  POST /api/v1/orchestrations        → convene the committee
  poll GET /api/v1/orchestrations/{id}  for the committee + task plan
  poll GET /api/v1/executions/{id}      until completed | failed
    stream GET /api/v1/executions/{id}/transcript?after=<seq>
  poll GET /api/v1/analyses/{id}        for the final analysis

How do I poll for a result?

Fetch the stage's read route on a sane interval — every two to three seconds is a good default — until its status is terminal. Read the status field on each poll and stop when it settles (for a brief, completed or rejected; for an execution, completed or failed).

bash
curl -sS https://investeam.io/api/v1/briefs/SESSION_ID \
  -H "Authorization: Bearer hfk_your_key_here"

Poll no faster than the limits allow — see Rate Limits & Quotas.

What does a 404 mean on an InvesTeam poll?

On the downstream poll routes — GET /api/v1/orchestrations/{id}, GET /api/v1/executions/{id}, GET /api/v1/executions/{id}/transcript, and GET /api/v1/analyses/{id} — a 404 means "valid id, this stage hasn't produced output yet." It is not a hard error; keep polling.

A 404 on GET /api/v1/briefs/{id} is different. A brief that exists is always readable by its owner, so a 404 there means the id is unknown or foreign — a genuine not_found, not a not-ready signal. This is the one poll route where 404 is terminal.

Treat status and transcript kind as an open set. If you receive a value you do not recognize, treat it as non-terminal and keep polling — the API may add states within v1. See Versioning & Deprecation.

Do I need an idempotency key?

Send an Idempotency-Key header on every submit — POST /api/v1/briefs, POST /api/v1/briefs/{id}/answers, and POST /api/v1/orchestrations — so a retry can never double-submit. The same key with the same request body returns the original result and starts no second run; the same key with a different body returns 409 conflict, so a buggy retry cannot silently overwrite.

bash
curl -sS https://investeam.io/api/v1/briefs \
  -H "Authorization: Bearer hfk_your_key_here" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 9f2c1e7a-brief-001" \
  -d '{"input": "Is NVDA a buy right now?"}'

Generate one key per logical submit — a UUID is ideal. Because submits are the only calls that spend a kickoff, the idempotency key is your protection against a retry storm multiplying cost.

When should I retry, and when should I not?

Let the error envelope decide. Every non-2xx response carries a retryable flag: client-caused errors (bad_request, unauthorized, forbidden, not_found, conflict) are false — fix the request, do not retry blindly — while upstream_error, internal_error, and rate_limited are true — retry with back-off. On a 429, wait the advertised Retry-After interval. See the Error Reference and Rate Limits & Quotas.

Where next?

See the whole pattern run once in the Pipeline Walkthrough, or go straight to the Briefs reference for the first submit.