curl --request POST \
--url https://app.testorim.com/api/runs/batch/{batchId}/cancel \
--header 'Authorization: Bearer <token>'import requests
url = "https://app.testorim.com/api/runs/batch/{batchId}/cancel"
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, headers=headers)
print(response.text)const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
fetch('https://app.testorim.com/api/runs/batch/{batchId}/cancel', 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/batch/{batchId}/cancel",
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://app.testorim.com/api/runs/batch/{batchId}/cancel"
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://app.testorim.com/api/runs/batch/{batchId}/cancel")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.testorim.com/api/runs/batch/{batchId}/cancel")
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{
"cancelled": 1,
"reapedHandlers": 1
}{
"error": "Invalid or revoked API key"
}{
"error": "Viewers have read-only access to this workspace",
"code": "read_only_role"
}{
"error": "Batch not found"
}{
"error": "<string>",
"retryAfter": 123
}Cancel every run in a batch
Same as the single-run cancel, applied to every pending/running row sharing the batchId. This is the way to stop a whole fuzz batch or matrix fan-out; queued fuzz variants that have not started are not fired. Ownership is checked by requiring at least one run in the batch to belong to the key’s organization. Takes no request body.
curl --request POST \
--url https://app.testorim.com/api/runs/batch/{batchId}/cancel \
--header 'Authorization: Bearer <token>'import requests
url = "https://app.testorim.com/api/runs/batch/{batchId}/cancel"
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, headers=headers)
print(response.text)const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
fetch('https://app.testorim.com/api/runs/batch/{batchId}/cancel', 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/batch/{batchId}/cancel",
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://app.testorim.com/api/runs/batch/{batchId}/cancel"
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://app.testorim.com/api/runs/batch/{batchId}/cancel")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.testorim.com/api/runs/batch/{batchId}/cancel")
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{
"cancelled": 1,
"reapedHandlers": 1
}{
"error": "Invalid or revoked API key"
}{
"error": "Viewers have read-only access to this workspace",
"code": "read_only_role"
}{
"error": "Batch 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/api-keys, in any
workspace, personal included. 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
The batch identifier. Read it from a run's batchId, or from an active-run group. Not validated as a UUID by the handler, though the column is uuid.
Response
Cancellation processed for the batch.
Number of DB rows flipped from pending/running to cancelled. Zero when the run(s) had already finished.
x >= 0Number of live orchestrators whose in-memory cancel handler actually fired and tore a browser down. Can be lower than cancelled when a process already exited.
x >= 0
