Launch offer+15% credits on every packends inClaim →
jev·agent
Get a free key

Developers

Calling the API with your key

Two endpoints, one key, one balance. Everything here works with a free key and nothing here needs an SDK.

Authentication

A bearer token on every request. Get one free at /api-access — no card, no waitlist — and manage it on your dashboard.

bash
Authorization: Bearer jv_live_…

Keys are stored hashed and shown exactly once. A lost key cannot be recovered by anyone, including us — create another instead. Up to five at a time, so staging and production can be revoked independently.

POST /api/v1/classify

Text plus a ruleset name. No question shapes to write, no model to choose.

bash
curl -X POST https://jev-agent.com/api/v1/classify \
  -H "Authorization: Bearer $JEV_AGENT_KEY" \
  -H "content-type: application/json" \
  -d '{
    "ruleset": "support-ticket-triage",
    "items": ["Charged twice for September and cancelling Friday unless refunded."]
  }'
json
{
  "ruleset": "support-ticket-triage",
  "ruleset_version": 1,
  "model": "jev-1.13.0",
  "results": [
    { "index": 0,
      "model": "jev-1.13.0",
      "answers": {
        "queue":      { "type": "choice", "choice": "billing", "confidence": 1 },
        "severity":   { "type": "score", "score": 2.48, "legend": {"0":"Low","3":"Urgent"} },
        "churn_risk": { "type": "noul", "noul": 0.97 }
      },
      "latency_ms": 333 }
  ],
  "usage": { "credits_charged": 1, "used": 1, "limit": 5, "remaining": 4 }
}

Up to 20 items per request. Each item is a separate upstream call; failures are reported per item rather than failing the batch, so one malformed ticket does not discard nineteen good answers.

The rulesets

idWhat it decidesQuestions
support-ticket-triageRoute an inbound ticket to a queue, grade its urgency, and flag churn risk.3
llm-model-routingDecide how much model capability a request actually needs, before you spend it.1
agent-tool-selectionPick which tool an agent should call next from a fixed toolset.1
content-moderationGrade harm on a four-band rubric and flag targeting and spam separately.3
phishing-detectionIndependent yes/no signals for an email — combine them yourself rather than trusting one verdict.5
rag-rerankingScore a retrieved passage for real relevance, not embedding similarity.1
agent-output-guardrailsVerification checks on a draft response before it reaches a user.4
lead-scoringScore fit and intent against a rubric so hot leads reach a human today.3

The exact Jev call each one makes is public at GET /api/v1/rulesets/<id>, no key required. That is deliberate: take it, add your own TypeSafe key, and you never have to call us again.

POST /api/v1/systemone

Your own questions, in the official shape.

bash
curl -X POST https://jev-agent.com/api/v1/systemone \
  -H "Authorization: Bearer $JEV_AGENT_KEY" \
  -H "content-type: application/json" \
  -d '{
    "state": "Charged twice for September and cancelling Friday unless refunded.",
    "questions": {
      "queue": {
        "type": "choice",
        "instructions": "Which team should handle this?",
        "criteria": { "billing": "Payments and refunds", "technical": "Bugs and outages" }
      },
      "severity": {
        "type": "score",
        "instructions": "How urgent is this?",
        "criteria": ["Low", "Normal", "High", "Urgent"]
      },
      "churn": {
        "type": "noul",
        "instructions": "Threatening to cancel?",
        "criteria": { "true": "Mentions cancelling", "false": "No cancellation intent" }
      }
    }
  }'

Caps here are ours, not the API's: 8,000 characters of state, 10 questions, 255 options on a choice. model is optional and accepts jev-latest, jev-preview or jev-1.13.0.

Three answer shapes that catch people out

State

state is what you are asking about. One state per request; every question sees it and is evaluated independently, so you can mix all three types in one call.

It does not have to be a string. A JSON object or an array of text values works too, and an object is usually better — each part of the state gets a name, and the relationships between the parts stay visible.

json
{
  "state": {
    "ticket": {
      "subject": "Duplicate charge",
      "messages": [
        { "from": "customer", "text": "Charged twice for order A-104." },
        { "from": "support",  "text": "We are checking the charges." }
      ]
    },
    "order": { "id": "A-104", "charges": [ { "usd": 49 }, { "usd": 49 } ] },
    "refund_policy": "Duplicate charges are eligible for a refund."
  },
  "questions": { "…": "…" }
}

That is one state, even though it holds a conversation, an order and a policy. Put related material together when the decision needs the parts compared. Text only — no images, no audio. English is where accuracy is best; other languages including CJK are accepted and are measurably weaker.

Confidence, and what to do with it

Choice and Score return a confidence; Noul does not, and its distance from 0.5 is the equivalent. Confidence is not the same as the winning probability: a two-option choice split 51/49 has a clear winner and very little certainty, and that difference is the whole reason to read it.

js
const { answers } = await callJev(ticket, { route: routeQuestion });

if (answers.route.confidence >= 0.85) {
  dispatch(answers.route.choice);   // decided
} else {
  escalate(ticket);                 // not sure enough — ask a human or an LLM
}

Pick the threshold against your own labelled data. The right number depends entirely on what a wrong decision costs you, and our own measurements put the separation between easy and genuinely ambiguous inputs at about 0.98 against 0.84 — real, but narrower than you might assume before testing.

Four patterns worth knowing

Speculative fan-out

Questions share one state and run in parallel, so asking five costs roughly the latency of asking one — measured: 70ms for one, 74ms for five. Ask everything you might want, including questions you will probably discard, and let your code decide what was relevant. Three separate calls pay for the state three times.

Confidence-gated routing

Two axes, not one: the answer says what, the confidence says whether to act on it unattended. A cheap fast path when sure, a human or an LLM when not.

Composite scoring

Do not ask one vague question. Ask several atomic ones and combine them with weights you own in code — the weights stay auditable and changeable without touching the model.

Intent routing

Classify the incoming request, then send each class to the handler that fits: deterministic code, a specialist model, or a person. This is the most common thing people build with Jev.

What a call costs

One credit is 1,000 input tokens, the unit TypeSafe bills us in. A request costs ceil(input_tokens / 1,000) with a floor of one, charged per request rather than per question — questions share the state and the state is nearly all of the tokens. A typical support ticket with three questions is about 440 input tokens, so it costs a single credit.

What you sendInput tokensCredits
A support ticket, three questions~4401
A short email, one question~2001
A page of documentation~1,8002
The 8,000-character maximum~2,0002
20 tickets through /classify in one call~8,8009

There is no per-request ceiling, so the published limits are the real ones: a fully loaded /v1/systemone call — 8,000 characters of state, ten questions, hundreds of options — can reach about 31 credits, and a twenty-item batch of 4,000-character items about 21. Those are the extremes of what the caps allow, not what normal use looks like, but nothing stops you reaching them.

Five requests and five credits are not the same thing. If you want the number of calls to be predictable, keep the state short; if you want the cheapest possible answer per decision, ask several questions in one request rather than several requests — they share the state, and the state is nearly all of the tokens.

Every account gets 5 free credits a month, spent before anything you have bought. Purchased credits never expire. Failed requests are not charged, because the charge is settled from the token count in a successful response. Top up or check GET /api/keys with your key for the current balance.

Limits

There is no per-minute limit on the API at any tier — a key is metered by credits, not frequency. The size ceilings are ours and holding credits raises them: 8,000 to 32,000 characters of state, 10 to 20 questions per request, and 20 to 50 items per /classify batch. Full table on the credits page.

Errors

400Malformed body — the message names the field. Sending `kind` instead of `type` lands here.
401Missing, unrecognised or revoked key. A TypeSafe key will not work on this host, and vice versa.
429Out of credits. The free grant resets on the 1st; top-ups do not expire.
502Upstream refused or timed out. Nothing is charged.
503Our key store or the API is unavailable. Nothing is charged.

Every error is {"error": "…"} with a sentence a human can act on, and the useful ones carry extra fields — a 400 on an unknown ruleset lists the valid ones.

Managing keys from code

bash
curl https://jev-agent.com/api/keys      -H "Authorization: Bearer $JEV_AGENT_KEY"   # usage
curl -X PUT    https://jev-agent.com/api/keys -H "Authorization: Bearer $JEV_AGENT_KEY"   # rotate
curl -X DELETE https://jev-agent.com/api/keys -H "Authorization: Bearer $JEV_AGENT_KEY"   # revoke

Rotating kills the old key immediately and returns a new one; the month's usage follows your account, not the credential, so it is not a way to reset the counter.