Quick start
Send us the JSON you send Jev. In minutes you get back your own model that answers the same questions, in the same shape, with your rules enforced. No past decisions or answers needed; a few examples of what you send Jev make it better. You need an API key from the console.
Early access: the hosted API opens to teams on the waitlist first. The base URL is https://api.canonopylabs.com.
Prefer clicking? In the console, New model, then Paste your Jev request: paste it, paste a few more example states if you have them, add your rules, and when it's ready the page gives you the model to call.
1. Send the JSON you send Jev
Take a request your code sends Jev today, as it is. Add 5-20 more real states in examples (states only, no answers: a quiet moment and a busy one, a small order and a large one), notes on what fields mean in fields if a name doesn't say it, your rules in plain words if you like, and a name.
curl https://api.canonopylabs.com/v1/build \
-H "Authorization: Bearer $CANONOPY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "jev-latest",
"state": { "order": { "amount": 42.5 }, "customer": { "tier": "pro", "fraud_flag": false } },
"questions": {
"action": { "type": "choice", "instructions": "What should we do with this refund request?",
"criteria": { "approve": "refund the customer", "escalate": "a person decides",
"decline": "politely decline" } },
"urgent": { "type": "noul", "instructions": "Does this need a person within the hour?" }
},
"examples": [
{ "order": { "amount": 820 }, "customer": { "tier": "free", "fraud_flag": false } },
{ "order": { "amount": 12.99 }, "customer": { "tier": "pro", "fraud_flag": true } }
],
"fields": { "order.amount": "the refund asked for, in USD (0-5,000)" },
"rules": "Never approve when amount is over 500. Always escalate when fraud_flag is true.",
"name": "refunds"
}'The answer comes at once. model is ignored, so a pasted request works as is. Check understood first: the fields read from your example (here order_amount, customer_tier and customer_fraud_flag), and the rules that will be enforced on every decision. With fields, understood.field_notes shows each note and the field it went to, and understood.field_notes_not_matched any note that matched no field. With a single state and no examples, notes reminds you that 5-20 real examples make a better model.
{ "build_id": "bld_…", "domain": "refunds", "model": "refunds@latest", "status": "queued", "phase": "understanding",
"understood": { "state": "object",
"fields": [{ "name": "order_amount", "path": "order.amount", "type": "number" }, "…"],
"decision_question": "action",
"rules": ["Never approve when amount is over 500.", "Always escalate when fraud_flag is true."],
"rules_not_understood": [] } }2. Wait for ready
There is nothing to do in between: the build goes queued → building → training → checking → ready, usually in a few minutes. Follow it with GET /v1/domains/refunds/build (or canonopy build status refunds; --wait and wait_for_build return when it's ready). Each question has to agree with your instructions and rules at least 95% of the time on fresh situations before it serves; ready means it passed. If one doesn't, the build is needs_attention and says where it's weakest and what to change. See the quality check.
3. Review how it decides (optional)
Your model is ready in minutes. Review how it decides any time (optional): about 20 situations, each with the answer your model gives and why. Nothing waits on them.
curl https://api.canonopylabs.com/v1/domains/refunds/examples -H "Authorization: Bearer $CANONOPY_API_KEY"If one is wrong, send only the ones you correct, with "retrain": true to retrain in the same call (about a minute):
curl https://api.canonopylabs.com/v1/domains/refunds/signoff -H "Authorization: Bearer $CANONOPY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"examples": [{"id": "ex_02", "ok": false, "correct": {"action": "escalate"}}], "retrain": true}'Or canonopy examples refunds, then canonopy signoff refunds --correct ex_02:action=escalate --retrain. The retrained model gives those answers. In the console, it's Review examples on the model's page.
4. Switch over and keep sending the same JSON
Change two things in the code that calls Jev: the base URL and the model name.
- POST https://api.typesafe.ai/v1/systemone "model": "jev-latest"
+ POST https://api.canonopylabs.com/v1/systemone "model": "refunds@latest"/v1/systemone is an alias of /v1/decide with the same body. The request and answer shapes are Jev's, and usage.input_tokens is still there so client code that reads it doesn't break (it isn't billed).
curl https://api.canonopylabs.com/v1/decide \
-H "Authorization: Bearer $CANONOPY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "refunds@latest",
"state": { "order": { "amount": 820 }, "customer": { "tier": "pro", "fraud_flag": false } },
"questions": {
"action": { "type": "choice", "instructions": "What should we do with this refund request?",
"criteria": { "approve": "refund the customer", "escalate": "a person decides",
"decline": "politely decline" } },
"urgent": { "type": "noul", "instructions": "Does this need a person within the hour?" }
}
}'The answer:
{
"id": "dec_4f1c2a9b0e7d6a51",
"model": "refunds@1",
"answers": {
"action": { "type": "choice", "choice": "escalate", "confidence": 0.9705,
"probabilities": { "approve": 0.0, "escalate": 0.9705, "decline": 0.0295 },
"source": "trained", "route": "act" },
"urgent": { "type": "noul", "noul": 0.09, "source": "trained", "route": "act" }
},
"decision": { "question": "action", "action": "escalate", "confidence": 0.9705,
"blocked_by_rules": ["never-approve-when-amount-is-over-500"], "blocked_actions": ["approve"], "route": "act" },
"language": "en",
"usage": { "input_tokens": 118, "output_tokens": 0, "decisions": 1 }
}sourcetells you who answered: your own model (trained), your day-one backend (fallback), or your rules alone (rule).routeon each answer, anddecision.route, isact(automatic, at or above the model's safety bar) orreview(held for a person);decision.routecan also beask(your rules allow no action).decisionis the final action with your rules applied: here the amount is over 500, soapproveis blocked whatever the model thinks. See Decisions and rules.- Keep
id: report what really happened withPOST /v1/outcomes, or mark the decision wrong.
5. Make it better, when you like
Your model is ready with no data. It gets better as you use it, and every retrain is your call:
- Add your history. Send your past cases in
history, or upload them, and build again: your cases become the main examples, and your model is measured on your own held-back cases. See Make it better with your history. - Confirm the rules found in your history. Each one comes with how many past cases it covers and what confirming it changes. See Rules found in your history.
- Answer a few unsure cases, then retrain.
GET /v1/domains/refunds/advicesays what would help most right now. A retrain takes about a minute and shows a before and after. See Improve your model.
Just trying a call?
The Playground sends a state to any of your models and shows each answer with its source, the decision and the rules that fired. Every run has a share link.
A model that doesn't exist yet is created on its first call in day-one mode, with the questions that call asked: until it has a model of its own, your day-one backend (your own Jev key, an OpenAI-compatible model or our built-in one) answers in the same shape ("source": "fallback"), and a day-one answer below 0.8 confidence is review. A model starting with jev- maps to your default model.
Other ways in
The API is all you need: every way in below is optional. The one package you'd install is canonopy-runtime, and only to run a downloaded model yourself.
- Coding agents: connect Claude Code, Cursor or Codex to the hosted MCP connector, nothing to install:
claude mcp add --transport http canonopy https://api.canonopylabs.com/mcp --header "Authorization: Bearer cnp_…". Then ask it to "build a Canonopy model from the Jev request insrc/refunds.py". See Use with coding agents. - CLI: the
canonopycommand for builds, examples, versions and more:pip install https://canonopylabs.com/dl/canonopy_cli-0.6.2-py3-none-any.whl. See the CLI reference. - Python SDK: mirrors Jev's
Choice,ScoreandNoul(from canonopy import Client), and@canonopy.fnin place of@jev.fn:pip install https://canonopylabs.com/dl/canonopy_decisions-0.4.0-py3-none-any.whl. See Start with no data. - Run it yourself: download a version and run it with
canonopy-runtime. See Running it yourself.