curl --request PUT \
--url https://gateway.errorbar.ai/v1/aliases \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "support-bot",
"target_model": "Qwen/Qwen3-32B",
"canary_model": "<string>",
"canary_percent": 0,
"description": "switched after eval ev_123 (90% win, -88% cost)",
"gate_criterion_id": "<string>",
"gate_mode": "recommend",
"gate_min_samples": 50,
"gate_rollback_threshold": 0.7,
"gate_window_hours": 168,
"require_evidence": true,
"override_reason": "<string>"
}
'import requests
url = "https://gateway.errorbar.ai/v1/aliases"
payload = {
"name": "support-bot",
"target_model": "Qwen/Qwen3-32B",
"canary_model": "<string>",
"canary_percent": 0,
"description": "switched after eval ev_123 (90% win, -88% cost)",
"gate_criterion_id": "<string>",
"gate_mode": "recommend",
"gate_min_samples": 50,
"gate_rollback_threshold": 0.7,
"gate_window_hours": 168,
"require_evidence": True,
"override_reason": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.put(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PUT',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: 'support-bot',
target_model: 'Qwen/Qwen3-32B',
canary_model: '<string>',
canary_percent: 0,
description: 'switched after eval ev_123 (90% win, -88% cost)',
gate_criterion_id: '<string>',
gate_mode: 'recommend',
gate_min_samples: 50,
gate_rollback_threshold: 0.7,
gate_window_hours: 168,
require_evidence: true,
override_reason: '<string>'
})
};
fetch('https://gateway.errorbar.ai/v1/aliases', 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://gateway.errorbar.ai/v1/aliases",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode([
'name' => 'support-bot',
'target_model' => 'Qwen/Qwen3-32B',
'canary_model' => '<string>',
'canary_percent' => 0,
'description' => 'switched after eval ev_123 (90% win, -88% cost)',
'gate_criterion_id' => '<string>',
'gate_mode' => 'recommend',
'gate_min_samples' => 50,
'gate_rollback_threshold' => 0.7,
'gate_window_hours' => 168,
'require_evidence' => true,
'override_reason' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"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://gateway.errorbar.ai/v1/aliases"
payload := strings.NewReader("{\n \"name\": \"support-bot\",\n \"target_model\": \"Qwen/Qwen3-32B\",\n \"canary_model\": \"<string>\",\n \"canary_percent\": 0,\n \"description\": \"switched after eval ev_123 (90% win, -88% cost)\",\n \"gate_criterion_id\": \"<string>\",\n \"gate_mode\": \"recommend\",\n \"gate_min_samples\": 50,\n \"gate_rollback_threshold\": 0.7,\n \"gate_window_hours\": 168,\n \"require_evidence\": true,\n \"override_reason\": \"<string>\"\n}")
req, _ := http.NewRequest("PUT", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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.put("https://gateway.errorbar.ai/v1/aliases")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"support-bot\",\n \"target_model\": \"Qwen/Qwen3-32B\",\n \"canary_model\": \"<string>\",\n \"canary_percent\": 0,\n \"description\": \"switched after eval ev_123 (90% win, -88% cost)\",\n \"gate_criterion_id\": \"<string>\",\n \"gate_mode\": \"recommend\",\n \"gate_min_samples\": 50,\n \"gate_rollback_threshold\": 0.7,\n \"gate_window_hours\": 168,\n \"require_evidence\": true,\n \"override_reason\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://gateway.errorbar.ai/v1/aliases")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"support-bot\",\n \"target_model\": \"Qwen/Qwen3-32B\",\n \"canary_model\": \"<string>\",\n \"canary_percent\": 0,\n \"description\": \"switched after eval ev_123 (90% win, -88% cost)\",\n \"gate_criterion_id\": \"<string>\",\n \"gate_mode\": \"recommend\",\n \"gate_min_samples\": 50,\n \"gate_rollback_threshold\": 0.7,\n \"gate_window_hours\": 168,\n \"require_evidence\": true,\n \"override_reason\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"name": "support-bot",
"target_model": "<string>",
"canary_model": "<string>",
"canary_percent": 123,
"description": "<string>",
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"gate_criterion_id": "<string>",
"gate_mode": "recommend",
"gate_verdict": {},
"gate_verdict_at": "2023-11-07T05:31:56Z",
"gate_min_samples": 123,
"gate_rollback_threshold": 123,
"gate_window_hours": 123,
"model_version_id": "<string>",
"require_evidence": true,
"last_evidence_run_id": "<string>"
}{
"error": {
"message": "<string>",
"type": "<string>",
"code": "<string>"
}
}{
"error": {
"message": "Invalid API key",
"type": "invalid_request_error",
"code": "invalid_api_key"
}
}{
"error": {
"message": "<string>",
"type": "<string>",
"code": "<string>"
}
}{
"error": {
"message": "<string>",
"type": "<string>",
"code": "<string>"
}
}Create or repoint an alias
Point a stable name at a model — and repoint it whenever you like, with no change to your code.
Your application keeps calling support-bot; the next request after a repoint already routes to the new model. This is what makes an eval result actionable: prove a cheaper model holds up, then repoint.
Upsert by name, so CI can repoint idempotently without a lookup first. Owner/admin key required — repointing silently redirects live production traffic, so it’s audited with the before/after.
You are always billed for the model that RAN. An alias is a routing decision, never a pricing one.
curl --request PUT \
--url https://gateway.errorbar.ai/v1/aliases \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "support-bot",
"target_model": "Qwen/Qwen3-32B",
"canary_model": "<string>",
"canary_percent": 0,
"description": "switched after eval ev_123 (90% win, -88% cost)",
"gate_criterion_id": "<string>",
"gate_mode": "recommend",
"gate_min_samples": 50,
"gate_rollback_threshold": 0.7,
"gate_window_hours": 168,
"require_evidence": true,
"override_reason": "<string>"
}
'import requests
url = "https://gateway.errorbar.ai/v1/aliases"
payload = {
"name": "support-bot",
"target_model": "Qwen/Qwen3-32B",
"canary_model": "<string>",
"canary_percent": 0,
"description": "switched after eval ev_123 (90% win, -88% cost)",
"gate_criterion_id": "<string>",
"gate_mode": "recommend",
"gate_min_samples": 50,
"gate_rollback_threshold": 0.7,
"gate_window_hours": 168,
"require_evidence": True,
"override_reason": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.put(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PUT',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: 'support-bot',
target_model: 'Qwen/Qwen3-32B',
canary_model: '<string>',
canary_percent: 0,
description: 'switched after eval ev_123 (90% win, -88% cost)',
gate_criterion_id: '<string>',
gate_mode: 'recommend',
gate_min_samples: 50,
gate_rollback_threshold: 0.7,
gate_window_hours: 168,
require_evidence: true,
override_reason: '<string>'
})
};
fetch('https://gateway.errorbar.ai/v1/aliases', 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://gateway.errorbar.ai/v1/aliases",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode([
'name' => 'support-bot',
'target_model' => 'Qwen/Qwen3-32B',
'canary_model' => '<string>',
'canary_percent' => 0,
'description' => 'switched after eval ev_123 (90% win, -88% cost)',
'gate_criterion_id' => '<string>',
'gate_mode' => 'recommend',
'gate_min_samples' => 50,
'gate_rollback_threshold' => 0.7,
'gate_window_hours' => 168,
'require_evidence' => true,
'override_reason' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"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://gateway.errorbar.ai/v1/aliases"
payload := strings.NewReader("{\n \"name\": \"support-bot\",\n \"target_model\": \"Qwen/Qwen3-32B\",\n \"canary_model\": \"<string>\",\n \"canary_percent\": 0,\n \"description\": \"switched after eval ev_123 (90% win, -88% cost)\",\n \"gate_criterion_id\": \"<string>\",\n \"gate_mode\": \"recommend\",\n \"gate_min_samples\": 50,\n \"gate_rollback_threshold\": 0.7,\n \"gate_window_hours\": 168,\n \"require_evidence\": true,\n \"override_reason\": \"<string>\"\n}")
req, _ := http.NewRequest("PUT", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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.put("https://gateway.errorbar.ai/v1/aliases")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"support-bot\",\n \"target_model\": \"Qwen/Qwen3-32B\",\n \"canary_model\": \"<string>\",\n \"canary_percent\": 0,\n \"description\": \"switched after eval ev_123 (90% win, -88% cost)\",\n \"gate_criterion_id\": \"<string>\",\n \"gate_mode\": \"recommend\",\n \"gate_min_samples\": 50,\n \"gate_rollback_threshold\": 0.7,\n \"gate_window_hours\": 168,\n \"require_evidence\": true,\n \"override_reason\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://gateway.errorbar.ai/v1/aliases")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"support-bot\",\n \"target_model\": \"Qwen/Qwen3-32B\",\n \"canary_model\": \"<string>\",\n \"canary_percent\": 0,\n \"description\": \"switched after eval ev_123 (90% win, -88% cost)\",\n \"gate_criterion_id\": \"<string>\",\n \"gate_mode\": \"recommend\",\n \"gate_min_samples\": 50,\n \"gate_rollback_threshold\": 0.7,\n \"gate_window_hours\": 168,\n \"require_evidence\": true,\n \"override_reason\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"name": "support-bot",
"target_model": "<string>",
"canary_model": "<string>",
"canary_percent": 123,
"description": "<string>",
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"gate_criterion_id": "<string>",
"gate_mode": "recommend",
"gate_verdict": {},
"gate_verdict_at": "2023-11-07T05:31:56Z",
"gate_min_samples": 123,
"gate_rollback_threshold": 123,
"gate_window_hours": 123,
"model_version_id": "<string>",
"require_evidence": true,
"last_evidence_run_id": "<string>"
}{
"error": {
"message": "<string>",
"type": "<string>",
"code": "<string>"
}
}{
"error": {
"message": "Invalid API key",
"type": "invalid_request_error",
"code": "invalid_api_key"
}
}{
"error": {
"message": "<string>",
"type": "<string>",
"code": "<string>"
}
}{
"error": {
"message": "<string>",
"type": "<string>",
"code": "<string>"
}
}Authorizations
Your workspace API key, e.g. sk_sovereign_..., sent as Authorization: Bearer <key>.
Body
3–64 chars (letters, numbers, dots, dashes, underscores). Scoped to your workspace — a name that isn't an alias is treated as a normal model id, so aliases never shadow the catalog.
"support-bot"
The model requests route to. Validated against the live catalog.
"Qwen/Qwen3-32B"
Optional. A share of requests route here instead — for a gradual cutover.
0 = no split. 100 = full cutover. The split is per REQUEST, not per user.
0 <= x <= 100200"switched after eval ev_123 (90% win, -88% cost)"
Turn the canary split into a supervised rollout: the online scorer judges BOTH arms with this criterion and the gate decides: promote when the canary's observed-rate CI lower bound reaches the incumbent's observed rate, roll back when the canary's corrected point estimate sits below gate_rollback_threshold. The criterion must have been aligned against your labels.
recommend: verdicts surface on GET /v1/aliases (gate_verdict) and via alert notifications — you click the button. auto: the gate may repoint the alias itself (promote) or zero the canary (roll back), always audited with the numbers. Auto requires a criterion whose trust is trustworthy (both TPR and TNR CI LOWER bounds clear 90%) and that is not drift-flagged: a judge may recommend with a weaker signal, but it doesn't get the keys.
recommend, auto No verdict of any kind until BOTH arms have this many scored requests.
10 <= x <= 1000Roll back when the canary's corrected pass rate (POINT estimate, not a CI bound) sits below this. Rollback is the safe action (the champion keeps serving), so it triggers on the best estimate; promotion needs the canary's observed-rate Wilson lower bound to reach the incumbent's observed rate.
0 <= x <= 1Scores older than this don't count toward the verdict.
1 <= x <= 720Omitted = leave the alias's existing policy alone (a plain repoint can't quietly switch the policy off); false on create. With it on, a PUT that routes traffic to a model it isn't already reaching must be backed by a finished comparison in this workspace, within the last 30 days, whose candidate win-rate CI lower bound clears 50% against the model traffic is leaving. Refusals are 412.
The audited escape hatch for an evidence refusal: a written justification of at least 10 characters lets the repoint through and writes an audit event naming the actor, both models, and the reason. Omitted or blank is not an override.
Response
The alias.
The name you put in model.
"support-bot"
The model this resolves to today.
0–100. Share of requests routed to canaryModel.
recommend, auto The last gate evaluation: {decision: promote|rollback|hold, reason, canary: {model, judged, observed_pass_rate, observed_ci, rate, ci, corrected}, incumbent: {...same}, acted: none|promoted|rolled_back}. rate/ci are corrected when the judge carries measured TPR/TNR (corrected: true), observed otherwise. Promotion compares observed rates (same judge on both arms, so judge error cancels); rollback compares the corrected point estimate to gate_rollback_threshold.
No gate verdict until both canary arms have this many scored samples in the window.
Roll back when the canary's corrected pass rate (point estimate, not a CI bound) sits below this. Rollback is the safe action, so it triggers on the best estimate; promotion is what needs proof.
Scores older than this do not count toward the verdict.
The model version this alias currently serves, when it points at a trained version (null for raw catalog models). Repoint to an older version to roll back.
Evidence policy: with this on, a repoint that would send traffic to an unproven model is refused with 412 unless a passing, in-window comparison exists (or an audited override_reason is given).
The eval run that authorized the current routing. Null when the routing predates the policy or went through as an audited override.