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:

FieldTypeMeaning
statestring, object or array (required)what to evaluate; see State for how much of it the engine reads
questionsobject of question id to question (required)at least one
modelstringa name from /v1/models, or this tenant's fine-tuned jers-ft-*; default jers
subjectstring, 1 to 36 of A-Za-z0-9_-use this subject's memory and rules
memoryobjectuse (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)
robusttrue 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
windowstrue or {"combine": {"question_id": "max" | "min" | "mean"}}read a state that is cut in overlapping windows (32 tokens shared), at most 16
deriveobject, at most 20 namesfacts 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
valuesobject, at most 50 fieldsnumbers and text that derive and rules may use; today sets the date days_since counts from
cachebooleanan 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:

FieldMeaning
decision_iddec_ and 24 hex digits; send it back with /v1/feedback. The state is never stored
modelthe name asked for, aliases resolved
enginename, checkpoint (the one that answered), runtime
answersper 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
warningsknown traps in this request: {code, message, question?}; see Warnings
readingper 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
derivedthe value of every derive name
memorywith 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)
windowswhen 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)
usagequestions, 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

RouteBody or queryResponse
POST /v1/memory/remembersubject, 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/forgetsubject, conceptlines_removed, rules_removed, verified_forgotten, leaks, usage
POST /v1/memory/deletesubjectlines_removed (lines that were in RAM), usage; the lines and rules on disk go too
GET /v1/memorysubject, lines=truelines_stored, rules; with lines=true also lines and rule_list (id, when, text, expires_at), word for word
POST /v1/memory/rulessubject, 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 subjectrule (with expires_at), rules (how many), usage; billed as one memory line
GET /v1/memory/rulessubjectrules
POST /v1/memory/rules/deletesubject, rule_iddeleted, rules

Labels and quality

RouteBody or queryResponse
POST /v1/feedbackdecision_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/qualityquestion, 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/fitmodel, 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/calibrationtemperatures in use
POST /v1/goldencases: {id, state, questions, expected, subject?, values?, derive?, memory?, robust?, windows?}; id is 1 to 64 characters, and a case with an existing id replaces itadded, cases (at most 5,000 per tenant)
GET /v1/goldencount, cases (ids, questions, expected), runs
POST /v1/golden/runmodel (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

RouteBodyResponse
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,000the job: id, status, total
GET /v1/batchesbatches
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>/resultsJSON Lines: custom_id, status, response or error, in the order sent

Account

RouteResponse
GET /v1/modelsmodels (name, engine, checkpoint, description, available, pinned; this tenant's fine-tuned jers-ft-* models also carry fine_tuned: true), default, aliases
GET /v1/usagecredited, 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": "..."}}

StatusTypeWhen
400invalid_request_errora Content-Length that is not a number
401authentication_errorno key, unknown key, revoked key
402payment_requiredthe tenant's balance is zero or below
403signup_disabled, invite_requiredsign-up is off, or needs an invite code
404not_foundunknown route, page, batch, or a decision id of another tenant
409conflicta limit: 5,000 golden cases for a tenant, 10,000 memory lines or 100 rules for a subject; nothing was stored
413invalid_request_errorbody over the cap
415invalid_request_errornot application/json (or JSON Lines for batches)
422invalid_request_errorthe reason is in the message: bad question, unknown model, bad subject id, a derive or when expression that is not allowed
429rate_limit_errorover the key's requests per minute, or too many sign-ups; Retry-After in seconds
500server_errorthe gateway failed; the message names only the error type, and nothing was charged
502engine_errorthe 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.