Chapter 2
Step-by-step setup for Slack OAuth and Teams Bot Framework, then connecting both to Courier. Covers sending notifications through the unified API, designing templates in the visual editor, targeting users and channels, adding interactive buttons, handling webhooks, managing rate limits, and debugging delivery issues.

Getting Slack and Teams notifications working involves platform setup, Courier configuration, and understanding the capabilities you can build for your users.
Head to the Slack API Apps page and create a new app from scratch. The OAuth scopes determine what your app can access. For sending notifications, you need chat:write for posting messages, users:read and users:read.email for looking up users by email, and im:write for direct messages. Add chat:write.public if you want to post to channels without joining them first.
Install the app to your development workspace to get a bot token starting with xoxb-. This token authenticates your API calls. In production, each customer workspace will have its own token.

Teams requires more infrastructure because it's built on Azure Bot Framework. Start by registering an app in the Azure Portal under App Registrations. You'll receive an Application (client) ID and need to generate a client secret.
Next, create the bot through the Teams Developer Portal. Add a bot under App Features and link it to your Azure app registration. Configure the bot endpoint URL where Teams sends incoming messages. This URL must be publicly accessible with HTTPS, requiring a deployed endpoint even for development.
The admin consent requirement adds friction for enterprise customers. When a company installs your app, their IT admin might need to approve it first. The Microsoft Teams integration guide covers complete setup including admin consent handling.

Once you've created apps in Slack and Teams, connect them through the Courier Integrations page. For Slack, you can either connect your own app using your bot token, or use Courier's OAuth flow where customers authorize directly through Courier. The OAuth approach is simpler for multi-tenant scenarios because Courier manages tokens automatically.
For Teams, enter your Azure Application ID and client secret. Courier handles Bot Framework communication and credential storage. The Slack and Teams documentation provide step-by-step instructions. Configuration happens once, then you use the same API for both platforms.
With Slack and Teams configured, sending notifications uses the same API. Install the Courier SDK (available for JavaScript, Python, Ruby, Go, and other languages) and initialize it:
Copied!
const { CourierClient } = require("@trycourier/courier");const courier = new CourierClient({authorizationToken: process.env.COURIER_AUTH_TOKEN});const { requestId } = await courier.send({message: {to: {slack: { email: "engineer@company.com" }},content: {title: "Deployment Complete",body: "Production environment updated to version 2.4.1"}}});
The email-based targeting works without managing Slack user IDs. Courier looks up the user and delivers the message. The content structure translates to Block Kit for Slack, Adaptive Cards for Teams, or plain text for SMS depending on channel.
Target multiple providers by including both slack and ms_teams in the recipient object. The routing documentation covers fallback logic and conditional delivery. For platform-specific control, provider overrides let you specify custom Block Kit or Adaptive Card layouts.
Courier supports several targeting patterns. For channel messages in Slack, specify the channel ID:
Copied!
{"to": {"slack": {"access_token": "xoxb-your-token","channel": "C1234567890"}}}
For Teams channels, provide tenant ID, team ID, channel name, and service URL:
Copied!
{"to": {"ms_teams": {"tenant_id": "your-tenant-id","team_id": "your-team-id","channel_name": "General","service_url": "https://smba.trafficmanager.net/amer"}}}
For multi-channel delivery, use routing preferences:
Copied!
await courier.send({message: {to: { email: "sarah@company.com" },content: {title: "Budget Approval Needed",body: "Q4 marketing budget requires your approval: $45,000"},routing: {method: "all",channels: ["email", "chat"]}}});
The message targeting documentation covers additional patterns including user IDs, incoming webhooks, and conversation IDs.
For recurring notifications, templates separate content from code. Go to the Courier Designer and create a notification with both Slack and Teams channels. Use the Block Kit editor for Slack and Adaptive Cards editor for Teams. Add variables using {{variable_name}} syntax.
Reference the template when sending:
Copied!
await courier.send({message: {to: { slack: { email: "sarah@company.com" } },template: "budget-approval-request",data: {budget_amount: "$45,000",department: "Marketing",quarter: "Q4"}}});
Your product team can update notification copy in the designer without code deployments.
Interactive notifications let users take action directly from the message. In the template designer, add action blocks with buttons for Slack or use the Adaptive Cards editor for Teams.

When someone clicks a button, Courier receives the webhook from Slack or Teams, verifies authenticity, and tracks the interaction in message logs. For custom handling, configure webhook endpoints in workspace settings to receive interaction events directly. The webhooks documentation covers setup for interaction events and delivery confirmations.
Slack's rate limiting uses tiers. Most message-posting falls into Tier 3, allowing approximately one message per second per channel. Burst above that and Slack queues messages. Sustain high rates and you get rate_limited errors. Note: Slack's Retry-After headers aren't always accurate. Developers report needing 60+ seconds even when headers say 3 seconds.
Teams allows approximately 30,000 event deliveries per workspace per app per hour. For most applications this is plenty, but high-volume notifications need queuing.
Courier handles rate limiting automatically, queuing messages and retrying with appropriate backoff. Check delivery status through Courier Logs without building custom debugging tools.
Neither platform provides sandbox environments, so you test against real workspaces. Use the Preview tab in the template designer to send test notifications with sample data. Click Send and verify formatting, variables, and interactive elements in your actual Slack or Teams workspace.
Test from your IDE: The Courier MCP lets you send test notifications directly from AI-enabled editors like Cursor or VS Code with Copilot. Ask your AI assistant to "send a test Slack notification to my email" and it will call the Courier API without leaving your editor. Useful for rapid iteration while building notification logic.

When notifications don't arrive, check Courier Messages. Search by recipient email, user ID, or notification ID. The logs show the complete delivery timeline including errors. Common issues: authentication failures from expired tokens, rate limiting showing as queued status, bots not being channel members for private channels.
For Teams, verify admin consent was granted and your bot has necessary Microsoft Graph permissions. The Messages API provides programmatic access to delivery data for custom dashboards.
Instead of sending separate notifications for each status change, update the original message. Configure a replacement key in your template's Slack channel settings (typically ts for timestamp). For Teams, activity IDs are tracked automatically.
Copied!
// Initial notificationawait courier.send({message: {to: { slack: { email: "engineer@company.com" } },template: "deployment-status",data: { status: "Deployment initiated", tracking_id: "deploy-2024-001" }}});// Update with same tracking_idawait courier.send({message: {to: { slack: { email: "engineer@company.com" } },template: "deployment-status",data: { status: "Deployment complete", tracking_id: "deploy-2024-001" }}});
Courier recognizes matching tracking IDs and updates rather than creates. This keeps channels clean and shows status progression in one place.
Notifications often contain sensitive information. Key requirements:
Verify webhook signatures. When Slack or Teams sends a webhook, they include a signature. Without verification, someone could send fake webhooks pretending to be user interactions. Reject any webhooks that don't verify.
Store tokens securely. Bot tokens grant full access to send messages as your application. Use environment variables or secrets management. Never commit to source control. Rotate periodically. Encrypt at rest.
Implement access controls. Just because someone is authenticated doesn't mean they should send arbitrary messages. Notifications should follow the same authorization rules as other actions.
Audit notification sending. Enterprise customers need to know who sent what when. Some industries require this for regulatory reasons.
Courier handles these by default: tokens encrypted at rest, HTTPS for all communication, automatic webhook signature verification, and SOC 2 Type II certification with HIPAA and GDPR support.
Previous chapter
Why Use Slack and Microsoft Teams Notification Tools
Why workplace notifications reach users faster than email and enable action without context switching. Covers the dual-platform reality facing B2B teams, where Slack and Teams fit within omnichannel strategy, and the essential components for production systems including OAuth, templates, routing, state tracking, and compliance.
Next chapter
Best Practices and Optimization
Message design principles that respect user attention, timing and frequency strategies to prevent fatigue, platform-specific optimization for Slack vs Teams threading and formatting. Covers delivery reliability patterns, error handling, monitoring and observability, user preference management, and edge case handling.
© 2025 Courier. All rights reserved.