API reference
Two endpoints, Bearer keys, JSON in and out. VAKYN MAX and open-server serve the same API, and it is compatible with TypeSafe's Jev API, so code written for Jev works once it points at VAKYN and uses a key from it.
Basics
| Topic | Details |
|---|---|
| Base URL | VAKYN MAX: https://api.vakyn.com. Self-hosted: your open-server, e.g. http://localhost:8080 (no TLS built in; put a reverse proxy in front for HTTPS) |
| Authentication | Authorization: Bearer vk_… on every request. VAKYN MAX keys come from the console; open-server keys from vakyn keys create or its dashboard. A key works only where it was made |
| Content | JSON request and response bodies, UTF-8 |
| Endpoints | POST /v1/systemone, GET /v1/models. No streaming and no batch endpoint. |
POST /v1/systemone
Answer named questions about one state.
Request body
| Field | Type | Notes |
|---|---|---|
model | string, required | jev-latest or a name from GET /v1/models; anything else is a 400 |
state | string | object | array, required | What the questions are about; not null |
questions | object, required | At least one entry: your name → a question (below). Answers come back in the same order |
| Question field | noul | choice | score |
|---|---|---|---|
type | "noul" | "choice" | "score" |
instructions | optional: string | object | array | null | same | same |
criteria | optional: { true?, false? }, each string | object | array | null | required: object of 1–255 options, name → string | object | array | null | required: array of 1–10 levels, lowest first, each string | object | array |
Fields the server does not know are ignored.
Response body
| Field | Type | Notes |
|---|---|---|
model | string | The concrete model that answered (the alias is resolved) |
answers | object | Your question names → answers, in request order |
usage.input_tokens | integer | Tokens the model read for this request |
usage.output_tokens | integer | Always 0: nothing is generated |
assets_used | null | Kept for compatibility |
| Answer | Fields |
|---|---|
noul | type, noul (probability of yes), stats |
choice | type, choice (the most likely option), confidence, probabilities (option → probability, in criteria order), stats |
score | type, score (expected level), legend ("0"… → your level descriptions, unchanged), probabilities ("0"… → probability), confidence, stats |
Probabilities, confidences and scores are rounded to two decimals. stats is always an empty object. Confidence formulas are on the Confidence page.
curl -s "https://api.vakyn.com/v1/systemone" \ -H "Authorization: Bearer $TYPESAFE_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "jev-latest", "state": { "channel": "email", "customer": { "plan": "team", "seats": 12, "months_active": 14 }, "message": "Since this morning nobody on our team can sign in. We have a client demo at 3pm." }, "questions": { "outage": { "type": "noul", "instructions": "Is the customer unable to use the product?" }, "team": { "type": "choice", "instructions": "Which team should handle this?", "criteria": { "billing": "Invoices, charges and refunds", "access": "Sign-in, passwords and permissions", "product": "Bugs and how-to questions" } }, "urgency": { "type": "score", "instructions": "How soon does this need a reply?", "criteria": [ "Can wait", "Today", "Within the hour" ] } } }'{ "model": "vakyn-fake", "answers": { "outage": { "type": "noul", "noul": 0.91, "stats": {} }, "team": { "type": "choice", "choice": "access", "confidence": 0.89, "probabilities": { "billing": 0.02, "access": 0.93, "product": 0.05 }, "stats": {} }, "urgency": { "type": "score", "score": 1.86, "legend": { "0": "Can wait", "1": "Today", "2": "Within the hour" }, "probabilities": { "0": 0.01, "1": 0.12, "2": 0.87 }, "confidence": 0.79, "stats": {} } }, "usage": { "input_tokens": 112, "output_tokens": 0 }, "assets_used": null}GET /v1/models
Lists the model that answers and the jev-latest alias that points to it. Both names are accepted in model. On api.vakyn.com it lists the model behind VAKYN MAX.
curl -s "https://api.vakyn.com/v1/models" \ -H "Authorization: Bearer $TYPESAFE_API_KEY"{ "models": [ { "name": "vakyn-fake", "description": "Deterministic fake engine for testing; answers are not meaningful.", "release_date": "2026-10-02" }, { "name": "jev-latest", "description": "Alias for vakyn-fake.", "release_date": "2026-10-02" } ]}Pricing
| VAKYN MAX | Self-hosted | |
|---|---|---|
| Input tokens | $0.0294 per million, as counted in usage.input_tokens | free |
| Output tokens | free (always 0) | free (always 0) |
| Errors | not charged: only answered calls are | free |
| Paying | a dollar balance per organization, topped up in the console; no subscription | your own hardware |
Every question in a request is answered from one reading of the state, so a request with ten questions costs little more than one with a single question. When the balance reaches zero, VAKYN MAX refuses calls with a 402 instead of running into debt; the owners of the organization get an email when the balance runs low.
Limits
| Limit | Value | Over the limit |
|---|---|---|
| State + the longest question | 32,768 tokens | 400 {"detail": {"error_type": "max_tokens_exceeded"}} |
| State + all questions | 65,536 tokens | same |
| Options in a choice | 1–255 | 400 Too many choices. Must have at most 255 choices. |
| Levels in a score | 1–10 | 400 Too many score levels. Must have at most 10 levels. |
| Requests admitted at once | open-server: --max-queue, default 32 | 429 with retry-after |
| Request body | 64 MiB | The token limits apply long before this |
Requests over a limit are rejected, never truncated: an answer is always computed on everything you sent. Tokens are counted by the model's own tokenizer; as a rough guide, English text runs at about four characters per token. Input is text only.
Errors
Errors have a JSON body with a detail field. Both SDKs raise a typed error per status and expose the body, the status and the request id.
| Status | When | detail |
|---|---|---|
| 400 | A limit is exceeded or the model is unknown; on VAKYN MAX also a body that is not JSON | A message string, or { error_type } for token limits |
| 401 | The key is missing, malformed, wrong or revoked | A message |
| 402 | VAKYN MAX only: the organization has no balance left | { error_type: "insufficient_balance", message } |
| 404 | Any other path under /v1 | Not Found |
| 422 | The body does not match the schema (open-server: or is not JSON) | A list of { type, loc, msg, … } entries |
| 429 | Every queue slot is taken | A message; wait for retry-after |
| 500 | The model failed on this request | A message |
| 502 | VAKYN MAX only: the model service sent an answer that could not be read | { error_type: "bad_gateway", message } |
| 503 | open-server: the model is still loading. VAKYN MAX: the model service is not available | A message; on VAKYN MAX { error_type: "service_unavailable", message } |
401 Unauthorized
open-server answers Missing or invalid API key and also sends WWW-Authenticate: Bearer. VAKYN MAX answers Invalid API key. Create one at https://vakyn.com/console/keys.
curl -s "https://api.vakyn.com/v1/systemone" \ -H "Content-Type: application/json" \ -d '{ "model": "jev-latest", "state": "Hello", "questions": { "greeting": { "type": "noul", "instructions": "Is this a greeting?" } } }'{ "detail": "Missing or invalid API key"}402 Payment Required
VAKYN MAX only. The organization that owns the key has no balance left, so the call is refused before it reaches the model and costs nothing. Top up or redeem a code in the console; the next call goes through. In the SDKs it arrives as an API error with status 402.
{ "detail": { "error_type": "insufficient_balance", "message": "This organization has no balance left. Top up at https://vakyn.com/console/billing." }}422 Unprocessable Entity
loc points at the offending field: ["body", "questions", "q", "score", "criteria"] means the criteria of the score question named q.
curl -s "https://api.vakyn.com/v1/systemone" \ -H "Authorization: Bearer $TYPESAFE_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "jev-latest", "questions": { "greeting": { "type": "noul" } } }'{ "detail": [ { "type": "missing", "loc": [ "body", "state" ], "msg": "Field required" } ]}400 Bad Request
curl -s "https://api.vakyn.com/v1/systemone" \ -H "Authorization: Bearer $TYPESAFE_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "jev-latest", "state": "Rate this.", "questions": { "rating": { "type": "score", "criteria": [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" ] } } }'{ "detail": "Too many score levels. Must have at most 10 levels."}curl -s "https://api.vakyn.com/v1/systemone" \ -H "Authorization: Bearer $TYPESAFE_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-4o", "state": "Hello", "questions": { "greeting": { "type": "noul", "instructions": "Is this a greeting?" } } }'{ "detail": "Unknown model 'gpt-4o'. Available models: vakyn-fake, jev-latest."}{ "detail": { "error_type": "max_tokens_exceeded" }}429 Too Many Requests
HTTP/1.1 429 Too Many Requestsretry-after: 1retry-after-ms: 1000x-typesafe-request-id: req_… {"detail": "Server is at capacity; retry after the delay in retry-after."}Headers
| Header | Direction | Meaning |
|---|---|---|
Authorization | request | Bearer vk_… |
Content-Type | request | application/json (the body is parsed as JSON either way) |
x-typesafe-request-id | response | The request id, on every response (open-server writes req_ plus 32 hex characters). Quote it when you report a problem; it is stored with each usage record |
x-vakyn-request-id | response (VAKYN MAX) | The same id |
retry-after | response (429) | Seconds to wait before retrying |
retry-after-ms | response (429) | The same delay in milliseconds |
WWW-Authenticate | response (401, open-server) | Bearer |