curl -sS -X POST "https://phosra-api-sandbox-production.up.railway.app/api/v1/advisors/register" \
-H "Authorization: Bearer $PHOSRA_SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"slug": "acme-advisor",
"display_name": "Acme Advisor",
"publisher_org": "Acme Safety Labs",
"public_key_pem": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEA...replace-with-your-ed25519-public-key...\n-----END PUBLIC KEY-----",
"key_id": "acme-advisor#2026-07",
"capability_domains": [
"csm_age_rating_override"
],
"scope": "global"
}'const BASE = "https://phosra-api-sandbox-production.up.railway.app/api/v1";
const res = await fetch(`${BASE}/advisors/register`, {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.PHOSRA_SESSION_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"slug": "acme-advisor",
"display_name": "Acme Advisor",
"publisher_org": "Acme Safety Labs",
"public_key_pem": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEA...replace-with-your-ed25519-public-key...\n-----END PUBLIC KEY-----",
"key_id": "acme-advisor#2026-07",
"capability_domains": [
"csm_age_rating_override"
],
"scope": "global"
}),
});
console.log(res.status, await res.json());
import os, requests
BASE = "https://phosra-api-sandbox-production.up.railway.app/api/v1"
res = requests.post(
f"{BASE}/advisors/register",
headers={"Authorization": f"Bearer {os.environ['PHOSRA_SESSION_TOKEN']}"},
json={
"slug": "acme-advisor",
"display_name": "Acme Advisor",
"publisher_org": "Acme Safety Labs",
"public_key_pem": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEA...replace-with-your-ed25519-public-key...\n-----END PUBLIC KEY-----",
"key_id": "acme-advisor#2026-07",
"capability_domains": [
"csm_age_rating_override"
],
"scope": "global"
},
)
print(res.status_code, res.json())
package main
import (
"bytes"
"fmt"
"io"
"net/http"
"os"
)
func main() {
base := "https://phosra-api-sandbox-production.up.railway.app/api/v1"
body := bytes.NewBufferString(`{
"slug": "acme-advisor",
"display_name": "Acme Advisor",
"publisher_org": "Acme Safety Labs",
"public_key_pem": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEA...replace-with-your-ed25519-public-key...\n-----END PUBLIC KEY-----",
"key_id": "acme-advisor#2026-07",
"capability_domains": [
"csm_age_rating_override"
],
"scope": "global"
}`)
req, _ := http.NewRequest("POST", base+"/advisors/register", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("PHOSRA_SESSION_TOKEN"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
out, _ := io.ReadAll(resp.Body)
fmt.Println(resp.Status, string(out))
}
<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://phosra-api-sandbox-production.up.railway.app/api/v1/advisors/register",
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([
'slug' => '<string>',
'display_name' => '<string>',
'public_key_pem' => '<string>',
'key_id' => '<string>',
'publisher_org' => '<string>',
'callback_url' => '<string>',
'capability_domains' => [
'<string>'
],
'scope_family_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'manifest_url' => '<string>'
]),
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;
}HttpResponse<String> response = Unirest.post("https://phosra-api-sandbox-production.up.railway.app/api/v1/advisors/register")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"slug\": \"<string>\",\n \"display_name\": \"<string>\",\n \"public_key_pem\": \"<string>\",\n \"key_id\": \"<string>\",\n \"publisher_org\": \"<string>\",\n \"callback_url\": \"<string>\",\n \"capability_domains\": [\n \"<string>\"\n ],\n \"scope_family_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"manifest_url\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://phosra-api-sandbox-production.up.railway.app/api/v1/advisors/register")
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 \"slug\": \"<string>\",\n \"display_name\": \"<string>\",\n \"public_key_pem\": \"<string>\",\n \"key_id\": \"<string>\",\n \"publisher_org\": \"<string>\",\n \"callback_url\": \"<string>\",\n \"capability_domains\": [\n \"<string>\"\n ],\n \"scope_family_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"manifest_url\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"advisor_id": "7e4c1a90-3b28-4d67-95f1-0a8c6b2e9d43",
"slug": "touchstone",
"trust_tier": "provisional",
"verification_token": "phosra-verify=Xk3n9QpL2mV8sT4wRc7bYd1fHzA0gJ6u",
"verification_instructions": "Add a DNS TXT record at _phosra-verify.rivera-safety.com with the value from verification_token, then call POST /advisors/{id}/verify."
}{
"error": "Bad Request",
"message": "scope must be \"family\" or \"global\"",
"code": 400
}{
"error": "Unauthorized",
"message": "missing authorization header",
"code": 401
}{
"error": "Too Many Requests",
"message": "rate limit exceeded",
"code": 429
}{
"error": "Internal Server Error",
"message": "internal error",
"code": 500
}{
"error": "Bad Gateway",
"message": "downstream provider error",
"code": 502
}{
"error": "Service Unavailable",
"message": "downstream provider unavailable",
"code": 503
}Register advisor
Registers an advisor agent at provisional tier. For scope=global a DNS verification token is returned — publish it as a DNS TXT record at _phosra-verify.<callback domain> to complete ownership verification. An unrecognized capability name causes the request to be rejected with 400 (unknown_capability: <name>). A recognized capability above the provisional band is silently dropped from the accepted set.
curl -sS -X POST "https://phosra-api-sandbox-production.up.railway.app/api/v1/advisors/register" \
-H "Authorization: Bearer $PHOSRA_SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"slug": "acme-advisor",
"display_name": "Acme Advisor",
"publisher_org": "Acme Safety Labs",
"public_key_pem": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEA...replace-with-your-ed25519-public-key...\n-----END PUBLIC KEY-----",
"key_id": "acme-advisor#2026-07",
"capability_domains": [
"csm_age_rating_override"
],
"scope": "global"
}'const BASE = "https://phosra-api-sandbox-production.up.railway.app/api/v1";
const res = await fetch(`${BASE}/advisors/register`, {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.PHOSRA_SESSION_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"slug": "acme-advisor",
"display_name": "Acme Advisor",
"publisher_org": "Acme Safety Labs",
"public_key_pem": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEA...replace-with-your-ed25519-public-key...\n-----END PUBLIC KEY-----",
"key_id": "acme-advisor#2026-07",
"capability_domains": [
"csm_age_rating_override"
],
"scope": "global"
}),
});
console.log(res.status, await res.json());
import os, requests
BASE = "https://phosra-api-sandbox-production.up.railway.app/api/v1"
res = requests.post(
f"{BASE}/advisors/register",
headers={"Authorization": f"Bearer {os.environ['PHOSRA_SESSION_TOKEN']}"},
json={
"slug": "acme-advisor",
"display_name": "Acme Advisor",
"publisher_org": "Acme Safety Labs",
"public_key_pem": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEA...replace-with-your-ed25519-public-key...\n-----END PUBLIC KEY-----",
"key_id": "acme-advisor#2026-07",
"capability_domains": [
"csm_age_rating_override"
],
"scope": "global"
},
)
print(res.status_code, res.json())
package main
import (
"bytes"
"fmt"
"io"
"net/http"
"os"
)
func main() {
base := "https://phosra-api-sandbox-production.up.railway.app/api/v1"
body := bytes.NewBufferString(`{
"slug": "acme-advisor",
"display_name": "Acme Advisor",
"publisher_org": "Acme Safety Labs",
"public_key_pem": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEA...replace-with-your-ed25519-public-key...\n-----END PUBLIC KEY-----",
"key_id": "acme-advisor#2026-07",
"capability_domains": [
"csm_age_rating_override"
],
"scope": "global"
}`)
req, _ := http.NewRequest("POST", base+"/advisors/register", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("PHOSRA_SESSION_TOKEN"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
out, _ := io.ReadAll(resp.Body)
fmt.Println(resp.Status, string(out))
}
<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://phosra-api-sandbox-production.up.railway.app/api/v1/advisors/register",
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([
'slug' => '<string>',
'display_name' => '<string>',
'public_key_pem' => '<string>',
'key_id' => '<string>',
'publisher_org' => '<string>',
'callback_url' => '<string>',
'capability_domains' => [
'<string>'
],
'scope_family_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'manifest_url' => '<string>'
]),
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;
}HttpResponse<String> response = Unirest.post("https://phosra-api-sandbox-production.up.railway.app/api/v1/advisors/register")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"slug\": \"<string>\",\n \"display_name\": \"<string>\",\n \"public_key_pem\": \"<string>\",\n \"key_id\": \"<string>\",\n \"publisher_org\": \"<string>\",\n \"callback_url\": \"<string>\",\n \"capability_domains\": [\n \"<string>\"\n ],\n \"scope_family_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"manifest_url\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://phosra-api-sandbox-production.up.railway.app/api/v1/advisors/register")
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 \"slug\": \"<string>\",\n \"display_name\": \"<string>\",\n \"public_key_pem\": \"<string>\",\n \"key_id\": \"<string>\",\n \"publisher_org\": \"<string>\",\n \"callback_url\": \"<string>\",\n \"capability_domains\": [\n \"<string>\"\n ],\n \"scope_family_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"manifest_url\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"advisor_id": "7e4c1a90-3b28-4d67-95f1-0a8c6b2e9d43",
"slug": "touchstone",
"trust_tier": "provisional",
"verification_token": "phosra-verify=Xk3n9QpL2mV8sT4wRc7bYd1fHzA0gJ6u",
"verification_instructions": "Add a DNS TXT record at _phosra-verify.rivera-safety.com with the value from verification_token, then call POST /advisors/{id}/verify."
}{
"error": "Bad Request",
"message": "scope must be \"family\" or \"global\"",
"code": 400
}{
"error": "Unauthorized",
"message": "missing authorization header",
"code": 401
}{
"error": "Too Many Requests",
"message": "rate limit exceeded",
"code": 429
}{
"error": "Internal Server Error",
"message": "internal error",
"code": 500
}{
"error": "Bad Gateway",
"message": "downstream provider error",
"code": 502
}{
"error": "Service Unavailable",
"message": "downstream provider unavailable",
"code": 503
}Authorizations
A logged-in user session bearer token (WorkOS AuthKit access token from signup/login).
Body
Unique identifier slug for the advisor agent.
Human-readable name for the advisor.
Ed25519 public key in PEM format, used to verify advisory signatures.
Identifier for the signing key (forms the did#kid).
family = per-family advisory (scope_family_id required); global = coalition-wide advisory (manifest_url required).
family, global Name of the organization publishing this advisor.
HTTPS callback endpoint for advisory verdicts.
Advisory capability domains this agent supports. An unrecognized capability name causes the request to be rejected with a 400 error (unknown_capability: <name>). A recognized capability that is above the provisional band is silently dropped (skipped) from the accepted set.
Family UUID to scope this advisor to. Required when scope=family.
URL of the advisor manifest. Required when scope=global.
Response
Advisor registered at provisional tier.