Skip to content

SMS Module

The SMS module sends text messages from the platform: confirmation codes, alerts, and marketing campaigns. It queues a message, picks a provider, sends it, then tracks the delivery report and what the message cost.

A message is never sent straight from the request. It goes into a queue first, and the queue is what makes retries, rate limits, send windows and scheduling possible without the caller waiting for the provider.

What it covers

  • Providers — 11 SMS integrations, each as an adapter with its own credentials schema and capability set.
  • Queue — FIFO with attempts, exponential backoff, stuck-message recovery and expiry.
  • Routing — the provider is chosen by the destination, with failover to backup profiles.
  • Encoding and segments — GSM-7 or UCS-2 is detected, and the text is measured in segments, because that is what the operator bills.
  • Templates and triggers — a platform event fires a template, so codes and notifications do not need a caller.
  • Delivery reports — final status from the provider, by webhook or by polling.
  • Send windows — messages respect the local time of the recipient.
  • DNC and opt-outSTOP replies and blacklisted numbers are never messaged again.
  • Spend and balance — per-segment price in reports, provider balance with low-balance warnings.

Methods

Names in the table are the TCP command names; the REST column is the HTTP entry point of the same method.

Messages

Method REST Description
SmsSendMessage POST sms/message Queue a message with an explicit text
SmsSendFromTemplate POST sms/message/fromTemplate Queue a message rendered from a template
SmsSendBulk POST sms/message/bulk Queue up to 10 000 recipients as one campaign
SmsResendMessage POST sms/message/resend Send a copy of an existing message
SmsCancelMessage POST sms/message/cancel Cancel a message that has not left the queue
SmsPreviewMessage POST sms/message/preview Text, encoding, segments and unresolved placeholders without sending
SmsGetMessage GET sms/message/:id One message with attempts, error and webhook events
SmsGetMessages GET sms/messages/list Message history with filters and aggregates
SmsGetStats GET sms/stats Volume, segments, spend and delivery rate
SmsGetLastMessagesByParents Last message time for a batch of customers or leads

Templates and triggers

Method REST Description
SmsAddTemplate POST sms/template Create a text template with placeholders
SmsUpdateTemplate PUT sms/template Update a template
SmsCloneTemplate POST sms/template/clone Copy a template, for another language
SmsDeleteTemplate DELETE sms/template Delete a template
SmsGetTemplates GET sms/templates/list Templates of the brand
SmsAddTrigger POST sms/trigger Subscribe a platform event to templates
SmsUpdateTrigger PUT sms/trigger Update a trigger
SmsDeleteTrigger DELETE sms/trigger Delete a trigger
SmsFireTrigger POST sms/trigger/fire Fire an event by hand, for testing
SmsGetTriggers GET sms/triggers/list Triggers of the brand
SmsGetTriggerSubscriptions GET sms/triggers/subscriptions What the module is listening to right now

Providers, profiles and agents

Method REST Description
SmsGetProviderAdapters GET sms/providers/adapters Implemented adapters, capabilities and credential fields
SmsAddProvider POST sms/provider Register an SMS provider
SmsUpdateProvider PUT sms/provider Update a provider record
SmsDeleteProvider DELETE sms/provider Soft-delete a provider
SmsGetProviders GET sms/providers/list Provider catalogue
SmsAddProfile POST sms/providerProfile Create a provider profile with credentials
SmsUpdateProfile PUT sms/providerProfile Update a provider profile
SmsDeleteProfile DELETE sms/providerProfile Soft-delete a provider profile
SmsGetProfiles GET sms/providerProfiles/list Provider profiles of the brand
SmsGetMyProfiles GET sms/providerProfile/available/me Profiles and templates available to the current manager
SmsGetProfileBalance GET sms/providerProfiles/balance Provider balance with low-balance flags
SmsAddAgent POST sms/agent Link a manager to a sender identity
SmsUpdateAgent PUT sms/agent Update a manager-to-sender link
SmsDeleteAgent DELETE sms/agent Remove a manager-to-sender link
SmsGetAgents GET sms/agents/list Manager-to-sender links

Blacklist and send windows

Method REST Description
SmsAddBlacklistPhone POST sms/blacklist Blacklist a number
SmsImportBlacklistPhones POST sms/blacklist/import Bulk import up to 10 000 numbers
SmsDeleteBlacklistPhone DELETE sms/blacklist Remove a number from the blacklist
SmsCheckBlacklistPhone GET sms/blacklist/check Check a number before sending
SmsGetBlacklist GET sms/blacklist/list Blacklist entries
SmsAddSendWindow POST sms/sendWindow Allowed sending hours for a country
SmsUpdateSendWindow PUT sms/sendWindow Update a send window
SmsDeleteSendWindow DELETE sms/sendWindow Delete a send window
SmsCheckSendWindow GET sms/sendWindow/check Whether a number can be messaged now, and when the window opens
SmsGetSendWindows GET sms/sendWindows/list Send windows

Webhooks and service

Method REST Description
SmsAddWebhook POST sms/webhook Create a public delivery-report URL for a profile
SmsUpdateWebhook PUT sms/webhook Update a webhook
SmsDeleteWebhook DELETE sms/webhook Delete a webhook
SmsGetWebhooks GET sms/webhooks/list Webhooks of the brand
SmsGetWebhookEvents GET sms/webhookEvents/list Raw incoming provider events
SmsHandleWebhook POST sms/handleWebhooks/:uuid Public endpoint the provider calls
SmsPing GET sms/ping Cheap liveness probe with a problem list
SmsHealth GET sms/health Full module state: database, adapters, crons, queue, balances

Entities

Entity Scope Purpose
providers global SMS integration catalogue; name is the adapter name
providerProfiles brand Credentials, default senderId, deliveryUpdateBy, allowed destinations, routingPriority
agents brand Manager-to-sender link, used by INDIVIDUAL profiles
triggers brand or global Platform event to template subscription; merge renames event fields
templates brand Text with placeholders, language, message class
sms brand Messages, queue and state: status, kind, attempts, encoding, parts, price, campaignId
webhooks brand Public delivery-report URLs and their secrets
webhookEvents via webhooks Raw provider payloads and deduplication
phoneBlacklist brand DNC numbers and opt-outs
sendWindows brand Allowed sending hours per country

Everything is scoped by brand. Desks are not part of the model: a phone number, a template and a provider profile belong to a brand, not to a department.

Message statuses

Status Meaning
PENDING In the queue, not sent yet
IN_PROGRESS The queue is handing it to the provider right now
SENT Provider accepted it; the operator has not reported yet
DELIVERED Operator confirmed delivery to the handset
UNDELIVERED Operator reported a failed delivery
REJECTED Provider or operator refused the message
EXPIRED No final report arrived within the allowed window
FAILED Sending failed and no attempts are left

SENT is not a final status: for an SMS "the provider accepted it" and "the handset got it" are different events, sometimes hours apart. Statuses are normalised by the module — every adapter maps its own vocabulary into this set.

Message class

Every message has a kind: TRANSACTIONAL or MARKETING.

TRANSACTIONAL MARKETING
Send windows ignored applied
Opt-out (STOP) ignored blocks
Blacklist, regulator entries block block

A confirmation code must reach the customer at 3 a.m., and an opt-out from promotions is not a refusal to receive login codes. That is the whole reason the two classes exist.

Sending pipeline

sequenceDiagram
    participant CRM
    participant Module as SMS module
    participant Queue
    participant Provider
    CRM->>Module: SmsSendMessage
    Module->>Module: phone, blacklist, duplicate, encoding, segments
    Module->>Module: send window and schedule
    Module->>Queue: PENDING
    Queue->>Provider: send (attempt N)
    Provider-->>Queue: provider message id → SENT
    Provider-->>Module: delivery report (webhook or polling)
    Module-->>CRM: sms.message.final

Checks that can reject a message for free run before the provider is contacted: number validity, blacklist and opt-out, duplicate protection, text length in segments, send window and schedule. Then the message is queued, and everything after that — attempts, backoff, failover to a backup profile — happens without the caller waiting.

Events

Event When
sms.message.queued Message accepted into the queue
sms.message.sent Provider accepted the message
sms.message.final Delivered, undelivered, rejected, expired or failed
sms.statusChanged Notification for the manager UI