curl -X POST "https://api.signalmd.dev/v1/agents/6f1d2c3b-4a5e-4f60-8b7a-9c0d1e2f3a4b/runs/d1e2f3a4-b5c6-4d7e-8f9a-0b1c2d3e4f5a/rescore" \
-H "Authorization: Bearer $SIGNAL_API_KEY"import requests
url = "https://api.signalmd.dev/v1/agents/{agentId}/runs/{runId}/rescore"
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, headers=headers)
print(response.text)const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.signalmd.dev/v1/agents/{agentId}/runs/{runId}/rescore', 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.signalmd.dev/v1/agents/{agentId}/runs/{runId}/rescore",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$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.signalmd.dev/v1/agents/{agentId}/runs/{runId}/rescore"
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.signalmd.dev/v1/agents/{agentId}/runs/{runId}/rescore")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.signalmd.dev/v1/agents/{agentId}/runs/{runId}/rescore")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"object": "run",
"id": "d1e2f3a4-b5c6-4d7e-8f9a-0b1c2d3e4f5a",
"status": "complete",
"message": null,
"kind": "run",
"trigger": "ci",
"version": 8,
"testSetId": "c7d8e9f0-a1b2-4c3d-8e4f-5a6b7c8d9e0f",
"testIds": [
"3f1c2d4e-5a6b-4c7d-8e9f-0a1b2c3d4e5f"
],
"personas": null,
"repeats": null,
"shadowAgentId": null,
"phoneCalls": false,
"progress": {
"completed": 12,
"total": 12
},
"cells": {
"requested": 12,
"runnable": 12
},
"summary": {
"cells": 12,
"scored": 12,
"counts": {
"passed": 9,
"failed": 2,
"flaky": 1,
"error": 0,
"drift": 0,
"notRun": 0
},
"passRate": 0.75
},
"cost": {
"retellUsd": 1.84,
"signalUsd": 0.21
},
"goalId": null,
"draftId": null,
"draftScope": null,
"spend": {
"retellUsd": 1.84,
"signalUsd": 0.21,
"totalUsd": 2.05,
"goalId": null
},
"phoneMinutes": null,
"approvedAt": null,
"createdBy": "key:00000000-0000-4000-8000-00000000000a",
"createdAt": "2026-10-02T11:00:03.000Z",
"updatedAt": "2026-10-02T11:07:41.000Z"
}{
"error": {
"type": "not_found_error",
"code": "agent_not_found",
"message": "Agent not found.",
"param": null,
"requestId": "req_8c1f0e2b4a6d9e3f7a5c1b0d"
}
}{
"error": {
"type": "not_found_error",
"code": "agent_not_found",
"message": "Agent not found.",
"param": null,
"requestId": "req_8c1f0e2b4a6d9e3f7a5c1b0d"
}
}{
"error": {
"type": "not_found_error",
"code": "agent_not_found",
"message": "Agent not found.",
"param": null,
"requestId": "req_8c1f0e2b4a6d9e3f7a5c1b0d"
}
}{
"error": {
"type": "not_found_error",
"code": "agent_not_found",
"message": "Agent not found.",
"param": null,
"requestId": "req_8c1f0e2b4a6d9e3f7a5c1b0d"
}
}{
"error": {
"type": "not_found_error",
"code": "agent_not_found",
"message": "Agent not found.",
"param": null,
"requestId": "req_8c1f0e2b4a6d9e3f7a5c1b0d"
}
}{
"error": {
"type": "not_found_error",
"code": "agent_not_found",
"message": "Agent not found.",
"param": null,
"requestId": "req_8c1f0e2b4a6d9e3f7a5c1b0d"
}
}{
"error": {
"type": "not_found_error",
"code": "agent_not_found",
"message": "Agent not found.",
"param": null,
"requestId": "req_8c1f0e2b4a6d9e3f7a5c1b0d"
}
}{
"error": {
"type": "not_found_error",
"code": "agent_not_found",
"message": "Agent not found.",
"param": null,
"requestId": "req_8c1f0e2b4a6d9e3f7a5c1b0d"
}
}Rescore a run
Scores every stored attempt of a finished run again from its transcript with SignalMD’s current scoring. No new calls are placed. A key may rescore only what the current scoring epoch would score differently, one rescore at a time, inside its monthly budget (402 when it does not cover it, 409 otherwise). Not idempotent.
curl -X POST "https://api.signalmd.dev/v1/agents/6f1d2c3b-4a5e-4f60-8b7a-9c0d1e2f3a4b/runs/d1e2f3a4-b5c6-4d7e-8f9a-0b1c2d3e4f5a/rescore" \
-H "Authorization: Bearer $SIGNAL_API_KEY"import requests
url = "https://api.signalmd.dev/v1/agents/{agentId}/runs/{runId}/rescore"
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, headers=headers)
print(response.text)const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.signalmd.dev/v1/agents/{agentId}/runs/{runId}/rescore', 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.signalmd.dev/v1/agents/{agentId}/runs/{runId}/rescore",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$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.signalmd.dev/v1/agents/{agentId}/runs/{runId}/rescore"
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.signalmd.dev/v1/agents/{agentId}/runs/{runId}/rescore")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.signalmd.dev/v1/agents/{agentId}/runs/{runId}/rescore")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"object": "run",
"id": "d1e2f3a4-b5c6-4d7e-8f9a-0b1c2d3e4f5a",
"status": "complete",
"message": null,
"kind": "run",
"trigger": "ci",
"version": 8,
"testSetId": "c7d8e9f0-a1b2-4c3d-8e4f-5a6b7c8d9e0f",
"testIds": [
"3f1c2d4e-5a6b-4c7d-8e9f-0a1b2c3d4e5f"
],
"personas": null,
"repeats": null,
"shadowAgentId": null,
"phoneCalls": false,
"progress": {
"completed": 12,
"total": 12
},
"cells": {
"requested": 12,
"runnable": 12
},
"summary": {
"cells": 12,
"scored": 12,
"counts": {
"passed": 9,
"failed": 2,
"flaky": 1,
"error": 0,
"drift": 0,
"notRun": 0
},
"passRate": 0.75
},
"cost": {
"retellUsd": 1.84,
"signalUsd": 0.21
},
"goalId": null,
"draftId": null,
"draftScope": null,
"spend": {
"retellUsd": 1.84,
"signalUsd": 0.21,
"totalUsd": 2.05,
"goalId": null
},
"phoneMinutes": null,
"approvedAt": null,
"createdBy": "key:00000000-0000-4000-8000-00000000000a",
"createdAt": "2026-10-02T11:00:03.000Z",
"updatedAt": "2026-10-02T11:07:41.000Z"
}{
"error": {
"type": "not_found_error",
"code": "agent_not_found",
"message": "Agent not found.",
"param": null,
"requestId": "req_8c1f0e2b4a6d9e3f7a5c1b0d"
}
}{
"error": {
"type": "not_found_error",
"code": "agent_not_found",
"message": "Agent not found.",
"param": null,
"requestId": "req_8c1f0e2b4a6d9e3f7a5c1b0d"
}
}{
"error": {
"type": "not_found_error",
"code": "agent_not_found",
"message": "Agent not found.",
"param": null,
"requestId": "req_8c1f0e2b4a6d9e3f7a5c1b0d"
}
}{
"error": {
"type": "not_found_error",
"code": "agent_not_found",
"message": "Agent not found.",
"param": null,
"requestId": "req_8c1f0e2b4a6d9e3f7a5c1b0d"
}
}{
"error": {
"type": "not_found_error",
"code": "agent_not_found",
"message": "Agent not found.",
"param": null,
"requestId": "req_8c1f0e2b4a6d9e3f7a5c1b0d"
}
}{
"error": {
"type": "not_found_error",
"code": "agent_not_found",
"message": "Agent not found.",
"param": null,
"requestId": "req_8c1f0e2b4a6d9e3f7a5c1b0d"
}
}{
"error": {
"type": "not_found_error",
"code": "agent_not_found",
"message": "Agent not found.",
"param": null,
"requestId": "req_8c1f0e2b4a6d9e3f7a5c1b0d"
}
}{
"error": {
"type": "not_found_error",
"code": "agent_not_found",
"message": "Agent not found.",
"param": null,
"requestId": "req_8c1f0e2b4a6d9e3f7a5c1b0d"
}
}Authorizations
An API key (sig_...), or a session token from the web app.
Path Parameters
The agent's id.
^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"3f1c2d4e-5a6b-4c7d-8e9f-0a1b2c3d4e5f"
The run's id.
^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"3f1c2d4e-5a6b-4c7d-8e9f-0a1b2c3d4e5f"
Response
The rescore is queued; the run as it stands.
run ^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"3f1c2d4e-5a6b-4c7d-8e9f-0a1b2c3d4e5f"
queued, running, then complete, refused (budget) or failed. An automatic run over the budget waits in awaiting_approval for a person.
queued, awaiting_approval, running, complete, refused, failed The latest status message: what the budget covered, or why it refused or failed.
A calibration run plays each test several times to decide whether it gates.
run, calibration Who started it: a person, SignalMD on a new version, or an API key.
manual, auto, ci, null The agent version played.
^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"3f1c2d4e-5a6b-4c7d-8e9f-0a1b2c3d4e5f"
The tests requested, in order.
^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$The personas requested; null means each test's own caller.
3: every cell runs three times and reports how many of them passed.
3 Set when the run played a shadow copy of the version.
^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"3f1c2d4e-5a6b-4c7d-8e9f-0a1b2c3d4e5f"
The goal this run worked toward.
^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"3f1c2d4e-5a6b-4c7d-8e9f-0a1b2c3d4e5f"
The draft whose shadow copy this run played.
^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"3f1c2d4e-5a6b-4c7d-8e9f-0a1b2c3d4e5f"
Set on a draft's test: an attempt, or the full accepted suite (what a publish through the API needs).
attempt, full_suite, null True when tests that need a phone call were played as real calls rather than skipped.
Cells finished of cells to play.
Show child attributes
Show child attributes
Fewer runnable than requested means the budget covered part of the run; the rest are not run.
Show child attributes
Show child attributes
Show child attributes
Show child attributes
{
"cells": 12,
"scored": 12,
"counts": {
"passed": 9,
"failed": 2,
"flaky": 1,
"error": 0,
"drift": 0,
"notRun": 0
},
"passRate": 0.75
}
Estimated spend.
Show child attributes
Show child attributes
What the run spent in one place; a goal's model spend is on GET .../goals/{goalId}.
Show child attributes
Show child attributes
Test minutes this run's phone calls count against the plan, from the same allowance its simulated tests use. Null when the run plays no phone calls.
Show child attributes
Show child attributes
When a person approved an automatic run that was over the budget.
"2026-10-02T14:03:07.120Z"
Who started it: a user id, or key: for an API key.
"2026-10-02T14:03:07.120Z"
"2026-10-02T14:03:07.120Z"
Was this page helpful?