Skip to content

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-suitesList the organization's eval suites with case counts and last-run status
POST/eval-suites/{evalSuiteId}/runRun every enabled case in an eval suite and return the finished run with its score and case counts
GET/issuesList monitoring issues, filterable by status, severity or active-only, newest last-seen first
POST/issues/{issueId}/acknowledgeAcknowledge a monitoring issue and return its resulting status
POST/issues/{issueId}/resolveResolve a monitoring issue, optionally recording a note, and return its resulting status
GET/monitorsList the organization's monitors with their thresholds, windows and last evaluation state
POST/monitorsCreate a monitor that evaluates a metric against a threshold over a rolling window
DELETE/monitors/{monitorId}Delete a monitor
POST/monitors/{monitorId}/evaluateEvaluate a monitor immediately and report whether its threshold was breached and which issue it opened
GET/scorecardsList the organization's scorecards with their metric definitions and pass thresholds
POST/scorecardsCreate 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-suitesList the organization's simulation suites with scenario counts, mode, transport and last-run status
POST/simulation-suites/{simulationSuiteId}/runRun 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 ​

GET/eval-runs/{evalRunId}
  • Requires eval.read.

Path parameters

NameTypeRequiredNotes
evalRunIdstringyes
bash
curl -X GET "$CALLAGENT_API_URL/eval-runs/01JQ0000000000000000000000" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
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
<?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'];
python
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

StatusBody
200data-wrapped object

Errors

StatusWhen it happens
403The API key lacks the eval.read scope
404No eval run with that id in this organization

Example response, generated from the schema:

json
{
  "data": "string"
}

List the organization's eval suites with case counts and last-run status ​

GET/eval-suites
  • Requires eval.read.
  • Returns all suites; there is no pagination on this endpoint
bash
curl -X GET "$CALLAGENT_API_URL/eval-suites" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
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
<?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'];
python
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

StatusBody
200data-wrapped array

Errors

StatusWhen it happens
403The API key lacks the eval.read scope

Example response, generated from the schema:

json
{
  "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 ​

POST/eval-suites/{evalSuiteId}/run
  • Requires eval.write.
  • Runs synchronously inside the request, so a large suite blocks until every case has finished. Optional seed body field

Path parameters

NameTypeRequiredNotes
evalSuiteIdstringyes
bash
curl -X POST "$CALLAGENT_API_URL/eval-suites/01JQ0000000000000000000000/run" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
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
<?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'];
python
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

StatusBody
201data-wrapped object

Errors

StatusWhen it happens
403The API key lacks the eval.write scope
404No eval suite with that id in this organization

Example response, generated from the schema:

json
{
  "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 ​

GET/issues
  • Requires analytics.read.
  • Page size comes from a limit query param (default 25, max 100); meta carries only total, no page number

Query parameters

NameTypeRequiredNotes
activeboolean—default false
bash
curl -X GET "$CALLAGENT_API_URL/issues?active=false" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
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
<?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'];
python
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

StatusBody
200data-wrapped array

Errors

StatusWhen it happens
403The API key lacks the analytics.read scope

Example response, generated from the schema:

json
{
  "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 ​

POST/issues/{issueId}/acknowledge
  • Requires issue.write.
  • The response body is only {"data":{"status":"..."}}; re-read the issue if you need the rest of it

Path parameters

NameTypeRequiredNotes
issueIdstringyes
bash
curl -X POST "$CALLAGENT_API_URL/issues/01JQ0000000000000000000000/acknowledge" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
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
<?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'];
python
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

StatusBody
200data-wrapped object

Errors

StatusWhen it happens
403The API key lacks the issue.write scope
404No issue with that id in this organization

Example response, generated from the schema:

json
{
  "data": {
    "status": "string"
  }
}

Resolve a monitoring issue, optionally recording a note, and return its resulting status ​

POST/issues/{issueId}/resolve
  • Requires issue.write.
  • Optional note body field is unvalidated. The response body is only {"data":{"status":"..."}}

Path parameters

NameTypeRequiredNotes
issueIdstringyes

Request body

FieldTypeRequiredNotes
notestring—
bash
curl -X POST "$CALLAGENT_API_URL/issues/01JQ0000000000000000000000/resolve" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
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
<?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'];
python
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

StatusBody
200data-wrapped object

Errors

StatusWhen it happens
403The API key lacks the issue.write scope
404No issue with that id in this organization

Example response, generated from the schema:

json
{
  "data": {
    "status": "string"
  }
}

List the organization's monitors with their thresholds, windows and last evaluation state ​

GET/monitors
  • Requires analytics.read.
  • Reading monitors needs analytics.read while writing them needs monitor.write
bash
curl -X GET "$CALLAGENT_API_URL/monitors" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
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
<?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'];
python
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

StatusBody
200data-wrapped array

Errors

StatusWhen it happens
403The API key lacks the analytics.read scope

Example response, generated from the schema:

json
{
  "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 ​

POST/monitors
  • Requires monitor.write.
  • The response body is only {"data":{"id":"..."}}; GET /monitors to read the stored monitor back

Request body

FieldTypeRequiredNotes
namestringyesmax 255 chars
descriptionstring | null—
categorytechnical · infrastructure · effectiveness · complianceyes
trigger_typestringyesmax 32 chars
comparatorgt · gte · lt · lte · null | null—
thresholdnumberyes
window_minutesinteger | null—min 1. max 10080
min_sampleinteger | null—min 1
evaluation_interval_minutesinteger | null—min 1
severityinfo · warning · critical · null | null—
filtersstring[] | null—
notifier_idsstring[] | null—
cooldown_minutesinteger | null—min 0
auto_resolve_after_minutesinteger | null—min 1
enabledboolean | null—
bash
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
     }'
js
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
<?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'];
python
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

StatusBody
201data-wrapped object

Errors

StatusWhen it happens
403The API key lacks the monitor.write scope
422The payload failed validation (name, category, trigger_type and threshold are required)

Example response, generated from the schema:

json
{
  "data": {
    "id": "01JQ0000000000000000000000"
  }
}

Delete a monitor ​

DELETE/monitors/{monitorId}
  • Requires monitor.write.
  • This response is not data-wrapped.

Path parameters

NameTypeRequiredNotes
monitorIdstringyes
bash
curl -X DELETE "$CALLAGENT_API_URL/monitors/01JQ0000000000000000000000" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
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
<?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'];
python
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

StatusBody
204No content

Errors

StatusWhen it happens
403The API key lacks the monitor.write scope
404No monitor with that id in this organization

Evaluate a monitor immediately and report whether its threshold was breached and which issue it opened ​

POST/monitors/{monitorId}/evaluate
  • Requires monitor.write.
  • Has side effects: it writes a trigger row, updates monitor state and may open or auto-resolve an issue. skipped explains a too-small sample

Path parameters

NameTypeRequiredNotes
monitorIdstringyes
bash
curl -X POST "$CALLAGENT_API_URL/monitors/01JQ0000000000000000000000/evaluate" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
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
<?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'];
python
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

StatusBody
200data-wrapped object

Errors

StatusWhen it happens
403The API key lacks the monitor.write scope
404No monitor with that id in this organization

Example response, generated from the schema:

json
{
  "data": {
    "breached": true,
    "value": "string",
    "sample": "string",
    "issue_id": "01JQ0000000000000000000000",
    "skipped": null
  }
}

List the organization's scorecards with their metric definitions and pass thresholds ​

GET/scorecards
  • Requires analytics.read.
bash
curl -X GET "$CALLAGENT_API_URL/scorecards" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
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
<?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'];
python
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

StatusBody
200data-wrapped array

Errors

StatusWhen it happens
403The API key lacks the analytics.read scope

Example response, generated from the schema:

json
{
  "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 ​

POST/scorecards
  • Requires scorecard.write.
  • The response body is only {"data":{"id":"..."}}; GET /scorecards to read the stored scorecard back

Request body

FieldTypeRequiredNotes
namestringyesmax 255 chars
keystring | null—max 96 chars
descriptionstring | null—
targetcall · chat · both · null | null—
pass_thresholdnumber | null—min 0. max 100
applies_to_allboolean | null—
assistant_idsstring[] | null—
squad_idsstring[] | null—
queue_idsstring[] | null—
operator_idsstring[] | null—
campaign_idsstring[] | null—
structured_output_idstring | null—max 26 chars. min 26 chars
metricsobject[] | null—
bash
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"
         }
       ]
     }'
js
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
<?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'];
python
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

StatusBody
201data-wrapped object

Errors

StatusWhen it happens
403The API key lacks the scorecard.write scope
422Validation failed: name, and each metric's name, type and comparator, are required

Example response, generated from the schema:

json
{
  "data": {
    "id": "01JQ0000000000000000000000"
  }
}

Delete a scorecard ​

DELETE/scorecards/{scorecardId}
  • Requires scorecard.write.
  • This response is not data-wrapped.

Path parameters

NameTypeRequiredNotes
scorecardIdstringyes
bash
curl -X DELETE "$CALLAGENT_API_URL/scorecards/01JQ0000000000000000000000" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
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
<?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'];
python
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

StatusBody
204No content

Errors

StatusWhen it happens
403The API key lacks the scorecard.write scope
404No scorecard with that id in this organization

Fetch one simulation run with its score, item counts, transport and every scenario iteration's transcript ​

GET/simulation-runs/{simulationRunId}
  • Requires eval.read.
  • transport and transport_note say whether the run used a mocked transport or a real call; a green mocked run proves nothing about telephony

Path parameters

NameTypeRequiredNotes
simulationRunIdstringyes
bash
curl -X GET "$CALLAGENT_API_URL/simulation-runs/01JQ0000000000000000000000" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
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
<?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'];
python
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

StatusBody
200data-wrapped object

Errors

StatusWhen it happens
403The API key lacks the eval.read scope
404No simulation run with that id in this organization

Example response, generated from the schema:

json
{
  "data": "string"
}

List the organization's simulation suites with scenario counts, mode, transport and last-run status ​

GET/simulation-suites
  • Requires eval.read.
  • Reading and running simulations use the eval.read and eval.write scopes, not simulation-specific ones
bash
curl -X GET "$CALLAGENT_API_URL/simulation-suites" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
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
<?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'];
python
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

StatusBody
200data-wrapped array

Errors

StatusWhen it happens
403The API key lacks the eval.read scope

Example response, generated from the schema:

json
{
  "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 ​

POST/simulation-suites/{simulationSuiteId}/run
  • 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

NameTypeRequiredNotes
simulationSuiteIdstringyes
bash
curl -X POST "$CALLAGENT_API_URL/simulation-suites/01JQ0000000000000000000000/run" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
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
<?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'];
python
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

StatusBody
201data-wrapped object

Errors

StatusWhen it happens
403The API key lacks the eval.write scope
404No simulation suite with that id in this organization

Example response, generated from the schema:

json
{
  "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"
  }
}

Documented against the code. Anything not yet implemented is labelled, never described as working.