Platform
Webhooks
Talki sends HTTPS POST requests to your endpoint when ticket events occur. Use webhooks to sync with your CRM, trigger Slack alerts, update analytics pipelines, or run any automation based on support activity.
Registering an endpoint
# In Admin → Webhooks → Add endpoint
# Enter your HTTPS URL and select which events to subscribe to.
# Talki will show you a signing secret — store it in your env vars.ⓘHTTPS required
Event types
| Event | When fired |
|---|---|
| ticket.created | Fired when a new ticket is created via any channel. |
| message.sent | Fired when a customer or agent sends a message in any ticket. |
Payload format
Every webhook delivery is a POST with a JSON body and these request headers:
| Name | Type | Description |
|---|---|---|
| X-Talki-Signature | string | HMAC-SHA256 signature of the raw body, prefixed with "sha256=". Use this to verify authenticity. |
| X-Talki-Event | string | The event type (e.g. "ticket.created"). |
| X-Talki-Delivery | string | A unique ID for this delivery attempt. Use for idempotency and deduplication. |
ticket.created example
POST /your-webhook-endpoint HTTP/1.1
Content-Type: application/json
X-Talki-Signature: sha256=a3f8c2d1...
X-Talki-Event: ticket.created
X-Talki-Delivery: del_abc123
{
"event": "ticket.created",
"createdAt": "2024-03-15T14:23:00Z",
"data": {
"ticket": {
"id": "tkt_abc123",
"orgId": "org_xyz",
"status": "open",
"channel": "widget",
"subject": "Can't log in to my account",
"createdAt": "2024-03-15T14:23:00Z",
"customer": {
"name": "Alice Johnson",
"email": "alice@example.com"
}
}
}
}message.sent example
{
"event": "message.sent",
"createdAt": "2024-03-15T14:58:00Z",
"data": {
"ticket": { "id": "tkt_abc123", "status": "open", ... },
"message": {
"id": "msg_002",
"role": "customer",
"text": "Hi, I still can't log in.",
"createdAt": "2024-03-15T14:58:00Z"
}
}
}Signature verification
Talki signs every webhook with HMAC-SHA256 using your endpoint's signing secret. The signature is in the X-Talki-Signature header, prefixed with sha256=. Always verify signatures before processing events.
Node.js / Express
const crypto = require('crypto');
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-talki-signature'];
const [, receivedHex] = signature.split('='); // "sha256=abc123..."
const expectedHex = crypto
.createHmac('sha256', process.env.TALKI_WEBHOOK_SECRET)
.update(req.body) // raw Buffer
.digest('hex');
const valid = crypto.timingSafeEqual(
Buffer.from(receivedHex),
Buffer.from(expectedHex),
);
if (!valid) return res.status(401).send('Invalid signature');
const event = JSON.parse(req.body);
console.log('Received event:', event.event);
// Handle events
if (event.event === 'ticket.created') {
// e.g. create CRM record, send Slack notification
}
res.status(200).send('ok');
});Python / Flask
import hmac, hashlib, os, json
from flask import Flask, request
app = Flask(__name__)
@app.route('/webhook', methods=['POST'])
def webhook():
signature = request.headers.get('X-Talki-Signature', '')
_, received_hex = signature.split('=')
expected_hex = hmac.new(
os.environ['TALKI_WEBHOOK_SECRET'].encode(),
request.get_data(),
hashlib.sha256,
).hexdigest()
if not hmac.compare_digest(received_hex, expected_hex):
return 'Invalid signature', 401
event = json.loads(request.get_data())
print('Event:', event['event'])
return 'ok', 200⚠Use the raw body
express.raw() middleware.Retry policy
Talki considers a delivery successful when your endpoint returns HTTP 2xx within 10 seconds. If the delivery fails (non-2xx, timeout, or connection error), Talki retries with exponential backoff:
| Attempt | Delay |
|---|---|
| 1st retry | 30 seconds after failure |
| 2nd retry | 5 minutes after 1st retry |
| 3rd retry | 30 minutes after 2nd retry |
| Final | Marked as failed — visible in Admin → Webhooks → Delivery log |
✦Idempotency
X-Talki-Delivery header as an idempotency key to deduplicate events in your database.