Send one request with your own labels
Install requests, keep the key in an environment variable, and post one bounded task: the text, the instruction that separates your outcomes, the labels your process already uses, and a threshold. The endpoint accepts text of 3–6,000 characters, instructions of 3–1,500 characters, 2–12 unique labels of up to 60 characters, and a threshold between 0.5 and 1 that defaults to 0.85.
Send an Idempotency-Key of 8–100 characters with every request. If the connection drops after the server has stored a decision, retrying with the same key returns that decision with replayed: true instead of charging a second credit.
import os, requests
key = os.environ["JEV_API_KEY"]
url = "https://jevapi.pro/api/v1/decisions"
teams = ["Billing", "Support", "Access"]
payload = {
"text": row_text,
"instructions": "Pick the owning team.",
"labels": teams,
"threshold": 0.85,
}
answer = requests.post(
url,
headers={
"Authorization": "Bearer " + key,
"Idempotency-Key": "row-1042-v3",
},
json=payload,
timeout=30,
).json()
if answer["needsReview"]:
review(answer["id"])
else:
route(answer["choice"])Read the answer as evidence, not as a verdict
A new decision answers 201 with id, choice, confidence, probabilities, needsReview, model and latencyMs, and an account request also returns the credits left. confidence is null when the model omits it, and needsReview is true in that case and whenever the reported confidence falls below your threshold.
probabilities is checked for domain and bounds only. Nothing promises that its values sum to one or that the largest one matches the returned label, so read choice instead of sorting a dictionary to guess the answer, and treat a label outside your list as a refusal rather than a fallback.
Loop over a file without paying twice
For a CSV, send rows one at a time and pace the calls to your published rate limit. Derive the idempotency key from the row itself — a message id plus the version of the rule — never from its position: a re-export with one new row at the top would shift every key and pay again for work you already did.
A 502 or 503 returns the credit and leaves no decision behind, so that row is safe to retry, while a 429 means you are sending faster than your allowance and a 402 means the account is out of credits. Store the state next to the answer so a failed row can be retried without reading the export a second time.
If you would rather not write the loop yet, the batch workspace runs the same rule over a pasted list or an uploaded file in the browser and exports every row, including the ones that failed.
When a model you host fits better
A scikit-learn or transformer model you run yourself is the cheaper choice when your labels are stable, your volume is high, and you can operate the model: no per-row cost, no network hop, and full control over latency.
An endpoint fits when the labels follow the process rather than the data, when you would rather not serve inference yourself, and when you want an uncertain answer flagged instead of guessed. The two combine: classify everything, then send only the low-confidence rows to a model you host or to a person.
Either way, measure on a held-out set of rows your team labelled, not on the examples you wrote the rule from. A rule that scores well on its own examples has usually just learned those examples.