# SMS

It's common to want customers to text your agent. For instance, a customer texts your support number "What is your return policy?", and the agent answers by SMS. The `telnyx` connector does this on your own Telnyx number.

## Answer by SMS

Add the `telnyx` connector to your agent:

```yaml title="agents/support/agent.yaml"
name: support
mode: text
llm: llm-smart
connectors:
  - name: telnyx
    connection: acme-sms # the label of your Telnyx connection
```

You need three things from Telnyx: an API key, a number with messaging in E.164, and your account's public key. The public key is under **Keys & Credentials > Public Key** in the Telnyx portal. Setup takes three steps:

1. **Point Telnyx at Stream.** At Telnyx, set the webhook URL of your number's messaging profile to `$STREAM_ACCELERATION_URL/v1/connectors/events/telnyx/<profile ID>`. `$STREAM_ACCELERATION_URL` is your router's URL. A profile ID looks like `0f3c5e2a-1b2c-4d5e-8f90-123456789abc`, and the first call in [Set it up from your backend](#set-it-up-from-your-backend) finds it. The URL applies to every number on that profile.
2. **Save your Telnyx account.** On the Stream Dashboard, open **Library > Connectors**, then **Telnyx**. Choose **Set OAuth client**. Fill **Provider app ID** with the profile ID and **Signing secret** with the public key, then choose **Save client**.
3. **Create the connection.** On the same page, choose **Create connection**. Choose **App** as the **Owner**. Enter `acme-sms` as the **Label**, your number as `phone_number`, such as `+12025550100`, and the Telnyx API key as the **Token**. Choose **Create connection**.

Sync the agent:

```sh
curl -fsSL https://getstream.io/cli/beta/install.sh | bash # the agents commands are in the beta CLI
getstream agents sync support
```

From a phone, text "What is your return policy?" to your Telnyx number. The reply comes back by SMS, from the same number.

## US phones need 10DLC

A reply to a US phone needs your number in an approved 10DLC campaign at Telnyx, in the account that holds the number. Without one, the agent answers, but Telnyx doesn't deliver the text. Telnyx explains the registration in [Getting Started with 10DLC](https://developers.telnyx.com/docs/messaging/10dlc/quickstart), and [10DLC](https://getstream.io/agents/docs/ios/telephony/10dlc/) explains what it is.

Replies to a phone in Canada are delivered without a 10DLC campaign.

## Conversations

- Each phone is one conversation. The agent reads the earlier texts from that phone.
- Telnyx answers STOP, START and HELP, not the agent.
- After STOP, the person gets no reply until they text START.

## Remind by SMS

The agent can remind a customer later, by SMS. Text "Remind me in 2 minutes to check my order status". The agent confirms, and about 2 minutes later the reminder arrives by SMS, once.

Reminders need `scheduling` on, so create `support-sms` with the last call in [Set it up from your backend](#set-it-up-from-your-backend) instead of syncing `agent.yaml`. One connection serves one agent, so delete a synced `support` first.

A text has no time zone, so on a customer's first reminder the agent asks for their city and works out their time zone from it. We recommend `llm-smart` for reminders.

## Set it up from your backend

Your backend can do the setup instead of the dashboard. First, find your number's messaging profile at Telnyx:

```bash
curl -g -H "Authorization: Bearer $TELNYX_API_KEY" \
  "https://api.telnyx.com/v2/phone_numbers?filter[phone_number]=%2B12025550100"
```

Write the number's `+` as `%2B`. Telnyx returns the profile ID as `messaging_profile_id`. Set it as `PROFILE_ID`, then point the profile's webhook URL at Stream:

```bash
curl -X PATCH "https://api.telnyx.com/v2/messaging_profiles/$PROFILE_ID" \
  -H "Authorization: Bearer $TELNYX_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"webhook_url\": \"$STREAM_ACCELERATION_URL/v1/connectors/events/telnyx/$PROFILE_ID\"}"
```

Then save your Telnyx account and create the connection. `$SERVER_TOKEN` is a [server token](https://getstream.io/agents/docs/ios/auth/):

```bash
curl -X PUT "$STREAM_ACCELERATION_URL/v1/agents/connectors/telnyx/oauth-client" \
  -H "api_key: $STREAM_API_KEY" -H "stream-auth-type: jwt" \
  -H "Authorization: Bearer $SERVER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"provider_app_id": "<profile ID>", "signing_secret": "<public key>"}'

curl -X POST "$STREAM_ACCELERATION_URL/v1/agents/connections" \
  -H "api_key: $STREAM_API_KEY" -H "stream-auth-type: jwt" \
  -H "Authorization: Bearer $SERVER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"connector_id": "telnyx", "owner": {"type": "app"}, "label": "acme-sms", "inputs": {"phone_number": "+12025550100"}}'

curl -X PUT "$STREAM_ACCELERATION_URL/v1/agents/connections/$CONNECTION_ID/credentials" \
  -H "api_key: $STREAM_API_KEY" -H "stream-auth-type: jwt" \
  -H "Authorization: Bearer $SERVER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"expected_revision": 1, "values": {"token": "<Telnyx API key>"}}'
```

`$CONNECTION_ID` is the `id` the second call returns. After the third call, the connection is `connected`.

For [reminders](#remind-by-sms), create the agent with this call. Put the connection's `id` in `connection_id`:

```bash
curl -X POST "$STREAM_ACCELERATION_URL/v1/agents/configs" \
  -H "api_key: $STREAM_API_KEY" -H "stream-auth-type: jwt" \
  -H "Authorization: Bearer $SERVER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "support-sms", "mode": "text", "llm": "llm-smart",
       "instructions": "Answer briefly. When asked for a reminder, schedule it with schedule_task, then confirm briefly.",
       "scheduling": {"enabled": true},
       "connectors": [{"name": "sms", "connector_id": "telnyx", "connection": {"type": "fixed", "connection_id": "<connection ID>"}, "tools": []}]}'
```

## When a text gets no answer

| What you see                                   | Why                                                      | What to do                                                                                  |
| ---------------------------------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
| The agent gets nothing                         | The profile's webhook URL points somewhere else          | Set it again, as in step 1                                                                  |
| The router answers Telnyx `401`                | The signing secret is not your account's public key      | Save the public key again, as in step 2                                                     |
| The agent answers, but a US phone gets nothing | Telnyx error `40010`: the number is in no 10DLC campaign | Get an approved 10DLC campaign at Telnyx. See [US phones need 10DLC](#us-phones-need-10dlc) |
| A person gets no reply after STOP              | The person opted out                                     | The person texts START                                                                      |

## Going further

- [Connectors](https://getstream.io/agents/docs/ios/connectors/): Whose account, the catalog, and the keys of a connector entry.
- [iMessage](https://getstream.io/agents/docs/ios/connectors/imessage/): Answer over iMessage on your own Linq line.
- [Slack](https://getstream.io/agents/docs/ios/connectors/slack/): Answer in Slack threads as your workspace's bot.
- [10DLC](https://getstream.io/agents/docs/ios/telephony/10dlc/): What 10DLC is, and why US numbers need it.

---

For the most recent version of this documentation, visit [https://getstream.io/agents/docs/ios/connectors/sms/](https://getstream.io/agents/docs/ios/connectors/sms/).