Skip to content

Backend Engineering

Microsoft Teams Notifications — Velocity X's Adaptive Card Pattern

Rich Enterprise Notifications in Teams

💼 🎯

Slack dominates the startup space—but bigger enterprise customers run Teams. If Velocity X is your system of record for deals, bookings, and leads, your enterprise buyers want those events flowing into Teams channels in real time, not buried in email or a third-party dashboard. Velocity X pattern: Incoming Webhooks + Adaptive Card JSON. Same trigger system as Slack, but richer formatting, inline actions, and the polish enterprises expect.

The catch? Adaptive Cards are JSON schemas, not markdown. Deal-won cards need to show the logo, rep name, amount, and a "View deal" button—all within Teams' card layout constraints. Get it wrong and notifications look amateur. Get it right and you ship the brand experience directly into the workflow tools your biggest customers live in.

Why Teams, Not Slack

Enterprise footprint. Every Fortune 500 runs Teams. It's baked into Office 365. Slack is a separate purchase—and security teams often block SaaS at mid-market.

Tighter Office 365 integration. Teams connectors can trigger Power Automate workflows, route to SharePoint, file into OneDrive. A single deal-won card ripples through the entire Microsoft stack.

Threading and smart formatting. Teams cards support reply threads, adaptive layouts, and mobile-friendly rendering out of the box. Your notifications don't flatten into a wall of text.

Architecture: Incoming Webhooks vs Connectors

Enterprise admin creates a Teams channel, say #sales. They click ⋯ → Connectors, search for "Incoming Webhook", and register the endpoint URL.

Velocity X stores that URL in a webhook config table (same pattern as outbound webhooks, but destination is Teams instead of a customer endpoint). When a deal closes, Velocity X POSTs an Adaptive Card JSON to the Teams webhook URL.

-- teams_endpoints table
CREATE TABLE teams_endpoints (
  id UUID PRIMARY KEY,
  account_id UUID NOT NULL REFERENCES accounts(id),
  webhook_url TEXT NOT NULL, -- Incoming Webhook URL from Teams
  channel_name TEXT, -- #sales, #deals, etc.
  events TEXT[] DEFAULT ARRAY['deal.won', 'booking.confirmed'],
  active BOOLEAN DEFAULT TRUE,
  created_at TIMESTAMP DEFAULT NOW()
);

Admin picks which events trigger notifications. Admin picks the channel. Velocity X handles payload formatting.

Adaptive Card JSON Schema

Slack uses message blocks. Teams uses Adaptive Cards—a Microsoft JSON spec for rich, interactive cards. A deal-won card looks like this:

{
  "@type": "MessageCard",
  "@context": "https://schema.org/extensions",
  "summary": "Deal Won: Acme Corp",
  "themeColor": "28a745",
  "sections": [
    {
      "activityTitle": "Deal Won 🎉",
      "activitySubtitle": "Acme Corp — $50K annual",
      "activityImage": "https://aidxn.com/logo.svg",
      "facts": [
        {
          "name": "Amount",
          "value": "$50,000"
        },
        {
          "name": "Closed By",
          "value": "Alice Johnson"
        },
        {
          "name": "Rep Email",
          "value": "alice@company.com"
        }
      ],
      "potentialAction": [
        {
          "name": "View Deal",
          "target": [
            "https://velocity-x.company.com/deals/deal_123"
          ]
        },
        {
          "name": "Follow Up",
          "target": [
            "https://velocity-x.company.com/deals/deal_123/follow-up"
          ]
        }
      ]
    }
  ]
}

The card renders as a formatted block in Teams: brand colour strip on the left (themeColor), logo at top, headline + subtitle, fact rows (Amount, Closed By, Rep Email), and action buttons. Mobile renders compactly; desktop shows the full card. No markdown parsing, no guessing about layout—the JSON spec is the layout spec.

Real-World Card Examples

Booking Confirmed. A booking-confirmed card shows the customer name, start time, duration, and buttons to view the booking or send a reminder SMS. Colour is blue. Facts highlight timezone and booking source.

Lead Created. A lead card shows source (web form, LinkedIn, inbound call), contact name, email, phone, and a "Quick Qualify" button that opens a side panel in Velocity X. Colour is orange. Facts include form URL and submission time.

Deal Won (high-touch). For enterprise deals over $10K, add a "Schedule Celebration Call" button or "Notify Exec Sponsor" action. Render the logo, the deal amount in large text, and a timeline of deal stages (Discovery → Proposal → Negotiation → Won) as a horizontal bar.

Each card is a mini-dashboard. Your sales team reads the card, clicks an action, and lands inside Velocity X without friction.

Sending Adaptive Cards from Velocity X

When a deal closes, the background job POSTs the Adaptive Card to the Teams webhook URL:

// After deal.won event fires
const teamsCard = {
  "@type": "MessageCard",
  "@context": "https://schema.org/extensions",
  "summary": `Deal Won: ${dealName}`,
  "themeColor": "28a745",
  "sections": [
    {
      "activityTitle": "Deal Won 🎉",
      "activitySubtitle": `${dealName} — $${dealAmount}`,
      "activityImage": companyLogo,
      "facts": [
        { "name": "Amount", "value": `$${dealAmount.toLocaleString()}` },
        { "name": "Closed By", "value": repName },
        { "name": "Account", "value": accountName }
      ],
      "potentialAction": [
        {
          "name": "View Deal",
          "target": [`${velocityXBaseUrl}/deals/${dealId}`]
        }
      ]
    }
  ]
};

// POST to Teams webhook
await fetch(teamsWebhookUrl, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(teamsCard)
});

Teams receives the card, renders it, and deposits it in the channel. Sales team sees it immediately, no refresh needed. Threading is automatic—replies to the card stay in a thread, keeping the channel clean.

Frequently Asked Questions

How is this different from Slack webhooks?

Slack uses Block Kit (a different JSON schema). Teams uses Adaptive Cards. Both deliver rich notifications, but the payload structure is incompatible. If you support both, format two card types at send time—or abstract the formatter into a shared interface and swap implementations per destination.

Can I add rich images or attachments to the card?

Yes. Adaptive Cards support images in the card body or as the activityImage. You can embed company logos, deal charts, or product screenshots. Keep file sizes under 5 MB and image dimensions under 2048×2048 to avoid rendering delays.

What if my Teams endpoint becomes invalid or returns 403?

Log the error and retry (same backoff as outbound webhooks). After 5 failures, mark the endpoint as inactive and alert the admin in the settings dashboard. Include a "Retest" button so they can validate the webhook URL without waiting for the next event.

Can I use Adaptive Cards for interactive workflows?

Partially. Cards support buttons and dropdown actions, but Teams doesn't support two-way interactive forms (like "Reply with a proposal"). For complex workflows, buttons should link back to Velocity X, where the real form lives. Keep the card as a notification + entry point, not a full UI.

Do Teams notifications respect user permissions?

No—any channel member sees the full card. If your deal amount or rep name is sensitive, filter it server-side before building the card. Never expose PII or secrets in the card JSON.

Can I test the Teams integration locally?

Yes. Generate a test webhook URL from Teams, save it to your env config, and trigger a deal-closed event in your dev environment. The card will post to your test channel instantly. Iterate on the card JSON and re-test until the layout is right.

The Bottom Line

Enterprise customers live in Microsoft Teams. Velocity X delivers deal wins, booking confirmations, and lead creation as rich Adaptive Cards—logos, amounts, rep names, and one-click actions. The JSON schema is clean and composable. Same event triggers as Slack, different formatter. If you're building a platform with enterprise customers, Teams support is table stakes. See pricing for notification volume tiers and integrations, or dig into outbound webhooks for the broader pattern.

Let us make some quick suggestions?

Please provide your full name.
Please provide your phone number.
Please provide a valid phone number.
Please provide your email address.
Please provide a valid email address.
Please provide your brand name or website.
Please provide your brand name or website.