WhatsApp Business API para código de verificação
Envia um template de autenticação do WhatsApp com um código de registro de uso único no corpo e um botão para copiar o código.
Visão geral do caso de uso
Envie um modelo de autenticação do WhatsApp com um código de registro único no corpo e um botão de copiar código. O usuário copia o código e completa o registro no seu aplicativo.
Exemplo de modelo
{{1}} é seu código de verificação. Para sua segurança, não compartilhe este código com ninguém.
- {{1}}código de verificação de registro único (dígitos)
- “Desculpe, preciso do texto que você gostaria que fosse traduzido. Por favor, forneça o conteúdo.”botão — fixo no modelo Meta

Quando usá-lo
Procure isso quando o registro atingir a etapa de verificação de telefone e você precisar de um código de uso único entregue na inicialização fria antes que qualquer conversa no WhatsApp exista. Ele se encaixa no cadastramento de novas contas, fluxos de integração que substituem o OTP por SMS e integradores conectando a verificação de telefone nas APIs de registro de backend.
Fluxo de Trabalho
- Capturar evento
O usuário inicia o registro e solicita a verificação por telefone.
phone:"+…" - Gera um código de uso único
O backend gera um código de uso único e resolve o número do WhatsApp.
phone:"+…" - Construir e enviar
A mensagem do modelo é construída com o código no corpo e o parâmetro do botão copiar-código.
POST/sendTemplate - Entregue
O usuário recebe WhatsApp e envia o código no seu formulário de inscrição.
delivered - Status rastreado
O backend valida o código e conclui o registro.
status:"read"

Implementação técnica
Pré-requisitos
- Chave da API 1MSG · Como obter a Chave da API
- Conta do WhatsApp Business · Como Conectar WABA
- Modelo do WhatsApp · Como Aprovar o Modelo WABA
- Consentimento do Cliente · Como Gerenciar o Consentimento dos Clientes
Exemplos de código
#!/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
Status de resposta e entrega
HTTP 2xx e JSON "sent": true significam que 1MSG aceitou a mensagem para envio — não que ela já chegou ao telefone do cliente. Salve o campo id (parece com wamid.…) para correlacionar os callbacks de entrega.
{
"sent": true,
"id": "wamid.HBgLMzgwNjM5...",
"message": "Message accepted for delivery"
}sentAceito para envio — não ainda no telefone do cliente
idArmazene-o; os retornos de entrega e
hookInfosão vinculados a isso.
A entrega em si chega mais tarde, como um callback separado. Registre um webhook (POST …/webhook) e 1MSG POSTs atualizações de status para seu endpoint HTTPS em uma carga útil hooks[] de nível superior.
{
"hooks": [
{
"id": "gBGGeSaGViBfAgnlzOSHEwK9O6F",
"type": "message",
"status": "sent",
"timestamp": "1654864094",
"recipient_id": "556123122026"
}
]
}statusenviado,entregue,lido— ou um status de falha quando aplicávelidCorrela o callback com o
idretornado pela chamada de enviotimestampSegundos Unix, como uma string
Se você prefere não receber chamadas de retorno, consulte GET {base}/{channel}/hookInfo?messageId=<id> em vez disso. Na prática, a entrega geralmente é concluída em poucos segundos — mas o contrato da API não garante isso, então nunca bloqueie um fluxo aguardando por isso.
Erros comuns
| Status | Resposta | Causa |
|---|---|---|
| 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. |

