Integrate in 5 minutes
One HTTP call before each tool execution. AgentShield evaluates your policies in <50ms
and returns allow, deny, or flag. That's it.
Quickstart
Three steps to full agent governance. No SDK required — just HTTP.
Get your API key
Join the waitlist and you'll receive an API key via email.
For testing, use the demo key: as_demo_agentshield_2026 — it has no quota limits
and runs against live policies.
Add one call before tool execution
Before your agent runs any tool, send a check request:
curl -X POST https://ledgerpilot-9.polsia.app/api/v1/check \
-H "Content-Type: application/json" \
-H "X-API-Key: as_demo_agentshield_2026" \
-d '{
"agent_id": "my-agent-prod",
"tool_name": "send_email",
"tool_input": { "to": "user@example.com", "subject": "Hello" }
}'
Handle the response
Check the decision field — proceed on allow, halt on deny, log on flag.
{
"decision": "allow",
"reason": "All policies passed",
"policy_id": null,
"latency_ms": 12
}
Authentication
All API requests require an X-API-Key header. Invalid or missing keys return 401.
X-API-Key: as_demo_agentshield_2026
The demo key as_demo_agentshield_2026 is shared and rate limits are not enforced per-account.
Production API keys are scoped to your organization and tracked separately in the audit log.
POST /api/v1/check
Evaluate all active policies for a single tool call. Returns a governance decision in <50ms.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
| agent_id | string | required | Unique identifier for the agent (e.g., my-agent-prod) |
| tool_name | string | required | Name of the tool being called (e.g., send_email) |
| tool_input | any | optional | The input payload for the tool — inspected by PII policies |
| context | object | optional | Additional context (e.g., { action: "user_triggered" }) stored in audit log |
Response
"reason": "All policies passed" // human-readable explanation
"policy_id": 42 | null // ID of the triggering policy, null if all passed
"latency_ms": 12 // end-to-end processing time
Code examples
import requests
AGENTSHIELD_URL = "https://ledgerpilot-9.polsia.app"
API_KEY = "as_demo_agentshield_2026"
def check_tool(agent_id: str, tool_name: str, tool_input=None) -> dict:
resp = requests.post(
f"{AGENTSHIELD_URL}/api/v1/check",
headers={"X-API-Key": API_KEY},
json={
"agent_id": agent_id,
"tool_name": tool_name,
"tool_input": tool_input or {}
}
)
resp.raise_for_status()
return resp.json()
# Before executing any tool:
result = check_tool("my-agent-prod", "send_email", {
"to": "user@example.com",
"subject": "Weekly report"
})
if result["decision"] == "deny":
raise RuntimeError(f"Tool blocked: {result['reason']}")
elif result["decision"] == "flag":
log_review_event(result) # your logging logic
# Proceed with tool execution
send_email(...)
const AGENTSHIELD_URL = 'https://ledgerpilot-9.polsia.app';
const API_KEY = 'as_demo_agentshield_2026';
async function checkTool(agentId, toolName, toolInput = {}) {
const resp = await fetch(`${AGENTSHIELD_URL}/api/v1/check`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': API_KEY
},
body: JSON.stringify({ agent_id: agentId, tool_name: toolName, tool_input: toolInput })
});
if (!resp.ok) throw new Error(`AgentShield error: ${resp.status}`);
return resp.json();
}
// Before executing any tool:
const result = await checkTool('my-agent-prod', 'send_email', {
to: 'user@example.com',
subject: 'Weekly report'
});
if (result.decision === 'deny') {
throw new Error(`Tool blocked: ${result.reason}`);
} else if (result.decision === 'flag') {
await logReviewEvent(result); // your logging logic
}
// Proceed with tool execution
await sendEmail(...);
curl -X POST https://ledgerpilot-9.polsia.app/api/v1/check \
-H "Content-Type: application/json" \
-H "X-API-Key: as_demo_agentshield_2026" \
-d '{
"agent_id": "my-agent-prod",
"tool_name": "send_email",
"tool_input": {
"to": "user@example.com",
"subject": "Weekly report"
}
}'
GET /api/v1/audit
Retrieve a paginated history of all policy checks. Supports filtering by agent, decision, and date range.
Query parameters
| Param | Type | Description |
|---|---|---|
| agent_id | string | Filter by agent ID |
| decision | allow | deny | flag | Filter by decision outcome |
| start_date | ISO 8601 | Include records after this timestamp |
| end_date | ISO 8601 | Include records before this timestamp |
| limit | integer | Max records to return (default: 50, max: 500) |
| offset | integer | Pagination offset (default: 0) |
Example
resp = requests.get(
f"{AGENTSHIELD_URL}/api/v1/audit",
headers={"X-API-Key": API_KEY},
params={
"decision": "deny",
"agent_id": "my-agent-prod",
"limit": 100
}
)
data = resp.json()
# data = { "logs": [...], "total": 14, "limit": 100, "offset": 0 }
const params = new URLSearchParams({
decision: 'deny',
agent_id: 'my-agent-prod',
limit: 100
});
const resp = await fetch(`${AGENTSHIELD_URL}/api/v1/audit?${params}`, {
headers: { 'X-API-Key': API_KEY }
});
const data = await resp.json();
// data = { logs: [...], total: 14, limit: 100, offset: 0 }
curl "https://ledgerpilot-9.polsia.app/api/v1/audit?decision=deny&agent_id=my-agent-prod&limit=100" \
-H "X-API-Key: as_demo_agentshield_2026"
GET /api/v1/policies
List all configured policies for your organization.
No parameters. Returns all policies in evaluation order.
resp = requests.get(
f"{AGENTSHIELD_URL}/api/v1/policies",
headers={"X-API-Key": API_KEY}
)
policies = resp.json()["policies"]
for p in policies:
print(f"{p['name']} ({p['rule_type']}) — enabled: {p['enabled']}")
const resp = await fetch(`${AGENTSHIELD_URL}/api/v1/policies`, {
headers: { 'X-API-Key': API_KEY }
});
const { policies } = await resp.json();
policies.forEach(p => {
console.log(`${p.name} (${p.rule_type}) — enabled: ${p.enabled}`);
});
curl https://ledgerpilot-9.polsia.app/api/v1/policies \
-H "X-API-Key: as_demo_agentshield_2026"
POST /api/v1/policies
Create a new policy. Takes effect immediately — all subsequent /check requests will evaluate it.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | required | Human-readable policy name |
| rule_type | string | required | rate_limit | pii | scope | cost | approval |
| description | string | optional | Internal description |
| rule_config | object | optional | Policy-specific configuration (see Policy Configuration) |
| enabled | boolean | optional | Default: true |
Example
resp = requests.post(
f"{AGENTSHIELD_URL}/api/v1/policies",
headers={"X-API-Key": API_KEY},
json={
"name": "Strict PII Blocker",
"rule_type": "pii",
"description": "Block any tool call containing PII",
"rule_config": {
"patterns": ["email", "ssn", "credit_card"],
"action": "deny" # "flag" or "deny"
}
}
)
print(resp.json()) # { "policy": { "id": 7, "name": "Strict PII Blocker", ... } }
const resp = await fetch(`${AGENTSHIELD_URL}/api/v1/policies`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': API_KEY
},
body: JSON.stringify({
name: 'Strict PII Blocker',
rule_type: 'pii',
description: 'Block any tool call containing PII',
rule_config: {
patterns: ['email', 'ssn', 'credit_card'],
action: 'deny'
}
})
});
const data = await resp.json();
console.log(data.policy.id); // 7
curl -X POST https://ledgerpilot-9.polsia.app/api/v1/policies \
-H "Content-Type: application/json" \
-H "X-API-Key: as_demo_agentshield_2026" \
-d '{
"name": "Strict PII Blocker",
"rule_type": "pii",
"rule_config": {
"patterns": ["email", "ssn", "credit_card"],
"action": "deny"
}
}'
Policy Configuration
Three built-in policy types, each with its own rule_config shape.
Rate Limiter
Cap calls per agent per time window. Automatically resets. Per-agent tracking.
PII Detector
Regex-based detection of emails, SSNs, and credit cards in tool inputs.
Scope Enforcer
Allowlist or blocklist tools globally or per agent. Fine-grained control.
Rate Limiter — rule_type: "rate_limit"
{
"max_calls": 60, // max calls before deny (default: 60)
"window_seconds": 60 // rolling window in seconds (default: 60)
}
PII Detector — rule_type: "pii"
{
"patterns": ["email", "ssn", "credit_card"], // which patterns to detect
"action": "flag" // "flag" or "deny" (default: "flag")
}
Scope Enforcer — rule_type: "scope"
{
"mode": "allow_all", // "allow_all" | "whitelist" | "blacklist"
"blocked_tools": ["delete_database"], // globally blocked tools
"allowed_tools": [], // required if mode = "whitelist"
"agent_rules": {
"my-agent-prod": {
"blocked_tools": ["write_file"], // per-agent block
"allowed_tools": ["read_file", "query_db"] // per-agent allowlist (overrides global)
}
}
}
Policy changes take effect immediately. The policy cache refreshes every 30 seconds — new policies will be evaluated within 30 seconds of creation.
Response Format
Every /check response has the same shape regardless of outcome.
Full JSON schema
"decision": "allow" | "deny" | "flag",
// "allow" — proceed; "deny" — block; "flag" — log and optionally review
"reason": string,
// Human-readable explanation. Examples:
// "All policies passed"
// "Rate limit exceeded: 61/60 calls in 60s window"
// "PII detected in tool input: credit_card"
// "Tool 'delete_database' not in global allowlist"
"policy_id": number | null,
// ID of the policy that triggered this outcome.
// null when all policies pass (decision = "allow").
// Use GET /api/v1/policies to look up full policy details.
"latency_ms": number
// End-to-end processing time in milliseconds. Typically <50ms.
}
Decision handling pattern
result = check_tool(agent_id, tool_name, tool_input)
match result["decision"]:
case "allow":
execute_tool(tool_name, tool_input)
case "flag":
# Log for review but don't block (or block — your call)
send_to_review_queue({
"agent": agent_id,
"tool": tool_name,
"reason": result["reason"],
"policy_id": result["policy_id"]
})
execute_tool(tool_name, tool_input) # optional
case "deny":
raise ToolBlockedError(
f"AgentShield denied '{tool_name}': {result['reason']}"
)
Error responses
| Status | Error | Cause |
|---|---|---|
| 400 | agent_id and tool_name are required |
Missing required fields in request body |
| 401 | Missing X-API-Key header |
No API key provided |
| 401 | Invalid API key |
Key not found in database |
| 500 | Policy check failed |
Internal error — retry with exponential backoff |
Complete integration examples
Drop-in wrappers that add governance to any agent framework.
LangChain tool wrapper (Python)
import requests
from langchain.tools import BaseTool
from typing import Any
class GovernedTool(BaseTool):
"""Wraps any LangChain tool with AgentShield governance."""
name: str
description: str
inner_tool: BaseTool
agent_id: str
api_key: str = "as_demo_agentshield_2026"
shield_url: str = "https://ledgerpilot-9.polsia.app"
def _run(self, *args, **kwargs) -> Any:
# Check policy before execution
resp = requests.post(
f"{self.shield_url}/api/v1/check",
headers={"X-API-Key": self.api_key},
json={
"agent_id": self.agent_id,
"tool_name": self.name,
"tool_input": kwargs
}
)
result = resp.json()
if result["decision"] == "deny":
return f"[BLOCKED] {result['reason']}"
if result["decision"] == "flag":
print(f"[FLAGGED] {result['reason']}") # send to your alerting
return self.inner_tool._run(*args, **kwargs)
# Usage:
governed_email = GovernedTool(
name="send_email",
description="Send an email to a recipient",
inner_tool=original_email_tool,
agent_id="my-agent-prod"
)
Express middleware (Node.js)
// agentshield.js — drop-in middleware for your agent tool router
const SHIELD_URL = 'https://ledgerpilot-9.polsia.app';
const API_KEY = process.env.AGENTSHIELD_API_KEY || 'as_demo_agentshield_2026';
async function governTool(agentId, toolName, toolInput) {
try {
const resp = await fetch(`${SHIELD_URL}/api/v1/check`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-API-Key': API_KEY },
body: JSON.stringify({ agent_id: agentId, tool_name: toolName, tool_input: toolInput })
});
if (!resp.ok) {
console.warn('[AgentShield] Non-2xx response, failing open:', resp.status);
return { decision: 'allow', reason: 'Shield unavailable — fail open' };
}
return resp.json();
} catch (err) {
// Fail open on network error — never break your agent for governance
console.warn('[AgentShield] Network error, failing open:', err.message);
return { decision: 'allow', reason: 'Shield unreachable — fail open' };
}
}
// Express route: POST /agent/tool
router.post('/agent/tool', async (req, res) => {
const { agent_id, tool_name, tool_input } = req.body;
const decision = await governTool(agent_id, tool_name, tool_input);
if (decision.decision === 'deny') {
return res.status(403).json({ error: decision.reason, blocked: true });
}
// Execute the actual tool
const result = await executeTool(tool_name, tool_input);
res.json({ result, governance: decision });
});
Ready to govern your agents?
Join the waitlist and get your API key within 24 hours. Integration takes 5 minutes.
Join the waitlist →