Monitors & evaluations
16 endpoints. Every path below is relative to the API base URL and already includes the /api/v1 prefix — see conventions for authentication, pagination, errors and idempotency.
| Endpoint | ||
|---|---|---|
| GET | /eval-runs/{evalRunId} | Fetch one eval run with its score, case counts, reproducibility fields and per-case results |
| GET | /eval-suites | List the organization's eval suites with case counts and last-run status |
| POST | /eval-suites/{evalSuiteId}/run | Run every enabled case in an eval suite and return the finished run with its score and case counts |
| GET | /issues | List monitoring issues, filterable by status, severity or active-only, newest last-seen first |
| POST | /issues/{issueId}/acknowledge | Acknowledge a monitoring issue and return its resulting status |
| POST | /issues/{issueId}/resolve | Resolve a monitoring issue, optionally recording a note, and return its resulting status |
| GET | /monitors | List the organization's monitors with their thresholds, windows and last evaluation state |
| POST | /monitors | Create a monitor that evaluates a metric against a threshold over a rolling window |
| DELETE | /monitors/{monitorId} | Delete a monitor |
| POST | /monitors/{monitorId}/evaluate | Evaluate a monitor immediately and report whether its threshold was breached and which issue it opened |
| GET | /scorecards | List the organization's scorecards with their metric definitions and pass thresholds |
| POST | /scorecards | Create a scorecard together with its metric definitions, generating a key when none is given |
| DELETE | /scorecards/{scorecardId} | Delete a scorecard |
| GET | /simulation-runs/{simulationRunId} | Fetch one simulation run with its score, item counts, transport and every scenario iteration's transcript |
| GET | /simulation-suites | List the organization's simulation suites with scenario counts, mode, transport and last-run status |
| POST | /simulation-suites/{simulationSuiteId}/run | Run every enabled scenario in a simulation suite and return the finished run with its score and item counts |
Endpoints
Fetch one eval run with its score, case counts, reproducibility fields and per-case results
- Requires
eval.read.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
evalRunId | string | yes |
curl -X GET "$CALLAGENT_API_URL/eval-runs/01JQ0000000000000000000000" \
-H "Authorization: Bearer $CALLAGENT_API_KEY" \
-H "Accept: application/json"const response = await fetch(`${process.env.CALLAGENT_API_URL}/eval-runs/01JQ0000000000000000000000`, {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
Accept: 'application/json',
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();<?php
$handle = curl_init(getenv('CALLAGENT_API_URL') . '/eval-runs/01JQ0000000000000000000000');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
'Accept: application/json',
],
]);
$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($status >= 400) {
throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}
$data = $body['data'];import os, requests
response = requests.get(
f"{os.environ['CALLAGENT_API_URL']}/eval-runs/01JQ0000000000000000000000",
headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]Responses
| Status | Body |
|---|---|
200 | data-wrapped object |
Errors
| Status | When it happens |
|---|---|
403 | The API key lacks the eval.read scope |
404 | No eval run with that id in this organization |
Example response, generated from the schema:
{
"data": "string"
}List the organization's eval suites with case counts and last-run status
- Requires
eval.read. - Returns all suites; there is no pagination on this endpoint
curl -X GET "$CALLAGENT_API_URL/eval-suites" \
-H "Authorization: Bearer $CALLAGENT_API_KEY" \
-H "Accept: application/json"const response = await fetch(`${process.env.CALLAGENT_API_URL}/eval-suites`, {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
Accept: 'application/json',
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();<?php
$handle = curl_init(getenv('CALLAGENT_API_URL') . '/eval-suites');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
'Accept: application/json',
],
]);
$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($status >= 400) {
throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}
$data = $body['data'];import os, requests
response = requests.get(
f"{os.environ['CALLAGENT_API_URL']}/eval-suites",
headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]Responses
| Status | Body |
|---|---|
200 | data-wrapped array |
Errors
| Status | When it happens |
|---|---|
403 | The API key lacks the eval.read scope |
Example response, generated from the schema:
{
"data": [
{
"id": "01JQ0000000000000000000000",
"name": "Support Line",
"key": "string",
"assistant_id": "01JQ0000000000000000000000",
"cases": "string",
"enabled": true,
"last_run_status": "string",
"last_run_at": "2026-01-01T12:00:00+00:00"
}
]
}Run every enabled case in an eval suite and return the finished run with its score and case counts
- Requires
eval.write. - Runs synchronously inside the request, so a large suite blocks until every case has finished. Optional
seedbody field
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
evalSuiteId | string | yes |
curl -X POST "$CALLAGENT_API_URL/eval-suites/01JQ0000000000000000000000/run" \
-H "Authorization: Bearer $CALLAGENT_API_KEY" \
-H "Accept: application/json"const response = await fetch(`${process.env.CALLAGENT_API_URL}/eval-suites/01JQ0000000000000000000000/run`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
Accept: 'application/json',
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();<?php
$handle = curl_init(getenv('CALLAGENT_API_URL') . '/eval-suites/01JQ0000000000000000000000/run');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
'Accept: application/json',
],
]);
$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($status >= 400) {
throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}
$data = $body['data'];import os, requests
response = requests.post(
f"{os.environ['CALLAGENT_API_URL']}/eval-suites/01JQ0000000000000000000000/run",
headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]Responses
| Status | Body |
|---|---|
201 | data-wrapped object |
Errors
| Status | When it happens |
|---|---|
403 | The API key lacks the eval.write scope |
404 | No eval suite with that id in this organization |
Example response, generated from the schema:
{
"data": {
"id": "01JQ0000000000000000000000",
"suite_id": "01JQ0000000000000000000000",
"status": "string",
"passed": true,
"score": 1,
"cases": {
"total": 1,
"passed": 1,
"failed": 1,
"errored": 1
},
"assistant_version_id": "01JQ0000000000000000000000",
"config_hash": "string",
"seed": 1,
"duration_ms": 30,
"started_at": "2026-01-01T12:00:00+00:00",
"finished_at": "2026-01-01T12:00:00+00:00"
}
}List monitoring issues, filterable by status, severity or active-only, newest last-seen first
- Requires
analytics.read. - Page size comes from a
limitquery param (default 25, max 100); meta carries onlytotal, no page number
Query parameters
| Name | Type | Required | Notes |
|---|---|---|---|
active | boolean | — | default false |
curl -X GET "$CALLAGENT_API_URL/issues?active=false" \
-H "Authorization: Bearer $CALLAGENT_API_KEY" \
-H "Accept: application/json"const response = await fetch(`${process.env.CALLAGENT_API_URL}/issues?active=false`, {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
Accept: 'application/json',
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();<?php
$handle = curl_init(getenv('CALLAGENT_API_URL') . '/issues?active=false');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
'Accept: application/json',
],
]);
$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($status >= 400) {
throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}
$data = $body['data'];import os, requests
response = requests.get(
f"{os.environ['CALLAGENT_API_URL']}/issues?active=false",
headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]Responses
| Status | Body |
|---|---|
200 | data-wrapped array |
Errors
| Status | When it happens |
|---|---|
403 | The API key lacks the analytics.read scope |
Example response, generated from the schema:
{
"data": [
{
"id": "01JQ0000000000000000000000",
"title": "string",
"description": "string",
"category": "string",
"severity": "string",
"status": "string",
"occurrences": 1,
"last_value": 1,
"threshold": 1,
"context": {},
"recommendation": {},
"recommendation_status": "string",
"first_seen_at": "2026-01-01T12:00:00+00:00",
"last_seen_at": "2026-01-01T12:00:00+00:00"
}
],
"meta": {
"total": 1
}
}Acknowledge a monitoring issue and return its resulting status
- Requires
issue.write. - The response body is only {"data":{"status":"..."}}; re-read the issue if you need the rest of it
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
issueId | string | yes |
curl -X POST "$CALLAGENT_API_URL/issues/01JQ0000000000000000000000/acknowledge" \
-H "Authorization: Bearer $CALLAGENT_API_KEY" \
-H "Accept: application/json"const response = await fetch(`${process.env.CALLAGENT_API_URL}/issues/01JQ0000000000000000000000/acknowledge`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
Accept: 'application/json',
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();<?php
$handle = curl_init(getenv('CALLAGENT_API_URL') . '/issues/01JQ0000000000000000000000/acknowledge');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
'Accept: application/json',
],
]);
$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($status >= 400) {
throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}
$data = $body['data'];import os, requests
response = requests.post(
f"{os.environ['CALLAGENT_API_URL']}/issues/01JQ0000000000000000000000/acknowledge",
headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]Responses
| Status | Body |
|---|---|
200 | data-wrapped object |
Errors
| Status | When it happens |
|---|---|
403 | The API key lacks the issue.write scope |
404 | No issue with that id in this organization |
Example response, generated from the schema:
{
"data": {
"status": "string"
}
}Resolve a monitoring issue, optionally recording a note, and return its resulting status
- Requires
issue.write. - Optional
notebody field is unvalidated. The response body is only {"data":{"status":"..."}}
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
issueId | string | yes |
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
note | string | — |
curl -X POST "$CALLAGENT_API_URL/issues/01JQ0000000000000000000000/resolve" \
-H "Authorization: Bearer $CALLAGENT_API_KEY" \
-H "Accept: application/json"const response = await fetch(`${process.env.CALLAGENT_API_URL}/issues/01JQ0000000000000000000000/resolve`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
Accept: 'application/json',
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();<?php
$handle = curl_init(getenv('CALLAGENT_API_URL') . '/issues/01JQ0000000000000000000000/resolve');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
'Accept: application/json',
],
]);
$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($status >= 400) {
throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}
$data = $body['data'];import os, requests
response = requests.post(
f"{os.environ['CALLAGENT_API_URL']}/issues/01JQ0000000000000000000000/resolve",
headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]Responses
| Status | Body |
|---|---|
200 | data-wrapped object |
Errors
| Status | When it happens |
|---|---|
403 | The API key lacks the issue.write scope |
404 | No issue with that id in this organization |
Example response, generated from the schema:
{
"data": {
"status": "string"
}
}List the organization's monitors with their thresholds, windows and last evaluation state
- Requires
analytics.read. - Reading monitors needs analytics.read while writing them needs monitor.write
curl -X GET "$CALLAGENT_API_URL/monitors" \
-H "Authorization: Bearer $CALLAGENT_API_KEY" \
-H "Accept: application/json"const response = await fetch(`${process.env.CALLAGENT_API_URL}/monitors`, {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
Accept: 'application/json',
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();<?php
$handle = curl_init(getenv('CALLAGENT_API_URL') . '/monitors');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
'Accept: application/json',
],
]);
$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($status >= 400) {
throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}
$data = $body['data'];import os, requests
response = requests.get(
f"{os.environ['CALLAGENT_API_URL']}/monitors",
headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]Responses
| Status | Body |
|---|---|
200 | data-wrapped array |
Errors
| Status | When it happens |
|---|---|
403 | The API key lacks the analytics.read scope |
Example response, generated from the schema:
{
"data": [
{
"id": "01JQ0000000000000000000000",
"name": "Support Line",
"category": "string",
"trigger_type": "string",
"comparator": "string",
"threshold": 1,
"window_minutes": 1,
"min_sample": 1,
"severity": "string",
"enabled": true,
"state": "string",
"last_value": 1,
"last_evaluated_at": "2026-01-01T12:00:00+00:00"
}
]
}Create a monitor that evaluates a metric against a threshold over a rolling window
- Requires
monitor.write. - The response body is only {"data":{"id":"..."}}; GET /monitors to read the stored monitor back
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
name | string | yes | max 255 chars |
description | string | null | — | |
category | technical · infrastructure · effectiveness · compliance | yes | |
trigger_type | string | yes | max 32 chars |
comparator | gt · gte · lt · lte · null | null | — | |
threshold | number | yes | |
window_minutes | integer | null | — | min 1. max 10080 |
min_sample | integer | null | — | min 1 |
evaluation_interval_minutes | integer | null | — | min 1 |
severity | info · warning · critical · null | null | — | |
filters | string[] | null | — | |
notifier_ids | string[] | null | — | |
cooldown_minutes | integer | null | — | min 0 |
auto_resolve_after_minutes | integer | null | — | min 1 |
enabled | boolean | null | — |
curl -X POST "$CALLAGENT_API_URL/monitors" \
-H "Authorization: Bearer $CALLAGENT_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"name": "Support Line",
"category": "technical",
"trigger_type": "string",
"threshold": 1,
"comparator": "gt",
"window_minutes": 1,
"min_sample": 1
}'const response = await fetch(`${process.env.CALLAGENT_API_URL}/monitors`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "Support Line",
"category": "technical",
"trigger_type": "string",
"threshold": 1,
"comparator": "gt",
"window_minutes": 1,
"min_sample": 1
}),
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();<?php
$handle = curl_init(getenv('CALLAGENT_API_URL') . '/monitors');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
'Accept: application/json',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'name' => 'Support Line',
'category' => 'technical',
'trigger_type' => 'string',
'threshold' => 1,
'comparator' => 'gt',
'window_minutes' => 1,
'min_sample' => 1,
]),
]);
$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($status >= 400) {
throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}
$data = $body['data'];import os, requests
response = requests.post(
f"{os.environ['CALLAGENT_API_URL']}/monitors",
headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
json={
"name": "Support Line",
"category": "technical",
"trigger_type": "string",
"threshold": 1,
"comparator": "gt",
"window_minutes": 1,
"min_sample": 1
},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]Responses
| Status | Body |
|---|---|
201 | data-wrapped object |
Errors
| Status | When it happens |
|---|---|
403 | The API key lacks the monitor.write scope |
422 | The payload failed validation (name, category, trigger_type and threshold are required) |
Example response, generated from the schema:
{
"data": {
"id": "01JQ0000000000000000000000"
}
}Delete a monitor
- Requires
monitor.write. - This response is not
data-wrapped.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
monitorId | string | yes |
curl -X DELETE "$CALLAGENT_API_URL/monitors/01JQ0000000000000000000000" \
-H "Authorization: Bearer $CALLAGENT_API_KEY" \
-H "Accept: application/json"const response = await fetch(`${process.env.CALLAGENT_API_URL}/monitors/01JQ0000000000000000000000`, {
method: 'DELETE',
headers: {
Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
Accept: 'application/json',
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();<?php
$handle = curl_init(getenv('CALLAGENT_API_URL') . '/monitors/01JQ0000000000000000000000');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
'Accept: application/json',
],
]);
$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($status >= 400) {
throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}
$data = $body['data'];import os, requests
response = requests.delete(
f"{os.environ['CALLAGENT_API_URL']}/monitors/01JQ0000000000000000000000",
headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]Responses
| Status | Body |
|---|---|
204 | No content |
Errors
| Status | When it happens |
|---|---|
403 | The API key lacks the monitor.write scope |
404 | No monitor with that id in this organization |
Evaluate a monitor immediately and report whether its threshold was breached and which issue it opened
- Requires
monitor.write. - Has side effects: it writes a trigger row, updates monitor state and may open or auto-resolve an issue.
skippedexplains a too-small sample
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
monitorId | string | yes |
curl -X POST "$CALLAGENT_API_URL/monitors/01JQ0000000000000000000000/evaluate" \
-H "Authorization: Bearer $CALLAGENT_API_KEY" \
-H "Accept: application/json"const response = await fetch(`${process.env.CALLAGENT_API_URL}/monitors/01JQ0000000000000000000000/evaluate`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
Accept: 'application/json',
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();<?php
$handle = curl_init(getenv('CALLAGENT_API_URL') . '/monitors/01JQ0000000000000000000000/evaluate');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
'Accept: application/json',
],
]);
$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($status >= 400) {
throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}
$data = $body['data'];import os, requests
response = requests.post(
f"{os.environ['CALLAGENT_API_URL']}/monitors/01JQ0000000000000000000000/evaluate",
headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]Responses
| Status | Body |
|---|---|
200 | data-wrapped object |
Errors
| Status | When it happens |
|---|---|
403 | The API key lacks the monitor.write scope |
404 | No monitor with that id in this organization |
Example response, generated from the schema:
{
"data": {
"breached": true,
"value": "string",
"sample": "string",
"issue_id": "01JQ0000000000000000000000",
"skipped": null
}
}List the organization's scorecards with their metric definitions and pass thresholds
- Requires
analytics.read.
curl -X GET "$CALLAGENT_API_URL/scorecards" \
-H "Authorization: Bearer $CALLAGENT_API_KEY" \
-H "Accept: application/json"const response = await fetch(`${process.env.CALLAGENT_API_URL}/scorecards`, {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
Accept: 'application/json',
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();<?php
$handle = curl_init(getenv('CALLAGENT_API_URL') . '/scorecards');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
'Accept: application/json',
],
]);
$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($status >= 400) {
throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}
$data = $body['data'];import os, requests
response = requests.get(
f"{os.environ['CALLAGENT_API_URL']}/scorecards",
headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]Responses
| Status | Body |
|---|---|
200 | data-wrapped array |
Errors
| Status | When it happens |
|---|---|
403 | The API key lacks the analytics.read scope |
Example response, generated from the schema:
{
"data": [
{
"id": "01JQ0000000000000000000000",
"name": "Support Line",
"key": "string",
"target": "string",
"enabled": true,
"pass_threshold": 1,
"applies_to_all": true,
"assistant_ids": {},
"metrics": []
}
]
}Create a scorecard together with its metric definitions, generating a key when none is given
- Requires
scorecard.write. - The response body is only {"data":{"id":"..."}}; GET /scorecards to read the stored scorecard back
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
name | string | yes | max 255 chars |
key | string | null | — | max 96 chars |
description | string | null | — | |
target | call · chat · both · null | null | — | |
pass_threshold | number | null | — | min 0. max 100 |
applies_to_all | boolean | null | — | |
assistant_ids | string[] | null | — | |
squad_ids | string[] | null | — | |
queue_ids | string[] | null | — | |
operator_ids | string[] | null | — | |
campaign_ids | string[] | null | — | |
structured_output_id | string | null | — | max 26 chars. min 26 chars |
metrics | object[] | null | — |
curl -X POST "$CALLAGENT_API_URL/scorecards" \
-H "Authorization: Bearer $CALLAGENT_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"name": "Support Line",
"target": "call",
"pass_threshold": 1,
"applies_to_all": true,
"structured_output_id": "01JQ0000000000000000000000",
"metrics": [
{
"name": "Support Line",
"key": "string",
"type": "boolean",
"comparator": "string",
"source_path": "string",
"expected_value": "string",
"expected_min": 1,
"expected_max": 1,
"weight": 1,
"points": 1,
"is_critical": true,
"on_missing": "fail"
}
]
}'const response = await fetch(`${process.env.CALLAGENT_API_URL}/scorecards`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "Support Line",
"target": "call",
"pass_threshold": 1,
"applies_to_all": true,
"structured_output_id": "01JQ0000000000000000000000",
"metrics": [
{
"name": "Support Line",
"key": "string",
"type": "boolean",
"comparator": "string",
"source_path": "string",
"expected_value": "string",
"expected_min": 1,
"expected_max": 1,
"weight": 1,
"points": 1,
"is_critical": true,
"on_missing": "fail"
}
]
}),
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();<?php
$handle = curl_init(getenv('CALLAGENT_API_URL') . '/scorecards');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
'Accept: application/json',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'name' => 'Support Line',
'target' => 'call',
'pass_threshold' => 1,
'applies_to_all' => true,
'structured_output_id' => '01JQ0000000000000000000000',
'metrics' => [
[
'name' => 'Support Line',
'key' => 'string',
'type' => 'boolean',
'comparator' => 'string',
'source_path' => 'string',
'expected_value' => 'string',
'expected_min' => 1,
'expected_max' => 1,
'weight' => 1,
'points' => 1,
'is_critical' => true,
'on_missing' => 'fail',
],
],
]),
]);
$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($status >= 400) {
throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}
$data = $body['data'];import os, requests
response = requests.post(
f"{os.environ['CALLAGENT_API_URL']}/scorecards",
headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
json={
"name": "Support Line",
"target": "call",
"pass_threshold": 1,
"applies_to_all": True,
"structured_output_id": "01JQ0000000000000000000000",
"metrics": [
{
"name": "Support Line",
"key": "string",
"type": "boolean",
"comparator": "string",
"source_path": "string",
"expected_value": "string",
"expected_min": 1,
"expected_max": 1,
"weight": 1,
"points": 1,
"is_critical": True,
"on_missing": "fail"
}
]
},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]Responses
| Status | Body |
|---|---|
201 | data-wrapped object |
Errors
| Status | When it happens |
|---|---|
403 | The API key lacks the scorecard.write scope |
422 | Validation failed: name, and each metric's name, type and comparator, are required |
Example response, generated from the schema:
{
"data": {
"id": "01JQ0000000000000000000000"
}
}Delete a scorecard
- Requires
scorecard.write. - This response is not
data-wrapped.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
scorecardId | string | yes |
curl -X DELETE "$CALLAGENT_API_URL/scorecards/01JQ0000000000000000000000" \
-H "Authorization: Bearer $CALLAGENT_API_KEY" \
-H "Accept: application/json"const response = await fetch(`${process.env.CALLAGENT_API_URL}/scorecards/01JQ0000000000000000000000`, {
method: 'DELETE',
headers: {
Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
Accept: 'application/json',
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();<?php
$handle = curl_init(getenv('CALLAGENT_API_URL') . '/scorecards/01JQ0000000000000000000000');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
'Accept: application/json',
],
]);
$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($status >= 400) {
throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}
$data = $body['data'];import os, requests
response = requests.delete(
f"{os.environ['CALLAGENT_API_URL']}/scorecards/01JQ0000000000000000000000",
headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]Responses
| Status | Body |
|---|---|
204 | No content |
Errors
| Status | When it happens |
|---|---|
403 | The API key lacks the scorecard.write scope |
404 | No scorecard with that id in this organization |
Fetch one simulation run with its score, item counts, transport and every scenario iteration's transcript
- Requires
eval.read. transportandtransport_notesay whether the run used a mocked transport or a real call; a green mocked run proves nothing about telephony
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
simulationRunId | string | yes |
curl -X GET "$CALLAGENT_API_URL/simulation-runs/01JQ0000000000000000000000" \
-H "Authorization: Bearer $CALLAGENT_API_KEY" \
-H "Accept: application/json"const response = await fetch(`${process.env.CALLAGENT_API_URL}/simulation-runs/01JQ0000000000000000000000`, {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
Accept: 'application/json',
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();<?php
$handle = curl_init(getenv('CALLAGENT_API_URL') . '/simulation-runs/01JQ0000000000000000000000');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
'Accept: application/json',
],
]);
$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($status >= 400) {
throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}
$data = $body['data'];import os, requests
response = requests.get(
f"{os.environ['CALLAGENT_API_URL']}/simulation-runs/01JQ0000000000000000000000",
headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]Responses
| Status | Body |
|---|---|
200 | data-wrapped object |
Errors
| Status | When it happens |
|---|---|
403 | The API key lacks the eval.read scope |
404 | No simulation run with that id in this organization |
Example response, generated from the schema:
{
"data": "string"
}List the organization's simulation suites with scenario counts, mode, transport and last-run status
- Requires
eval.read. - Reading and running simulations use the eval.read and eval.write scopes, not simulation-specific ones
curl -X GET "$CALLAGENT_API_URL/simulation-suites" \
-H "Authorization: Bearer $CALLAGENT_API_KEY" \
-H "Accept: application/json"const response = await fetch(`${process.env.CALLAGENT_API_URL}/simulation-suites`, {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
Accept: 'application/json',
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();<?php
$handle = curl_init(getenv('CALLAGENT_API_URL') . '/simulation-suites');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
'Accept: application/json',
],
]);
$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($status >= 400) {
throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}
$data = $body['data'];import os, requests
response = requests.get(
f"{os.environ['CALLAGENT_API_URL']}/simulation-suites",
headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]Responses
| Status | Body |
|---|---|
200 | data-wrapped array |
Errors
| Status | When it happens |
|---|---|
403 | The API key lacks the eval.read scope |
Example response, generated from the schema:
{
"data": [
{
"id": "01JQ0000000000000000000000",
"name": "Support Line",
"key": "string",
"mode": "string",
"transport": "string",
"scenarios": "string",
"enabled": true,
"last_run_status": "string",
"last_run_at": "2026-01-01T12:00:00+00:00"
}
]
}Run every enabled scenario in a simulation suite and return the finished run with its score and item counts
- Requires
eval.write. - Runs synchronously inside the request, and the default transport driver is a mock, so no real call is placed unless one is configured
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
simulationSuiteId | string | yes |
curl -X POST "$CALLAGENT_API_URL/simulation-suites/01JQ0000000000000000000000/run" \
-H "Authorization: Bearer $CALLAGENT_API_KEY" \
-H "Accept: application/json"const response = await fetch(`${process.env.CALLAGENT_API_URL}/simulation-suites/01JQ0000000000000000000000/run`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
Accept: 'application/json',
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();<?php
$handle = curl_init(getenv('CALLAGENT_API_URL') . '/simulation-suites/01JQ0000000000000000000000/run');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
'Accept: application/json',
],
]);
$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($status >= 400) {
throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}
$data = $body['data'];import os, requests
response = requests.post(
f"{os.environ['CALLAGENT_API_URL']}/simulation-suites/01JQ0000000000000000000000/run",
headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]Responses
| Status | Body |
|---|---|
201 | data-wrapped object |
Errors
| Status | When it happens |
|---|---|
403 | The API key lacks the eval.write scope |
404 | No simulation suite with that id in this organization |
Example response, generated from the schema:
{
"data": {
"id": "01JQ0000000000000000000000",
"suite_id": "01JQ0000000000000000000000",
"status": "string",
"mode": "string",
"transport": "string",
"transport_note": "The tester talked to the assistant configuration directly. No call was placed and no telephony provider was involved.",
"passed": true,
"score": 1,
"items": {
"total": 1,
"passed": 1,
"failed": 1,
"errored": 1
},
"config_hash": "string",
"duration_ms": 30,
"started_at": "2026-01-01T12:00:00+00:00",
"finished_at": "2026-01-01T12:00:00+00:00"
}
}