Webhooks
Receive real-time notifications when documents finish processing, chat sessions close, or reports generate.
Subscription
POST /api/v1/webhooks/subscribe
{
"url": "https://your-platform.com/webhooks/sentinel",
"events": ["document.completed", "document.failed", "chat.session.closed"],
"secret": "whsec_your_webhook_secret"
}
Response:
{
"webhook_id": "whk_123",
"url": "https://your-platform.com/webhooks/sentinel",
"events": ["document.completed", "document.failed", "chat.session.closed"],
"status": "active",
"created_at": "2026-05-15T10:00:00Z"
}
Event Types
document.completed
{
"event": "document.completed",
"timestamp": "2026-05-15T10:05:00Z",
"data": {
"document_id": "doc_abc123",
"tenant_id": "ten_xyz",
"user_id": "usr_456",
"document_type": "cas_statement",
"pages": 4,
"extractions": {
"holdings_count": 12,
"total_aum": 12500000,
"currency": "INR"
},
"confidence": {
"average": 0.94,
"minimum": 0.87
},
"processing_time_ms": 45000
}
}
document.failed
{
"event": "document.failed",
"timestamp": "2026-05-15T10:05:00Z",
"data": {
"document_id": "doc_abc123",
"error_code": "EXTRACTION_TIMEOUT",
"error_message": "Document exceeded maximum processing time",
"stage": "layout_extraction",
"retryable": true
}
}
chat.session.closed
{
"event": "chat.session.closed",
"timestamp": "2026-05-15T10:10:00Z",
"data": {
"session_id": "ses_def456",
"user_id": "usr_456",
"message_count": 24,
"token_usage": {
"input": 4500,
"output": 3200
},
"summary": "Portfolio review for Sharma family office"
}
}
report.generated
{
"event": "report.generated",
"timestamp": "2026-05-15T10:15:00Z",
"data": {
"report_id": "rpt_ghi789",
"report_type": "portfolio_review",
"client_id": "cli_123",
"url": "https://sentinel.centricitywealth.tech/reports/rpt_ghi789",
"format": "pdf",
"generated_by": "usr_456"
}
}
Signature Verification
Sentinel signs every webhook with HMAC-SHA256:
X-Sentinel-Signature: sha256=<hex_signature>
X-Sentinel-Timestamp: <unix_timestamp>
Python Verification
import hmac
import hashlib
def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(secret.encode(), payload, hashlib.sha256).hexdigest()
return hmac.compare_digest(f"sha256={expected}", signature)
TypeScript Verification
import { createHmac } from "crypto";
function verifyWebhook(payload: string, signature: string, secret: string): boolean {
const expected = createHmac("sha256", secret).update(payload).digest("hex");
return `sha256=${expected}` === signature;
}
Security: Reject webhooks with timestamps older than 5 minutes to prevent replay attacks.
Retry Logic
If your endpoint returns non-2xx:
| Attempt | Delay | Action |
|---|---|---|
| 1 | Immediate | Retry |
| 2 | 5 seconds | Retry |
| 3 | 30 seconds | Retry |
| 4 | 5 minutes | Retry |
| 5 | 30 minutes | Retry |
| 6+ | Exponential backoff up to 24h | Retry |
After 48 hours of failures, the webhook is auto-paused. Resume via API or contact support.
Testing Webhooks
Use the sandbox environment to test:
POST https://sentinel-dev.centricitywealth.tech/api/v1/webhooks/test
{
"webhook_id": "whk_123",
"event": "document.completed"
}
This sends a synthetic payload to your endpoint without processing a real document.