Dashboard|

Judgment API

Structured decisions from decision models (TypeSafe Jev, Cloudflare Clef) — yes/no, choice, and score answers with probabilities over any state.

Get calibrated decisions instead of generated text. Send a state plus typed questions and get back one answer per question with probabilities your code can branch on — routing tickets, gating automation on confidence, scoring content against a rubric. Any judgment-type catalog model works through this same endpoint (TypeSafe's Jev and Cloudflare's Clef today).

Two vendors are wired in, one request contract. TypeSafe models proxy the System One API (POST /v1/systemone); Cloudflare Clef models run at one Workers AI path per size (POST /accounts/.../ai/run/@cf/cloudflare/clef[-flash|-omni]). Cencori adds its own auth, per-project keys (BYOK), input-token billing, logging, and usage metering either way.

Endpoints

PathPurpose
POST /v1/judgmentsJudge a state against typed questions
GET /v1/judgmentsJudgment models + pricing + limits (no key required)

Authenticate with your Cencori key (CENCORI_API_KEY: csk_... header or Authorization: Bearer). A vendor key is resolved per project — your own provider key first (typesafe, cloudflare), the managed key as fallback. BYOK calls are not charged; managed calls bill input tokens (output tokens are unbilled): Jev at $0.042/MTok, Clef at $0.24/MTok, Clef Flash at $0.038/MTok, Clef Omni at $0.15/MTok. Adding a project key in Project Settings makes calls BYOK — save a Workers AI key under Cloudflare as <ACCOUNT_ID>:<API_TOKEN> (Workers AI runs inside a Cloudflare account, so both halves are needed). A typesafe key is the API key alone.

Quick start

curl https://api.cencori.com/v1/judgments \
  -H "CENCORI_API_KEY: csk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "model": "jev-latest",
    "state": "I was charged twice. Please refund the duplicate.",
    "questions": {
      "department": {
        "type": "choice",
        "instructions": "Which team should handle this?",
        "criteria": {
          "billing": "Payments, invoicing, refunds",
          "technical": "Bugs, outages, integrations"
        }
      },
      "requests_refund": {
        "type": "noul",
        "instructions": "Does the customer request a refund?"
      }
    }
  }'
import { Cencori } from 'cencori';
 
const cencori = new Cencori({ apiKey: 'csk_...' });
const result = await cencori.judgment.judge({
  state: 'I was charged twice. Please refund the duplicate.',
  questions: {
    department: {
      type: 'choice',
      instructions: 'Which team should handle this?',
      criteria: { billing: 'Payments, invoicing, refunds', technical: 'Bugs, outages' },
    },
    requests_refund: { type: 'noul', instructions: 'Does the customer request a refund?' },
  },
});
 
if (result.answers.department.type === 'choice' && result.answers.department.confidence > 0.8) {
  routeTicket(result.answers.department.choice);
}

Omit model to use the default (jev-latest). Aliases resolve upstream — the response names the version that actually judged (e.g. jev-1.13.0).

Question types

TypeAsksReturns
noulA yes/no questionnoul: probability the answer is yes (0–1)
choicePick one of 1–255 options you definechoice, confidence (0–1), full probabilities per option
scoreRate against 2–10 ordered levels, lowest firstscore, confidence, legend, full probabilities per level

Every question needs instructions. choice needs criteria as an option → rubric map (use null where an option needs no detail); score needs criteria as the ordered level array. noul accepts optional true/false criteria describing each side. Answers come back under the same ids you sent.

state is what the questions are about: a string, a JSON object, or an array of text. The per-request budget covers the state plus all questions combined, measured as the state plus the single longest question (~4 characters per token, enforced before billing): 64k tokens for Jev, 64k for Clef and Clef Omni, 24k for Clef Flash. Over-budget requests are rejected before billing.

Models

ModelVendorNotes
jev-latestTypeSafeLatest stable Jev release (default)
jev-previewTypeSafePreview build, ahead of latest when one exists
jev-1.13.0TypeSafePinned release
clef-latestCloudflareFlagship 27B Clef (image/video states supported upstream)
clef-flashCloudflareFast 9B Clef, cheap tier ($0.038/MTok), 24k budget
clef-omniCloudflareOmni Clef — the tier that adds WAV/MP3 audio and MP4/WebM video states upstream

GET /v1/judgments is the authoritative list with live pricing, context windows, and availability.

Response

{
  "object": "judgment",
  "model": "jev-1.13.0",
  "answers": {
    "department": {
      "type": "choice",
      "choice": "billing",
      "confidence": 0.91,
      "probabilities": { "billing": 0.93, "technical": 0.07 }
    },
    "requests_refund": { "type": "noul", "noul": 0.97 }
  },
  "usage": { "input_tokens": 214, "output_tokens": 18 }
}

confidence (choice/score) says how peaked the distribution is — use it as a second axis: act above your threshold, escalate to a person or a reasoning model below it. (noul carries no separate confidence; max(noul, 1 - noul) is the equivalent.)

Errors

CodeStatusMeaning
invalid_questions / invalid_state / context_exceeded400Fix the request (limits above); nothing was billed
unknown_model404Not a judgment model id — see GET /v1/judgments
model_not_allowed403The calling key is not granted this model
provider_connection_required402No vendor key configured — add a typesafe or cloudflare provider key
rate_limited429Upstream rate limit; honor retry-after and retry with backoff
provider_auth / provider_validation / upstream_error502Upstream rejected the key or the call

When not to use it

Judgment classifies and rates content you already have — it never writes replies, summaries, or code, and it answers one flat batch of independent questions per call (no agent loop, no tool use). For generation or multi-step reasoning, use Chat or Responses and let a judgment call gate or route the result.