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)✓✓
Templates✓see 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.