Интеграция Twilio и n8n: SMS/WhatsApp с consent, E.164 и status callback ¶
Обновлено: 2026-05-30
Импортируйте JSON в n8n, замените credentials, домены, sender IDs, лимиты, callback URL и production-политики под вашу инфраструктуру.
Проблема: уведомления через SMS или WhatsApp нельзя отправлять как обычный HTTP-запрос: повторный retry списывает деньги, неправильный формат телефона даёт failed message, а отсутствие consent создаёт юридический риск.
Решение: интеграция Twilio и n8n должна нормализовать телефон в E.164, проверить consent/channel policy, записать idempotency key, отправить сообщение через Messaging API и обработать status callback. Такой подход закрывает не демонстрационный happy path, а реальную production-боль: повторы, consent, delivery status, API-ошибки, ограничения провайдера и понятный audit trail.
Проблема: почему простая отправка ломает коммуникации ¶
Коммуникационный workflow нельзя оценивать только по ответу API. Важны consent, формат адреса или телефона, повторная отправка, связь с CRM, callback-статусы и способ отката, если провайдер принял запрос, но сообщение не доставлено.
Для этой страницы основной объект — Twilio message. Входной контракт должен явно фиксировать phone, channel, message_template, consent, customer_id, message_sid, status_callback. Если эти поля приходят нестабильно, автоматизация начинает угадывать и может отправить сообщение не тому получателю, не тем каналом или повторно.
Поэтому workflow строится вокруг детерминированных проверок: сначала validation, consent и idempotency, затем отправка, затем callback/audit и только потом бизнес-действия вроде смены статуса или уведомления менеджера.
Архитектура workflow для n8n ¶
| Блок | Задача | Production-проверка |
|---|---|---|
| Business trigger | получает событие доставки, оплаты или SLA | есть customer_id и phone |
| Normalize E.164 | приводит телефон к формату API | +7XXXXXXXXXX или другой country policy |
| Consent guard | проверяет разрешённый канал | SMS/WhatsApp не отправляются без consent |
| Idempotency storage | не списывает деньги повторной отправкой | unique key до Twilio API |
| Twilio Messaging API | отправляет SMS/WhatsApp | from/messagingServiceSid, body, callback |
| Status callback | обновляет queued/sent/delivered/failed | message_sid связан с customer_id |
Такой workflow удобно сопровождать: mapping, API-запрос, retry, callback и human-readable audit не смешиваются в одной ноде.
Контракт входных данных ¶
{
"event": "send_delivery_notice",
"customer_id": "cust-7781",
"phone": "+7 (916) 123-45-67",
"channel": "sms",
"template": "delivery_notice_ru",
"variables": {
"order_id": "10492",
"pickup_code": "7310"
},
"consent": {
"sms": true,
"whatsapp": false
},
"priority": "normal"
}Payload можно расширять, но нельзя делать обязательные поля “по настроению”. Если источник не передал внешний ID, получателя, шаблон или consent, workflow должен остановиться с понятной ошибкой до отправки.
Code Node: нормализация, mapping и guard-условия ¶
const src = $json.body ?? $json;
const rawPhone = String(src.phone ?? '').trim();
let digits = rawPhone.replace(/\D/g, '');
if (digits.length === 11 && digits.startsWith('8')) digits = `7${digits.slice(1)}`;
if (digits.length === 10) digits = `7${digits}`;
if (!/^7\d{10}$/.test(digits)) throw new Error(`Phone is not valid for RU E.164: ${rawPhone}`);
const channel = String(src.channel ?? 'sms').toLowerCase();
if (!['sms', 'whatsapp'].includes(channel)) throw new Error(`Unsupported Twilio channel: ${channel}`);
if (channel === 'sms' && src.consent?.sms !== true) throw new Error('No SMS consent');
if (channel === 'whatsapp' && src.consent?.whatsapp !== true) throw new Error('No WhatsApp consent');
const customerId = String(src.customer_id ?? '').trim();
const template = String(src.template ?? '').trim();
if (!customerId || !template) throw new Error('customer_id and template are required');
const e164 = `+${digits}`;
const idempotencyKey = `twilio:${channel}:${template}:${customerId}:${e164}`;
return [{
json: {
action: 'send_twilio_message',
idempotency_key: idempotencyKey,
to: channel === 'whatsapp' ? `whatsapp:${e164}` : e164,
channel,
body: `Заказ ${src.variables?.order_id ?? ''}: код ${src.variables?.pickup_code ?? ''}`.trim(),
status_callback: 'https://YOUR-N8N-DOMAIN/webhook/twilio-status-callback',
audit: { customer_id: customerId, template, phone_e164: e164 }
}
}];Этот скрипт n8n не заменяет политику провайдера. Его задача — привести данные к стабильному контракту, сформировать idempotency key и не пропустить опасный payload дальше по цепочке.
Готовый workflow JSON: скачать и импортировать ¶
В архиве страницы есть импортируемый workflow JSON и тестовый payload. После импорта замените credentials, домены, sender IDs, callback URL, лимиты и правила доступа. Не запускайте сценарий на production-данных, пока не проверены повторы, пустые значения и ошибки API.
{
"name": "Nodbot - Twilio SMS WhatsApp with consent and status callback",
"nodes": [
{
"name": "Business trigger",
"type": "n8n-node",
"purpose": "получает событие доставки, оплаты или SLA"
},
{
"name": "Normalize E.164",
"type": "n8n-node",
"purpose": "приводит телефон к формату API"
},
{
"name": "Consent guard",
"type": "n8n-node",
"purpose": "проверяет разрешённый канал"
},
{
"name": "Idempotency storage",
"type": "n8n-node",
"purpose": "не списывает деньги повторной отправкой"
},
{
"name": "Twilio Messaging API",
"type": "n8n-node",
"purpose": "отправляет SMS/WhatsApp"
},
{
"name": "Status callback",
"type": "n8n-node",
"purpose": "обновляет queued/sent/delivered/failed"
}
],
"connections": "Business trigger → Normalize E.164 → Consent guard → Idempotency storage → Twilio Messaging API → Status callback"
}Пошаговая настройка связки ¶
- Определите allowed channels: SMS, WhatsApp или оба, и где хранится consent клиента.
- Настройте sender: Twilio number или Messaging Service, а для WhatsApp — approved sender и шаблоны.
- Добавьте нормализацию E.164 и запретите отправку на телефоны без country policy.
- Сохраняйте idempotency key до отправки и Twilio message_sid после ответа API.
- Подключите Status Callback webhook в n8n и обновляйте CRM по delivered/failed, а не только по созданию message.
Что проверить после импорта workflow
Откройте каждую ноду, замените credentials и IDs, включите dry-run там, где доступно, затем выполните сценарий на тестовом объекте. Для платных или внешних отправок добавьте approval, rate limit и отдельный тестовый получатель.
Тесты перед production ¶
Минимальный smoke test:
curl -X POST "https://YOUR-N8N-DOMAIN/webhook/twilio-sms-whatsapp-n8n" -H "Content-Type: application/json" --data @integration-twilio-n8n-sms-whatsapp-payload.json- повторный payload
- телефон 8 916 123-45-67
- нет SMS consent
- unsupported channel
- failed status callback от Twilio
Отдельно проверьте, что retry n8n не создаёт повторную отправку. Для критичных действий используйте durable storage: Postgres, CRM custom field, audit table или другой слой с уникальным ключом.
Production-риски ¶
- Retry создаёт повторную платную отправку.
- Телефон не нормализован в E.164, и сообщения падают silently.
- WhatsApp отправляется без approved template или consent.
- Status callback не обрабатывается, поэтому CRM считает сообщение доставленным.
- PII и текст SMS уходят в execution logs без retention policy.
Полезные ссылки и смежные материалы ¶
Внутренняя перелинковка помогает перейти от общего integration-гайда к готовым workflow, а внешние ссылки ведут на официальную документацию API и n8n-нод.
Критерии готовности ¶
- Повторный запуск не отправляет второе сообщение.
- Consent проверяется до Twilio API.
- message_sid и status сохраняются в audit table.
- failed/undelivered callbacks создают задачу или alert.
- Секреты Twilio не попадают в payload, логи и публичные workflow JSON.