Customer.io
Customer.io — платформа автоматизации маркетинговых коммуникаций. Готового SMS-канала для AlphaSMS в ней нет, но на любом тарифе Customer.io умеет вызывать внешний API действием Send and receive data (в рассылках тот же механизм называется каналом Webhook).
В этой инструкции — как отправлять SMS из кампании, рассылки или транзакционного сообщения Customer.io через API AlphaSMS и как получать отчёты о доставке.
| Направление | Как работает |
|---|---|
| Customer.io → AlphaSMS | POST-вебхук с телом JSON, где type равен sms |
| AlphaSMS → ваша система | Отчёт о доставке на адрес из параметра hook |
Что нужно перед началом
- Активный аккаунт AlphaSMS с включённой опцией Активировать API — см. Настройки API.
- API-ключ (шаг 1 ниже).
- Имя отправителя — буквенно-цифровая подпись, которую абонент видит вместо номера (от 3 до 11 латинских букв и цифр). Телефонный номер в качестве отправителя AlphaSMS не использует.
- Профили в Customer.io с телефоном в международном формате
(например,
+380971234567или380971234567).
Шаг 1. Создайте API-ключ
В кабинете AlphaSMS откройте Настройки → API. В таблице перечислены ключи с датой создания, сроком действия, состоянием, комментарием и списком разрешённых IP.
Нажмите ADD, укажите комментарий (например, Customer.io), отметьте Active и нажмите
EXECUTE.
Полное значение ключа показывается один раз — сразу после создания. Скопируйте его тут же: в таблице потом видны только первые символы.
Для ключа, который используется в Customer.io, оставьте поле IP whitelisting пустым.
Customer.io отправляет вебхуки с большого и меняющегося пула адресов, поэтому фиксированный список
IP рано или поздно начнёт отбивать трафик ошибкой Access denied. Лучше завести для Customer.io
отдельный ключ — его можно отозвать, не задев другие интеграции.
Шаг 2. Выберите имя отправителя
Имя отправителя передаётся в каждом сообщении в параметре sms_signature, поэтому для разных
кампаний можно использовать разные имена: бренд — для маркетинга, название сервиса — для
транзакционных уведомлений. Имена работают динамически: вы не ограничены заранее заданным списком,
новое имя начинает работать сразу после первой отправки с ним.
Ограничения приходят только со стороны сети получателя: часть операторов и стран принимает буквенно-цифровые имена лишь после регистрации и может отклонить или подменить незнакомое имя. Уточните у поддержки направления, на которые вы планируете слать.
Имена, которые уже используются на аккаунте, видны в кабинете — см. Имя отправителя.
Шаг 3. Добавьте вебхук в Customer.io
- Кампания (journey) — откройте workflow, перетащите блок Send and receive data и нажмите Add Request.
- Рассылка (broadcast) — на шаге Content выберите канал Webhook и нажмите Add content.
Настройки запроса:
| Поле | Значение |
|---|---|
| Method | POST |
| Request URL | https://api-async.alphasms.ua/v1/json |
| Header | Content-Type: application/json |
Используйте именно этот адрес для всех сообщений из Customer.io. Эндпоинт асинхронный: он принимает запрос в очередь и отвечает мгновенно — ровно это и нужно рассыльщику, потому что Customer.io делает по вебхуку на каждый профиль и кампания легко порождает сотни параллельных запросов.
Заголовки X-CIO-Idempotency-Key и X-CIO-Signature Customer.io добавляет сам. Отдельный
заголовок авторизации не нужен — API AlphaSMS авторизует запрос по полю auth в теле.
Шаг 4. Соберите тело запроса
Вставьте payload ниже в редактор тела и замените YOUR_API_KEY и YOUR_SENDER_ID. Панель
Preview справа подставляет данные тестового профиля, поэтому видно точный JSON, который уйдёт
в API.
{% capture sms_text %}Привет, {{ customer.first_name | default: 'друг' }}! Ваш заказ уже в пути.{% endcapture %}
{
"auth": "YOUR_API_KEY",
"data": [
{
"type": "sms",
"id": "{{delivery_id}}",
"phone": "{{ customer.phone | default: '' | remove: '+' | remove: ' ' | remove: '-' }}",
"sms_signature": "YOUR_SENDER_ID",
"sms_message": {{ sms_text | strip_newlines | json }},
"hook": "https://your-app.example.com/dlr"
}
]
}
| Параметр | Обязательный | Описание |
|---|---|---|
auth | да | Ваш API-ключ |
type | да | sms. Другие значения включают Viber, RCS, WhatsApp и мультиканальную отправку |
id | нет | Ваш идентификатор сообщения, возвращается в каждом отчёте о доставке. {{delivery_id}} — идентификатор конкретной отправки в Customer.io |
phone | да | Номер получателя в международном формате, только цифры |
sms_signature | да | Имя отправителя |
sms_message | да | Текст сообщения |
hook | нет | Адрес, на который придут отчёты о доставке этого сообщения |
sms_lifetime | нет | Срок жизни сообщения в секундах, от 60 до 259200 (3 суток) |
short_link | нет | true — сокращать и отслеживать ссылки в тексте (согласно тарифу) |
unsubscribe_link | нет | true — добавить ссылку отписки (согласно тарифу) |
Полный список параметров — в разделе Отправка SMS.
{{delivery_id}}в предпросмотре пустой (показываетсяunsent) и подставляется в момент отправки. Оставьте его: значение должно быть уникальным для каждого сообщения — повтор воспринимается как дубликат, и сообщение не отправляется.- Оборачивайте текст в блок
captureи выводите фильтромjson. Фильтр сам ставит кавычки и экранирует кавычки, слэши и управляющие символы, поэтому эмодзи, апострофы и переносы строк из данных клиента не сломают JSON. - Не применяйте к тексту фильтр
escape— в Customer.io он делает percent-кодирование (@превращается в%40), и абонент получит закодированный текст. - К атрибутам, которых может не быть в профиле, всегда добавляйте
| default: ''. Неопределённая переменная для Customer.io — ошибка композера (undefined variable: customer.phone), запрос уходит с испорченным телом, и API его отклоняет. - Переменные
{{event.*}}существуют только в кампаниях по событию. В рассылке и в кампании по сегменту они дают ту же ошибку неопределённой переменной. - Одно сообщение на профиль. Если нужно отправить сразу на несколько номеров, добавьте объекты в
массив
data.
Шаг 5. Обработайте ответ
Эндпоинт подтверждает, что пакет принят в очередь, и возвращает идентификатор запроса:
{
"request_id": "cf-ray-1234567890-ABC",
"success": true
}
Идентификаторов отдельных сообщений в этом ответе нет — сообщение ещё идёт к шлюзу.
request_id повторяется в каждом отчёте о доставке, поэтому его стоит сохранить. В разделе
Response действия нажмите Add attributes и сопоставьте:
| Атрибут journey | Значение |
|---|---|
sms_request_id | response.request_id |
sms_queued | response.success |
Проблемы с самим запросом возвращаются настоящими HTTP-кодами:
| Код | Что означает |
|---|---|
400 | Невалидный JSON или пустой/некорректный массив data |
401 | Не передан, пуст или не принят auth |
405 | Метод отличается от POST |
413 | Слишком большое тело запроса |
415 | Content-Type не application/json |
503 | Очередь временно недоступна |
Customer.io повторяет запросы с кодами 408, 409, 429 и 5xx до 11 раз примерно в течение
часа, так что короткий 503 лечится сам. 400, 401 и 415 — ошибки конфигурации, они не
повторяются: следите за ними в метриках кампании после запуска.
Принятое сообщение всё ещё может быть отклонено, когда его обработает шлюз. Причина приходит в отчёте о доставке и видна в кабинете в разделе Отчёты → API:
| Причина | Что означает |
|---|---|
Error in Alpha-name | Имя отправителя недопустимо на этом маршруте или у этого оператора |
Not enough money | Недостаточно средств на балансе |
Duplicate ID | Значение id уже использовалось на аккаунте — оно должно быть уникальным |
Please enter valid receiver phone number | Пустой или некорректный phone |
Receiver blacklisted | Номер в вашем чёрном списке или отписался |
SMS is too long | Текст превышает максимальную длину |
Operator not supported | Нет маршрута к этому оператору |
Шаг 6. Принимайте отчёты о доставке
Каждое сообщение с параметром hook порождает POST-запрос на этот адрес при каждой смене
статуса. Именно там виден итоговый результат отправки, поэтому настройте приём отчётов до запуска
кампании.
{
"id": "01HB…",
"msg_id": 123456789,
"type": "sms",
"status": "DELIVERED",
"updated": "2026-08-10T12:34:56+03:00",
"request_id": "cf-ray-1234567890-ABC"
}
id— значение, которое вы передали в запросе (в примере выше этоdelivery_idиз Customer.io); по нему отчёт сопоставляется с сообщением.msg_id— идентификатор, присвоенный шлюзом.updated— момент смены статуса, форматYYYY-MM-DDThh:mm:ss±hh:mm.request_id— идентификатор запроса, в котором пришло сообщение (асинхронный эндпоинт).
Запрос подписан: в заголовке X-Signature лежит sha256(json_body + api_key), посчитанный тем же
ключом, которым отправлялось сообщение. Запросы с несовпавшей подписью отбрасывайте.
$body = file_get_contents('php://input');
if (!hash_equals(hash('sha256', $body . $apiKey), $_SERVER['HTTP_X_SIGNATURE'] ?? '')) {
http_response_code(403);
exit;
}
Отвечайте кодом 200. Статусы перечислены в справочнике
Статусы сообщений; чаще всего встречаются
ACCEPTED, QUEUED, DELIVERED, UNDELIVERABLE, EXPIRED, REJECTED.
Общий для аккаунта адрес отчётов можно указать в Настройки → API → URL для отчётов о доставке: он действует на все сообщения аккаунта. Подробнее: Webhook.
Шаг 7. Тест и запуск
- Нажмите Send test… в редакторе и подтвердите запрос. Ответ появится в панели Preview — это настоящий запрос, поэтому с боевым ключом SMS действительно уйдёт.
- Проверьте результат в кабинете: Отчёты → API показывают сообщение, его цену и статус.
- Переключите действие в режим Send automatically (кампании) или завершите мастер рассылки.
- Жёсткого лимита запросов в секунду нет. Если планируются всплески в десятки тысяч сообщений, предупредите поддержку заранее — пропускную способность аккаунта пересмотрят.
- Customer.io обрывает вебхук через 16 секунд. Наш API отвечает заведомо быстрее.
- Добавьте в триггер или аудиторию кампании условие по телефону (например, phone exists), чтобы профили без номера вообще не доходили до вебхука.
Другие каналы
Тем же вебхуком отправляются Viber, RCS, WhatsApp и голосовые звонки, в том числе каскадом:
например, сначала Viber, а SMS — только если Viber не доставлен. Меняется type и добавляются
параметры канала:
type | Результат |
|---|---|
viber | Viber-сообщение |
viber+sms | Viber с досылкой SMS |
rcs+sms | RCS с досылкой SMS |
voice | Голосовой звонок |
hlr | Проверка номера — оператор, роуминг и переносимость, без отправки сообщения |