tkrnx / laravel-teams-notifier
Send safe, structured Microsoft Teams Workflow notifications from Laravel applications.
Package info
github.com/ThanakornxMerkle/laravel-teams-notifier
pkg:composer/tkrnx/laravel-teams-notifier
Requires
- php: ^8.2
- illuminate/contracts: ^11.0 || ^12.0
- illuminate/http: ^11.0 || ^12.0
- illuminate/queue: ^11.0 || ^12.0
- illuminate/support: ^11.0 || ^12.0
- psr/log: ^2.0 || ^3.0
Requires (Dev)
- laravel/pint: ^1.18
- orchestra/testbench: ^9.0 || ^10.0
- phpunit/phpunit: ^10.5 || ^11.5
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
Throwableobjects - 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:
- In Teams, open the target channel or chat's More options, then select Workflows.
- Choose the appropriate Send webhook alerts to a channel/chat template.
- Authenticate the connection, choose the destination, and add the workflow.
- Copy the generated HTTP POST URL into
TEAMS_NOTIFIER_WEBHOOK_URL. - 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, thenX-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.