Skip to content

kvick api

Kvick API

Ask Kvick questions about a text or any JSON, and get the probability of every possible answer. One endpoint, three kinds of question.

Base URL
https://api.skena.ai, which Jev clients take as is (they add /v1/systemone)
Model
kvick-1
Auth
Authorization: Bearer skl_…, a key you make on the dashboard's API key page (one per app or server; keys)
Paid from
Skena AI credit, text only. Prices

Quickstart

Put your key in SKENA_API_KEY and ask one yes or no question:

curl https://api.skena.ai/v1/systemone \
  -H "Authorization: Bearer $SKENA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "kvick-1",
    "state": "My card was charged twice, please refund one.",
    "questions": {
      "refund": {
        "type": "noul",
        "instructions": "Is the customer asking for money back?"
      }
    }
  }'

The answer comes back under the question's id. noul is the probability of yes:

200 OK
{
  "model": "kvick-1",
  "answers": {
    "refund": {
      "type": "noul",
      "noul": 0.97,
      "stats": {}
    }
  },
  "usage": {
    "input_tokens": 151,
    "output_tokens": 1
  }
}

The request

POST/v1/systemone

One request carries one state and as many questions about it as fit the limits below. Kvick reads the state once and answers every question against it: ten questions in one request read the state once, where ten requests read it ten times.

  • Field
    modelrequired
    Type
    string
    Description
    Send "kvick-1", the one model today. The answer names the model that answered.
  • Field
    staterequired
    Type
    string, object or array
    Description
    What the questions are about: a text, or any JSON (an email with its headers, a form, a list of rows). Images go inside it.
  • Field
    questionsrequired
    Type
    object
    Description
    At least one question, keyed by an id you choose. Each answer comes back under the same id.

Questions

  • Field
    typerequired
    Type
    "noul", "choice" or "score"
    Description
    Yes or no, multiple choice, or a rating.
  • Field
    instructions
    Type
    string, number, boolean, object, array or null
    Description
    The question itself, usually a string. A choice whose options say everything can leave it out.
  • Field
    criteria
    Type
    depends on type
    Description
    What the possible answers mean: see the three types below. Required for choice and score.

Each question has a type:

  • type
    noul
    Asks
    Yes or no
    criteria
    Optional. An object with a true and/or false description, when yes and no need defining.
    Answers with
    noul: the probability of yes, from 0 to 1.
  • type
    choice
    Asks
    Multiple choice
    criteria
    Required. An object of option name to description (null when the name says it all), 1 to 255 options.
    Answers with
    choice: the likeliest option; probabilities: every option's probability; confidence: 0 for a coin toss, 1 for certainty.
  • type
    score
    Asks
    Rating
    criteria
    Required. An array of 2 to 10 level descriptions, lowest first. A level's number is its position, counting from 0.
    Answers with
    score: the expected level (it can fall between levels); probabilities and legend, keyed by level number; confidence.

A full example

One question of each type about the same message:

request body
{
  "model": "kvick-1",
  "state": "My card was charged twice, please refund one.",
  "questions": {
    "refund": {
      "type": "noul",
      "instructions": "Is the customer asking for money back?"
    },
    "department": {
      "type": "choice",
      "criteria": {
        "billing": null,
        "technical": null,
        "sales": null
      }
    },
    "frustration": {
      "type": "score",
      "instructions": "How frustrated is the customer?",
      "criteria": [
        "calm",
        "mildly annoyed",
        "annoyed",
        "frustrated",
        "furious"
      ]
    }
  }
}
200 OK
{
  "model": "kvick-1",
  "answers": {
    "refund": {
      "type": "noul",
      "noul": 0.97,
      "stats": {}
    },
    "department": {
      "type": "choice",
      "choice": "billing",
      "confidence": 0.93,
      "probabilities": {
        "billing": 0.95,
        "technical": 0.03,
        "sales": 0.02
      },
      "stats": {}
    },
    "frustration": {
      "type": "score",
      "score": 1.64,
      "confidence": 0.45,
      "legend": {
        "0": "calm",
        "1": "mildly annoyed",
        "2": "annoyed",
        "3": "frustrated",
        "4": "furious"
      },
      "probabilities": {
        "0": 0.08,
        "1": 0.35,
        "2": 0.44,
        "3": 0.11,
        "4": 0.02
      },
      "stats": {}
    }
  },
  "usage": {
    "input_tokens": 214,
    "output_tokens": 3
  }
}

The probabilities in these examples are illustrative.

Answers

Every answer carries its type and the fields for that type. Probabilities and confidence have two decimals. stats is empty.

  • type
    noul
    Fields
    noul: the probability of yes, from 0 to 1.
  • type
    choice
    Fields
    choice: the likeliest option; probabilities: every option's probability; confidence: 0 for a coin toss, 1 for certainty.
  • type
    score
    Fields
    score: the expected level (it can fall between levels); probabilities and legend, keyed by level number; confidence.

usage reports what the call read and scored: see What counts below.

What counts

  • usage.input_tokens is what Kvick read: the state, every question and the format around them, and from Kvick's next release the tokens its images became (counted once, however many questions). With images, usage.image_tokens says how many of input_tokens the images took. usage.output_tokens is the number of answer steps it scored: one per question, a few more for a choice with over 26 options.
  • From Kvick's next release, an image is charged by the tokens Kvick really reads it as, at $0.10 per million. Each image token is charged at the text price times the image weight, today 440% (an image token counts as 4.4 text tokens): measured on Kvick's GPU, an image token takes about that much more time than a text token. Before the call runs, each image holds 65,536 tokens' worth of credit ($0.0288); the charge never goes above the hold.
  • A refusal from Skena Cloud (an error.code) costs nothing and does not count against the welcome gift's day. That includes a request Kvick cannot answer (400 invalid-decision-request): it is refused before it runs.
  • A call Kvick answered is charged for its input tokens, at $0.10 per million; output is free. On the welcome gift its input and output tokens also count against the day.
  • A call Kvick could not answer (it was busy or failed) costs nothing, and is given back to the welcome gift's day.
  • Only an answer is charged. If your connection drops before Kvick's answer reaches Skena Cloud, the call costs nothing and you get no answer: send it again.

Images

Images on the API come with Kvick's next release, paid from credit per image token. Until then, a request with an image in state is refused before it runs with 400 invalid-decision-request, and costs nothing.

From that release, put an image anywhere in state as {"type": "image", "url": "data:image/…;base64,…"}, beside any text or JSON about it. The object must have exactly those two keys: with any other key it is read as plain JSON text. Kvick reads the images first, then the rest of the state.

request body, from Kvick's next release
{
  "model": "kvick-1",
  "state": {
    "receipt": {
      "type": "image",
      "url": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ..."
    },
    "note": "Lunch with a customer, paid by card."
  },
  "questions": {
    "is_receipt": {
      "type": "noul",
      "instructions": "Is the image a receipt?"
    },
    "over_100": {
      "type": "noul",
      "instructions": "Is the total more than 100?"
    }
  }
}
  • Base64 data URLs only (data:image/png;base64,…, JPEG, WebP and the like). Links are refused, never fetched.
  • Up to 8 images per request, each at most 10 MiB decoded and 40 megapixels, inside the 24 MiB body.
  • Charged by the tokens Kvick really reads the image as, at $0.10 per million. Each image token is charged at the text price times the image weight, today 440% (an image token counts as 4.4 text tokens): measured on Kvick's GPU, an image token takes about that much more time than a text token.
  • Each image holds 65,536 tokens' worth ($0.0288) before the call runs, and the charge never goes above the hold. The answer's usage.image_tokens says how many of input_tokens the images took.
  • An image that breaks these rules is refused with 422 image_rejected, which costs nothing.
  • Inside Skena Builder and Skena Servant, a Skena AI subscription's Kvick images count the same weighted tokens against the daily token limit from that release.

Limits

  • The state plus the longest question: at most 32,768 tokens. The state plus every question: at most 65,536 tokens.
  • A choice takes 1 to 255 options; a rating 2 to 10 levels.
  • At most 1,024 scored steps per request: one per question, a few more for a choice with over 26 options.
  • A request past any of these is refused before it runs with 400 invalid-decision-request.
  • The request body: at most 24 MiB, with its length declared in Content-Length (no chunked uploads). Every common HTTP client does this for a JSON body.
  • On credit from Skena: no daily limit and no per-account bound on requests at a time, up to 120 credit calls a minute (Kvick and Klok together).
  • On the welcome gift alone: 5,000 requests and 5,000,000 tokens (input plus output) per account per UTC day, 2 requests in flight or waiting at a time, and 5,000 credit calls in 24 hours.
  • When Skena Cloud is full, a call waits up to 10 seconds for room before 503 labs-busy.

Errors

Two shapes reach you. Skena Cloud's refusals carry error.code; Kvick's own carry detail, in the Jev API's shapes.

From Skena Cloud

429 Too Many Requests
{
  "error": {
    "message": "daily-limit-reached",
    "type": "skena_labs_error",
    "code": "daily-limit-reached"
  }
}
  • Status
    400
    error.code
    invalid-decision-request
    Meaning
    Kvick cannot answer the request: a field is wrong, it is too long, or (until Kvick's next release) it holds an image. Refused before it runs, so it costs nothing.
    What to do
    Check the request against the rules on this page: Kvick's own field-by-field reason is not passed on.
  • Status
    400
    error.code
    unreadable-body
    Meaning
    The body could not be read.
    What to do
    Send the whole body again.
  • Status
    400
    error.code
    invalid-credit-request-id
    Meaning
    The Idempotency-Key header is longer than 128 bytes, or holds a line break or a NUL.
    What to do
    Send a shorter key.
  • Status
    401
    error.code
    invalid-labs-key
    Meaning
    No key, a malformed key, a revoked key, or a device key from Skena Builder or Skena Servant (the API takes Skena API keys only).
    What to do
    Use a key from your dashboard's API key page, or make a new one there.
  • Status
    402
    error.code
    ai-credit-insufficient
    Meaning
    Your credit does not cover this call.
    What to do
    Check your balance on the dashboard's Skena AI page.
  • Status
    402, 403
    error.code
    ai-credit-unavailable
    Meaning
    Nothing is left to pay for the call: the welcome gift is used up or expired, and the account has no other credit (403 while the welcome gift is paused).
    What to do
    Check your balance on the dashboard's Skena AI page.
  • Status
    403
    error.code
    ai-credit-required
    Meaning
    The account has no Skena AI credit. The API is paid from credit alone, whatever plan the account has.
    What to do
    Check your balance on the dashboard's Skena AI page.
  • Status
    403
    error.code
    ai-credit-activation-required
    Meaning
    Only the welcome gift is left, and no computer has activated it yet. Skena Cloud refuses before reading the body, so these calls cost nothing.
    What to do
    Sign in to Skena Builder or Skena Servant on a computer once, and connect Skena AI.
  • Status
    403
    error.code
    account-unverified
    Meaning
    The account's email is not verified.
    What to do
    Verify your email.
  • Status
    403
    error.code
    account-suspended
    Meaning
    The account is suspended.
    What to do
    Contact us.
  • Status
    409
    error.code
    inference-request-already-recorded
    Meaning
    The call reused an Idempotency-Key this account already sent, whatever happened to that first call.
    What to do
    Nothing ran or was charged again. The 409 does not repeat the first answer: to retry a call that failed, send a new key.
  • Status
    411
    error.code
    length-required
    Meaning
    The body did not declare its length (a chunked upload), or it is empty.
    What to do
    Send the JSON body with a Content-Length header.
  • Status
    413
    error.code
    request-too-large
    Meaning
    The body is over the 24 MiB limit.
    What to do
    Send a smaller state.
  • Status
    429
    error.code
    too-many-concurrent-requests
    Meaning
    On the welcome gift: more than 2 calls in flight or waiting on this account, or its calls together hold more than a third of Skena Cloud's room.
    What to do
    Wait for one to finish (Retry-After).
  • Status
    429
    error.code
    daily-limit-reached
    Meaning
    On the welcome gift: 5,000 requests today.
    What to do
    Retry-After says when the day resets, at 00:00 UTC.
  • Status
    429
    error.code
    daily-token-limit-reached
    Meaning
    On the welcome gift: 5,000,000 tokens today.
    What to do
    Retry-After says when the day resets, at 00:00 UTC.
  • Status
    429
    error.code
    inference-attempt-limit
    Meaning
    Calls paid from credit, Kvick and Klok together: over 120 in the last minute (on the welcome gift, also 5,000 in the last 24 hours).
    What to do
    Retry after the Retry-After seconds.
  • Status
    503
    error.code
    labs-busy
    Meaning
    Skena Cloud was full and the call waited 10 seconds for room.
    What to do
    Retry after a short delay (Retry-After).
  • Status
    503
    error.code
    labs-not-serving
    Meaning
    Kvick is not serving right now.
    What to do
    Retry later.
  • Status
    503
    error.code
    credit-quote-unavailable
    Meaning
    Skena Cloud could not price the call before running it.
    What to do
    Retry after a short delay.
  • Status
    503
    error.code
    labs-store-unavailable
    Meaning
    A temporary problem on our side.
    What to do
    Retry after a short delay.
  • Status
    503
    error.code
    labs-cache-isolation-unavailable
    Meaning
    A temporary problem on our side.
    What to do
    Retry after a short delay.
  • Status
    503
    error.code
    labs-upstream-unavailable
    Meaning
    Kvick could not be reached.
    What to do
    Retry after a short delay (Retry-After).
  • Status
    500
    error.code
    labs-upstream-auth
    Meaning
    Skena Cloud could not sign in to Kvick: our problem, not your key.
    What to do
    Retry later.
  • Status
    500
    error.code
    labs-upstream-response
    Meaning
    Kvick's answer was unreadable or too large to relay.
    What to do
    Retry; if it persists, ask fewer questions per request.

A request that breaks a rule, such as a rating with one level, is refused before it runs:

request body
{
  "model": "kvick-1",
  "state": "My card was charged twice, please refund one.",
  "questions": {
    "frustration": {
      "type": "score",
      "criteria": [
        "calm"
      ]
    }
  }
}
400 Bad Request
{
  "error": {
    "message": "invalid-decision-request",
    "type": "skena_labs_error",
    "code": "invalid-decision-request"
  }
}

From Kvick

  • Status
    422
    detail
    detail[]
    Meaning
    Kvick's engine refused a request that passed Skena Cloud's check: rarely engine_rejected, and from Kvick's next release image_rejected for an image it cannot read. Each entry names the field (loc), what is wrong (msg) and a type. It costs nothing.
    What to do
    Fix the named field or image; if it looks right, tell us when it happened.
  • Status
    429
    detail
    detail
    Meaning
    Too many of your calls are already waiting in Kvick's own queue.
    What to do
    Retry after the Retry-After seconds.
  • Status
    503
    detail
    detail
    Meaning
    Kvick's own queue is full, or the call waited its 30 seconds there.
    What to do
    Retry after the Retry-After seconds.
  • Status
    529
    detail
    overloaded_error
    Meaning
    The decision engine is temporarily unavailable.
    What to do
    Retry after a short delay (Retry-After).
  • Status
    500
    detail
    internal_error
    Meaning
    Something failed inside Kvick.
    What to do
    Retry; if it persists, tell us when it happened.

Headers

Besides Authorization and Content-Type, a request may send:

  • Header
    Idempotency-Key
    Meaning
    Optional: up to 128 bytes, a new one for each call. A call that reuses a key answers 409 inference-request-already-recorded and is neither run nor charged, so an automatic retry can never charge a call twice. The 409 does not repeat the first answer.

Response headers worth reading:

  • Header
    X-Decide-Request-Id
    Meaning
    Kvick's id for the call (req_…), on its answers. Quote it when you report a problem.
  • Header
    X-Skena-Usage-Id
    Meaning
    The call's entry in your credit history, once Skena Cloud has priced the call and set its cost aside.
  • Header
    Retry-After
    Meaning
    Seconds to wait before retrying: on every 429, on labs-busy and labs-upstream-unavailable, and on Kvick's own 503 and 529.

Calling it well

  • Ask several questions about one state in one request: Kvick reads the state once and answers every question against it.
  • Make one key per app or server, and keep keys on your server: anyone with one can spend your account's credit, on Klok as well as Kvick. Revoke a key that leaks, and the others keep working.
  • Set your own thresholds: a probability is more useful than a yes, so act on 0.9 where a mistake is costly and on 0.5 where it is not.
  • Retry 429, 503 and 529 after the Retry-After seconds, and treat a 500 as temporary. Send each retry with a new Idempotency-Key.

Models

GET/v1/models

Lists every model your key can call, in one answer with two shapes: OpenAI's data (what OpenAI's SDKs read) and the Jev API's models (what Jev clients read, Kvick only). A model is listed only while Skena Cloud serves it.

200 OK
{
  "object": "list",
  "data": [
    {
      "id": "klok-1",
      "object": "model",
      "owned_by": "skena",
      "name": "Skena Klok",
      "context_window": 262144
    },
    {
      "id": "kvick-1",
      "object": "model",
      "owned_by": "skena",
      "name": "Skena Kvick"
    }
  ],
  "models": [
    {
      "name": "kvick-1",
      "description": "Skena Kvick: calibrated System One decisions (Jev-compatible)."
    }
  ]
}

It needs a valid key on an account with credit, and never wakes a model. Its refusals use the skena_inference_error envelope, for Kvick too.

Jev compatibility

Kvick speaks the Jev API: the same POST /v1/systemone request and the same answer shapes, and Kvick's own refusals use the Jev API's error shapes. Code written for Jev works by pointing it at https://api.skena.ai (Jev clients add /v1/systemone) with your key, and sending "model": "kvick-1". Skena Cloud's refusals (a key, credit, a limit) use their own error envelope.

Jev and TypeSafe are trademarks of their owners. Skena Labs is not affiliated with TypeSafe or Bespoke Labs.

OpenAPI

The same reference, machine-readable, for code generators, API clients and coding agents:

https://skena.ai/docs/kvick/openapi.json

  • Kvick is a Skena Labs model: there is no uptime guarantee yet, and the API may change.
  • Please do not send personal or sensitive data.