Messaging Quick Start
Send outbound SMS, email, and AI-powered calls with a single SDK call. No SMTP servers, SMS gateway contracts, telephony stacks, retry logic, or compliance plumbing — the platform handles all of it.
SDK coverage
This reflects what the SDK example guides demonstrate for each language.
| Operation | TypeScript | Python |
|---|---|---|
| Send SMS (direct, template) | ✓ | ✓ |
| Send SMS (scheduled) | — | ✓ |
| Send email (direct, template, CC/BCC) | ✓ | ✓ |
| Send email (attachment) | — | ✓ |
| Request call (immediate, scheduled) | ✓ | ✓ |
| Templates | ✓ | see Outbound Communications |
| Status queries | see Outbound Communications | ✓ |
| Error handling | — | ✓ |
Quick start
- TypeScript
- Python
import { WiilClient } from 'wiil-js';
const client = new WiilClient({ apiKey: process.env.WIIL_API_KEY! });
// Send an SMS
await client.outboundSms.create({
to: '+12125551234',
from: '+12125559999',
body: 'Your appointment is confirmed for tomorrow at 3 PM.',
});
// Send an Email
await client.outboundEmails.create({
to: [{ email: 'customer@example.com', name: 'John Smith' }],
subject: 'Order Confirmed',
bodyHtml: '<h1>Thank you!</h1><p>Your order is confirmed.</p>',
bodyText: 'Thank you! Your order is confirmed.',
});
// Request a Call
await client.outboundCalls.create({
to: '+12125551234',
from: '+12125559999',
agentConfigurationId: 'confirmation_agent',
scheduleType: 'immediate',
});
import os
from wiil import WiilClient
from wiil.models.conversation import (
CreateCallRequest,
CreateEmailRequest,
CreateSmsRequest,
EmailRecipient,
)
from wiil.types import ScheduleType
client = WiilClient(api_key=os.environ["WIIL_API_KEY"])
# Send an SMS
sms = client.outbound_sms.create(
CreateSmsRequest(
to="+12125551234",
from_number="+12125559999",
body="Your appointment is confirmed for tomorrow at 3 PM.",
)
)
# Send an email
email = client.outbound_emails.create(
CreateEmailRequest(
to=[EmailRecipient(email="customer@example.com", name="John Smith")],
subject="Order Confirmed",
body_html="<h1>Thank you!</h1><p>Your order is confirmed.</p>",
body_text="Thank you! Your order is confirmed.",
)
)
# Request an AI-powered call
call = client.outbound_calls.create(
CreateCallRequest(
to="+12125551234",
from_number="+12125559999",
agent_configuration_id="confirmation_agent",
schedule_type=ScheduleType.IMMEDIATE,
)
)
print(sms.id, email.id, call.id)
Three channels. One pattern.
Send SMS
Direct message
- TypeScript
- Python
await client.outboundSms.create({
to: '+12125551234',
from: '+12125559999',
body: 'Your verification code is 847291. Valid for 10 minutes.',
maxRetries: 2,
});
from wiil.models.conversation import CreateSmsRequest
sms = client.outbound_sms.create(
CreateSmsRequest(
to="+12125551234",
from_number="+12125559999",
body="Your verification code is 847291. Valid for 10 minutes.",
max_retries=2,
)
)
With a template
- TypeScript
- Python
await client.outboundSms.create({
to: '+12125551234',
from: '+12125559999',
templateId: 'verification_code',
templateVariables: { code: '847291' },
});
sms = client.outbound_sms.create(
CreateSmsRequest(
to="+12125551234",
from_number="+12125559999",
template_id="verification_code",
body="Your verification code is {{code}}.",
variables={"code": "847291"},
)
)
Scheduled SMS (Python)
import time
sms = client.outbound_sms.create(
CreateSmsRequest(
to="+12125551234",
from_number="+12125559999",
body="Reminder: your appointment starts in one hour.",
scheduled_at=int(time.time() * 1000) + 60 * 60 * 1000,
)
)
Send Email
Direct content
- TypeScript
- Python
await client.outboundEmails.create({
to: [{ email: 'customer@example.com', name: 'John Smith' }],
subject: 'Your Order Has Shipped',
bodyHtml: '<h1>Good news!</h1><p>Your order is on its way.</p>',
bodyText: 'Good news! Your order is on its way.',
replyTo: 'support@example.com',
});
from wiil.models.conversation import CreateEmailRequest, EmailRecipient
email = client.outbound_emails.create(
CreateEmailRequest(
to=[EmailRecipient(email="customer@example.com", name="John Smith")],
subject="Your Order Has Shipped",
body_html="<h1>Good news!</h1><p>Your order is on its way.</p>",
body_text="Good news! Your order is on its way.",
reply_to="support@example.com",
)
)
With a template
- TypeScript
- Python
await client.outboundEmails.create({
to: [{ email: 'customer@example.com', name: 'John Smith' }],
templateId: 'order_shipped',
templateVariables: {
customerName: 'John',
orderNumber: 'ORD-12345',
trackingUrl: 'https://track.example.com/12345',
},
});
email = client.outbound_emails.create(
CreateEmailRequest(
to=[EmailRecipient(email="customer@example.com", name="John Smith")],
template_id="order_shipped",
subject="Your order {{orderNumber}} has shipped",
body_html="<p>Track your order here: {{trackingUrl}}</p>",
body_text="Track your order: {{trackingUrl}}",
variables={
"orderNumber": "ORD-12345",
"trackingUrl": "https://track.example.com/12345",
},
)
)
Multiple recipients & CC/BCC
- TypeScript
- Python
await client.outboundEmails.create({
to: [
{ email: 'alice@example.com', name: 'Alice' },
{ email: 'bob@example.com', name: 'Bob' },
],
cc: [{ email: 'manager@example.com' }],
bcc: [{ email: 'archive@example.com' }],
templateId: 'team_update',
templateVariables: { ... },
});
email = client.outbound_emails.create(
CreateEmailRequest(
to=[EmailRecipient(email="customer@example.com")],
cc=[EmailRecipient(email="manager@example.com")],
bcc=[EmailRecipient(email="archive@example.com")],
subject="Team Update",
body_html="<p>Weekly update attached.</p>",
body_text="Weekly update attached.",
)
)
With an attachment (Python)
import base64
from pathlib import Path
from wiil.models.conversation import EmailAttachment
pdf_content = base64.b64encode(Path("invoice.pdf").read_bytes()).decode()
email = client.outbound_emails.create(
CreateEmailRequest(
to=[EmailRecipient(email="customer@example.com")],
subject="Your Invoice",
body_html="<p>Please find your invoice attached.</p>",
body_text="Please find your invoice attached.",
attachments=[
EmailAttachment(
filename="invoice.pdf",
content=pdf_content,
content_type="application/pdf",
)
],
)
)
Request a Call
Immediate
- TypeScript
- Python
await client.outboundCalls.create({
to: '+12125551234',
from: '+12125559999',
agentConfigurationId: 'support_agent',
scheduleType: 'immediate',
maxDuration: 300, // 5 minutes
maxRetries: 2,
});
from wiil.models.conversation import CreateCallRequest
from wiil.types import ScheduleType
call = client.outbound_calls.create(
CreateCallRequest(
to="+12125551234",
from_number="+12125559999",
agent_configuration_id="agent_456",
schedule_type=ScheduleType.IMMEDIATE,
)
)
Scheduled
- TypeScript
- Python
await client.outboundCalls.create({
to: '+12125551234',
from: '+12125559999',
agentConfigurationId: 'reminder_agent',
scheduleType: 'scheduled',
scheduledAt: Math.floor(Date.now() / 1000) + (60 * 60), // 1 hour from now (UTC seconds)
maxDuration: 300,
maxRetries: 3,
});
import time
from wiil.models.conversation import CallingHours
call = client.outbound_calls.create(
CreateCallRequest(
to="+12125551234",
from_number="+12125559999",
agent_configuration_id="agent_456",
schedule_type=ScheduleType.SCHEDULED,
scheduled_at=int(time.time() * 1000) + 60 * 60 * 1000,
calling_hours=CallingHours(
start_time="09:00",
end_time="17:00",
days_of_week=[1, 2, 3, 4, 5],
),
max_retries=3,
retry_delay_minutes=30,
)
)
Templates (TypeScript)
Create once, use everywhere. Marketing updates copy without code deploys. For Python template management and the full set of template operations, see Outbound Communications.
import { OutboundTemplateChannel } from 'wiil-core-js';
// Create email template
const emailTemplate = await client.outboundTemplates.createEmailTemplate({
name: 'Order Confirmation',
code: 'order_confirmation',
channel: OutboundTemplateChannel.EMAIL,
subjectTemplate: 'Order #{{orderNumber}} Confirmed',
bodyHtmlTemplate: '<h1>Thank you, {{customerName}}!</h1><p>Order confirmed.</p>',
bodyTextTemplate: 'Thank you, {{customerName}}! Order confirmed.',
variables: [
{ key: 'customerName', required: true },
{ key: 'orderNumber', required: true },
],
});
// Create SMS template
const smsTemplate = await client.outboundTemplates.createSmsTemplate({
name: 'Verification Code',
code: 'verification',
channel: 'SMS',
bodyTemplate: 'Your code is {{code}}. Valid for 10 minutes.',
variables: [{ key: 'code', required: true }],
});
// Activate templates
await client.outboundTemplates.activate(emailTemplate.id);
await client.outboundTemplates.activate(smsTemplate.id);
// Preview before sending
const preview = await client.outboundTemplates.render(emailTemplate.id, {
customerName: 'Test User',
orderNumber: 'TEST-001',
});
console.log(preview.subject, preview.bodyHtml);
Status queries (Python)
from wiil.types import CallRequestStatus, EmailStatus, PaginationRequest, SmsStatus
pending_calls = client.outbound_calls.get_by_status(
CallRequestStatus.PENDING,
PaginationRequest(page=1, page_size=20),
)
queued_emails = client.outbound_emails.get_by_status(
EmailStatus.QUEUED,
PaginationRequest(page=1, page_size=20),
)
queued_sms = client.outbound_sms.get_by_status(
SmsStatus.QUEUED,
PaginationRequest(page=1, page_size=20),
)
Error handling (Python)
from wiil.errors import WiilAPIError, WiilNetworkError, WiilValidationError
try:
sms = client.outbound_sms.create(
CreateSmsRequest(to="+12125551234", body="Hello")
)
except WiilValidationError as exc:
print("Invalid request:", exc.details)
except WiilAPIError as exc:
print(f"API error {exc.status_code}:", exc.message)
except WiilNetworkError:
print("Network error. Retry with backoff.")
Complete example (TypeScript)
Multi-channel appointment notifications:
import { WiilClient } from 'wiil-js';
const client = new WiilClient({ apiKey: process.env.WIIL_API_KEY! });
async function sendAppointmentNotifications(appointment: {
customerEmail: string;
customerName: string;
customerPhone: string;
dateTime: string;
serviceName: string;
}) {
const appointmentTime = new Date(appointment.dateTime).getTime();
// 1. Immediate confirmation email
await client.outboundEmails.create({
to: [{ email: appointment.customerEmail, name: appointment.customerName }],
templateId: 'appointment_confirmed',
templateVariables: {
customerName: appointment.customerName,
serviceName: appointment.serviceName,
dateTime: appointment.dateTime,
},
});
console.log('Confirmation email sent');
// 2. 24-hour reminder SMS
await client.outboundSms.create({
to: appointment.customerPhone,
from: '+12125559999',
templateId: 'appointment_reminder_24h',
templateVariables: {
serviceName: appointment.serviceName,
dateTime: appointment.dateTime,
},
});
console.log('Reminder SMS queued');
// 3. 2-hour confirmation call
await client.outboundCalls.create({
to: appointment.customerPhone,
from: '+12125559999',
agentConfigurationId: 'appointment_confirmation_agent',
scheduleType: 'scheduled',
scheduledAt: appointmentTime - (2 * 60 * 60 * 1000),
maxDuration: 180,
maxRetries: 2,
});
console.log('Confirmation call scheduled');
}
sendAppointmentNotifications({
customerEmail: 'jane@example.com',
customerName: 'Jane Smith',
customerPhone: '+12125551234',
dateTime: '2026-06-25T15:00:00Z',
serviceName: 'Haircut & Style',
}).catch(console.error);
What the platform handles
| You call | Platform handles |
|---|---|
outboundSms.create() / outbound_sms.create() | Gateway selection, delivery, retry, status tracking |
outboundEmails.create() / outbound_emails.create() | SMTP routing, bounce handling, deliverability |
outboundCalls.create() / outbound_calls.create() | Telephony stack, AI agent, call recording |
No provider contracts. No infrastructure setup. No reliability engineering.
Phone number format
Always use E.164 format (+[country][number]):
Correct: +12125551234
Incorrect: (212) 555-1234 or 212-555-1234
Production checklist (Python guide)
- Store phone numbers in E.164 format.
- Use templates for messages edited by non-developers.
- Set retry limits intentionally.
- Respect local calling-hour and consent rules.
- Track message IDs and statuses in your own system.
Next steps
For the comprehensive reference — full template operations, status enums and types, architecture, and best practices — see the Outbound Communications Guide.