curl --request POST \
--url https://api.humanos.tech/agents/fork-evidence/{did} \
--header 'Content-Type: application/json' \
--data '
{
"keyId": "did:web:humanos.tech:agent:3f2a9c1e-7b4d-4e8a-9f60-2d1c5b7a8e90#key-1",
"evidenceRef": "https://detector.example.com/forks/8f14e45f",
"evidenceDigest": "sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
"suspend": true,
"reason": "same key signed in two regions"
}
'import requests
url = "https://api.humanos.tech/agents/fork-evidence/{did}"
payload = {
"keyId": "did:web:humanos.tech:agent:3f2a9c1e-7b4d-4e8a-9f60-2d1c5b7a8e90#key-1",
"evidenceRef": "https://detector.example.com/forks/8f14e45f",
"evidenceDigest": "sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
"suspend": True,
"reason": "same key signed in two regions"
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
keyId: 'did:web:humanos.tech:agent:3f2a9c1e-7b4d-4e8a-9f60-2d1c5b7a8e90#key-1',
evidenceRef: 'https://detector.example.com/forks/8f14e45f',
evidenceDigest: 'sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=',
suspend: true,
reason: 'same key signed in two regions'
})
};
fetch('https://api.humanos.tech/agents/fork-evidence/{did}', 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.humanos.tech/agents/fork-evidence/{did}",
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([
'keyId' => 'did:web:humanos.tech:agent:3f2a9c1e-7b4d-4e8a-9f60-2d1c5b7a8e90#key-1',
'evidenceRef' => 'https://detector.example.com/forks/8f14e45f',
'evidenceDigest' => 'sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=',
'suspend' => true,
'reason' => 'same key signed in two regions'
]),
CURLOPT_HTTPHEADER => [
"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.humanos.tech/agents/fork-evidence/{did}"
payload := strings.NewReader("{\n \"keyId\": \"did:web:humanos.tech:agent:3f2a9c1e-7b4d-4e8a-9f60-2d1c5b7a8e90#key-1\",\n \"evidenceRef\": \"https://detector.example.com/forks/8f14e45f\",\n \"evidenceDigest\": \"sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=\",\n \"suspend\": true,\n \"reason\": \"same key signed in two regions\"\n}")
req, _ := http.NewRequest("POST", url, payload)
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.humanos.tech/agents/fork-evidence/{did}")
.header("Content-Type", "application/json")
.body("{\n \"keyId\": \"did:web:humanos.tech:agent:3f2a9c1e-7b4d-4e8a-9f60-2d1c5b7a8e90#key-1\",\n \"evidenceRef\": \"https://detector.example.com/forks/8f14e45f\",\n \"evidenceDigest\": \"sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=\",\n \"suspend\": true,\n \"reason\": \"same key signed in two regions\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.humanos.tech/agents/fork-evidence/{did}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"keyId\": \"did:web:humanos.tech:agent:3f2a9c1e-7b4d-4e8a-9f60-2d1c5b7a8e90#key-1\",\n \"evidenceRef\": \"https://detector.example.com/forks/8f14e45f\",\n \"evidenceDigest\": \"sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=\",\n \"suspend\": true,\n \"reason\": \"same key signed in two regions\"\n}"
response = http.request(request)
puts response.read_body{
"revokedKeyId": "did:web:humanos.tech:agent:2f8b6c41-9d37-4e5a-8b02-6c1d9e7a4f35#key-1",
"suspended": true
}{
"statusCode": 400,
"message": "evidenceRef must be a string",
"error": "Bad Request"
}{
"statusCode": 404,
"message": "unknown key did:web:humanos.tech:agent:2f8b6c41-9d37-4e5a-8b02-6c1d9e7a4f35#key-9",
"error": "Not Found"
}Report Fork
Record cryptographic evidence that one key was used in two places, and route it through the kill channel
The named key is revoked, because two holders means one of them is not the agent and there is no way to tell which. The agent is suspended unless you say otherwise
The evidence is carried by reference: supply evidenceRef (and ideally evidenceDigest), so the chain commits to which evidence justified the kill without carrying a record whose shape it does not own
Only the organization that operates the agent may report a fork: a false report destroys a key, so a detector that is not the organization routes its finding through it
curl --request POST \
--url https://api.humanos.tech/agents/fork-evidence/{did} \
--header 'Content-Type: application/json' \
--data '
{
"keyId": "did:web:humanos.tech:agent:3f2a9c1e-7b4d-4e8a-9f60-2d1c5b7a8e90#key-1",
"evidenceRef": "https://detector.example.com/forks/8f14e45f",
"evidenceDigest": "sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
"suspend": true,
"reason": "same key signed in two regions"
}
'import requests
url = "https://api.humanos.tech/agents/fork-evidence/{did}"
payload = {
"keyId": "did:web:humanos.tech:agent:3f2a9c1e-7b4d-4e8a-9f60-2d1c5b7a8e90#key-1",
"evidenceRef": "https://detector.example.com/forks/8f14e45f",
"evidenceDigest": "sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
"suspend": True,
"reason": "same key signed in two regions"
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
keyId: 'did:web:humanos.tech:agent:3f2a9c1e-7b4d-4e8a-9f60-2d1c5b7a8e90#key-1',
evidenceRef: 'https://detector.example.com/forks/8f14e45f',
evidenceDigest: 'sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=',
suspend: true,
reason: 'same key signed in two regions'
})
};
fetch('https://api.humanos.tech/agents/fork-evidence/{did}', 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.humanos.tech/agents/fork-evidence/{did}",
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([
'keyId' => 'did:web:humanos.tech:agent:3f2a9c1e-7b4d-4e8a-9f60-2d1c5b7a8e90#key-1',
'evidenceRef' => 'https://detector.example.com/forks/8f14e45f',
'evidenceDigest' => 'sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=',
'suspend' => true,
'reason' => 'same key signed in two regions'
]),
CURLOPT_HTTPHEADER => [
"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.humanos.tech/agents/fork-evidence/{did}"
payload := strings.NewReader("{\n \"keyId\": \"did:web:humanos.tech:agent:3f2a9c1e-7b4d-4e8a-9f60-2d1c5b7a8e90#key-1\",\n \"evidenceRef\": \"https://detector.example.com/forks/8f14e45f\",\n \"evidenceDigest\": \"sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=\",\n \"suspend\": true,\n \"reason\": \"same key signed in two regions\"\n}")
req, _ := http.NewRequest("POST", url, payload)
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.humanos.tech/agents/fork-evidence/{did}")
.header("Content-Type", "application/json")
.body("{\n \"keyId\": \"did:web:humanos.tech:agent:3f2a9c1e-7b4d-4e8a-9f60-2d1c5b7a8e90#key-1\",\n \"evidenceRef\": \"https://detector.example.com/forks/8f14e45f\",\n \"evidenceDigest\": \"sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=\",\n \"suspend\": true,\n \"reason\": \"same key signed in two regions\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.humanos.tech/agents/fork-evidence/{did}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"keyId\": \"did:web:humanos.tech:agent:3f2a9c1e-7b4d-4e8a-9f60-2d1c5b7a8e90#key-1\",\n \"evidenceRef\": \"https://detector.example.com/forks/8f14e45f\",\n \"evidenceDigest\": \"sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=\",\n \"suspend\": true,\n \"reason\": \"same key signed in two regions\"\n}"
response = http.request(request)
puts response.read_body{
"revokedKeyId": "did:web:humanos.tech:agent:2f8b6c41-9d37-4e5a-8b02-6c1d9e7a4f35#key-1",
"suspended": true
}{
"statusCode": 400,
"message": "evidenceRef must be a string",
"error": "Bad Request"
}{
"statusCode": 404,
"message": "unknown key did:web:humanos.tech:agent:2f8b6c41-9d37-4e5a-8b02-6c1d9e7a4f35#key-9",
"error": "Not Found"
}Headers
Pin request, response, and webhook shapes to a specific dated API version (YYYY-MM-DD). Omit to use the version pinned to your API key (set when the key is created; new keys default to the latest version). New integrations should target the latest version.
^\d{4}-\d{2}-\d{2}$"2026-10-16"
Path Parameters
The agent's DID, URL-encoded.
"did:web:humanos.tech:agent:2f8b6c41-9d37-4e5a-8b02-6c1d9e7a4f35"
Body
The key seen in two places. It is revoked.
"did:web:humanos.tech:agent:3f2a9c1e-7b4d-4e8a-9f60-2d1c5b7a8e90#key-1"
Where the evidence record is kept; the chain carries this reference, not the record.
"https://detector.example.com/forks/8f14e45f"
The digest of the evidence record, so the chain commits to what was seen.
"sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU="
Suspend the agent with the key. Defaults to true for an active agent.
"same key signed in two regions"
Response
Returns the key revoked, and whether the agent was suspended.