Skip to main content

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

  1. Go to Events → Webhook
  2. Copy the Endpoint URL — this is the URL your system will POST to
  3. 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:

  1. Go to Events → Webhook
  2. Click Rotate Secret
  3. 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

FieldTypeRequiredNotes
actionstringYesupsert, cancel, or delete
eventobjectYesEvent data — see below

Event object

FieldTypeRequiredNotes
titlestringYesName of the event
starts_atstringYesISO 8601 datetime — include a timezone offset
ends_atstringNoISO 8601 datetime
descriptionstringNoShort summary
locationstringNoCity, address, or venue
urlstringNoRegistration or event page URL
pricestringNoe.g. Free, $25, ₹500
recurringstringNodaily, weekly, monthly, yearly, or empty
statusstringNoupcoming (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:

HeaderValue
X-Konvoq-TimestampCurrent Unix timestamp in seconds
X-Konvoq-Signaturesha256= + 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

CodeMeaning
200 OKEvent accepted and processed
400 Bad RequestMalformed JSON, missing required fields, or invalid timestamp
401 UnauthorizedInvalid or missing signature
403 ForbiddenWebhook source is inactive or plan limit reached
429 Too Many RequestsRate 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.