API Reference

Continua AI API documentation

Create document-based responses, retrieve results asynchronously, and continue a completed response with follow-up questions. Call the API directly over HTTPS, or use the OpenAI Python or JavaScript client library with a custom base URL.

Overview

Only the endpoints and parameters documented here are supported. All base paths are relative to the API base URL.

Base URL
https://app.askcontinua.com/api/v1

If your Continua AI account uses a different site URL, append /api/v1 to that site URL.

Authentication

Every request requires a Continua AI API token in the Authorization header.

HTTP
Authorization: Bearer YOUR_CONTINUA_AI_API_TOKEN

Keep API tokens on your server. Do not expose them in browser code, mobile applications, public repositories, or client-side logs.

Bash
export CONTINUA_AI_API_KEY="YOUR_CONTINUA_AI_API_TOKEN"
export CONTINUA_AI_API_BASE_URL="https://app.askcontinua.com/api/v1"

How requests work

All responses are created asynchronously.

  • Upload one or more files and retain each returned file_id.
  • Create a response with a prompt and at least one file or project.
  • Poll the response until its status becomes completed, failed, or cancelled.
  • Read the generated answer from output_text.
  • To continue the conversation, create another response with previous_response_id.

Streaming is not currently supported. Set background to true and do not send stream: true.

Quickstart

Install the client library with python -m pip install openai or npm install openai. The first response must include at least one uploaded file or a Continua AI project.

Python

Python
import os
import time
from uuid import uuid4

from openai import OpenAI

client = OpenAI(
    api_key=os.environ["CONTINUA_AI_API_KEY"],
    base_url=os.environ["CONTINUA_AI_API_BASE_URL"].rstrip("/"),
)

uploaded_file = client.files.create(
    file=("hello.txt", b"Hello world.", "text/plain"),
    purpose="user_data",
)

response = client.responses.create(
    model="deepseek-flash",
    background=True,
    input=[
        {
            "role": "user",
            "content": [
                {"type": "input_file", "file_id": uploaded_file.id},
                {"type": "input_text", "text": "Summarize this file in one sentence."},
            ],
        }
    ],
    extra_headers={"Idempotency-Key": f"response-{uuid4().hex}"},
)

terminal_statuses = {"completed", "failed", "cancelled"}

while response.status not in terminal_statuses:
    time.sleep(5)
    response = client.responses.retrieve(response.id)

if response.status != "completed":
    raise RuntimeError(f"Response ended with status={response.status}")

print(response.output_text)

Node.js

TypeScript
import { randomUUID } from "node:crypto";
import OpenAI, { toFile } from "openai";

const client = new OpenAI({
  apiKey: process.env.CONTINUA_AI_API_KEY!,
  baseURL: process.env.CONTINUA_AI_API_BASE_URL!.replace(/\/$/, ""),
});

const uploadedFile = await client.files.create({
  file: await toFile(Buffer.from("Hello world."), "hello.txt", { type: "text/plain" }),
  purpose: "user_data",
});

let response = await client.responses.create(
  {
    model: "deepseek-flash",
    background: true,
    input: [
      {
        role: "user",
        content: [
          { type: "input_file", file_id: uploadedFile.id },
          { type: "input_text", text: "Summarize this file in one sentence." },
        ],
      },
    ],
  },
  { headers: { "Idempotency-Key": `response-${randomUUID()}` } },
);

const terminalStatuses = new Set(["completed", "failed", "cancelled"]);

while (!terminalStatuses.has(response.status)) {
  await new Promise((resolve) => setTimeout(resolve, 5000));
  response = await client.responses.retrieve(response.id);
}

if (response.status !== "completed") {
  throw new Error(`Response ended with status=${response.status}`);
}

console.log(response.output_text);

Models

Use a full model identifier in every create request, or auto to let Continua choose the model.

ModelModel identifierBest suited for
AutoautoContinua picks the best model for the task
DeepSeek Flashdeepseek-flashFast, everyday analysis
DeepSeek Prodeepseek-proDeeper reasoning
GLM Flashglm-flashFast, cost-efficient work
GLMglmBalanced performance
GPT Lunagpt-lunaFast, cost-efficient work
GPT Terragpt-terraBalanced performance
GPT Solgpt-solAdvanced reasoning
GPT Astragpt-astraMost capable reasoning
Claude Haikuclaude-haikuFast responses
Claude Sonnetclaude-sonnetBalanced speed and depth
Claude Opusclaude-opusDeep analysis
Claude Fableclaude-fableFrontier reasoning
Gemini Flashgemini-flashFast multimodal work
Gemini Progemini-proLong-context work
GrokgrokGeneral-purpose reasoning
KimikimiLong-context analysis

Model access may depend on your account plan. See pricing for plan information and benchmarks for published evaluations on long-document investigations.

Upload a file

Uploads one file for use in a response.

POST/files

Form fields

FieldTypeRequiredDescription
fileFileYesOne file. Send one file per upload request.
purposeStringYesMust be user_data.

Supported filename extensions

Text
.txt, .md, .markdown, .json, .pdf, .docx, .xlsx, .csv,
.eml, .msg, .pptx, .html, .htm, .xhtml

The maximum file size depends on the account plan.

cURL example

Bash
curl --request POST \
  "${CONTINUA_AI_API_BASE_URL}/files" \
  --header "Authorization: Bearer ${CONTINUA_AI_API_KEY}" \
  --form "purpose=user_data" \
  --form "file=@report.pdf"

Response

JSON
{
  "id": "file_1234567890abcdef",
  "object": "file",
  "bytes": 24831,
  "created_at": 1789344000,
  "expires_at": 1789430400,
  "filename": "report.pdf",
  "purpose": "user_data",
  "status": "processed"
}
FieldTypeDescription
idStringFile identifier to use in a response request.
objectStringAlways file.
bytesIntegerFile size in bytes.
created_atIntegerCreation time as a Unix timestamp in seconds.
expires_atIntegerDeadline for using an unsubmitted upload.
filenameStringOriginal filename.
purposeStringAlways user_data.
statusStringAlways processed after a successful upload.

Files uploaded for an API response are temporary and follow the Zero Document Retention workflow: the documents are deleted after the task completes. Each uploaded file can be used in one response creation request; upload the document again to obtain a new file identifier. Files intentionally added to a Project remain available for reuse. See Trust & Security for the complete retention policy.

Create a response

Creates an asynchronous response.

POST/responses

Send a unique Idempotency-Key header with every new request.

HTTP
Idempotency-Key: response-7c86b96c5a4d48c58bbdb6bca75e1098

Request body

JSON
{
  "model": "deepseek-flash",
  "background": true,
  "input": [
    {
      "role": "user",
      "content": [
        { "type": "input_file", "file_id": "file_1234567890abcdef" },
        { "type": "input_text", "text": "Summarize the main risks in this document." }
      ]
    }
  ]
}

Parameters

ParameterTypeRequiredDescription
modelStringYesA full model identifier, or auto.
backgroundBooleanRecommendedMust be true when provided. Responses always run asynchronously.
inputString or arrayYesThe user's request.
previous_response_idStringNoIdentifier of a completed response to continue.
reportObjectNoOptional report configuration.

Only the parameters documented here affect a response. Omit other OpenAI Responses API parameters. In particular, streaming is unavailable.

Input rules

  • input must contain exactly one message.
  • The message role must be user.
  • content must contain exactly one non-empty input_text item.
  • content may contain up to 200 unique input_file items.
  • Each input_file must reference a valid, unexpired file identifier owned by the same account.
  • For the first response, provide at least one input_file or at least one project identifier in report.project_ids.

For a follow-up response, input can be a string and no new file or project is required.

JSON
{
  "model": "deepseek-flash",
  "background": true,
  "previous_response_id": "resp_1234567890abcdef",
  "input": "Which of these risks should we address first?"
}

Report configuration

ParameterTypeRequiredDescription
project_idsArray of stringsNoUnique Continua AI project identifiers to include as sources.
findings_criteriaStringNoCriteria used to select relevant findings.
composition_criteriaStringNoInstructions for organizing and presenting the response.
guardrail_modeStringNoValidation level: off, lite, or strict.

Each referenced project must belong to the authenticated account and contain at least one document that has finished processing.

Python
from uuid import uuid4

response = client.responses.create(
    model="deepseek-flash",
    background=True,
    input="Identify the most material risks in this project.",
    extra_body={
        "report": {
            "project_ids": ["project_1234567890abcdef"],
            "findings_criteria": "Material risks supported by source evidence",
            "composition_criteria": "Present a concise, prioritized report",
            "guardrail_mode": "lite",
        }
    },
    extra_headers={"Idempotency-Key": f"project-{uuid4().hex}"},
)

Idempotency

An idempotency key must contain 1 to 255 visible ASCII characters. Use a new key for every new response, and reuse the same key only when retrying an identical request.

Create response payload

JSON
{
  "id": "resp_1234567890abcdef",
  "object": "response",
  "created_at": 1789344000,
  "status": "queued",
  "previous_response_id": null,
  "background": true,
  "output_text": "",
  "output": [],
  "error": null
}

The create response is not the final result. Save id and retrieve the response until it reaches a terminal status.

Retrieve a response

Retrieves the current state and result of a response.

GET/responses/{response_id}
Bash
curl \
  "${CONTINUA_AI_API_BASE_URL}/responses/${RESPONSE_ID}" \
  --header "Authorization: Bearer ${CONTINUA_AI_API_KEY}"

Status values

StatusMeaning
queuedAccepted and waiting to run.
in_progressCurrently running.
completedFinished successfully. The result is available.
failedCould not be completed. See error.
cancelledCancelled before completion.

While a response is not terminal, output_text is empty and output is normally empty. The server returns a Retry-After header; wait at least that many seconds before retrieving the response again.

Completed response

JSON
{
  "id": "resp_1234567890abcdef",
  "object": "response",
  "created_at": 1789344000,
  "status": "completed",
  "previous_response_id": null,
  "background": true,
  "output_text": "The document identifies supplier concentration as its primary risk.",
  "output": [
    {
      "id": "msg_1234567890abcdef",
      "type": "message",
      "role": "assistant",
      "status": "completed",
      "content": [
        {
          "type": "output_text",
          "text": "The document identifies supplier concentration as its primary risk.",
          "annotations": [],
          "logprobs": []
        }
      ]
    }
  ],
  "report": {
    "findings": [
      {
        "finding_index": 1,
        "record_id": "record_1234567890abcdef",
        "claim": "The company relies on one supplier for most critical components.",
        "quote": "Our primary supplier provides most critical components.",
        "document": "report.pdf",
        "position": "p.12",
        "relevance": 0.97,
        "confidence": 0.94,
        "evidence": 0.91,
        "materiality": 0.89
      }
    ],
    "billing": {
      "billing": "charged",
      "charged": 0.42,
      "metered": 0.42,
      "llm_cost": 0.31,
      "platform_fee": 0.11
    }
  },
  "error": null
}

Response fields

FieldTypeDescription
idStringResponse identifier.
objectStringAlways response.
created_atIntegerCreation time as a Unix timestamp in seconds.
modelStringModel used for the response.
statusStringCurrent response status.
previous_response_idString or nullParent response identifier for a follow-up.
backgroundBooleanAlways true.
output_textStringComplete generated answer when status is completed.
outputArrayGenerated messages in Responses API format.
reportObjectFindings and billing details, available after completion.
errorObject or nullFailure details when status is failed.

Finding fields

FieldTypeDescription
finding_indexIntegerOne-based finding number.
record_idStringFinding record identifier.
claimStringFinding or conclusion supported by the source.
quoteStringSupporting source text, when available.
documentStringSource document or source URL, when available.
positionStringPage or paragraph location, when available.
relevanceNumberRelevance score from 0 to 1, when available.
confidenceNumberConfidence score from 0 to 1, when available.
evidenceNumberEvidence strength score from 0 to 1, when available.
materialityNumberMateriality score from 0 to 1, when available.

Continue a response

To ask a follow-up question, create another response and set previous_response_id to the latest completed response identifier. Every follow-up creates a new response identifier. The parent response must be completed; a parent that is still queued or in_progress returns HTTP 409 with code response_not_complete.

Python

Python
import time
from uuid import uuid4

follow_up = client.responses.create(
    model="deepseek-flash",
    background=True,
    previous_response_id=response.id,
    input="Give me one concise recommendation based on the findings.",
    extra_headers={"Idempotency-Key": f"follow-up-{uuid4().hex}"},
)

while follow_up.status not in {"completed", "failed", "cancelled"}:
    time.sleep(5)
    follow_up = client.responses.retrieve(follow_up.id)

if follow_up.status != "completed":
    raise RuntimeError(f"Follow-up ended with status={follow_up.status}")

print(follow_up.output_text)

Node.js

TypeScript
import { randomUUID } from "node:crypto";

let followUp = await client.responses.create(
  {
    model: "deepseek-flash",
    background: true,
    previous_response_id: response.id,
    input: "Give me one concise recommendation based on the findings.",
  },
  { headers: { "Idempotency-Key": `follow-up-${randomUUID()}` } },
);

while (!["completed", "failed", "cancelled"].includes(followUp.status)) {
  await new Promise((resolve) => setTimeout(resolve, 5000));
  followUp = await client.responses.retrieve(followUp.id);
}

if (followUp.status !== "completed") {
  throw new Error(`Follow-up ended with status=${followUp.status}`);
}

console.log(followUp.output_text);

A follow-up may contain text only; you do not need to upload the original files again. Use the newest completed response identifier for each subsequent follow-up.

List responses

Returns responses for the authenticated account, newest first.

GET/responses

Query parameters

ParameterTypeRequiredDescription
limitIntegerNoNumber of responses to return, from 1 to 25. Defaults to 25.
statusStringNoComma-separated status values to include.
cursorStringNoOpaque cursor returned by the previous page.
Bash
curl \
  "${CONTINUA_AI_API_BASE_URL}/responses?limit=10&status=completed,failed" \
  --header "Authorization: Bearer ${CONTINUA_AI_API_KEY}"
JSON
{
  "responses": [
    {
      "id": "resp_1234567890abcdef",
      "object": "response",
      "status": "completed",
      "created_at": 1789344000,
      "last_updated_at": 1789344060
    }
  ],
  "next_cursor": "eyJzY2hlbWEiOiIuLi4ifQ"
}

When next_cursor is not null, pass it unchanged in the next request and keep limit and status unchanged while following a cursor.

Errors

Errors use a consistent JSON envelope.

JSON
{
  "error": {
    "message": "The response is not complete.",
    "type": "invalid_request_error",
    "param": "previous_response_id",
    "code": "response_not_complete"
  }
}

Every response includes an x-request-id header. Include this value when contacting support about a failed request.

Common errors

StatusCodeMeaning
400invalid_modelThe requested model identifier is not supported.
400missing_file_sourceA first response did not include a file or project.
400insufficient_creditsThe account does not have enough credits to create the response.
400unsupported_parameterThe request uses an unsupported option, such as streaming.
401invalid_api_keyThe bearer token is missing, invalid, disabled, or rotated.
403access_deniedThe authenticated account cannot access the requested resource.
404file_not_foundThe file does not exist or belongs to another account.
404project_not_foundThe project does not exist or belongs to another account.
404response_not_foundThe response does not exist, is no longer available, or belongs to another account.
409file_already_usedThe uploaded file was already used in another response request.
409response_not_completeA follow-up references a response that is not complete.
409idempotency_key_reusedAn idempotency key was reused with different parameters.
410file_expiredThe uploaded file has expired.
413file_too_largeThe file exceeds the account's current size limit.
415unsupported_file_typeThe file extension is not supported.
429concurrency_limit_exceededThe account's concurrent response limit has been reached.
500server_errorThe request could not be completed because of a temporary service error.

Retry guidance

  • Poll response status no more frequently than directed by the Retry-After header. When the header is unavailable, wait at least five seconds.
  • For HTTP 429, wait for the duration specified by Retry-After before retrying.
  • For temporary HTTP 500 errors, retry with exponential backoff and random jitter.
  • If a create request times out, retry with the same Idempotency-Key and the exact same request body.
  • Do not retry other 400, 401, 403, 404, 409, 410, or 415 errors without correcting the request or application state.

Integration checklist

  • Keep the API token on your server.
  • Use the /api/v1 base URL exactly once.
  • Use a full model identifier, or auto.
  • Include a unique idempotency key for every new response.
  • Save every returned response identifier.
  • Poll until a terminal status is reached and honor Retry-After.
  • Handle failed and cancelled responses explicitly.
  • Upload a file again if its identifier has expired or has already been used.
  • Use the latest completed response identifier for follow-up questions.

Start building with Continua AI

Create an account to generate an API token, or read the Help Center for guidance on criteria, guardrails, and Projects.