Skip to main content

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.

OperationTypeScriptPython
Send SMS (direct, template)
Send SMS (scheduled)
Send email (direct, template, CC/BCC)
Send email (attachment)
Request call (immediate, scheduled)
Templatessee Outbound Communications
Status queriessee Outbound Communications
Error handling

Quick start

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',
});

Three channels. One pattern.

Send SMS

Direct message

await client.outboundSms.create({
to: '+12125551234',
from: '+12125559999',
body: 'Your verification code is 847291. Valid for 10 minutes.',
maxRetries: 2,
});

With a template

await client.outboundSms.create({
to: '+12125551234',
from: '+12125559999',
templateId: 'verification_code',
templateVariables: { 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

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',
});

With a template

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',
},
});

Multiple recipients & CC/BCC

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: { ... },
});

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

await client.outboundCalls.create({
to: '+12125551234',
from: '+12125559999',
agentConfigurationId: 'support_agent',
scheduleType: 'immediate',
maxDuration: 300, // 5 minutes
maxRetries: 2,
});

Scheduled

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,
});

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 callPlatform 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.