WhatsApp Business API для запроса CSAT по поддержке
Сценарий отправляет клиенту персонализированный шаблон WhatsApp после завершения поддержки, предлагая оценить качество обслуживания.
Обзор сценария
Сценарий отправляет клиенту персонализированный шаблон WhatsApp после завершения поддержки с просьбой оценить качество обслуживания. Сообщение включает имя клиента, номер тикета и краткий запрос на участие в опросе. Кнопка со статичным URL открывает форму CSAT или страницу отзывов.
Пример шаблона
Здравствуйте, {{1}}! Запрос #{{2}} закрыт. {{3}} Оцените качество поддержки — это займёт около минуты.
- {{1}}имя клиента
- {{2}}номер тикета или дела
- {{3}}Оцените свой опыт по шкале от 1 до 5 (это займёт 1 минуту)
- “Оценить поддержку”кнопка — исправлено в шаблоне Meta

Когда использовать это
Используйте этот сценарий, когда обращение в поддержку решено или закрыто, и команде нужна структурированная оценка удовлетворённости в WhatsApp, а не сообщение вручную от агента или опрос только по электронной почте. Подходит для служб поддержки, собирающих отзывы от 1 до 5 звёзд или NPS после закрытия тикета, контакт-центров, проводящих стандартизированные опросы после решения случаев, и агентств, подключающих триггеры CSAT из Zendesk, Freshdesk или пользовательских CRM Как это работает.
Как это работает
- Создать и отправить
Служба поддержки запускает триггер CSAT после решения, когда случай подходит.
POST/sendTemplate - Фиксация события
Система определяет номер телефона получателя и поля опроса.
phone:"+…" - Персонализированный шаблон сообщения
Персонализированный шаблон сообщения создаётся с тремя переменными в теле и кнопкой со статичной ссылкой.
POST/sendTemplate - Доставлено
Клиент получает запрос на WhatsApp CSAT с контекстом тикета.
delivered - Статус отслеживается
Результат доставки фиксируется, завершение опроса отслеживается за пределами WhatsApp.
status:"read"

Техническая реализация
Требования
- Ключ 1MSG API · Как получить API-ключ
- Бизнес-аккаунт WhatsApp · Как подключить WABA
- Шаблон WhatsApp · Как одобрить шаблон WABA
- Согласие клиента на получение сообщений · Как управлять согласием клиентов
Примеры кода
#!/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_TICKETNUMBER="___" # {{2}} ticket number
TEST_NEXTSTEP="___" # {{3}} next step
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_TICKETNUMBER=$TEST_TICKETNUMBER" \
"TEST_NEXTSTEP=$TEST_NEXTSTEP"; 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}} ticket number → ${TEST_TICKETNUMBER}
# {{3}} next step → ${TEST_NEXTSTEP}
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_TICKETNUMBER}" },
{ "type": "text", "text": "${TEST_NEXTSTEP}" }
]
}
]
}
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.…), чтобы сопоставить с уведомлениями о доставке.
{
"sent": true,
"id": "wamid.HBgLMzgwNjM5...",
"message": "Message accepted for delivery"
}sentПринято для отправки — ещё не доставлено на телефон клиента
idСохраните это; обратные вызовы доставки и
hookInfoпривязываются к этому
Delivery itself arrives later, as a separate callback. Register a webhook (POST …/webhook) and 1MSG POSTs status updates to your HTTPS endpoint in a top-level hooks[] payload.
{
"hooks": [
{
"id": "gBGGeSaGViBfAgnlzOSHEwK9O6F",
"type": "message",
"status": "sent",
"timestamp": "1654864094",
"recipient_id": "556123122026"
}
]
}statussent,delivered,read— или статус ошибки, если это уместноidСоотносит callback с
id, возвращённым вызовом sendtimestampUnix-секунды в виде строки
Если вы предпочитаете не получать обратные вызовы, используйте GET {base}/{channel}/hookInfo?messageId=<id>опросы. На практике доставка часто завершается в течение нескольких секунд — но контракт API этого не гарантирует, поэтому никогда не блокируйте процесс в ожидании этого
Типичные ошибки
| Статус | Ответ | Причина |
|---|---|---|
| 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. |

