26 de set. de 2026

Como chamar a API do Jev a partir de curl, Python e JavaScript

Uma primeira requisição /v1/systemone do Jev AI que você pode colar no terminal e depois no seu app — com uma resposta real, latência medida e a tabela completa de erros.

Antes da primeira chamada

O Jev responde decisões tipadas: você envia um estado mais perguntas nomeadas, e ele retorna uma das respostas que você declarou, com uma probabilidade. A Optio é um gateway operado de forma independente que encaminha a requisição ao Jev — você cria uma conta, abre o dashboard e cria uma chave de API. A chave completa é exibida exatamente uma vez e começa com jev_live_; guarde-a em um gerenciador de segredos do lado do servidor ou em uma variável de ambiente, nunca em código de frontend e nunca em um repositório Git.

O endpoint é o mesmo para todos os clientes:

POST https://jevai.website/api/v1/systemone
Authorization: Bearer $JEV_API_KEY
Content-Type: application/json
Endpoint e cabeçalho de autenticação

A menor requisição útil

Um corpo de requisição tem duas partes: state (o assunto da decisão) e questions (o que você quer saber). O state pode ser uma string simples, um array de strings ou um objeto JSON, até 100,000 caracteres. As questions são um mapa de 1 a 8 perguntas nomeadas; o nome deve ser um identificador válido (letras, dígitos e underscores — ele vira a chave na resposta).

curl https://jevai.website/api/v1/systemone \
  -H "Authorization: Bearer $JEV_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "state": "The payments webhook failed twice overnight. Should I wake up the on-call engineer?",
    "questions": {
      "page": {
        "type": "noul",
        "instructions": "Should someone be paged right now?",
        "criteria": {
          "true": "Revenue-impacting or data loss",
          "false": "Can wait until morning"
        }
      }
    }
  }'
curl — uma pergunta sim/não

Os valores em criteria são palavras suas — escreva-os como linhas de política. São eles que o modelo julga, então uma pergunta como “Devo acionar alguém de plantão?” com definições explícitas de true/false é muito mais repetível do que a mesma pergunta sem definições.

Como é a resposta

Uma resposta 200 real deste endpoint fica assim (capturada contra o gateway em produção; as contagens de tokens vieram da requisição real):

{
  "request_id": "req_fe17d05411092c4f7f97947a",
  "model": "jev-1.14.0",
  "answers": {
    "page": { "type": "noul", "noul": 0.91 }
  },
  "usage": {
    "input_tokens": 128,
    "output_tokens": 21,
    "credits": 1,
    "credits_remaining": 4
  },
  "latency_ms": 432
}
Resposta 200, abreviada

As respostas são indexadas pelos nomes das suas perguntas, então ramificar no código é trivial: if (answers.page.noul < 0.8) escalate(). Toda resposta também carrega um request_id — cite-o quando escrever para o suporte e registre-o do seu lado para conciliação.

Os três tipos de pergunta

  • noul — sim/não. Retorna noul: a probabilidade (0–1) de a resposta ser sim. criteria com descrições true/false é opcional, mas recomendado.
  • choice — escolha uma entre 2–20 opções rotuladas. Retorna choice (o rótulo selecionado), probabilities por opção e um valor de confidence.
  • score — posiciona o estado em uma escala ordenada de 2–10 níveis, ex. [Calm, Frustrated, Very angry]. Retorna um score contínuo (0 = primeiro nível), probabilidades sobre os níveis, uma legend que mapeia as faixas de score de volta aos rótulos, e confidence.

Até oito perguntas cabem em uma requisição — isso importa para o custo, porque a cobrança é por token de entrada com mínimo de 1 crédito, não por pergunta. Três perguntas sobre o mesmo estado custam o mesmo que uma, sempre que o total ficar abaixo de 1,000 tokens.

Interpretando a resposta em Python e JavaScript

import os, requests

resp = requests.post(
    "https://jevai.website/api/v1/systemone",
    headers={"Authorization": f"Bearer {os.environ['JEV_API_KEY']}"},
    json={
        "state": {
            "ticket": {"subject": "Refund duplicate charge", "order": "A-104"},
            "refund_policy": "Duplicate charges are eligible for a full refund.",
        },
        "questions": {
            "policy_supports": {"type": "noul", "instructions": "Does the policy support this refund?"},
            "frustration": {"type": "score", "instructions": "How frustrated is the customer?",
                            "criteria": ["Calm", "Frustrated", "Very angry"]},
        },
    },
    timeout=30,
)
resp.raise_for_status()
answers = resp.json()["answers"]
if answers["policy_supports"]["noul"] > 0.9:
    print("auto-approve; frustration =", answers["frustration"]["legend"])
Python
const resp = await fetch("https://jevai.website/api/v1/systemone", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.JEV_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    state: "Charged twice for order A-104, please refund the duplicate.",
    questions: {
      route: {
        type: "choice",
        instructions: "Which team handles this?",
        criteria: {
          billing: "Payments, payouts, invoicing, refunds",
          technical: "Bugs, outages, integrations",
          sales: "Pricing, upgrades, new accounts",
        },
      },
    },
  }),
});
const { answers, usage, latency_ms } = await resp.json();
console.log(answers.route.choice, answers.route.probabilities, latency_ms);
JavaScript / TypeScript

Códigos de erro e retentativas

Os erros sempre usam um único formato: {error: {code, message, request_id}}. Ramifique pelo code, não pelo texto da mensagem. A tabela:

  • 401 missing_api_key / invalid_api_key — sem cabeçalho Bearer, ou a chave foi revogada. Não tente novamente.
  • 402 insufficient_credits — o saldo do workspace não cobriu a reserva. Não tente novamente; recarregue.
  • 422 invalid_request — corpo malformado, nomes de pergunta inválidos, zero perguntas, state acima de 100,000 caracteres. Não tente novamente; corrija a requisição.
  • 429 rate_limited — o teto de concorrência ou de requisições por minuto do plano foi atingido. Tente novamente com backoff exponencial; a resposta traz os cabeçalhos Retry-After e X-RateLimit-Remaining.
  • 502 upstream_error (também upstream_timeout, upstream_unreachable) — o provedor do modelo falhou ou a janela upstream de 15 segundos expirou. Tente novamente com backoff; você não foi cobrado.
  • 529 upstream_overloaded — capacidade do provedor. Mesmo tratamento do 502.
import time

def decide(body, max_retries=3):
    for attempt in range(max_retries + 1):
        resp = requests.post(URL, headers=HEADERS, json=body, timeout=30)
        if resp.status_code in (429, 502, 529):
            time.sleep(min(2 ** attempt, 8))
            continue
        resp.raise_for_status()
        return resp.json()
    raise RuntimeError("upstream kept failing; give up or degrade")
Loop de retentativa em Python que vale copiar

Os créditos são reservados antes de o modelo rodar e liquidados depois contra a contagem real de tokens; se o provedor falhar, a reserva é devolvida automaticamente. Uma requisição com falha nunca deixa uma cobrança no ledger.

Quanto custa e quão rápido responde

Um crédito equivale a 1,000 tokens de entrada; a cobrança é ceil(tokens de entrada / 1,000), mínimo 1, e os tokens de saída são gratuitos. No teste acima, uma requisição de 401 tokens com duas perguntas custou exatamente 1 crédito. No pacote Starter ($10 = 100,000 créditos), isso dá $0.0001 por decisão.

Latência: em 16 chamadas reais sucessivas em um único dia útil, a latency_ms reportada se concentrou entre 400–560 ms tanto para requisições de uma quanto de duas perguntas, com mediana perto de 445 ms. A primeira chamada depois de um período ocioso teve um cold start ocasional de ~3 s; caudas mais longas não foram observadas nesse tamanho de amostra. Defina seu timeout pelo p99 da sua própria região em vez de confiar nesta única medição.

Posso fazer mais de 8 perguntas em uma requisição?

Não — o limite é de 8 perguntas por requisição. Divida o restante em uma segunda requisição sobre o mesmo estado, ou mova as perguntas de menor valor para um caminho mais barato em lote.

Onde consigo meus primeiros créditos gratuitos?

Todo novo workspace começa com 5 créditos gratuitos, e o playground é gratuito no navegador (30 execuções por dia de forma anônima, 50 quando logado). Cinco créditos bastam para validar uma decisão com dados reais antes de pagar qualquer coisa.

Este é o endpoint oficial da TypeSafe?

Não. A Optio é um gateway independente para chamar o Jev e não tem vínculo com a TypeSafe. O formato da requisição segue o mesmo contrato /v1/systemone, então clientes existentes podem apontar para ele.

Teste o playground do Jev AI para enviar sua primeira decisão gratuita depois de terminar este guia.