Como publicar Adaptive Card dinâmico no Microsoft Teams via Webhook

Publicar um Adaptive Card dinâmico num canal do Microsoft Teams por meio de Webhook permite que uma aplicação informe a equipa sobre novas versões, alertas ou métricas em tempo (quase) real, sem depender de bots ou de conetores mais complexos. Contudo, muitos desenvolvedores deparam‑se com um cartão totalmente em branco logo depois de um HTTP POST que aparentemente foi bem‑sucedido. A causa costuma ser uma combinação de detalhes pouco documentados no formato da mensagem e de limitações próprias do conector de Webhook. Este guia aprofunda esses pontos, ensina a criar o envelope correto, demonstra como aplicar o template em Python e apresenta boas práticas que evitam armadilhas.

Índice

Contexto e desafios ao usar Webhooks no Teams

O Webhook de entrada (incoming Webhook) do Teams existe para receber cargas de trabalho simples baseadas em JSON. Ele funciona como um endpoint HTTPS vinculado a um canal específico, autenticado por um token longo incorporado na URL. Ao contrário de um bot ou do Microsoft Graph, o Webhook não possui identidade própria, não participa em conversas privadas nem executa lógica de negócios; limita‑se a publicar a mensagem recebida.

Por isso, quando se deseja enviar um Adaptive Card, é obrigatório encapsular o cartão dentro de um objeto “message” que o conector compreenda. Webhooks não interpretam a linguagem de templates do Adaptive Cards (${…}, {} etc.) e não avaliam bindings em tempo de execução. Esse comportamento explica por que placeholders sem valores viram campos vazios, resultando num cartão aparentemente sem conteúdo.

Estrutura exata da mensagem

Envelope do tipo message

O corpo do request deve começar com:

{
  "type": "message",
  "attachments": [
    {
      "contentType": "application/vnd.microsoft.card.adaptive",
      "content": { ...seu cartão... }
    }
  ]
}

O Adaptive Card aparece no campo content; qualquer propriedade fora dessa hierarquia é ignorada. Se o cartão for enviado como objeto raiz, o Teams até aceita o POST, mas renderiza um retângulo vazio.

Versionamento do cartão

Certifique‑se de usar "$schema":"http://adaptivecards.io/schemas/adaptive-card.json" e "version":"1.5" ou inferior. O Teams preserva compatibilidade apenas até a versão 1.5; elementos introduzidos depois disso não são reconhecidos.

Onde o templating não funciona

O seguinte trecho de cartão enviado tal‑qual:

{
  "type":"AdaptiveCard",
  "body":[
    { "type":"TextBlock", "text":"${releaseTitle}" },
    { "type":"TextBlock", "text":"${description}" }
  ],
  "version":"1.5"
}

resulta em campos vazios porque o conector não processa ${releaseTitle} nem ${description}. O valor literal “${releaseTitle}” é percebido como texto legítimo, mas é filtrado por motivos de segurança e acaba não exibido.

Erros comuns que levam ao cartão em branco

  1. Falta do contedor message – O cartão é enviado diretamente como raiz do JSON.
  2. Placeholders não substituídos – A aplicação gera o template, mas não aplica os dados.
  3. Características não suportadas – A versão do cartão ultrapassa a 1.5 ou inclui Action.Execute, que o Webhook não compreende.
  4. Codificação incorreta de carateres – JSON malformado, erro de aspas ou uso de comentários (//) invalida o documento e o conector devolve 204 sem corpo, sugerindo sucesso, mas o cartão falha na renderização interna.

Passo a passo para enviar o Adaptive Card

PassoO que fazerObservações
Preparar o JSON completoSubstitua todas as variáveis no lado da aplicação ou utilize o SDK Adaptive Cards Templating para Python, gerando o cartão expandido.Considera a localização, p. ex. datas no formato pt‑BR.
Ajustar o envelopeInclua "type":"message" e attachments conforme modelo.Sem esse passo o cartão não é reconhecido.
Testar no DesignerCole o JSON final no designer on‑line para verificar layout e erros de schema.Ideal para validar em segundos antes do deploy.
Disparar o POSTEnvie para o URL do Webhook com cabecalhos Content‑Type: application/json.Tempo médio de entrega: 50–300 ms.

Exemplo de código Python end‑to‑end

import json
import requests
from adaptivecard_templating import Template

WEBHOOK\_URL = "[https://outlook.office.com/webhook/](https://outlook.office.com/webhook/)..."  # URL do canal

Carregar o cartão‑modelo

with open("card\_template.json", encoding="utf-8") as f:
template = Template(json.load(f))

data = {
"releaseTitle": "Versão 2.1",
"description": "Correções de segurança e melhorias de desempenho."
}

card = template.expand(data)

Construir envelope

payload = {
"type": "message",
"attachments": \[
{
"contentType": "application/vnd.microsoft.card.adaptive",
"content": card
}
]
}

Enviar

resp = requests.post(WEBHOOK\_URL, json=payload)
resp.raise\for\status()
print("Status:", resp.status\_code)

Validação e depuração

Caso o cartão não apareça:

  • Verifique se o canal mostra “Fulano posted a notification” — isso indica que o Teams recebeu algo.
  • Inspecione a mensagem clicando nos três pontos > Copy link e abra a MessageCard viewer interna do Teams (tipo https://teams.microsoft.com/…&messageId=…). Se o JSON estiver lá, mas vazio, o problema é o conteúdo; se não estiver, o corpo não chegou.
  • Cheque se há erros no console do navegador (F12) ao abrir a mensagem; elementos desconhecidos são reportados.

Alternativas para dados em tempo real ou interação

Quando é imprescindível que os dados sejam avaliados somente à hora de leitura, ou quando se quer coletar resposta do utilizador (botões que retornam valores), considere:

  • Microsoft Power Automate / Workflows – A ação “Post Adaptive Card and wait for a response” aceita variáveis de ambiente e mantém estado até 28 dias, gerindo bindings sem escrever código.
  • Bot Framework – Um bot registrado no Azure pode conversar em qualquer chat, disparar cartões com databinding e processar Action.Submit.
  • Microsoft Graph (/chats/{id}/messages) – A API oficial permite anexar cartões e editar mensagens já enviadas.

Boas práticas de segurança e governança

  • Guarde o URL do Webhook num Key Vault ou em variáveis de ambiente criptografadas; qualquer pessoa com o link consegue postar no canal.
  • Crie Webhooks separados para cada serviço; assim pode revogar apenas o que vazar sem afetar os demais.
  • Implemente retry exponencial: o endpoint pode devolver erros transitórios HTTP 429 ou 502.
  • Registre audit logs para rastrear quem disparou qual payload.

Checklist rápido antes de entrar em produção

  • Cartão validado no designer oficial.
  • Envelope contém type: message e attachments.
  • Versão do cartão ≤ 1.5.
  • Placeholders totalmente substituídos.
  • URL do Webhook protegido.
  • Estratégia de erro (retry) implementada.
  • Governança de acesso documentada.

Conclusão

Usar um Webhook de entrada é a maneira mais simples de introduzir Adaptive Cards em canais do Teams, mas o conector é estrito: não há suporte a templates nem a funcionalidades avançadas como Action.Execute. Se transformar o cartão em HTML não resolver, observe minuciosamente o envelope, garanta substituição local de variáveis e verifique a compatibilidade de versão. Assim, a experiência do utilizador final será idêntica à de um cartão criado manualmente no chat, mas com a agilidade de um processo 100 % automatizado.

Índice