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.
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.
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.
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.
{
"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.
{
"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.
{
"route": {
"type": "choice",
"instructions": "Which team should handle this message?",
"criteria": {
"billing": "Payments and refunds",
"technical": "Bugs and outages",
"account": null
}
}
}
{
"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.
{
"urgency": {
"type": "score",
"instructions": "How urgent is this request?",
"criteria": [
"Routine",
"Important",
"Critical"
]
}
}
{
"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.
{
"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."
}
}
}
{
"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.
{
"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.
{
"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
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
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. |
{
"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.
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.