> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.runtype.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.runtype.com/_mcp/server.

# Get persisted grader scores for an eval run

GET https://api.runtype.com/v1/eval/runs/{batchId}/scores

Return the persisted per-case grader scores for a run (a `batchExecutions` row) — the read side of eval score persistence. Grader outcomes use the same shape as the synchronous POST /eval/run response, so live and historical results render identically. Runs land here from persisted saved-suite runs (POST /eval/run) and completed suite-linked batch runs. Returns an empty case list for a run with no persisted scores (ephemeral/virtual runs, ad-hoc comparisons, legacy evals).

Reference: https://docs.runtype.com/api-reference/runtype-api/evals/get-persisted-grader-scores-for-an-eval-run

## Authentication

- `Authorization` header (bearer token, required) — API key or Clerk session token

## Servers

- `https://api.runtype.com` (Production, default)
- `https://api.runtype-staging.com` (Staging)

## Request

### Path parameters

- `batchId` (string, required)

## Response

### 200

Per-case grader scores for the run

- `cases` (list of EvalRunScoresResponseCasesItems, required)
- `name` (string, required, nullable) — The eval name recorded on the run.
- `passedCases` (integer, required)
- `platformAbortedCases` (integer, required) — Cases the platform aborted before the target could answer. They run no graders and are counted in neither half of score, so totalCases minus this is the denominator score was taken over.
- `runId` (string, required) — The run (batch execution) id these scores belong to.
- `score` (double, required, nullable) — Suite score, 0..1 (passed cases / graded cases). Platform-aborted cases are excluded from both halves; null when the run graded no cases.
- `strict` (boolean, required) — The severity semantics the run was graded with (and that these verdicts reproduce): true when a soft grader miss failed its case.
- `suiteId` (string, required, nullable) — The eval suite the run executed; null when the suite was since deleted.
- `totalCases` (integer, required)
- `agentTargetAlias` (string, optional, nullable) — The release alias the run resolved through, when it resolved through one.
- `agentTargetResolution` (enum, optional) — How the run picked its version. Null on a run that predates release aliases.
  - Allowed values: `alias`, `version`, `legacy-live-row`
- `agentVersionId` (string, optional, nullable) — The exact Agent version every case of this run executed. Null for a legacy run.
- `caseManifestHash` (string, optional, nullable) — SHA-256 over the ordered, normalized case set this run executed.
- `evaluatorFingerprint` (string, optional, nullable) — SHA-256 over the evaluator configuration this run scored with.

## Errors

### 401 Unauthorized Error

Unauthorized

- `error` (string, required)
- `code` (string, optional) — Stable error code. `insufficient_scope` marks an API key that lacks a scope this request needs.
- `details` (list of ErrorDetailsItems, optional)
- `requiredScopes` (list of string, optional) — On `insufficient_scope`: every API key scope this request needs.

### 403 Forbidden Error

Forbidden

- `error` (string, required)
- `code` (string, optional) — Stable error code. `insufficient_scope` marks an API key that lacks a scope this request needs.
- `details` (list of ErrorDetailsItems, optional)
- `requiredScopes` (list of string, optional) — On `insufficient_scope`: every API key scope this request needs.

### 404 Not Found Error

Run not found in this account scope

- `error` (string, required)
- `code` (string, optional) — Stable error code. `insufficient_scope` marks an API key that lacks a scope this request needs.
- `details` (list of ErrorDetailsItems, optional)
- `requiredScopes` (list of string, optional) — On `insufficient_scope`: every API key scope this request needs.

### 500 Internal Server Error

Internal server error

- `error` (string, required)
- `code` (string, optional) — Stable error code. `insufficient_scope` marks an API key that lacks a scope this request needs.
- `details` (list of ErrorDetailsItems, optional)
- `requiredScopes` (list of string, optional) — On `insufficient_scope`: every API key scope this request needs.

## Types

### EvalRunScoresResponseCasesItems

- `caseId` (string, required, nullable) — The saved eval case id; null when the case row was deleted or the record could not be mapped to a case.
- `error` (string, required, nullable) — Why the case errored (the provider or execution failure text, 2000 chars max); null when the case did not error or the run predates this field.
- `name` (string, required)
- `nextStepToolCalls` (list of EvalRunScoresResponseCasesItemsNextStepToolCallsItems, required, nullable) — For a checkpoint ("saved from run") case run in next-step mode: the tool-call intent(s) the target emitted as its graded next step. An empty array means it replied with a message instead of calling a tool. Null for ordinary runs and for runs recorded before this field shipped.
- `outcomes` (list of EvalRunScoresResponseCasesItemsOutcomesItems, required)
- `outputExcerpt` (string, required) — Truncated snapshot of the output that was graded (2000 chars max).
- `passed` (boolean, required) — Recomputed from the persisted outcomes using the run's recorded strict mode, so historical verdicts match what the run originally reported.
- `executionEngine` (enum, optional) — Engine that actually executed this graded case ('runtime' | 'legacy' | 'external'). Recorded at write time from the committed lane decision; never inferred later. 'external' marks a run a customer executed outside Runtype and reported through ingest. Null for rows written before attribution shipped and for units that never started executing.
  - Allowed values: `runtime`, `legacy`, `external`
- `failureKind` (enum, optional) — Present when the failure belongs to the platform, not the target: the model gateway went silent and the stall watchdog gave up before the target could answer. Such a case runs no graders (its outcomes are empty) and is excluded from the suite score. Absent on an ordinary failure.
  - Allowed values: `platform_stall`

### ErrorDetailsItems

- `message` (string, required)
- `code` (string, optional) — Stable Runtype validation code (e.g. MISSING_REQUIRED_FIELD, INVALID_ENUM).
- `path` (string, optional) — Dotted JSON path to the offending field.
- `suggestion` (string, optional) — Actionable hint (allowed values, accepted range, …).

### EvalRunScoresResponseCasesItemsNextStepToolCallsItems

- `name` (string, required) — Tool the target intended to call.
- `input` (any, optional) — The call input the model emitted (captured, never executed).

### EvalRunScoresResponseCasesItemsOutcomesItems

- `graderIndex` (integer, required)
- `humanVerdict` (enum, required) — Lightweight human review of this verdict; null when unreviewed.
  - Allowed values: `agree`, `disagree`
- `kind` (string, required)
- `passed` (boolean, required)
- `scoreId` (string, required) — The persisted eval_case_scores row id (the review handle).
- `evidence` (list of EvalRunScoresResponseCasesItemsOutcomesItemsEvidenceItems, optional) — AI graders only: transcript entries the verdict rests on — indices into the run's trace steps (message) or tool calls (tool_call).
- `judgeDiagnostics` (EvalRunScoresResponseCasesItemsOutcomesItemsJudgeDiagnostics, optional)
- `reasoning` (string, optional)
- `score` (double, optional)
- `severity` (enum, optional) — Grader severity. A soft miss is reported but only fails the suite under strict mode. Absent ⇒ gate.
  - Allowed values: `gate`, `soft`
- `verdict` (enum, optional) — AI graders only: the judge's binary verdict. insufficient_evidence means the judge declined to guess; it renders as a warning and never fails the case.
  - Allowed values: `pass`, `fail`, `insufficient_evidence`

### EvalRunScoresResponseCasesItemsOutcomesItemsEvidenceItems

- `index` (integer, required)
- `kind` (enum, required)
  - Allowed values: `message`, `tool_call`

### EvalRunScoresResponseCasesItemsOutcomesItemsJudgeDiagnostics

- `attempts` (list of EvalRunScoresResponseCasesItemsOutcomesItemsJudgeDiagnosticsAttemptsItems, required)
- `flowFailure` (enum, optional)
  - Allowed values: `deadline_exhausted`, `execution_failed`, `invalid_response`

### EvalRunScoresResponseCasesItemsOutcomesItemsJudgeDiagnosticsAttemptsItems

- `attempt` (EvalRunScoresResponseCasesItemsOutcomesItemsJudgeDiagnosticsAttemptsItemsAttempt, required)
- `durationMs` (integer, required)
- `requestedModel` (string, required)
- `status` (enum, required)
  - Allowed values: `valid`, `invalid_response`, `model_error`
- `usageObserved` (boolean, required)
- `cacheReadTokens` (integer, optional)
- `cacheWriteTokens` (integer, optional)
- `completionTokens` (integer, optional)
- `finishReason` (enum, optional)
  - Allowed values: `stop`, `length`, `content-filter`, `tool-calls`, `error`, `other`, `unknown`
- `modelError` (enum, optional)
  - Allowed values: `empty_completion`, `model_call_error`
- `parseError` (enum, optional)
  - Allowed values: `empty_completion`, `invalid_json`, `invalid_contract`, `missing_access_assessment`, `invalid_access_assessment`, `output_truncated`
- `promptTokens` (integer, optional)
- `provider` (string, optional)
- `reasoningTokens` (integer, optional)
- `resolvedModel` (string, optional)
- `responseChars` (integer, optional)

### EvalRunScoresResponseCasesItemsOutcomesItemsJudgeDiagnosticsAttemptsItemsAttempt

- enum
  - Allowed values: `1`
- enum
  - Allowed values: `2`

## Examples

**Response**

```json
{
  "cases": [
    {
      "caseId": "string",
      "error": "string",
      "name": "string",
      "nextStepToolCalls": [
        {
          "name": "string",
          "input": null
        }
      ],
      "outcomes": [
        {
          "graderIndex": 1,
          "humanVerdict": "agree",
          "kind": "string",
          "passed": true,
          "scoreId": "string",
          "evidence": [
            {
              "index": 1,
              "kind": "message"
            }
          ],
          "judgeDiagnostics": {
            "attempts": [
              {
                "attempt": 1,
                "durationMs": 1,
                "requestedModel": "string",
                "status": "valid",
                "usageObserved": true,
                "cacheReadTokens": 1,
                "cacheWriteTokens": 1,
                "completionTokens": 1,
                "finishReason": "stop",
                "modelError": "empty_completion",
                "parseError": "empty_completion",
                "promptTokens": 1,
                "provider": "string",
                "reasoningTokens": 1,
                "resolvedModel": "string",
                "responseChars": 1
              }
            ],
            "flowFailure": "deadline_exhausted"
          },
          "reasoning": "string",
          "score": 1.1,
          "severity": "gate",
          "verdict": "pass"
        }
      ],
      "outputExcerpt": "string",
      "passed": true,
      "executionEngine": "runtime",
      "failureKind": "platform_stall"
    }
  ],
  "name": "string",
  "passedCases": 1,
  "platformAbortedCases": 1,
  "runId": "string",
  "score": 1.1,
  "strict": true,
  "suiteId": "string",
  "totalCases": 1,
  "agentTargetAlias": "string",
  "agentTargetResolution": "alias",
  "agentVersionId": "string",
  "caseManifestHash": "string",
  "evaluatorFingerprint": "string"
}
```

**SDK Code**

```python
import requests

url = "https://api.runtype.com/v1/eval/runs/batchId/scores"

headers = {"Authorization": "Bearer <token>"}

response = requests.get(url, headers=headers)

print(response.json())
```

```javascript
const url = 'https://api.runtype.com/v1/eval/runs/batchId/scores';
const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"net/http"
	"io"
)

func main() {

	url := "https://api.runtype.com/v1/eval/runs/batchId/scores"

	req, _ := http.NewRequest("GET", url, nil)

	req.Header.Add("Authorization", "Bearer <token>")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://api.runtype.com/v1/eval/runs/batchId/scores")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.get("https://api.runtype.com/v1/eval/runs/batchId/scores")
  .header("Authorization", "Bearer <token>")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.runtype.com/v1/eval/runs/batchId/scores', [
  'headers' => [
    'Authorization' => 'Bearer <token>',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://api.runtype.com/v1/eval/runs/batchId/scores");
var request = new RestRequest(Method.GET);
request.AddHeader("Authorization", "Bearer <token>");
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = ["Authorization": "Bearer <token>"]

let request = NSMutableURLRequest(url: NSURL(string: "https://api.runtype.com/v1/eval/runs/batchId/scores")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```