curl --request POST \
--url https://api.visiqlabs.com/allow/evaluate \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"agent_id": "billing-copilot",
"target_app": "stripe",
"action": "refund.create",
"context": {
"amount_cents": 5000
}
}
'import requests
url = "https://api.visiqlabs.com/allow/evaluate"
payload = {
"agent_id": "billing-copilot",
"target_app": "stripe",
"action": "refund.create",
"context": { "amount_cents": 5000 }
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
agent_id: 'billing-copilot',
target_app: 'stripe',
action: 'refund.create',
context: {amount_cents: 5000}
})
};
fetch('https://api.visiqlabs.com/allow/evaluate', 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.visiqlabs.com/allow/evaluate",
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([
'agent_id' => 'billing-copilot',
'target_app' => 'stripe',
'action' => 'refund.create',
'context' => [
'amount_cents' => 5000
]
]),
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;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.visiqlabs.com/allow/evaluate"
payload := strings.NewReader("{\n \"agent_id\": \"billing-copilot\",\n \"target_app\": \"stripe\",\n \"action\": \"refund.create\",\n \"context\": {\n \"amount_cents\": 5000\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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.visiqlabs.com/allow/evaluate")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"agent_id\": \"billing-copilot\",\n \"target_app\": \"stripe\",\n \"action\": \"refund.create\",\n \"context\": {\n \"amount_cents\": 5000\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.visiqlabs.com/allow/evaluate")
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 \"agent_id\": \"billing-copilot\",\n \"target_app\": \"stripe\",\n \"action\": \"refund.create\",\n \"context\": {\n \"amount_cents\": 5000\n }\n}"
response = http.request(request)
puts response.read_body{
"decision_id": "4b2b8c1e-6f2a-4a1e-9e2b-9d5b0a1c2d3e",
"decision": "permit",
"reason": "Within policy",
"rule_code": "R-1042",
"enforced": true,
"agent_mode": "enforce",
"plane": "action",
"operation": "create",
"is_retrieval": false
}{
"error": "Invalid request body",
"code": "invalid_request",
"details": [
{
"path": [
"agent_id"
],
"message": "Required"
}
]
}{
"error": "Unauthorized",
"code": "unauthenticated"
}{
"error": "insufficient_scope",
"code": "insufficient_scope",
"detail": "This API key is not authorized for the requested operation."
}{
"error": "Rule not found",
"code": "not_found"
}{
"error": "rate_limiter_unavailable",
"code": "rate_limiter_unavailable",
"detail": "Rate limiter unavailable, please retry."
}Evaluate an agent action
Evaluate a single agent action against your action-governance rules and return the enforced decision. This is the agent-facing hot path.
Requires scope rules:evaluate (or the legacy allow:write).
curl --request POST \
--url https://api.visiqlabs.com/allow/evaluate \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"agent_id": "billing-copilot",
"target_app": "stripe",
"action": "refund.create",
"context": {
"amount_cents": 5000
}
}
'import requests
url = "https://api.visiqlabs.com/allow/evaluate"
payload = {
"agent_id": "billing-copilot",
"target_app": "stripe",
"action": "refund.create",
"context": { "amount_cents": 5000 }
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
agent_id: 'billing-copilot',
target_app: 'stripe',
action: 'refund.create',
context: {amount_cents: 5000}
})
};
fetch('https://api.visiqlabs.com/allow/evaluate', 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.visiqlabs.com/allow/evaluate",
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([
'agent_id' => 'billing-copilot',
'target_app' => 'stripe',
'action' => 'refund.create',
'context' => [
'amount_cents' => 5000
]
]),
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;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.visiqlabs.com/allow/evaluate"
payload := strings.NewReader("{\n \"agent_id\": \"billing-copilot\",\n \"target_app\": \"stripe\",\n \"action\": \"refund.create\",\n \"context\": {\n \"amount_cents\": 5000\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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.visiqlabs.com/allow/evaluate")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"agent_id\": \"billing-copilot\",\n \"target_app\": \"stripe\",\n \"action\": \"refund.create\",\n \"context\": {\n \"amount_cents\": 5000\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.visiqlabs.com/allow/evaluate")
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 \"agent_id\": \"billing-copilot\",\n \"target_app\": \"stripe\",\n \"action\": \"refund.create\",\n \"context\": {\n \"amount_cents\": 5000\n }\n}"
response = http.request(request)
puts response.read_body{
"decision_id": "4b2b8c1e-6f2a-4a1e-9e2b-9d5b0a1c2d3e",
"decision": "permit",
"reason": "Within policy",
"rule_code": "R-1042",
"enforced": true,
"agent_mode": "enforce",
"plane": "action",
"operation": "create",
"is_retrieval": false
}{
"error": "Invalid request body",
"code": "invalid_request",
"details": [
{
"path": [
"agent_id"
],
"message": "Required"
}
]
}{
"error": "Unauthorized",
"code": "unauthenticated"
}{
"error": "insufficient_scope",
"code": "insufficient_scope",
"detail": "This API key is not authorized for the requested operation."
}{
"error": "Rule not found",
"code": "not_found"
}{
"error": "rate_limiter_unavailable",
"code": "rate_limiter_unavailable",
"detail": "Rate limiter unavailable, please retry."
}Authorizations
A VisIQ API key presented as Authorization: Bearer vq_prod_.... Mint harness keys under Settings → Harness Keys and API keys under Settings → API Keys in the dashboard.
Body
1 - 2551 - 2551 - 255Arbitrary decision inputs (e.g. amount, resource id).
1 - 255The action-schema identity the SDK computed for this event. When omitted, the server derives it from context.
1 - 128The MCP server the tool call came from. A server your registry marks blocked, or one that drifted from its approved definition, is denied whatever the rule outcome.
1 - 255Identity evidence for the event, read by rules as input.session.identity.*. Put a principal in attested only when it came through a channel the agent cannot author (an IdP assertion, your application's own request context, or a check you performed). A principal the model only read in the conversation goes in claimed, which grants nothing. Unknown keys are refused with 400.
Show child attributes
Show child attributes
Response
The enforced decision.
permit, deny, approval_required, mask off, monitor, enforce The matched rule code (synthetic D-* for defaults; null in off-mode).
action, retrieval, delegation, null Present only when decision is mask.
Present only when decision is approval_required, as the fallback if no human responds.
mask, deny