curl --request GET \
--url https://api.cekura.ai/test_framework/v2/results/reports/ \
--header 'X-CEKURA-API-KEY: <api-key>'import requests
url = "https://api.cekura.ai/test_framework/v2/results/reports/"
headers = {"X-CEKURA-API-KEY": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-CEKURA-API-KEY': '<api-key>'}};
fetch('https://api.cekura.ai/test_framework/v2/results/reports/', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.cekura.ai/test_framework/v2/results/reports/",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"X-CEKURA-API-KEY: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.cekura.ai/test_framework/v2/results/reports/"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-CEKURA-API-KEY", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.cekura.ai/test_framework/v2/results/reports/")
.header("X-CEKURA-API-KEY", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.cekura.ai/test_framework/v2/results/reports/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-CEKURA-API-KEY"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"status": "<string>",
"success_rate": 123,
"total_runs_count": 123,
"completed_runs_count": 123,
"success_runs_count": 123,
"failed_runs_count": 123,
"agent": 123,
"agent_version": "<unknown>",
"overall_evaluation": "<unknown>",
"metrics": "<unknown>",
"critical_categories": "<unknown>",
"runs_by_tags": "<unknown>",
"latency_data": "<unknown>",
"failed_reasons": "<unknown>",
"performance_metrics": "<unknown>",
"runs": "<unknown>"
}{
"field_name": [
"<string>"
]
}Get Combined Results Report
Aggregate two or more test results into a single report with success rate, metric summary, critical categories, latency and failure reasons
curl --request GET \
--url https://api.cekura.ai/test_framework/v2/results/reports/ \
--header 'X-CEKURA-API-KEY: <api-key>'import requests
url = "https://api.cekura.ai/test_framework/v2/results/reports/"
headers = {"X-CEKURA-API-KEY": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-CEKURA-API-KEY': '<api-key>'}};
fetch('https://api.cekura.ai/test_framework/v2/results/reports/', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.cekura.ai/test_framework/v2/results/reports/",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"X-CEKURA-API-KEY: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.cekura.ai/test_framework/v2/results/reports/"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-CEKURA-API-KEY", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.cekura.ai/test_framework/v2/results/reports/")
.header("X-CEKURA-API-KEY", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.cekura.ai/test_framework/v2/results/reports/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-CEKURA-API-KEY"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"status": "<string>",
"success_rate": 123,
"total_runs_count": 123,
"completed_runs_count": 123,
"success_runs_count": 123,
"failed_runs_count": 123,
"agent": 123,
"agent_version": "<unknown>",
"overall_evaluation": "<unknown>",
"metrics": "<unknown>",
"critical_categories": "<unknown>",
"runs_by_tags": "<unknown>",
"latency_data": "<unknown>",
"failed_reasons": "<unknown>",
"performance_metrics": "<unknown>",
"runs": "<unknown>"
}{
"field_name": [
"<string>"
]
}Authorizations
API Key Authentication. It should be included in the header of each request.
Query Parameters
Results to combine — comma-separated string (e.g. '5591,5592'), not a JSON array.
Optional JSON-encoded filter object restricting which runs the report counts. Every aggregate in the response is computed over the matching runs only. Invalid JSON returns 400.
join is and (every filter must match) or or (any filter may match). Each item in filters has an id (the run field), an operator and a value.
Supported filters:
success—equalswithtrueorfalsestatus—equalswith one run status, e.g."completed"id—equalsorinwith run IDsscenarios—inwith scenario IDstags—inwith scenario tags; a run matches if its scenario carries any of themscenario_name,call_ended_reason—inwith a list of valuesmetrics— no top-leveloperator;valueis a list of metric conditions, each with the metricidand anoperator:equals(withvalue),greaterThanOrEqual/lessThanOrEqual(withvalue),range(withminandmax), orexists/notExists
Example — failed runs from two scenarios whose metric 101 scored at least 3:
{
"join": "and",
"filters": [
{"id": "success", "operator": "equals", "value": false},
{"id": "scenarios", "operator": "in", "value": [3120, 3121]},
{"id": "metrics", "value": [{"id": 101, "operator": "greaterThanOrEqual", "value": 3}]}
]
}
Field selection. {-runs} (the default) returns the aggregates only; {*} additionally embeds every run and can be very large.
Tenant scope. Supply one of agent_id, assistant_id, project_id when authenticating with a user session or OAuth bearer token; omit when using an API key already scoped to the tenant.
Tenant scope. Supply one of agent_id, assistant_id, project_id when authenticating with a user session or OAuth bearer token; omit when using an API key already scoped to the tenant.
Tenant scope. Supply one of agent_id, assistant_id, project_id when authenticating with a user session or OAuth bearer token; omit when using an API key already scoped to the tenant.
Response
Always 'completed' — the report is computed on read, not queued.
Percentage of runs that passed, across every result in the report
Runs in the report, including those still executing
Runs that reached a terminal state (completed, failed, timeout or cancelled)
Completed runs that passed
Completed runs that failed
ID of the agent the results belong to
Agent version every result ran against, or null when the results did not all run against the same version.
Example:
{
"history_id": 812,
"version_id": "v3",
"version_name": "Pricing prompt fix",
"is_current": true
}
Aggregate evaluation across all runs in the report.
success_rate— percentage of runs that passedmetric_summary— keyed by metric ID. Every entry hasid,name,type,score,errors(the scenarios whose runs failed the metric, with the failing run IDs) andoverall_explanation. Enum metrics addenums(per enum value:scoreas a percentage,countandruns), numeric metrics add percentiles such asp50, and critical metrics addcategorieskeyed by category IDworst_performing_metrics—binary_adherencelists the IDs of binary metrics that did not pass on every run, lowest pass rate firstnumeric_metrics— numeric metric averages with their percentiles, plus average ringing duration when availableenum_metrics— the metric ID of every enum evaluation, one entry per evaluated runextra_metrics— derived figures such as average ringing duration and expected-outcome score
Example:
{
"success_rate": 66.67,
"metric_summary": {
"101": {
"id": 101,
"name": "Politeness",
"type": "binary",
"vocera_defined_metric_code": "",
"score": 0.67,
"overall_explanation": [],
"errors": [
{
"id": 3120,
"name": "Asks for pricing",
"agent": 42,
"personality": 7,
"personality_name": "Busy professional",
"retell_agent_id": "",
"instructions": "",
"is_simulating": false,
"runs": [90012]
}
]
},
"102": {
"id": 102,
"name": "Sentiment",
"type": "enum",
"vocera_defined_metric_code": "",
"score": null,
"overall_explanation": [],
"errors": [],
"enums": {
"positive": {"score": 100.0, "count": 3, "runs": [{"id": 90011}, {"id": 90012}, {"id": 90013}]}
}
},
"103": {
"id": 103,
"name": "Latency",
"type": "numeric",
"vocera_defined_metric_code": "",
"score": 850.0,
"p50": 800.0,
"overall_explanation": [],
"errors": []
},
"104": {
"id": 104,
"name": "Critical Deviations",
"type": "binary",
"vocera_defined_metric_code": "",
"score": 0.67,
"overall_explanation": [],
"errors": [],
"categories": {
"55": {
"id": 55,
"category": "Wrong price quoted",
"runs": [{"id": 90012}],
"runs_count": 1,
"priority_counts": {"critical": 1, "non-critical": 0, "not_a_bug": 0},
"scenarios": {}
}
}
}
},
"worst_performing_metrics": {"binary_adherence": [101, 104]},
"numeric_metrics": [
{"name": "Latency", "type": "numeric", "value": 850.0, "percentiles": {"p50": 800.0}},
{"name": "Average Ringing Duration", "type": "numeric", "value": 2.5, "percentiles": {"p50": 2.5}}
],
"enum_metrics": [102, 102, 102],
"extra_metrics": [
{"name": "Average Ringing Duration", "type": "numeric", "value": 2.5, "percentiles": {"p50": 2.5}},
{"name": "Expected Outcome", "type": "numeric", "value": 3.33}
]
}
Metrics configured on the agent.
Example:
[
{
"id": 101,
"name": "Politeness",
"eval_type": "binary",
"simulation_enabled": true,
"observability_enabled": true,
"function_name": null,
"vocera_defined_metric_code": ""
}
]
Critical-issue categories found across the runs, most critical first. Categories marked as not a bug and evaluations marked as wrong are excluded.
Example:
[
{
"id": 55,
"category": "Wrong price quoted",
"scenarios": {},
"runs_count": 1,
"runs": [{"id": 90012}],
"priority_counts": {"critical": 1, "non-critical": 0, "not_a_bug": 0}
}
]
Keyed by scenario tag: the IDs of the runs whose scenario carries the tag and the success rate (percentage) of those runs.
Example:
{
"billing": {"runs": [90013, 90012, 90011], "success_rate": 66.67}
}
Response latency in milliseconds across all measured turns of all runs.
Example:
{"mean": 800.0, "median": 800.0, "p50": 800.0, "p95": 890.0, "p99": 898.0}
Failure issues merged and deduplicated across the results, ranked by how many runs they affect.
Example:
{
"issues": [
{
"rank": 1,
"title": "Missed pricing",
"description": "The agent never shared pricing when asked.",
"run_ids": [90012],
"affected_count": 1
}
],
"total_failed_runs": 1
}
Per-metric performance across the runs, rubric metrics first. aggregate_unit is percent, value, score or an empty string. passed and threshold_text come from the project rubric; passed is null and in_rubric is false for metrics without a rubric rule. Enum metrics add enum_run_ids (run IDs per enum value), rating metrics add score_range_run_ids and expected-outcome metrics add review_required_run_ids.
Example:
[
{
"metric_id": 101,
"metric_name": "Politeness",
"eval_type": "binary",
"aggregate_value": 66.7,
"aggregate_unit": "percent",
"passed": false,
"threshold_text": ">= 80%",
"evaluated_runs_count": 3,
"evaluated_run_ids": [90013, 90012, 90011],
"failing_run_ids": [90012],
"passing_run_ids": [90013, 90011],
"in_rubric": true
},
{
"metric_id": 105,
"metric_name": "Clarity",
"eval_type": "continuous_qualitative",
"aggregate_value": 4.0,
"aggregate_unit": "score",
"passed": null,
"threshold_text": "",
"evaluated_runs_count": 3,
"evaluated_run_ids": [90013, 90012, 90011],
"failing_run_ids": [],
"passing_run_ids": [],
"in_rubric": false,
"score_range_run_ids": {"0-50": [], "50-75": [], ">75": [90013, 90012, 90011]}
}
]
Every run in the report, keyed by run ID. Present only when ql selects it (e.g. {*}); the default {-runs} omits it.
Example:
{
"90012": {
"id": 90012,
"result_id": 5591,
"result_name": "Nightly regression",
"scenario": 3120,
"scenario_name": "Asks for pricing",
"personality_name": "Busy professional",
"test_profile_name": null,
"expected_outcome": {"score": 0},
"success": false,
"status": "completed",
"evaluation_status": "failure",
"evaluation": {
"metrics": [
{
"id": 101,
"name": "Politeness",
"type": "binary",
"score": false,
"score_normalized": 0,
"explanation": ["The agent interrupted the caller twice."],
"extra": {},
"vocera_defined_metric_code": "",
"function_name": null,
"thumbs_up": null
},
{
"id": 102,
"name": "Sentiment",
"type": "enum",
"enum": "positive",
"explanation": [],
"extra": {},
"vocera_defined_metric_code": "",
"function_name": null,
"thumbs_up": null
}
]
},
"timestamp": "2026-09-24T08:43:10.473761Z",
"executed_at": "2026-09-24T08:43:12.000000Z",
"duration": "01:00",
"error_message": "",
"metadata": {"ringing_duration": 2.5},
"inbound_number": "",
"outbound_dial_window_opens_at": null,
"outbound_dial_window_seconds": null,
"outbound_dial_window_closes_at": null
}
}