Teams technical integration
Microsoft Teams integration relies on three main tools - Graph API, Adaptive Cards, and Power Automate. Pick whichever fits your setup.
The easiest route uses Power Automate as middleware between Teams and Tallyfy:
Trigger: When a message is posted to a channelAction: HTTP POST to Tallyfy APIAction: Post Adaptive Card to Teams with workflow linkYou can send rich, interactive cards to Teams channels whenever Tallyfy tasks get assigned:
{ "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", "type": "AdaptiveCard", "version": "1.4", "body": [ { "type": "TextBlock", "text": "New Task Assigned", "weight": "Bolder", "size": "Medium" }, { "type": "FactSet", "facts": [ { "title": "Task:", "value": "${taskTitle}" }, { "title": "Process:", "value": "${processName}" }, { "title": "Due:", "value": "${dueDate}" }, { "title": "Assigned by:", "value": "${assignedBy}" } ] }, { "type": "TextBlock", "text": "${taskDescription}", "wrap": true } ], "actions": [ { "type": "Action.OpenUrl", "title": "Open in Tallyfy", "url": "${taskUrl}" }, { "type": "Action.Submit", "title": "Mark Complete", "data": { "action": "complete", "taskId": "${taskId}" } } ]}Post Tallyfy workflow updates to Teams channels through the Graph API:
const { Client } = require('@microsoft/microsoft-graph-client');
const postToTeamsChannel = async (channelId, teamId, message, card) => { const client = Client.init({ authProvider: (done) => done(null, accessToken) });
await client .api(`/teams/${teamId}/channels/${channelId}/messages`) .post({ body: { contentType: 'html', content: message }, attachments: [{ contentType: 'application/vnd.microsoft.card.adaptive', content: JSON.stringify(card) }] });};
// Example: Post when Tallyfy workflow completesconst notifyWorkflowComplete = async (workflow) => { const card = { type: 'AdaptiveCard', version: '1.4', body: [{ type: 'TextBlock', text: `✅ Workflow Complete: ${workflow.name}`, weight: 'Bolder' }, { type: 'FactSet', facts: [ { title: 'Completed by:', value: workflow.completedBy }, { title: 'Duration:', value: workflow.duration }, { title: 'Tasks:', value: `${workflow.completedTasks}/${workflow.totalTasks}` } ] }] };
await postToTeamsChannel(channelId, teamId, 'Workflow completed', card);};For simpler setups, Teams incoming webhooks work well:
const postToTeamsWebhook = async (webhookUrl, message) => { await fetch(webhookUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ '@type': 'MessageCard', '@context': 'http://schema.org/extensions', summary: message.title, themeColor: '0076D7', title: message.title, sections: [{ activityTitle: message.subtitle, facts: message.facts, text: message.body }], potentialAction: [{ '@type': 'OpenUri', name: 'View in Tallyfy', targets: [{ os: 'default', uri: message.url }] }] }) });};Need richer interaction? Build a custom Teams bot:
const { TeamsActivityHandler, CardFactory } = require('botbuilder');
class TallyfyBot extends TeamsActivityHandler { constructor() { super();
this.onMessage(async (context, next) => { const text = context.activity.text.toLowerCase();
if (text.includes('launch workflow')) { const workflowName = text.replace('launch workflow', '').trim(); const workflow = await launchTallyfyWorkflow(workflowName);
await context.sendActivity({ attachments: [CardFactory.adaptiveCard(createWorkflowCard(workflow))] }); }
if (text.includes('my tasks')) { const tasks = await getTallyfyTasks(context.activity.from.aadObjectId); await context.sendActivity({ attachments: [CardFactory.adaptiveCard(createTaskListCard(tasks))] }); }
await next(); }); }
async handleTeamsTaskSubmit(context, taskModuleRequest) { const { action, taskId } = taskModuleRequest.data;
if (action === 'complete') { await completeTallyfyTask(taskId); return { task: { type: 'message', value: 'Task marked complete!' }}; } }}Teams integration uses Azure AD OAuth 2.01. Here’s the setup in Azure portal:
- Register your app in Azure AD
- Add Microsoft Graph API permissions
- Set redirect URIs for your integration
- Use client credentials flow for server-to-server calls
const { ConfidentialClientApplication } = require('@azure/msal-node');
const msalConfig = { auth: { clientId: process.env.AZURE_CLIENT_ID, clientSecret: process.env.AZURE_CLIENT_SECRET, authority: `https://login.microsoftonline.com/${process.env.AZURE_TENANT_ID}` }};
const cca = new ConfidentialClientApplication(msalConfig);
const getGraphToken = async () => { const result = await cca.acquireTokenByClientCredential({ scopes: ['https://graph.microsoft.com/.default'] }); return result.accessToken;};If you don’t want to write custom code:
- Power Automate - Microsoft’s native automation platform
- Zapier - pre-built Teams triggers and actions
- Workato - enterprise automation with a Teams connector
- Make - visual workflow builder with Teams integration
Power Automate > Integrating Power Automate approvals with Microsoft Teams
-
Industry-standard protocol for secure delegated authorization without sharing passwords ↩
Was this helpful?
- 2025 Tallyfy, Inc.
- Privacy Policy
- Terms of Use
- Report Issue
- Trademarks