Skip to content

Completion

POST /v1/completion is the engine's front door. You give it an input and a mode; it enqueues a run and returns a job envelope. The run itself is asynchronous — read the result from /v1/jobs/{id}.


POST /v1/completion

Enqueue an engine run. Returns a pending JobStatus with an id of the form job-<uuid>.

Input: prompt or messages

Provide exactly one of these (supplying both or neither is a 422):

Field Type Description
prompt string A single instruction or question. Up to 500,000 characters.
messages array An OpenAI-format chat history — a list of { "role", "content" } turns. The last turn must be role: "user".

For messages, role is one of system, user, or assistant; the summed length of all content is capped at 500,000 characters (1–256 turns).

Body

Field Type Required Default Description
prompt string one of Single-string input (see above).
messages array one of Chat-history input (see above).
mode string Which orchestration to run. See Modes.
main string resolved The lead companion (name or cmp_<uuid>). If omitted, it is resolved from your preferences.
participants string[] conditional The companions to involve. Required for multi-persona modes unless supplied by a preference.
stream boolean false Hint that you intend to subscribe to the event stream.
settings object Per-call overrides. See Settings.
tools array Client-side tools the model may call. See Client tools.

Companions and teams

A companion is a persona; a team groups companions. List the ones you can use with GET /v1/discover, and pass their names or ids as main / participants.

Modes

Mode What it produces
answer One companion's answer.
answer_crumbs One companion's answer, deepened over internal reasoning iterations.
parallel Every participant answers independently — N responses, no synthesis.
parallel_with_main Participants answer in parallel; a lead companion synthesizes them.
panel A two-stage expert panel that converges on a synthesized answer.
discussion A moderated, multi-turn discussion ending in a summary.

Settings

settings is the single per-call override object. Every field is optional.

Field Type Description
model string Model slug for the answering personas. Must appear in GET /v1/models.
temperature number Sampling temperature, range-checked against the model's bounds.
top_p number Nucleus-sampling cutoff, range-checked against the model's bounds.
crumbs boolean Toggle the reasoning-deepening loop. answer + crumbs: true runs as answer_crumbs.
zdr boolean Per-call Zero Data Retention. When true, the run uses only non-retaining providers. Omit to inherit your account default.
web_search boolean Per-call web search. When true, personas can search the web and cite live sources. Omit to inherit your account default.

Examples

curl https://api.humx.ai/v1/completion \
  -H "Authorization: ApiKey $COMPANIONS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "prompt": "What are the trade-offs of optimistic locking?",
        "mode": "answer",
        "settings": { "temperature": 0.4 }
      }'
import os, requests

r = requests.post(
    "https://api.humx.ai/v1/completion",
    headers={"Authorization": f"ApiKey {os.environ['COMPANIONS_API_KEY']}"},
    json={
        "prompt": "What are the trade-offs of optimistic locking?",
        "mode": "answer",
        "settings": {"temperature": 0.4},
    },
)
r.raise_for_status()
job = r.json()
print(job["id"], job["status"])   # job-... pending
const res = await fetch("https://api.humx.ai/v1/completion", {
  method: "POST",
  headers: {
    Authorization: `ApiKey ${process.env.COMPANIONS_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    prompt: "What are the trade-offs of optimistic locking?",
    mode: "answer",
    settings: { temperature: 0.4 },
  }),
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const job = await res.json();
console.log(job.id, job.status); // job-... pending
interface JobStatus {
  id: string;
  kind: "completion" | "companion" | "team" | "forensics";
  status: "pending" | "running" | "complete" | "failed" | "requires_action";
  content?: unknown;
}

const res = await fetch("https://api.humx.ai/v1/completion", {
  method: "POST",
  headers: {
    Authorization: `ApiKey ${process.env.COMPANIONS_API_KEY!}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    prompt: "What are the trade-offs of optimistic locking?",
    mode: "answer",
    settings: { temperature: 0.4 },
  }),
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const job = (await res.json()) as JobStatus;

A multi-persona example — a parallel run across three companions:

{
  "prompt": "Should we adopt event sourcing for the orders service?",
  "mode": "parallel",
  "participants": ["architect", "sre", "product-lead"]
}

Response

200 — a pending job envelope. The answer arrives later via /v1/jobs/{id}.

{
  "type": "status",
  "id": "job-1a2b3c4d-...",
  "kind": "completion",
  "status": "pending",
  "mode": "answer"
}

Once complete, the same job carries a typed content keyed by shape:

{
  "id": "job-1a2b3c4d-...",
  "kind": "completion",
  "status": "complete",
  "content": {
    "shape": "answer",
    "companion": "Ada",
    "response": "Optimistic locking trades..."
  }
}

See Jobs → Result shapes for every mode's content.


Client tools

Attach a tools array to declare functions the model can call on your machine (available for answer and answer_crumbs). When the model calls one, the run pauses and hands the call back — the server never executes your tools. You run them and return the results via POST /v1/jobs/{id}/tool_outputs.

{
  "prompt": "What's in my workspace?",
  "mode": "answer",
  "tools": [
    {
      "name": "read_user_file",
      "description": "Read a file from the user's local workspace.",
      "parameters": {
        "type": "object",
        "properties": {
          "path": { "type": "string", "description": "Path relative to workspace root" }
        },
        "required": ["path"]
      }
    }
  ]
}

parameters is plain, provider-neutral JSON Schema. Bounds: up to 32 tools; each name matches ^[a-zA-Z_][a-zA-Z0-9_]*$ (1–64 chars, unique per request); parameters ≤ 16 KiB serialized. The full pause/resume loop lives on the Jobs page.

Validation

A 422 is returned before any run is enqueued when, for example:

type Trigger
prompt_or_messages Both or neither of prompt / messages supplied.
last_message_not_user The final messages turn is not role: "user".
messages_too_large Summed content exceeds 500,000 characters.
unknown_model settings.model is not in your GET /v1/models allow-list.
value_error (temperature / top_p) The value is outside the model's published range.

Insufficient balance surfaces as 402 when the run is charged.