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

Когда использовать
Используйте этот сценарий, когда тикет застрял в ожидании ответа клиента, и служба поддержки не может двигаться дальше без него. Он подходит сервисным центрам, которые ждут уточняющих ответов по приостановленным случаям, претензионным командам и командам KYC, приближающимся к сроку ответа по SLA, а также агентствам, автоматизирующим процесс отслеживания, когда статус тикета — ожидание клиента.
Как это работает
- Триггер
Служба поддержки помечает тикет как ожидающий ответа клиента или при срабатывании таймера.
event·triggered - Захватить событие
Система определяет номер телефона получателя и поля для напоминания.
phone:"+…" - Сборка и отправка
Персонализированное сообщение-шаблон создаётся с тремя переменными в теле и статической кнопкой URL.
POST/sendTemplate - Доставлено
Клиент получает напоминание в WhatsApp с контекстом тикета и нужным действием.
delivered - Статус отслеживается
Результат доставки записывается; клиент может продолжать отвечать в сессии.
status:"read"

Техническая реализация
Предварительные требования
- Ключ API 1MSG · Как получить API-ключ
- Аккаунт WhatsApp Business · Подключение к 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_REQUESTDETAIL="___" # {{3}} request detail
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_REQUESTDETAIL=$TEST_REQUESTDETAIL"; 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}} request detail → ${TEST_REQUESTDETAIL}
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_REQUESTDETAIL}" }
]
}
]
}
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Соотносит обратный вызов с
id, возвращённым вызовом sendtimestampUnix-секунды в виде строки
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. |

