Docs Webhooks

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

  1. You register a webhook endpoint URL in Tiqora
  2. You select which events you want to receive
  3. When an event occurs, Tiqora sends a POST request to your URL with the event payload
  4. Your server responds with a 2xx status code to acknowledge receipt
  5. 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

  1. Respond quickly — Return a 200 response immediately before processing the event. Use a queue to handle the actual work asynchronously.

  2. Handle duplicate events — In rare cases, events may be delivered more than once. Use the event's data.id to deduplicate.

  3. Use HTTPS endpoints — Tiqora only delivers webhooks to HTTPS URLs for security.

  4. Log webhook payloads — Store incoming webhook payloads for debugging. They're invaluable when troubleshooting integration issues.

  5. Monitor for failures — If your endpoint starts failing, check the delivery logs in the Tiqora dashboard. Five consecutive failures will disable your endpoint.

  6. Subscribe selectively — Only subscribe to events you actually need. This reduces noise and saves processing time.