Files
sentryagent-idp/docs/developers/guides/configure-webhooks.md
SentryAgent.ai Developer 8cabc0191c docs: commit all Phase 6 documentation updates and OpenSpec archives
- devops docs: 8 files updated for Phase 6 state; field-trial.md added (946-line runbook)
- developer docs: api-reference (50+ endpoints), quick-start, 5 existing guides updated, 5 new guides added
- engineering docs: all 12 files updated (services, architecture, SDK guide, testing, overview)
- OpenSpec archives: phase-7-devops-field-trial, developer-docs-phase6-update, engineering-docs-phase6-update
- VALIDATOR.md + scripts/start-validator.sh: V&V Architect tooling added
- .gitignore: exclude session artifacts, build artifacts, and agent workspaces

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 02:24:24 +00:00

5.9 KiB

Configure Webhooks

Webhooks let AgentIdP push real-time events to your application when agents, credentials, or tokens change state. This guide covers creating subscriptions, the available event types, delivery guarantees, and how to inspect delivery history.


Prerequisites

  • A running AgentIdP instance
  • A valid Bearer token with organization_id in its claims
  • A publicly reachable HTTPS endpoint to receive events (for local development, use a tool like ngrok)

Available event types

Event type Triggered when
agent.created A new agent is registered
agent.updated An agent's metadata is updated
agent.suspended An agent's status changes to suspended
agent.reactivated An agent's status changes from suspended to active
agent.decommissioned An agent is decommissioned
credential.generated New credentials are created for an agent
credential.rotated A credential's secret is rotated
credential.revoked A credential is revoked
token.issued An access token is issued
token.revoked An access token is revoked

Create a subscription

POST /api/v1/webhooks

curl -s -X POST http://localhost:3000/api/v1/webhooks \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "prod-agent-events",
    "url": "https://my-app.example.com/hooks/sentryagent",
    "events": ["agent.created", "agent.decommissioned", "token.issued"]
  }' | jq .

Response (201 Created):

{
  "id": "wh-1a2b3c4d-e5f6-7890-abcd-ef1234567890",
  "organization_id": "org-0a1b2c3d-e4f5-6789-abcd-ef0123456789",
  "name": "prod-agent-events",
  "url": "https://my-app.example.com/hooks/sentryagent",
  "events": ["agent.created", "agent.decommissioned", "token.issued"],
  "active": true,
  "signingSecret": "whsec_a1b2c3d4e5f6789...",
  "failure_count": 0,
  "created_at": "2026-04-04T09:00:00.000Z",
  "updated_at": "2026-04-04T09:00:00.000Z"
}

Save the signingSecret now. It is shown once. Use it to verify the HMAC-SHA256 signature on incoming webhook requests. See "Verifying delivery signatures" below.

export WEBHOOK_ID="wh-1a2b3c4d-e5f6-7890-abcd-ef1234567890"
export SIGNING_SECRET="whsec_a1b2c3d4e5f6789..."

Webhook payload format

Every delivery sends a POST to your URL with Content-Type: application/json and this body:

{
  "id": "evt-uuid-here",
  "event": "agent.created",
  "timestamp": "2026-04-04T09:00:00.000Z",
  "organization_id": "org-0a1b2c3d-e4f5-6789-abcd-ef0123456789",
  "data": {
    "agentId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "email": "screener-001@talent.ai",
    "agentType": "screener"
  }
}

The data object contains event-specific fields. For agent.* events it includes agent metadata. For credential.* events it includes credentialId and agentId. For token.* events it includes agentId and scope.


Verifying delivery signatures

AgentIdP signs every delivery with HMAC-SHA256 using your signingSecret. The signature is in the X-SentryAgent-Signature header as sha256=<hex-digest>.

Verify it in Node.js:

const crypto = require('crypto');

function verifySignature(rawBody, signingSecret, signatureHeader) {
  const expected = 'sha256=' + crypto
    .createHmac('sha256', signingSecret)
    .update(rawBody)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signatureHeader)
  );
}

Always verify the signature before processing the event. Reject requests with invalid signatures with 401 Unauthorized.


Delivery guarantees and retry policy

  • AgentIdP delivers each event at least once — your endpoint may receive duplicates
  • Use the id field to deduplicate events
  • Delivery is attempted immediately; on failure, retries use exponential backoff
  • After repeated failures, the delivery moves to dead_letter status
  • Subscriptions with high failure_count may be automatically disabled

Delivery statuses: pendingdelivered (success) or failed (attempt failed) → dead_letter (all retries exhausted)


List subscriptions

curl -s "http://localhost:3000/api/v1/webhooks" \
  -H "Authorization: Bearer $TOKEN" | jq .

Pause or resume a subscription

To pause (disable) a subscription without deleting it:

curl -s -X PATCH "http://localhost:3000/api/v1/webhooks/$WEBHOOK_ID" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "active": false }' | jq .

To resume:

curl -s -X PATCH "http://localhost:3000/api/v1/webhooks/$WEBHOOK_ID" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "active": true }' | jq .

Inspect delivery history

GET /api/v1/webhooks/{id}/deliveries

curl -s "http://localhost:3000/api/v1/webhooks/$WEBHOOK_ID/deliveries?limit=20&offset=0" \
  -H "Authorization: Bearer $TOKEN" | jq .

Response:

{
  "deliveries": [
    {
      "id": "del-uuid",
      "subscription_id": "wh-uuid",
      "event_type": "agent.created",
      "payload": { ... },
      "status": "delivered",
      "http_status_code": 200,
      "attempt_count": 1,
      "next_retry_at": null,
      "delivered_at": "2026-04-04T09:00:01.000Z",
      "created_at": "2026-04-04T09:00:00.000Z",
      "updated_at": "2026-04-04T09:00:01.000Z"
    }
  ],
  "total": 47,
  "limit": 20,
  "offset": 0
}

Use offset to paginate through delivery history. Increase limit to retrieve more records per page (the server default is 20).


Delete a subscription

curl -s -X DELETE "http://localhost:3000/api/v1/webhooks/$WEBHOOK_ID" \
  -H "Authorization: Bearer $TOKEN" \
  -o /dev/null -w "%{http_code}\n"

Expected response: 204. This permanently deletes the subscription and all its delivery records.