DEVELOPER DOCS

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.

1

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.

2

Add one call before tool execution

Before your agent runs any tool, send a check request:

curl
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" }
  }'
3

Handle the response

Check the decision field — proceed on allow, halt on deny, log on flag.

✓ allow — proceed normally
✕ deny — block execution
⚠ flag — log and optionally review
json
{
  "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.

http header
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.

POST /api/v1/check Requires authentication

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

"decision": "allow" | "deny" | "flag"
"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

python
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(...)
javascript
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(...);
bash
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.

GET /api/v1/audit Requires authentication

Query parameters

ParamTypeDescription
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

python
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 }
javascript
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 }
bash
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.

GET /api/v1/policies Requires authentication

No parameters. Returns all policies in evaluation order.

python
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']}")
javascript
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}`);
});
bash
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.

POST /api/v1/policies Requires authentication

Request body

FieldTypeRequiredDescription
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

python
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", ... } }
javascript
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
bash
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"

json — rule_config
{
  "max_calls": 60,          // max calls before deny (default: 60)
  "window_seconds": 60      // rolling window in seconds (default: 60)
}

PII Detector — rule_type: "pii"

json — rule_config
{
  "patterns": ["email", "ssn", "credit_card"],  // which patterns to detect
  "action": "flag"                               // "flag" or "deny" (default: "flag")
}

Scope Enforcer — rule_type: "scope"

json — rule_config
{
  "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

python
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

StatusErrorCause
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)

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)

javascript
// 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 →