API

Polling

Follow a request with GET /v1/requests/{request_id}, optionally long-polling with ?wait.

Poll a request with its status_url:

HTTP
GET /v1/requests/{request_id}
GET /v1/requests/{request_id}/status   (alias, same answer)

Each call returns the request object. While the request is open, the call checks the run's current state first, so every answer is up to date. A final request (completed, partial, failed, cancelled) is answered from storage and never changes.

#Long-polling with ?wait

Add ?wait=N (an integer from 0 to 60, in seconds) to hold the call until the request is final or N seconds have passed, whichever comes first. Between checks the server waits at least 2 seconds, or longer when the model reports a later check time.

Shell
curl "https://api-live.aitopia.ai/v1/requests/$REQUEST_ID?wait=30" \
  -H "Authorization: Key $AITOPIA_KEY"
  • wait outside 0–60, or not an integer, answers 400 INVALID_INPUT with field: "wait".
  • An account can hold 3 waiting calls at a time (shared with the AITOPIA MCP server). A call made while all 3 are busy checks once and answers immediately, as if wait were 0.
  • If you close the connection, the wait ends.

The submit endpoints take ?wait=N too: the submit answers with the state after up to N seconds, still with status code 202.

#A polling loop

Loop on ?wait=30 until the status is final. Each long-poll counts as one request against your rate limits.

curl
STATUS=queued
while [ "$STATUS" = "queued" ] || [ "$STATUS" = "running" ]; do
  BODY=$(curl -s "https://api-live.aitopia.ai/v1/requests/$REQUEST_ID?wait=30" \
    -H "Authorization: Key $AITOPIA_KEY")
  STATUS=$(echo "$BODY" | jq -r .status)
done
echo "$BODY" | jq .output
Node.js
const TERMINAL = new Set(["completed", "partial", "failed", "cancelled"]);

async function waitForResult(statusUrl) {
  const headers = { Authorization: `Key ${process.env.AITOPIA_KEY}` };
  for (;;) {
    const res = await fetch(`${statusUrl}?wait=30`, { headers });
    const body = await res.json();
    if (!res.ok) {
      if (!body.error?.retryable) throw new Error(`${body.error.code}: ${body.error.message}`);
      const delay = (body.error.retry_after_seconds ?? 5) * 1000;
      await new Promise((r) => setTimeout(r, delay));
      continue;
    }
    if (TERMINAL.has(body.status)) return body;
  }
}
Python
import os, time, requests

TERMINAL = {"completed", "partial", "failed", "cancelled"}
HEADERS = {"Authorization": f"Key {os.environ['AITOPIA_KEY']}"}

def wait_for_result(status_url):
    while True:
        r = requests.get(status_url, params={"wait": 30}, headers=HEADERS, timeout=90)
        body = r.json()
        if not r.ok:
            err = body["error"]
            if not err.get("retryable"):
                raise RuntimeError(f"{err['code']}: {err['message']}")
            time.sleep(err.get("retry_after_seconds", 5))
            continue
        if body["status"] in TERMINAL:
            return body

Set your HTTP client timeout above the wait value (the examples use 90 seconds for wait=30).

#Polling without wait

Plain GET calls work as well; poll every few seconds rather than in a tight loop.

#Errors while polling

StatusCodeMeaning
400INVALID_INPUTBad wait value.
404NOT_FOUNDNo request with this id in your account (including ids that are not UUIDs).
401UNAUTHENTICATED, KEY_SESSION_EXPIREDSee Authentication.
429RATE_LIMITSlow down; see retry_after_seconds.

A 200 answer for an open request may carry an error with retryable: true (for example STATUS_CHECK_FAILED). The request is still open; keep polling. See open requests with an error.

Instead of polling, you can have the result sent to you: see Webhooks.

AITOPIA REST API · Live https://api-live.aitopia.ai/v1 · Sandbox https://api-sandbox.aitopia.ai/v1