Aviary
Channels

Microsoft Teams

Post notifications to Microsoft Teams via an incoming webhook. A fluent TeamsMessage builder for MessageCards, or post a custom Adaptive Card, routed per notifiable.

The Teams channel posts a notification to Microsoft Teams through an incoming webhook. Build the message with a fluent builder that produces a legacy MessageCard, or hand it a fully custom payload (for example an Adaptive Card). Delivery uses the platform fetch.

Install

pnpm add @dudousxd/nestjs-notifications-teams
npm install @dudousxd/nestjs-notifications-teams

Register the channel

app.module.ts
import { TeamsChannelModule } from '@dudousxd/nestjs-notifications-teams';

@Module({
  imports: [
    TeamsChannelModule.forRoot({ webhookUrl: process.env.TEAMS_WEBHOOK_URL }),
  ],
})
export class AppModule {}

TeamsChannelModule.forRoot() takes:

OptionTypeDefaultDescription
webhookUrlstringDefault incoming-webhook URL, used when the route doesn't supply one.
globalbooleantrueRegister globally so the channel is discoverable app-wide.

The notification side

Annotate the payload method with the @Teams() handle and return a TeamsMessage:

deploy-finished.notification.ts
import { type Notifiable, Notification } from '@dudousxd/nestjs-notifications-core';
import { Teams, TeamsMessage } from '@dudousxd/nestjs-notifications-teams';

@Notification()
export class DeployFinished {
  constructor(private service: string) {}

  @Teams()
  toTeams({ notifiable }: ChannelContext): TeamsMessage {
    return new TeamsMessage()
      .title('Deploy finished')
      .text(`**${this.service}** is live.`);
  }
}

The Teams handle also works as a via() token (via() { return [Teams]; }) for explicit routing; implement TeamsNotification alongside the decorator for compile-time checks on toTeams().

TeamsMessage builder

TeamsMessage is a fluent builder; each method returns this:

MethodEffect
.title(s)Set the card title.
.text(s)Set the card body text.
.card(obj)Provide a fully custom payload (MessageCard or an Adaptive Card envelope); posted verbatim, and the fluent title/text are ignored.
.toPayload()Serialize to the JSON body Teams expects (a MessageCard, unless a custom card was set).

You can also return a plain object from toTeams() and it is posted verbatim — handy for a hand-built Adaptive Card.

Routing

routeNotificationFor('teams') controls the target per notifiable. Return an https:// webhook URL to override the module default:

team.ts
export class Team implements Notifiable {
  constructor(public teamsWebhook: string) {}

  routeNotificationFor(channel: string) {
    if (channel !== 'teams') return undefined;
    return this.teamsWebhook; // an https:// webhook URL
  }
}

If the route returns a non-URL value, the channel falls back to the module's webhookUrl. If neither supplies a URL, the channel throws asking you to set one.

On this page