# Messages

Source: https://modulify.ai/docs/built-in/messages

Text your customers from your site, with booking and order texts and verification codes sent through Sent, from templates Sent approves and paid from your workspace credits.

Every site can send texts (SMS) to its customers: a booking confirmation, an order update, a verification code or an alert when someone fills in a form. Texts go out through Sent, with nothing to sign up for, and are paid from your workspace credits. Everything lives in the **Messages** tab under **More** in the editor, with four sub-tabs: **Overview**, **Templates**, **History** and **Settings**. In the Modulify app for iPhone and Android, **Messages** is in **More** too, with the same tabs, see [On the mobile app](https://modulify.ai/docs/build/site-chat#on-the-mobile-app).

Anyone with the Editor role on the site can use the tab. Unblocking a number and deleting a template also need the **Delete projects** permission, and without it those controls are disabled with the tooltip "You do not have permission to do this."

## Turn texting on

Texting is off until you turn it on. **Send texts from this site** on the **Overview** tab turns it on and gives the site its own account on Sent. Turning it off asks first, **Turn off texting?**, because every text from the site is refused until you turn it back on.

### Test mode

**Test mode** is on from the start. Sent checks each text, but nothing goes out and nothing is charged, so you can try a template before anyone receives it. Real texts need a paid plan, and on a free plan test mode stays on. Turning it off asks first, **Send real texts?**, because real texts reach real people and cost credits.

## Templates

Every first text has to use a template Sent approved. A template is the text with placeholders for what changes from one text to the next, such as a name or an order number. Every site starts with six built-in templates: **Verification code**, **Form alert**, **Booking confirmed**, **Booking reminder**, **Order confirmed** and **Order status**. You can add your own, see [Your own templates](https://modulify.ai/docs/built-in/messages#your-own-templates).

### Template review

Each template is reviewed on its own, and separately on every site. **Send for review** in a template's menu puts it on Sent and sends it for review. The badge next to its name shows where it stands, and the info icon next to the badge explains it:

| Status | What it means |
| --- | --- |
| **Initial** | Not sent for review yet. Send it for review so your site can send real texts with it |
| **Pending** | Sent is reviewing it |
| **Approved** | Sent approved it, so your site can send real texts with it |
| **Rejected** | Sent rejected it. Edit the text and send it again, or let the AI fix it |
| **Paused** | Sent paused it, so it cannot send real texts until Sent resumes it |
| **Disabled** | Sent turned it off. Send it for review again to put a fresh copy on Sent |

A template that is on Sent but not approved yet can send in test mode only. The tab checks Sent on its own while a template is pending, and when the review ends, the person who sent it for review gets a notice in the editor, such as **Template approved** or **Template rejected**.

When Sent rejects a template, the reason it gave shows under the template, for example `Sent said: The link must point to a domain you own.` When sending it for review fails, the template stays **Initial** with an orange warning icon and the reason, such as `Sending it for review failed: no WhatsApp Business Account is connected`. **Fix with AI** in the menu of either one puts the template and the reason in the chat box, so the AI can change the text and send it again.

**Edit template** changes the text of a template that is **Initial**, **Rejected** or **Disabled**, and sends it for review again. A built-in template keeps its name, and **Verification code** keeps its text.

### Your own templates

**Create template** opens **New text template**. Give it a **Name**, such as Pickup ready, and write the **Text** with each placeholder in double braces:

```text
Hi {{name}}, your order {{order}} is ready to collect at {{site}}. Reply STOP to opt out.
```

Each placeholder gets an example under **Examples**, which Sent reviews the text with, so make them realistic. `{{site}}` is filled with your site's name on its own, and a placeholder named `link` or `url` needs a full link that starts with `https://`. **Preview** shows the text with the examples filled in, and **Add "Reply STOP to opt out."** adds that line when the text has no way to stop the texts.

The dialog checks the rules Sent refuses a text for before anything is sent:

- A word before the first placeholder and after the last one.
- A word between two placeholders.
- At least two words for each placeholder, plus one.
- Each placeholder used once, at most 10 of them, and a text of at most 1,024 characters.

**Send for review** saves the template on Sent and sends it for review. A site can have 20 templates of its own, with names of up to 40 characters that no other template on the site has. Your own templates show **Yours**, and **Delete template** deletes one on Sent too, after asking **Delete this template?**. Texts already sent with it stay in the history.

## Send a text

**Send a text** on the **Overview** tab sends one text. Pick the **Template**, the **Channel** and the **Phone number** in international format, such as `+14155551234`, then fill in the template's fields. The preview shows the text, the button shows its price, and **Send test** sends it in test mode while **Send text** sends it for real.

A text is refused while texting is off, to a country the site may not text, to a number that is blocked or replied STOP, and with a template Sent has not approved, unless it is a test. A site can send 30 texts a minute, 5 texts to one number a day and 20 credits of texts a day on a paid plan.

**Channel** is **SMS** by default. **WhatsApp** stays disabled until the site has a WhatsApp account of its own, and **Let Sent choose** lets Sent pick the channel.

## Prices and credits

A text costs credits from your workspace, set by the country it goes to and the number of parts it takes. An SMS part holds 160 characters, or 153 in a text of several parts, and a text with an emoji or another character outside the plain SMS alphabet holds 70, or 67 in a text of several parts. The first text to a number each calendar month adds a small fee once. **Countries** on the **Settings** tab shows the price of one part to each country.

The price can only go down once Sent reports what it charged, and the difference comes back to your workspace. A text that fails, is filtered, is blocked or is cancelled gets its credits back. Texts count as **Texts** in your workspace's credit usage, and under your workspace [spending caps](https://modulify.ai/docs/plans/spending).

## History

**History** lists every text the site sent, newest first, with its template, number, status and cost. Pick **All statuses**, **In progress**, **Delivered**, **Failed** or **Cancelled**, or search by phone number. Opening a text shows its status, every update Sent reported, the text that went out with a verification code masked, the credits it cost and whether they came back. It updates on its own while the text is on its way, and **Cancel text** stops one that has not gone out yet, after asking **Cancel this text?**. Texts stay in the history for 90 days.

## Settings

### Sender name

**Sender name** is the name people see on texts, where their country allows it. It takes 3 to 11 letters, digits and spaces, and other characters are left out. It is the same for every text from the site.

### Countries

**Countries** lists every country Sent texts, more than 230 of them, each with the price of one part, and the ones the site already texts come first. **Search countries** finds one by its name or its code. Pick the countries the site can text, up to 3 on Starter and 5 on Pro, and the count above the list says how many you picked. **Select all** picks every country, or every result while you search, when that many fit your plan, and otherwise it is disabled with the reason. **Clear all** unpicks every country after asking **Clear every country?**. A text to a number in any other country is refused. A number from a territory that dials through another country's code, such as the Åland Islands with Finland's, counts as that country.

### API access

**API access** shows the **API URL** and the **Texting key** your site's code sends texts with, with buttons to copy them, show the key and rotate it. Showing and rotating the key need the **Delete projects** permission. Rotating asks **Rotate the texting key?** first, because the old key stops working at once: the preview gets the new key right away, and the live site keeps the old one until you publish again, so its texts fail until then. A site that moves to another workspace gets a new key the same way.

### Blocked numbers

**Blocked numbers** lists the numbers the site never texts. Someone who replies STOP to a text lands here on their own, shown as **Replied STOP**, and only they can opt back in, by texting START. **Block number** blocks a number yourself, shown as **Blocked**, and **Unblock number** takes it off the list again.

## What the AI can do

Chat can do everything the tab does. Ask it to turn texting on, write a template and send it for review, fix a rejected one, send a text, read the history or block a number, and it does it with its site actions. It asks you first before it sends a real text, turns test mode off, turns texting off, unblocks a number, deletes a template or rotates the texting key. When you would rather write a template yourself, ask for that and it shows a card that opens **New text template** with its draft filled in. It also writes your site's code that sends texts, see [Send texts from your site's code](https://modulify.ai/docs/built-in/messages#send-texts-from-your-sites-code).

## Send texts from your site's code

Your site's own server code can send texts too, such as a verification code at sign-up or a booking text when a form is sent. Ask chat for it, and it writes the code with the helper `@/lib/modulify/messages`, which it keeps in your project at `src/lib/modulify/messages.ts`:

```ts
import { sendText } from '@/lib/modulify/messages'

await sendText({
    to: '+14155551234',
    template: 'order_confirmed',
    variables: { name: 'Ana', order: '#1042', total: 'EUR 48.00' },
    idempotencyKey: `order-confirmed-${order.id}`
})
```

The helper reads two [managed secrets](https://modulify.ai/docs/data/secrets), `MODULIFY_MESSAGES_URL` and `MODULIFY_MESSAGES_KEY`, which reach the preview when it starts and your published site when you publish it. It runs only on the server, never in the browser. Texts from your code follow the same rules as the tab: test mode, the template review, the countries and the limits, and they show in the **History** like any other text. A verification code is your site's to check, so your code keeps a hash of the code it sent and compares it with what the visitor types. Every text costs credits, so a form that texts a number a visitor types needs a limit per visitor and per number. The [Messages HTTP API](https://modulify.ai/docs/built-in/messages-http-api) lists every call, field and error.

## MCP and the API

The [Messages tools](https://modulify.ai/docs/mcp/tools#messages) do everything the tab does from an AI client or the [HTTP API](https://modulify.ai/docs/api): reading needs the `config:read` scope and changing anything `config:write`.

## Limits

| Limit | Value |
| --- | --- |
| Texts a minute, per site | 30 on a paid plan |
| Texts to one number a day | 5 on a paid plan |
| Credits of texts a day, per site | 20 on a paid plan |
| Countries a site can text | 5 on Pro |
| Value of one placeholder in a text | 120 characters |
| Templates of a site's own | 20 |
| Placeholders in one template | 10 |
| Template name | 40 characters |
| Template text | 1,024 characters |
| How long texts stay in the history | 90 days |