curl -X POST "https://api.signalmd.dev/v1/agents/6f1d2c3b-4a5e-4f60-8b7a-9c0d1e2f3a4b/watches/<watchId>/labels" \
-H "Authorization: Bearer $SIGNAL_API_KEY"import requests
url = "https://api.signalmd.dev/v1/agents/{agentId}/watches/{watchId}/labels"
payload = { "callId": "3f1c2d4e-5a6b-4c7d-8e9f-0a1b2c3d4e5f" }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({callId: '3f1c2d4e-5a6b-4c7d-8e9f-0a1b2c3d4e5f'})
};
fetch('https://api.signalmd.dev/v1/agents/{agentId}/watches/{watchId}/labels', 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}/watches/{watchId}/labels",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'callId' => '3f1c2d4e-5a6b-4c7d-8e9f-0a1b2c3d4e5f'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.signalmd.dev/v1/agents/{agentId}/watches/{watchId}/labels"
payload := strings.NewReader("{\n \"callId\": \"3f1c2d4e-5a6b-4c7d-8e9f-0a1b2c3d4e5f\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
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}/watches/{watchId}/labels")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"callId\": \"3f1c2d4e-5a6b-4c7d-8e9f-0a1b2c3d4e5f\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.signalmd.dev/v1/agents/{agentId}/watches/{watchId}/labels")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"callId\": \"3f1c2d4e-5a6b-4c7d-8e9f-0a1b2c3d4e5f\"\n}"
response = http.request(request)
puts response.read_body{
"object": "watch",
"id": "3f1c2d4e-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
"name": "<string>",
"lane": "hearing",
"state": "draft",
"revision": 123,
"origin": "<string>",
"passRate": 123,
"calls": 123,
"precision": 123,
"labelled": 123,
"source": {
"agentVersion": 123,
"step": "<string>",
"line": "<string>",
"verbatim": true
},
"firstSample": {
"inScope": 123,
"flagged": 123
},
"createdAt": "2026-10-02T14:03:07.120Z",
"updatedAt": "2026-10-02T14:03:07.120Z",
"scope": {
"text": "<string>",
"code": {
"kind": "tool_called",
"tool": "<string>",
"step": "<string>"
}
},
"expectation": {
"text": "<string>",
"polarity": "must",
"code": {}
},
"createdBy": "<string>",
"backtest": {
"watchRevision": 123,
"considered": 123,
"inScope": 123,
"flagged": 123,
"createdAt": "2026-10-02T14:03:07.120Z",
"updatedAt": "2026-10-02T14:03:07.120Z"
},
"samples": [
{
"callId": "3f1c2d4e-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
"kind": "flagged",
"verdict": "<string>",
"quote": "<string>",
"turn": 123,
"label": "right"
}
],
"labels": {
"right": 123,
"wrong": 123,
"labelled": 123,
"precision": 123
},
"goLiveBlock": "<string>"
}{
"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"
}
}Label a sample call
Marks a flagged sample call on the current revision right or wrong. Cleared calls are refused (400). Only labels on flagged calls count toward turning the watch on.
curl -X POST "https://api.signalmd.dev/v1/agents/6f1d2c3b-4a5e-4f60-8b7a-9c0d1e2f3a4b/watches/<watchId>/labels" \
-H "Authorization: Bearer $SIGNAL_API_KEY"import requests
url = "https://api.signalmd.dev/v1/agents/{agentId}/watches/{watchId}/labels"
payload = { "callId": "3f1c2d4e-5a6b-4c7d-8e9f-0a1b2c3d4e5f" }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({callId: '3f1c2d4e-5a6b-4c7d-8e9f-0a1b2c3d4e5f'})
};
fetch('https://api.signalmd.dev/v1/agents/{agentId}/watches/{watchId}/labels', 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}/watches/{watchId}/labels",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'callId' => '3f1c2d4e-5a6b-4c7d-8e9f-0a1b2c3d4e5f'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.signalmd.dev/v1/agents/{agentId}/watches/{watchId}/labels"
payload := strings.NewReader("{\n \"callId\": \"3f1c2d4e-5a6b-4c7d-8e9f-0a1b2c3d4e5f\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
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}/watches/{watchId}/labels")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"callId\": \"3f1c2d4e-5a6b-4c7d-8e9f-0a1b2c3d4e5f\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.signalmd.dev/v1/agents/{agentId}/watches/{watchId}/labels")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"callId\": \"3f1c2d4e-5a6b-4c7d-8e9f-0a1b2c3d4e5f\"\n}"
response = http.request(request)
puts response.read_body{
"object": "watch",
"id": "3f1c2d4e-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
"name": "<string>",
"lane": "hearing",
"state": "draft",
"revision": 123,
"origin": "<string>",
"passRate": 123,
"calls": 123,
"precision": 123,
"labelled": 123,
"source": {
"agentVersion": 123,
"step": "<string>",
"line": "<string>",
"verbatim": true
},
"firstSample": {
"inScope": 123,
"flagged": 123
},
"createdAt": "2026-10-02T14:03:07.120Z",
"updatedAt": "2026-10-02T14:03:07.120Z",
"scope": {
"text": "<string>",
"code": {
"kind": "tool_called",
"tool": "<string>",
"step": "<string>"
}
},
"expectation": {
"text": "<string>",
"polarity": "must",
"code": {}
},
"createdBy": "<string>",
"backtest": {
"watchRevision": 123,
"considered": 123,
"inScope": 123,
"flagged": 123,
"createdAt": "2026-10-02T14:03:07.120Z",
"updatedAt": "2026-10-02T14:03:07.120Z"
},
"samples": [
{
"callId": "3f1c2d4e-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
"kind": "flagged",
"verdict": "<string>",
"quote": "<string>",
"turn": 123,
"label": "right"
}
],
"labels": {
"right": 123,
"wrong": 123,
"labelled": 123,
"precision": 123
},
"goLiveBlock": "<string>"
}{
"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 watch'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"
Body
Response
The watch.
watch ^[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 lane a defect lives in: hearing, understanding, flow, speaking or integrations.
hearing, understanding, flow, speaking, integrations draft/backtesting while authoring; review once a backtest finished; live once a person turns it on; paused or rejected leave it off.
draft, backtesting, review, live, paused, rejected Share of production calls in scope where the expectation held. Null until there are calls to measure.
Production calls behind the pass rate. 0 until there are any.
Of the sample calls a person labelled on the current revision, the share labelled right. Null until any are labelled.
For a generated watch (origin generated): the agent version and instruction line it was drafted from. Null otherwise.
Show child attributes
Show child attributes
On a suggested draft: how many past calls the first backtest found in scope and how many it flagged. Null until that backtest finishes. Precision is not known until the draft is kept and its sample calls are labelled.
Show child attributes
Show child attributes
"2026-10-02T14:03:07.120Z"
"2026-10-02T14:03:07.120Z"
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Why Turn on is refused, or null when the bar is met.
Was this page helpful?