# Initiate outbound conversations

TAC supports outbound (agent-initiated) conversations across all channels. Your agent can send the first message over SMS, WhatsApp, or RCS, or place an outbound voice call — then handle customer replies through the same `on_message_ready` callback used for inbound conversations.

## Prerequisites

* TAC SDK installed and configured with your Twilio credentials (see [Add TAC to your agent](/docs/conversations/agent-connect/build-with-tac#prerequisites))
* A running TAC server with channels configured (the server must be running to receive replies)
* For Voice: `TWILIO_VOICE_PUBLIC_DOMAIN` set to your public domain (for example, your ngrok domain)
* For WhatsApp: `TWILIO_WHATSAPP_NUMBER` set to your WhatsApp-enabled number (format: `whatsapp:+1234567890`)
* For RCS: `TWILIO_RCS_SENDER_ID` set to your RCS Sender ID

## Outbound SMS

Send an SMS to a customer and handle their replies.

## Python

```python
from tac import TAC, TACConfig
from tac.channels.sms import SMSChannel, SMSChannelConfig
from tac.models.outbound import InitiateMessagingConversationOptions
from tac.server import TACFastAPIServer

tac = TAC(config=TACConfig.from_env())
sms_channel = SMSChannel(tac, config=SMSChannelConfig(memory_mode="always"))

async def handle_message_ready(message, context, memory):
    # Called when the customer replies
    llm_response = await your_llm.generate(message)
    return llm_response

tac.on_message_ready(handle_message_ready)

# Initiate outbound SMS after server starts
result = await sms_channel.initiate_outbound_conversation(
    InitiateMessagingConversationOptions(
        to="+16505551234",
        message="Hi! This is Acme Corp. Your order has shipped.",
    )
)
print(f"Conversation started: {result.conversation_id}")

# Start the TACFastAPIServer to receive replies
server = TACFastAPIServer(tac=tac, messaging_channels=[sms_channel])
server.start()
```

## TypeScript

```typescript
import { TAC, TACConfig, SMSChannel, TACServer } from 'twilio-agent-connect';

const tac = await TAC.create({ config: TACConfig.fromEnv() });
const smsChannel = new SMSChannel(tac);
tac.registerChannel(smsChannel);

tac.onMessageReady(async ({ message }) => {
  // Called when the customer replies
  const llmResponse = await yourLLM.generate(message);
  return llmResponse;
});

// Start the TACServer to receive replies
const server = new TACServer(tac);
await server.start();

// Initiate outbound SMS
const result = await smsChannel.initiateOutboundConversation({
  to: '+16505551234',
  message: 'Hi! This is Acme Corp. Your order has shipped.',
});
console.log(`Conversation started: ${result.conversationId}`);
```

The `initiate_outbound_conversation` method creates a conversation through Conversation Orchestrator, adds both participants (customer and AI agent), and sends the initial message. When the customer replies, TAC routes their response to your `on_message_ready` callback.

## Outbound Voice

Place an outbound voice call. The call connects to your TAC server's WebSocket endpoint, where Conversation Relay handles speech-to-text and text-to-speech.

## Python

```python
import os
from tac import TAC, TACConfig
from tac.channels.voice import VoiceChannel, VoiceChannelConfig
from tac.models.outbound import InitiateVoiceConversationOptions
from tac.server import TACFastAPIServer
from tac.server.config import TACServerConfig

tac = TAC(config=TACConfig.from_env())
voice_channel = VoiceChannel(tac, config=VoiceChannelConfig(memory_mode="always"))

async def handle_message_ready(message, context, memory):
    llm_response = await your_llm.generate(message)
    return llm_response

tac.on_message_ready(handle_message_ready)

# Get public domain for WebSocket URL
server_config = TACServerConfig.from_env()
public_domain = server_config.public_domain

# Initiate outbound voice call
result = await voice_channel.initiate_outbound_conversation(
    InitiateVoiceConversationOptions(
        to="+16505551234",
        websocket_url=f"wss://{public_domain}/ws",
        welcome_greeting="Hi! This is an AI assistant calling from Acme Corp.",
        action_url=f"https://{public_domain}/conversation-relay-callback",
    )
)
print(f"Call placed: {result.call_sid}")

# Start the TACFastAPIServer to handle the call
server = TACFastAPIServer(tac=tac, voice_channel=voice_channel)
server.start()
```

## TypeScript

```typescript
import { TAC, TACConfig, VoiceChannel, TACServer } from 'twilio-agent-connect';

const tac = await TAC.create({ config: TACConfig.fromEnv() });
const voiceChannel = new VoiceChannel(tac);
tac.registerChannel(voiceChannel);

tac.onMessageReady(async ({ message }) => {
  const llmResponse = await yourLLM.generate(message);
  return llmResponse;
});

// Start the TACServer to handle the call
const server = new TACServer(tac);
await server.start();

// Initiate outbound voice call
const publicDomain = process.env.TWILIO_VOICE_PUBLIC_DOMAIN!;
const result = await voiceChannel.initiateOutboundConversation({
  to: '+16505551234',
  conversationRelayConfig: {
    url: `wss://${publicDomain}/ws`,
    welcomeGreeting: 'Hi! This is an AI assistant calling from Acme Corp.',
  },
});
console.log(`Call placed: ${result.callSid}`);
```

The `welcome_greeting` (Python) or `welcomeGreeting` (TypeScript) is optional — if provided, Conversation Relay speaks it to the customer as soon as they pick up, before waiting for your agent to respond.

## Outbound WhatsApp and RCS

WhatsApp and RCS outbound follow the same pattern as SMS. Use the corresponding channel class and configure the required environment variable.

## Python

```python
from tac.channels.whatsapp import WhatsAppChannel, WhatsAppChannelConfig
from tac.channels.rcs import RCSChannel, RCSChannelConfig
from tac.models.outbound import InitiateMessagingConversationOptions

# WhatsApp — requires TWILIO_WHATSAPP_NUMBER env var
whatsapp_channel = WhatsAppChannel(tac, config=WhatsAppChannelConfig(memory_mode="always"))

result = await whatsapp_channel.initiate_outbound_conversation(
    InitiateMessagingConversationOptions(
        to="whatsapp:+16505551234",
        message="Hi! Your appointment is confirmed for tomorrow at 2pm.",
    )
)

# RCS — requires TWILIO_RCS_SENDER_ID env var
rcs_channel = RCSChannel(tac, config=RCSChannelConfig(memory_mode="always"))

result = await rcs_channel.initiate_outbound_conversation(
    InitiateMessagingConversationOptions(
        to="+16505551234",
        message="Hi! Your appointment is confirmed for tomorrow at 2pm.",
    )
)
```

## TypeScript

```typescript
import { WhatsAppChannel, RCSChannel } from 'twilio-agent-connect';

// WhatsApp — requires TWILIO_WHATSAPP_NUMBER env var
const whatsAppChannel = new WhatsAppChannel(tac);
tac.registerChannel(whatsAppChannel);

const waResult = await whatsAppChannel.initiateOutboundConversation({
  to: 'whatsapp:+16505551234',
  message: 'Hi! Your appointment is confirmed for tomorrow at 2pm.',
});

// RCS — requires TWILIO_RCS_SENDER_ID env var
const rcsChannel = new RCSChannel(tac);
tac.registerChannel(rcsChannel);

const rcsResult = await rcsChannel.initiateOutboundConversation({
  to: 'rcs:+16505551234',
  message: 'Hi! Your appointment is confirmed for tomorrow at 2pm.',
});
```

## Handling replies

Outbound conversations use the same `on_message_ready` callback as inbound conversations. When a customer replies to your outbound message or speaks during an outbound call, TAC delivers the message to your callback. You can distinguish inbound from outbound using the conversation session metadata if needed.

## Next steps

* [Channels](/docs/conversations/agent-connect/channels): Learn more about channel configuration and supported channels.
* [Add TAC to your agent](/docs/conversations/agent-connect/build-with-tac): Configure tools, knowledge, and memory alongside channels.
