$npx -y skills add ccheney/robust-skills --skill teams-adaptive-cardsProactively apply when generating Microsoft Teams Adaptive Card JSON, Bot Framework card attachments, Teams SDK card responses, message extension cards, Microsoft Graph chatMessage Adaptive Card attachments, Incoming Webhook or Workflows webhook Adaptive Cards, notification cards
| 1 | # Teams Adaptive Cards |
| 2 | |
| 3 | Adaptive Cards are the primary rich-message surface for Microsoft Teams. Always choose the transport first, because the same card JSON is wrapped differently for bots, Workflows webhooks, and Microsoft Graph — most broken Teams cards are wrapper mistakes, not card mistakes. |
| 4 | |
| 5 | ## Quick Decision Trees |
| 6 | |
| 7 | ### "Should I use a card?" |
| 8 | |
| 9 | ``` |
| 10 | Response type? |
| 11 | |-- Short conversational reply, <3 lines -> text only; use $teams-message-formatting |
| 12 | |-- Status notification with facts/actions -> Adaptive Card |
| 13 | |-- Approval, form, or data collection -> Adaptive Card through bot/Universal Actions |
| 14 | |-- Search result or message extension response -> Adaptive Card |
| 15 | |-- Service alert to a channel -> Workflows webhook or notification bot card |
| 16 | |-- Delegated Graph message with attachment -> Graph chatMessage card wrapper |
| 17 | `-- Legacy connector/MessageCard payload -> migrate to Workflows + Adaptive Card |
| 18 | (O365 connectors stopped working May 2026) |
| 19 | ``` |
| 20 | |
| 21 | ### "Which transport wrapper?" |
| 22 | |
| 23 | ``` |
| 24 | Delivery path? |
| 25 | |-- Bot Framework / Teams SDK |
| 26 | | `-- Activity `attachments[]` with contentType `application/vnd.microsoft.card.adaptive` |
| 27 | |-- Workflows (Power Automate) webhook |
| 28 | | `-- Top-level `{ "type": "message", "attachments": [...] }` |
| 29 | | (same wrapper the retired Incoming Webhook connectors used) |
| 30 | |-- Microsoft Graph chatMessage |
| 31 | | `-- Body `<attachment id="..."></attachment>` plus matching `attachments[]` |
| 32 | | with the card as a JSON *string* in attachment content |
| 33 | |-- Message extension result |
| 34 | | `-- Attachment with Adaptive Card content and preview as required by extension type |
| 35 | `-- Outlook + Teams universal scenario |
| 36 | `-- Use Universal Actions (`Action.Execute`) with bot backend |
| 37 | ``` |
| 38 | |
| 39 | ### "Which card version?" |
| 40 | |
| 41 | ``` |
| 42 | Need maximum Teams mobile compatibility? |
| 43 | |-- Yes -> use version "1.2" |
| 44 | `-- No |
| 45 | |-- Need Action.Execute / refresh / Universal Actions -> version "1.4"+, bot-backed |
| 46 | |-- Need Table / CodeBlock / charts / Icon / targetWidth -> version "1.5" |
| 47 | `-- No special features -> version "1.2" |
| 48 | ``` |
| 49 | |
| 50 | Teams supports Adaptive Card schema v1.5 or earlier; Teams does not support v1.6 (that release was scoped to mobile SDK renderers). Newer Teams elements — `CodeBlock`, chart elements (`Chart.Donut`, `Chart.Line`, ...), `Icon`, `CompoundButton`, people picker — are declared in `"version": "1.5"` payloads and gated by host capability, not by a schema bump. Teams mobile reliably supports up to v1.2; later-version features can render incorrectly or inconsistently on mobile, so default to v1.2 and provide `fallback`/`fallbackText` when you go higher. |
| 51 | |
| 52 | ## Minimal Card |
| 53 | |
| 54 | ```json |
| 55 | { |
| 56 | "$schema": "https://adaptivecards.io/schemas/adaptive-card.json", |
| 57 | "type": "AdaptiveCard", |
| 58 | "version": "1.2", |
| 59 | "fallbackText": "Deployment succeeded for API.", |
| 60 | "body": [ |
| 61 | { |
| 62 | "type": "TextBlock", |
| 63 | "text": "Deployment succeeded", |
| 64 | "weight": "Bolder", |
| 65 | "size": "Medium", |
| 66 | "wrap": true |
| 67 | }, |
| 68 | { |
| 69 | "type": "FactSet", |
| 70 | "facts": [ |
| 71 | { "title": "Service", "value": "API" }, |
| 72 | { "title": "Duration", "value": "4 min 12 sec" } |
| 73 | ] |
| 74 | } |
| 75 | ], |
| 76 | "actions": [ |
| 77 | { |
| 78 | "type": "Action.OpenUrl", |
| 79 | "title": "View release", |
| 80 | "url": "https://example.com/releases/42" |
| 81 | } |
| 82 | ] |
| 83 | } |
| 84 | ``` |
| 85 | |
| 86 | ## Transport Wrappers |
| 87 | |
| 88 | ### Bot Framework / Teams SDK |
| 89 | |
| 90 | ```json |
| 91 | { |
| 92 | "type": "message", |
| 93 | "attachments": [ |
| 94 | { |
| 95 | "contentType": "application/vnd.microsoft.card.adaptive", |
| 96 | "content": { |
| 97 | "$schema": "https://adaptivecards.io/schemas/adaptive-card.json", |
| 98 | "type": "AdaptiveCard", |
| 99 | "version": "1.2", |
| 100 | "body": [ |
| 101 | { "type": "TextBlock", "text": "Hello from a bot", "wrap": true } |
| 102 | ] |
| 103 | } |
| 104 | } |
| 105 | ] |
| 106 | } |
| 107 | ``` |
| 108 | |
| 109 | ### Workflows Webhook |
| 110 | |
| 111 | Office 365 connectors — including connector-based Incoming Webhooks — were disabled by Microsoft in May 2026. Post to a Workflows (Power Automate) webhook URL instead; the message wrapper is identical: |
| 112 | |
| 113 | ```json |
| 114 | { |
| 115 | "type": "message", |
| 116 | "attachments": [ |
| 117 | { |
| 118 | "contentType": "application/vnd.microsoft.card.adaptive", |
| 119 | "contentUrl": null, |
| 120 | "content": { |
| 121 | "$schem |