ShahiAssist

Webhooks

Webhooks allow ShahiAssist to send real-time notifications to external services when specific events occur, enabling seamless integration with other applications.

Overview

Webhooks are HTTP callbacks triggered by events in ShahiAssist. When an event occurs, the system sends a POST request to configured URLs with event data.

Configuration

Enable Webhooks

  1. Go to ShahiAssist → Settings → Integrations
  2. Check “Enable webhooks”
  3. Add webhook URLs (one per line)
  4. Select events to trigger
  5. Programmatic Setup

    `php
    addfilter(‘shahiassistwebhookurls’, function($urls) {
    $urls[] = ‘https://myapp.com/webhook’;
    return $urls;
    });

    addfilter(‘shahiassistwebhookevents’, function($events) {
    return array_merge($events, [‘custom.event’]);
    });
    `

    Available Events

    Ticket Events

    • ticket.created: Triggered when a new ticket is submitted
    • ticket.status_changed: Triggered when ticket status changes
    • ticket.reply_added: Triggered when a reply is added
    • ticket.assigned: Triggered when ticket is assigned to an agent
    • ticket.closed: Triggered when ticket is closed
    • Knowledge Base Events

    • article.published: Triggered when KB article is published
    • article.updated: Triggered when article is updated
    • article.viewed: Triggered when article is viewed (throttled)
    • User Events

    • user.role_changed: Triggered when user role changes
    • agent.login: Triggered when support agent logs in
    • Payload Structure

      Common Payload Fields

      `json
      {
      “event”: “ticket.created”,
      “timestamp”: 1638019200,
      “site_url”: “https://example.com”,
      “data”: {
      // Event-specific data
      },
      “signature”: “sha256=…”
      }
      `

      Ticket Created Payload

      `json
      {
      “event”: “ticket.created”,
      “timestamp”: 1638019200,
      “site_url”: “https://example.com”,
      “data”: {
      “ticket_id”: 123,
      “title”: “Login issue”,
      “content”: “I can’t log in”,
      “status”: “open”,
      “author_id”: 5,
      “author_email”: “user@example.com”,
      “custom_fields”: {
      “priority”: “high”,
      “product”: “web_app”
      },
      “ticket_url”: “https://example.com/ticket/login-issue/”
      },
      “signature”: “sha256=abc123…”
      }
      `

      Status Changed Payload

      `json
      {
      “event”: “ticket.status_changed”,
      “timestamp”: 1638019260,
      “data”: {
      “ticket_id”: 123,
      “old_status”: “open”,
      “new_status”: “pending”,
      “changed_by”: 10,
      “change_reason”: “Waiting for user response”
      }
      }
      `

      Article Published Payload

      `json
      {
      “event”: “article.published”,
      “timestamp”: 1638019320,
      “data”: {
      “article_id”: 456,
      “title”: “How to reset password”,
      “author_id”: 1,
      “categories”: [“getting-started”],
      “tags”: [“password”, “login”],
      “article_url”: “https://example.com/kb/how-to-reset-password/”
      }
      }
      `

      Security

      Signature Verification

      Each webhook includes a signature for verification:
      `php
      function verifywebhooksignature($payload, $signature, $secret) {
      $expectedsignature = hashhmac(‘sha256’, json_encode($payload), $secret);
      return hashequals($expectedsignature, str_replace(‘sha256=’, ”, $signature));
      }

      // Usage
      $secret = ‘yourwebhooksecret’;
      if (verifywebhooksignature($POST, $SERVER[‘HTTPXSHAHIASSISTSIGNATURE’], $secret)) {
      // Process webhook
      } else {
      // Invalid signature
      httpresponsecode(401);
      exit;
      }
      `

      HTTPS Requirement

      Webhooks are only sent to HTTPS URLs for security.

      Secret Management

      Store webhook secrets securely:
      `php
      // In wp-config.php
      define(‘SHAHIASSISTWEBHOOKSECRET’, ‘yoursecret_here’);

      // In code
      $secret = defined(‘SHAHIASSISTWEBHOOKSECRET’) ? SHAHIASSISTWEBHOOKSECRET : ‘fallback_secret’;
      `

      Handling Webhooks

      Basic Handler

      `php
      // webhook-handler.php
      header(‘Content-Type: application/json’);

      $payload = jsondecode(fileget_contents(‘php://input’), true);
      $signature = $SERVER[‘HTTPXSHAHIASSIST_SIGNATURE’] ?? ”;

      $secret = ‘yourwebhooksecret’;
      if (!verify_signature($payload, $signature, $secret)) {
      httpresponsecode(401);
      echo json_encode([‘error’ => ‘Invalid signature’]);
      exit;
      }

      switch ($payload[‘event’]) {
      case ‘ticket.created’:
      handleticketcreated($payload[‘data’]);
      break;
      case ‘ticket.status_changed’:
      handlestatuschanged($payload[‘data’]);
      break;
      default:
      // Unknown event
      break;
      }

      echo json_encode([‘status’ => ‘success’]);
      `

      Laravel Handler

      `php
      // routes/web.php
      Route::post(‘/webhook/shahi-assist’, ‘WebhookController@handle’);

      // app/Http/Controllers/WebhookController.php
      public function handle(Request $request) {
      $payload = $request->all();
      $signature = $request->header(‘X-Shahi-Assist-Signature’);

      if (!$this->verifySignature($payload, $signature)) {
      return response()->json([‘error’ => ‘Invalid signature’], 401);
      }

      // Process event
      event(new ShahiAssistWebhookReceived($payload));

      return response()->json([‘status’ => ‘success’]);
      }
      `

      Node.js Handler

      `javascript
      const express = require(‘express’);
      const crypto = require(‘crypto’);

      const app = express();
      app.use(express.json());

      function verifySignature(payload, signature, secret) {
      const expected = crypto.createHmac(‘sha256’, secret).update(JSON.stringify(payload)).digest(‘hex’);
      return crypto.timingSafeEqual(Buffer.from(signature.replace(‘sha256=’, ”)), Buffer.from(expected));
      }

      app.post(‘/webhook’, (req, res) => {
      const signature = req.headers[‘x-shahi-assist-signature’];
      const secret = ‘yourwebhooksecret’;

      if (!verifySignature(req.body, signature, secret)) {
      return res.status(401).json({ error: ‘Invalid signature’ });
      }

      // Process webhook
      console.log(‘Received event:’, req.body.event);

      res.json({ status: ‘success’ });
      });

      app.listen(3000);
      `

      Retry Logic

      Automatic Retries

      ShahiAssist automatically retries failed webhook deliveries:

    • Retry 1: After 1 minute
    • Retry 2: After 5 minutes
    • Retry 3: After 30 minutes
    • Manual Retry

      `php
      addaction(‘shahiassistwebhookfailed’, function($webhook_url, $payload, $attempt) {
      if ($attempt < 3) { // Custom retry logic wpschedulesingleevent(time() + (60 * $attempt), ‘retrywebhook’, [$webhook_url, $payload, $attempt + 1]);
      }
      });
      `

      Testing Webhooks

      Local Development

      Use tools like ngrok or localtunnel for local webhook testing:
      `bash

      Install ngrok

      npm install -g ngrok

      Expose local server

      ngrok http 8000

      Use the ngrok URL in ShahiAssist settings

      `

      Test Payloads

      Create test webhooks programmatically:
      `php
      function test_webhook($url, $event = ‘ticket.created’) {
      $payload = [
      ‘event’ => $event,
      ‘timestamp’ => time(),
      ‘siteurl’ => getsite_url(),
      ‘data’ => [
      ‘test’ => true,
      ‘ticket_id’ => 999,
      ‘title’ => ‘Test Ticket’
      ]
      ];

      $response = wpremotepost($url, [
      ‘body’ => json_encode($payload),
      ‘headers’ => [
      ‘Content-Type’ => ‘application/json’,
      ‘X-Shahi-Assist-Signature’ => ‘sha256=’ . hashhmac(‘sha256’, jsonencode($payload), ‘test_secret’)
      ]
      ]);

      return $response;
      }
      `

      Webhook Testing Tools

    • Webhook.site – Inspect webhook payloads
    • RequestBin – Capture and inspect requests
    • ngrok – Expose local servers
    • Integration Examples

      Slack Integration

      `php
      function sendtoslack($payload) {
      $slackwebhookurl = ‘https://hooks.slack.com/services/…’;

      $message = [
      ‘text’ => “New ticket: {$payload[‘data’][‘title’]}”,
      ‘attachments’ => [
      [
      ‘title’ => $payload[‘data’][‘title’],
      ‘titlelink’ => $payload[‘data’][‘ticketurl’],
      ‘fields’ => [
      [
      ‘title’ => ‘Status’,
      ‘value’ => $payload[‘data’][‘status’],
      ‘short’ => true
      ]
      ]
      ]
      ]
      ];

      wpremotepost($slackwebhookurl, [
      ‘body’ => json_encode($message),
      ‘headers’ => [‘Content-Type’ => ‘application/json’]
      ]);
      }

      addaction(‘shahiassistwebhookticketcreated’, ‘sendto_slack’);
      `

      Zapier Integration

    • Create a Zap with “Webhooks by Zapier” trigger
    • Set up the webhook URL in ShahiAssist
    • Configure actions in Zapier (create Trello cards, send emails, etc.)
    • CRM Integration

      `php
      function synctocrm($payload) {
      $crmapiurl = ‘https://api.crm.com/contacts’;
      $apikey = ‘yourcrmapikey’;

      $contact_data = [
      ’email’ => $payload[‘data’][‘author_email’],
      ‘name’ => getuserdata($payload[‘data’][‘authorid’])->display_name,
      ‘ticketid’ => $payload[‘data’][‘ticketid’],
      ‘status’ => $payload[‘data’][‘status’]
      ];

      wpremotepost($crmapiurl, [
      ‘body’ => jsonencode($contactdata),
      ‘headers’ => [
      ‘Content-Type’ => ‘application/json’,
      ‘Authorization’ => ‘Bearer ‘ . $api_key
      ]
      ]);
      }

      addaction(‘shahiassistwebhookticketcreated’, ‘syncto_crm’);
      `

      Performance Considerations

      Asynchronous Processing

      Webhooks are sent asynchronously to avoid blocking the main request:
      `php
      addaction(‘shahiassistticketcreated’, function($ticket_id) {
      // Schedule webhook delivery
      wpschedulesingleevent(time(), ‘sendwebhook’, [‘ticket.created’, $ticket_id]);
      });

      addaction(‘sendwebhook’, function($event, $resource_id) {
      // Send webhook here
      shahiassistsendwebhook($event, getwebhookpayload($event, $resourceid));
      });
      `

      Rate Limiting

      Implement rate limiting to prevent webhook spam:
      `php
      function checkratelimit($url) {
      $key = ‘webhookrate‘ . md5($url);
      $attempts = get_transient($key) ?: 0;

      if ($attempts >= 10) { // 10 attempts per hour
      return false;
      }

      settransient($key, $attempts + 1, HOURIN_SECONDS);
      return true;
      }
      `

      Payload Size Limits

      Keep payloads under 1MB to ensure reliable delivery.

      Monitoring and Logging

      Log Webhook Activity

      `php
      addaction(‘shahiassistwebhooksent’, function($url, $payload, $response) {
      $log_entry = [
      ‘timestamp’ => time(),
      ‘url’ => $url,
      ‘event’ => $payload[‘event’],
      ‘responsecode’ => wpremoteretrieveresponse_code($response),
      ‘success’ => !iswperror($response)
      ];

      // Log to custom table or file
      shahiassistlogwebhook($logentry);
      });
      `

      Dashboard Monitoring

      Create a dashboard to monitor webhook health:
      `php
      function getwebhookstats() {
      global $wpdb;
      return $wpdb->get_results(“
      SELECT url, event, COUNT(*) as count, AVG(responsetime) as avgtime
      FROM {$wpdb->prefix}shahiassistwebhook_logs
      WHERE timestamp > ” . (time() – DAYINSECONDS) . “
      GROUP BY url, event
      “);
      }
      `

      Troubleshooting

      Webhooks Not Firing

    • Check if webhooks are enabled in settings
    • Verify event is selected
    • Check debug logs for errors
    • Delivery Failures

    • Ensure URL is accessible and uses HTTPS
    • Check firewall settings
    • Verify SSL certificate validity
    • Signature Verification Issues

    • Confirm secret matches between systems
    • Check JSON encoding/decoding
    • Use raw payload for signature calculation
    • Duplicate Webhooks

    • Implement idempotency keys
    • Check for duplicate events in handler
    • Best Practices

      Idempotency

      Handle duplicate webhooks gracefully:
      `php
      function process_webhook($payload) {
      $eventid = $payload[‘data’][‘ticketid’] . ‘_’ . $payload[‘event’];

      if (gettransient(‘processed‘ . $event_id)) {
      return; // Already processed
      }

      // Process webhook
      settransient(‘processed‘ . $eventid, true, HOURIN_SECONDS);
      }
      `

      Error Handling

      Always handle errors gracefully:
      `php
      try {
      // Process webhook
      sendtoexternal_service($payload);
      } catch (Exception $e) {
      error_log(‘Webhook processing failed: ‘ . $e->getMessage());
      // Optionally retry or alert admin
      }
      `

      Documentation

      Document webhook integrations:
      `php
      /**
      * Handles ShahiAssist ticket.created webhooks
      *
      * @param array $payload Webhook payload
      * @return void
      */
      function handleticketcreated_webhook($payload) {
      // Implementation
      }
      `

      Resources

    • Webhook Security Best Practices
    • Webhook Testing Tools
    • ShahiAssist Webhook Events Reference (in plugin code)

Share this article

Was this article helpful?

Help us improve our documentation

Still need help?

Our support team is ready to assist you with personalized guidance for your workspace.

Submit a support ticket