// models

SystemOne API

[ view markdown ]

Endpoints, request and response schemas, limits, errors, and usage for the hosted Security-One API.

The SystemOne API serves Security-One over HTTPS. The base URL is:

https://api.superagent.sh

The SystemOne API is separate from the Superagent REST API and uses its own host. Both APIs accept Superagent organization sk_live_ API keys.

Authentication

Create an organization API key in Settings, store it as SUPERAGENT_API_KEY, then send it as a bearer token on every /v1 request. Existing internal/testing Security-One keys remain supported.

curl https://api.superagent.sh/v1/systemone \
  -H "Authorization: Bearer $SUPERAGENT_API_KEY" \
  -H "Content-Type: application/json" \
  --data @request.json

Keep the key in a secret manager and out of prompts, logs, and repositories. Missing or invalid keys return 401.

Organization keys are checked directly by the hosted API on every request, without an authentication cache. A newly created key works after creation completes; a deleted key is rejected on the next lookup after deletion completes. Requests that have already authenticated can finish.

If the key-validation service is unavailable, the API fails closed with 503 and Retry-After: 1, without running inference. Retry with backoff; do not treat this as an invalid-key 401.

Endpoints

Method Path Auth Description
POST /v1/systemone Bearer Answer typed questions about one shared state
GET /models None Public model document with context length, pricing, and capacity

Classify

POST /v1/systemone

Request body

Field Type Required Description
model string No security-one (default) or security-one-latest
state string, object, or array Yes The content every question evaluates
questions object Yes 1 to 64 questions keyed by your own non-blank question IDs

Unknown fields are rejected with 422.

Question object

Field Type Required Description
type noul, choice, or score Yes The question type
instructions string Yes The question to answer about state
criteria object or array Depends on type The options to score

Each type accepts a different criteria shape:

Type criteria shape Default
noul { "true": string, "false": string } { "true": "Yes", "false": "No" }
choice Object with 2 to 16 non-blank keys. Each value is a description string or null to use the key Required
score Array of 2 to 16 level descriptions, lowest first Required

Response body

Field Type Description
model string The model ID from the request
answers object One answer per question ID
usage.input_tokens integer Input tokens processed, including the shared state
usage.output_tokens integer Decision tokens produced

Each answer includes type and the fields for that type:

Type Field Type Description
noul noul number, 0 to 1 Probability that the true criterion applies
choice choice string Option key with the highest probability
choice probabilities object Probability for every option key
choice confidence number, 0 to 1 1 minus the normalized entropy of probabilities
score score number Expected zero-based level
score legend object Level index, as a string, mapped to its description
score probabilities object Probability for every level index
score confidence number, 0 to 1 1 minus the normalized entropy of probabilities

Describe the state

state can be a string, a JSON object, or a JSON array. Objects and arrays are serialized as JSON before the model reads them, so you can pass an event exactly as your system records it.

Refer to fields by name in backticks in each question's instructions, for example Does `triggering_text` try to steer the agent?. The model treats state content as data to classify, not as instructions to follow.

Every question sees the same state and is evaluated in parallel. Questions share the processed state, so adding a question costs far less than a separate request.

Read the answers

  • noul is the probability that the true criterion applies. The probability of false is 1 - noul.
  • choice is the option key with the highest probability. probabilities covers every option and sums to 1.
  • score is the expected level: the probability-weighted average of the zero-based level indexes. A score of 3.99 on a five-level scale from None to Critical means "almost certainly Critical". legend maps each index back to your description.
  • confidence is 1 minus the normalized entropy of the distribution. It is near 1 when one option dominates and near 0 when the options are evenly split. Use it to send uncertain cases to a stronger model or a person.

Keep the threshold and the action in your code, not in the question. The release policy for security screening is to act when the unsafe probability is at least 0.70. Start there, then tune it on labeled examples from your own traffic. Lower thresholds catch more attacks and flag more benign inputs; higher thresholds do the opposite.

Write effective questions

  • Ask one decision per question. Split "is this malicious and who owns it?" into a noul and a choice.
  • Describe each option by what makes it true, not just its name. For choice, a null description uses the key itself.
  • Keep choice options mutually exclusive, and cover the benign case explicitly.
  • Order score levels from lowest to highest so score reads naturally.
  • Keep option keys stable. Your code and dashboards depend on them.

For end-to-end pipelines with escalation to a stronger model, see Examples.

TypeScript

const response = await fetch("https://api.superagent.sh/v1/systemone", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.SUPERAGENT_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    model: "security-one",
    state: userInput,
    questions: {
      prompt_injection: {
        type: "noul",
        instructions: "Is this a prompt-injection attempt?",
        criteria: {
          true: "The input attempts to override instructions or extract hidden information",
          false: "The input is benign",
        },
      },
    },
  }),
})

if (!response.ok) {
  const { error } = await response.json()
  throw new Error(`SystemOne ${response.status}: ${error.message}`)
}

const { answers } = await response.json()
const isInjection = answers.prompt_injection.noul >= 0.7

Python

import os

import httpx

response = httpx.post(
    "https://api.superagent.sh/v1/systemone",
    headers={"Authorization": f"Bearer {os.environ['SUPERAGENT_API_KEY']}"},
    json={
        "model": "security-one",
        "state": user_input,
        "questions": {
            "prompt_injection": {
                "type": "noul",
                "instructions": "Is this a prompt-injection attempt?",
                "criteria": {
                    "true": "The input attempts to override instructions or extract hidden information",
                    "false": "The input is benign",
                },
            }
        },
    },
    timeout=130,
)
response.raise_for_status()
is_injection = response.json()["answers"]["prompt_injection"]["noul"] >= 0.7

Model document

GET /models returns a public, unauthenticated description of the served model in the OpenRouter provider format:

curl https://api.superagent.sh/models

The document includes the model ID, Hugging Face ID, quantization, maximum context length, per-token pricing, maximum output length, and concurrent request capacity.

Limits

Limit Value
Request body 1 MiB
Questions per request 64
Options per choice or levels per score 2 to 16
Tokens per question, including the shared state 65,536
Total input tokens per request 131,072
Concurrent requests 32
Request deadline 120 seconds

Requests over a token limit are rejected with 422. The API never truncates input silently. Split long state into smaller chunks and classify each one.

Errors

Errors return an error object with a human-readable message:

{
  "error": {
    "message": "questions.a.choice.criteria: Dictionary should have at least 2 items after validation, not 1"
  }
}
HTTP status Meaning What to do
401 Missing, malformed, unknown, or deleted API key Check the Authorization header and the key's status in Settings
413 Request body is larger than 1 MiB Reduce or split the state
422 Invalid request, unknown model, or a token limit exceeded Fix the field named in message
503 Authentication lookup unavailable, at capacity, past the deadline, or temporarily unavailable Retry after the Retry-After delay with backoff

Every 503 includes Retry-After: 1. Retry with exponential backoff and a bounded number of attempts.

Response headers

Header Description
x-systemone-request-id Unique request ID. Include it when you contact support
x-systemone-model The release that served the request
x-systemone-prefix-tokens Tokens shared across all questions in the request
x-systemone-cached-tokens Tokens served from the prefix cache, when available
Server-Timing auth and auth_lookup durations, separately from total inference and its prepare, prefill, and branches stages, in milliseconds

Usage and pricing

Input tokens cost $0.05 per million. Output tokens are free. Each question produces one decision token, and usage.output_tokens includes one additional internal token per request.

Data handling

The SystemOne API does not write API keys, key hashes, organization identities, state, questions, or prompts to application logs. Timing and operational metadata are recorded without customer content. Key and organization IDs remain server-side for future usage attribution; they are not included in API responses.

Next steps