curl --request GET \
--url https://app.testorim.com/api/runs/{id} \
--header 'Authorization: Bearer <token>'import requests
url = "https://app.testorim.com/api/runs/{id}"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://app.testorim.com/api/runs/{id}', 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://app.testorim.com/api/runs/{id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
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://app.testorim.com/api/runs/{id}"
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(string(body))
}HttpResponse<String> response = Unirest.get("https://app.testorim.com/api/runs/{id}")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.testorim.com/api/runs/{id}")
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{
"run": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"projectId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"instruction": "<string>",
"status": "pending",
"passedCount": 123,
"failedCount": 123,
"skippedCount": 123,
"totalDurationMs": 123,
"llmTokensUsed": 123,
"llmCostCents": 123,
"browserMinutesUsed": 123,
"createdAt": "2023-11-07T05:31:56Z",
"procedureId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"triggeredByUserId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"userExpectation": "pass",
"overallStatus": "passed",
"initialUrl": "<string>",
"finalUrl": "<string>",
"reportMarkdown": "<string>",
"confidenceScore": 123,
"stepsJson": [
{}
],
"screenshotRefsJson": "<array>",
"finalScreenshotR2Key": "<string>",
"finalScreenshotUrl": "<string>",
"networkEventsJson": [
{}
],
"consoleEventsJson": [
{}
],
"videoR2Key": "<string>",
"videoUrl": "<string>",
"traceR2Key": "<string>",
"traceUrl": "<string>",
"accessibilityViolationsJson": [
{}
],
"viewportPreset": "<string>",
"batchId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"browser": "<string>",
"attemptIndex": 123,
"ticketTitle": "<string>",
"ticketMarkdown": "<string>",
"ticketGeneratedAt": "2023-11-07T05:31:56Z",
"performanceMetricsJson": {},
"perPagePerformanceJson": [
{}
],
"visualResultsJson": [
{}
],
"downloadsJson": [
{}
],
"parentRunId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"runKind": "<string>",
"perfStatus": "<string>",
"startedAt": "2023-11-07T05:31:56Z",
"completedAt": "2023-11-07T05:31:56Z",
"lastHeartbeatAt": "2023-11-07T05:31:56Z",
"maxDurationMinutes": 123
}
}{
"error": "Invalid or revoked API key"
}{
"error": "Run not found"
}{
"error": "<string>",
"retryAfter": 123
}Get one run with all artifacts
The polling target named by pollUrl in the trigger response.
Returns the complete run row (steps, network and console events,
accessibility violations, performance metrics, visual-diff results,
downloads) plus resolved artifact URLs.
Two encrypted-at-rest columns, cookiesJson and localStorageJson,
are stripped from the response by augmentDetail and never appear
here.
A run is finished when status is completed, failed or
cancelled. Use overallStatus (passed / failed) for the
pass/fail verdict. The reference CLI exits 0 only on
overallStatus === "passed".
curl --request GET \
--url https://app.testorim.com/api/runs/{id} \
--header 'Authorization: Bearer <token>'import requests
url = "https://app.testorim.com/api/runs/{id}"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://app.testorim.com/api/runs/{id}', 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://app.testorim.com/api/runs/{id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
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://app.testorim.com/api/runs/{id}"
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(string(body))
}HttpResponse<String> response = Unirest.get("https://app.testorim.com/api/runs/{id}")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.testorim.com/api/runs/{id}")
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{
"run": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"projectId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"instruction": "<string>",
"status": "pending",
"passedCount": 123,
"failedCount": 123,
"skippedCount": 123,
"totalDurationMs": 123,
"llmTokensUsed": 123,
"llmCostCents": 123,
"browserMinutesUsed": 123,
"createdAt": "2023-11-07T05:31:56Z",
"procedureId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"triggeredByUserId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"userExpectation": "pass",
"overallStatus": "passed",
"initialUrl": "<string>",
"finalUrl": "<string>",
"reportMarkdown": "<string>",
"confidenceScore": 123,
"stepsJson": [
{}
],
"screenshotRefsJson": "<array>",
"finalScreenshotR2Key": "<string>",
"finalScreenshotUrl": "<string>",
"networkEventsJson": [
{}
],
"consoleEventsJson": [
{}
],
"videoR2Key": "<string>",
"videoUrl": "<string>",
"traceR2Key": "<string>",
"traceUrl": "<string>",
"accessibilityViolationsJson": [
{}
],
"viewportPreset": "<string>",
"batchId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"browser": "<string>",
"attemptIndex": 123,
"ticketTitle": "<string>",
"ticketMarkdown": "<string>",
"ticketGeneratedAt": "2023-11-07T05:31:56Z",
"performanceMetricsJson": {},
"perPagePerformanceJson": [
{}
],
"visualResultsJson": [
{}
],
"downloadsJson": [
{}
],
"parentRunId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"runKind": "<string>",
"perfStatus": "<string>",
"startedAt": "2023-11-07T05:31:56Z",
"completedAt": "2023-11-07T05:31:56Z",
"lastHeartbeatAt": "2023-11-07T05:31:56Z",
"maxDurationMinutes": 123
}
}{
"error": "Invalid or revoked API key"
}{
"error": "Run not found"
}{
"error": "<string>",
"retryAfter": 123
}Authorizations
Send Authorization: Bearer tst_live_….
Format (services/api-keys.ts): the literal prefix tst_live_
followed by 24 random bytes rendered as 32 base64url characters.
Only the SHA-256 hash is stored server-side. The shape check that
routes a token down the API-key path rather than the Clerk JWT path
requires the tst_live_ prefix and a total length of at least 25
characters.
Keys are minted in the dashboard at /settings/team. The same header
also accepts a Clerk session JWT, which is how the web app
authenticates, but the JWT path is out of scope for this document.
Path Parameters
Run id (UUID). Returned as runId by POST /api/runs/trigger. Not UUID-validated by the handler; a malformed value simply finds nothing and 404s.
Response
OK
The full run row from GET /api/runs/{id}, minus the two encrypted
columns cookiesJson and localStorageJson (stripped by
augmentDetail), plus three resolved artifact URLs.
The JSON payload columns are deliberately typed loosely below: they are written by the run orchestrator without a wire schema, so their inner shape can change without an API change. Read them defensively.
Show child attributes
Show child attributes

