vicigeeksimple guides
Browse
All guides

Carriers & SIP · Carrier redundancy

Prepare and verify two VICIdial carrier routes

Prepare two provider-specific routes, choose the right health checks for each trunk, and rehearse a bounded prefix cutover with call evidence and rollback. The retained demo shows inactive/missing example endpoints, not a successful dual-carrier test.

Reader setup

Before you start

  1. An isolated campaign and two approved provider accounts with their actual authentication,number format,caller-ID,media and monitoring requirements.
  2. Native carrier/campaign administration plus an authorized Asterisk shell and root/sudo read-only database context;keep secrets and call identifiers private.
  3. A previously known-good route,owned test destinations,provider capacity for the contingency and a named cutover/rollback operator.
Expected result
A provider-specific two-route plan and an acceptance record showing each completed or unfinished configuration,health,call,cutover and rollback check. A demo configuration listing does not complete those checks.
Before making changes
Never paste a real SIP username, secret, or registration string into a ticket, chat log, or these examples; a leaked SIP credential converts directly into toll fraud, calls placed on your account by someone else. Rehearse the cutover on a low-risk campaign before an outage forces you to do it for the first time.

01 / 07

Choose a manual cutover design before adding automation

This guide uses two distinct outbound patterns:prefix9 selects provider A and prefix8 selects provider B. Both carrier configurations are prepared before an incident. The operator moves only the reviewed campaign/list scope, observes one controlled call and records the actual result.

VICIdial does not provide a generic carrier-health policy that chooses a safe route for every deployment. Custom Asterisk Dialplan Entry fallback or an owned external controller can automate a reviewed policy;that is a separate design. A configured fallback cannot rescue an already-ended call, and repeated attempts may create duplicate calls or charges.

A carrier is a provider;a trunk is its configured connection;a channel is one live call leg. Two trunks can still share the same upstream network, account limit or internet path. Record what is independent and which outage the second route is meant to survive.

  • Define which campaigns/lists and manual paths may move.
  • Confirm provider B has approved destination/caller-ID permissions and contingency capacity.
  • Separate outbound cutover from inbound-number recovery;an outbound prefix does not move an inbound DID.
Trace path · read left to right
01Verify each route independently02Move one reviewed prefix scope03Prove the route and restore deliberately
Reference screenshots 3 images

Reference capture

Reference screens from the demo

Captured on an isolated VICIdial demo: Administration screens on September 24, 2026, and the idle Agent screen on August 11, 2026. Each caption states its own capture time, and every sanitized image helps you recognize a related screen; none proves that this article's call, command, or result occurred.
Step 1 · Locate Carriers

Find carrier administration

Open to enlarge
Sanitized VICIdial Administration menu showing phones, carriers, servers, system settings, and system statuses
Captured September 24, 2026 at 21:34:11 UTC on the authorized isolated demo.
Capture detailsThis menu is a navigation map only; it does not show that any system-wide setting was changed or verified.
Step 2 · Review the carrier list

Open Carrier Listings

Open to enlarge
Sanitized VICIdial Carrier Listings page showing only the stock example carriers
Captured September 24, 2026 at 21:53:32 UTC on the authorized isolated demo.
Capture detailsOnly stock example carrier rows are shown, with addresses replaced and registration values redacted; no real carrier is present. This does not prove registration, routing, audio quality, or a completed call.
Step 3 · Confirm system SIP context

Check the allowed SIP-stack setting

Open to enlarge
Sanitized VICIdial Modify System Settings page showing revision, schema, interface, SIP-stack, and API-related controls
Captured August 11, 2026 at 16:22:08 UTC on the authorized isolated demo.
Capture detailsThis is a read-only view of system-wide settings with no credentials or addresses; it does not prove that a setting was changed or that an API request succeeded.

02 / 07

Record provider facts and save each managed carrier

Use Admin → Carriers to store the carrier Account Entry and separate Dialplan Entry;the installation’s configuration generator loads active records. Preserve the prior values and use the normal supported generation path. Do not hand-edit generated includes.

On this build a new carrier must be reopened before its Active state is deliberately set. Keep it inactive until the provider values, unique endpoint ID, server and pattern are reviewed. A registering trunk and an IP-authenticated trunk can both be valid;registration is required only when the provider’s model calls for it.

The historical row below is PJSIPExample Active N. It establishes an inactive example record only. It does not show either provider ready for cutover.

Before you use it
Run this through your read-only database client for each carrier you want to confirm, replacing <CARRIER_ID> with the one you are checking.
Read-only inspection of a carrier row
SELECT carrier_id, carrier_name, protocol, activeFROM vicidial_server_carriersWHERE carrier_id = '<CARRIER_ID>';
Evidence · ViciBox 12 demo capture · demo values substituted

Captured demo response · 2026-09-24 22:25 UTC. Any filtering, hidden values or test-only data are identified in the capture label. Select Replay transcript to read the recorded output.

Command output line: SELECT carrier_id, carrier_name, protocol, active FROM vicidial_server_carriers WHERE carrier_id = 'PJSIPExample';
+--------------+---------------+----------+--------+
| carrier_id | carrier_name | protocol | active |
+--------------+---------------+----------+--------+
| PJSIPExample | PJSIP Example | PJSIP | N |
+--------------+---------------+----------+--------+
Success looks like
The row shows the selected ID, protocol and actual saved Active state. N is incomplete readiness, not a successful route.
Stop if
Missing or unexpected values require inspecting the native saved record. Do not activate or cut over until the provider-specific preflight is complete.
Fill from the actual provider and installationScroll sideways to compare columns
Required factProvider AProvider B
Unique carrier ID / assigned serverPrivate reviewed ID and dialerDifferent reviewed ID;its intended dialer.
AuthenticationIP ACL, registration and/or credentials as actually requiredIts independently reviewed model;do not copy A’s secret.
Signaling / transport / mediaCurrent host, port, TLS policy and allowed source/media rangesCurrent provider-published resiliency ranges and transport.
Number / caller ID / DTMFPermitted format and authorized identity;provider DTMF methodVerify separately;do not assume A’s rules.
Limits / healthChannels, CPS, approved OPTIONS behavior and test destinationContingency capacity plus model-specific health.
  • Save, reopen and compare only the intended carrier values.
  • Keep private credentials out of captures and diagnostics.
  • Leave an accepted standby route available according to its model;do not add registration merely to satisfy a generic checklist.

03 / 07

The Dial Prefix, Not a Carrier Field on the Campaign, Decides the Route

For this narrow NANP illustration, provider A owns _91NXXNXXXXXX and provider B owns _81NXXNXXXXXX. Each Account Entry names its own real endpoint;its Dialplan Entry retains the call_log AGI and strips exactly the one access-prefix digit before applying that provider’s required destination format. This pattern is not an international or internal-extension recipe.

Check the campaign Dial Prefix and Manual Dial Prefix, list Dial Prefix Override, phone code, Omit Phone Code and the effective dialplan match. A saved campaign prefix alone cannot establish which route a manual/list override actually uses.

Illustrative digits only:9+1+2025550123 gives912025550123;the B form starts812025550123. These fictional numbers must not be dialed. Use an owned/provider-approved destination in a separately authorized acceptance test.

  1. Write each exact pattern and endpoint next to its carrier ID in the change record. Open the saved Dialplan Entry and verify the effective loaded match on the assigned server.
  2. Identify the actual path:campaign automatic dialing, list override or manual prefix. Select one path for the first rehearsal;record every field that path reads.
  3. Change the campaign/list prefix only through native Admin after both routes independently pass acceptance. Verify a new actual call’s route;do not infer session refresh timing from a saved field.
Before you use it
Run this through your read-only client before and after any Dial Prefix change; replace <CAMPAIGN_ID> with the real campaign_id.
Read-only check of a campaign's current route
SELECT campaign_id, campaign_name, dial_prefix, activeFROM vicidial_campaignsWHERE campaign_id = '<CAMPAIGN_ID>';
Evidence · ViciBox 12 demo capture · demo values substituted

Captured demo response · 2026-09-24 22:25 UTC. Any filtering, hidden values or test-only data are identified in the capture label. Select Replay transcript to read the recorded output.

Command output line: SELECT campaign_id, campaign_name, dial_prefix, active FROM vicidial_campaigns WHERE campaign_id = 'KPISYN1';
+-------------+------------------------+-------------+--------+
| campaign_id | campaign_name | dial_prefix | active |
+-------------+------------------------+-------------+--------+
| KPISYN1 | KPI synthetic campaign | 9 | Y |
+-------------+------------------------+-------------+--------+
Success looks like
dial_prefix shows the value you expect for the carrier that campaign should currently be using.
Stop if
Stop and recheck Admin if dial_prefix still shows the old value after a save, or if it matches neither carrier's dialplan pattern.
  • Distinct patterns do not replace a provider-specific Account Entry.
  • Inspect exact constructed digits and effective context before any test.
  • Keep manual/list overrides in the cutover and rollback record.

04 / 07

Build the second route and complete model-specific acceptance

Follow the linked native carrier guide for provider B using its actual reviewed configuration. Set the assigned dialer and a unique ID/pattern;record the initial state. After the authorized save/activation, let managed generation finish and inspect the intended endpoint, AoR and exact route.

The retained historical CLI below returned Unable to find object for both example endpoints. It is a useful missing/inactive state, not a dual-active readiness check. The fixed external-zone query is also historical;your own source/interface zones and complete policy must be reviewed.

  1. Collect provider B’s facts from the intake table;save its Account Entry and separate exact pattern. Reopen to verify before activation.
  2. Activate only under the approved change;inspect generation errors and the loaded endpoint/AoR and effective route. Stop if the loaded values differ.
  3. Review both host and upstream source/protocol/port/media policy with the network owner. A broad trusted source zone may admit management services too;do not add a provider to such a zone as if it were a SIP-only rule.
  4. Apply the health row below that matches the provider’s model. If OPTIONS is disabled or unsupported, record that state;do not demand Avail or invent a registration.
  5. In a separately approved test window, verify one owned destination on each route:actual next hop, answer, two-way media, hangup and the matching call/provider records. Record failed/unperformed items and leave that route unavailable for cutover until resolved.
Before you use it
Run these after both carriers are active; replace <CARRIER_ID> and <BACKUP_CARRIER_ID> with your real carrier_id values.
Read-only endpoint and firewall check for both carriers
asterisk -rx 'pjsip show endpoint <CARRIER_ID>'asterisk -rx 'pjsip show endpoint <BACKUP_CARRIER_ID>'asterisk -rx 'pjsip show contacts' | grep -E '<CARRIER_ID>|<BACKUP_CARRIER_ID>'if firewall-cmd --state >/dev/null 2>&1; then  firewall-cmd --zone=external --list-services  firewall-cmd --info-service=asteriskelif command -v VB-firewall >/dev/null 2>&1; then  echo "VB-firewall detected - see 'VB-firewall --help'; it loads the external zone's whitelist at runtime and has no status subcommand of its own"elif command -v ufw >/dev/null 2>&1; then  ufw statuselse  iptables -L -nfi
Evidence · ViciBox 12 demo capture · demo values substituted

Captured demo response · 2026-09-24 22:25 UTC. Any filtering, hidden values or test-only data are identified in the capture label. Select Replay transcript to read the recorded output.

Command output line: asterisk -rx 'pjsip show endpoint PJSIPExample' asterisk -rx 'pjsip show endpoint PJSIPWIZExample' asterisk -rx 'pjsip show contacts' | grep -E 'PJSIPExample|PJSIPWIZExample' if firewall-cmd --state >/dev/null 2>&1; then firewall-cmd --zone=external --list-services firewall-cmd --info-service=asterisk elif command -v VB-firewall >/dev/null 2>&1; then echo "VB-firewall detected - see 'VB-firewall --help'; it loads the external zone's whitelist at runtime and has no status subcommand of its own" elif command -v ufw >/dev/null 2>&1; then ufw status else iptables -L -n fi
Unable to find object PJSIPExample.
Unable to find object PJSIPWIZExample.
apache2 apache2-ssl asterisk dhcpv6-client rtp ssh
asterisk
ports: 5060/udp 4569/udp 8089/tcp
protocols:
source-ports:
modules:
destination:
includes:
helpers:
Success looks like
The capture is interpreted literally:both example endpoints were missing. For your completed preflight, loaded objects, model-specific checks and independently observed test calls must agree.
Stop if
Missing objects after the intended active generation require checking saved state/load errors. Unavail matters only with expected qualification;NonQual is not interchangeable with failed registration.
Health evidence depends on the trunk modelScroll sideways to compare columns
ModelPreliminary checkAcceptance still required
Provider requires outbound registrationActual configured registration and authenticated successRegistration alone does not prove destination routing/audio.
IP-authenticated or non-registering trunkLoaded endpoint/AoR and required source authorization;no registration expectedOne authorized completed call and its actual route.
Approved OPTIONS qualification enabledConfigured qualify_frequency plus expected contact status over successive intervalsOPTIONS can succeed while calls fail.
Qualification disabled/unsupportedNonQual or absent qualify evidence may be expectedUse provider-supported health plus controlled call evidence;no universal Avail gate.

Create the provider-specific carrier

Map the complete access policy

  • No missing endpoint accepted as a working standby.
  • No registration requirement invented for a non-registering trunk.
  • No broad source-zone allowlist mistaken for SIP-only access.

05 / 07

Validate the local status mapping before declaring an outage

Keep three vocabularies separate:the Asterisk Dial() result, the status stored by the installed carrier-log writer, and the VICIdial call disposition. CHANUNAVAIL, CONGESTION and NOANSWER are Asterisk result names;NA is a VICIdial outcome. Do not assume that a carrier-log field has either vocabulary until you inspect the installed mapping and known calls.

Use a bounded interval of known routed calls. Compare stored dialstatus, SIP cause, answered_time meaning, provider result and model-specific health. A string cluster alone cannot establish a dead carrier;account permissions, capacity, DNS and downstream failures can produce similar symptoms.

Before you use it
Use an authorized root/sudo read-only SQL session. Replace all placeholders and validate the channel-prefix scope against known calls first;overlapping endpoint names can match unrelated routes. Keep real call identifiers private. Open the approved client with sudo mysql --defaults-file=/etc/vicidial-readonly.cnf and confirm SELECT CURRENT_USER(), DATABASE() before entering this scoped SQL. Do not widen the credential-file permissions.
Inspect the observed carrier-log vocabulary before mapping it
SELECT dialstatus,sip_hangup_cause,COUNT(*) AS observed_rowsFROM vicidial_carrier_logWHERE call_date >= '<START_SERVER_TIME>' AND call_date < '<END_SERVER_TIME>' AND channel LIKE '<VALIDATED_CHANNEL_PREFIX>%'GROUP BY dialstatus,sip_hangup_causeORDER BY observed_rows DESC;
Reader-run example · not executed for this guide

This example has no recorded result here. Follow its preparation, expected result and stop conditions before using it.

Success looks like
The result inventories actual stored values for that interval. Match them to known permitted calls and the installed log writer/provider evidence before defining an alert.
Stop if
No rows or an unvalidated prefix means the scope is unresolved, not a healthy carrier. Unknown mappings or conflicting provider evidence stop the automated cutover decision.
A failure worksheet rather than an assumed status translationScroll sideways to compare columns
EvidenceRecordDecision
Model-specific healthRegistration if required;OPTIONS only if configured/supportedA preliminary signal, not a complete call test.
Known call mappingCall ID, time, stored carrier status, SIP cause, provider responseUnresolved translation means UNKNOWN.
Failure patternSeveral comparable approved attempts and same failure boundaryDo not create extra customer attempts merely to obtain a pattern.
Cutover decisionOwner, scope, known-good B acceptance and reasonOnly a reviewed policy can authorize moving traffic.
  • Do not compare carrier-log dialstatus to NA without a verified local mapping.
  • Separate a missing endpoint from a loaded but failing route.
  • Preserve observations and route scope before changing a prefix.

06 / 07

Step 3 — Fail Traffic Over to the Carrier That Is Still Working

This manual cutover is a policy you own. Custom Dialplan Entry fallback is possible, but it has separate provider/status/duplicate-attempt requirements described in the LCR guide;it is not established by this two-prefix example.

Move one narrow reviewed scope at a time after B’s independent acceptance. A field change alone does not establish when a running session picks it up or where the next call went. Verify both saved state and a controlled new call before moving further traffic.

  1. Pause/stop new work for the approved test scope using the local procedure. Record affected campaign/list IDs, original campaign/manual/list prefixes and the current active-session state. Do not leave untracked in-flight work.
  2. Open the exact native campaign/list record. For the path under test, change the recorded A prefix to the reviewed B prefix;save/reopen and compare every affected field.
  3. If the installed Agent/session caches that setting, use its documented paused refresh/relogin procedure under the test plan. Do not assume immediate uptake or refresh a live call.
  4. Place only the separately approved controlled test. Match the effective digits/endpoint/provider ID, answer, audio and hangup to B. If any boundary fails, stop the scope and restore the recorded values rather than moving more campaigns.
  5. After acceptance, move additional approved scopes individually and maintain the exact rollback list. Leave unrelated paths unchanged.
Before you use it
Run this through your read-only client immediately after changing Dial Prefix on every affected campaign, replacing the placeholder list with your own affected campaign_id values. Open the approved client with sudo mysql --defaults-file=/etc/vicidial-readonly.cnf and confirm SELECT CURRENT_USER(), DATABASE() before entering this scoped SQL. Do not widen the credential-file permissions.
Read-only confirmation after the cutover
SELECT campaign_id, dial_prefixFROM vicidial_campaignsWHERE campaign_id IN ('<CAMPAIGN_ID_1>','<CAMPAIGN_ID_2>','<CAMPAIGN_ID_3>')ORDER BY campaign_id;
Reader-run example · not executed for this guide

This example has no recorded result here. Follow its preparation, expected result and stop conditions before using it.

Success looks like
Returned rows confirm stored prefix values only. The new call/provider evidence establishes the effective route.
Stop if
Any missing or unchanged row stops expansion. Restore the recorded values and verify the previous route if acceptance fails.

Review a custom conditional Dial() fallback

  • Saved values and actual route are separate checks.
  • No untested standby receives full campaign traffic.
  • Record every moved scope;do not reconstruct rollback from memory.

07 / 07

Restore deliberately and retain the failed boundary

If B fails, keep the affected scope stopped while its first failed boundary is investigated. A prefix typo, stale manual/list/session value, wrong destination format, provider rejection or media failure needs a different correction. Do not keep increasing traffic to discover which one applies.

Return to A only after its model-specific health and a separately approved call acceptance pass. Restore the exact campaign/manual/list values through native Admin, save/reopen and verify the actual route. Avail is a condition only when qualification is part of that trunk’s approved model.

If neither route is accepted, keep new dialing stopped and escalate with the time, scope, route evidence and current rollback state. Outbound-prefix changes do not repair inbound DID delivery or a shared upstream failure.

Close the cutover recordScroll sideways to compare columns
BoundaryRequired recordIncomplete result
ConfigurationBefore/after carrier and all path-specific prefix valuesMissing identity or unknown session uptake.
Route acceptanceActual endpoint/provider ID plus answer/media/hangup/loggingOPTIONS or saved form only.
RollbackExact original values restored and previous route observedA save without a route check.
Evidence scopeChecks performed, failures and unperformed checksNo dual-provider success inferred from the old missing-object capture.
  • Pause/stop before retrying an unexplained failure.
  • Restore only the recorded changed scope.
  • Keep configuration, call acceptance and provider outage claims distinct.

Checks and sources

What was checked

  • The retained historical carrier row is inactive and both endpoint lookups report missing objects. These observations demonstrate incomplete preflight states only.
  • The two-prefix design and model-specific acceptance steps are source-reviewed. No dual-active provider test,cutover,rollback or uptime result was executed for this article.
  • Changed status-inventory SQL has no execution capture. Stored carrier-log values require local writer/call/provider mapping;no universal NA↔DIALSTATUS translation is asserted.

Primary references

Sources

  1. VICIdial PJSIP SupportVICIdial · accessed August 5, 2026
  2. Configuring res_pjsip (Asterisk PJSIP channel driver)Asterisk · accessed August 5, 2026
  3. RFC 3261: SIP: Session Initiation ProtocolIETF · accessed August 5, 2026
  4. RFC 3550: RTP: A Transport Protocol for Real-Time ApplicationsIETF · accessed August 5, 2026
  5. PJSIP qualification settingsAsterisk · accessed November 7, 2026
  6. Asterisk Dial result vocabularyAsterisk · accessed November 7, 2026
  7. Non-registering trunk and provider requirementsTwilio · accessed November 7, 2026

Follow without guesswork

Get the next article

RSS is live now. Email delivery below is an explicit local preview and sends nothing.Open the RSS feed
Email preview only. The address stays in this browser and is never transmitted.