Webhooks
Webhooks let you receive real-time HTTP notifications when events happen in Tiqora. Instead of polling the API for changes, Tiqora pushes events to your server as they occur.
How Webhooks Work
- You register a webhook endpoint URL in Tiqora
- You select which events you want to receive
- When an event occurs, Tiqora sends a POST request to your URL with the event payload
- Your server responds with a 2xx status code to acknowledge receipt
- If delivery fails, Tiqora retries with exponential backoff
Available Events
| Event | Trigger |
|---|---|
ticket.created |
A new ticket is created |
ticket.assigned |
A ticket is assigned to an agent |
ticket.status_changed |
A ticket's status changes |
ticket.replied |
A new reply is added to a ticket |
ticket.resolved |
A ticket is marked as resolved |
ticket.sla_breached |
An SLA policy is breached |
ticket.escalated |
A ticket is escalated |
Webhook Payload Format
All webhook payloads follow this structure:
{
"event": "ticket.created",
"timestamp": "2025-01-15T10:00:00Z",
"data": {
"id": "01912345-6789-7abc-def0-123456789abc",
"ticket_number": "1043",
"subject": "Payment not processing",
"status": "new",
"priority": "high",
"customer": {
"id": "01912345-0000-7abc-def0-123456789abc",
"email": "jane@example.com",
"name": "Jane Smith"
}
}
}
Event-Specific Payloads
ticket.status_changed:
{
"event": "ticket.status_changed",
"timestamp": "2025-01-15T10:30:00Z",
"data": {
"id": "01912345-6789-7abc-def0-123456789abc",
"ticket_number": "1043",
"subject": "Payment not processing",
"status": "in_progress",
"previous_status": "open",
"changed_by": {
"id": "01912345-3333-7abc-def0-123456789abc",
"name": "Alex Johnson",
"type": "agent"
}
}
}
ticket.replied:
{
"event": "ticket.replied",
"timestamp": "2025-01-15T10:15:00Z",
"data": {
"ticket_id": "01912345-6789-7abc-def0-123456789abc",
"ticket_number": "1043",
"reply": {
"id": "01912345-aaaa-7abc-def0-123456789abc",
"body": "Hi Jane, I can see the issue...",
"author_type": "agent",
"is_internal_note": false
}
}
}
ticket.sla_breached:
{
"event": "ticket.sla_breached",
"timestamp": "2025-01-15T11:00:00Z",
"data": {
"ticket_id": "01912345-6789-7abc-def0-123456789abc",
"ticket_number": "1043",
"breach_type": "first_response",
"sla_policy": "Critical Priority SLA",
"due_at": "2025-01-15T09:45:00Z",
"breached_at": "2025-01-15T11:00:00Z"
}
}
Verifying Webhook Signatures
Every webhook request includes a signature header so you can verify it came from Tiqora:
X-Webhook-Signature: sha256=abc123...
The signature is computed as HMAC-SHA256(webhook_secret, request_body).
Verification Example (Node.js)
const crypto = require('crypto');
function verifyWebhookSignature(body, signature, secret) {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(body, 'utf8')
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// In your webhook handler
app.post('/webhooks/tiqora', (req, res) => {
const signature = req.headers['x-webhook-signature'];
const body = req.rawBody; // Raw request body string
if (!verifyWebhookSignature(body, signature, WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
const event = req.body;
console.log('Received event:', event.event);
// Process the event...
res.status(200).send('OK');
});
Verification Example (Python)
import hashlib
import hmac
def verify_webhook(body: bytes, signature: str, secret: str) -> bool:
expected = 'sha256=' + hmac.new(
secret.encode(),
body,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)
Verification Example (PHP)
function verifyWebhook(string $body, string $signature, string $secret): bool
{
$expected = 'sha256=' . hash_hmac('sha256', $body, $secret);
return hash_equals($expected, $signature);
}
Important: Always verify webhook signatures in production. Without verification, anyone could send fake events to your endpoint.
Retry Policy
If your server doesn't respond with a 2xx status code, Tiqora retries delivery with exponential backoff:
| Attempt | Delay |
|---|---|
| 1st retry | 1 minute |
| 2nd retry | 5 minutes |
| 3rd retry | 30 minutes |
| 4th retry | 2 hours |
| 5th retry | 12 hours |
After 5 failed attempts, the webhook endpoint is automatically disabled. You can re-enable it from the dashboard and retry failed deliveries.
Managing Webhooks
Webhook endpoints are managed through the Tiqora dashboard under Settings → Webhooks. You can:
- Create new webhook endpoints
- Select which events to subscribe to
- View delivery logs with payloads and response codes
- Retry failed deliveries
- Disable/enable endpoints
- Send test events to verify your endpoint
Best Practices
Respond quickly — Return a
200response immediately before processing the event. Use a queue to handle the actual work asynchronously.Handle duplicate events — In rare cases, events may be delivered more than once. Use the event's
data.idto deduplicate.Use HTTPS endpoints — Tiqora only delivers webhooks to HTTPS URLs for security.
Log webhook payloads — Store incoming webhook payloads for debugging. They're invaluable when troubleshooting integration issues.
Monitor for failures — If your endpoint starts failing, check the delivery logs in the Tiqora dashboard. Five consecutive failures will disable your endpoint.
Subscribe selectively — Only subscribe to events you actually need. This reduces noise and saves processing time.