IntegrationsAgent Setup

Agent Setup Guide

Connect any AI agent or autonomous script to SilentAuth so sensitive actions require human approval before executing. No SDK required — just HTTP.

No SDK requiredAny language5 minute setup

Prerequisites

Before you start, you need:

  • A SilentAuth account (free)
  • A project created in the Projects dashboard
  • Your project's Secret Key (from Agent Setup → Your API Credentials)
  • Any HTTP client (requests, curl, fetch, httpx, etc.)
Your Secret Key is available in the dashboard under Account → Agent Setup → Your API Credentials. Keep it server-side — never expose it in client-side code.

Core Concepts

Intent

A record of what your agent wants to do. Contains the action name, source, risk tier, and parameters. Created before execution.

Policy

A rule that matches intents by action pattern, risk tier, or source type and auto-resolves them — either auto-approve or auto-deny.

Pending

An intent status meaning no policy matched and a human must review it. Appears in the Execution Gate dashboard.

Permit Token

A short-lived signed JWT issued when an intent is approved. Your agent polls for it, validates it, then proceeds.

Register an Agent

Before your agent starts sending intents, register it in the AI Agent Authorization dashboard. Registration links a human-readable name to a unique fingerprint, enables status enforcement, and starts tracking when the agent was last seen.

FieldDescription
NameHuman-readable label for this agent (e.g. Refund Agent v2)
FingerprintUnique string sent as the source field in every intent. Auto-generated or custom.
FrameworkPython, LangChain, OpenAI Assistants, AutoGen, CrewAI, or Other. Informational only.
Risk SensitivityDefault risk tier for the integration snippet. Can be overridden per request.
ProjectOptional. Scopes this agent to a specific project's API key.
Statusactive | paused | revoked. Controls whether intents from this agent are accepted.
Use Auto-generate to create a fingerprint from the agent name. Copy it into your agent code and set it as the source field on every intent.

Agent Status Enforcement

Once registered, the agent's status is enforced by the API on every intent submission. This gives you a kill switch that takes effect instantly — no code changes or redeployments required.

active

Normal operation. Intents are accepted, validated against policies, and processed.

paused

Intents return HTTP 403 with error code AGENT_PAUSED. Use for maintenance or investigation.

revoked

Intents return HTTP 403 with error code AGENT_REVOKED. Use for decommissioned or compromised agents.

403 response when agent is paused
{
  "data": null,
  "error": {
    "code":    "AGENT_PAUSED",
    "message": "Agent \"Refund Agent v2\" is paused. Resume the agent in the dashboard before submitting intents."
  }
}

When an intent is successfully submitted from a registered agent, last_seen_at is updated automatically — giving you a live activity signal per agent without any extra tracking code.

Unregistered fingerprints (no matching record in the dashboard) are still accepted and processed normally. Registration only adds enforcement on top of the existing flow.

Step 1 — Create an Intent

Before executing any sensitive action, your agent sends a POST /api/intents request. This is the single integration point — everything else happens asynchronously.

POST /api/intents
curl -X POST https://silentauth.ai/api/intents \
  -H "Authorization: Bearer sk_your_secret_key" \
  -H "Content-Type: application/json" \
  -d '{
    "action":      "issue_refund",
    "source_type": "ai_agent",
    "source":      "refund-agent-v1",
    "risk_tier":   "high",
    "parameters":  {
      "customer_id": "cust_4821",
      "amount": 50.00
    }
  }'

Request fields

FieldTypeRequiredDescription
actionstringYesName of the action your agent wants to perform
source_typestringYesai_agent | devops | automation
sourcestringNoAgent fingerprint. If it matches a registered agent, status is enforced and last_seen_at is updated.
risk_tierstringNolow | medium | high | critical (default: medium)
parametersobjectNoArbitrary key-value pairs — shown in the dashboard during review
project_iduuidNoOverride project association (auto-detected from API key)

Step 2 — Handle the Decision

The API responds immediately with a decision field. This tells your agent what happened right now — before any human has reviewed it.

Response (201 Created)
{
  "id":       "a3f2c1b0-4e52-4d1a-9b0f-12c34d56e789",
  "decision": "require_approval",
  "data": {
    "id":          "a3f2c1b0-...",
    "status":      "pending",
    "action":      "issue_refund",
    "risk_tier":   "high",
    "source":      "refund-agent-v1",
    "parameters":  { "customer_id": "cust_4821", "amount": 50.00 },
    "created_at":  "2026-03-16T12:00:00.000Z"
  }
}

Decision values

auto_approveAuto-approved by policy

A policy matched and auto-approved. The permit_token is immediately available in data.permit_token. Proceed.

auto_denyAuto-denied by policy

A policy matched and blocked this action. data.status is 'denied'. Abort and surface the error to your caller.

require_approvalAwaiting human review

No policy matched. data.status is 'pending'. Your agent must now poll or use webhooks to wait for a human decision.

Step 3 — Poll for Approval

When decision is require_approval, your agent blocks and polls until a human resolves the intent in the dashboard.

poll_until_resolved.py
import requests, time

def wait_for_approval(intent_id, secret_key, timeout_seconds=600):
    """Block until the intent is approved or denied."""
    headers = {"Authorization": f"Bearer {secret_key}"}
    base    = "https://silentauth.ai"
    deadline = time.time() + timeout_seconds

    while time.time() < deadline:
        time.sleep(5)

        # Check approved intents
        approved = requests.get(
            f"{base}/api/intents?status=approved",
            headers=headers,
        ).json()
        for intent in approved.get("data", []):
            if intent["id"] == intent_id:
                return intent["permit_token"]   # ✓ approved

        # Check denied intents
        denied = requests.get(
            f"{base}/api/intents?status=denied",
            headers=headers,
        ).json()
        for intent in denied.get("data", []):
            if intent["id"] == intent_id:
                raise PermissionError(f"Intent denied: {intent_id}")

    raise TimeoutError(f"Timed out after {timeout_seconds}s")
For production agents, prefer webhooks over polling. They respond instantly when a human approves, rather than on your next poll interval.

Step 4 — Use the Permit Token

Once you have a permit_token, pass it through to your backend action. The permit is a signed JWT — your backend can verify it without a network call. Permits expire after 5 minutes.

execute_with_permit.py
def issue_refund(customer_id: str, amount: float):
    # Step 1: Declare intent
    resp = requests.post(
        "https://silentauth.ai/api/intents",
        headers={"Authorization": f"Bearer {SECRET_KEY}"},
        json={
            "action":      "issue_refund",
            "source_type": "ai_agent",
            "risk_tier":   "high",
            "parameters":  {"customer_id": customer_id, "amount": amount},
        },
    )
    result = resp.json()

    if result["decision"] == "auto_deny":
        raise PermissionError("Blocked by policy")

    if result["decision"] == "auto_approve":
        permit = result["data"]["permit_token"]
    else:
        # Blocks here until a human approves (or timeout)
        permit = wait_for_approval(result["id"], SECRET_KEY)

    # Step 4: Execute — pass permit to your backend
    payment_service.refund(
        customer_id=customer_id,
        amount=amount,
        permit_token=permit,   # Backend verifies this
    )
The permit token is a standard JWT signed with HMAC-SHA256. Your backend can decode and verify it offline using the same secret you configured in EXECUTION_SECRET. It contains: intent_id, action, risk_tier, iat, and exp.

Using Webhooks Instead of Polling

Configure a webhook in Gate Webhooks and SilentAuth will POST to your endpoint the moment an intent is approved or denied. No polling loop required.

webhook_payload.json
{
  "event":        "intent.approved",
  "intent_id":    "a3f2c1b0-...",
  "project_id":   "proj_...",
  "action":       "issue_refund",
  "source":       "refund-agent-v1",
  "source_type":  "ai_agent",
  "risk_tier":    "high",
  "status":       "approved",
  "parameters":   { "customer_id": "cust_4821", "amount": 50.00 },
  "permit_token": "eyJhbGciOiJIUzI1NiJ9...",
  "approved_by":  "admin@example.com",
  "timestamp":    "2026-03-16T12:34:56.000Z"
}

Verifying webhook signatures

Every webhook request includes an X-SilentAuth-Signature header. Always verify it to reject forged requests.

verify_webhook.py
import hmac, hashlib
from flask import Flask, request, abort

app = Flask(__name__)
WEBHOOK_SECRET = "whsec_your_signing_secret"

@app.route("/webhooks/silentauth", methods=["POST"])
def handle_webhook():
    body      = request.get_data()
    sig       = request.headers.get("X-SilentAuth-Signature", "")
    expected  = "sha256=" + hmac.new(
        WEBHOOK_SECRET.encode(),
        body,
        hashlib.sha256
    ).hexdigest()

    if not hmac.compare_digest(expected, sig):
        abort(401)   # Invalid signature — reject

    payload = request.json
    if payload["event"] == "intent.approved":
        permit_token = payload["permit_token"]
        intent_id    = payload["intent_id"]
        # Resume the waiting agent thread here
        resolve_pending_intent(intent_id, permit_token)

    return "", 200
Your webhook endpoint must respond with HTTP 2xx within 10 seconds or SilentAuth will mark the delivery as failed and increment the failure counter. Offload slow work to a background queue.

Automating with Policies

Policies let you define rules that resolve intents instantly without human review. Set them up in Execution Policies.

Policy fieldValuesDescription
action_patternglob stringMatch action names. Supports * wildcard. E.g. read_* matches all reads.
source_typeany | ai_agent | devops | automationMatch by intent origin type.
risk_tierany | low | medium | high | criticalMatch by risk tier.
decisionauto_approve | auto_deny | require_approvalWhat to do when this policy matches.
priorityinteger (higher = evaluated first)Policies are checked in descending priority. First match wins.
A good default setup: create a high-priority auto_approve policy for risk_tier=low, and leave everything else to fall through to require_approval. You get speed for safe actions and control for risky ones.

Full Python Example

A self-contained integration you can copy and adapt. No external dependencies beyond requests.

silentauth_integration.py
import requests, time, os

SECRET_KEY = os.environ["SILENTAUTH_SECRET_KEY"]
BASE_URL   = "https://silentauth.ai"

def require_approval(action, risk_tier="medium", source="my-agent", parameters=None):
    """Declare an intent and block until a human approves or policy resolves it."""
    headers = {
        "Authorization": f"Bearer {SECRET_KEY}",
        "Content-Type":  "application/json",
    }
    resp = requests.post(
        f"{BASE_URL}/api/intents",
        headers=headers,
        json={
            "action":      action,
            "source_type": "ai_agent",
            "source":      source,
            "risk_tier":   risk_tier,
            "parameters":  parameters or {},
        },
    )
    resp.raise_for_status()
    result = resp.json()

    intent_id = result["id"]
    decision  = result.get("decision", "require_approval")

    if decision == "auto_approve":
        return result["data"]["permit_token"]

    if decision == "auto_deny":
        raise PermissionError(f"Intent {intent_id} was auto-denied by policy")

    # Poll until human resolves (timeout: 10 minutes)
    deadline = time.time() + 600
    while time.time() < deadline:
        time.sleep(5)

        approved = requests.get(
            f"{BASE_URL}/api/intents?status=approved",
            headers=headers,
        ).json()
        for intent in approved.get("data", []):
            if intent["id"] == intent_id:
                return intent["permit_token"]

        denied = requests.get(
            f"{BASE_URL}/api/intents?status=denied",
            headers=headers,
        ).json()
        for intent in denied.get("data", []):
            if intent["id"] == intent_id:
                raise PermissionError(f"Intent {intent_id} was denied")

    raise TimeoutError(f"Intent {intent_id} timed out after 10 minutes")


# --- Usage examples ---

def issue_refund(customer_id: str, amount: float):
    permit = require_approval(
        action="issue_refund",
        risk_tier="high",
        parameters={"customer_id": customer_id, "amount": amount},
    )
    print(f"Permit: {permit[:40]}…")
    # ← proceed with actual refund

def delete_account(user_id: str):
    permit = require_approval(
        action="delete_account",
        risk_tier="critical",
        parameters={"user_id": user_id},
    )
    print(f"Permit: {permit[:40]}…")
    # ← proceed with account deletion

def read_profile(user_id: str):
    # Low-risk — likely auto-approved by policy, no human needed
    permit = require_approval(
        action="read_profile",
        risk_tier="low",
        parameters={"user_id": user_id},
    )
    # ← proceed immediately

Risk Tier Reference

TierDefault behaviorUse for
lowCreates pending; auto-approve policy recommendedRead operations, status checks, notifications
mediumCreates pending; awaits human reviewProfile updates, config changes, non-financial writes
highCreates pending; typically requires reviewFinancial ops, email blasts, data exports
criticalCreates pending; requires typed confirmationDeletions, secret rotation, irreversible changes

Error Reference

HTTPCodeDescription
401UNAUTHORIZEDAPI key missing or invalid. Check your Authorization header.
400MISSING_FIELDSaction and source_type are required fields.
403AGENT_PAUSEDThe registered agent matching this fingerprint is paused. Resume it in the dashboard.
403AGENT_REVOKEDThe registered agent matching this fingerprint has been revoked and cannot submit intents.
404NOT_FOUNDIntent ID not found or does not belong to this project.
409ALREADY_RESOLVEDAttempted to approve/deny an intent that's already been resolved.
500DB_ERRORInternal error. Retry with exponential backoff.