---
title: "Send a Webhook to Microsoft Teams | WebhookRelay"
meta:
  "og:description": "Send any incoming webhook to Microsoft Teams. Forward an event through Webhook Relay, transform the raw payload into the Teams message JSON in flight, and post it to a Teams Incoming Webhook or Power Automate Workflow URL."
  "og:title": "Send a Webhook to Microsoft Teams"
  description: "Send any incoming webhook to Microsoft Teams. Forward an event through Webhook Relay, transform the raw payload into the Teams message JSON in flight, and post it to a Teams Incoming Webhook or Power Automate Workflow URL."
---

![Stripes](https://webhookrelay.com/blog/webhook-to-microsoft-teams/images/stripes.svg)

# **Send a Webhook to Microsoft Teams**

Send any incoming webhook to Microsoft Teams. Forward an event through Webhook Relay, transform the raw payload into the Teams message JSON in flight, and post it to a Teams Incoming Webhook or Power Automate Workflow URL.

![Send a Webhook to Microsoft Teams: Transform &amp; Forward Any Payload](https://webhookrelay.com/blog/webhook-to-microsoft-teams/images/blog/heroes/route.jpg)

You have a service that fires webhooks — a CI pipeline, an uptime monitor, a form, a payment provider, an alerting tool — and you want each event to land in a **Microsoft Teams channel**. The problem: Teams doesn't accept arbitrary payloads. It expects a specific JSON body, and the webhook your source sends almost never matches that shape.

[Webhook Relay](https://webhookrelay.com) sits in the middle. It receives the incoming webhook at a stable public URL, **transforms** the payload into the format Teams expects, and delivers it — no glue server, no Lambda, no maintenance.

> **Build it visually first:** the free [webhook → Slack/Discord/Teams formatter](https://webhookrelay.com/blog/webhook-to-microsoft-teams/webhook-message-formatter/) lets you paste a sample payload, template the Teams message, preview it live, and copy the exact transform function used below — for any incoming webhook.

## [How it works](#how-it-works)

The flow is a single hop with a transform in the middle:

```
Your service  ──▶  Webhook Relay  ──▶  transform to Teams JSON  ──▶  Teams channel
 (raw webhook)      (public URL)        (serverless function)        (message appears)
```

The simplest message Teams accepts is a JSON body with a `text` field POSTed to a Teams Incoming Webhook URL:

```
{ "text": "your message" }
```

A generic incoming webhook isn't shaped like that, so we add a small [transformation function](https://webhookrelay.com/blog/webhook-to-microsoft-teams/features/transform-webhooks/) that wraps the raw body into Teams' format before delivery. That one feature is what turns Webhook Relay into a universal "anything → Teams" bridge.

## [A note on connectors vs. Workflows](#a-note-on-connectors-vs-workflows)

Historically, Teams Incoming Webhooks came from **Office 365 connectors** and accepted the legacy **MessageCard** format. Microsoft is now **migrating away from connectors toward Power Automate Workflows**, where the modern format is an **Adaptive Card**. New integrations should create a **Workflow-based Incoming Webhook**.

Good news: the Webhook Relay side doesn't change. Whichever URL you're given, your job is the same — produce the JSON that endpoint expects and POST it. The `{ "text": "..." }` shape below is the quickest to get working; we'll show the richer Adaptive Card variant at the end.

## [Step 1: Create the Teams webhook URL](#step-1-create-the-teams-webhook-url)

In Teams, the current path is **+ New (or the channel's ••• menu) → Workflows → "Post to a channel when a webhook request is received"** (a Power Automate template). Select the team and channel, finish the flow, and copy the generated **HTTP POST URL**. It's a long Power Automate / Logic Apps URL.

> If your tenant still uses the legacy route, you'd add an **Incoming Webhook** connector to the channel instead and copy that URL. Either URL works as a destination below.

Keep this URL handy — it's where Webhook Relay will deliver.

## [Step 2: Create a Webhook Relay public endpoint](#step-2-create-a-webhook-relay-public-endpoint)

Open [the new public destination page](https://my.webhookrelay.com/new-public-destination) and paste the Teams webhook URL as the **destination**. Webhook Relay gives you back an **input URL** — a public endpoint you'll point your source service at.

That input URL is a stable address you can hand to any service. Everything sent to it gets forwarded toward Teams.

## [Step 3: Add a transformation function](#step-3-add-a-transformation-function)

Right now, anything you send to the input URL would be forwarded to Teams _as-is_ — and Teams would reject it, because it isn't in the shape it expects. Add a [transformation](https://webhookrelay.com/blog/webhook-to-microsoft-teams/features/transform-webhooks/) to fix that.

Click **Transform** on the input, open the [Functions](https://my.webhookrelay.com/functions) page, create a function "from scratch", and paste this Lua:

```
local json = require("json")

local payload = {
    text = r.RequestBody,
}

local body, err = json.encode(payload)
if err then error(err) end

r:SetRequestHeader("content-type", "application/json")
r:SetRequestMethod("POST")
r:SetRequestBody(body)
```

This takes the raw incoming body, wraps it as `{ "text": "..." }`, sets the right headers and method, and lets Webhook Relay deliver it. Teams now accepts the message and posts it to your channel.

## [Step 4: Point your source at the URL and test](#step-4-point-your-source-at-the-url-and-test)

Configure your source service (the CI tool, monitor, form, payment provider — whatever you're integrating) to send its webhook to the Webhook Relay **input URL**.

To confirm everything works before wiring up the real service, fire a quick test with `curl`:

```
curl -X POST https://my.webhookrelay.com/v1/webhooks/your-input-id \
  -d 'Deployment finished: build #482 passed on main'
```

Within a second or two, **Deployment finished: build #482 passed on main** appears in your Teams channel. If nothing shows up, open the request log in your dashboard to see exactly what was received and delivered.

## [Going further](#going-further)

Once the basic bridge works, the transform function is where the real power is.

**Build a richer Adaptive Card.** Workflow-based webhooks expect an Adaptive Card wrapped in an `attachments` array. If your source sends JSON, parse it and construct the card so you get titled, formatted messages instead of a flat string:

```
local json = require("json")

local event = json.decode(r.RequestBody)

local payload = {
    type = "message",
    attachments = {
        {
            contentType = "application/vnd.microsoft.card.adaptive",
            content = {
                ["$schema"] = "http://adaptivecards.io/schemas/adaptive-card.json",
                type = "AdaptiveCard",
                version = "1.4",
                body = {
                    { type = "TextBlock", size = "Large", weight = "Bolder",
                      text = "Deployment " .. event.status },
                    { type = "TextBlock", wrap = true, text = event.message },
                },
            },
        },
    },
}

local body, err = json.encode(payload)
if err then error(err) end

r:SetRequestHeader("content-type", "application/json")
r:SetRequestMethod("POST")
r:SetRequestBody(body)
```

**Filter out noise.** Not every event deserves a ping. Use [forwarding rules](https://webhookrelay.com/blog/webhook-to-microsoft-teams/features/forwarding-rules/) to only deliver events that match a condition, or drop them in the function with an early `return`.

**Fan out to multiple channels.** Add more destinations so one incoming webhook lands in several Teams channels — or in Teams _and_ Slack _and_ Discord — at the same time. See [forwarding to multiple destinations](https://webhookrelay.com/blog/webhook-to-microsoft-teams/features/webhook-multiple-destinations/).

## [FAQ](#faq)

**What does Teams need to receive?** A `POST` with a JSON body. The minimum is `{ "text": "your message" }`; the modern Workflow path expects an Adaptive Card inside an `attachments` array. The transform function produces exactly the shape your URL expects.

**Do I need to run a server?** No. Webhook Relay receives, transforms, and delivers everything in the cloud. There's nothing to host or keep online.

**How do I see the raw payload my source sends?** Send it to a free [Webhook Bin](https://webhookrelay.com/blog/webhook-to-microsoft-teams/webhook-bin/) first to inspect the exact body and headers, then write your transform around that structure.

## [Get started](#get-started)

[Create a free Webhook Relay account](https://my.webhookrelay.com/register) and set up your first "anything → Teams" bridge in a few minutes. Not sure what your source sends? [Inspect the payload in a Webhook Bin](https://webhookrelay.com/blog/webhook-to-microsoft-teams/webhook-bin/) first, then write the transform to match.