Despite what you may be lead to believe after reading up on sending business text messages from 3CX, there is no inherent support for sending text messages with an alphanumeric sender ID, aka one-way SMS.
Why might you want to do this? For multiple reasons really – sending a text with an alphanumeric sender ID means that when the recipient sees the message, the sender is your company name, not a random phone number like +61412345678. Further, if you just want to send notifications to people, but don’t want to initiate a two-way conversation, people can’t reply to text messages with alphanumeric sender IDs.
Whilst 3CX supports sending text messages via your SIP trunk, when you’re using the built-in Twilio provider template, it locks the MessagingUrl field and does not expose it in the UI. Twilio requires a MessagingServiceSid parameter in the POST body to send from an alphanumeric sender ID (e.g. Automatica), which 3CX cannot pass natively.
The solution is a Cloudflare Worker that acts as a translation layer:
3CX → Cloudflare Worker → Twilio API (with MessagingServiceSid) → SMS sent as "Automatica"
A Generic VoIP Provider trunk is used in 3CX instead of the built-in Twilio template, because it exposes an editable Provider URL field on the SMS tab.
Prerequisites
- Twilio account with:
- An SMS-enabled Australian mobile number (the DID)
- An approved alphanumeric sender ID (e.g.
Automatica) - A Messaging Service with the alphanumeric sender ID in the sender pool
- Account SID, Auth Token, and Messaging Service SID
- Cloudflare account (free tier is sufficient)
- 3CX v20 (Pro or Enterprise for Generic trunk SMS support)
Cloudflare Worker
The key to making this all work is the Worker Script which receives the text message from 3CX, inserts the Messaging Service SID and then passes it along to Twilio.
Worker Script
export default {
async fetch(request, env) {
// Validate shared secret
const url = new URL(request.url);
const secret = url.searchParams.get('secret');
if (secret !== env.SECRET_TOKEN) {
return new Response('Unauthorized', { status: 401 });
}
// Parse 3CX request body
const body = await request.json();
const { to, text } = body;
// Build Twilio request
const params = new URLSearchParams();
params.append('To', to);
params.append('MessagingServiceSid', env.MESSAGING_SERVICE_SID);
params.append('Body', text);
// Forward to Twilio
const credentials = btoa(`${env.TWILIO_ACCOUNT_SID}:${env.TWILIO_AUTH_TOKEN}`);
const twilioResponse = await fetch(
`https://api.twilio.com/2010-04-01/Accounts/${env.TWILIO_ACCOUNT_SID}/Messages.json`,
{
method: 'POST',
headers: {
'Authorization': `Basic ${credentials}`,
'Content-Type': 'application/x-www-form-urlencoded',
},
body: params,
}
);
const result = await twilioResponse.json();
if (!twilioResponse.ok) {
return new Response(JSON.stringify(result), {
status: twilioResponse.status,
headers: { 'Content-Type': 'application/json' },
});
}
return new Response(JSON.stringify({ success: true, sid: result.sid }), {
status: 200,
headers: { 'Content-Type': 'application/json' },
});
}
};
Deployment Steps
1. Log in to cloudflare.com
2. Click Workers & Pages → Create → Create Worker
3. Name the Worker (e.g. automatica-sms) and click Deploy
4. Click Edit Code, replace all default code with the script above, click Deploy
Environment Secrets
In the Worker dashboard, go to Settings → Variables and Secrets and add the following as Secret type:
| Secret Name | Value |
|---|---|
SECRET_TOKEN | A strong random string of your choice; e.g. 4caf72c8552b9d9915736b408e8d4485 |
TWILIO_ACCOUNT_SID | Your Twilio Account SID (ACxxxxxxxx...) |
TWILIO_AUTH_TOKEN | Your Twilio Auth Token |
MESSAGING_SERVICE_SID | Your Twilio Messaging Service SID (MGxxxxxxxx...) |
Click Save and Deploy after adding all four.
Test the Worker
Before configuring 3CX, verify end-to-end with curl:
curl 'https://YOUR-WORKER.YOUR-SUBDOMAIN.workers.dev/sms?secret=YOURSECRETTOKEN' \
-X POST \
-H 'Content-Type: application/json' \
-d '{"from":"+61XXXXXXXXX","to":"+61XXXXXXXXX","text":"Test from Worker"}'
Expected response:
{"success":true,"sid":"SMxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}
3CX Configuration
Create a Generic Trunk
1. Admin → Voice & Chat → Add Trunk
2. Country: Worldwide, Provider: Generic VoIP Provider
3. On the General tab, disable inbound and outbound calls if this trunk is SMS-only
4. On the SMS tab:
- Enable SMS
- Provider URL:
https://YOUR-WORKER.YOUR-SUBDOMAIN.workers.dev/sms?secret=SECRET_TOKEN - API Key: any value (not used by the Worker — auth is via the secret token in the URL)
5. On the DID Numbers tab, add your Twilio number in E.164 format (e.g.+61412345678)
6. Save
Assign the DID
Assign the SIP trunk to a user or queue so agents can send SMS from it via the 3CX chat interface.
Maintenance Notes
- If the Twilio Auth Token is rotated, update
TWILIO_AUTH_TOKENin the Worker secrets - The Cloudflare free tier allows 100,000 Worker requests per day — sufficient for any normal SMS volume
- The
SECRET_TOKENvalue must match between the Worker secret and the Provider URL in 3CX — if either is changed, update the other - This is outbound (one-way) SMS only — inbound replies will not route back through this trunk