Jev API answers bounded questions about a piece of text or data. You send a state (the facts) and a set of typed questions. You get back structured answers with probabilities, plus the token usage for the call. There is no chat endpoint and no free-form text generation: the API is built for classification, routing, scoring and yes/no judgments that your code can act on directly.
This tutorial goes from a new account to your first decision. You will create an account, add credit, mint an API key, check that the key works, send a request with curl, and learn how to read each part of the response. Allow about five minutes, plus however long the card payment takes.
What you need
- A terminal with
curl.jqis optional but makes JSON output easier to read. - A payment card for Stripe Checkout. The minimum top-up is $5.
- A short piece of text you want to classify. The examples below use a customer support message.
Step 1: Create an account
Open the registration page and sign up with an email address and a password of at least 8 characters. No verification email or OAuth flow is involved. You are signed in straight away and taken to the dashboard, where you manage your balance, API keys, usage history and ledger.
Step 2: Add prepaid credit
Jev API is prepaid. Every successful call deducts its cost from your balance, so calls only work once the balance is above zero. On the dashboard, find the Add credit card, enter a whole-dollar amount (minimum $5) and click Pay with Stripe. You complete the payment on Stripe Checkout and come back to the dashboard.
Credit is applied when Stripe's signed webhook confirms the payment, so the balance may take a moment to update. Reload the dashboard if it still shows the old amount. Two terms are worth knowing before you pay. Purchased credits are non-refundable, and they cannot be withdrawn or cashed out (see the Terms of Service). Start with a small top-up until you have measured your real usage. The cost guide shows how to estimate it.
You can create keys before adding credit. Until the balance covers a call, POST /v1/systemone returns HTTP 402 with the error code insufficient_balance.
Step 3: Create an API key
In the New API key card, give the key a name that says where it will be used, such as support-triage-prod, and pick an environment:
- live keys start with
jev_live_ - test keys start with
jev_test_
Both kinds authenticate against the same endpoints and are billed from the same prepaid balance. Treat the environment as a label for organising keys, not as a free sandbox. The full key is shown once, right after you create it. Jev API keeps only a SHA-256 hash and a short prefix, which is what the keys table shows afterwards. Copy the key into a secret store or an environment variable straight away:
export JEV_API_KEY="jev_live_xxx" # paste your real key here; never commit it
If a key leaks, click Revoke next to it on the dashboard. Requests with that key then fail with 401 Invalid or revoked API key.
Step 4: Check the key with GET /v1/models
GET /v1/models uses the same Bearer authentication as the decision endpoint. It does not run a model and does not deduct credit, so it is a safe way to confirm that your key and network path work:
curl -s https://jev-api.com/v1/models \
-H "Authorization: Bearer $JEV_API_KEY"
A valid key returns a models array with the aliases jev-latest and jev-preview, each with a name, description and release_date:
{
"models": [
{ "name": "jev-latest", "description": "…", "release_date": "2026-09-10T18:38:01.391457+00:00" },
{ "name": "jev-preview", "description": "…", "release_date": "2026-09-10T18:39:06.057655+00:00" }
]
}
The pinned version jev-1.13.0 is not in this list, but the decision endpoint accepts it.
Step 5: Send your first decision
Now call POST /v1/systemone. The request body has three fields:
model: which model to use.jev-latestis a sensible default.state: the facts the decision is about. It can be a string, an object or an array.questions: an object whose keys are your own identifiers and whose values are typed questions.
This request asks three things about a single support message: which team should handle it (choice), how urgent it is (score), and whether the customer wants money back (noul).
curl -s https://jev-api.com/v1/systemone \
-H "Authorization: Bearer $JEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "jev-latest",
"state": "Hi, I was charged twice for my March invoice and need one of the charges reversed before my card statement closes on Friday.",
"questions": {
"department": {
"type": "choice",
"instructions": "Which team should handle this message?",
"criteria": {
"billing": "Charges, invoices, refunds or subscription changes",
"technical": "Bugs, outages, errors or integration problems",
"sales": "Pricing questions or new purchases"
}
},
"urgency": {
"type": "score",
"instructions": "How urgent is this message?",
"criteria": ["Routine", "Needs attention this week", "Needs attention today"]
},
"wants_refund": {
"type": "noul",
"instructions": "Is the customer asking for money back?"
}
}
}'
The Authorization header must be exactly Bearer, one space, then the key. Pipe the output through jq if you want it pretty-printed.
Step 6: Read the response
A successful call returns HTTP 200 with model, answers and usage. The numbers below are illustrative. Yours will differ.
{
"model": "jev-1.13.0",
"answers": {
"department": {
"type": "choice",
"choice": "billing",
"confidence": 0.9,
"probabilities": { "billing": 0.94, "technical": 0.04, "sales": 0.02 }
},
"urgency": {
"type": "score",
"score": 2.0,
"confidence": 0.8,
"legend": { "0": "Routine", "1": "Needs attention this week", "2": "Needs attention today" },
"probabilities": { "0": 0.02, "1": 0.13, "2": 0.85 }
},
"wants_refund": { "type": "noul", "noul": 0.97 }
},
"usage": { "input_tokens": 310, "output_tokens": 58 }
}
Choice answers
choice is one of the keys you defined in criteria. probabilities gives a value for every option, and confidence summarises how decisive the answer is. In code, branch on choice. Use confidence or the probability gap between the top two options if you want to send uncertain cases to a person.
Score answers
Score questions take an ordered list of criteria, lowest level first. The response repeats the levels in legend, keyed "0", "1", "2" and so on, with a probability for each level and a numeric score on that scale. Keep the number for sorting and thresholds, and use legend to show a human-readable label.
Noul answers
A noul answer is a single value between 0 and 1: how strongly the state supports a “yes”. The API does not turn it into true or false for you. You choose the threshold that fits your workflow. The question design guide shows one way to pick it.
Model and usage
The response model is a versioned ID such as jev-1.13.0, even when you requested an alias like jev-latest. Log it next to each decision so you can tell later which version produced which result. usage.input_tokens is what you are billed for. Output tokens are free. At $0.084 per million input tokens, the 310-token call above costs 310 × 0.084 = 26.04 micro-dollars, rounded up to $0.000027.
When something goes wrong
Errors use one JSON envelope on every endpoint:
{ "error": { "code": "unauthorized", "message": "Invalid or revoked API key.", "request_id": "req_…" } }
Every response, successful or not, also carries an x-request-id header with the same ID. Note it when you report a problem. These are the errors you are most likely to see on a first call:
| Status | error.code | Example error.message | What it means |
|---|---|---|---|
| 400 | invalid_request | JSON body is required. | The body is missing or is not valid JSON. |
| 400 | invalid_request | Field `model` is required. | No model string was sent. |
| 400 | invalid_request | Field `state` is required (string, object, or array). | The state key is absent. |
| 400 | invalid_request | Field `questions` must be an object of typed questions. | questions is missing, is an array, or is not an object. |
| 400 | invalid_request | At least one question is required. | questions is an empty object. |
| 400 | invalid_request | Unknown model. Use one of: jev-latest, jev-preview, jev-1.13.0. | The model ID is not one the API accepts. |
| 400 | invalid_request | The model request failed validation. | The request passed the basic checks, but the questions were rejected, for example because a question is malformed. |
| 401 | unauthorized | Provide a Bearer API key (jev_live_… or jev_test_…). | No Authorization: Bearer … header was sent. |
| 401 | unauthorized | Invalid or revoked API key. | The key is mistyped, does not exist, or was revoked on the dashboard. |
| 402 | insufficient_balance | Balance 0.000000 USD is below the estimated 0.000057 USD charge. | Your prepaid balance does not cover the estimated cost of this call. |
| 429 | service_error | The model service could not complete the request. | The model service is rate limiting requests. Back off and retry. |
| 502 | service_error | The model service could not be reached. | A temporary failure behind the API. Also used for “could not complete the request” and “returned an unexpected response”. |
| 503 | service_error | The model service is temporarily unavailable. | Model requests are not available right now. |
| 500 | internal_error | An unexpected error occurred. | An unhandled server error. |
Authentication is checked before the body. A request with a bad key and a bad body therefore returns 401, not 400. Requests that end in an error are not charged, because credit is deducted only after a call succeeds.
Choosing a model
Three model IDs are available, all at the same price:
jev-latestfollows the current stable Jev release.jev-previewfollows the newest release, including previews.jev-1.13.0pins a version. Use it when thresholds you tuned must stay stable from one request to the next.
Start on jev-latest while you experiment. Switch to the pinned version once you have tuned thresholds against real data.
Next steps
You now have a working key and know how to read each answer type. From here, move the call into your application code and harden it:
- Docs: account, key and credit setup from start to finish.
- API reference: the full request and response contract for
POST /v1/systemoneandGET /v1/models. - Pricing: current per-token price and how prepaid credit works.
More tutorials on this blog:
- Calling Jev API from Python: a robust client with timeouts, retries and error handling
- Using Jev API from Node.js and TypeScript with typed, validated responses
- Designing decision questions: how to frame state and criteria for reliable typed answers
- Controlling cost on Jev API: estimating tokens, tracking usage and managing prepaid credit