| Field | Value |
|---|---|
| Display name | Orcha |
| Application (client) ID | eda62fe4-7d17-4f58-af23-838e1b554458 |
| Object ID | a97616b0-c7e6-4a69-aea1-e7f7ec21c452 |
| Directory (tenant) ID | 818432d6-b012-47e8-a326-09e010bf22d0 |
| Supported account types | Multiple Entra ID tenants (all tenants) |
| Client credentials | 1 secret (no certificates) |
| State | Activated |
Portal URL: https://portal.azure.com → Entra ID → App registrations → "Orcha"
| Setting | Value |
|---|---|
| Platform | Web |
| Redirect URI | https://orcha.ngrok.app/settings/notifications/teams/callback |
For production, add: https://app.getorcha.com/settings/notifications/teams/callback
| Permission | Type | Admin Consent | Purpose |
|---|---|---|---|
| Channel.ReadBasic.All | Application | Yes (granted) | List channels in a team via Graph API |
| Team.ReadBasic.All | Application | Yes (granted) | List teams (not currently used but useful) |
| User.Read | Delegated | No | Default permission, not actively used |
Note: Message sending uses Bot Framework API (https://api.botframework.com), not Graph API,
so no Graph permission is needed for sending notifications.
Important: Separate from the App Registration. This is where the messaging endpoint is set.
| Setting | Value |
|---|---|
| Messaging endpoint | https://orcha.ngrok.app/webhooks/teams (local dev) |
| Messaging endpoint | https://app.getorcha.com/webhooks/teams (production) |
Portal URL: https://portal.azure.com → search "Azure Bot" or "Bot Services"
When switching between local dev and production, update the messaging endpoint accordingly.
| Parameter | Purpose |
|---|---|
/v1-orcha/teams-bot-app-id |
Same as Application (client) ID above |
/v1-orcha/teams-bot-app-secret |
Client secret from Certificates & secrets |
/v1-orcha/teams-state-secret |
HMAC key for signing OAuth state params |
Local dev values are in scripts/init_aws.clj (lines 71-77).
Test values are in test/com/getorcha/test/fixtures.clj.
:teams {:bot-app-id #orcha/param "/v1-orcha/teams-bot-app-id"
:bot-app-secret #orcha/param "/v1-orcha/teams-bot-app-secret"
:bot-tenant-id "818432d6-b012-47e8-a326-09e010bf22d0" ;; hardcoded Orcha tenant
:state-secret #orcha/param "/v1-orcha/teams-state-secret"}
bot-tenant-id is hardcoded because Bot Framework tokens are always obtained from the
app's own tenant, regardless of which customer tenant the bot is installed in.
https://orcha.ngrok.app (configured in config.edn line 20, profile :local-dev)
https://app.getorcha.com
| Route | Method | Purpose |
|---|---|---|
/notifications |
GET | Notifications page (Teams UI lives here) |
/settings/notifications/teams/authorize |
GET | Initiates admin consent redirect |
/settings/notifications/teams/callback |
GET | Microsoft redirects back here after consent |
/settings/notifications/teams/{id}/channels |
GET | HTMX: fetch available channels dropdown |
/settings/notifications/teams/{id}/update-channel |
POST | Save selected channel |
/settings/notifications/teams/{id}/disconnect |
POST | Remove Teams connection |
/webhooks/teams |
POST | Bot Framework sends events here |
| URL | Purpose |
|---|---|
https://login.microsoftonline.com/common/adminconsent |
Admin consent flow start |
https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token |
Graph API token (per customer tenant) |
https://login.microsoftonline.com/{bot-tenant-id}/oauth2/v2.0/token |
Bot Framework token (Orcha tenant) |
https://graph.microsoft.com/v1.0/teams/{team-id}/channels |
List channels in a team |
{service-url}/v3/conversations/{channel-id}/activities |
Send message via Bot Framework |
https://login.botframework.com/v1/.well-known/openidconfiguration |
JWT verification keys for webhook |
Location: resources/teams-app/manifest.json
| Field | Value |
|---|---|
| App ID | eda62fe4-7d17-4f58-af23-838e1b554458 |
| Name | Orcha / Orcha Notifications |
| Bot scopes | ["team"] |
| isNotificationOnly | true |
| Valid domains | orcha.ngrok.app, app.getorcha.com |
To sideload: zip manifest.json + color.png (192x192) + outline.png (32x32) into a .zip.
| Column | Type | Notes |
|---|---|---|
| id | UUID (PK) | |
| tenant_id | UUID (FK) | |
| channel_type | enum: email, slack, teams | |
| status | enum: pending, active, disabled |
| Column | Type | Notes |
|---|---|---|
| channel_id | UUID (FK → notification_channel.id) | |
| tenant_id | UUID | Microsoft tenant ID of the customer |
| team_id | TEXT | Thread-format ID (e.g. 19:...@thread.tacv2) |
| team_aad_group_id | TEXT | Azure AD group ID (UUID format, for Graph API) |
| team_name | TEXT | Display name of the team |
| teams_channel_id | TEXT | Channel thread ID |
| teams_channel_name | TEXT | Display name of the channel |
| service_url | TEXT | Bot Framework service URL |
| conversation_id | TEXT | Bot Framework conversation ID |
1. User clicks "Add to Microsoft Teams" on /notifications
→ GET /settings/notifications/teams/authorize
→ 302 to https://login.microsoftonline.com/common/adminconsent?...
2. Customer admin grants consent on Microsoft's page
→ Microsoft redirects to /settings/notifications/teams/callback
→ Creates notification_channel (status=pending) + notification_channel_teams (tenant_id only)
3. Customer installs bot in their Teams team (sideload or app store)
→ Microsoft sends POST /webhooks/teams (conversationUpdate)
→ Updates notification_channel_teams with team_id, team_name, service_url, conversation_id
4. User selects a channel on /notifications page
→ GET /settings/notifications/teams/{id}/channels (fetches from Graph API)
→ POST /settings/notifications/teams/{id}/update-channel
→ Updates teams_channel_id, teams_channel_name, sets status=active
5. Notification triggered
→ Bot Framework token obtained from Orcha's tenant
→ Adaptive Card posted to {service_url}/v3/conversations/{channel_id}/activities
→ Message appears in Teams channel
| File | Description |
|---|---|
20260218120000-add-teams-notification-channel.up.sql |
Creates notification_channel_teams table |
20260222123700-add-teams-aad-group-id.up.sql |
Adds team_aad_group_id column |
20260222123700-add-teams-aad-group-id.down.sql |
Drops team_aad_group_id column |