WhatsApp Business API para envio de proposta comercial
O cenário envia ao prospect um modelo de WhatsApp personalizado quando uma proposta comercial está pronta.
Visão geral do caso de uso
O cenário envia para o prospect uma mensagem personalizada pelo WhatsApp quando uma proposta comercial está pronta. A mensagem inclui o nome do prospect, o produto ou serviço oferecido e uma breve nota sobre a proposta. Um botão de URL estático abre o documento da proposta online.
Exemplo de modelo
Olá, {{1}}! Estamos enviando uma proposta comercial para "{{2}}". {{3}} Abra o documento usando o botão abaixo — estamos aqui se você tiver perguntas.
- {{1}}nome do prospect ou cliente
- {{2}}produto ou serviço coberto pela proposta
- {{3}}Nota de proposta curta (por exemplo, válida até 30 de junho, inclui cronograma de implementação)
- “Proposta aberta”botão — fixo no modelo do Meta

Quando usá-lo
Aja para este cenário quando uma proposta comercial estiver pronta, mas o e-mail ou um link de CRM sozinho não está sendo aberto — o prospect não tem um thread ativo no WhatsApp, então apenas um template aprovado pode ser utilizado na primeira abordagem. Isso se encaixa em equipes de vendas B2B que estão enviando cotações logo após a geração, agências acionando o WhatsApp quando uma proposta em PDF ou na web é publicada no CRM, e empresas de serviços enviando pacotes de preços para leads qualificados.
Fluxo de trabalho
- Acionar
O CRM ou o sistema de propostas emite um evento pronto para proposta.
event·triggered - Capturar evento
O sistema resolve os campos de telefone do prospect e proposta.
phone:"+…" - Construir & enviar
Uma mensagem de template personalizada é construída com três variáveis de corpo e um botão de URL estático.
POST/sendTemplate - Entregue
O prospect recebe a mensagem do WhatsApp com o link da proposta.
delivered - Status rastreado
O resultado da entrega é registrado no CRM; as vendas podem acompanhar com base no engajamento.
status:"read"

Implementação técnica
Pré-requisitos
- 1MSG API Key · Como obter a chave da API
- Conta do WhatsApp Business · Como Conectar WABA
- Modelo do WhatsApp · Como Aprovar o Modelo WABA
- Cadastro do cliente · Como Gerenciar o Consentimento
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_CUSTOMERNAME="___" # {{1}} customer name
TEST_PRODUCTORSERVICENAME="___" # {{2}} product or service name
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_PRODUCTORSERVICENAME=$TEST_PRODUCTORSERVICENAME" \
"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}} product or service name → ${TEST_PRODUCTORSERVICENAME}
# {{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_PRODUCTORSERVICENAME}" },
{ "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
Status de resposta e entrega
HTTP 2xx e JSON "sent": true significam que 1MSG aceitou a mensagem para envio — não que ela já tenha chegado ao telefone do cliente. Salve o campo id (que 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 isso; os callbacks de entrega e
hookInfoestão vinculados a isso.
A entrega em si chega depois, como um callback separado. Registre um webhook (POST …/webhook) e o 1MSG envia atualizações de status para seu endpoint HTTPS em um payload 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ávelidCorrelaciona o callback com o
idretornado pela chamada de enviotimestampSegundos Unix, como uma string
Se você preferir não receber chamadas de retorno, faça uma consulta GET {base}/{channel}/hookInfo?messageId=<id> em vez disso. Na prática, a entrega geralmente é concluída em segundos — mas o contrato da API não garante isso, então nunca bloqueie um fluxo esperando 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. |

