Skip to content

Version: Arctyk ITSM v0.6.0+ Last Updated: January 2026

Microsoft Teams Integration

Real-time Microsoft Teams notifications for ticket events in Arctyk ITSM.


Overview

Current Status

🔄 Planned for v0.7.0+

Microsoft Teams integration will provide:

  • ✅ Real-time ticket notifications in Teams
  • ✅ Interactive Teams cards for ticket actions
  • ✅ Adaptive Cards for rich formatting
  • ✅ Teams bot commands for ticket management
  • ✅ Ticket updates from Teams

Planned Features

1. Incoming Webhook Notifications

Receive Teams messages when tickets are created or updated:

🎫 New Ticket
Title: Unable to login
Ticket: TKT-001
Priority: 🔴 High
Requester: John Doe
Project: Platform

[View] [Assign] [Add Comment]

2. Adaptive Cards

Rich, interactive cards in Teams:

┌─────────────────────────────────┐
│ TKT-001: Unable to Login        │
│─────────────────────────────────│
│ Status: 🟡 In Progress          │
│ Priority: 🔴 High              │
│ Assigned: Alice Johnson         │
│ Due: Tomorrow                   │
│─────────────────────────────────│
│ [Resolve] [Hold] [Comment]      │
└─────────────────────────────────┘

3. Teams Bot Commands

Manage tickets via @mention:

@arctyk create "Server Down" "Production offline"
@arctyk TKT-001 status resolved
@arctyk comment TKT-001 "Fixed the issue"

4. Conversation Threading

Ticket comments sync with Teams conversation:

Main Message (Ticket created)
  └─ Reply (Comment 1)
     └─ Reply (Comment 2)

Setup Instructions (v0.7.0+)

1. Create Teams App

  1. Go to Microsoft App Studio
  2. Click "Create a new app"
  3. Fill in basic information:
  4. App Name: Arctyk ITSM
  5. Version: 1.0.0
  6. Package ID: Generate unique ID
  7. Description: ITSM notifications

2. Register Bot

Under "Capabilities" → "Bot":

  1. Click "Create"
  2. Set Bot Endpoint: https://arctyk.example.com/integrations/teams/messages/
  3. Generate App ID and Password
  4. Select "Personal", "Team", "Group Chat"

3. Generate OAuth Token

  1. Copy Bot App ID and Password
  2. Store in environment variables
  3. Configure in Arctyk admin

4. Create Incoming Webhook

  1. Go to your Teams channel
  2. Click "⋯" (More options)
  3. Select "Connectors"
  4. Configure "Incoming Webhook"
  5. Get webhook URL
  6. Add to Arctyk settings

5. Configure in Arctyk

Navigate to Admin > Integrations > Teams:

Teams Webhook URL: https://outlook.webhook.office.com/...
Bot App ID: YOUR-BOT-ID
Bot App Password: YOUR-BOT-PASSWORD
Channel: General

Configuration

Environment Variables

TEAMS_BOT_ID=YOUR-BOT-APP-ID
TEAMS_BOT_PASSWORD=YOUR-BOT-PASSWORD
TEAMS_WEBHOOK_URL=https://outlook.webhook.office.com/...
TEAMS_DEFAULT_CHANNEL=General

Django Settings

# src/config/settings.py
TEAMS_INTEGRATION = {
    'enabled': True,
    'bot_id': os.getenv('TEAMS_BOT_ID'),
    'bot_password': os.getenv('TEAMS_BOT_PASSWORD'),
    'webhook_url': os.getenv('TEAMS_WEBHOOK_URL'),
    'default_channel': os.getenv('TEAMS_DEFAULT_CHANNEL', 'General'),
}

Event Mapping

Ticket Events

Arctyk Event Teams Notification
Ticket Created Adaptive Card in channel
Ticket Assigned Mention in reply
Status Changed Card update or new message
Comment Added Reply in thread
Overdue Alert card
SLA Breach Warning card

Example Notifications

Ticket Created Card

{
  "@type": "MessageCard",
  "@context": "https://schema.org/extensions",
  "summary": "New Ticket: Unable to login",
  "themeColor": "0078D4",
  "title": "🎫 New Ticket",
  "sections": [
    {
      "activityTitle": "Unable to login (TKT-001)",
      "activitySubtitle": "Platform Project",
      "facts": [
        { "name": "Priority", "value": "🔴 High" },
        { "name": "Requester", "value": "John Doe" },
        { "name": "Status", "value": "🆕 New" }
      ]
    }
  ],
  "potentialAction": [
    {
      "@type": "OpenUri",
      "name": "View Ticket",
      "targets": [
        { "os": "default", "uri": "https://arctyk.example.com/tickets/1/" }
      ]
    },
    {
      "@type": "Action.OpenUri",
      "name": "Assign to Me",
      "uri": "https://arctyk.example.com/api/tickets/1/assign/"
    }
  ]
}

Status Update Notification

✅ TKT-001: Unable to login → Resolved
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Resolver: Alice Johnson
Time to Resolve: 2h 30m
Updated: 5 minutes ago

[View] [Close] [Reopen]

Teams Bot Commands (v0.7.0+)

Create Ticket

@arctyk create
Title: Website Down
Description: Homepage not loading
Priority: Critical

Or:

@arctyk ticket "Website Down" --priority=critical --project=Platform

Manage Ticket

@arctyk TKT-001 status in_progress
@arctyk TKT-001 assign @alice.johnson
@arctyk TKT-001 comment "Working on this now"

List Tickets

@arctyk my-tickets
@arctyk team-tickets
@arctyk critical

Adaptive Card Template

{
  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
  "type": "AdaptiveCard",
  "version": "1.4",
  "body": [
    {
      "type": "Container",
      "style": "emphasis",
      "items": [
        {
          "type": "ColumnSet",
          "columns": [
            {
              "width": "stretch",
              "items": [
                {
                  "type": "TextBlock",
                  "text": "{{ ticket.title }}",
                  "weight": "bolder",
                  "size": "large"
                }
              ]
            },
            {
              "width": "auto",
              "items": [
                {
                  "type": "TextBlock",
                  "text": "{{ ticket.ticket_number }}",
                  "color": "good"
                }
              ]
            }
          ]
        }
      ]
    },
    {
      "type": "FactSet",
      "facts": [
        { "name": "Status", "value": "{{ ticket.status }}" },
        { "name": "Priority", "value": "{{ ticket.priority }}" },
        { "name": "Assigned", "value": "{{ ticket.assigned_user }}" }
      ]
    }
  ],
  "actions": [
    {
      "type": "Action.OpenUri",
      "title": "View in Arctyk",
      "uri": "{{ view_url }}"
    },
    {
      "type": "Action.Submit",
      "title": "Update Status",
      "data": { "action": "update_status" }
    }
  ]
}

Integration Architecture

┌──────────────────────┐
│  Arctyk ITSM Event   │
│  (Ticket Created)    │
└──────────┬───────────┘
┌──────────────────────┐
│  Celery Task         │
│  send_teams_message  │
└──────────┬───────────┘
┌──────────────────────┐
│  Teams Webhook       │
│  POST Adaptive Card  │
└──────────┬───────────┘
┌──────────────────────┐
│  Teams Channel       │
│  Display Card        │
└──────────────────────┘

Thread/Conversation Management

Link Teams messages to Arctyk tickets:

# When card is posted, store the Teams message ID
teams_message = TeamsMessage.objects.create(
    ticket=ticket,
    channel_id='19:...',
    message_id='1234567890',
    thread_id='1234567890'
)

# When ticket is updated, update Teams card
update_teams_card(teams_message, updated_ticket)

Troubleshooting

Message Not Sending

  1. Verify webhook URL is correct
  2. Check bot has proper permissions
  3. Verify channel name matches configuration
  4. Check Celery worker is running

Bot Commands Not Working

  1. Verify bot is installed in Teams
  2. Check bot app ID and password
  3. Verify bot endpoint URL is accessible
  4. Check Teams app logs

Adaptive Cards Not Rendering

  1. Validate JSON schema
  2. Check required fields
  3. Use Adaptive Card Designer

Security

Token Management

  • ✅ Store tokens in environment variables
  • ✅ Rotate tokens periodically
  • ✅ Use app-only auth for service account
  • ❌ Don't commit tokens to repository

Message Validation

Validate Teams requests:

from botframework.connector.auth import JwtTokenValidation

if not JwtTokenValidation.authenticate_request(activity, credentials):
    raise ValidationError('Invalid Teams message')

Rate Limiting

Teams API rate limits:

  • Webhook: ~5 messages per second per webhook
  • API: Varies by resource

Solution: Queue messages and batch.


Testing

Local Testing

# Install ngrok
ngrok http 8000

# Update Teams endpoint to:
# https://YOUR-NGROK-URL/integrations/teams/messages/

Mock Testing

@patch('teams_sdk.AdaptiveCardAction')
def test_ticket_notification(mock_card):
    ticket = Ticket.objects.create(...)

    mock_card.assert_called_once()
    assert 'Unable to login' in mock_card.call_args.kwargs['text']

Future Enhancements

v0.7.0

  • Real-time notifications
  • Adaptive Cards
  • Bot commands
  • Thread syncing

v0.8.0

  • Workflow automation
  • Rich media support
  • Advanced filtering
  • CoPilot integration


Support

For Teams integration questions:

  1. Check Microsoft Teams Bot Documentation
  2. Review Adaptive Cards
  3. Contact the development team