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
- Go to ShahiAssist → Settings → Integrations
- Check “Enable webhooks”
- Add webhook URLs (one per line)
- Select events to trigger
ticket.created: Triggered when a new ticket is submittedticket.status_changed: Triggered when ticket status changesticket.reply_added: Triggered when a reply is addedticket.assigned: Triggered when ticket is assigned to an agentticket.closed: Triggered when ticket is closedarticle.published: Triggered when KB article is publishedarticle.updated: Triggered when article is updatedarticle.viewed: Triggered when article is viewed (throttled)user.role_changed: Triggered when user role changesagent.login: Triggered when support agent logs in- Retry 1: After 1 minute
- Retry 2: After 5 minutes
- Retry 3: After 30 minutes
- Webhook.site – Inspect webhook payloads
- RequestBin – Capture and inspect requests
- ngrok – Expose local servers
- 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.)
- Check if webhooks are enabled in settings
- Verify event is selected
- Check debug logs for errors
- Ensure URL is accessible and uses HTTPS
- Check firewall settings
- Verify SSL certificate validity
- Confirm secret matches between systems
- Check JSON encoding/decoding
- Use raw payload for signature calculation
- Implement idempotency keys
- Check for duplicate events in handler
- Webhook Security Best Practices
- Webhook Testing Tools
- ShahiAssist Webhook Events Reference (in plugin code)
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
Knowledge Base Events
User Events
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:
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
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
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
Delivery Failures
Signature Verification Issues
Duplicate Webhooks
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
Share this article
Still need help?
Our support team is ready to assist you with personalized guidance for your workspace.