Сценарий отправляет клиенту персонализированный шаблон WhatsApp после завершения визита или приема, предлагая поделиться впечатлениями. Сообщение включает имя клиента, дату визита и краткое приглашение пройти опрос. Статическая кнопка URL открывает форму отзыва или страницу опроса.
Пример шаблона
Здравствуйте, {{1}}! Спасибо за ваш визит.{{2}}. {{3}} Пожалуйста, пройдите наш короткий опрос — это займет около минуты.
Пройти опрос
{{1}}
Имя клиента
{{2}}
дата визита или приема (например 12 августа 2026)
{{3}}
Оцените визит от 1 до 5. Это займет 1 минуту
“Пройти опрос”
кнопка — исправлена в шаблоне Meta
Когда использовать это
Используйте этот сценарий, когда клиент завершает визит или запись, и команде нужен структурированный опрос на WhatsApp вместо ручного сообщения или опроса только по электронной почте. Подходит для клиник и салонов, собирающих отзывы после записи, выездных сервисных команд после визитов на месте и агентств, подключающих триггеры после визита из систем бронирования, CRM или пользовательских процессов в разделе «Как это работает» планирования.
Более высокая частота ответов на опросы после визита
Запрос на участие в опросе приходит в WhatsApp с именем, датой визита и текстом запроса как тремя переменными в теле сообщения, чтобы запрос на отзыв находился в канале, который клиент уже использует, вместо опроса по email, который они никогда не открывают.
Сообщение после визита, отвечающее требованиям
Система бронирования отправляет утвержденный шаблон, когда встреча помечена как завершенная, поэтому запрос на опрос доходит до клиента, даже если активной переписки нет и свободные ответы не разрешены.
Никаких сообщений опроса вручную для агентов
Поствизитный триггер заполняет поля с телефоном получателя и опросом, формирует шаблон с тремя переменными в теле и статической кнопкой URL, чтобы персоналу не приходилось заново вводить данные о визите и помнить об отправке ссылки на опрос.
Посмотрите контекст, прежде чем они ответят
Имя клиента и дата визита отображаются в тексте сообщения, чтобы клиент знал, какое завершенное посещение он оценивает, прежде чем нажать на кнопку «Пройти опрос», которая открывает форму для отзыва.
Доставка зарегистрирована для дальнейшего анализа
Результат доставки записывается обратно в систему бронирования или CRM, завершение опроса отслеживается на связанном форме, чтобы обратная связь после визита оставалась привязанной к той же записи о встрече.
Как это работает
Собрать и отправить
Система бронирования или CRM запускает триггер после визита, когда встреча помечена как завершенная.
POST/sendTemplate
Захват события
Система определяет номер телефона получателя и поля анкеты.
phone: "+…"
Персонализированное сообщение по шаблону
Персонализированное сообщение по шаблону составляется с тремя переменными в теле и статической кнопкой URL.
POST/sendTemplate
Доставлено
Клиент получает запрос на опрос в WhatsApp с информацией о визите.
delivered
Отслеживание статуса
Результат доставки фиксируется в журнале, завершение опроса отслеживается вне WhatsApp.
#!/usr/bin/env bash
set -euo pipefail
# === Configuration (replace "___" placeholders) ===
API_BASE_URL="https://api.1msg.io" # production 1MSG API base URL
CHANNEL_ID="___" # channel ID from 1MSG dashboard
API_TOKEN="___" # channel JWT token (Bearer)
TEMPLATE_NAME="___" # approved template name
TEMPLATE_NAMESPACE="___" # template namespace (required — send fails without it)
TEMPLATE_LANGUAGE="___" # template language code, e.g. "en"
# === Test data ===
TEST_PHONE="___" # client phone in international format
TEST_CUSTOMERNAME="___" # {{1}} customer name
TEST_DATE="___" # {{2}} date or time
TEST_INFO="___" # {{3}} additional info
PHONE_NORM="$(printf '%s' "$TEST_PHONE" | tr -cd '0-9')"
for pair in "CHANNEL_ID=$CHANNEL_ID" "API_TOKEN=$API_TOKEN" \
"TEMPLATE_NAME=$TEMPLATE_NAME" "TEMPLATE_NAMESPACE=$TEMPLATE_NAMESPACE" \
"TEMPLATE_LANGUAGE=$TEMPLATE_LANGUAGE" "TEST_PHONE=$TEST_PHONE" \
"TEST_CUSTOMERNAME=$TEST_CUSTOMERNAME" \
"TEST_DATE=$TEST_DATE" \
"TEST_INFO=$TEST_INFO"; do
val="${pair#*=}"
if [ -z "$val" ] || [ "$val" = "___" ]; then
echo "Missing configuration value: ${pair%%=*}" >&2
exit 1
fi
done
if [ -z "$PHONE_NORM" ]; then
echo "Error: phone number has no digits after normalization" >&2
exit 1
fi
URL="${API_BASE_URL%/}/${CHANNEL_ID}/sendTemplate"
# params carries body ONLY. Button text is fixed in the Meta template — no button param.
# {{1}} customer name → ${TEST_CUSTOMERNAME}
# {{2}} date or time → ${TEST_DATE}
# {{3}} additional info → ${TEST_INFO}
read -r -d '' PAYLOAD <<JSON || true
{
"phone": "${PHONE_NORM}",
"template": "${TEMPLATE_NAME}",
"namespace": "${TEMPLATE_NAMESPACE}",
"language": { "policy": "deterministic", "code": "${TEMPLATE_LANGUAGE}" },
"params": [
{
"type": "body",
"parameters": [
{ "type": "text", "text": "${TEST_CUSTOMERNAME}" },
{ "type": "text", "text": "${TEST_DATE}" },
{ "type": "text", "text": "${TEST_INFO}" }
]
}
]
}
JSON
RESPONSE="$(curl -s -w '\n%{http_code}' -X POST "$URL" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${API_TOKEN}" \
-d "$PAYLOAD")"
HTTP_CODE="$(printf '%s' "$RESPONSE" | tail -n1)"
BODY="$(printf '%s' "$RESPONSE" | sed '$d')"
case "$BODY" in
*'"sent":true'*) ok=1 ;;
*) ok=0 ;;
esac
if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 300 ] && [ "$ok" -eq 1 ]; then
echo "Message sent to client."
echo "API response: $BODY"
else
echo "Send failed. HTTP status: $HTTP_CODE" >&2
echo "$BODY" >&2
exit 1
fi
Статус ответа и доставки
HTTP 2xx и JSON "sent": trueозначают, что 1MSG принял сообщение для отправки, но не то, что оно уже достигло телефона клиента. Сохраните idполе (выглядит как wamid.…), чтобы сопоставить обратные вызовы о доставке.
Принято к отправке — еще не получено на телефон клиента
id
Храните это: обратные вызовы доставки и hookInfo используют это как ключ
Уведомление о доставке приходит позже, в виде отдельного обратного вызова. Зарегистрируйте вебхук (POST …/webhook), и 1MSG будет отправлять обновления статуса на ваш HTTPS-эндпоинт в виде данных верхнего уровня.hooks[]
200 OKВебхук статуса доставки — данные, которые вы получаете
sent, delivered, read — или статус ошибки, если это уместно
id
Сопоставляет callback с id, возвращенным вызовом send
timestamp
Unix-секунды в виде строки
If you would rather not receive callbacks, poll GET {base}/{channel}/hookInfo?messageId=<id> instead. In practice delivery often completes within seconds — but the API contract does not guarantee it, so never block a flow waiting on it.
Типичные ошибки
Статус
Ответ
Причина
200
Message was not sent: template is not defined
namespace, template or language missing from the request body.
200
template name (…) does not exist in <language>
The template is approved in a different language than the one requested.
200
Message was not sent: provide chatId, phone, bsuid, or username
No recipient the channel could resolve.
403
access denied
The token is wrong, or belongs to a different channel than the URL.
429
too many requests. please try later
The channel is over its send rate.
ЧАСТО ЗАДАВАЕМЫЕ ВОПРОСЫ
Да, для холодных сообщений в WhatsApp нужен одобренный Meta шаблон.