API reference
Base URL: http://<host>:8797. Every /v1 route except sign-up needs Authorization: Bearer <key>, and every POST Content-Type: application/json. Bodies are capped at 1 MB (16 MB for /v1/batches and /v1/golden). Duplicate JSON keys are rejected. Connections stay open between requests (HTTP/1.1).
POST /v1/systemone
Request:
| Field | Type | Meaning |
|---|---|---|
state | string, object or array (required) | what to evaluate; see State for how much of it the engine reads |
questions | object of question id to question (required) | at least one |
model | string | a name from /v1/models, or this tenant's fine-tuned jers-ft-*; default jers |
subject | string, 1 to 36 of A-Za-z0-9_- | use this subject's memory and rules |
memory | object | use (default true with a subject), top_k (1 to 20, default 6), min_share (0.05 to 1, default 0.2), compare (default false), placebo (default false) |
robust | true or {"orders": 1-5} | ask each choice of 2 to 20 options in several option orders and average them; true is 3. A choice of more than 20 options is answered in two rounds instead and is not reordered |
windows | true or {"combine": {"question_id": "max" | "min" | "mean"}} | read a state that is cut in overlapping windows (32 tokens shared), at most 16 |
derive | object, at most 20 names | facts computed in code: {"name": "expression"} or {"name": {"when": "expression", "fact": "text", "else": "text"}}; a name starts with a letter and has at most 40 letters, digits or underscores; an expression has at most 300 characters, a fact at most 500 |
values | object, at most 50 fields | numbers and text that derive and rules may use; today sets the date days_since counts from |
cache | boolean | an identical request that does not use a subject's memory returns the stored answers |
Questions: {"type": "choice", "instructions", "criteria": {name: description}} with 1 to 255 options (more than 20 are answered in two rounds); {"type": "score", "instructions", "criteria": [level, ...]} with 2 to 10 levels, lowest first; {"type": "noul", "instructions", "criteria"?: {"true", "false"}}. instructions and descriptions may be strings, objects or arrays. A request may need at most 400 engine questions, counting every option order, every group of a two-round choice and its final round. context is not accepted: Jers builds it from the subject's memory and derive.
Response:
| Field | Meaning |
|---|---|
decision_id | dec_ and 24 hex digits; send it back with /v1/feedback. The state is never stored |
model | the name asked for, aliases resolved |
engine | name, checkpoint (the one that answered), runtime |
answers | per question, each with type, confidence and the engine's action. choice: choice, probabilities; rounds and groups above 20 options; orders and agreement with robust. score: score (probability-weighted level), probabilities, legend. noul: noul (probability of yes). With a tenant temperature: calibration and the raw_ values before it. With windows: window |
warnings | known traps in this request: {code, message, question?}; see Warnings |
reading | per question: state_tokens, read, room, chars_read, truncated (counted on the state with memory and computed lines in front); context_lines_read when such lines were placed; windows when windows read the whole state |
derived | the value of every derive name |
memory | with a subject: subject, lines_used (fired rules and recalled lines sent to the engine), lines_seen (how many of them it read), lines_dropped (left out of its 64 context lines), hits, rules_fired, rules_broken, recall_ms, without_memory and changes (with compare, otherwise null), placebo (with placebo) |
windows | when the state was read in windows: count, covered_all (whether the windows reached the end of the state), state_tokens, tokens_per_window; each answer's window names the window it came from (null with mean) |
usage | questions, answers, answers_billed, engine_answers, input_characters, input_tokens (when the engine counted them), state_tokens, state_tokens_read, state_truncated, memory_lines_used, memory_lines_seen, cached, engine_ms, gateway_ms, cost, currency, balance. answers_billed is the sum over questions of the option orders used (1 without robust) × windows × passes (2 with placebo; compare is free) |
Memory
| Route | Body or query | Response |
|---|---|---|
POST /v1/memory/remember | subject, text (one fact per line, each at most 2,000 characters; a subject holds at most 10,000 lines) | lines_added, lines_stored, warnings, usage |
POST /v1/memory/forget | subject, concept | lines_removed, rules_removed, verified_forgotten, leaks, usage |
POST /v1/memory/delete | subject | lines_removed (lines that were in RAM), usage; the lines and rules on disk go too |
GET /v1/memory | subject, lines=true | lines_stored, rules; with lines=true also lines and rule_list (id, when, text, expires_at), word for word |
POST /v1/memory/rules | subject, when (at most 300 characters), text (at most 500), expires (ISO date or time) or ttl_seconds (at most ten years); at most 100 rules per subject | rule (with expires_at), rules (how many), usage; billed as one memory line |
GET /v1/memory/rules | subject | rules |
POST /v1/memory/rules/delete | subject, rule_id | deleted, rules |
Labels and quality
| Route | Body or query | Response |
|---|---|---|
POST /v1/feedback | decision_id, question, correct (an option, a level, or true/false) | label, correct, labels_for_this_question; calibration_refit at 50, 100, 200 … labels |
GET /v1/quality | question, days (default 30), model, source (feedback or golden) | per question and model: labels, accuracy, calibration_error, brier, log_loss, bands, automate_at |
POST /v1/calibration/fit | model, question, source, min_labels (at least 20, default 50) | results: per question, and per group of questions with the same type and number of options, the fitted temperature and whether it was kept |
GET /v1/calibration | temperatures in use | |
POST /v1/golden | cases: {id, state, questions, expected, subject?, values?, derive?, memory?, robust?, windows?}; id is 1 to 64 characters, and a case with an existing id replaces it | added, cases (at most 5,000 per tenant) |
GET /v1/golden | count, cases (ids, questions, expected), runs | |
POST /v1/golden/run | model (default jers) | run_id, cases, accuracy, questions, changed_since_last_run (null on a model's first run); billed like decisions; a case that fails, or is not run because the credit ran out, is left out |
POST /v1/golden/delete | {"ids": [...]}, or {} for every case (an empty list deletes nothing) | deleted |
POST /v1/decisions/delete | {} | decisions_deleted (question records), labels_deleted: every stored decision record and label of the tenant |
Decision records (the decision id, question ids and a hash of each question, the probabilities before and after calibration; never the state or the question text) are kept 30 days.
Batches
| Route | Body | Response |
|---|---|---|
POST /v1/batches | {"requests": [...]}, or JSON Lines with Content-Type: application/x-ndjson; each request a /v1/systemone body with an optional custom_id; at most 5,000 | the job: id, status, total |
GET /v1/batches | batches | |
GET /v1/batches/<id> | status (queued, running, done, stopped: no credit left, or failed with error when the job itself broke), total, done, succeeded, failed, cost | |
GET /v1/batches/<id>/results | JSON Lines: custom_id, status, response or error, in the order sent |
Account
| Route | Response |
|---|---|
GET /v1/models | models (name, engine, checkpoint, description, available, pinned; this tenant's fine-tuned jers-ft-* models also carry fine_tuned: true), default, aliases |
GET /v1/usage | credited, spent, balance, requests, rate_limit_per_minute, prices, totals, recent (last 20 ledger lines), keys |
POST /v1/signup (no key) | email, invite_code when the gateway asks for one → tenant, key (shown once), key_id, credit, currency, note. Off unless the owner turns it on; by default 3 sign-ups per address a day, and the new key gets 60 requests per minute |
No key needed
GET /health (whether the gateway, the memory service and the engine are up, and the engine's code hash; nothing about tenants or subjects), GET / (a how-to), GET /playground, GET /docs, GET /docs/<page>.md, GET /llms.txt.
Errors
{"error": {"type": "...", "message": "..."}}
| Status | Type | When |
|---|---|---|
| 400 | invalid_request_error | a Content-Length that is not a number |
| 401 | authentication_error | no key, unknown key, revoked key |
| 402 | payment_required | the tenant's balance is zero or below |
| 403 | signup_disabled, invite_required | sign-up is off, or needs an invite code |
| 404 | not_found | unknown route, page, batch, or a decision id of another tenant |
| 409 | conflict | a limit: 5,000 golden cases for a tenant, 10,000 memory lines or 100 rules for a subject; nothing was stored |
| 413 | invalid_request_error | body over the cap |
| 415 | invalid_request_error | not application/json (or JSON Lines for batches) |
| 422 | invalid_request_error | the reason is in the message: bad question, unknown model, bad subject id, a derive or when expression that is not allowed |
| 429 | rate_limit_error | over the key's requests per minute, or too many sign-ups; Retry-After in seconds |
| 500 | server_error | the gateway failed; the message names only the error type, and nothing was charged |
| 502 | engine_error | the engine or the product behind the gateway is down or answered an error; nothing was charged (a proxy in front of the gateway may answer 503 for the same) |
Retry 429 after Retry-After, and 502 or 503 with backoff. The SDKs do both, and never send a decision again once it may have arrived.