SMS Messaging
An Erdo agent can send outbound SMS on your behalf through Erdo’s managed number — the same Erdo-managed model as Voice Calls. No account or carrier setup to connect; just ask the agent to text someone.“Text +1 415 555 0142 to confirm their demo on Thursday at 2pm.”Like voice calls, every send is approval-gated (you confirm it in chat first) and requires a consent basis — a concrete reason the message is permitted (explicit opt-in, an existing business relationship, an internal test).
Opt-out is enforced
Recipients who reply STOP are added to your organization’s suppression list, and any further send to that number is blocked before it leaves — the agent is told the recipient opted out and no credit is charged. (STOP is also enforced at the carrier level, so opt-out is honored even on the very first reply.) Suppression is per-organization.Texts Erdo starts say how to opt out
When Erdo starts a conversation by text, it tells the person how to stop. This covers a follow-up to a lead, an agent’ssend_sms and an outreach batch. Erdo adds “Reply STOP to opt out.” to
the first text it sends a number from each of your numbers, and records that the person was told.
US carriers expect that line on the first text after somebody opts in.
Texts to Canadian numbers carry it every time, with your business’s legal name from its
business profile: “Reply STOP to opt out of texts from .” Canada’s anti-spam law asks every
commercial message to name its sender and give a way to unsubscribe.
Replies to somebody who texted you first are sent as written, because they started the conversation.
A draft that already ends with the line is not given it twice. Outreach batches end every text with
the line, as before. Erdo doesn’t add your business name to outreach texts to Canada, so write it
into the batch message yourself.
Sending is rate-limited
Erdo caps how many messages can go out so a loop or a mistake can’t spam anyone: there’s a per-recipient limit (you can’t blast one number) and a per-organization limit over a rolling window. A send that would exceed either is blocked before it leaves and not charged — the agent is told to back off. A logical send can also carry an idempotency key so a retry never sends the same message twice. Calling hours are shared with Voice — configure them once and both channels respect them — but the opt-out list, consent, and rate limits here are tracked per channel: opting out of SMS does not by itself suppress voice calls to that number, and vice versa. To stop all outreach to a recipient, suppress them on each channel you use.What the agent does
Thesend_sms capability:
- Validates the number, body, and consent basis.
- Checks the opt-out list and your credit balance first.
- Sends from Erdo’s number and records the message.
- Charges a small flat credit cost per message, only after the message is accepted (a blocked or opted-out send is never charged).
send_whatsapp_replysends the agent’s own words. WhatsApp delivers these only within 24 hours of the person’s last message to that number. Outside that, the reply is refused before any approval card, and the agent is told to use a template instead.send_whatsapp_templatesends a template Meta has approved, with its variables filled in. This is how the agent reaches someone who has not written in the last 24 hours, such as a new lead. The approval card shows the approved wording as the person will read it, in their language. A template Meta has not approved yet is refused before any card.
+54 11 5555 0142 gets the message at
+54 9 11 5555 0142, and their reply from that number lands in the same conversation. The lead keeps
the number it was captured with. A Stop sent from either spelling stops both. If the person has
already written to you from a number without the 9, Erdo answers on that number unchanged.
Lead outreach
SMS pairs with Voice for lead outreach loops: text a list, capture replies, and let Erdo qualify and follow up. Combined with datasets and workstreams, a whole list can be worked end-to-end.Incoming texts
A voice agent with its own phone number receives texts on that number as well as calls, and Erdo keeps every one of them. Texts are grouped into an SMS conversation: one Erdo number and one person, kept for as long as they keep texting, rather than a pile of separate messages. A conversation records who wrote and when, every message body and its delivery status, and how many pictures or files were attached. A summary and the topics covered arrive with the reply feature. Someone who texts STOP (orUNSUBSCRIBE, CANCEL, END, QUIT, OPTOUT) is added to your
suppression list exactly as if they had replied to an outbound send, and their conversation shows
as suppressed. START, UNSTOP or YES lifts it again — from outreach too, if the STOP was
a reply to an outreach send. From someone who never opted out, a “Yes” is just a reply, and your
agent answers it like any other message. On WhatsApp, “cancel” and “end” are ordinary messages too;
only STOP (or UNSUBSCRIBE, QUIT, OPTOUT) opts someone out there. Erdo never writes those
confirmations itself — Twilio sends them at the carrier level, which is why opt-out is honored even
before Erdo has seen a single message from that person. A block you placed by hand is not lifted by
someone texting START: only their own STOP is. The conversation’s suppressed flag always reflects
your suppression list as it stands — a block placed before the person ever texted shows on their
conversation from its first message.
A texter becomes a lead
Whoever texts your agent’s number reaches you from a number their carrier already verified, so a text conversation becomes a lead in the same table your landing pages and your widget write to — nothing to wire up. Once the conversation goes quiet, Erdo reads it, takes whatever the person said about themselves, and saves the lead withsource = sms_incoming and modality = text, alongside
the conversation it came from so you can read the whole exchange. The number they texted from is
the lead’s phone unless they asked to be reached on a different one — so an enquiry with no name
attached is still a lead, exactly as a phone call is.
A person who is already a lead is not duplicated: the text conversation fills in what your form left
blank and changes nothing you already have. A text that is only an opt-out or opt-in keyword (STOP,
START) is not an enquiry and is never saved as a lead.
Whether this happens is the Save leads setting on the agent whose number was texted, the same
switch that governs the callers who ring it (Agents → Deployments, or lead_capture_enabled on
the agent), including which dataset the leads land in. Turn it off and texts are still captured and
readable; nothing is written as a lead. Turning it back on starts from the next conversation rather
than writing months of old ones.
Lead saving starts from the day it ships, too: conversations your number had before then stay
readable conversations and are never turned into leads retroactively, so nothing lands in your
dataset — or fires a notification — for an enquiry you have already dealt with.
Someone texting STOP stops Erdo texting them. It does not delete a lead already saved — you
still have the enquiry they made, you simply cannot text them about it.
The agent answers
Your agent replies to a text from its own number, with the same persona and the same knowledge it uses on a phone call. Nothing to switch on: an agent that has a number answers what arrives on it. It writes like a person texting. Plain text, no markdown or bullet lists, no dashes, usually under 300 characters, and at most one question at a time. It never promises that somebody will call back at a particular time, because it cannot make that happen. It qualifies before it asks for a name. The question a reply asks goes first to what your team needs to know: the person’s budget and their timeline, or the qualifying questions your agent’s instructions name instead. It never sends somebody who is texting you to a form. It asks for their name later, once, and never if it already knows it. It knows when you just called. If you phoned the number in the last hour and this is the person’s first text since, often their phone’s automatic “can’t talk” reply, the agent opens by saying who it is and that you just tried to call about their enquiry, and asks nothing else. It is honest and steps back. Asked “who is this?” or “is this a bot?”, it says in one line that it is your business’s virtual assistant and what it can help with. Asked for a person, it says it is passing the request to your team and that someone will get back to them on this number, then stops asking questions. Three texts in ten seconds get one reply. People text in fragments, so your agent waits a few seconds for the person to finish before it answers, then covers everything they said in one message rather than firing back three disconnected replies. A reply normally arrives within seconds of that pause; if something inside Erdo goes wrong on the way, it re-checks every few minutes and answers then, so a text is not left waiting for the person to write again — and no conversation can crowd out another, however long any one of them has been stuck. Replying is on the person’s terms, for a day. For 24 hours after somebody texts you, your agent answers whenever they write — quiet hours do not apply, because they wrote to you and are waiting. A conversation is capped at 30 messages per rolling 24 hours — counted over the last day at every moment, not reset on the hour — which bounds a loop or a flood without anybody having to notice it; if a real conversation hits the cap, it lands in your work feed so you can pick it up yourself. Outside that day, a message from Erdo is your own initiative again and the ordinary calling hours and frequency limits apply. Your organization also has a daily ceiling on how many messages it can send in total. If replies stop because you have reached it, Erdo says so in your work feed rather than going quiet, and the texts waiting are answered as the ceiling rolls forward. STOP always wins. The 24-hour posture relaxes quiet hours and a frequency cap, both of which are about Erdo’s own manners. It never touches opt-out: a person who has texted STOP is never texted again until they say START. Each reply costs credits, at the same flat per-message rate as an outbound SMS, charged only after the carrier accepts it.Before a US number can reply
US carriers require a local (10-digit) number to be registered before it can send text messages — a one-time registration of your business, not something you do per message. Until a US number is registered, your agent reads texts but cannot reply. Everything is captured and readable in the meantime, and the moment registration is approved the next text is answered with nothing else to switch on. If a text arrives at an unregistered number, Erdo puts an item in your work feed naming the number and pointing at the Business settings page where you register it. This applies to US and Canadian long codes, which share the same carrier registry. A number in another country replies as soon as it is provisioned, and a US toll-free number is verified through its own process rather than this one. If your number moves to a different Twilio account, its approval does not move with it — the registration belongs to the account that holds the campaign — so the number needs registering again before it can reply.Turning it off
Ask in chat — “stop my Ana agent answering texts” — or use the switch on Agents → Deployments, beside the agent’s number. Texts still arrive and are still readable; the agent just does not write back. The switch is per agent, and an update to anything else about that agent leaves it alone. Outside the app it isPOST /v1/voice/agents/{slug}/sms-replies with {"enabled": false},
erdo voice agents sms-replies <slug> --off, or the MCP tool
erdo_set_voice_agent_sms_replies (voice toolset; see Toolsets).
WhatsApp is in early access and is switched on per organization — ask us if you would like it. Once
it is on, WhatsApp answers on the same number, as its own conversation with its own opt-out — a
person who texts you and a person who messages you on WhatsApp are two threads, because they are two
separate permissions. RCS comes after that. Outbound SMS the agent starts itself still sends from Erdo’s
shared number; only a reply comes from the agent’s own.
Your WhatsApp profile
Once WhatsApp is connected on Settings → Business, the WhatsApp section has a WhatsApp profile card. It sets what people see about your business on WhatsApp:
One profile applies to every WhatsApp number in your organization. Saving sends it to each number
straight away, and it shows within a few minutes — these fields are not reviewed. A number you
register for WhatsApp later starts with the profile already on it. If a number does not accept the
update, the card lists it with the reason; your changes are kept, and saving again retries.
Upload a PNG, JPG or WebP picture. WhatsApp shows it in a circle, so a square logo with some space
around it works best. Erdo fits it into a 640×640 square and puts a transparent background on white,
because WhatsApp accepts neither a non-square picture nor transparency.
The name people see is not on this card. It is set when each number is registered for WhatsApp, and
WhatsApp reviews it; changing it later is a request to us rather than an edit.
Message templates
WhatsApp lets a business send any message to someone who wrote to it in the last 24 hours. To write to someone first — a new lead who filled in your website form, say — it only allows a template: a fixed message Meta has reviewed and approved, with a few blanks like the person’s name. Erdo writes these templates and installs them on your WhatsApp account for you, within about ten minutes of your number going live. The WhatsApp section of Settings → Business lists them under Message templates, with where each one stands with Meta:
Each is installed in English, Spanish and Portuguese (Brazil), and each language is reviewed on its
own. Erdo writes to a lead in their language; until that language is approved, it uses the English
version.
Tapping Yes, please is an ordinary reply: your agent answers it, and the conversation carries
on normally. A lead who doesn’t want to hear from you can reply STOP, which opts them out of
WhatsApp messages from your number. (Earlier copies of this message also had a Stop messages
button; tapping it still works the same way as replying STOP.)
WhatsApp limits how many people you can write to first each day: 250 until your business is
verified by Meta, and more once it is (2,000, then higher as you send). Erdo follows the limit
Meta reports for your number. Replies to people who wrote to you do not count.
Reading conversations
Ask in chat — “has anyone texted my number?”, “what did they say?” — or read them directly. From the CLI:- List —
GET /v1/voice/sms-conversations(or aPOSTwith a JSON body) returns each conversation’s session id, the two numbers, when it opened, when each side last wrote, how many texts it holds, whether the person is suppressed, and — once the conversation has been quiet on both sides for half an hour — itssummary,topicsandcontact. The summary keeps up with the conversation: a reply Erdo sends after one has already been summarised is read into the next summary rather than leaving a stale one until the person texts again. Narrow withphone_number(one of your Erdo numbers) oraddress(the person); both accept any format and are compared on digits. Narrow withcanonical_lead_idto read one lead’s conversations (see below); filters combine. When a response includesnext_cursor, pass it back ascursorfor the next stable page, with the same filters. MCP tool:erdo_voice_sms_conversation_list. - Read one —
GET /v1/voice/sms-conversations/{session_id}, using a session id from the list, returns the conversation plus its texts oldest first, so the exchange reads in order. MCP tool:erdo_voice_sms_conversation_get.
Delivery times
Each outbound text carriesdelivered_at: when the carrier confirmed it reached the person. It is
set by the first delivery report and never changes after, so you can use it as the time a text was
delivered — for example, as proof that a lead’s number works. It is absent on inbound texts and on
outbound ones that have not been confirmed, including texts the carrier reported as undelivered.
Each conversation in the list and in a single read also carries first_delivered_outbound_at and
first_delivered_outbound_message_id: the earliest confirmed delivery in that conversation and the
text it belongs to, absent while nothing has been delivered.
WhatsApp messages carry the same delivered_at, plus read_at when the person opened the message.
A message that was read counts as delivered even if its delivery report never arrived. WhatsApp
conversations carry the same two first_delivered_outbound_* fields.
The time is when Erdo received the provider’s report, usually seconds after the send for a text.
For WhatsApp it can be hours later, because the report only arrives once the person’s phone comes
online. Messages delivered before these fields existed carry the time of the last report Erdo
stored; for a WhatsApp message that had already been read, that is the read time, so its
delivered_at is the latest it could have been delivered.
Media stays at the carrier: a conversation reports how many attachments a text carried, and Erdo
does not serve the files themselves.
When your leads dataset uses lead identity, each conversation also names the lead
it became: canonical_lead_id is that lead’s permanent UUID and lead_reference is the same id in
22 characters, the form a link or a text message carries. Join on it when you show a lead’s texts,
rather than on the number — the same person can text from one number and later leave an email that
their lead is keyed on. Pass either form as canonical_lead_id on the list to read one lead’s
conversations; it narrows your organization’s conversations and never reaches anyone else’s. The
same filter works on phone calls and widget
conversations.
A conversation Erdo starts is named the same way, from the other direction. When a text is sent about
a lead you already have — a follow-up your playbook decided on — the conversation is linked to that
lead as it is sent, so it appears in the lead’s texts alongside the ones they began. A conversation
that already names a lead keeps that one: what the person said about themselves is never replaced by
what a send assumed.
A text conversation can become a lead more than once — each time the person comes back and says
something new about themselves, that episode is written too — so the id is the lead the most recent
write resolved to. An episode that resolves none (lead saving was switched off, or the dataset is not
enrolled) leaves an earlier id in place rather than erasing it. Both fields are empty while no write
has resolved a lead, when the leads dataset is not enrolled in lead identity, and on conversations
recorded before conversations carried the lead’s identity; those older conversations keep empty
fields rather than being matched to a lead after the fact.
Reading WhatsApp conversations
WhatsApp conversations are read on their own, beside texts rather than mixed into them. They are a separate thread with a separate opt-out, and a WhatsApp message can be things a text cannot: a shared location, a tap on a quick-reply button, a reply quoting an earlier message, or the first message from someone who clicked one of your ads. From the CLI:- List —
GET /v1/voice/whatsapp-conversations(or aPOSTwith a JSON body) takes the same filters as the SMS list —phone_number,address,canonical_lead_id,limitandcursor— whereaddressfinds an Argentine mobile with or without its 9 — and returns the same fields, plusdisplay_name: the WhatsApp profile name the person chose, from their most recent message.suppressedis true while the person has opted out of WhatsApp with you; it says nothing about whether they still accept texts. MCP tool:erdo_voice_whatsapp_conversation_list. - Read one —
GET /v1/voice/whatsapp-conversations/{session_id}returns the conversation plus its messages oldest first. Beside the body, direction, status and attachment count, each message carries itsmessage_type(text,location,button,voice, …) and theprofile_namethe person had at the time, and — only when present —location(a shared pin’s latitude, longitude, label and address; the message body is empty),context(the message it quoted or the button it tapped) andreferral(the ad the person came in from). A session id from the SMS list is not found here. MCP tool:erdo_voice_whatsapp_conversation_get.
canonical_lead_id and lead_reference, so a lead’s timeline can show its texts and its WhatsApp
messages side by side by reading both lists with the same filter.
