> ## Documentation Index
> Fetch the complete documentation index at: https://docs.novu.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Microsoft Teams Workflows (webhook)

> Send Novu Chat notifications to a Teams channel with a Workflows webhook URL. No Azure bot or admin consent required.

## Workflows for Teams (Webhook-style)

If you don't need a full Bot identity or Direct Message capabilities, then you can support a simplified, channel-only integration using Workflows for Microsoft Teams.

This approach relies on a unique Webhook URL generated by the Teams client. It requires no Azure app registration and no administrator consent.

### User generates the webhook URL (Teams client)

The setup begins inside the Microsoft Teams app. Instruct your users to follow these steps:

<Steps>
  <Step title="Open Workflows">
    In Microsoft Teams, go to **Apps** in the sidebar.
    Search for and open **Workflows**.
  </Step>

  <Step title="Create a new flow">
    Start from a blank flow or use a template.
  </Step>

  <Step title="Choose a trigger">
    For example, select **When a Teams webhook request is received**.
  </Step>

  <Step title="Add a post message action">
    Add an action to post a message into a specific channel.
  </Step>

  <Step title="Save the workflow">
    Publish your changes so the Teams workflow can receive events.
  </Step>

  <Step title="Copy the webhook URL">
    Once created, the workflow generates a unique URL. The user must copy this URL.
  </Step>
</Steps>

### Register the webhook endpoint (Novu)

Unlike the Bot integration, you don't use `ms_teams_channel` here. Instead, you treat this as a generic webhook endpoint. Your app should provide a form where the user can paste the URL they generated in the previous step.

<Tabs>
  <Tab title="Node.js">
    ```typescript theme={null}
    import { Novu } from '@novu/api';

    const novu = new Novu({ secretKey: "<NOVU_SECRET_KEY>" });

    await novu.channelEndpoints.create({
      type: 'webhook',
      identifier: 'teams-workflow-alerts',
      integrationIdentifier: 'ms-teams-workflow',
      subscriberId: 'customer-account-id',
      context: { tenant: 'acme' },
      endpoint: { url: 'https://prod-00.westeurope.logic.azure.com:443/workflows/...' },
    });
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import os
    from novu_py import Novu

    with Novu(secret_key=os.getenv("NOVU_SECRET_KEY", "")) as novu:
        novu.channel_endpoints.create(request_body={
            "type": "webhook",
            "identifier": "teams-workflow-alerts",
            "integration_identifier": "ms-teams-workflow",
            "subscriber_id": "customer-account-id",
            "context": {"tenant": "acme"},
            "endpoint": {"url": "https://prod-00.westeurope.logic.azure.com:443/workflows/..."},
        })
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    import (
        "context"
        "os"

        novugo "github.com/novuhq/novu-go"
        "github.com/novuhq/novu-go/models/components"
        "github.com/novuhq/novu-go/models/operations"
    )

    s := novugo.New(novugo.WithSecurity(os.Getenv("NOVU_SECRET_KEY")))

    res, err := s.ChannelEndpoints.Create(context.Background(), operations.CreateChannelEndpointsControllerCreateChannelEndpointRequestBodyWebhook(
        components.CreateWebhookEndpointDto{
            Identifier: novugo.String("teams-workflow-alerts"),
            IntegrationIdentifier: "ms-teams-workflow",
            SubscriberID: "customer-account-id",
            Context: map[string]any{
                "tenant": "acme",
            },
            Type: components.CreateWebhookEndpointDtoTypeWebhook,
            Endpoint: components.WebhookEndpointDto{URL: "https://prod-00.westeurope.logic.azure.com:443/workflows/..."},
        },
    ), nil)
    ```
  </Tab>

  <Tab title="PHP">
    ```php theme={null}
    use novu;
    use novu\Models\Components;

    $sdk = novu\Novu::builder()->setSecurity('<NOVU_SECRET_KEY>')->build();
    $sdk->channelEndpoints->create(
        requestBody: new Components\CreateWebhookEndpointDto(
            identifier: 'teams-workflow-alerts',
            integrationIdentifier: 'ms-teams-workflow',
            subscriberId: 'customer-account-id',
            context: [
                'tenant' => 'acme',
            ],
            type: Components\CreateWebhookEndpointDtoType::Webhook,
            endpoint: new Components\WebhookEndpointDto(url: 'https://prod-00.westeurope.logic.azure.com:443/workflows/...'),
        ),
    );
    ```
  </Tab>

  <Tab title=".NET">
    ```csharp theme={null}
    using Novu;
    using Novu.Models.Components;

    var sdk = new NovuSDK(secretKey: "<NOVU_SECRET_KEY>");
    await sdk.ChannelEndpoints.CreateAsync(
        requestBody: CreateWebhookEndpointDto.CreateWebhook(
            new CreateWebhookEndpointDto() {
                Identifier = "teams-workflow-alerts",
                IntegrationIdentifier = "ms-teams-workflow",
                SubscriberId = "customer-account-id",
                Context = new Dictionary<string, object> {
                    { "tenant", "acme" },
                },
                Type = CreateWebhookEndpointDtoType.Webhook,
                Endpoint = new WebhookEndpointDto() { Url = "https://prod-00.westeurope.logic.azure.com:443/workflows/..." },
            }));
    ```
  </Tab>

  <Tab title="Java">
    ```java theme={null}
    import co.novu.Novu;
    import co.novu.models.components.*;

    Novu novu = Novu.builder().secretKey("<NOVU_SECRET_KEY>").build();
    novu.channelEndpoints().create()
        .requestBody(CreateWebhookEndpointDto.builder()
            .identifier("teams-workflow-alerts")
            .integrationIdentifier("ms-teams-workflow")
            .subscriberId("customer-account-id")
            .context(java.util.Map.of("tenant", "acme"))
            .type(CreateWebhookEndpointDtoType.WEBHOOK)
            .endpoint(WebhookEndpointDto.builder().url("https://prod-00.westeurope.logic.azure.com:443/workflows/...").build())
            .build())
        .call();
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    curl -L -X POST 'https://api.novu.co/v1/channel-endpoints' \
    -H 'Content-Type: application/json' \
    -H 'Authorization: ApiKey <NOVU_SECRET_KEY>' \
    -d '{
      "type": "webhook",
      "identifier": "teams-workflow-alerts",
      "integrationIdentifier": "ms-teams-workflow",
      "subscriberId": "customer-account-id",
      "context": {
        "tenant": "acme"
      },
      "endpoint": {
        "url": "https://prod-00.westeurope.logic.azure.com:443/workflows/..."
      }
    }'
    ```
  </Tab>
</Tabs>

### Sending the notification

When you trigger a workflow that targets this subscriber:

<Steps>
  <Step title="Novu sends HTTP POST">
    Novu sends a standard HTTP POST payload to the Teams Workflow URL.
  </Step>

  <Step title="Workflows receives payload" />

  <Step title="Workflow posts message">
    The Workflow runs and posts the message content into the configured channel.
  </Step>
</Steps>

## Related

<Card title="MS Teams overview" icon="layout-grid" href="/platform/integrations/chat/ms-teams">
  Compare the bot, webhook, and agent paths.
</Card>
