curl --request DELETE \
--url https://app.testorim.com/api/keys/{id} \
--header 'Authorization: Bearer <token>'import requests
url = "https://app.testorim.com/api/keys/{id}"
headers = {"Authorization": "Bearer <token>"}
response = requests.delete(url, headers=headers)
print(response.text)const options = {method: 'DELETE', headers: {Authorization: 'Bearer <token>'}};
fetch('https://app.testorim.com/api/keys/{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/keys/{id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "DELETE",
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/keys/{id}"
req, _ := http.NewRequest("DELETE", 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.delete("https://app.testorim.com/api/keys/{id}")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.testorim.com/api/keys/{id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Delete.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"error": "key id required"
}{
"error": "Invalid or revoked API key"
}{
"error": "Viewers have read-only access to this workspace",
"code": "read_only_role"
}{
"error": "Key not found"
}{
"error": "<string>",
"retryAfter": 123
}{
"error": "Failed to revoke key"
}Revoke an API key
Soft-revokes the key by stamping revokedAt; the row survives so
audit references stay resolvable. Authentication rejects a revoked
key immediately afterwards.
The update is scoped to keys owned by the calling user and not
already revoked. A key that does not exist, belongs to someone else,
or was already revoked all return the same 404. The handler
deliberately does not distinguish them.
Revoking the key you are currently authenticating with is allowed and takes effect on the next request.
curl --request DELETE \
--url https://app.testorim.com/api/keys/{id} \
--header 'Authorization: Bearer <token>'import requests
url = "https://app.testorim.com/api/keys/{id}"
headers = {"Authorization": "Bearer <token>"}
response = requests.delete(url, headers=headers)
print(response.text)const options = {method: 'DELETE', headers: {Authorization: 'Bearer <token>'}};
fetch('https://app.testorim.com/api/keys/{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/keys/{id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "DELETE",
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/keys/{id}"
req, _ := http.NewRequest("DELETE", 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.delete("https://app.testorim.com/api/keys/{id}")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.testorim.com/api/keys/{id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Delete.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"error": "key id required"
}{
"error": "Invalid or revoked API key"
}{
"error": "Viewers have read-only access to this workspace",
"code": "read_only_role"
}{
"error": "Key not found"
}{
"error": "<string>",
"retryAfter": 123
}{
"error": "Failed to revoke key"
}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
API key id (the id field from the list, not the key itself). Not UUID-validated by the handler.
Response
Revoked. Empty body.

