vicigeeksimple guides
Browse
All guides

Automate tasks · SMS and Omnichannel

Plan an SMS integration for VICIdial

Explore a possible SMS integration using Call URLs, a separate relay and the Non-Agent API. The worksheet describes required controls; it is not a working messaging service.

Reader setup

Before you choose

  1. A VICIdial campaign or in-group already configured with a Start Call URL, Dispo Call URL, or No Agent Call URL — see VICIdial Call URLs: trigger an external system on call events if none of those fields are set yet
  2. An account with an SMS provider that publishes a documented HTTPS API, with its API key available only as an environment variable, never typed into a URL or committed to a script
  3. An API-enabled VICIdial user with modify_leads permission and a user_level of 8 or higher, so update_lead can write the delivery result back onto the lead — see The VICIdial Non-Agent API, with real code for the full permission model
Expected result
You can identify the pieces needed for a test integration and the checks a complete relay must implement; the samples do not establish a working SMS service.
Before making changes
A Call URL puts lead data, including the phone number you are about to text, directly into a URL, and that URL lands in your web server's access logs by default. Pass only an opaque lead identifier in the Call URL itself, keep the phone number and message body inside your own relay, and never put an SMS provider credential or a VICIdial API password anywhere a URL or a log file can capture it.

Understand the integration boundary

Write one example of a customer request and the agent action it requires. For each channel, identify where replies appear, how an opt-out is recorded and who can see the conversation before selecting an integration.

This guide discusses an external SMS provider connected through a Call URL, a separate relay and the Non-Agent API. Check your installed revision and any existing add-ons before concluding which messaging features your system provides.

In plain language: a lead is one contact record — a phone number plus a name, a status, and a call history. A list is a named batch of leads dialed as a unit. A campaign is the calling project that ties one or more lists, a group of agents, and a set of dialing rules together. An agent is the person logged into the agent screen taking or making calls. A disposition is the outcome code an agent, or the dialer itself, assigns when a call ends — SALE, CALLBK, NA, and dozens more. A DID (Direct Inward Dial number) is the phone number a carrier hands an inbound call to before VICIdial routes it anywhere. A carrier is the phone company or SIP trunk provider that connects VICIdial's Asterisk server to the public telephone network for voice calls — and, in this article, it is also the separate wireless network your SMS provider uses to actually put a text on a handset. VICIdial has no relationship with that second network. Your SMS provider does.

The official documents describe chat, Call URLs and the Non-Agent API. They do not by themselves establish whether your deployment has another SMS integration or whether an example relay works.

Trace path · read left to right
01A call ends and VICIdial fires a Dispo, No Agent, or Start Call URL with --A--field--B-- substitution02Your own relay receives the GET, calls your SMS provider's HTTPS API, and gets back a message ID or an error03The relay writes that result onto the lead through the Non-Agent API's update_lead, and a separate provider webhook logs inbound replies the same way
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 · Find Scripts

Open the script workspace

Open to enlarge
Sanitized VICIdial Scripts Listings page showing where agent-visible scripts are managed
Captured September 24, 2026 at 21:53:14 UTC on the authorized isolated demo.
Capture detailsNo scripts are defined for the fixture account, so the listing is empty. It does not show a script execution, CRM exchange, or call result.
Step 2 · Locate URL overrides

Check list-level form and URL fields

Open to enlarge
Sanitized VICIdial list detail page showing list state, reset, time, script, and URL override settings
Captured August 11, 2026 at 16:21:03 UTC on the authorized isolated demo.
Capture detailsThis is list configuration rather than a lead record; it contains no customer row and does not prove a dialing or import result.
Step 3 · See the Agent-side surface

Recognize where the agent sees the workflow

Open to enlarge
Sanitized logged-in VICIdial Agent screen in an idle no-live-call state with blank customer fields
Captured August 11, 2026 at 16:25:04 UTC on the authorized isolated demo.
Capture detailsThis is a real logged-in idle Agent screen with session and system identifiers redacted. Customer fields are blank, and it does not prove a placed, answered, recorded, transferred, or completed call.

What VICIdial actually has for messaging

VICIdial's own chat system is real, and it is entirely web-based, using its own protocol rather than SMS or any external messaging standard. It lets a website visitor chat with an agent through a page you host, an agent chat with another agent, and a manager broadcast to logged-in agents, all inside the same agent screen a phone call would use. Every message is logged and searchable through the Agent-Manager Chat Log in Admin Utilities. A customer types into a browser widget on your website; nothing about it reaches a phone's messaging app.

Email is the second native channel: agent email, disposition email sent on a chosen outcome, and email in-groups that route inbound email to agents the same way an in-group routes inbound calls. All three exist in the shipped source, though whether they are switched on for a given campaign is a separate System Settings question from whether the code exists at all.

The two extension points that make an SMS integration possible are Call URLs and the Non-Agent API, and both already have their own full articles in this library, so this one does not repeat their syntax. VICIdial Call URLs: trigger an external system on call events covers the --A--field--B-- substitution syntax, the difference between a browser-triggered and a webserver-triggered URL, and why every receiver must be idempotent, meaning that handling the same event twice leaves the system in the same state as handling it once. The VICIdial Non-Agent API, with real code covers authentication, per-function permissions, and the exact request shape for reading and writing a lead over HTTP. Read both before wiring up SMS; this article assumes you have.

Put together, that is the entire native toolbox: chat, email, Call URLs, and the Non-Agent API. SMS is what you get when you point a Call URL at your own relay, have that relay call an SMS provider's HTTPS API, and use the Non-Agent API to write the result back onto the lead. Nothing in that chain is a VICIdial feature; every moving part other than the trigger and the write-back belongs to you and your provider.

  • Chat — native, web-based, its own protocol, not SMS
  • Email — native, agent email, disposition email, email in-groups
  • Call URLs — native, an HTTP request fired on a call event
  • Non-Agent API — native, HTTP read and write access to a lead
  • SMS — not native; built from the four rows above plus your own provider

Step 1 — Pick the call event that should trigger a text

Choose the event that actually exists for the intended call mode. Dispo Call URL runs when an agent dispositions a call. No Agent Call URL covers auto-dial/inbound calls not sent to an agent, including configured drop/no-answer/busy/timeout outcomes;it excludes manual calls. Start Call URL also excludes manual calls. A manual unsuccessful attempt cannot be assumed to emit a No Agent callback.

Pick exactly one event per workflow rather than wiring several at once on a first pass. If you only want a text on some dispositions and not others, use the alternate Dispo Call URL mechanism described in VICIdial Call URLs: trigger an external system on call events to scope the URL to specific statuses or lists, instead of filtering inside your own relay after the fact.

Sending a text to a consumer phone number is regulated in most places — get documented consent before the first message and honor an opt-out on every one after it — so confirm the exact rule for your jurisdiction with your own compliance counsel before this goes live, not after.

  1. Write one synthetic event example for the selected row and confirm that this mode can emit it. If unsupported, choose another documented workflow rather than waiting for a nonexistent event.
  2. Use an opaque lead/call identifier in the URL and keep recipient/body/secrets in the relay. Include a verified call identity for deduplication;lead_id+dispo alone can recur across different calls.
  3. In a provider test environment, check one accepted event, one duplicate, an unsupported mode and a timeout. A repeat of the same event must not send again;different calls must not collide.
  4. Keep both source events and provider message IDs in the private ledger so trigger receipt, provider acceptance and delivery are separate states.
Select a documented trigger and payloadScroll sideways to compare columns
EventEligible pathContract to verify
Dispo Call URLAgent-dispositioned call;the appropriate agent outcome workflowlead_id, call identity, dispo, timestamp;configured campaign/in-group/ALT selection.
No Agent Call URLAuto-dial or inbound not sent to agent;not manuallead_id, call identity, status, timestamp;for inbound configure the actual in-group.
Start Call URLCall sent to agent;not manualCall identity and start event;do not label it a completed-call follow-up.

You should seeThe selected trigger has a supported mode and an explicit identity/schema. This is an integration contract, not a claim that a relay or SMS send was executed.

Step 2 — Build a relay that turns the Call URL hit into an SMS send

A Call URL is a plain HTTP GET request with the substituted fields embedded in the query string — there is no request body. Point the campaign's Dispo Call URL at this relay's own address with only lead_id and dispo in the query string — never phone_number: `VARhttps://<RELAY_HOST>/dispo?lead_id=--A--lead_id--B--&dispo=--A--dispo--B--`. The relay calls lead_field_info itself to look the number up before it ever sends a text, exactly the opaque-identifier boundary this article's own safety note promises. Most SMS providers document a POST endpoint that expects a JSON body and an authentication header, not a GET with query parameters. Build a small first-party relay, reachable over HTTPS, that receives the Call URL's GET and re-issues a proper POST to your provider's documented endpoint. This is the same get-to-post reshaping the platform's own guidance recommends for the closely related Agent Events Push mechanism; reuse that pattern here instead of inventing a new one.

Keep the Call URL's query string short and boring. Every value you add becomes part of a URL, and a URL lands in your web server's access logs by default, along with any reverse proxy or monitoring tool sitting in front of it. Pass only what you need to look the lead back up — a lead ID and a disposition code are usually enough — and let the relay itself, not the logged URL, carry the phone number, the message body, and any provider credential.

The checklist below identifies required integration controls. It is not an implementation and does not send messages.

Before you use it
Use this checklist to define and test a relay before connecting real leads.
SMS relay requirements checklist
Before connecting an SMS relay:1. Authenticate incoming events and validate the event schema.2. Confirm recipient consent and check current opt-out status before each send.3. Store a stable event ID and prevent duplicate sends, including after timeouts.4. Distinguish provider acceptance, delivery receipts and failures.5. Test failure, retry, opt-out and duplicate-event paths with synthetic records before any real message.
Not executed · worksheet or reference text

This sample is a template or reading aid, not a terminal command. There is no output to show.

Success looks like
A complete implementation must separately verify permissions, message eligibility, event authentication, idempotency, provider acceptance and delivery receipts using a provider test environment.
Stop if
Do not send a real message if any eligibility, authentication, deduplication or delivery-state check is missing; implement and test those controls first.

Step 3 — Log the delivery result back onto the lead

Once the provider answers with a message ID or an error, write that outcome onto the lead so an agent looking at the record, or a report running later, can see it without checking a second system. update_lead, documented in full in The VICIdial Non-Agent API, with real code, takes a custom_fields=Y flag plus any field name already defined on the lead's list through Admin's custom-fields screen — sms_status and sms_message_id are reasonable names to define once and reuse across every workflow.

update_lead requires an API-enabled VICIdial user with modify_leads permission and a user_level of 8 or higher — a real permission requirement, not a suggestion, and a call from a user missing either one fails with a plain-text error rather than a silent no-op. Search by lead_id where possible; the Call URL already handed you --A--lead_id--B--, and matching on it is faster and less ambiguous than a phone-number or vendor-lead-code search across a whole list or campaign.

If you would rather not define new custom fields for a first pass, the built-in comments field on every lead accepts up to 255 characters and needs no setup at all — write a short summary such as SMS sent id MSG-90142 into it instead. That is simpler to start with and harder to report on cleanly later; move to a real custom field once the workflow is proven.

Before you use it
Run this block as a dedicated reviewed script in the approved root context for the root-owned mode-600 writer file; do not paste strict-mode or exit commands into a shared interactive SSH shell. Create /etc/vicidial-api/writer.cfg once, root:root mode 600, holding the endpoint and this API user's own source/user/pass exactly as The VICIdial Non-Agent API, with real code sets up — never a password on this command line or in shell history.
Write the SMS result onto a lead with curl --config
#!/usr/bin/env bashset -euo pipefail # /etc/vicidial-api/writer.cfg (root:root, mode 600) already holds:#   url = "https://<VICIDIAL_HOST>/vicidial/non_agent_api.php"#   data-urlencode = "source=sms_relay"#   data-urlencode = "user=<API_USER>"#   data-urlencode = "pass=<API_PASS>" curl --fail-with-body --silent --show-error --config /etc/vicidial-api/writer.cfg \  --data-urlencode "function=update_lead" \  --data-urlencode "lead_id=<LEAD_ID>" \  --data-urlencode "custom_fields=Y" \  --data-urlencode "sms_status=SENT" \  --data-urlencode "sms_message_id=MSG-90142" 
Not executed · worksheet or reference text

This sample is a template or reading aid, not a terminal command. There is no output to show.

Success looks like
Check the documented API response and reopen the synthetic lead to verify the intended fields. A successful HTTP status alone does not prove the update applied.
Stop if
Read the API response and check permissions, parameter names and network errors; do not assume all errors have the same cause.

Handle inbound replies the same way, in reverse

The provider owns inbound text delivery. Verify its webhook authenticity and normalized recipient/sender or message-service identity before applying an opt-out. Persist the provider-confirmed STOP state in a recipient-level suppression record before attempting to select a VICIdial lead.

A recipient may occur in several lists or have no unambiguous lead match. Keep suppression effective for the provider/service/sender scope even while the lead mapping is unresolved;send the ambiguous conversation for human review. A lead field can display the state, but is not the only enforcement key.

Before every send, re-check the recipient suppression and current consent in the authoritative ledger. Use provider message/event ID for idempotency;handle verified START/re-consent only through the provider’s documented process and the organization’s policy. Do not remove suppression merely because another lead row has a blank field.

  1. Define the normalized recipient/provider-scope key and its retention/owner before implementation.
  2. Apply verified opt-out first, then update any safely mapped lead display fields.
  3. Test duplicate and ambiguous-recipient cases with provider-approved synthetic events;assert no outbound provider send is attempted.
  4. If any case sends unexpectedly, disable the relay’s send switch, preserve events and suppression ledger, fix the guard and rerun the synthetic suite before re-enabling.
Synthetic opt-out acceptance casesScroll sideways to compare columns
CaseRequired behaviorFailure recovery
One verified STOP, two matching lead rowsRecipient suppressed before matching;both future sends blocked for the defined provider scope.Disable sends for that scope and reconcile any unsuppressed duplicate.
STOP with ambiguous/no lead matchSuppression remains active;conversation sent for review.Do not guess a lead to make the block effective.
Duplicate STOP webhookOne state transition, no duplicate confirmation from the relay.Deduplicate by provider event ID.
Provider accepted earlier messageTrack its actual delivery state separately;STOP blocks subsequent sends.Do not relabel acceptance as delivered.
Unverified webhookNo untrusted state change;alert/review through the approved path.Fix signature/auth validation before reconnecting sends.

The boundaries: no queueing, no retry, no delivery guarantee

Do not build this integration as if VICIdial were a message queue standing behind it. It is not, on either side of the Call URL. If your relay's call to the SMS provider fails outright, VICIdial has already moved on to the next call; nothing on its side notices, retries, or re-queues that failed send.

Delivery and retry behavior varies by event source and installed revision. Do not assume exactly-once delivery or rely on VICIdial to retry a provider send; test duplicates and failures for the actual integration.

There is no ordering guarantee either. Build the relay assuming a call event can arrive once, twice, or with delay, exactly as the Call URLs article requires of any receiver, and never assume a start event arrives before a disposition event for the same call.

Decide up front what happens when the provider call itself fails outright — a network error or a provider 5xx response. Queue it for a bounded retry with your own backoff inside the relay, or drop it and let sms_status = FAILED on the lead be the signal a human follows up on. VICIdial gives you neither option; whichever you pick, you are building it, not configuring it.

  • No SMS queue on failure
  • No automatic retry of a failed provider call
  • No delivery confirmation from a handset
  • No inbound texting endpoint of any kind
  • Idempotent write-back is your responsibility in both directions

Troubleshoot: no text sent, and how to roll back safely

Work through this in order instead of guessing which layer is broken. Three different systems sit between a call ending and a text arriving, and each one fails differently.

If nothing appears to happen at all, confirm the Call URL fired first, using the same checks as VICIdial Call URLs: trigger an external system on call events — the right column on the right campaign or list, and a request landing in your relay's own access log. A Call URL that never fires is a VICIdial configuration problem, not an SMS problem.

If the relay's log shows the Call URL landed but no text goes out, check the relay's own log for the provider's HTTP response next. A non-2xx status there is the SMS provider rejecting the send — a bad phone number, an unverified sender ID, insufficient account balance — and has nothing to do with VICIdial at all.

If the text sends but the lead never shows a result, confirm the update_lead call used a valid lead_id and that the API user actually has modify_leads and a user_level of 8 or higher. A missing permission or a bad credential returns a plain-text error in the response body, not an HTTP failure code, so a check that only looks at the status code will miss it.

If the relay sends a wrong message or changes a wrong lead, disable the integration using its documented stop switch and preserve the prior Call URL value. After correcting the test workflow, restore the intended configuration and verify that unauthorized sends have stopped.

Before you use it
Replace <LEAD_ID> with a real lead_id from your own test call, and confirm <LIST_ID> is the actual list_id that lead belongs to before querying its custom_ table; treat this as a template for your own test call, not a query to run unscoped against a shared server's real leads. 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.
Confirm the delivery result actually landed on the lead
SELECT lead_id, status, comments FROM vicidial_list WHERE lead_id = '<LEAD_ID>';SELECT lead_id, sms_status, sms_message_id FROM custom_<LIST_ID> WHERE lead_id = '<LEAD_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
The first query shows the lead's normal status and comments; the second shows sms_status and sms_message_id populated with the values your relay wrote.
Stop if
An unknown table error on the second query means you guessed the wrong custom_<LIST_ID> table name — confirm the lead's real list_id first, since custom_<LIST_ID> is a naming pattern, not a fixed table name.

Checks and sources

What was checked

  • CHAT_MESSAGING.txt describes VICIdial's chat system as entirely web-based with its own protocol, logged through the Agent-Manager Chat Log, and names no SMS or text-messaging capability anywhere in the document.
  • CALL_URL_FEATURES.txt documents Start Call URL, Dispo Call URL, No Agent Call URL, and the --A--field--B-- substitution syntax used to pass lead data to an external system; a Call URL that uses variables must begin with the literal VAR prefix.
  • NON-AGENT_API.txt documents update_lead, including its modify_leads and user_level 8 permission requirement and its custom_fields=Y flag for writing arbitrary lead fields, and documents lead_field_info, which needs user_level 7 or higher and modify_leads, for reading one named field — such as phone_number — off a lead by lead_id without ever putting it in a Call URL.

Primary references

Sources

  1. Official Chat Messaging documentationVICIdial Group · accessed August 5, 2026
  2. Official Call URL featuresVICIdial Group · accessed August 5, 2026
  3. Official VICIdial Non-Agent API documentVICIdial Group · accessed August 5, 2026
  4. Official Agent Events PushVICIdial Group · accessed August 5, 2026
  5. Provider opt-out state and webhook semanticsTwilio · 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.