Routing Studio
Create Routing Preference
Author a new Routing Studio preference.
POST
/
api
/
v1
/
routing-preferences
Create Routing Preference
curl --request POST \
--url https://api.example.com/api/v1/routing-preferences \
--header 'Content-Type: application/json' \
--data '
{
"name": "<string>",
"description": "<string>",
"rules": [
{}
],
"examples": [
{}
],
"confidence_floor_overrides": {},
"scope": "<string>",
"is_default": true
}
'import requests
url = "https://api.example.com/api/v1/routing-preferences"
payload = {
"name": "<string>",
"description": "<string>",
"rules": [{}],
"examples": [{}],
"confidence_floor_overrides": {},
"scope": "<string>",
"is_default": True
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
name: '<string>',
description: '<string>',
rules: [{}],
examples: [{}],
confidence_floor_overrides: {},
scope: '<string>',
is_default: true
})
};
fetch('https://api.example.com/api/v1/routing-preferences', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/api/v1/routing-preferences",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'name' => '<string>',
'description' => '<string>',
'rules' => [
[
]
],
'examples' => [
[
]
],
'confidence_floor_overrides' => [
],
'scope' => '<string>',
'is_default' => true
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/api/v1/routing-preferences"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"description\": \"<string>\",\n \"rules\": [\n {}\n ],\n \"examples\": [\n {}\n ],\n \"confidence_floor_overrides\": {},\n \"scope\": \"<string>\",\n \"is_default\": true\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/api/v1/routing-preferences")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"description\": \"<string>\",\n \"rules\": [\n {}\n ],\n \"examples\": [\n {}\n ],\n \"confidence_floor_overrides\": {},\n \"scope\": \"<string>\",\n \"is_default\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/v1/routing-preferences")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"<string>\",\n \"description\": \"<string>\",\n \"rules\": [\n {}\n ],\n \"examples\": [\n {}\n ],\n \"confidence_floor_overrides\": {},\n \"scope\": \"<string>\",\n \"is_default\": true\n}"
response = http.request(request)
puts response.read_bodyCreate a new Routing Studio preference. Idempotent — the same
Idempotency-Key header replays the same response.
Creating a preference does not auto-bind it to a key. Use PUT /api/v1/keys//routing-preference to opt a key in, or edit rules directly on a key via PUT /api/v1/keys//routing-rules.
Authentication
Requires a Bearer token with thebilling API key scope.
Body
string
required
Preference name. 1–128 chars. May not reference upstream provider names (Claude, OpenAI, Anthropic, Gemini, fal.ai, etc.).
string
Free-text description. Up to 512 chars.
object[]
Up to 50 keyword/regex rules. Each rule has
pattern (ECMAScript regex source, ≤512 chars), target_mode (a Theo mode), optional target_engine (Theo-branded engine id), confidence (clamped server-side to [0.5, 0.99]), and an optional description.object[]
Up to 30 few-shot examples injected into the classifier’s system prompt. Each example has
prompt (≤1024 chars), expected_mode, and optional expected_engine.object
Per-mode replacements for the global
0.85 promotion floor. Values are clamped to [0.5, 0.99].string
"personal" (default) or "team". Team scope requires an active org and the manageWebhooks permission.boolean
Mark this preference as the default for its scope. At most one default per scope.
Request Examples
curl -X POST https://www.hitheo.ai/api/v1/routing-preferences \
-H "Authorization: Bearer $THEO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "ContractIQ Legal",
"description": "Contract terms get the analytical engine.",
"rules": [
{
"pattern": "\\b(clause|provision|indemnity|warranty)\\b",
"target_mode": "think",
"confidence": 0.92,
"description": "Contract terms get the analytical engine."
}
],
"examples": [
{ "prompt": "Look at this clause", "expected_mode": "think" }
]
}'
const pref = await theo.routingPreferences.create({
name: "ContractIQ Legal",
description: "Contract terms get the analytical engine.",
rules: [
{
pattern: "\\b(clause|provision|indemnity|warranty)\\b",
target_mode: "think",
confidence: 0.92,
description: "Contract terms get the analytical engine.",
},
],
examples: [{ prompt: "Look at this clause", expected_mode: "think" }],
});
Errors
400 routing_preference_invalid— Vendor-named label or pattern, uncompilable regex, unknown engine, or rule/example cap exceeded.400 org_required—scope: "team"without an active organization.403 missing_scope— API key lacks thebillingscope.409 conflict—is_default: truealready set for this scope.
Was this page helpful?
Create Routing Preference
curl --request POST \
--url https://api.example.com/api/v1/routing-preferences \
--header 'Content-Type: application/json' \
--data '
{
"name": "<string>",
"description": "<string>",
"rules": [
{}
],
"examples": [
{}
],
"confidence_floor_overrides": {},
"scope": "<string>",
"is_default": true
}
'import requests
url = "https://api.example.com/api/v1/routing-preferences"
payload = {
"name": "<string>",
"description": "<string>",
"rules": [{}],
"examples": [{}],
"confidence_floor_overrides": {},
"scope": "<string>",
"is_default": True
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
name: '<string>',
description: '<string>',
rules: [{}],
examples: [{}],
confidence_floor_overrides: {},
scope: '<string>',
is_default: true
})
};
fetch('https://api.example.com/api/v1/routing-preferences', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/api/v1/routing-preferences",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'name' => '<string>',
'description' => '<string>',
'rules' => [
[
]
],
'examples' => [
[
]
],
'confidence_floor_overrides' => [
],
'scope' => '<string>',
'is_default' => true
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/api/v1/routing-preferences"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"description\": \"<string>\",\n \"rules\": [\n {}\n ],\n \"examples\": [\n {}\n ],\n \"confidence_floor_overrides\": {},\n \"scope\": \"<string>\",\n \"is_default\": true\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/api/v1/routing-preferences")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"description\": \"<string>\",\n \"rules\": [\n {}\n ],\n \"examples\": [\n {}\n ],\n \"confidence_floor_overrides\": {},\n \"scope\": \"<string>\",\n \"is_default\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/v1/routing-preferences")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"<string>\",\n \"description\": \"<string>\",\n \"rules\": [\n {}\n ],\n \"examples\": [\n {}\n ],\n \"confidence_floor_overrides\": {},\n \"scope\": \"<string>\",\n \"is_default\": true\n}"
response = http.request(request)
puts response.read_body