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

Когда использовать это
Используйте этот сценарий, когда оформление заказа завершается, а у клиента всё ещё нет открытого чата в WhatsApp — только утверждённый шаблон может отправить первое подтверждение. Он подходит для интернет-магазинов и маркетплейсов, брендов сегмента D2C, усталых от тикетов «мой заказ прошёл?», и агентств, подключающих Shopify, WooCommerce или кастомную OMS к вебхуку нового заказа.
Как это работает
- Триггер
Платформа электронной коммерции создаёт событие нового заказа при завершении покупки.
event·triggered - Отслеживать событие
Система определяет номер телефона клиента и поля заказа из платформы или OMS.
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_PRODUCTNAME="___" # {{3}} product name
TEST_PAYMENTAMOUNT="___" # {{4}} payment amount
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_PRODUCTNAME=$TEST_PRODUCTNAME" \
"TEST_PAYMENTAMOUNT=$TEST_PAYMENTAMOUNT"; 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}} product name → ${TEST_PRODUCTNAME}
# {{4}} payment amount → ${TEST_PAYMENTAMOUNT}
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_PRODUCTNAME}" },
{ "type": "text", "text": "${TEST_PAYMENTAMOUNT}" }
]
}
]
}
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 and JSON "sent": true mean 1MSG accepted the message for sending — not that it already reached the customer's phone. Save the id field (looks like wamid.…) to correlate delivery callbacks.
{
"sent": true,
"id": "wamid.HBgLMzgwNjM5...",
"message": "Message accepted for delivery"
}sentПринято к отправке — ещёне на телефоне клиента
idСохраните это; обратные вызовы о доставке и
hookInfoиспользуют этот ключ
Доставка поступает позже, как отдельный callback. Зарегистрируйте вебхук (POST …/webhook), и 1MSG отправляет обновления статуса на ваш HTTPS-эндпоинт в основной hooks[] нагрузке.
{
"hooks": [
{
"id": "gBGGeSaGViBfAgnlzOSHEwK9O6F",
"type": "message",
"status": "sent",
"timestamp": "1654864094",
"recipient_id": "556123122026"
}
]
}statussent,delivered,read— или статус сбоя, если применимоidСоотносит обратный вызов с
id, возвращённым вызовом sendtimestampСекунды 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. |

