Async jobs

Handoff and insight generation runs on a worker, not inline. Any generation endpoint returns 202 Accepted with a jobId instead of the artifact. You poll the job until it reaches a terminal state.

Lifecycle

A job moves through these statuses:

pending -> processing -> completed
                      -> failed
  • pending – enqueued, not yet picked up.
  • processing – the worker is generating.
  • completed – done; result_id points at the handoff or insight.
  • failed – generation failed; error and error_code explain why.

Polling loop

Poll GET /jobs/{jobId} every couple of seconds with a sane timeout. Stop on completed or failed.

async function waitForJob(jobId, apiKey, { intervalMs = 2000, timeoutMs = 120000 } = {}) {
  const deadline = Date.now() + timeoutMs;
  while (Date.now() < deadline) {
    const res = await fetch(`https://www.flowrelay.it/api/v1/jobs/${jobId}`, {
      headers: { Authorization: `Bearer ${apiKey}` },
    });
    const { job, result } = await res.json();
    if (job.status === "completed") return result;
    if (job.status === "failed") throw new Error(job.error ?? "Generation failed");
    await new Promise((r) => setTimeout(r, intervalMs));
  }
  throw new Error("Timed out waiting for job");
}
import time
import requests
 
def wait_for_job(job_id, api_key, interval=2, timeout=120):
    deadline = time.time() + timeout
    headers = {"Authorization": f"Bearer {api_key}"}
    while time.time() < deadline:
        resp = requests.get(
            f"https://www.flowrelay.it/api/v1/jobs/{job_id}", headers=headers
        )
        payload = resp.json()
        job = payload["job"]
        if job["status"] == "completed":
            return payload["result"]
        if job["status"] == "failed":
            raise RuntimeError(job.get("error") or "Generation failed")
        time.sleep(interval)
    raise TimeoutError("Timed out waiting for job")

Project handoffs and architecture insights can take tens of seconds because they build context and run larger models. Use a timeout of 120 seconds and a poll interval of 2 seconds. Do not poll faster than once per second – it only burns your rate limit.

Reading the result

When status is completed, the job response embeds the artifact under result. result_kind tells you whether it is a handoff or an insight, and result_id is the row id you can fetch again later via the list endpoints.

See Errors for what a failed job's error_code means.