Skip to content
← All posts
· 8 min read·Emre Yurtbay

Incoming Webhooks in Microsoft Teams Are Being Retired: How to Post to a Channel Today Using Workflows (Power Automate)

Microsoft is retiring Office 365 Connectors and Incoming Webhooks in Teams. Here is the verified status and the recommended Workflows (Power Automate) replacement.

Microsoft TeamsPower AutomateWorkflowsIncoming WebhookOffice 365 ConnectorsAdaptive CardsMigrationdotnet

Anyone who has pushed build statuses, monitoring alerts, or deployment messages into a Teams channel over the past few years knows the pattern: one Incoming Webhook connector per channel, a URL as a secret, a POST with a MessageCard. This approach is being phased out. Microsoft is retiring the Office 365 Connectors (now called Microsoft 365 Connectors) in Teams, and the classic Incoming Webhook is part of that. This article summarizes the verified status (June 2026) and shows Microsoft's recommended replacement via the "Workflows" app (Power Automate), including working code snippets.

The Problem: Connectors Are Being Retired

Microsoft announced the retirement on July 3, 2024. The original plan envisioned two waves:

  • Wave 1, starting August 15, 2024: Creating new connectors is blocked.
  • Wave 2, starting October 1, 2024: All connectors stop functioning.

These dates were postponed several times. Two points are decisive for operations today:

  • URL migration: Existing webhook-based connectors (Incoming Webhook and third-party connectors) had to be switched to a new, more secure URL. The deadline for this was extended to January 31, 2025. Polling connectors such as RSS are not affected.
  • Final retirement: Microsoft has documented the final rollout for the period from May 18, 2026, to May 22, 2026. After May 22, 2026, the Office 365 Connectors no longer work.

As of June 2026, this rollout period is therefore complete. Anyone still using Incoming Webhooks should not delay the migration any further. Creating new connectors via the connector developer portal is already blocked.

As a replacement, Microsoft explicitly names Power Automate workflows, the "Workflows" app in Teams, and Microsoft Graph as a scalable, flexible, and secure way to move data into and out of Teams.

The Recommended Replacement: the "Workflows" App

The "Workflows" app is based on Microsoft Power Automate and is integrated directly into Teams. For the use case "an external service should write a message into a channel via HTTP POST," there is the trigger "When a Teams webhook request is received" (German: "Beim Empfang einer Teams-Webhookanfrage"). Microsoft provides prebuilt templates for this. For channels, according to Microsoft Support, they are named "Send webhook alerts to a channel," among others, along with the variants "... from specific people to a channel" and "... from people in an org to a channel"; in some interfaces and documentation the template also appears as "Post to a channel when a webhook request is received."

Important characteristics compared to the old connector:

  • The workflow belongs to a user (owner), not to a channel. If the owner is removed and no co-owner is set, the flow can become orphaned. Therefore, set co-owners in production scenarios.
  • By default, the workflow posts as the "Flow Bot." The Workflows bot can post in standard and shared channels. Posting as the Flow Bot in private channels is, according to Microsoft, still in development.
  • Workflows support Adaptive Cards and the message card format; however, the button rendering of the message card format is not supported.

Step by Step: Create the Workflow and Retrieve the URL

The fastest path is via the template directly in the Teams client:

  1. Click "More options" next to the desired channel and select "Workflows."
  2. Choose a webhook template, such as "Send webhook alerts to a channel."
  3. Adjust the workflow name and authenticate with your account.
  4. Select "Next," then set the team and channel as the target.
  5. Click "Add workflow."
  6. Copy the generated webhook URL from the dialog.

Alternatively, create the workflow from scratch: in Power Automate, choose "Create from blank," search for the trigger "When a Teams webhook request is received," set the authentication type (Anyone / Any user in my tenant / Specific users), then add the action "Post card in chat or channel" and fill in the target and required fields. The callback URL is shown when the flow is saved and can be retrieved again later in the Power Automate designer.

The generated URL is a Power Automate / Logic Apps trigger callback URL. It typically points to a domain in the style of https://<region>.logic.azure.com:443/... and carries query parameters, including api-version and a signature sig. This signature is precisely what authorizes the call.

Notes on securing it:

  • Treat the entire URL as a secret. Anyone who knows the URL including sig can post to the channel. Store it in a secret store (e.g., Azure Key Vault), not in the Git repository.
  • Rotation: If you suspect a leak, delete the workflow or regenerate the trigger so that a new sig is created. The old URL becomes invalid as a result.
  • Additional auth: Do not set the trigger type to "Anyone" if the caller can be associated with a tenant. With "Any user in my tenant" or "Specific users," the trigger additionally requires an auth token in the request header.

The New Payload Format: Adaptive Card as an Attachment

The decisive difference from the old connector: the Workflows template expects an Adaptive Card, embedded as a message with an attachments array. The contentType must be application/vnd.microsoft.card.adaptive. The exact JSON looks like this:

{
  "type": "message",
  "attachments": [
    {
      "contentType": "application/vnd.microsoft.card.adaptive",
      "contentUrl": null,
      "content": {
        "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
        "type": "AdaptiveCard",
        "version": "1.2",
        "body": [
          {
            "type": "TextBlock",
            "text": "Deployment erfolgreich auf prod-01"
          }
        ]
      }
    }
  ]
}

The required fields according to the Microsoft schema: type is always "message", attachments is an array of card objects, contentType is always "application/vnd.microsoft.card.adaptive", contentUrl is null, and content contains the Adaptive Card as JSON. A tip from practice: keep the Adaptive Card version conservative (1.2 to 1.4); very recent versions are not always rendered correctly in Teams.

For comparison, the old Office 365 Connector format ("MessageCard"), which works with @type and @context:

{
  "@type": "MessageCard",
  "@context": "http://schema.org/extensions",
  "themeColor": "0076D7",
  "summary": "Larry Bryant created a new task",
  "sections": [{ "activityTitle": "Larry Bryant created a new task" }]
}

With Adaptive Cards, all native schema elements except Action.Submit are supported. The permitted actions are Action.OpenUrl, Action.ShowCard, and Action.ToggleVisibility.

Code Snippets

The following examples post the above Adaptive Card JSON to the workflow URL. Replace <WORKFLOW_URL> with your callback URL.

curl

curl -H "Content-Type: application/json" \
     -d @card.json \
     "<WORKFLOW_URL>"

PowerShell

$body = Get-Content -Path .\card.json -Raw
Invoke-RestMethod -Method Post `
                  -ContentType 'application/json' `
                  -Body $body `
                  -Uri '<WORKFLOW_URL>'

C# / .NET (HttpClient)

using System.Net.Http.Json;

var card = new
{
    type = "message",
    attachments = new[]
    {
        new
        {
            contentType = "application/vnd.microsoft.card.adaptive",
            contentUrl = (string?)null,
            content = new
            {
                schema = "http://adaptivecards.io/schemas/adaptive-card.json",
                type = "AdaptiveCard",
                version = "1.2",
                body = new[]
                {
                    new { type = "TextBlock", text = "Deployment erfolgreich auf prod-01" }
                }
            }
        }
    }
};

using var client = new HttpClient();
var response = await client.PostAsJsonAsync("<WORKFLOW_URL>", card);

// Power Automate / Logic Apps quittiert den Trigger mit 202 Accepted
if (response.StatusCode == System.Net.HttpStatusCode.Accepted)
    Console.WriteLine("Angenommen (202).");
else
    Console.WriteLine($"Unerwarteter Status: {(int)response.StatusCode}");

Note: The $schema field is named "$schema" in the JSON. Since $ is not allowed in C# anonymous types, it was written here as schema; in practice, serialize with a JsonPropertyName attribute or a dictionary so that the key $schema is preserved exactly.

Migration: from MessageCard to Adaptive Card

Three points are central when switching over:

  • Change the format: The old @type/@context MessageCard body no longer works as usual with the Workflows (in particular, without button rendering). Convert your payloads to the message/attachments format with an Adaptive Card. The "When a Teams webhook request is received" trigger does not support actionable messages, so remove the actions/potentialAction properties from old payloads during conversion.
  • Check the status code: The old Incoming Webhook responded on success with a plain 1 in the body. The Power Automate / Logic Apps trigger, by contrast, acknowledges acceptance asynchronously with HTTP 202 (Accepted). Adjust your success check accordingly: expect 202, not 200 and not the body 1. Note: 202 means "accepted," not necessarily "posted to the channel"; if you run into problems, additionally check whether the card actually appears.
  • Mind the rate limits: Throughput limits apply to connectors (max. 4 requests per second). For higher volumes, implement retry logic with exponential backoff.

ASCII Diagram: Old vs. New

ALT (eingestellt):

  +------------+      +------------------------+      +------------+
  | App/Skript | ---> |  Incoming Webhook      | -X-> | Teams-     |
  | MessageCard|      |  Connector             |  X   | Kanal      |
  +------------+      +------------------------+      +------------+
                          eingestellt ab 22.05.2026


NEU (empfohlen):

  +------------+      +------------------------+      +------------+
  | App/Skript | ---> |  Power Automate        | ---> | Teams-     |
  | Adapt.Card |      |  Workflow (Flow Bot)   |      | Kanal      |
  +------------+      +------------------------+      +------------+
       HTTP POST              -> 202 Accepted

Practical Recommendation

First, inventory all existing Incoming Webhook calls (search for office.com/webhook or the old connector URLs in your repos and pipelines). Create one workflow per channel via the template, assign at least one co-owner, store the new URL as a secret, and convert your payloads to the Adaptive Card format. Test against the 202 status code instead of the old 1 body. Those who do this early will avoid silent failures after the final rollout.

If you have questions about the migration or about integration into your .NET pipelines, you can reach me at info@yurtbay.dev.

Sources (Microsoft)

Discuss your project