BUILD WITH SIMPLE JEV

API documentation.

Context and questions in. Structured decisions out.

Demo · POST
https://simple-jev-demo-api.featherless.ai/v1/classifier

Production · POST
https://api.featherless.ai/v1/classifier
Requires a production API key: Authorization: Bearer YOUR_API_KEY.

No demo API key2k-token context4 requests / second

This page covers the public demo’s client-facing interface and explains where the self-hosted HF implementation differs. Try your requests in the question playground.

Make your first request

The public demo requires no login, API key, or Authorization header. Start by discovering the available models, then send a classifier request.

bash
curl https://simple-jev-demo-api.featherless.ai/v1/models

This example uses Gemma. You can replace its ID with any ID returned by the model list.

bash
curl --fail-with-body https://simple-jev-demo-api.featherless.ai/v1/classifier \
  -H 'Content-Type: application/json' \
  --data-binary @- <<'JSON'
{
  "model": "featherless-ai/gemma-4-26B-A4B-classifier",
  "state": "Mia owns a red bicycle.",
  "questions": {
    "color": {
      "type": "choice",
      "instructions": "What color is Mia’s bicycle?",
      "criteria": {
        "red": null,
        "blue": null
      }
    }
  }
}
JSON

A successful response looks like this. These numbers illustrate the response format; they are not a promised result or measured token count.

json
{
  "model": "featherless-ai/gemma-4-26B-A4B-classifier",
  "answers": {
    "color": {
      "type": "choice",
      "choice": "red",
      "confidence": 0.95,
      "probabilities": {
        "red": 0.95,
        "blue": 0.05
      }
    }
  },
  "usage": {
    "input_tokens": 350,
    "output_tokens": 1
  }
}

Endpoints & limits

Method Path Purpose
GET /v1/models List the public demo’s available model IDs.
POST /v1/classifier Evaluate questions against shared context. Returns non-streaming JSON.

The public demo has a 2k-token context limit and a 4 requests-per-second rate limit. The context budget includes the classifier instructions, questions, criteria, and model chat formatting—not just your text. Short inputs and focused question sets work best.

The playground caps input at 1,200 characters and six questions for convenience. Characters are not tokens, and those UI caps do not replace the API’s limits.

The API permits cross-origin browser requests. Models can change; use /v1/models rather than assuming the list is permanent. Every response’s model identifies the requested model.

json
{
  "object": "list",
  "data": [
    {
      "id": "featherless-ai/gemma-4-26B-A4B-classifier",
      "object": "model"
    }
  ]
}

Illustrative model-list excerpt. The live list can contain additional models and metadata.

Request body

Field Type Meaning
model string · required Exact model ID from the public model list.
state string, object, or array Shared context. Supply this or messages, not both.
messages array of text messages Chat history instead of state. Must contain at least one message.
questions object · required One or more unique, nonempty IDs mapped to question definitions. IDs become keys in answers.
options object · optional Diagnostics, such as raw_logits, when supported and enabled by the serving implementation.

Each question has a type and an instructions field. Criteria depend on its type. Plain text is usually easiest; the shared schema also accepts JSON objects, arrays, or null for instructions and criterion descriptions.

In the shared request schema, unknown top-level fields are ignored, while unknown question and option fields are rejected. Completion settings such as temperature, max_tokens, and stream do not configure classifier scoring. Omit them.

Use text-only input for this demo. Do not send images, audio, tool calls, or media options. messages supplies context; this is not a chat-completions endpoint.

Choice: select an answer

Use choice for routing, intent, sentiment, or any decision among named candidates. Provide 2–50 candidates in the shared schema. Each key is a public answer ID; its value is an optional description.

json
{
  "route": {
    "type": "choice",
    "instructions": "Which team should handle this message?",
    "criteria": {
      "billing": "Payments and refunds",
      "technical": "Bugs and outages",
      "account": null
    }
  }
}
json
{
  "route": {
    "type": "choice",
    "choice": "billing",
    "confidence": 0.8,
    "probabilities": {
      "billing": 0.8,
      "technical": 0.15,
      "account": 0.05
    }
  }
}

The largest candidate probability determines choice and confidence. Probabilities are normalized over the supplied candidates. They do not measure the probability that the answer is objectively correct. Candidate order controls internal label assignment and resolves exact ties in v1.

Score: evaluate an ordered rubric

Use score for urgency, relevance, quality, or support against an explicit rubric. Provide 2–50 levels in the shared schema, ordered from lowest to highest.

json
{
  "urgency": {
    "type": "score",
    "instructions": "How urgent is this request?",
    "criteria": [
      "Routine",
      "Important",
      "Critical"
    ]
  }
}
json
{
  "urgency": {
    "type": "score",
    "score": 1.75,
    "confidence": 0.8,
    "probabilities": {
      "0": 0.05,
      "1": 0.15,
      "2": 0.8
    },
    "legend": {
      "0": "Routine",
      "1": "Important",
      "2": "Critical"
    }
  }
}

The returned score is the expected zero-based rubric index: sum(probability[i] × i). Here, 0 × 0.05 + 1 × 0.15 + 2 × 0.8 = 1.75. With three levels, the range is 0–2, not 0–1 or 0–100.

confidence is the highest individual level probability, not a confidence interval around the score. legend maps numeric-string keys back to your rubric.

Noul: judge a proposition

Use noul for a yes/no proposition, such as whether a customer explicitly requests a refund. Optional criteria describe what true and false mean.

json
{
  "refund": {
    "type": "noul",
    "instructions": "Does the customer explicitly request a refund?",
    "criteria": {
      "true": "The customer asks for money back.",
      "false": "There is no explicit refund request."
    }
  }
}
json
{
  "refund": {
    "type": "noul",
    "noul": 0.9
  }
}

The value lies between 0.01 and 0.99, with higher values indicating more support for “yes.” Noul has no separate confidence field. In v1, it comes from the expected value of nine rating bins, mapped to that range; it is not a softmax between two binary answer tokens.

Treat it as a model judgment. If your application needs a yes/no action, choose and evaluate a threshold on representative data rather than assuming 0.5 is appropriate for every task.

State, chat history & multiple questions

state can be structured JSON when your application already has a useful data object. It is serialized as context, not executed.

json
{
  "state": {
    "ticket": {
      "message": "Charged twice",
      "plan": "Pro"
    },
    "duplicate_payment_confirmed": true
  }
}

For a conversation, replace state with messages. Send plain text content with roles supported by the model’s chat template. The HF adapter supports system, developer, user, and assistant roles, but a particular template may impose further restrictions.

json
{
  "model": "featherless-ai/gemma-4-26B-A4B-classifier",
  "messages": [
    {
      "role": "user",
      "content": "I was charged twice."
    },
    {
      "role": "assistant",
      "content": "Would you like the duplicate charge refunded?"
    },
    {
      "role": "user",
      "content": "Yes, please."
    }
  ],
  "questions": {
    "refund": {
      "type": "noul",
      "instructions": "Does the customer want a refund?"
    }
  }
}

To ask several questions, put their definitions in the same questions object under different IDs. They share the context but do not consume one another’s answers. The server returns all answers together. More questions and longer criteria consume more of the context budget.

JavaScript & Python

These clients call the public demo directly, without credentials. Keep production credentials on your server if your production service requires them.

JavaScript

javascript
const endpoint = "https://simple-jev-demo-api.featherless.ai/v1/classifier";
const response = await fetch(endpoint, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    model: "featherless-ai/gemma-4-26B-A4B-classifier",
    state: "The bicycle is red.",
    questions: {
      color: {
        type: "choice",
        instructions: "What color is the bicycle?",
        criteria: { red: null, blue: null }
      }
    }
  }),
  signal: AbortSignal.timeout(45000)
});
const result = await response.json();
if (!response.ok) {
  throw new Error(result.error?.message ?? result.detail ?? `HTTP ${response.status}`);
}
console.log(result.answers.color.choice);

Python · standard library

python
import json
import urllib.request
import urllib.error

payload = {
    "model": "featherless-ai/gemma-4-26B-A4B-classifier",
    "state": "The bicycle is red.",
    "questions": {
        "color": {
            "type": "choice",
            "instructions": "What color is the bicycle?",
            "criteria": {"red": None, "blue": None},
        }
    },
}
request = urllib.request.Request(
    "https://simple-jev-demo-api.featherless.ai/v1/classifier",
    data=json.dumps(payload).encode("utf-8"),
    headers={"Content-Type": "application/json"},
)
try:
    with urllib.request.urlopen(request, timeout=45) as response:
        result = json.load(response)
    print(result["answers"]["color"]["choice"])
except urllib.error.HTTPError as error:
    print(error.code, error.read().decode("utf-8"))
    raise

Errors & troubleshooting

Status What to check
400 / 413 / 422 Read the actual error: invalid fields, unsupported input, token limits, or model scoring failures may all reject a request.
429 Rate or capacity limit. Honor Retry-After when present; otherwise back off before retrying. Avoid retry loops without a delay.
5xx Service failure. Retry with bounded backoff and preserve the original request for debugging.
Network / timeout Check connectivity and API availability. A browser error alone does not establish a model failure.
json
{
  "error": {
    "message": "Expected nine finite logits",
    "type": "invalid_request_error",
    "code": 422,
    "param": null,
    "details": []
  }
}

This is an observed scoring-error shape from the hosted demo. “Expected nine finite logits” or “Expected one finite logit per choice” indicates a failure in answer scoring; it does not mean your text is too long. Capture the model, complete request, response, time, and request ID if available. Comparing a combined request with isolated questions can help identify the failing path.

The self-hosted HF server can use FastAPI-style detail errors instead. Clients should inspect both HTTP status and body, and handle non-JSON failure responses gracefully. The playground preserves failed response JSON under “Under the hood.”

Usage, confidence & versioning

usage.input_tokens and usage.output_tokens report the serving implementation’s accounting. Hosted demo responses have reported one output token per question. The local HF reference reports zero output tokens because it reads logits without sampling; its input count counts unique token prefixes across questions. Do not assume those implementations report identical usage.

Choice and score probabilities are conditional on the supplied candidate/rating set. Noul is a transformed expected rating. None is automatically calibrated to real-world correctness. Model quality, question wording, and rubric design affect decisions.

The shared prompt contract currently uses v1. In Python, prepare_prompt(request, version="v1") selects it. It is not a client-selectable HTTP request field. Legacy independent/rating mode and score-format switches are not supported by the shared schema.

Self-hosting & Open Source reference implement

The repository’s HF server uses the same shared request, prompt, and scoring modules. Unlike the hosted demo, it loads one model at startup: the request’s model must match that ID or local path.

bash
python -m pip install -e './hf-server'
python hf-server/hf_server.py \
  --model Qwen/Qwen3.5-0.8B --device cpu --dtype float32 \
  --max-model-len 4096 --port 8000

Its classifier URL is http://127.0.0.1:8000/v1/classifier. It also exposes /health, /docs, and /openapi.json, plus /v1/systemone as a classifier alias. The local HF implementation does not expose the demo’s /v1/models endpoint. Its default branch cap is 100; the shared schema allows up to 256 questions. Runtime token/branch limits apply in addition to schema validation.

For local diagnostic logits, start the HF server with ENABLE_OPEN_JEV_ADVANCED_METRICS=1 and send "options": {"raw_logits": true}. Do not assume that diagnostics are enabled on the public demo.

See the complete HF server reference and the language-independent v1 prompt specification.

Scaling into Production

Send the same classifier request body to https://api.featherless.ai/v1/classifier with your production key in the Authorization: Bearer YOUR_API_KEY header. Keep Content-Type: application/json. Production limits and billing follow your account.

Simple Jev is currently in beta on Featherless developer plans, with higher limits for production usage.

Beta pricing

Model ID Input token price (per million) Images & vision
featherless-ai/RWKV-small-classifier $0.03 Text only
featherless-ai/RWKV-mid-classifier $0.10 Text only
featherless-ai/RWKV-std-classifier $0.20 Text only
featherless-ai/gemma-4-26B-A4B-classifier $0.28 Supported
featherless-ai/Qwen3.6-35B-A3B-classifier $0.28 Supported
featherless-ai/Qwen3.8-27B-classifier $0.30 Supported

*Prices may change after beta. Refer to Featherless.ai official pricing for up-to-date information.

Hosted fine-tuned models and fine-tuning are planned as support and usage grow.