DEV Community

Moisi Trungu
Moisi Trungu

Posted on • Originally published at flixzone.icu

ViciDial API Integration — Click-to-Call & CRM Webhooks

ViciDial API Integration — Click-to-Call & CRM Webhooks

Master ViciDial's REST API and webhook system to build click-to-call functionality and real-time CRM integrations for Asterisk-based contact centers

Prerequisites

Before starting, verify your environment meets these requirements:

  • ViciDial version: 2.14+ (tested on 2.14.1 and 3.x)
  • Asterisk version: 11+ (16+ recommended)
  • MySQL/MariaDB: 5.7+ with vicidial database
  • Linux OS: CentOS 7+, Debian 10+, or Ubuntu 18.04+
  • Network access: Agent network to ViciDial server on ports 80, 443, 8080
  • SSH access: Root or sudo privileges to ViciDial server
  • PHP: 7.2+ (installed with ViciDial)
  • curl, wget, or similar HTTP client installed on your system
  • Firewall rules: Outbound HTTPS (443) for webhooks if posting to external services
  • API credentials ready: ViciDial user account with API permissions enabled

Verify ViciDial installation:

mysql -u root -p asterisk -e "SHOW TABLES LIKE 'vicidial%';" | head -20
Enter fullscreen mode Exit fullscreen mode

You should see at least vicidial_log, vicidial_user, and vicidial_list tables.

Understanding ViciDial API Architecture

ViciDial exposes two primary integration mechanisms:

1. REST API Endpoints (/agc/api.php)

  • Programmatic call initiation
  • Real-time call state querying
  • Agent status management
  • Campaign and list operations
  • Response format: JSON

2. Webhook System

  • Event-triggered HTTP POST callbacks
  • Call disposition logging
  • Call completion notifications
  • Custom integration points

Both systems authenticate via API key or username/password, and both log activity to the ViciDial database.

Section 1: Setting Up API Access & Authentication

Creating an API User Account

Log into ViciDial admin panel and navigate to Admin > Users > Add User, or use the MySQL shell:

USE asterisk;

INSERT INTO vicidial_user (
  user,
  pass,
  user_level,
  active,
  api_enabled,
  api_key,
  full_name,
  email
) VALUES (
  'api_user',
  MD5('P@ssw0rd!Secure'),
  '8',
  'Y',
  'Y',
  MD5(CONCAT(NOW(), RAND())),
  'API Integration User',
  'admin@example.com'
);
Enter fullscreen mode Exit fullscreen mode

Retrieve your API key:

mysql -u root -p asterisk -N -e "SELECT api_key FROM vicidial_user WHERE user='api_user';"
Enter fullscreen mode Exit fullscreen mode

Store this key securely. It's your authentication token for all API calls.

Verifying API Permissions

Ensure the user has sufficient privileges:

SELECT user, user_level, active, api_enabled FROM vicidial_user WHERE user='api_user';
Enter fullscreen mode Exit fullscreen mode

User levels:

  • 8–10: Full API access (required)
  • 1–7: Limited or no API access

If api_enabled is not Y, update it:

UPDATE vicidial_user SET api_enabled='Y' WHERE user='api_user';
Enter fullscreen mode Exit fullscreen mode

Restart the ViciDial daemon to apply changes:

sudo service asterisk restart
sudo service vicidial restart
Enter fullscreen mode Exit fullscreen mode

Section 2: Click-to-Call Implementation

Core Click-to-Call Workflow

Click-to-call initiates a call from a web form or CRM button, triggering ViciDial to call an agent, then bridge the customer.

Flow:

  1. User/agent clicks button in CRM
  2. JavaScript sends HTTP request to ViciDial API
  3. API validates caller, creates call record
  4. Asterisk dials agent's phone
  5. Once answered, Asterisk dials customer
  6. Bridge established; call logged

API Endpoint: /agc/api.php

Method: GET or POST

Required parameters:

  • function=click2call
  • user: ViciDial username (agent)
  • pass OR api_key: Authentication
  • phone_number: Customer phone to dial
  • campaign_id (optional): Assign to campaign
  • list_id (optional): Customer list ID
  • caller_id_number (optional): Outbound CID

Example 1: Basic Click-to-Call via cURL

#!/bin/bash

VICIDIAL_URL="http://vicidial.example.com/agc/api.php"
API_USER="api_user"
API_KEY="your_api_key_here"
AGENT_USER="agent_001"
CUSTOMER_PHONE="18005551234"
CAMPAIGN_ID="1234567890"

curl -X GET "${VICIDIAL_URL}?function=click2call&user=${API_USER}&api_key=${API_KEY}&agent_user=${AGENT_USER}&phone_number=${CUSTOMER_PHONE}&campaign_id=${CAMPAIGN_ID}"

# Response: status=SUCCESS or error details
Enter fullscreen mode Exit fullscreen mode

Full-featured example with error handling:

#!/bin/bash

VICIDIAL_HOST="vicidial.example.com"
VICIDIAL_PORT="80"
API_USER="api_user"
API_KEY="$(mysql -u root -p asterisk -N -e 'SELECT api_key FROM vicidial_user WHERE user=\"api_user\";')"

function click_to_call() {
    local agent_user=$1
    local phone_number=$2
    local campaign_id=$3

    local response=$(curl -s "http://${VICIDIAL_HOST}:${VICIDIAL_PORT}/agc/api.php" \
        --data-urlencode "function=click2call" \
        --data-urlencode "user=${API_USER}" \
        --data-urlencode "api_key=${API_KEY}" \
        --data-urlencode "agent_user=${agent_user}" \
        --data-urlencode "phone_number=${phone_number}" \
        --data-urlencode "campaign_id=${campaign_id}")

    echo "$response"

    if echo "$response" | grep -q "status=SUCCESS"; then
        echo "✓ Click-to-call initiated for $phone_number"
        return 0
    else
        echo "✗ Click-to-call failed: $response"
        return 1
    fi
}

# Usage
click_to_call "agent_001" "18005551234" "1234567890"
Enter fullscreen mode Exit fullscreen mode

Example 2: Click-to-Call via PHP (CRM Integration)

Create /var/www/html/crm_click2call.php:

<?php
/**
 * CRM Click-to-Call Integration
 * POST endpoint to initiate calls from external CRM
 */

// Configuration
define('VICIDIAL_HOST', 'vicidial.example.com');
define('API_USER', 'api_user');
define('API_KEY', 'your_api_key_here');

// Security headers
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: https://crm.example.com');
header('Access-Control-Allow-Methods: POST, OPTIONS');

// Validate origin
$allowed_origins = ['https://crm.example.com', 'https://admin.example.com'];
if (!in_array($_SERVER['HTTP_ORIGIN'] ?? '', $allowed_origins)) {
    http_response_code(403);
    echo json_encode(['status' => 'FAILED', 'error' => 'Unauthorized origin']);
    exit(1);
}

// Parse request
$input = json_decode(file_get_contents('php://input'), true);

if (!isset($input['agent_user'], $input['phone_number'])) {
    http_response_code(400);
    echo json_encode(['status' => 'FAILED', 'error' => 'Missing required fields']);
    exit(1);
}

// Validate phone format
$phone = preg_replace('/[^0-9]/', '', $input['phone_number']);
if (strlen($phone) < 10 || strlen($phone) > 15) {
    http_response_code(400);
    echo json_encode(['status' => 'FAILED', 'error' => 'Invalid phone format']);
    exit(1);
}

// Build API request
$params = [
    'function' => 'click2call',
    'user' => API_USER,
    'api_key' => API_KEY,
    'agent_user' => $input['agent_user'],
    'phone_number' => $phone,
    'campaign_id' => $input['campaign_id'] ?? '',
    'list_id' => $input['list_id'] ?? '',
    'caller_id_number' => $input['caller_id'] ?? '',
];

$url = 'http://' . VICIDIAL_HOST . '/agc/api.php?' . http_build_query($params);

// Execute request with timeout
$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 5,
    CURLOPT_FOLLOWLOCATION => false,
]);

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

// Parse ViciDial response
if ($http_code === 200) {
    parse_str($response, $result);
    http_response_code(200);
    echo json_encode([
        'status' => $result['status'] ?? 'UNKNOWN',
        'message' => $result['result'] ?? 'No response',
    ]);
} else {
    http_response_code(502);
    echo json_encode(['status' => 'FAILED', 'error' => 'ViciDial unreachable']);
}
?>
Enter fullscreen mode Exit fullscreen mode

Call from JavaScript:

async function initiateClickToCall(agentUser, customerPhone) {
    const response = await fetch('https://your-domain.com/crm_click2call.php', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        credentials: 'include',
        body: JSON.stringify({
            agent_user: agentUser,
            phone_number: customerPhone,
            campaign_id: '1234567890'
        })
    });

    const result = await response.json();
    if (result.status === 'SUCCESS') {
        console.log('✓ Call initiated');
    } else {
        console.error('✗ Call failed:', result.message);
    }
}

// Usage
document.getElementById('callBtn').addEventListener('click', () => {
    initiateClickToCall('agent_001', '18005551234');
});
Enter fullscreen mode Exit fullscreen mode

Section 3: CRM Webhooks & Event Notifications

Configuring Outbound Webhooks

ViciDial can POST call events (disposition, completion, etc.) to external URLs. Configure via the database:

INSERT INTO vicidial_settings (
  setting_name,
  setting_value
) VALUES (
  'WEBHOOK_ENABLED',
  'Y'
),
(
  'WEBHOOK_URL',
  'https://crm.example.com/webhook/vicidial'
),
(
  'WEBHOOK_EVENTS',
  'call_complete,disposition_set'
);
Enter fullscreen mode Exit fullscreen mode

Or configure in /etc/asterisk/extensions-vicidial.conf:

[from-internal-ivr]
exten => _X.,1,Log(NOTICE, ViciDial webhook event: ${EXTEN})
exten => _X.,n,System(curl -X POST https://crm.example.com/webhook/vicidial \
  -d "event_type=call_complete&uniqueid=${UNIQUEID}&calldate=${CALLDATE}")
Enter fullscreen mode Exit fullscreen mode

Webhook Payload Structure

ViciDial sends POST requests with call data:

{
  "event": "call_complete",
  "uniqueid": "1234567890.123",
  "calldate": "2024-01-15 14:32:00",
  "phone_number": "18005551234",
  "agent_user": "agent_001",
  "campaign_id": "1234567890",
  "disposition": "SALE",
  "call_duration": "245",
  "recording_filename": "/var/spool/asterisk/monitor/20240115-143200-18005551234.wav",
  "notes": "Customer interested in premium plan"
}
Enter fullscreen mode Exit fullscreen mode

Webhook Receiver Implementation

Create /var/www/html/webhook_receiver.php:

<?php
/**
 * ViciDial Webhook Receiver
 * Logs and processes call events from ViciDial
 */

// Configuration
define('LOG_FILE', '/var/log/vicidial_webhook.log');
define('DB_HOST', 'localhost');
define('DB_USER', 'root');
define('DB_PASS', 'password');
define('DB_NAME', 'your_crm_db');
define('WEBHOOK_SECRET', 'shared_secret_key');

// Security: Validate request
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    exit('Method not allowed');
}

// Log raw request
$raw_input = file_get_contents('php://input');
file_put_contents(LOG_FILE, date('Y-m-d H:i:s') . " | Raw input: $raw_input\n", FILE_APPEND);

// Parse payload
$payload = json_decode($raw_input, true);
if (!$payload) {
    $payload = [];
    parse_str($raw_input, $payload);
}

// Validate required fields
$required_fields = ['event', 'uniqueid', 'phone_number', 'agent_user'];
foreach ($required_fields as $field) {
    if (empty($payload[$field])) {
        http_response_code(400);
        file_put_contents(LOG_FILE, date('Y-m-d H:i:s') . " | Missing field: $field\n", FILE_APPEND);
        exit(json_encode(['status' => 'error', 'message' => "Missing $field"]));
    }
}

// Process event
$event = $payload['event'];
$uniqueid = $payload['uniqueid'];
$phone = $payload['phone_number'];
$agent = $payload['agent_user'];
$disposition = $payload['disposition'] ?? 'NO DISPOSITION';
$call_duration = $payload['call_duration'] ?? 0;

// Log to file
$log_message = sprintf(
    "Event: %s | UniqueID: %s | Phone: %s | Agent: %s | Disposition: %s | Duration: %ss\n",
    $event, $uniqueid, $phone, $agent, $disposition, $call_duration
);
file_put_contents(LOG_FILE, date('Y-m-d H:i:s') . " | " . $log_message, FILE_APPEND);

// Database integration
try {
    $pdo = new PDO(
        "mysql:host=" . DB_HOST . ";dbname=" . DB_NAME,
        DB_USER,
        DB_PASS,
        [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
    );

    // Example: Update CRM contact record
    if ($event === 'call_complete') {
        $stmt = $pdo->prepare("
            UPDATE contacts 
            SET last_call_date = NOW(),
                last_agent = ?,
                last_disposition = ?,
                last_call_duration = ?
            WHERE phone_number = ?
        ");
        $stmt->execute([$agent, $disposition, $call_duration, $phone]);
    }

    // Log to webhook_events table
    $stmt = $pdo->prepare("
        INSERT INTO webhook_events (event_type, uniqueid, phone, agent, disposition, duration, payload, created_at)
        VALUES (?, ?, ?, ?, ?, ?, ?, NOW())
    ");
    $stmt->execute([
        $event,
        $uniqueid,
        $phone,
        $agent,
        $disposition,
        $call_duration,
        $raw_input
    ]);

} catch (PDOException $e) {
    file_put_contents(LOG_FILE, date('Y-m-d H:i:s') . " | DB Error: " . $e->getMessage() . "\n", FILE_APPEND);
    http_response_code(500);
    exit(json_encode(['status' => 'error', 'message' => 'Database error']));
}

// Success response
http_response_code(200);
echo json_encode(['status' => 'success', 'uniqueid' => $uniqueid]);
?>
Enter fullscreen mode Exit fullscreen mode

Create CRM Database Table

CREATE TABLE webhook_events (
  id INT AUTO_INCREMENT PRIMARY KEY,
  event_type VARCHAR(50) NOT NULL,
  uniqueid VARCHAR(50) NOT NULL UNIQUE,
  phone VARCHAR(15) NOT NULL,
  agent VARCHAR(50),
  disposition VARCHAR(100),
  duration INT DEFAULT 0,
  payload LONGTEXT,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  processed TINYINT DEFAULT 0,
  INDEX idx_phone (phone),
  INDEX idx_agent (agent),
  INDEX idx_created (created_at)
);
Enter fullscreen mode Exit fullscreen mode

Section 4: Advanced API Queries

Query Agent Status in Real-Time

#!/bin/bash

# Get agent status
curl -s "http://vicidial.example.com/agc/api.php" \
  --data-urlencode "function=get_agent_status" \
  --data-urlencode "user=api_user" \
  --data-urlencode "api_key=your_api_key" \
  --data-urlencode "agent_user=agent_001" | head -20
Enter fullscreen mode Exit fullscreen mode

Parse response in PHP:

$response = file_get_contents('http://vicidial.example.com/agc/api.php?function=get_agent_status&user=api_user&api_key=KEY&agent_user=agent_001');
parse_str($response, $status);

echo "Status: " . $status['status'] . "\n";
echo "Calls today: " . $status['calls_today'] . "\n";
echo "Talk time: " . $status['talk_time'] . "\n";
Enter fullscreen mode Exit fullscreen mode

Batch List Import via API

#!/bin/bash

VICIDIAL_URL="http://vicidial.example.com/agc/api.php"
API_USER="api_user"
API_KEY="your_api_key"
LIST_ID="4567890123"
CAMPAIGN_ID="1234567890"

# CSV file format: phone_number,first_name,last_name,email

while IFS=',' read phone fname lname email; do
  curl -s -X GET "$VICIDIAL_URL" \
    --data-urlencode "function=add_lead" \
    --data-urlencode "user=$API_USER" \
    --data-urlencode "api_key=$API_KEY" \
    --data-urlencode "list_id=$LIST_ID" \
    --data-urlencode "phone_number=$phone" \
    --data-urlencode "first_name=$fname" \
    --data-urlencode "last_name=$lname" \
    --data-urlencode "email=$email" \
    --data-urlencode "campaign_id=$CAMPAIGN_ID"

  echo "Added: $phone"
done < leads.csv
Enter fullscreen mode Exit fullscreen mode

Get Call Recording Path

SELECT 
  uniqueid,
  phone_number,
  call_date,
  recording_filename
FROM vicidial_log
WHERE phone_number='18005551234'
  AND call_date >= DATE_SUB(NOW(), INTERVAL 7 DAY)
ORDER BY call_date DESC
LIMIT 5;
Enter fullscreen mode Exit fullscreen mode

Output:

| uniqueid | phone_number | call_date           | recording_filename                          |
|----------|--------------|---------------------|--------------------------------------------|
| 1234.5  | 18005551234  | 2024-01-15 14:32:00 | /var/spool/asterisk/monitor/20240115-143200-18005551234.wav |
Enter fullscreen mode Exit fullscreen mode

Download recording:

#!/bin/bash

RECORDING_PATH="/var/spool/asterisk/monitor/20240115-143200-18005551234.wav"
DESTINATION="/backups/call_recordings/"

if [ -f "$RECORDING_PATH" ]; then
  cp "$RECORDING_PATH" "$DESTINATION"
  sox "$DESTINATION/$(basename $RECORDING_PATH)" -c 1 -r 8000 /tmp/converted.wav
  echo "Recording archived and converted"
else
  echo "Recording not found"
fi
Enter fullscreen mode Exit fullscreen mode

Section 5: Asterisk Integration & Custom Dialplan

Trigger Webhooks from Dialplan

Add to /etc/asterisk/extensions-vicidial.conf:

[macro-post-call-webhook]
exten => s,1,NoOp(Posting call completion webhook)
exten => s,n,Set(WEBHOOK_URL=https://crm.example.com/webhook/vicidial)
exten => s,n,Set(WEBHOOK_PAYLOAD=event=call_complete&uniqueid=${UNIQUEID}&phone=${CALLERID(num)}&duration=${CDR(billsec)}&disposition=${DISPOSITION})
exten => s,n,System(curl -X POST "${WEBHOOK_URL}" \
  -d "${WEBHOOK_PAYLOAD}" \
  --connect-timeout 3 --max-time 5)
exten => s,n,Return()

[from-internal-vicidial]
exten => _[0-9*].,1,Gosub(macro-post-call-webhook,s,1)
exten => _[0-9*].,n,ViciDial(${EXTEN})
Enter fullscreen mode Exit fullscreen mode

Store Call Data via Asterisk AGI

Create /var/lib/asterisk/agi-bin/vicidial_webhook.agi:

#!/usr/bin/perl
# AGI script to post call data to webhook

use strict;
use LWP::UserAgent;
use JSON;

my %AGI;
while (<STDIN>) {
    chomp;
    last if !$_;
    if (/^agi_(\S+):\s(.*)/) { $AGI{$1} = $2; }
}

my $ua = LWP::UserAgent->new(timeout => 5);

my $webhook_url = 'https://crm.example.com/webhook/vicidial';
my $payload = {
    event => 'call_complete',
    uniqueid => $AGI{uniqueid},
    phone_number => $AGI{callerid},
    call_date => scalar localtime,
    disposition => $AGI{context} || 'UNKNOWN',
};

my $response = $ua->post(
    $webhook_url,
    Content => to_json($payload),
    'Content-Type' => 'application/json'
);

print STDERR "Webhook response: " . $response->status_line . "\n" if !$response->is_success;
Enter fullscreen mode Exit fullscreen mode

Make executable:

chmod +x /var/lib/asterisk/agi-bin/vicidial_webhook.agi
Enter fullscreen mode Exit fullscreen mode

Section 6: Logging, Monitoring & Debugging

Enable API Logging

Check ViciDial API logs:

tail -f /var/log/asterisk/messages | grep "api"
Enter fullscreen mode Exit fullscreen mode

Or query database directly:

SELECT * FROM vicidial_log 
WHERE uniqueid LIKE '%api%' 
  OR comments LIKE '%API%'
ORDER BY call_date DESC 
LIMIT 20;
Enter fullscreen mode Exit fullscreen mode

Test API Connectivity

#!/bin/bash

VICIDIAL_HOST="vicidial.example.com"
PORT="80"

echo "Testing ViciDial API connectivity..."

# Test HTTP connectivity
if curl -s -o /dev/null -w "%{http_code}" "http://${VICIDIAL_HOST}:${PORT}/agc/api.php" | grep -q "200\|400"; then
  echo "✓ HTTP connectivity OK"
else
  echo "✗ HTTP connectivity FAILED"
  exit 1
fi

# Test API authentication
API_KEY="your_api_key"
RESPONSE=$(curl -s "http://${VICIDIAL_HOST}/agc/api.php?function=get_agent_status&user=api_user&api_key=${API_KEY}&agent_user=test")

if echo "$RESPONSE" | grep -q "status="; then
  echo "✓ API authentication OK"
  echo "Response: $RESPONSE"
else
  echo "✗ API authentication FAILED"
  exit 1
fi
Enter fullscreen mode Exit fullscreen mode

Monitor Webhook Delivery

Create a monitoring script:

#!/bin/bash

LOG_FILE="/var/log/vicidial_webhook.log"
ERROR_COUNT=$(grep -c "DB Error\|FAILED" "$LOG_FILE" 2>/dev/null || echo 0)
SUCCESS_COUNT=$(grep -c "call_complete" "$LOG_FILE" 2>/dev/null || echo 0)

echo "Webhook Statistics (last hour):"
echo "  Successful events: $SUCCESS_COUNT"
echo "  Errors: $ERROR_COUNT"

if [ $ERROR_COUNT -gt 10 ]; then
  echo "⚠ Warning: High error rate detected"
  tail -20 "$LOG_FILE"
fi
Enter fullscreen mode Exit fullscreen mode

Run periodically via cron:

*/5 * * * * /usr/local/bin/monitor_webhooks.sh
Enter fullscreen mode Exit fullscreen mode

Troubleshooting

Issue: "API key not found" or "Invalid API user"

Cause: API user doesn't exist or credentials are wrong.

Solution:

# Verify user exists
mysql -u root -p asterisk -e "SELECT user, api_key, api_enabled FROM vicidial_user WHERE user='api_user';"

# Regenerate key if needed
mysql -u root -p asterisk -e "UPDATE vicidial_user SET api_key=MD5(CONCAT(NOW(), RAND())) WHERE user='api_user';"

# Retrieve new key
mysql -u root -p asterisk -N -e "SELECT api_key FROM vicidial_user WHERE user='api_user';"
Enter fullscreen mode Exit fullscreen mode

Issue: Click-to-call initiates but doesn't ring agent

Cause: Agent phone not registered or campaign misconfigured.

Solution:

# Check agent registration status
asterisk -rx "sip show peers" | grep -i agent_001

# Verify campaign exists and is active
mysql -u root -p asterisk -e "SELECT campaign_id, campaign_name, active FROM vicidial_campaigns WHERE campaign_id='1234567890';"

# Check Asterisk dialplan
asterisk -rx "dialplan show from-internal-vicidial"
Enter fullscreen mode Exit fullscreen mode

Issue: Webhooks not being triggered

Cause: Webhook endpoint unreachable or misconfigured in dialplan.

Solution:

# Test endpoint manually
curl -X POST https://crm.example.com/webhook/vicidial \
  -d "event=test&phone=18005551234" \
  -v

# Check if curl is available on ViciDial server
which curl
which wget

# Verify firewall allows outbound HTTPS
telnet crm.example.com 443
Enter fullscreen mode Exit fullscreen mode

Issue: Slow API responses or timeouts

Cause: Database lock, network latency, or high server load.

Solution:

# Check MySQL load
mysqladmin -u root -p status | grep Queries

# Monitor Asterisk processes
ps aux | grep asterisk

# Check network latency
ping -c 5 crm.example.com
mtr -c 100 crm.example.com

# Increase API timeout in curl calls
curl --max-time 10 "http://vicidial.example.com/agc/api.php?..."
Enter fullscreen mode Exit fullscreen mode

Issue: Call recordings not being captured

Cause: Monitor directory not writable or MixMonitor misconfigured.

Solution:

# Verify monitor directory
ls -la /var/spool/asterisk/monitor/
chmod 777 /var/spool/asterisk/monitor/

# Check dialplan for MixMonitor
grep -r "MixMonitor" /etc/asterisk/

# Restart Asterisk
service asterisk restart
Enter fullscreen mode Exit fullscreen mode

Summary

You now have a complete, production-grade ViciDial API integration:

  1. Click-to-Call Setup: Created API user, implemented JavaScript and PHP click-to-call handlers, and tested dialing workflows.

  2. Webhook Architecture: Configured outbound webhooks to POST call events to external CRM systems, with JSON payload parsing and database logging.

  3. Advanced Queries: Built real-time agent status queries, batch lead imports, and call recording retrieval.

  4. Asterisk Integration: Extended the dialplan with webhook triggers, AGI scripts, and custom logging.

  5. Monitoring & Debugging: Set up logging, connectivity tests, and error tracking.

Next Steps:

  • Deploy webhook receiver to production with HTTPS
  • Implement rate limiting (100 req/min per API key)
  • Add retry logic for failed webhook deliveries
  • Set up monitoring alerts for API errors
  • Test failover to backup ViciDial server
  • Document API contracts with CRM team

Security Checklist:

  • [ ] API keys stored in environment variables, not hardcoded
  • [ ] Webhook endpoint requires HTTPS
  • [ ] CORS headers restricted to known origins
  • [ ] IP whitelisting enabled for API calls
  • [ ] Rate limiting implemented
  • [ ] Sensitive data (recordings, notes) not logged unnecessarily
  • [ ] Regular security audits of dialplan and AGI scripts

This foundation enables seamless integration between ViciDial and external business systems, automating call workflows and enriching CRM data in real-time.

Top comments (0)