💎 ChatSDK Ruby

Microsoft Teams Adapter

Bot Framework adapter with Adaptive Cards for Microsoft Teams integration.

The Teams adapter (chat_sdk-teams) integrates with Microsoft Teams via the Bot Framework.

Installation

# Gemfile
gem "chat_sdk"
gem "chat_sdk-teams"

Configuration

require "chat_sdk"
require "chat_sdk/teams"

teams = ChatSDK::Teams::Adapter.new(
  app_id: ENV["TEAMS_APP_ID"],           # or set TEAMS_APP_ID env var
  app_password: ENV["TEAMS_APP_PASSWORD"], # or set TEAMS_APP_PASSWORD env var
  tenant_id: ENV["TEAMS_TENANT_ID"]       # optional, set TEAMS_TENANT_ID env var
)

app_id and app_password are required. tenant_id is optional.

Environment Variables

VariableDescription
TEAMS_APP_IDBot's Application (client) ID from Azure AD
TEAMS_APP_PASSWORDBot's client secret
TEAMS_TENANT_IDAzure AD tenant ID (optional)

Azure Bot Setup

  1. Register a bot in the Azure Portal under Bot Services.
  2. Note the Application (client) ID and create a client secret.
  3. Configure the messaging endpoint to your webhook URL (e.g., https://your-app.com/webhooks/teams).
  4. Create a Teams app manifest and install it in your Teams organization.

Webhook URL

https://your-domain.com/webhooks/teams
map "/webhooks/teams" do
  run bot.webhooks[:teams]
end

Capabilities

CapabilitySupportedNotes
edit_messagesYes
delete_messagesYes
ephemeral_messagesNoRaises NotSupportedError
file_uploadsYesVia Base64-encoded attachments
reactionsInbound onlyParsing works, but adding/removing raises PlatformError
modalsNoRaises NotSupportedError
typing_indicatorYesVia Bot Framework typing activity
streaming_editYes
threadsYesUses replyToId
direct_messagesYesCreates 1:1 conversations
message_historyYesVia Microsoft Graph API (requires additional credentials)

Service URL Registration

Teams requires a serviceUrl to send messages. ChatSDK resolves a conversation URL in this order: the URL from a trusted incoming activity registered in the current adapter, the shared state key chat_sdk:teams:service_url:<conversation_id>, then the configured service_url: or DEFAULT_SERVICE_URL. For proactive messaging, you may register it manually:

teams_adapter = bot.adapter(:teams)
teams_adapter.register_service_url(
  "conversation-id-123",
  "https://smba.trafficmanager.net/..."
)

ChatSDK::Chat injects its state adapter into adapters that support set_state(state). When processes share a state backend, a background job or another process can reply using the service URL persisted from an incoming activity. Redis, PostgreSQL, and MySQL state adapters can be shared across processes; ChatSDK::State::Memory is per-process. A process-local URL registered with register_service_url takes precedence over the value in shared state.

When opening a DM, the adapter reuses the user's last trusted activity service URL from state (with a 30-day TTL), then falls back to a process-local registered URL and the configured default. Set service_url: or TEAMS_SERVICE_URL to override the final default for a deployment whose Bot Framework service endpoint is not the standard Teams endpoint.

Cards Rendering

Cards are rendered as Adaptive Cards using the AdaptiveCardRenderer. They are sent as message attachments with content type application/vnd.microsoft.card.adaptive.

Direct Client Access

teams_adapter = bot.adapter(:teams)
client = teams_adapter.client  # BotFrameworkClient

Mention Formatting

Teams mentions use the format <at>USER_ID</at>:

thread.mention_user("user-id-123")  # => "<at>user-id-123</at>"

Graph API Message History

The Bot Framework does not natively support fetching message history. To enable fetch_messages, provide Microsoft Graph API credentials:

teams = ChatSDK::Teams::Adapter.new(
  app_id: ENV["TEAMS_APP_ID"],
  app_password: ENV["TEAMS_APP_PASSWORD"],
  graph_client_id: ENV["TEAMS_GRAPH_CLIENT_ID"],
  graph_client_secret: ENV["TEAMS_GRAPH_CLIENT_SECRET"],
  graph_tenant_id: ENV["TEAMS_GRAPH_TENANT_ID"]
)

messages, next_cursor = teams.fetch_messages(channel_id: "chat-id-123")

The Graph API credentials are separate from the Bot Framework credentials. Register an Azure AD app with Chat.Read permissions and grant admin consent. Without these credentials, calling fetch_messages raises a ConfigurationError.

On this page