You have added a carrier in VICIdial, the SIP trunk shows Registered, and the campaign still will not dial. Nine times out of ten the problem is in the Dialplan Entry field, not the trunk. This post covers what actually goes into that box and why.
Where the Dialplan Entry Actually Lands
In plain Asterisk you write your routing in /etc/asterisk/extensions.conf. VICIdial does not work that way. Whatever you type into Admin → Carriers → Dialplan Entry gets written out to /etc/asterisk/extensions-vicidial.conf by the ADMIN_keepalive_ALL.pl script, which runs from cron roughly every minute.
That has two consequences worth remembering:
- Editing
extensions-vicidial.confby hand is pointless. Your changes are overwritten on the next keepalive run. - After saving a carrier, changes take up to a couple of minutes to appear. If you are impatient:
/usr/share/astguiclient/ADMIN_keepalive_ALL.pl
asterisk -rx "dialplan reload"
Confirm the context loaded:
asterisk -rx "dialplan show default" | head -40
Anatomy of a Dialplan Line
Every line follows the same shape:
exten => extension,priority,Application(arguments)
- extension — the number or pattern being matched
- priority — the step number; execution runs 1, 2, 3 or uses
nfor “next” - application — what Asterisk does at that step
A minimal outbound entry:
exten => _91NXXNXXXXXX,1,AGI(agi://127.0.0.1:4577/call_log)
exten => _91NXXNXXXXXX,n,Dial(SIP/mytrunk/${EXTEN:1},,tTo)
exten => _91NXXNXXXXXX,n,Hangup()
Priority 1 Is Not Optional
That first AGI(agi://127.0.0.1:4577/call_log) line is the single most common omission. VICIdial’s call_log AGI is what registers the channel against the dialer’s session tracking. Leave it out and calls may well connect, but the agent screen will hang on Waiting for Ring, dispositions will not save correctly, and your reports will be full of orphaned records.
Put it at priority 1. Always. On every outbound pattern you define.
Pattern Matching
Patterns start with an underscore. Without it, Asterisk treats the string as a literal extension.
| Character | Matches |
|---|---|
X | any digit 0–9 |
Z | any digit 1–9 |
N | any digit 2–9 |
[1-5] | any digit in the range |
[2489] | any digit in the set |
. | one or more of any character |
! | zero or more of any character |
Avoid ! in production. It matches on partial dial and will fire before the full number arrives.
Some worked examples:
_91NXXNXXXXXX
The leading 9 is the VICIdial dial prefix, 1 is the country code, NXX blocks area codes starting 0 or 1.
_9447XXXXXXXXX
_991XXXXXXXXX ; with 91 country code
_9[6-9]XXXXXXXXX ; bare 10-digit starting 6,7,8 or 9
_9X.
Use _9X. while testing, then tighten it. A permissive catch-all on a public-facing box is how people end up with a five-figure toll-fraud bill.
The Dial Prefix and ${EXTEN:1}
Under Admin → Campaigns → Detail → Dial Prefix, VICIdial prepends a digit (default 9) to every number it dials. This exists so the dialer’s traffic is distinguishable from agent extensions and internal features.
Your carrier almost certainly does not want that 9. Strip it with substring syntax:
${EXTEN:1}
This means “skip the first character.” So if the campaign dials 915551234567, the carrier receives 15551234567.
Need to strip two digits and prepend a different prefix?
exten => _9011X.,1,AGI(agi://127.0.0.1:4577/call_log)
exten => _9011X.,n,Dial(SIP/mytrunk/00${EXTEN:4},,tTo)
exten => _9011X.,n,Hangup()
Dial Options You Actually Want
Dial(SIP/mytrunk/${EXTEN:1},,tTo)
The third argument is the options string:
t— allow the called party to transferT— allow the calling party to transfero— preserve the original caller ID on the outbound leg
Add a timeout in the second argument if your carrier is slow to reject:
Dial(SIP/mytrunk/${EXTEN:1},30,tTo)
Thirty seconds is reasonable for most predictive campaigns. Longer and you tie up channels on dead numbers.
Routing Across Multiple Trunks
For failover, chain Dial() steps and test ${DIALSTATUS}:
exten => _9X.,1,AGI(agi://127.0.0.1:4577/call_log)
exten => _9X.,n,Dial(SIP/trunkA/${EXTEN:1},30,tTo)
exten => _9X.,n,GotoIf($["${DIALSTATUS}" = "ANSWER"]?hang)
exten => _9X.,n,Dial(SIP/trunkB/${EXTEN:1},30,tTo)
exten => _9X.,n(hang),Hangup()
For load balancing rather than failover, the cleaner approach is a single carrier entry per trunk with different dial prefixes per campaign, so you can shift volume by editing a campaign rather than a dialplan.
Setting Caller ID
VICIdial normally sets outbound caller ID from the campaign or list. To force it at the dialplan level:
exten => _9X.,1,AGI(agi://127.0.0.1:4577/call_log)
exten => _9X.,n,Set(CALLERID(num)=15551230000)
exten => _9X.,n,Set(CALLERID(name)=Support)
exten => _9X.,n,Dial(SIP/mytrunk/${EXTEN:1},,tTo)
exten => _9X.,n,Hangup()
Most carriers ignore CALLERID(name) on SIP trunks and substitute their own CNAM lookup, so do not spend hours debugging a name that will not stick.
Debugging
Watch a live call:
asterisk -rvvvvv
Then on the CLI:
core set verbose 5
sip set debug peer mytrunk
Useful things to look for:
No such extension in context 'default'— your pattern does not match what VICIdial dialed. Check the dial prefix.chan_sip.c: Failed to authenticate— carrier credentials, not dialplan.- Call connects, agent screen hangs — missing
call_logAGI line.
Check precisely what is being dialed:
tail -f /var/log/asterisk/messages | grep -i "executing"
Turn the debug off when finished. Leaving SIP debug on a busy dialer will fill your disk faster than you expect.
Summary
The Dialplan Entry field is ordinary Asterisk dialplan with three VICIdial-specific rules: the call_log AGI goes at priority 1, the dial prefix needs stripping with ${EXTEN:1}, and edits land via the keepalive script rather than instantly. Get those three right and most “my carrier will not dial” tickets disappear.