Skip to main content
Benchmarks is in preview and rolling out to organizations gradually. The endpoints and tools on this page are available once Benchmarks is enabled for your organization; until then they answer 403 not_entitled.
Everything the Add cases menu does in the dashboard, you can do over the REST API or MCP: write cases by hand, turn production conversations or traces into cases in bulk, and attach tool-call expectations and judge overrides. Both surfaces use the same service as the dashboard, so a case created over the API is identical to one created in the UI.

What a case is

A case is one input plus its expected outcome. Every case has a caseType: A turn case does not own a prompt. It points at an agent version (prompt.agentVersionId), so the same case can be replayed against several prompt revisions and models.

Authentication

Use an organization API key as a bearer token. The same key works for REST and MCP. Creating and editing cases is a write: the key must belong to an organization owner or admin, otherwise the request is refused with 403.
Cases can only reference agents assigned to the benchmark. To add a case for another agent, assign that agent to the benchmark first.

Create cases

POST /v1/benchmarks/{id}/cases creates up to 100 cases per request and returns them in data.
cases.json
Response (201)
Send an Idempotency-Key header on batch creation so a retried request returns the cases it created the first time instead of creating duplicates.

Case fields

A turn case must check at least one thing: a reply expectation other than none, or a tool expectation.

Tool-call expectations

toolExpectation checks whether the step called the right tool and whether the call has the right form. Pick one of three shapes: This case expects a payment plan to be created with three installments, in the customer’s currency, and never a refund:
Only the arguments you list are checked; set noExtraArguments: true to fail calls that send any other argument. When a step both speaks and calls tools, replyAt (with ordered: true) pins where the reply sits among the calls: 0 means before every call. Every listed tool must exist in the case’s prompt.

Argument matchers

Separately from matchers, the arguments of every call must validate against the tool’s JSON schema: "amount": "240" fails a { "type": "number" } argument.

Skip or tune a judge for one case

Judges are defined on the benchmark. Get their ids from GET /v1/benchmarks/{id} (validators[]); the API calls judges “validators”.
  • skippedJudgeIds opts this case out of judges that don’t make sense for it, such as a tone rubric on a tool-only step. Required judges can’t be skipped, and at least one judge must still run.
  • judgeParamOverrides changes a judge’s parameters for this case only. A judge labelled “Reply under words” with a default of 60 can be tightened to 10 for one case:
Every judge id and parameter key must exist on the benchmark, and values must match the parameter’s type and stay within its min / max. An override for a judge you also skip is dropped.

Conversation cases

Audio cases (STT)

For an STT benchmark, each case is { audio, referenceTranscript, keyTerms?, tags? }. Audio never goes through the request body except for short clips:
  1. Stage the file with POST /v1/recording-uploads, then PUT the bytes to the returned uploadUrl.
  2. Create the case with "audio": { "uploadId": "<id>" }.
You can also pass "audio": { "url": "https://..." } (fetched by Zelto; the case is preparing until the download finishes) or, for clips up to 3 MB, "audio": { "base64": "...", "contentType": "audio/wav" }.

Add cases from production calls

POST /v1/benchmarks/{id}/cases/from-conversations turns up to 100 conversations into cases in one request, using the same mapping as From production calls in the dashboard. Each case records the call’s agent version, the variable values captured from the call, the active node (for node-based agents), and the transcript before the evaluated turn.
Captured variables are masked in the response. Cases whose node couldn’t be resolved come back as draft. Use PATCH /v1/benchmarks/{id}/cases/{caseId} to refine any case afterwards: change its expected outcome, add a tool expectation, override a captured variable with variableOverrides, or set "status": "ready" to accept a draft.

Add cases from traces

POST /v1/benchmarks/{id}/cases/from-traces creates up to 100 cases from traces, the same as Add to benchmark on a trace or span.
  • With a spanId (an LLM or tool span), the case tests that one LLM call: the span’s own input messages become the history, and its output becomes the expected step.
  • Without a spanId, the trace’s linked conversation is used, like from-conversations with turn: "last_assistant".
Each created case reports turnSource: span_messages when the history came from the span, or transcript when it came from the linked call. A trace with no linked call needs a span that recorded its messages, otherwise that item fails with 422 no_turn_source.

Via MCP

The Zelto MCP server exposes the same operations as tools, so you can ask Claude, Cursor, or any MCP client to build a benchmark for you: An example prompt:
The client calls list_benchmarks, list_conversations, add_benchmark_cases_from_conversations, then update_benchmark_case for the tool expectations.

Where new cases land

New and edited cases go to the benchmark’s draft, the working copy shown as “Draft changes” in the dashboard. Runs use the latest published version by default, so new cases are part of a run only after you publish:
Publishing excludes cases still in draft status and warns you about them. Owners and admins can also run the draft directly; that run is labelled “draft run”. Cases are never deleted: editing one creates a new revision, and retiring one removes it from the next version while older runs keep their results.

Errors

Errors are JSON: { "error": "<code>", "details": ... }. Over MCP the same refusals come back as tool results with isError: true; see Error results.
  • Benchmarks: cases, judges, and versions.
  • Agent versions: what prompt.agentVersionId points at.
  • MCP: connect a client and authenticate.