Learn the SMS gateway & SMS marketing plugin
This is the manual for the SwarmSMS Plugin for WordPress; the same text is built into the plugin under SwarmSMS → Instructions. Using SwarmSMS Cloud? Its API docs and quick start are inside your dashboard.
📦 Get started
Install the plugin and app, activate your license and send your first SMS.
📚 Guides & tutorials
Step-by-step posts: campaigns, OTP login, push, AI/MCP and compliance.
Quick start
SwarmSMS is an SMS gateway and SMS marketing system for your WordPress site, running on your own Android phones: send and receive texts, run marketing campaigns, react to form submissions and orders, log users in with a code, and let AI tools operate it. Your messages go out through your own phone's SIM plan — there is no per-message fee from this plugin.
- Set the basics — Settings: country code (e.g.
61for Australia), business name. - Install the app on an Android phone — APK tab (download link / QR / email / text it to the phone).
- Pair the phone — Devices → Generate pairing code → scan the QR in the app → tap the gateway switch on.
- Send a test — Send & Log → type your own number and a message → Send. It appears in the phone's activity list and your log shows delivered.
- Optional but recommended: set up instant delivery so messages leave in about a second instead of up to 15.
Your site should use HTTPS: device keys and message contents travel between the phone and the site.
Connecting phones
Each phone is a device with its own key. Pair as many as you like; they share the work (see failover).
- Pair: Devices → Generate pairing code. The code is single-use and expires in 10 minutes. In the app tap Scan QR code (or enter the server URL + code manually).
- Daily limit: cap how many texts a phone sends per day (carriers often limit SIM plans). Blank/0 = unlimited. When a phone reaches its limit, new messages use another phone.
- Disable / remove: a disabled phone gets no new messages; queued ones move to another phone.
- Keep it running: allow background activity in the app and set the battery to Unrestricted (Samsung: Settings → Apps → the app → Battery). Keep the phone on power and online.
- Dual SIM: in the app Settings → SMS → SIM for sending choose which SIM sends.
- One phone, up to 25 websites (Agency plan): the app can be paired to up to 25 sites at once (app version 3.1 or newer; every site involved needs an Agency licence — a site on another plan is told to upgrade and sends nothing while the phone is shared). In the app tap Add another website and scan that site’s pairing QR code. Each site sees the phone as its own device with its own key and daily limit, and the app sends for all of them, spacing messages out across sites. An incoming reply goes to the site that last texted that number; a message from an unknown number goes to every site that has Receive SMS switched on (it is a per-site switch). For instant delivery on every site, use the same Firebase project on each; a site on a different project is still checked every few seconds.
Instant delivery (Firebase push)
Instant delivery is part of the Agency plan.
By default phones check the site every ~15 seconds. Firebase Cloud Messaging (FCM) is free and unlimited and lets the site wake the phone the instant a message is queued. Polling remains as a safety net.
One-time setup (about 5 minutes, no coding):
- Go to console.firebase.google.com → Add project (free Spark plan; Analytics not needed).
- In the project: Project settings → General → Your apps → Add app → Android. Package name:
com.swarmsms.app. Register, then download google-services.json. - Project settings → Service accounts → Generate new private key → downloads a JSON file.
- Open Devices → Instant delivery, paste the contents of both files, and save. Phones pick up the configuration on their next check-in — no app rebuild or re-pairing.
- Use Send test push next to a phone to confirm. The Devices list shows a “push” tick per phone.
The service-account file is a secret: it lets the site send pushes for your Firebase project. It is stored in your WordPress database and never shown again.
Sending & scheduling
- Send & Log: type numbers (commas or new lines;
0400 111 222is fine), or tick a list to broadcast to subscribers. Use the template menu, merge tags and the live SMS segment counter. - Schedule: set Send at (site time zone). The message waits in the queue and goes out when due.
- Statuses:
pending→dispatched(phone has it) →sent→delivered; orfailed/cancelled. Pending messages can be cancelled; failed ones retried from Logs → Messages. - Merge tags:
{first_name|there}(with a fallback),{last_name},{name},{phone},{business},{link},{discount_code}. - Spintax:
{{Hi|Hello|Hey}} {first_name|there}picks one option at random per message, so bulk messages are not identical. - Templates: save reusable messages in the Templates tab.
- Message gap: the phone waits a few seconds between texts (Settings → Gap) so carriers don't see a burst.
Conversations (inbox)
Every text a phone receives appears in Conversations, grouped by number, with an unread badge in the menu. Click a conversation to read it and reply (from the same phone by default). Incoming texts also fire webhooks, the wpsg_message_received action, and your keyword rules.
Alphanumeric senders (banks, carriers) are shown but can't be replied to and never get automatic replies.
Contacts, lists & consent
Each contact has a status:
- Subscribed — agreed to marketing texts. The only status campaigns send to.
- Pending — double opt-in: waiting for them to reply
YES. - Unsubscribed — texted STOP. Never texted by automated sends again; imports and forms can't resubscribe them — only an explicit
STARTtext (or you, in the admin) can. - Blocked — admin-blocked. None — known number without marketing consent (e.g. a contact-form sender): transactional texts only.
Adding people: the Add a contact form (requires a consent tick), CSV import (Contacts → Import; header columns phone, first_name, last_name, email; you must confirm they gave permission), the [wpsg_subscribe lists="1"] sign-up shortcode, the WooCommerce checkout opt-in checkbox, automations, or the API. Every subscriber records where and when they consented.
Lists group contacts (Contacts → Lists). Turn on double opt-in in Settings if you want confirmation texts.
Campaigns (drip & broadcast)
A campaign is one or more messages. Each step's delay is counted from when the previous message was sent to that person.
Example: offer now, reminder 3 days later
- Campaigns → New campaign, type Broadcast, audience: your list.
- Step 1 — send
0minutes after start:Hi {first_name|there}, 20% off massages this week: {link} - + Add another message — Step 2 — send
3days after the previous message:Last chance {first_name|there}! Your 20% off ends tomorrow: {link} - Set an End date. Nothing is ever sent after it; a follow-up that would land after it is never sent.
- Save & start. Use Send a test first to preview on your own phone.
- Broadcast captures the audience when it starts. Drip lets people keep joining (e.g. a welcome series that starts when someone joins a list — set Auto-enrol when joining list).
- Safeguards: only subscribed contacts; opted-out numbers re-checked before every send; sending-hours window (Settings; default 9am–8pm Mon–Sat); rate limit (messages/minute); the opt-out line; stop if they reply.
- Links:
{link}is a short tracked link per person (clicks, UTM tags). With WooCommerce, a campaign can create and auto-apply a coupon ({discount_code}). - Controls: pause, resume, stop (cancels unsent messages), duplicate. The report shows per-step delivery and every person's progress.
Automations (forms & WooCommerce)
Automations do something when an event happens. Triggers: Contact Form 7, Gravity Forms, WPForms, Elementor Pro Forms, Ninja Forms, Fluent Forms, WooCommerce order status, or custom code. Actions: send an SMS (immediately, delayed, or to your staff), add to a list, or enrol in a campaign.
Field mapping: tell the automation which form field holds the phone number, name, email and the consent checkbox.
| Plugin | Field key to type |
|---|---|
| Contact Form 7 | the field name, e.g. your-phone from [tel* your-phone] |
| Gravity Forms | the field ID (3, 1.3) or its label |
| WPForms | the field ID or label |
| Elementor Pro Forms | the field ID (Advanced tab) or label; the form is matched by its Form Name |
| Ninja Forms | the field key or label |
| Fluent Forms | the input name |
Examples
- Thank-you text: trigger = your form, action = Send an SMS to the person:
Thanks {first_name}, we got your enquiry and will reply soon. - Staff alert: action = Send an SMS to specific number(s):
New enquiry from {field:your-name}: {field:your-message} - Subscribe from a form: add a checkbox “I agree to receive SMS”, set it as the Consent field, action = Add to list. Without the ticked box nothing is added — marketing always needs consent.
- Order updates: trigger = WooCommerce, order becomes
processing:Order #{order_number} ({order_total}) is confirmed, {first_name}!Tags:order_id, order_number, order_total, order_status, order_items, order_url.
Every form field is available as {field:key}. Delays are supported (“send 2 hours after”). The same order/status is never texted twice.
Auto-replies & keywords
When a text arrives, the plugin checks, in order: the built-in compliance words, then your Auto-replies rules (lowest priority number first, first match wins), then the optional fallback reply.
- Built in:
STOP, STOPALL, UNSUBSCRIBE, CANCEL, END, QUIT, OPTOUTunsubscribe the sender;START, UNSTOP, SUBSCRIBEresubscribe;HELPsends your help text;YESconfirms double opt-in. Edit the reply texts in Settings. - Your rules: keywords can match exactly, at the start, as a whole word anywhere, or by regular expression. Each rule can reply and run actions: subscribe/unsubscribe, add/remove from a list, enrol in a campaign, alert you by SMS or email. A cooldown stops repeat replies.
- Fallback: “thanks, we'll reply soon” always, or only outside business hours (Settings).
- Safety: max N automatic replies per number per hour (loop protection).
OTP login & two-factor
OTP & Login uses your phones to deliver one-time codes.
- Log in with an SMS code: turn it on, then add
[wpsg_otp_login]to any page, or use the link on the normal login screen. Users are matched by their profile Mobile number (or WooCommerce billing phone). Optionally allow new visitors to register with just a phone number (never as administrator). - SMS two-factor: after the password step, chosen roles (default: administrators) must enter a code. Users need a mobile number on their profile; users without one aren't challenged. If no phone is connected, login falls back to password-only so you can't be locked out. Emergency off-switch: add
define('WPSG_DISABLE_2FA', true);towp-config.php. - For developers / other apps:
wpsg_otp_send($phone, 'checkout')andwpsg_otp_verify($phone, $code, 'checkout'), or the REST endpointsPOST /otp/sendandPOST /otp/verify(API key). - Protection: codes are random, stored hashed, expire (default 5 minutes), allow 5 tries, and are rate-limited per number, per IP and site-wide. OTP texts jump the queue. Login never reveals whether a number has an account.
Multiple phones & failover
With two or more phones, new messages go to the online phone with the shortest queue and under its daily limit. If a phone goes offline (no check-in for N minutes) or hits its limit, its waiting messages move to another phone automatically. If a send fails on one phone, it is retried once on a different phone. Messages are never moved onto another dead phone, and a message already handed to a phone is never re-sent (to avoid duplicates). Tune it under Settings → Failover.
Twilio delivery (fallback or only)
Your phones are the main way SwarmSMS sends. Twilio (a paid SMS service) can back them up, or replace them. Choose under Settings → Delivery:
- Devices only (default): every message is sent by your Android phones.
- Devices and Twilio: phones first. If every phone is offline (or none can take the message), Twilio sends instead — a last resort, so you pay Twilio only when your phones can’t do the job.
- Twilio only: every message goes through Twilio. No phone is needed.
Set it up (about 5 minutes)
- In the Twilio console copy your Account SID and Auth Token, and buy (or choose) a Twilio phone number — or create a Messaging Service.
- In Settings → Delivery pick a mode and paste the Account SID, Auth Token and the number (international format, e.g.
+61400111222) or the Messaging Service SID (starts withMG). The Auth Token is stored in your database and never shown again; leave the field blank to keep it. - Save, then use Send a test via Twilio to check it works.
- To receive replies to your Twilio number, open the number in Twilio → Messaging → A message comes in → Webhook (HTTP POST) and paste the URL shown in Settings. Delivery reports need no set-up: every message carries its own status callback.
How the last-resort fallback works
- A new message goes to Twilio at once when no phone is online (or all online phones are at their daily limit).
- A message already waiting for a phone moves to Twilio after the wait before falling back time (default 90 seconds) if still no phone is online. If any phone is online, messages stay with the phones (and normal failover applies).
- If a phone reports a hard failure and no other phone can retry it, the message is handed to Twilio once.
- Messages show Twilio in the Logs and a
channelin the REST API. Status moves to sent then delivered (or failed with Twilio’s error code) as Twilio reports back. - Replies that arrive on a Twilio number are answered through Twilio (including the automatic STOP / HELP replies).
Good to know
- You pay Twilio per message and any number rental; phone sending costs nothing extra. Twilio trial accounts can only text verified numbers, and countries such as the US need number registration (A2P 10DLC) — see Twilio’s docs.
- Opt-outs and consent are always honoured. If someone replies STOP to your Twilio number, Twilio blocks further texts (error 21610) and SwarmSMS marks the contact unsubscribed everywhere.
- Login codes (OTP), replies and API messages leave immediately; campaign messages are sent in batches of up to 60 a minute.
- While every phone is offline in Devices and Twilio mode you cannot receive texts sent to your phone numbers (Twilio only covers sending, and replies to its own number).
- Twilio delivery is part of the Pro and Agency plans. Without a license (or without complete Twilio details) SwarmSMS simply uses your phones.
Device stats & logs
- Dashboard: today's numbers, 7-day delivery, queue, phones online, warnings (offline phones, no HTTPS, high failure rate).
- Device stats: per phone — sent, delivered, failed, received, success and delivery rates, average delivery time, battery, app version, push status and a daily chart. Switch between 7 / 30 / 90 days.
- Logs: Messages (every text, with filters, retry/cancel and CSV export), Activity (campaign starts, failovers, automation runs, skipped sends, errors), Webhooks (every delivery with its HTTP status), OTP (codes sent, numbers masked).
Alerts (offline, low battery)
Get an email and/or SMS when something needs attention — configured under Alerts:
- a phone goes offline (after N minutes without a check-in) and when it comes back;
- a phone's battery falls to your chosen level (default 5%);
- all phones offline at once; a phone hits its daily limit; a phone is failing most messages; messages are stuck in the queue.
You get one alert when a problem starts, a reminder every few hours while it lasts, and a “fixed” notice. SMS alerts are sent from a different phone than the one with the problem; if no other phone is online you still get the email. Active alerts also show on the Dashboard. Use Send a test alert to check your settings. Offline detection needs WP-Cron (or other phones checking in) to be running.
The Android app (APK)
Uploading your own white-label app is part of the Agency plan.
The APK tab hosts the Android app for your phones: a download link (http://127.0.0.1:9500/wpsg-app/) with QR code, buttons to email the link or text it to a phone, and an upload box to replace the app (for example with your own branded build).
- On the phone open the link and download the file.
- Allow Install unknown apps for the browser/Files app when Android asks.
- Open SwarmSMS, allow SMS and notifications, then pair (scan the QR on the Devices tab).
Sideloading is expected: Google Play restricts apps that read and send SMS. The app can check for updates (Settings → Check for updates) against your site.
REST API & webhooks
Create an API key under API & Webhooks (full access, or read-only). Send it as X-API-Key: KEY or Authorization: Bearer KEY. Base URL: http://127.0.0.1:9500/wp-json/wpsg/v1
curl -X POST "http://127.0.0.1:9500/wp-json/wpsg/v1/sms/send" -H "X-API-Key: KEY" -H "Content-Type: application/json" \
-d '{"recipients":["0400111222"],"message":"Hello","send_at":"2026-12-01T09:00:00+10:00"}'
Endpoints: /sms/send /sms/messages /sms/messages/{id}/cancel /devices /contacts /contacts/unsubscribe /lists /campaigns /campaigns/{id}/enroll|pause|resume /otp/send /otp/verify.
Webhooks: set a URL (and optional secret) — you receive JSON for MESSAGE_RECEIVED and MESSAGE_STATUS. With a secret, verify the X-WPSG-Signature: sha256=… HMAC of the raw body. Each delivery is logged under Logs → Webhooks.
AI / MCP connection
The MCP server is part of the Agency plan.
The MCP tab turns the gateway into a tool for AI assistants (Claude Code, OpenAI Codex, Claude Desktop, Cursor, VS Code…). Ask in plain English: “how did last week's campaign do?”, “text Sam that the order shipped”, “create a 2-step campaign for the VIP list”.
- Switch the MCP server on and create a key (full to let the AI send/modify, read-only to let it look but not touch).
- Copy the ready-made command or config for your tool from the tab.
Tools: account summary, send SMS, list/get messages, devices & device stats, contacts (add requires consent), unsubscribe, lists, campaigns (create, stats, pause/resume/stop). OTP codes are never exposed to AI tools. Treat the key like a password.
Compliance & best practice
The plugin helps you stay compliant but you are responsible for the laws that apply to you (e.g. Australia's Spam Act 2003 / ACMA, US TCPA, GDPR/PECR).
- Only text people who agreed. Record consent (the plugin stores source and time). Don't buy lists.
- Identify your business and give an easy opt-out (“Reply STOP”) — added automatically to marketing messages.
- Respect sending hours (configurable). Honour STOP immediately — the plugin does, everywhere.
- Carriers watch for spam from consumer SIMs: use the gap between messages, rate limit, daily limits per phone, and several phones for big lists.
License & plans
SwarmSMS is sold as an annual subscription: Basic (1 site, up to 2 phones) Pro (5 sites, unlimited phones, failover, Twilio fallback, drip sequences, automations and OTP/2FA) and Agency (25 sites, everything in Pro, plus instant Firebase push, the AI/MCP connection, WooCommerce coupons, the white-label app and one phone paired to up to 25 websites at once). Open License, paste the key from your SwarmSMS account and click Activate. Compare plans on the License tab.
After the first year SwarmSMS and the Android app keep working with every feature in your plan — you simply stop receiving updates and support until you renew (the License tab and dashboard show a notice). A refunded purchase is different: it ends the license and the plugin returns to trial mode. Activating on a new site needs an active subscription.
- 1-day free trial (no key): every feature is unlocked for 24 hours from the first time the plugin runs. After that, without a license, only the basics remain: 1 phone, 10 messages a day and 100 contacts; campaigns, automations and every premium feature are paused until you activate a license. Your data is kept.
- Updates appear on the normal WordPress Plugins → Updates screen while your subscription is active.
- Moving sites: use Deactivate on this site, then activate on the new site. Each key has a limited number of site activations.
- If a purchase is refunded the license ends and the plugin drops to the basic after-trial limits; your data is kept. STOP / opt-out handling always keeps working.
- If your host blocks outgoing requests, the license check may fail; the plugin keeps your last known plan for 7 days.
Troubleshooting
| Can’t install the app | Turn off Google Play Protect scanning: open the Play Store, tap your profile icon (top right), choose Play Protect → Settings and switch Scan apps with Play Protect off. Then install the APK again (you can turn it back on afterwards). |
|---|---|
| Can’t pair the phone | Allow the SMS permission when the app asks. On Android 15 and newer, Android blocks it at first: open App info, tap the menu (⋮), choose Allow restricted settings, then allow SMS for SwarmSMS. |
| Phone shows offline | Is the app's gateway switch on? Battery set to Unrestricted? Phone online? The dashboard shows when it last checked in. Re-pair if the app says “device key rejected”. |
| Messages stay “pending” | No phone is online or the phone is at its daily limit. With Firebase push configured the phone wakes immediately; otherwise it takes up to the poll interval. |
| Messages go “failed” | The log shows the phone's reason (no service, airplane mode, invalid number). Check credit/signal. Samsung/Xiaomi may need Allow restricted settings for sideloaded apps. |
| Never reaches “delivered” | Some carriers don't return delivery reports; “sent” is then the final status. |
| Campaign link 404 | Go to Settings → Permalinks and click Save. |
| Campaign isn't sending | Check: started? inside the sending hours? a phone online? the contact is subscribed? See Logs → Activity. |
| Locked out by SMS 2FA | Add define('WPSG_DISABLE_2FA', true); to wp-config.php, log in, fix, remove it. |
| API / MCP says 401 but the key is right | Some hosts strip the Authorization header. Send the key as X-API-Key: KEY instead (for MCP clients that allow custom headers, use that header; Codex: http_headers = { "X-API-Key" = "KEY" }). |
| Push test fails | The message from Firebase is shown. Common causes: package name in Firebase isn't com.swarmsms.app; the two JSON files are from different projects; the phone hasn't opened the updated app yet. |
Developer reference
wpsg_send_sms( '0400111222', 'Hello', 0, array( 'send_at' => gmdate( 'Y-m-d H:i:s', time() + 3600 ) ) );
wpsg_otp_send( '0400111222', 'checkout' ); wpsg_otp_verify( '0400111222', $code, 'checkout' );
add_action( 'wpsg_message_received', function ( $m ) { /* $m['phone'], $m['message'] */ } );
add_action( 'wpsg_message_status', function ( $m ) { /* sent | delivered | failed */ } );
add_action( 'wpsg_contact_subscribed', function ( $contact_id ) {} );
add_action( 'wpsg_contact_unsubscribed', function ( $contact_id ) {} );
add_filter( 'wpsg_can_text', function ( $ok, $phone, $marketing ) { return $ok; }, 10, 3 );
add_filter( 'wpsg_merge_tags', function ( $tags, $campaign, $contact ) { $tags['vip'] = 'Gold'; return $tags; }, 10, 3 );
add_filter( 'wpsg_otp_max_per_hour', function () { return 200; } );
// Custom automation trigger (create an automation of type "Custom" with key my_event)
do_action( 'wpsg_trigger', 'my_event', array( 'phone' => '0400111222', 'first_name' => 'Sam', 'consent' => true ) );
[wpsg_subscribe lists="1" title="Get our offers by text"]
[wpsg_otp_login redirect="/my-account/"]Changelog
You are running SwarmSMS 3.5.1. Every release of the plugin, SwarmSMS Cloud and the Android app is listed at swarmsms.com/changelog.
3.5.1
- New Changelog section in the documentation (SwarmSMS > Help) showing what changed in recent versions, with a link to the full changelog at swarmsms.com/changelog.
3.5.0
- New sites get a 1-day free trial with every feature unlocked. After the trial, without a license, only the basics remain: 1 phone, 10 messages a day, 100 contacts.
3.4.1
- Positioning: SwarmSMS is now described everywhere as an SMS gateway and SMS marketing plugin (plugin description, readme, store, website).
3.4.0
- New: Twilio delivery. Settings > Delivery lets you choose Devices only, Devices and Twilio (Twilio sends as a last resort when every phone is offline, or when a phone fails a message and no other phone can retry it) or Twilio only. Delivery reports and replies come back through signed Twilio webhooks. Pro and Agency plans.
- Messages record their channel (device / twilio) in the logs and the REST API.
3.3.1
- Plans: Instant delivery (Firebase push), the AI (MCP) connection, WooCommerce coupons and the white-label app are now Agency-plan features. Pro keeps failover, drip sequences, automations and OTP/2FA.
3.3.0
- After the year the plan keeps working: when a subscription ends SwarmSMS and the app carry on with every feature of the plan; only updates and support stop until you renew. A refunded purchase still returns to trial mode (the store tells expired from revoked).
- One phone can now be paired to up to 25 websites (Agency plan), enforced server-side.
- Android app 3.3: the SwarmSMS three-hexagon logo throughout the app and notification.
- Notice on the dashboard and License tab when a subscription has ended.
3.2.1
- Fix: the pairing QR code was blank once Firebase push was set up (the code carried too much data). It now holds only the server URL and pairing code, and the QR library is bundled with the plugin.
3.2.0
- New Agency plan: 25 sites and one phone paired to several websites at once. Sharing a phone across sites is now enforced by plan (server side). Sites pick up a plan upgrade automatically.
