Most teams know OpenRouter as one API key for many chat models. It also serves Jev, TypeSafe's decision model, but not through the chat endpoint. Jev does not generate text, so it has its own endpoint with its own request shape.

We call Jev through OpenRouter for all of our internal tools: a Claude Code model router, a skill picker and text triage. This is the practical guide we wanted when we started: the endpoint, the payload, the price, the latency we measured, and when you should call TypeSafe directly instead.

The endpoint

POST https://openrouter.ai/api/alpha/decisions
Authorization: Bearer <your OpenRouter API key>
Content-Type: application/json

Note the alpha in the path. This is OpenRouter's Decisions API, separate from /api/v1/chat/completions. The model id is typesafe/jev-1.13. OpenRouter's reference for it lives at Submit a Decisions request; an older link to it returns a 404, so bookmark the current one.

The request

A decisions request has three required fields:

  • model: typesafe/jev-1.13.
  • state: the content to evaluate. A plain string, or a JSON object or array when the context has several parts.
  • questions: a map of typed questions. You choose each key, and the answer comes back under the same key.

Each question has a type (Choice, Score or Noul), instructions and criteria. Here is a support ticket with all three types, adapted from OpenRouter's own example:

curl https://openrouter.ai/api/alpha/decisions \
  -H "Authorization: Bearer $OPENROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "typesafe/jev-1.13",
    "state": {
      "customer_tier": "enterprise",
      "ticket": "My checkout page shows a blank screen after I click Pay. I have tried two browsers."
    },
    "questions": {
      "is_bug": {
        "type": "noul",
        "instructions": "Is the customer reporting a software defect?",
        "criteria": {
          "true": "The customer describes broken or unexpected product behavior.",
          "false": "The customer is asking a question or requesting a feature."
        }
      },
      "team": {
        "type": "choice",
        "instructions": "Which team should own this ticket?",
        "criteria": {
          "account": "Login, permissions, or profile issues.",
          "frontend": "Rendering, layout, or browser compatibility issues.",
          "payments": "Checkout, billing, or payment processing issues."
        }
      },
      "urgency": {
        "type": "score",
        "instructions": "How urgent is this ticket?",
        "criteria": [
          "Can wait for the next release",
          "Should be fixed this week",
          "Blocking revenue right now"
        ]
      }
    }
  }'

Two details trip people up. Question keys are for your code only; they are not sent to the model, so the full meaning belongs in instructions. And Score criteria are an ordered array, lowest level first.

Optional fields include session_id (groups related requests for OpenRouter's observability and private logging, and is never sent to the provider), trace metadata, user, and provider routing preferences.

The response

{
  "id": "gen-dec-1789738314-X5e5eKGQdvR9rblyX250",
  "model": "typesafe/jev-1.13-20260917",
  "provider": "TypeSafe",
  "answers": {
    "is_bug": { "type": "noul", "noul": 0.96 },
    "team": {
      "type": "choice",
      "choice": "payments",
      "confidence": 0.75,
      "probabilities": { "account": 0, "frontend": 0.16, "payments": 0.84 }
    },
    "urgency": {
      "type": "score",
      "score": 1.99,
      "confidence": 0.99,
      "probabilities": { "0": 0, "1": 0.01, "2": 0.99 },
      "legend": {
        "0": "Can wait for the next release",
        "1": "Should be fixed this week",
        "2": "Blocking revenue right now"
      }
    }
  },
  "usage": { "cost": 0.000019992, "input_tokens": 476, "output_tokens": 70 }
}

This is OpenRouter's documented example response. The model field reports the exact build that answered, which is worth logging next to every decision.

How to read it:

  • Noul returns noul: the probability that the answer is yes. It has no separate confidence.
  • Choice returns the choice, a probability per option, and confidence.
  • Score returns score on a 0-based scale that can be fractional (a probability-weighted position between levels, which is why the example shows 1.99 rather than 2), plus probabilities, a legend and confidence.

Our confidence guide covers what to do with those numbers.

Pricing

TypeSafe prices Jev 1.13 at $0.042 per million input tokens, and output tokens are free. The answer is a handful of numbers, so the cost of a request is essentially the size of your state plus your questions.

Through OpenRouter, every response reports its own usage.cost, which makes cost easy to log per call. The documented example above is a clean illustration: 476 input tokens at $0.042 per million is exactly the $0.000019992 reported, and its 70 output tokens added nothing. In our own first live test, three questions on one sales email came to 745 input tokens and a reported cost of $0.000031, again in line with the published rate (about $0.0000313).

Two consequences for design:

  • Batch your questions. The state dominates the bill, so asking five questions about one document in one request costs little more than asking one. See speculative fan-out.
  • Trim your state. Send the fields a question needs, not the whole record. TypeSafe's jaggedness notes also warn that a large state full of irrelevant detail hurts accuracy, so trimming saves money and improves answers.

Latency we measured

Wall-clock times from our own tools on 2026-09-23, calling OpenRouter from a workstation:

Tool What it asks Time
Text triage 3 questions, one sales email, 745 input tokens 354 ms
Skill picker 1 Choice over 16 skills about 340 to 460 ms
Model router 1 Choice plus 1 Noul per message about 350 to 530 ms

These are end-to-end numbers including the network, not a benchmark. Your latency will depend on region, payload size and load. TypeSafe notes that adding questions to a request barely changes response time, because they are evaluated in parallel against the same state.

Limits worth knowing

From TypeSafe's models page:

  • Context: 64k tokens per request, and 32k for the state plus the single longest question.
  • Input: text only. Strings, JSON objects or arrays of text. Convert images, audio and PDFs to text first.
  • Language: English is where accuracy is best; test other languages on your own content.
  • Options: up to 255 options in a single Choice question.

OpenRouter or TypeSafe direct?

TypeSafe's own API is POST https://api.typesafe.ai/v1/systemone, with Python and JavaScript SDKs. The question shapes are the same, so moving between the two is mostly a change of URL, key and model name.

Use OpenRouter when you already run your LLM traffic through it. One key, one bill, per-response cost, and OpenRouter's observability via session_id and trace.

Go direct when you want:

  • Typed SDKs with built-in retries that back off and honor retry-after on rate limits.
  • Version control over the model. TypeSafe offers aliases (jev-latest, jev-preview) and versioned ids; if you tuned confidence thresholds on one version, pin it and upgrade on your own schedule. On OpenRouter, pin typesafe/jev-1.13 for the same reason.
  • Enterprise terms: higher rate limits on custom plans, and zero data retention for enterprise customers.

Current published direct limits are 250,000 tokens per second and 1,200 requests per minute, and TypeSafe says those are adjusting dynamically while it adds capacity.

A note on privacy

Whatever route you pick, anything in state leaves your machine. Through OpenRouter it passes through OpenRouter and then TypeSafe. TypeSafe states that Jev is not trained on customer requests or responses, but that does not make every payload safe to send. Our rule is simple: made-up or already public text is fine; for customer data, credentials or anything from production, we ask first.

If you are deciding how Jev fits into your stack, or want someone to build the integration, see our AI engineering services or contact us.

FAQ

What is the model id for Jev on OpenRouter?

typesafe/jev-1.13, sent to POST https://openrouter.ai/api/alpha/decisions.

Does Jev use OpenRouter's chat completions endpoint?

No. Jev is served through OpenRouter's Decisions API, which takes state and typed questions instead of chat messages and returns typed answers instead of text.

How is Jev billed?

TypeSafe prices Jev 1.13 at $0.042 per million input tokens, with free output. On OpenRouter each response reports its own usage.cost; in our test the reported cost matched that rate.

How fast is Jev through OpenRouter?

In our tools it answered in roughly 340 to 530 ms end to end, including the network. A three-question triage request took 354 ms.