> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Build a WhatsApp and SMS AI Agent

> Deploy one Claude-powered AI agent that answers customers on WhatsApp and SMS, sharing the same prompt, tools, and knowledge base on both channels.

# Build a WhatsApp and SMS AI Agent

This guide builds one AI agent and puts it in front of customers on two
channels — SMS for universal reach on any handset, WhatsApp for rich media
and the 2 billion people already on it. The agent is defined once; deploying
it to a second channel is a single extra API call, not a second integration.

## What you'll build

* One agent (`POST /api/v1/agents`) with a system prompt, a knowledge base,
  and guardrails.
* The same agent deployed to **SMS** and **WhatsApp**, each bound to a phone
  number with its own `deploy` call.
* No webhook server of your own, and no LLM calls to wire up — Orbit's agent
  runtime receives the inbound message, runs the conversation, and sends the
  reply back over the channel it arrived on.

If you've built this kind of thing before by wiring a messaging webhook to
your own server and calling an LLM yourself, that step is what Orbit's
`deploy` call replaces: the runtime already speaks SMS and WhatsApp, so
there's no relay to host or keep alive.

## How it works

1. A customer texts your number, or messages your WhatsApp Business number.
2. Orbit's agent runtime loads that contact's conversation state.
3. The runtime sends the conversation to Claude along with the agent's
   tools and knowledge base.
4. The agent's response is sent back over the same channel the inbound
   message arrived on — SMS in, SMS out; WhatsApp in, WhatsApp out.

## Prerequisites

* An Orbit account and an API key (**Dashboard → Settings → API Keys**).
* For WhatsApp: a WhatsApp Business Account (WABA) connected through the
  dashboard's Embedded Signup flow — see [WABA Setup](/guides/whatsapp/waba-setup)
  if you haven't connected one yet. You can also test against Orbit's shared
  test WABA before connecting your own.
* A phone number with SMS capability. WhatsApp rides on the same E.164
  number once it's registered to your WABA, so you generally deploy both
  channels to one number.

## Step 1 — Get a number

Search for an available number with SMS (and voice, if you want it later):

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/numbers/available?country=US&type=local&capabilities=sms,voice" \
  -H "X-API-Key: dv_live_sk_..."
```

Copy the `phone_number` field from the entry you want (e.g. `+14155550123`),
then buy it:

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/numbers/purchase \
  -H "X-API-Key: dv_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "phone_number": "+14155550123",
    "country_code": "US",
    "capabilities": ["sms", "voice"]
  }'
```

```bash theme={null}
export PHONE_NUMBER="+14155550123"
```

## Step 2 — Create the agent

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/agents \
  -H "X-API-Key: dv_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Support Agent",
    "description": "Answers customer questions over SMS and WhatsApp",
    "model": "claude-sonnet-4-6",
    "system_prompt": "You are a customer support agent for Acme Corp. Be concise — SMS and WhatsApp readers are on their phones. Answer from the knowledge base when you can, and offer to transfer to a human agent if you cannot resolve the issue.",
    "temperature": 0.3,
    "tools": ["search_knowledge", "transfer_agent"]
  }'
```

The response includes the agent's `id` (e.g. `agent_abc123`) — use it in the
steps below. See [Creating Agents](/agents/creating-agents) for the full
`tools`, guardrail, and escalation-trigger options.

## Step 3 — Ground it in your content

Create a knowledge base, upload your docs, and link it to the agent so
`search_knowledge` has something to retrieve from:

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/knowledge-bases \
  -H "X-API-Key: dv_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{ "name": "Acme Support Docs" }'
```

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/knowledge-bases/kb_xyz789/documents \
  -H "X-API-Key: dv_live_sk_..." \
  -F "file=@faq.pdf"
```

```bash theme={null}
curl -X PUT https://api.orbit.devotel.io/api/v1/agents/agent_abc123 \
  -H "X-API-Key: dv_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{ "knowledge_base_ids": ["kb_xyz789"] }'
```

This step is optional — an agent with no knowledge base still replies from
its system prompt alone — but a support agent grounded in your actual docs
gives fewer wrong answers than one working from the prompt alone.

## Step 4 — Deploy to SMS

Deploying is what binds the agent to a channel and number — there's no
separate "routing" step for messaging channels.

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/agents/agent_abc123/deploy \
  -H "X-API-Key: dv_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "channel": "sms",
    "phone_number": "'"$PHONE_NUMBER"'"
  }'
```

Text `$PHONE_NUMBER` from your own phone — the agent replies within a few
seconds.

## Step 5 — Deploy to WhatsApp

Repeat the deploy call with `channel` set to `whatsapp`, using the same
number now that it's registered to your WABA:

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/agents/agent_abc123/deploy \
  -H "X-API-Key: dv_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "channel": "whatsapp",
    "phone_number": "'"$PHONE_NUMBER"'"
  }'
```

Message the WhatsApp number and the same agent — same prompt, same
knowledge base, same guardrails — answers there too.

<Note>
  The agent's replies are always sent in response to an inbound customer
  message, so they always land inside Meta's
  [24-hour customer-care window](/guides/whatsapp/24h-window) — no template
  approval needed for the conversation itself. Templates only come into play
  if you need the agent (or one of its tools) to message a customer who
  hasn't texted you in the last 24 hours.
</Note>

## Step 6 — Test before you go live

Replay a scripted conversation without sending a real message or spending
LLM/channel cost on a live send:

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/agents/agent_abc123/dry-run \
  -H "X-API-Key: dv_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "scenario": {
      "turns": [
        { "user_msg": "What are your business hours?" }
      ]
    }
  }'
```

Or send one interactive test turn against the live agent (this calls the
LLM but isn't channel-routed, so no SMS or WhatsApp message goes out):

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/agents/agent_abc123/chat \
  -H "X-API-Key: dv_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{ "message": "What are your business hours?" }'
```

## Writing one prompt for two channels

WhatsApp and SMS aren't the same reading experience, so keep a few things
in mind while both channels share a prompt:

* **Default to plain text.** WhatsApp supports rich media, buttons, and list
  pickers; SMS doesn't. Don't have the agent reference a button or a list
  it can only render on one of the two channels.
* **Keep replies short.** SMS splits long messages into segments; WhatsApp
  readers are still on a phone screen. A concise system prompt (as above)
  keeps replies usable on both.
* **Escalate the same way everywhere.** `transfer_agent` and your
  `escalation_triggers` (keyword, sentiment, turn-count) work identically
  regardless of which channel the conversation is happening on.

## Troubleshooting

| Symptom                                                      | Fix                                                                                                                                                                                                           |
| ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Deploy returns `422 AGENT_NOT_CONFIGURED`                    | The agent has no `system_prompt` yet. Set one via `PUT /api/v1/agents/:id` before deploying.                                                                                                                  |
| Deploy returns `422 Unprocessable Entity` with an empty body | `channel` is required on every deploy call — `webhook`, `sms`, `whatsapp`, `voice`, or `rcs`.                                                                                                                 |
| SMS works but WhatsApp never replies                         | The number isn't registered to a connected WABA yet. Finish [WABA Setup](/guides/whatsapp/waba-setup) and confirm the number's Embedded Signup status before redeploying.                                     |
| WhatsApp send rejected outside a conversation                | The agent (or a tool call) tried to message a customer more than 24 hours after their last inbound message. Use an approved template for that case — see the [24h window guide](/guides/whatsapp/24h-window). |

## See also

* [Creating Agents](/agents/creating-agents) — full agent configuration reference (tools, guardrails, escalation triggers).
* [WhatsApp](/channels/whatsapp) and [SMS](/channels/sms) — channel-level API reference.
* [WABA Setup](/guides/whatsapp/waba-setup) — connecting your own WhatsApp Business Account.
* [AI Voice Agents via `sip_forward`](/guides/ai-voice-agent-sip-forward) — add a third channel, voice, to the same kind of setup.
* [Webhooks](/webhooks/events) — subscribe to `agent.conversation.started` and `agent.response` to observe conversations happening on either channel.
