Skip to content
Last updated

Webhook Events Integration

Instrument any AI agent with Capsule Security's detection pipeline using a generic HTTP webhook interface for real-time prevention and observability.

Overview

The Webhook Events integration is a platform-agnostic HTTP API that lets you connect any AI agent — custom-built agents, orchestration frameworks, internal tools — to Capsule Security. Unlike IDE-specific integrations (Claude Code, Cursor, GitHub Copilot), this integration requires you to add HTTP calls directly in your agent code.

Two modes of operation are supported:

  • Prevention (synchronous) — your agent sends an event before executing an action and waits for an allow/block decision
  • Telemetry (asynchronous) — your agent fires an event after an action completes for observability, without blocking execution
Your Agent → HTTP POST → Capsule → Detection Pipeline → Allow/Block Response

Use this integration when:

  • You are building a custom AI agent or orchestration pipeline
  • Your platform does not have a native Capsule integration
  • You need programmatic control over when and how events are sent

Event Types

Blocking Events

Synchronous — your agent waits for an allow/block response before proceeding.

EventDescription
tool_invocationBefore a tool or action executes
user_messageBefore a user prompt is processed

Observational Events

Fire-and-forget — Capsule responds with 202 Accepted.

EventDescription
tool_resultAfter tool execution completes
agent_messageAgent response text
session_startSession begins
session_endSession terminates

Prerequisites

Before you begin, ensure you have:

  • A Capsule Security account with admin access
  • An AI agent or application you want to instrument

Step 1: Generate API Credentials

  1. Log in to the Capsule Security portal

  2. Navigate to Integrations and locate Webhook Events

  3. Click Install — Capsule generates a JWT token scoped to your tenant

  4. Copy the token and store it securely (it will not be shown again)


Step 2: Instrument Your Agent

Add HTTP calls to your agent code at the appropriate lifecycle points. Refer to the API Reference and Integration Examples sections below.


API Reference

Endpoint

POST https://{capsule-host}/v1/generic-webhook/hooks/events

Headers

HeaderRequiredDescription
AuthorizationYesBearer <jwt-token>
x-correlation-idNoTrace ID for request correlation

Request Body

All events share a common envelope with event-specific fields.

tool_invocation

Sent before a tool executes. Blocks until Capsule responds.

{
  "event_type": "tool_invocation",
  "session_id": "sess-abc123",
  "timestamp": "2026-03-03T10:30:00Z",
  "agent": {
    "id": "support-agent",
    "name": "Customer Support Agent"
  },
  "user": {
    "email": "user@example.com"
  },
  "tool": {
    "name": "database_query",
    "input": { "query": "SELECT * FROM users" }
  }
}

user_message

Sent before a user prompt is processed. Blocks until Capsule responds.

{
  "event_type": "user_message",
  "session_id": "sess-abc123",
  "timestamp": "2026-03-03T10:30:00Z",
  "agent": {
    "id": "support-agent",
    "name": "Customer Support Agent"
  },
  "user": {
    "email": "user@example.com"
  },
  "message": {
    "content": "Show me all customer records from the last month"
  }
}

tool_result

Sent after tool execution completes. Fire-and-forget.

{
  "event_type": "tool_result",
  "session_id": "sess-abc123",
  "timestamp": "2026-03-03T10:30:05Z",
  "agent": {
    "id": "support-agent",
    "name": "Customer Support Agent"
  },
  "user": {
    "email": "user@example.com"
  },
  "tool": {
    "name": "database_query",
    "input": { "query": "SELECT * FROM users" },
    "output": { "row_count": 42 }
  }
}

agent_message

Sent after the agent produces a response. Fire-and-forget.

{
  "event_type": "agent_message",
  "session_id": "sess-abc123",
  "timestamp": "2026-03-03T10:30:06Z",
  "agent": {
    "id": "support-agent",
    "name": "Customer Support Agent"
  },
  "user": {
    "email": "user@example.com"
  },
  "message": {
    "content": "Here are the 42 customer records from the last month..."
  }
}

session_start

Sent when a session begins. Fire-and-forget.

{
  "event_type": "session_start",
  "session_id": "sess-abc123",
  "timestamp": "2026-03-03T10:29:55Z",
  "agent": {
    "id": "support-agent",
    "name": "Customer Support Agent"
  },
  "user": {
    "email": "user@example.com"
  }
}

session_end

Sent when a session terminates. Fire-and-forget.

{
  "event_type": "session_end",
  "session_id": "sess-abc123",
  "timestamp": "2026-03-03T10:45:00Z",
  "agent": {
    "id": "support-agent",
    "name": "Customer Support Agent"
  },
  "user": {
    "email": "user@example.com"
  }
}

Responses

Blocking Events (tool_invocation, user_message)

Allowed:

{
  "apiVersion": "1",
  "response": {
    "action": "allow"
  }
}

Blocked:

{
  "apiVersion": "1",
  "response": {
    "action": "block",
    "reason": "Policy violation: query accesses sensitive table"
  }
}

Observational Events

202 Accepted with an empty body.

Error Codes

CodeMeaningRecommended Action
400Malformed request bodyFix the payload and retry
401Invalid or expired JWTRegenerate credentials in the Capsule portal
408Request timeoutTreat as allow (fail-open)
500Server errorTreat as allow (fail-open)

Integration Examples

Pre-Execution Guard

Call tool_invocation before executing a tool. If the response contains "action": "block", deny the action.

curl -X POST "$CAPSULE_URL" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "event_type": "tool_invocation",
    "session_id": "sess-abc123",
    "timestamp": "2026-03-03T10:30:00Z",
    "agent": {"id": "my-agent", "name": "My Agent"},
    "user": {"email": "user@example.com"},
    "tool": {"name": "database_query", "input": {"query": "SELECT * FROM users"}}
  }'

Allowed response:

{
  "apiVersion": "1",
  "response": {
    "action": "allow"
  }
}

Blocked response:

{
  "apiVersion": "1",
  "response": {
    "action": "block",
    "reason": "Policy violation: query accesses sensitive table"
  }
}

Telemetry Reporter

Fire-and-forget tool_result after execution. Capsule responds with 202 Accepted.

curl -X POST "$CAPSULE_URL" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "event_type": "tool_result",
    "session_id": "sess-abc123",
    "timestamp": "2026-03-03T10:30:05Z",
    "agent": {"id": "my-agent", "name": "My Agent"},
    "user": {"email": "user@example.com"},
    "tool": {"name": "database_query", "input": {"query": "SELECT * FROM users"}, "output": {"row_count": 42}}
  }'

Full Session Lifecycle

A complete sequence showing all event types.

CAPSULE_URL="https://{capsule-host}/v1/generic-webhook/hooks/events"
TOKEN="your-jwt-token"
SESSION_ID="sess-$(uuidgen)"

# 1. Session start
curl -X POST "$CAPSULE_URL" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "event_type": "session_start",
    "session_id": "'"$SESSION_ID"'",
    "timestamp": "'"$(date -u +%Y-%m-%dT%H:%M:%SZ)"'",
    "agent": {"id": "my-agent", "name": "My Agent"},
    "user": {"email": "user@example.com"}
  }'

# 2. User message (blocking)
curl -X POST "$CAPSULE_URL" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "event_type": "user_message",
    "session_id": "'"$SESSION_ID"'",
    "timestamp": "'"$(date -u +%Y-%m-%dT%H:%M:%SZ)"'",
    "agent": {"id": "my-agent", "name": "My Agent"},
    "user": {"email": "user@example.com"},
    "message": {"content": "Look up order #12345"}
  }'

# 3. Tool invocation (blocking)
curl -X POST "$CAPSULE_URL" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "event_type": "tool_invocation",
    "session_id": "'"$SESSION_ID"'",
    "timestamp": "'"$(date -u +%Y-%m-%dT%H:%M:%SZ)"'",
    "agent": {"id": "my-agent", "name": "My Agent"},
    "user": {"email": "user@example.com"},
    "tool": {"name": "order_lookup", "input": {"order_id": "12345"}}
  }'

# 4. Tool result (fire-and-forget)
curl -X POST "$CAPSULE_URL" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "event_type": "tool_result",
    "session_id": "'"$SESSION_ID"'",
    "timestamp": "'"$(date -u +%Y-%m-%dT%H:%M:%SZ)"'",
    "agent": {"id": "my-agent", "name": "My Agent"},
    "user": {"email": "user@example.com"},
    "tool": {"name": "order_lookup", "input": {"order_id": "12345"}, "output": {"status": "shipped", "tracking": "1Z999AA10123456784"}}
  }'

# 5. Agent message (fire-and-forget)
curl -X POST "$CAPSULE_URL" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "event_type": "agent_message",
    "session_id": "'"$SESSION_ID"'",
    "timestamp": "'"$(date -u +%Y-%m-%dT%H:%M:%SZ)"'",
    "agent": {"id": "my-agent", "name": "My Agent"},
    "user": {"email": "user@example.com"},
    "message": {"content": "Order #12345 has been shipped. Tracking number: 1Z999AA10123456784"}
  }'

# 6. Session end (fire-and-forget)
curl -X POST "$CAPSULE_URL" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "event_type": "session_end",
    "session_id": "'"$SESSION_ID"'",
    "timestamp": "'"$(date -u +%Y-%m-%dT%H:%M:%SZ)"'",
    "agent": {"id": "my-agent", "name": "My Agent"},
    "user": {"email": "user@example.com"}
  }'

Timeout and Reliability

SettingBlocking EventsTelemetry Events
Server timeout10s10s
Recommended client timeout10s5s

Always fail-open: if Capsule is unreachable or returns a server error, allow the action to proceed. Telemetry failures must never block agent operation.


Verify the Integration

  1. Send a session_start event followed by a tool_invocation event using the examples above

  2. Log in to the Capsule Security portal

  3. Navigate to Inventory > Agents and confirm your agent appears

  4. Click on the agent and review the audit logs to verify events are captured

  5. To view the full conversation, navigate to Observability and filter by Activity Type — Session


Troubleshooting

SymptomCauseResolution
401 UnauthorizedInvalid or expired JWTRegenerate credentials in Integrations → Webhook Events
Events not appearing in portalIncorrect endpoint URL or malformed payloadVerify the URL and validate your JSON against the examples above
Blocking events always returning allowNo active policies configuredConfigure detection policies in the Capsule portal
High latency on blocking eventsNetwork distance to Capsule instanceEnsure your agent is in the same region as your Capsule deployment
408 Request TimeoutCapsule processing exceeded timeoutYour agent should treat this as allow (fail-open)

Security Considerations

  • Store JWT tokens in a secrets manager or environment variables — never hardcode them in source code
  • Use HTTPS exclusively — all Capsule endpoints require TLS
  • Rotate tokens periodically via the Capsule portal
  • Always fail-open — never let a dropped link to Capsule block your agent's operation

Support

For help with this integration, contact support.


References

  • JWT.io — debug and inspect JWT tokens