Technical¶
Components¶
Addon Manual SMS uses the following different components in Lime CRM:
- Web components
- Custom endpoints
- Lime Marketing
- Task Handler
- Data structure
- Security policies
- Lime Bootstrap apps
- Actionpads
- Runtime configuration in Lime Admin
- Application configuration
How it works — SMS lifecycle & statuses¶
When an SMS is sent, the addon creates one SMS sendout and one SMS recipient per receiver, and both move through a series of statuses as the work progresses.
The flow is:
- The
send_smsendpoint creates the sendout in Lime (statuscreated) and a matching SMS message in Lime Marketing. - A background task (Lime task handler) creates and validates the recipients, and moves the sendout to
init:- One recipient object is created per receiver in Lime, each in status
init. At this point the recipient exists in Lime but hasn't been handed to Lime Marketing yet. - A recipient list is created in Lime Marketing and all recipients are imported into it (with their phone numbers and merge variables). This happens before the sendout is actually sent.
- The addon reads the imported list back from Lime Marketing and reconciles it against the Lime recipients. For each recipient: if its phone number was imported successfully, it stores the Lime Marketing recipient id and sets the status to
queued; if the phone number is missing from the imported list (e.g. invalid format), it sets the status tofailed.
- One recipient object is created per receiver in Lime, each in status
- Lime Marketing sends the messages and reports progress back through webhooks, which update the statuses (
sending/finishedon the sendout,sent/deliveredon the recipients).
Webhooks only ever move a status forward — a later webhook can never downgrade a status that is already further along.
Sendout statuses¶
| Status | Meaning | When it's set | Why it could be stuck here |
|---|---|---|---|
Created |
The sendout and the Lime Marketing message have been created, but the background task hasn't run yet. | By the send_sms endpoint. |
The Lime task handler isn't running, or the background task failed immediately (e.g. missing addon config). |
Initialized |
The background task created the recipients and handed the list to Lime Marketing. Waiting for sending to start. | By the background task once recipients are queued. | The task failed before/at the hand-off to Lime Marketing, or the send_started webhook never arrived. |
Sending |
Lime Marketing has started sending. | By the send_started webhook. |
The send_finished webhook never arrived. Large sendouts can also legitimately stay here a while. |
Finished |
Lime Marketing finished processing all sends. This is the final status. | By the send_finished webhook. |
— (final status) |
Failed |
Exists as an option but is never set automatically by the addon. | — | A failed background task leaves the sendout in Created/Initialized, not Failed. |
Recipient statuses¶
| Status | Meaning | When it's set | Why it could be stuck here |
|---|---|---|---|
Initialized |
The recipient object was created in Lime but not yet handed to Lime Marketing. | By the background task when creating recipients. | The background task failed before reaching the hand-off to Lime Marketing. |
Queued |
The phone number was accepted and imported into Lime Marketing. | By the background task after syncing the list with Lime Marketing. | The message was never actually sent (task failed at the send step), the sent webhook never arrived, or the message genuinely failed at the operator (no failure webhook is sent — see below). |
Sent |
The message reached Lime Marketing's SMS service. This is not a delivery guarantee. | By the sent_to_recipient webhook. |
The delivered_to_recipient webhook never arrived — the operator doesn't return delivery receipts, or the message was dropped after the sent webhook (e.g. by downstream sender-ID/country filtering, which shows as blocked in Lime Marketing). |
Delivered |
The recipient's device confirmed delivery. This is the final status. | By the delivered_to_recipient webhook. |
— (final status, operator-dependent) |
Failed |
The phone number was invalid or didn't match anything in the Lime Marketing import. This is terminal. | By the background task during the recipient import sync. | — (terminal; no webhook ever changes it) |
Why a status can get "stuck"¶
A status stops advancing whenever the next step in the chain doesn't happen. The most common causes:
- The Lime task handler isn't running or is busy — the background task never starts or never finishes, so the sendout stays in
Created/Initializedand recipients stay inInitialized. - The background task failed partway — depending on where it failed, recipients may be missing entirely, stuck in
Initialized(never handed off), or stuck inQueued(handed off but the send step failed). The sendout stays in its current status. - The integration settings in Lime Marketing is misconfigured (wrong URL or API key) — Lime Marketing sends, but the addon never hears about it, so the sendout stays in
Initialized/Sendingand recipients stay inQueued/Sent.
Two things the status can't tell you
There are no failure webhooks from Lime Marketing — only success ones (sent, delivered). This means a message that genuinely failed at the operator stays in Queued or Sent forever. Queued/Sent is therefore not proof of success, and the absence of Delivered does not prove the message failed.
A sendout is never set to Failed automatically. If the background task throws, the sendout is simply left in Created or Initialized. Check the task handler and web server logs to confirm whether a sendout actually failed.
Sent means "handed to Lime Marketing's SMS service" — not "sent to the phone". Downstream sender-ID/country filtering can drop a message after the sent webhook has already fired (for example an unregistered sender ID for a country that requires registration, such as Finland). Because no non-delivery report is sent back, such a recipient stays in Sent in Lime CRM and never reaches Delivered — the addon can't tell it was dropped. In Lime Marketing the same recipient is shown with status blocked, so that's where you can confirm it.
Custom adjustments¶
Handle phone numbers¶
Phone numbers expects the current format: +<COUNTRY_CODE>701234567 i.e. +46701234567
The format of a phone number is quite strict. So if the phone numbers in your solution don't follow the same strict rules we recommend you to write your own custom formatting.
You can in a custom limeobject on your limetype containing the phone number. Set the formatted version of the phone number in a hidden field or maybe just replace the phone number if you'd like.
Here's one example on how it could look if you always expects the phone number to be swedish.
def format_phone_number(phone_number: str):
valid_chars = [
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+'
]
formatted_phone_number = ''.join([
c for c
in phone_number
if c in valid_chars
])
if (
len(formatted_phone_number) == 10
and formatted_phone_number.startswith('0')
):
return f'+46{formatted_phone_number[1:]}'
return formatted_phone_number
Table and Field Definitions Lime CRM¶
smssendout (SMS sendout)¶
| Field name | Suggested local name(en/sv) | Field type | Description |
|---|---|---|---|
| name | Name/Namn | Text field | (32 characters) ReadOnly |
| message | Message/Meddelande | Text field | (4000 characters) ReadOnly |
| send_date | Send date/Utskicksdatum | Time field | Default value getdate().ReadOnly |
| smssendoutstatus | Sendout status/Utskicksstatus | Option field | Option keys (finished, failed, init, sending, created (default)) ReadOnly |
| bw_sms_message_id | SMS Message ID/SMS-meddelande ID | Integer field | The SMS message ID from Lime Marketing ReadOnly |
| smsrecipient | Recipient/Mottagare | relation (1:n smssendout-smsrecipient) | Relation tab to the SMS recipients, a SMS sendout can have many SMS recipients ReadOnly |
smstemplate (SMS template)¶
| Field name | Suggested local name(en/sv) | Field type | Description |
|---|---|---|---|
| name | Name/Namn | Text field | (256 characters) |
| inactive | Inactive/Inaktiv | Yes/No field | |
| fortable | For table/Mot tabell | Text field | (256 characters), (Make sure to add empty option if the customer is using the desktop version) |
| default | Default/Standardvärde | Yes/No field | |
| message | Message/Meddelande | Text field | (1024 characters) |
smsrecipient (SMS recipient)¶
| Field name | Suggested local name(en/sv) | Field type | Description |
|---|---|---|---|
| smssendout | SMS sendout/SMS-utskick | Relation field | ReadOnly |
| smsrecipientstatus | Delivery status/Leveransstatus | Option field | Option keys (init, queued, delivered, failed, sent) ReadOnly |
| bw_smsrecipient_id | Recipient ID/MottagarID | Integer field | The SMS recipient ID from Lime Marketing ReadOnly |
| phoneno | Phone number/Telefonnummer | Formatted text field | (128 characters) ReadOnly |
Permissions¶
If the solution is using Object Access make sure that the API user is a member of a group with access to the data that should be available for the integration to use
| Policy name | R | W | A | D | Apply to |
|---|---|---|---|---|---|
| tbl_smssendout | • | • | • | smssendout table | |
| tbl_smsrecipient | • | • | • | smsrecipient table | |
| tbl_smstemplate | • | • | smstemplate table | ||
| tbl_xyz | • | xyz table if relation to xyz exists and is used on smsrecipient |