1Ambientes e chaves
| Ambiente | URL base | Chave começa com |
|---|---|---|
| Homologação | https://www.dwmsystems.com.br/api/v1/mensageria | dwmmsg_test_ |
| Produção | https://www.dwmsystems.com.br/api/v1/mensageria | dwmmsg_live_ |
A URL é a mesma. O que define o ambiente é a chave: cada ambiente é uma conta separada, com chaves próprias.
Homologação nunca envia mensagem real e não gera custo. Ela simula o ciclo completo: aceita → enviada → entregue → lida. Um número terminado em 0000 simula falha (código 131026, número sem WhatsApp). Os eventos de webhook saem iguais aos de produção.
Autenticação
Todas as chamadas levam o cabeçalho:
Authorization: Bearer dwmmsg_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx- A chave é entregue uma única vez, por canal seguro. A DWM guarda só o hash dela e não consegue recuperá-la: se perder, pedimos uma nova.
- Rotação: a DWM gera uma chave nova e mantém a anterior valendo por um prazo combinado (por exemplo, 7 dias), para o sistema trocar sem parar.
- Revogação: a chave para de valer na hora.
- Só HTTPS (TLS 1.2 ou superior). A chave nunca vai na URL.
- Use a chave só no servidor. Guarde em variável de ambiente ou cofre de segredos; nunca em aplicativo, página no navegador, log ou repositório de código. Se vazar, peça a revogação na hora.
Conectar o número da empresa
O número e a conta do WhatsApp Business continuam sendo da empresa, e a cobrança da Meta é feita na conta dela.
- A DWM envia um link de conexão. Ele vale 7 dias e serve para uma conexão.
- Quem administra a empresa na Meta abre o link e clica em Conectar com o Facebook.
- Na janela da Meta, a pessoa escolhe (ou cria) a conta do WhatsApp Business e o número, e autoriza a DWM Systems.
A DWM registra o número na API oficial e passa a receber os status de entrega. O acesso pode ser removido a qualquer momento nas Configurações do negócio da Meta.
2Enviar mensagem
POST /mensagens com Content-Type: application/json.
Cabeçalho opcional e recomendado: Idempotency-Key: <id único do seu lado> (até 100 caracteres). Se a mesma chave chegar de novo, por exemplo numa retentativa depois de um tempo esgotado na sua rede, a API devolve a mensagem original com 200, sem enviar de novo.
Campos
| Campo | Tipo | Obrigatório | Observação |
|---|---|---|---|
para | texto | sim | Número com DDI e DDD, ex.: 5569999998888. Pontuação é ignorada. Sem o 55, ele é acrescentado quando o número tem 10 ou 11 dígitos. |
tipo | texto | sim | texto, imagem, documento ou modelo |
texto | texto | se tipo=texto | até 4.096 caracteres |
arquivo | objeto | se imagem ou documento | ver abaixo |
modelo | objeto | se tipo=modelo | ver abaixo |
referencia_externa | texto | não | seu identificador (ex.: nº do protocolo), até 100 caracteres; volta em consultas e webhooks |
arquivo — informe um dos dois, url ou base64:
| Campo | Observação |
|---|---|
url | endereço https público do arquivo; a Meta baixa o arquivo no momento do envio |
base64 | conteúdo do arquivo. Documento: só PDF, até 10 MB. Imagem: JPEG ou PNG, até 5 MB |
nome | nome que o destinatário vê (documento). .pdf é acrescentado se faltar |
legenda | texto abaixo da imagem ou do documento (opcional) |
modelo:
| Campo | Observação |
|---|---|
nome | nome do modelo aprovado pela Meta (minúsculas, números e _) |
idioma | padrão pt_BR |
parametros | lista com os valores de {{1}}, {{2}}… do corpo, na ordem |
cabecalho | opcional, para modelos com cabeçalho de mídia: {"tipo": "documento" | "imagem", "url" | "base64", "nome"} |
Regra da Meta: modelo × mensagem livre
O WhatsApp só permite iniciar uma conversa com um modelo aprovado. Texto, imagem e documento avulsos só são entregues se o destinatário tiver escrito para o número nas últimas 24 horas. Para avisos ativos, use tipo: "modelo", com o PDF no cabeçalho do modelo quando houver arquivo. Fora da janela, a Meta recusa com o código 131047.
Exemplo — modelo com um PDF
POST /api/v1/mensageria/mensagens
Authorization: Bearer dwmmsg_live_...
Idempotency-Key: protocolo-2026-000123
Content-Type: application/json
{
"para": "5569999998888",
"tipo": "modelo",
"referencia_externa": "PROT-2026-000123",
"modelo": {
"nome": "documento_disponivel",
"idioma": "pt_BR",
"parametros": ["Maria", "PROT-2026-000123"],
"cabecalho": { "tipo": "documento", "base64": "JVBERi0xLjQK...", "nome": "documento.pdf" }
}
}202 Accepted{
"id": "msg_19a3f0c1d2e4a1b2c3d4e5f6",
"referencia_externa": "PROT-2026-000123",
"para": "5569*****8888",
"tipo": "modelo",
"status": "na_fila",
"wamid": null,
"erro": null,
"tentativas": 0,
"criada_em": "2026-11-03T09:15:02-03:00",
"enviada_em": null,
"entregue_em": null,
"lida_em": null,
"falhou_em": null
}O envio é assíncrono. Normalmente sai em segundos; com a fila cheia ou à espera de uma retentativa, pode levar alguns minutos.
curl -X POST https://www.dwmsystems.com.br/api/v1/mensageria/mensagens \
-H "Authorization: Bearer $DWM_MENSAGERIA_CHAVE" \
-H "Idempotency-Key: protocolo-2026-000123" \
-H "Content-Type: application/json" \
-d '{"para":"5569999998888","tipo":"texto","texto":"Seu protocolo foi recebido."}'3Status
| Status | Significado |
|---|---|
na_fila | aceita pela DWM, aguardando envio (ou uma retentativa) |
processando | sendo enviada à Meta agora |
enviada | aceita pela Meta (wamid preenchido) |
entregue | entregue no aparelho do destinatário |
lida | lida, quando o destinatário mantém a confirmação de leitura ligada |
falhou | não enviada ou não entregue (veja erro) |
O status só anda para frente. Se uma confirmação da Meta chegar fora de ordem, ela não faz o status voltar.
Reenvio automático e duplicidade
A DWM reenvia sozinha só quando é certo que nada saiu: falha de conexão, limite de taxa ou indisponibilidade temporária da Meta. São até 6 tentativas, em 1, 2, 5, 15 e 60 minutos. Se a Meta recebeu o pedido mas não respondeu a tempo, a mensagem vai para falhou com o código resultado_incerto, sem reenvio, porque reenviar poderia duplicar a mensagem. Nesse caso, o seu sistema decide se envia de novo.
4Consultar
| Chamada | Devolve |
|---|---|
GET /mensagens/{id} | a mensagem e a linha do tempo dos eventos |
GET /mensagens?referencia_externa=PROT-2026-000123 | busca pelo seu identificador |
GET /mensagens?status=falhou&desde=2026-11-01T00:00&ate=2026-12-01T00:00&limite=500 | datas em horário de Brasília; até 500 itens, os mais recentes primeiro |
GET /conta | limites e quantas mensagens já foram usadas hoje |
GET /relatorio?mes=2026-11 | relatório mensal (seção 7) |
5Webhook (eventos de status)
Se a empresa informar uma URL https, a DWM faz um POST a cada mudança de status:
| Evento | Quando |
|---|---|
mensagem.aceita | pedido aceito na fila |
mensagem.enviada | aceita pela Meta |
mensagem.entregue | entregue ao destinatário |
mensagem.lida | lida |
mensagem.falhou | falha (com o código) |
{
"id": "evt_19a3f0c1d9f0aa11bb22cc33",
"tipo": "mensagem.entregue",
"ocorrido_em": "2026-11-03T09:15:09-03:00",
"mensagem": { "id": "msg_19a3f0c1d2e4a1b2c3d4e5f6", "status": "entregue", "referencia_externa": "PROT-2026-000123", "...": "..." }
}Cabeçalhos: X-DWM-Evento, X-DWM-Evento-Id, X-DWM-Timestamp e X-DWM-Assinatura.
- Responda 2xx em até 10 segundos. Qualquer outra resposta gera nova tentativa em 1 min, 5 min, 30 min, 2 h, 6 h e 24 h. Depois disso o evento é marcado como não entregue, e a DWM é avisada.
- Cada evento é entregue pelo menos uma vez. Use
X-DWM-Evento-Idpara descartar repetições. - A ordem de chegada não é garantida. O campo
mensagem.statustraz sempre o estado mais recente. - Um evento
tipo: "teste"pode ser enviado a pedido, para validar a URL.
Conferindo a assinatura
X-DWM-Assinatura = "v1=" + hex(HMAC_SHA256(segredo_do_webhook, timestamp + "." + corpo_bruto))Recuse o evento se a assinatura não bater ou se o timestamp estiver a mais de 5 minutos do seu relógio. Calcule sobre o corpo bruto recebido, antes de converter o JSON, e só processe o evento depois dessa conferência. O segredo do webhook segue as mesmas regras da chave: fica só no servidor.
import hashlib, hmac, time
def evento_valido(segredo: str, headers: dict, corpo: bytes) -> bool:
ts = headers["X-DWM-Timestamp"]
if abs(time.time() - int(ts)) > 300:
return False
esperado = "v1=" + hmac.new(segredo.encode(), ts.encode() + b"." + corpo, hashlib.sha256).hexdigest()
return hmac.compare_digest(esperado, headers["X-DWM-Assinatura"])function evento_valido(string $segredo, string $ts, string $assinatura, string $corpo): bool {
if (abs(time() - (int) $ts) > 300) return false;
$esperado = 'v1=' . hash_hmac('sha256', $ts . '.' . $corpo, $segredo);
return hash_equals($esperado, $assinatura);
}6Erros
Sempre neste formato:
{ "erro": { "codigo": "destinatario_invalido", "mensagem": "Número inválido. ..." } }| HTTP | Código | O que fazer |
|---|---|---|
| 400 | json_invalido | corrigir o corpo |
| 401 | chave_ausente, chave_invalida | conferir a chave (revogada ou expirada) |
| 403 | conta_inativa | falar com o suporte DWM |
| 404 | mensagem_nao_encontrada | conferir o id |
| 413 | corpo_grande | corpo maior que 15 MB |
| 422 | destinatario_invalido, tipo_invalido, texto_invalido, arquivo_obrigatorio, url_invalida, base64_invalido, formato_invalido, arquivo_grande, modelo_invalido, parametros_invalidos, cabecalho_invalido, referencia_invalida, idempotencia_invalida | corrigir o pedido; não repetir igual |
| 429 | limite_diario_atingido, muitas_requisicoes | aguardar (cabeçalho Retry-After) |
| 5xx | — | repetir com a mesma Idempotency-Key |
Erros de entrega
Aparecem em mensagem.erro.codigo, com o código da Meta. Os mais comuns:
| Código | Significado |
|---|---|
131026 | o número não tem WhatsApp ou não pode receber a mensagem |
131047 | fora da janela de 24 h: use um modelo |
131049 | a Meta não entregou para preservar a experiência do usuário (limite de mensagens de marketing) |
132000, 132001 | parâmetros ou nome do modelo não conferem com o aprovado |
131053 | a Meta não conseguiu baixar ou processar a mídia (url) |
resultado_incerto | sem resposta da Meta; não reenviado para evitar duplicidade |
temporario_esgotado | a Meta seguiu indisponível em todas as tentativas |
7Limites, disponibilidade e relatório
- Limite diário de mensagens por conta, definido no contrato (padrão: 1.000 por dia), e ritmo máximo de envio por minuto (padrão: 60).
- O limite de conversas da própria Meta depende da verificação da empresa no Gerenciador de Negócios. Portfólios não verificados começam com limite baixo, e a DWM apoia esse processo.
- Disponibilidade mensal mínima de 99%. Manutenção programada é avisada com 48 horas de antecedência.
GET /relatorio?mes=AAAA-MMtraz mensagens processadas, enviadas, entregues, lidas e não entregues; falhas por código; percentual de disponibilidade; períodos de indisponibilidade; manutenções; chamados; incidentes de segurança; e entregas de webhook.
8Segurança e dados (LGPD)
- A DWM trata somente os dados necessários ao envio (número, conteúdo e arquivo), sob as instruções da empresa contratante.
- Arquivos enviados em base64 são apagados logo depois do envio; fica só o hash SHA-256, para auditoria.
- Painéis e relatórios mostram o número mascarado (
5569*****8888). - O token da conta oficial da empresa na Meta é guardado cifrado.
- Incidentes de segurança são comunicados em até 24 horas da ciência.
- No fim do contrato, a DWM entrega todos os registros em CSV, revoga as credenciais e depois anonimiza os dados (números mascarados e conteúdo apagado).
Mais detalhes na Política de Privacidade, nos Termos de Uso e em Exclusão de dados.
9Suporte
Em português, em dias úteis e horário comercial de Brasília, por e-mail (contato@dwmsystems.com.br), telefone ou WhatsApp ((31) 98105-2030). Para incidente que impeça o envio: resposta inicial em até 2 horas úteis e solução ou contorno em até 8 horas úteis.