Events Webhook
The Events Webhook lets your external systems push events directly into Konvoq in real time. Use it when you manage events in a booking platform, CRM, or custom backend and want Konvoq's AI to stay in sync without a CSV import or iCal feed.
Find your webhook endpoint at Dashboard → Knowledge → Events → Webhook.
Getting your webhook URL and secret
- Go to Events → Webhook
- Copy the Endpoint URL — this is the URL your system will POST to
- Copy the Signing Secret — used to sign and verify requests
The endpoint URL looks like:
https://app.konvoq.com/api/v1/events/webhook/<your-source-id>
Rotating the signing secret
If your secret is compromised:
- Go to Events → Webhook
- Click Rotate Secret
- Confirm the rotation in the dialog
Important: The old secret stops working immediately. Update your external system with the new secret before rotating.
Sending events
Send an HTTP POST request to your endpoint URL with a JSON body. The request must be signed — see Signing requests.
Create or update an event
POST https://app.konvoq.com/api/v1/events/webhook/<source-id>
Content-Type: application/json
X-Konvoq-Timestamp: 1717200000
X-Konvoq-Signature: sha256=<hmac-hex>
{
"action": "upsert",
"event": {
"title": "Summer Workshop",
"starts_at": "2026-06-20T10:00:00+05:30",
"ends_at": "2026-06-20T12:00:00+05:30",
"description": "Hands-on creative workshop for beginners.",
"location": "Mumbai",
"url": "https://example.com/events/summer-workshop",
"price": "₹500",
"recurring": ""
}
}
Cancel an event
POST https://app.konvoq.com/api/v1/events/webhook/<source-id>
Content-Type: application/json
X-Konvoq-Timestamp: 1717200000
X-Konvoq-Signature: sha256=<hmac-hex>
{
"action": "cancel",
"event": {
"title": "Summer Workshop",
"starts_at": "2026-06-20T10:00:00+05:30",
"location": "Mumbai"
}
}
Delete an event
POST https://app.konvoq.com/api/v1/events/webhook/<source-id>
Content-Type: application/json
X-Konvoq-Timestamp: 1717200000
X-Konvoq-Signature: sha256=<hmac-hex>
{
"action": "delete",
"event": {
"title": "Summer Workshop",
"starts_at": "2026-06-20T10:00:00+05:30",
"location": "Mumbai"
}
}
Request fields
Top-level
| Field | Type | Required | Notes |
|---|---|---|---|
action | string | Yes | upsert, cancel, or delete |
event | object | Yes | Event data — see below |
Event object
| Field | Type | Required | Notes |
|---|---|---|---|
title | string | Yes | Name of the event |
starts_at | string | Yes | ISO 8601 datetime — include a timezone offset |
ends_at | string | No | ISO 8601 datetime |
description | string | No | Short summary |
location | string | No | City, address, or venue |
url | string | No | Registration or event page URL |
price | string | No | e.g. Free, $25, ₹500 |
recurring | string | No | daily, weekly, monthly, yearly, or empty |
status | string | No | upcoming (default) or cancelled |
:::tip Always include timezone in starts_at
Use 2026-06-20T10:00:00+05:30 not 2026-06-20T10:00:00. A bare time with no offset is interpreted as UTC, which may shift the event to the wrong date for your visitors.
:::
Signing requests
Every request must include two headers:
| Header | Value |
|---|---|
X-Konvoq-Timestamp | Current Unix timestamp in seconds |
X-Konvoq-Signature | sha256= + HMAC-SHA256 hex of <timestamp>.<raw-body> |
Konvoq rejects requests where the timestamp is more than 5 minutes old — this prevents replay attacks.
Signing — Node.js
const crypto = require('crypto');
function signRequest(body, secret) {
const timestamp = Math.floor(Date.now() / 1000).toString();
const payload = timestamp + '.' + body;
const signature = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return { timestamp, signature };
}
// Usage
const body = JSON.stringify({ action: 'upsert', event: { ... } });
const { timestamp, signature } = signRequest(body, 'your-signing-secret');
fetch(endpointUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Konvoq-Timestamp': timestamp,
'X-Konvoq-Signature': signature,
},
body,
});
Signing — Python
import hmac, hashlib, time, json, requests
def sign_request(body: str, secret: str):
timestamp = str(int(time.time()))
payload = f"{timestamp}.{body}"
signature = 'sha256=' + hmac.new(
secret.encode(), payload.encode(), hashlib.sha256
).hexdigest()
return timestamp, signature
body = json.dumps({"action": "upsert", "event": { ... }})
timestamp, signature = sign_request(body, "your-signing-secret")
requests.post(
endpoint_url,
data=body,
headers={
"Content-Type": "application/json",
"X-Konvoq-Timestamp": timestamp,
"X-Konvoq-Signature": signature,
}
)
Signing — PHP
$body = json_encode(['action' => 'upsert', 'event' => [...]]);
$timestamp = (string) time();
$payload = $timestamp . '.' . $body;
$signature = 'sha256=' . hash_hmac('sha256', $payload, $secret);
$ch = curl_init($endpointUrl);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'X-Konvoq-Timestamp: ' . $timestamp,
'X-Konvoq-Signature: ' . $signature,
]);
curl_exec($ch);
Response codes
| Code | Meaning |
|---|---|
200 OK | Event accepted and processed |
400 Bad Request | Malformed JSON, missing required fields, or invalid timestamp |
401 Unauthorized | Invalid or missing signature |
403 Forbidden | Webhook source is inactive or plan limit reached |
429 Too Many Requests | Rate limit hit — slow down and retry |
Delivery log
Every request sent to your webhook endpoint is logged. View recent deliveries at Events → Webhook → Recent Deliveries.
Each entry shows:
- Delivery timestamp
- Action (
upsert,cancel,delete) - HTTP status returned by Konvoq
- Event title processed
Logs are retained for 30 days.
Rate limits
The webhook endpoint is rate-limited to prevent abuse. If you exceed the limit, you receive 429 Too Many Requests. Implement exponential backoff and retry.
For bulk initial imports, use the CSV import instead, which has no rate limit.
Testing the webhook
Use curl to send a quick test:
TIMESTAMP=$(date +%s)
BODY='{"action":"upsert","event":{"title":"Test Event","starts_at":"2026-06-20T10:00:00+05:30","location":"Mumbai"}}'
PAYLOAD="${TIMESTAMP}.${BODY}"
SIG="sha256=$(echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "your-secret" | awk '{print $2}')"
curl -s -X POST "https://app.konvoq.com/api/v1/events/webhook/<source-id>" \
-H "Content-Type: application/json" \
-H "X-Konvoq-Timestamp: $TIMESTAMP" \
-H "X-Konvoq-Signature: $SIG" \
-d "$BODY"
Expected response: {"ok":true} or {"status":"ok"}.
After sending, open Events → All Events and confirm the test event appears.