Webhooks
Webhooks allow you to receive real-time notifications about call events via HTTP POST requests to your configured endpoint.
Webhooks allow you to receive real-time notifications about call events. Configure a webhook URL on your assistant to receive HTTP POST requests when events occur.
Webhook Events
| Event | When Triggered | Response Used |
|---|---|---|
assistant-request | Before call is answered | Yes - can configure assistant |
tool-calls | Assistant needs to execute a tool | Yes - return tool result |
status-update | Call status changes | No |
end-of-call-report | After call ends | No |
Configuring Webhooks
Set the webhook URL and events on your assistant:
curl -X PATCH https://api.hmsovereign.com/api/v1/assistants/ASSISTANT_ID
-H "Authorization: Bearer YOUR_API_KEY"
-H "Content-Type: application/json"
-d '{
"webhook_url": "https://api.example.com/webhooks/hms-sovereign",
"webhook_secret": "your-secret-for-verification",
"webhook_events": ["assistant-request", "tool-calls", "status-update", "end-of-call-report"]
}'Webhook Headers
All webhook requests include these headers:
| Header | Description |
|---|---|
Content-Type | application/json |
User-Assistant | HMS-Sovereign/1.0 |
X-Webhook-Event | Event type (e.g., tool-calls) |
X-Webhook-Timestamp | Unix timestamp of the request |
X-Webhook-Signature | HMAC-SHA256 signature (if secret configured) |
Signature Verification
If you configure a webhook_secret, verify the signature to ensure requests come from HMS Sovereign:
Python:
import hmac
import hashlib
def verify_signature(payload: str, secret: str, timestamp: str, signature: str) -> bool:
sig_hex = signature.removeprefix("sha256=")
message = f"{timestamp}.{payload}"
expected = hmac.new(
secret.encode(),
message.encode(),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(sig_hex, expected)
# In your webhook handler:
payload = request.body.decode()
timestamp = request.headers.get("X-Webhook-Timestamp")
signature = request.headers.get("X-Webhook-Signature")
if not verify_signature(payload, "your-secret", timestamp, signature):
return Response("Invalid signature", status=401)Node.js:
const crypto = require('crypto');
function verifySignature(payload, secret, timestamp, signature) {
const sigHex = signature.replace(/^sha256=/, '');
const message = `${timestamp}.${payload}`;
const expected = crypto
.createHmac('sha256', secret)
.update(message)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(sigHex),
Buffer.from(expected)
);
}Event Details
Assistant Request
Called before an inbound call is answered. Allows you to:
- Customize the assistant configuration per call
- Personalize the greeting based on caller
- Reject calls (e.g., outside business hours)
Timeout: 5 seconds. If your endpoint doesn't respond in time, the call proceeds with default configuration.
Response format:
{
"assistant_id": "uuid", // Reference mode: use saved assistant
"assistant": { ... }, // Transient mode: full assistant config
"assistant_override": { ... } // Hybrid mode: merge with assistant_id
}See Dynamic Assistant Configuration Webhook for payload details.
Tool Calls
Called when the assistant needs to execute a custom tool during the conversation.
Timeout: 10 seconds for synchronous tools.
Response formats supported:
- Object format:
{"results": [{"tool_call_id": "...", "result": {...}}]} - Simple format:
{"result": {...}} - Direct format:
{...}(your data directly) - Error format:
{"error": "message"}
See Tool/Function Call Webhook for payload details.
Status Update
Called when the call status changes:
in-progress- Call connectedended- Call ended normallyended-with-error- Call ended due to error
Response is ignored.
See Call Status Update Webhook for payload details.
End of Call Report
Called after the call ends with:
- Call duration
- AI-generated summary
- Structured analysis (if
analysis_planconfigured)
Response is ignored.
See End of Call Report Webhook for payload details.
Common Payload Fields
All webhooks include this structure:
{
"message": {
"type": "status-update",
"timestamp": "2025-12-13T12:00:00.000Z",
"call": {
"id": "5c4d030f-43e3-4e65-899e-8148521e660f",
"type": "inbound_phone_call",
"status": "in-progress"
},
"phone_number": {
"number": "+31850835037",
"name": "HMS Sovereign Demo"
},
"customer": {
"number": "+31612345678"
},
"assistant": {
"id": "assistant-uuid",
"name": "Customer Support Assistant",
"llm_config": { ... },
"tts_config": { ... },
"stt_config": { ... }
}
}
}Best Practices
- Respond quickly - Return 200 OK as fast as possible, especially for status updates
- Process asynchronously - Queue heavy processing for later
- Verify signatures - Always verify webhook signatures in production
- Handle retries - Implement idempotency for duplicate deliveries
- Log everything - Keep webhook logs for debugging
Related
- Custom Tools Guide - Building tools for your assistant
- Call Analysis Guide - Structured post-call data
- Webhook Security - Securing your webhooks