Webhooks
Webhooks let Konvoq push data to you the moment something happens — a new lead, a new conversation, a handoff request. Instead of polling "did anything happen?", Konvoq notifies you automatically.
Set up webhooks at Dashboard → Connect → Webhooks.
Setting up a webhook
- Go to Connect → Webhooks
- Click Add Webhook
- Enter a name and your endpoint URL — must be
https:// - Select the events you want to subscribe to (or leave empty to receive all)
- Click Save — Konvoq immediately sends a test request to verify your endpoint responds
Available events
| Event | When it fires |
|---|---|
lead.created | Visitor submits the lead capture form |
lead.updated | Lead data is edited |
lead.stage_changed | Lead moves to a new CRM pipeline stage |
lead.deleted | Lead is deleted |
conversation.started | Visitor opens the chatbot |
conversation.ended | Conversation is closed |
conversation.handed_off | Conversation transferred to a human agent |
message.received | A new message arrives in a conversation |
handoff.created | Visitor requests a human agent |
handoff.assigned | Agent picks up a handoff |
handoff.resolved | Agent closes a handoff |
knowledge.synced | A knowledge base re-index completes |
Payload format
Every webhook request is an HTTP POST with a JSON body:
{
"id": "evt_abc123",
"type": "lead.created",
"occurredAt": "2025-04-23T10:00:00Z",
"payload": {
"id": "lead_xyz",
"name": "Jane Doe",
"email": "jane@example.com",
"pipeline_stage": "new",
"created_at": "2025-04-23T10:00:00Z"
}
}
The payload shape varies by event type. Use type to route to the right handler.
Request headers
Every webhook request includes these headers:
| Header | Description |
|---|---|
X-Konvoq-Event-Id | Unique ID of this event delivery |
X-Konvoq-Event-Type | Event type string (e.g. lead.created) |
X-Konvoq-Timestamp | Unix timestamp of delivery (seconds) |
X-Konvoq-Signature | HMAC-SHA256 signature — sha256=<hex> |
Verifying requests are from Konvoq
Every request includes an X-Konvoq-Signature header — an HMAC-SHA256 signature computed from timestamp + "." + body using your webhook's signing secret.
Always verify this signature before processing the payload.
// Node.js
const crypto = require('crypto');
function verifySignature(rawBody, headers, secret) {
const timestamp = headers['x-konvoq-timestamp'];
const signature = headers['x-konvoq-signature'];
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(timestamp + '.' + rawBody)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
# Python
import hmac, hashlib
def verify_signature(raw_body: bytes, headers: dict, secret: str) -> bool:
timestamp = headers.get('x-konvoq-timestamp', '')
signature = headers.get('x-konvoq-signature', '')
message = f"{timestamp}.{raw_body.decode('utf-8')}"
expected = 'sha256=' + hmac.new(
secret.encode(), message.encode(), hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)
:::tip Use the raw body Compute the signature over the raw request body bytes, before any JSON parsing. Parsing and re-serializing can change whitespace and break the signature check. :::
The signing secret is shown when you create or view a webhook in the dashboard.
Retries
If your endpoint returns a non-2xx response (or times out), Konvoq retries with exponential backoff:
| Attempt | Delay |
|---|---|
| 1 | 5 seconds |
| 2 | 10 seconds |
| 3 | 20 seconds |
| 4 | 40 seconds |
| 5 | 80 seconds |
| 6 | 160 seconds |
| 7 | 320 seconds |
| 8 (final) | — marked dead |
Maximum 8 attempts total. After 8 failures, the event is marked dead and no further retries occur.
You can manually retry dead events from Connect → Webhooks → [webhook name] → View Events.
:::tip Respond fast, process later
Return 200 OK immediately, then process the payload asynchronously. If your handler takes more than ~30 seconds, Konvoq treats it as a failure and retries.
:::
Delivery log
Every delivery attempt is logged. View them at Connect → Webhooks → [webhook name] → View Events.
Each log entry shows:
- Event type and ID
- Delivery status (
delivered,retrying,dead) - HTTP response status from your endpoint
- Error message (if failed)
- Timestamp of each attempt
Testing your webhook
Click Test on any webhook to send a sample lead.created payload immediately — useful for verifying your endpoint and signature logic before going live.
Disabling a webhook
Toggle a webhook inactive from the webhook list. Events still fire internally but are not delivered until you re-enable it. All queued events are discarded when a webhook is disabled.