Microsoft Teams
Publishes an agent flow as a Teams bot that can message users, be published to a customer's private Teams app catalog, and be installed for named users.
Section 1 covers the Azure artifacts you create outside NeuraFlow, once per bot
(NeuraFlow, NeuraFlow HR, NeuraFlow Growth, …). Section 2 is the console
setup. Section 3 covers the consent flows the customer's admin must approve.
1. Prerequisites
- Directory (tenant) ID
- Application (client) ID
- Client secret
- Bot handle
- Messaging endpoint:
{BASE_URL}/api/v1/webhooks/channels/teams/messages
Steps 1.1–1.6 below produce all five.
All of section 1 happens in Microsoft's portals, not in NeuraFlow. Steps 1.1 to 1.5 are in the Microsoft Entra admin center, step 1.6 is in the Azure portal. You need an account that can create app registrations and grant admin consent, normally Application Administrator or Global Administrator.
1.1 Create the app registration
- Entra admin center → Applications → App registrations → New registration.
- Name it (this is the display name customers see).
- Supported account types: Accounts in any organizational directory (Multi-tenant).
- Register, then copy the Application (client) ID and Directory (tenant) ID from Overview.
Single-tenant registrations authenticate only in your own directory. The bot will fail in every customer tenant, and the fix is a new registration.
1.2 Add redirect URIs
Authentication → Add a platform → Web, then add both. Each derives
from BASE_URL, so register the pair for every environment you run:
{BASE_URL}/api/v1/channels/teams/oauth/callback
{BASE_URL}/api/v1/channels/teams/oauth/catalog/callback
1.3 Add API permissions
API permissions → Add a permission → Microsoft Graph. Add only what you need. Catalog and push are optional (see section 3).
| Permission | Type | Needed for |
|---|---|---|
Chat.Create | Application | Mandatory: bot messages users |
User.Read.All | Application | Mandatory: resolve users |
AppCatalog.ReadWrite.All | Application | Catalog: server-side catalog checks |
AppCatalog.ReadWrite.All | Delegated | Catalog: admin publishes during setup |
TeamsAppInstallation.ReadWriteForUser.All | Application | Push: install for named users |
openid, profile, email | Delegated | Catalog: admin sign-in |
Then Grant admin consent for your own tenant.
1.4 Create the client secret
Certificates & secrets → New client secret. Copy the Value column immediately. Azure hides it after you leave the blade.
1.5 Verify the publisher
Without publisher verification the customer's consent screen labels the app unverified. With it, it reads Brain Station 23.
1.6 Create the Azure Bot
Create a resource → Azure Bot:
| Field | Value |
|---|---|
| Bot handle | Your choice |
| Type of app | Single Tenant |
| Creation type | Create new Microsoft App ID |
| Microsoft App ID | The Application (client) ID from 1.1 |
| App tenant ID | The Directory (tenant) ID from 1.1 |
| Messaging endpoint | {BASE_URL}/api/v1/webhooks/channels/teams/messages |
| Enable Streaming Endpoint | Yes |
Then Channels → add Microsoft Teams.
2. Configuration
Azure credentials are not entered here. They live in the System Configuration and each bot references one.
| Route | Purpose |
|---|---|
/channels/teams | List the organization's bots |
/channels/teams/create | Create a bot |
/channels/teams/{id}/edit | Configure, authorize and deploy |
Create
| Field | Required | Purpose |
|---|---|---|
| Bot Name | Yes | Placeholder My Teams Bot |
| Agent Flow | Yes | Routes every incoming message |
| Azure Configuration | Yes | Which system config to use. Hidden and auto-selected when only one is available |
Short and full descriptions are not on this screen. The console posts fixed
placeholder text (AI Assistant, AI-powered assistant for your organization) and you edit them afterwards on Bot Configuration.
Create Bot validates client side, then calls POST /channels/teams. On
success it navigates to the edit page.
Blocking conditions:
| Condition | Result |
|---|---|
| No organization selected | Form disabled, "Organization Required" banner |
| No Azure configuration available | Creation blocked, "No Available Configuration" banner |
| Organization has no agent flows | Inline warning linking to /agent-builder/create |
Server errors are rewritten before display:
| Server message contains | Toast shown |
|---|---|
Azure, tenant or app | Please configure Azure credentials in Settings > Channels > Teams first. |
already has a Teams bot | This organization already has a bot using this system configuration. |
| anything else | The raw server message |
Edit
Three tabs: Permissions, Bot Configuration, Deploy.
Permissions
Grants and revokes the three consents from section 3. The tenant shown is read from the system config and is not editable here.
| Control | Calls | Result |
|---|---|---|
| Authorize Chat | POST /channels/teams/oauth/authorize | Full-page redirect to Microsoft |
| Authorize Push | POST /channels/teams/oauth/push/authorize | Full-page redirect. Disabled until chat is authorized |
| Sign In (catalog) | POST /channels/teams/oauth/catalog/authorize | Full-page redirect |
| Revoke (chat) | POST /channels/teams/oauth/revoke | Clears consent, refetches status |
| Revoke (push) | POST /channels/teams/oauth/push/revoke | Clears push consent |
| Sign Out (catalog) | POST /channels/teams/oauth/catalog/revoke | Clears catalog token |
| Revoke All | Both revoke endpoints in sequence | Disabled when neither is authorized |
Each consent shows a status badge, its scope badges, and once granted the
approving admin and timestamp. Status comes from
GET /channels/teams/oauth/consent-info.
Verify calls GET /channels/teams/{id}/test, which does not exist on the
backend. It always fails with "Connection test failed."
Authorize Both writes a teams_authorize_both_{id} flag to
sessionStorage intended to auto-continue into push authorization after the
chat redirect returns. Nothing reads that flag, so the button needs a second
click once you land back on the page.
Bot Configuration
Everything that ends up in the Teams app manifest.
| Field | Required | Default | Manifest target |
|---|---|---|---|
| Bot Enabled | No | On | Not in the manifest. Off stops responses without deleting the bot |
| Name | Yes | Placeholder NeuraFlow Bot | name.short (truncated to 30) and name.full |
| Agent Flow | Yes | none | Not in the manifest. Selects the answering flow |
| Short Description | No | none | description.short. Hard limit 80, truncated as you type |
| Full Description | No | none | description.full |
| Version | No | 1.0.0 | version |
| Accent Color | No | #5558AF | accentColor |
| Privacy URL | To deploy | none | developer.privacyUrl. Must be HTTPS |
| Terms of Use URL | To deploy | none | developer.termsOfUseUrl. Must be HTTPS |
| Color Icon | No | none | 192x192 PNG |
| Outline Icon | No | none | 32x32 PNG |
| Control | Calls | Result |
|---|---|---|
| Color / Outline Icon picker | POST /channels/teams/{id}/icons/{color|outline} | Uploads immediately on file choice, no save step. Shows an "Uploaded" badge |
| Save Changes | PUT /channels/teams/{id} | Saves every field above except icons |
A missing or non-HTTPS Privacy or Terms URL raises an inline error and blocks both actions on the Deploy tab.
The database column default for Accent Color is #0066CC, but the create API
supplies #5558AF and the console never sends the field, so new bots get
#5558AF.
Deploy
| Control | Available when | Calls | Result |
|---|---|---|---|
| Push to Catalog | Catalog signed in and URLs set | POST /channels/teams/{id}/deploy | Publishes to the tenant's app catalog, updates deployment status |
| Download Manifest | URLs set | GET /channels/teams/{id}/manifest | Downloads a .zip for manual upload |
| Search Users | Push consent granted | GET /channels/teams/{id}/users | Populates the user dropdown |
| Push to User | A user is selected | POST /channels/teams/{id}/push-to-user | Installs the bot for that user |
| Teams Admin Center | Always | none | Opens the Microsoft admin portal in a new tab |
Deployment status is not_deployed, deploying, active or error.
Missing prerequisites replace the relevant control with a banner linking to the tab that fixes it: unset URLs point at Bot Configuration, missing catalog sign-in or push consent point at Permissions. Download Manifest stays available without catalog sign-in, since it only needs the URLs.
3. Other
Three independent consents. Only the first is required. A customer can grant chat alone and still run the bot.
| Consent | Required | Scopes | Endpoint |
|---|---|---|---|
| Chat | Yes | Chat.Create, User.Read.All | /{tenant}/adminconsent |
| Catalog | No | AppCatalog.ReadWrite.All, offline_access, openid, profile, email | /{tenant}/oauth2/v2.0/authorize?prompt=consent |
| Push | No | TeamsAppInstallation.ReadWriteForUser.All | /{tenant}/adminconsent |
Chat and push are tenant-wide admin consent: the admin approves once for the
whole organization. Catalog is delegated: the admin signs in as themselves
and their token is stored, which is why offline_access is in scope and why
catalog is the only consent that expires.
Each consent revokes independently.
Getting the bot into Teams
| Path | Requires |
|---|---|
| Deploy from NeuraFlow. Publishes to the customer's private catalog, updates in place | Catalog consent |
Download manifest .zip, customer uploads it themselves | Chat consent only |
Deployment errors
| Message | Fix |
|---|---|
Privacy URL is required / must be a valid HTTPS URL | Set it on the bot |
Terms of Use URL is required / must be a valid HTTPS URL | Set it on the bot |
Developer Website URL is required | System Configuration (BS23 admin) |
Developer Name exceeds 32 characters | System Configuration (BS23 admin) |
Admin sign-in required. Please authorize catalog permissions first | Grant catalog consent, or use the manual path |
Catalog authorization has expired | Re-run catalog consent on the Permissions tab |