Skip to content

Webhooks Configuration Guide

This guide explains how to configure webhooks for real-time ticket updates from PSA systems (Freshservice, SuperOps) to HiveMatrix Codex.

Overview

By default, Codex polls your PSA system every 5 minutes to check for ticket updates. With webhooks enabled, your PSA can push updates to Codex immediately when tickets change, reducing latency from 5 minutes to under 1 second.

Benefits of Webhooks

Aspect Polling (Default) With Webhooks
Update latency Up to 5 minutes < 1 second
API calls 288/day ~24/day (hourly backup)
Deleted ticket detection 5 min delay Instant
Complexity Simple Requires PSA configuration

Architecture

PSA System (Freshservice/SuperOps)
        │ HTTP POST (on ticket change)
    Nexus (443)
        │ Proxy to internal
    Codex (5010)
    /webhooks/<provider>/ticket
        │ Update database
    PostgreSQL
        │ Next refresh
    Beacon Dashboard

Configuration

Step 1: Generate a Webhook Secret

Generate a secure secret key that will authenticate webhook requests:

python3 -c "import secrets; print(secrets.token_urlsafe(32))"

Save this secret - you'll need it for both Codex and Freshservice configuration.

Step 2: Configure Codex

Edit /path/to/hivematrix-codex/instance/codex.conf:

[webhooks]
# Enable webhook receivers
enabled = true

# Secret key (must match what you configure in Freshservice)
secret = YOUR_GENERATED_SECRET_HERE

# Optional: Restrict to specific IPs (comma-separated, leave empty to allow all)
allowed_ips =

# Log payloads for debugging (disable in production)
log_payloads = true

Step 3: Restart Codex

# If using systemd
sudo systemctl restart hivematrix

# Or if in development
./stop.sh && ./start.sh

Step 4: Verify Webhook Endpoint

Test that the webhook endpoint is accessible:

# Health check (no auth required)
curl https://yourdomain.com/codex/webhooks/health

# Test authentication
curl -X POST https://yourdomain.com/codex/webhooks/test \
  -H "X-Webhook-Secret: YOUR_SECRET_HERE" \
  -H "Content-Type: application/json"

Expected response:

{
  "status": "ok",
  "message": "Webhook authentication successful",
  "source_ip": "x.x.x.x",
  "timestamp": "2024-01-15T10:30:00Z"
}

Freshservice Configuration

Step 1: Open Workflow Automator

  1. Log into Freshservice as an admin
  2. Go to Admin (gear icon) → Helpdesk ProductivityWorkflow Automator
  3. Click New AutomatorTicket

Step 2: Create Ticket Updated Workflow

Basic Info: - Title: HiveMatrix Webhook - Ticket Updated - Description: Send ticket updates to HiveMatrix Codex

Event: - Select: Ticket is Updated

Conditions (Optional): - You can add conditions to filter which updates trigger webhooks - For all updates, leave conditions empty

Actions: 1. Click Add ActionTrigger Webhook 2. Configure: - Request Type: POST - URL: https://yourdomain.com/codex/webhooks/freshservice/ticket - Encoding: JSON - Requires Authentication: Yes - Select API Key - Header Name: X-Webhook-Secret - API Key: YOUR_SECRET_HERE

  1. Click Advanced and enter this JSON payload:
{
  "event": "ticket.updated",
  "ticket_id": {{ticket.id}},
  "subject": "{{ticket.subject}}",
  "status_id": {{ticket.status}},
  "priority_id": {{ticket.priority}},
  "requester_email": "{{ticket.requester.email}}",
  "requester_name": "{{ticket.requester.name}}",
  "requester_id": {{ticket.requester.id}},
  "responder_id": {{ticket.agent.id}},
  "group_id": {{ticket.group.id}},
  "department_id": {{ticket.department.id}},
  "updated_at": "{{ticket.updated_at}}"
}
  1. Click Save and Activate the workflow

Step 3: Create Ticket Created Workflow

Repeat the above steps with: - Title: HiveMatrix Webhook - Ticket Created - Event: Ticket is Created - JSON payload:

{
  "event": "ticket.created",
  "ticket_id": {{ticket.id}},
  "subject": "{{ticket.subject}}",
  "status_id": {{ticket.status}},
  "priority_id": {{ticket.priority}},
  "requester_email": "{{ticket.requester.email}}",
  "requester_name": "{{ticket.requester.name}}",
  "requester_id": {{ticket.requester.id}},
  "responder_id": {{ticket.agent.id}},
  "group_id": {{ticket.group.id}},
  "department_id": {{ticket.department.id}},
  "created_at": "{{ticket.created_at}}",
  "updated_at": "{{ticket.updated_at}}"
}

Step 4: Create Ticket Deleted Workflow (Optional)

For deleted/spam ticket detection: - Title: HiveMatrix Webhook - Ticket Deleted - Event: Ticket status is changed → Status changed to Spam or Deleted - JSON payload:

{
  "event": "ticket.deleted",
  "ticket_id": {{ticket.id}},
  "status_id": {{ticket.status}},
  "updated_at": "{{ticket.updated_at}}"
}

Step 5: Test the Workflow

  1. Create or update a test ticket in Freshservice
  2. Check Codex logs for webhook receipt:
    sudo journalctl -u hivematrix -f | grep webhook
    
  3. Verify the ticket updated in Beacon dashboard

Webhook Endpoints Reference

Health Check

GET /webhooks/health
Returns webhook configuration status (no authentication required).

Test Authentication

POST /webhooks/test
Headers: X-Webhook-Secret: <secret>
Verifies authentication is working.

Freshservice Ticket Webhook

POST /webhooks/freshservice/ticket
Headers: X-Webhook-Secret: <secret>
Content-Type: application/json
Receives ticket create/update/delete events from Freshservice.

SuperOps Ticket Webhook (Coming Soon)

POST /webhooks/superops/ticket
Headers: X-Webhook-Secret: <secret>
Content-Type: application/json
Placeholder for SuperOps integration.

Troubleshooting

Webhook Not Received

  1. Check webhook is enabled:

    curl https://yourdomain.com/codex/webhooks/health
    
    Should show webhooks_enabled: true

  2. Check Freshservice workflow is active:

  3. Go to Workflow Automator
  4. Ensure the workflow shows "Active" status

  5. Check Codex logs:

    sudo journalctl -u hivematrix -f | grep -i webhook
    

  6. Test from command line:

    curl -X POST https://yourdomain.com/codex/webhooks/freshservice/ticket \
      -H "X-Webhook-Secret: YOUR_SECRET" \
      -H "Content-Type: application/json" \
      -d '{"event":"ticket.updated","ticket_id":12345,"status_id":2}'
    

Authentication Failed (401)

  • Verify the secret in codex.conf matches the API key in Freshservice
  • Check for extra spaces or newlines in the secret
  • Ensure X-Webhook-Secret header is being sent (not Authorization)

IP Rejected (403)

  • If using allowed_ips, verify Freshservice's IP ranges are included
  • Freshservice uses AWS infrastructure - IPs can change
  • Consider leaving allowed_ips empty and relying on secret authentication

Webhook Timeout

  • Freshservice has a 15-second timeout
  • If Codex is slow to respond, webhooks may fail
  • Check database performance and server load

Rate Limits

  • Freshservice limit: 1,000 webhook calls per hour
  • Retry behavior: Failed webhooks retry 4 times at 3, 5, 9, 17 minute intervals
  • Typical usage: ~50-200 tickets/day = well under limit

Security Considerations

  1. Secret Key: Use a strong, randomly generated secret (32+ characters)
  2. HTTPS: Always use HTTPS for webhook endpoints
  3. IP Allowlist: Consider restricting to known PSA IP ranges
  4. Log Payloads: Disable log_payloads in production to avoid logging sensitive data
  5. Rate Limiting: Codex applies standard rate limits to webhook endpoints

Reducing Polling After Webhooks

Once webhooks are working reliably, you can reduce polling frequency:

Edit codex.conf:

[scheduler]
# Change from 'frequent' (5 min) to 'hourly' as backup
sync_tickets_schedule = hourly

The light sync will still run hourly to catch any webhooks that may have failed.