Отправляет новый одноразовый код подтверждения через шаблон аутентификации WhatsApp, когда пользователь нажимает «Отправить код ещё раз». Каждая попытка использует параметры тела и кнопки «Копировать код» с заново сгенерированным значением.
Пример шаблона
{{1}} — ваш код подтверждения. Не сообщайте его никому.
Скопировать код
{{1}}
свежесгенерированный одноразовый код подтверждения (числа)
“Скопировать код”
кнопка — исправлено в шаблоне Meta
Когда использовать это
Используйте это, когда пользователь нажимает «Отправить код повторно», потому что первый OTP истёк или не дошёл, и вам всё ещё нужно отправить новый код подтверждения без открытой сессии WhatsApp. Подходит для процессов входа и подтверждения аккаунта для разработчиков, небольших команд и агентств, которые используют один и тот же шаблон аутентификации при каждой повторной попытке с ограничением частоты.
Меньше заброшенных верификаций
Одна переменная в теле передаёт свежесгенерированные цифры в шаблоне аутентификации, поэтому пользователь получает новый код в WhatsApp, а не остаётся на экране входа.
Повторные отправки без сессии
Каждая попытка отправляет утверждённый шаблон аутентификации с параметрами тела и кнопки копирования кода, так как при отправке OTP с холодным стартом нельзя использовать свободный текст.
Быстрый ввод кода
Кнопка копирования кода получает такое же значение OTP, как и тело сообщения, поэтому пользователь может вставить цифры, вместо того чтобы вводить их заново.
Управляемая безопасность повторных попыток
Ваш бекенд аннулирует предыдущий код перед созданием нового шаблона, поэтому только последний OTP остаётся действительным при повторных отправках.
Как это работает
Действия клиента
Пользователь нажимает «Отправить код заново» после тайм-аута.
user action
Собрать и отправить
Бэкэнд аннулирует старый код, генерирует новый и отправляет шаблон.
POST/sendTemplate
Копировать новый код
Пользователь копирует новый код и отправляет.
user action
Доставлено
Бэкэнд проверяет данные и продолжает исходный процесс проверки.
#!/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_CODE="___" # {{1}} otp code
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_CODE=$TEST_CODE"; 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 and button blocks.
# {{1}} otp code → ${TEST_CODE}
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_CODE}" }
]
},
{
"type": "button",
"sub_type": "url",
"index": "0",
"parameters": [ { "type": "text", "text": "${TEST_CODE}" } ]
}
]
}
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
Связывает обратный вызов с id, возвращённым вызовом отправки
timestamp
Строка, представляющая секунды Unix
Если вы предпочитаете не получать обратные вызовы, вместо этого используйте опрос 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.
ЧАСТО ЗАДАВАЕМЫЕ ВОПРОСЫ
Да, для холодных сообщений в WhatsApp нужен одобренный Meta шаблон.