tkrnx/laravel-teams-notifier

Send safe, structured Microsoft Teams Workflow notifications from Laravel applications.

Maintainers

Package info

github.com/ThanakornxMerkle/laravel-teams-notifier

pkg:composer/tkrnx/laravel-teams-notifier

Transparency log

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-08-04 09:56 UTC

This package is auto-updated.

Last update: 2026-08-04 10:35:53 UTC


README

A small Laravel package for sending structured, fail-safe notifications to a Microsoft Teams Workflow webhook. It builds compact Adaptive Cards, adds application and request metadata, redacts sensitive context, and keeps Teams outages from breaking the application that reported the event.

Features

  • INFO, WARNING, and ERROR notifications through one simple API
  • Microsoft Teams Workflow-compatible Adaptive Card payloads
  • Automatic application name, environment, timestamp, request path, request ID, and authenticated user ID
  • Recursive, case-insensitive redaction of sensitive context keys
  • Safe rendering and truncation of strings, arrays, objects, exceptions, and debug traces
  • A card text budget that keeps generated messages below Teams' 28 KB message limit
  • Fail-safe HTTP delivery with a short timeout and conservative retry
  • Optional Laravel queue delivery without serializing Throwable objects
  • Facade and dependency-injection APIs
  • Laravel package auto-discovery and publishable configuration

Requirements

  • PHP 8.2 or newer
  • Laravel 11 or Laravel 12
  • A Microsoft Teams Workflow webhook URL

Installation

Install the package with Composer:

composer require tkrnx/laravel-teams-notifier

Laravel discovers the service provider and TeamsNotifier alias automatically. Publish the configuration if you need to customize it:

php artisan vendor:publish --tag=teams-notifier-config

The explicit provider form is also supported:

php artisan vendor:publish \
  --provider="Tkrnx\LaravelTeamsNotifier\TeamsNotifierServiceProvider" \
  --tag="teams-notifier-config"

Configuration

Add the Workflow URL and the settings appropriate for your application:

TEAMS_NOTIFIER_ENABLED=true
TEAMS_NOTIFIER_WEBHOOK_URL=https://your-teams-workflow-webhook-url
TEAMS_NOTIFIER_APP_NAME="My Laravel App"
TEAMS_NOTIFIER_ENVIRONMENT=production
TEAMS_NOTIFIER_TIMEOUT=5
TEAMS_NOTIFIER_INCLUDE_DEBUG=false
TEAMS_NOTIFIER_QUEUE=false

The published config/teams-notifier.php file also contains the sensitive-key list. Add application-specific secret field names there when needed.

Setting Default Purpose
enabled true Makes all notifier calls no-ops when disabled.
webhook_url null Microsoft Teams Workflow HTTP POST URL.
app_name APP_NAME Name displayed on every card.
environment APP_ENV Environment displayed on every card.
timeout 5 HTTP timeout in seconds.
include_debug false Includes a bounded exception trace. Keep disabled unless needed.
queue false Dispatches delivery to the application's default queue.
sensitive_keys See config Context keys whose values are recursively replaced with [REDACTED].

If notification delivery is enabled without a webhook URL, the package logs one warning per resolved webhook client and returns safely. The webhook URL itself is never included in package log messages.

Microsoft Teams Workflow Setup

Microsoft currently supports creating incoming webhooks through the Workflows app or from a channel/chat workflow template. The shortest setup is:

  1. In Teams, open the target channel or chat's More options, then select Workflows.
  2. Choose the appropriate Send webhook alerts to a channel/chat template.
  3. Authenticate the connection, choose the destination, and add the workflow.
  4. Copy the generated HTTP POST URL into TEAMS_NOTIFIER_WEBHOOK_URL.
  5. Send a test notification from the application.

You can also create a workflow from blank with the When a Teams webhook request is received trigger and a Post card in chat or channel action. Microsoft's Workflows webhook setup guide covers both paths. For operational continuity, add co-owners to production workflows because workflows are owned by users.

The package sends the documented type: message envelope with application/vnd.microsoft.card.adaptive attachments. Microsoft documents this payload and the 28 KB message limit in its Teams incoming webhook developer guide.

Treat the generated URL as a secret. Store it in environment or secret-management configuration; do not commit it.

Basic Usage

Import the package facade:

use Tkrnx\LaravelTeamsNotifier\Facades\TeamsNotifier;

With Laravel's discovered alias, use TeamsNotifier; is also available.

INFO Notifications

TeamsNotifier::info(
    title: 'Order Created',
    message: 'A new order has been created.',
    context: [
        'order_id' => 123,
        'total' => 1500,
    ],
);

WARNING Notifications

TeamsNotifier::warning(
    title: 'Reward Stock Low',
    message: 'Reward stock is below threshold.',
    context: [
        'reward_id' => 10,
        'remaining_stock' => 3,
    ],
);

ERROR Notifications

Attach an exception when it adds useful diagnostic detail:

try {
    $service->run();
} catch (Throwable $exception) {
    TeamsNotifier::error(
        title: 'Operation Failed',
        message: 'The operation could not be completed.',
        context: [
            'entity_id' => 123,
            'event' => 'operation.failed',
        ],
        exception: $exception,
    );

    throw $exception;
}

Delivery failures are caught and logged, so the notifier does not replace the original business exception.

Exception Notifications

The shortcut creates an ERROR notification and uses the exception's short class name as its default title:

TeamsNotifier::exception(
    exception: $exception,
    context: [
        'event' => 'operation.failed',
        'entity_id' => 123,
    ],
);

Override the title when a business-specific name is clearer:

TeamsNotifier::exception(
    exception: $exception,
    context: ['entity_id' => 123],
    title: 'Entity Processing Failed',
);

Dependency Injection

Use the contract when a service should not depend on the facade:

use Tkrnx\LaravelTeamsNotifier\Contracts\TeamsNotifierContract;

final class ProcessEntity
{
    public function __construct(
        private readonly TeamsNotifierContract $notifier,
    ) {}

    public function handle(): void
    {
        $this->notifier->info('Entity Processed');
    }
}

Context Data

Context can contain strings, integers, floats, booleans, null, arrays, enums, dates, stringable values, and objects. Keys such as reward_id are displayed as Reward ID. Arrays and objects are safely converted to compact JSON.

During HTTP requests, the package automatically includes:

  • HTTP method and path, without query parameters or request body
  • X-Request-ID, then X-Correlation-ID, when supplied
  • One stable generated UUID for the request when neither header exists
  • Authenticated user ID when it can be resolved safely

The request body, authorization headers, cookies, and other headers are not collected.

Security and Sensitive Data

Sensitive keys are matched case-insensitively and recursively. The defaults are:

password
password_confirmation
token
access_token
refresh_token
authorization
cookie
secret
api_key

For example, both password and a nested Access_Token become [REDACTED]. Normal context strings are bounded to 2,000 characters, exception messages are bounded to 4,000 characters, debug traces are bounded to 8,000 characters, collection size and depth are capped, and the builder applies a final card text budget.

Full traces can reveal internal paths or values. TEAMS_NOTIFIER_INCLUDE_DEBUG is therefore false by default. Never put secrets in titles or exception messages; key-based redaction applies to context data.

Queue Support

Set queued delivery in production when the main request should not wait for Teams:

TEAMS_NOTIFIER_QUEUE=true

Run a Laravel queue worker using your application's normal queue configuration:

php artisan queue:work

The queued job receives only scalar/array notification data. Exceptions are normalized to class, message, file, line, and an optional bounded trace before dispatch; raw Throwable objects are never serialized. The job allows one attempt and does not create another Teams alert when Teams delivery fails.

Failure Behavior

HTTP requests use Laravel's HTTP client, the configured short timeout, and two total attempts separated by 200 milliseconds. Non-success responses and transport exceptions are logged as warnings with only safe metadata such as status code or exception class. They are not thrown into application code.

Disable all HTTP and queue activity at runtime with:

TEAMS_NOTIFIER_ENABLED=false

Testing

The HTTP transport works with Laravel's normal HTTP fake:

use Illuminate\Support\Facades\Http;
use Tkrnx\LaravelTeamsNotifier\Facades\TeamsNotifier;

Http::fake([
    '*' => Http::response('', 202),
]);

TeamsNotifier::info('Test Notification');

Http::assertSentCount(1);

Run the package checks locally:

composer install
composer test
composer format:test
composer validate --strict

The suite uses Orchestra Testbench and covers the facade, service provider, all levels, exception helper, request context, recursive redaction, card structure, payload size, disabled mode, missing webhooks, HTTP failures, queue dispatch, and queued delivery.

License

Laravel Teams Notifier is open-sourced software licensed under the MIT license.