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.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).
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. 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, usually under 300 characters, one question at a time — and it never promises that somebody will call back at a particular time, because it cannot make that happen. It asks for the person’s name, since a phone number on its own is not a lead. 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.
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.
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.
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.
