Skip to content

Teams technical integration

Ways to connect Teams and Tallyfy

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 channel
Action: HTTP POST to Tallyfy API
Action: Post Adaptive Card to Teams with workflow link

Adaptive Cards for task notifications

You 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}"
}
}
]
}

Microsoft Graph API integration

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 completes
const 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);
};

Incoming webhooks

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 }]
}]
})
});
};

Bot Framework integration

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!' }};
}
}
}

Authentication setup

Teams integration uses Azure AD OAuth 2.01. Here’s the setup in Azure portal:

  1. Register your app in Azure AD
  2. Add Microsoft Graph API permissions
  3. Set redirect URIs for your integration
  4. 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;
};

iPaaS alternatives

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

Vendors > Microsoft Teams

Microsoft Teams handles communication but not structured process execution so Tallyfy fills that gap by turning chat messages into tracked workflows with assigned owners and deadlines and escalation rules and audit trails that prevent requests from getting buried in busy channels.

Middleware > Power Automate

Microsoft Power Automate serves as a no-code bridge between Tallyfy and your other business systems—including Office 365 and SharePoint and Dynamics—using a Premium-tier OAuth 2.0 connector with 13 actions to sync data and automatically launch processes or complete tasks based on events happening across your entire software stack.

Power Automate > Connect Tallyfy to Power Automate

Tallyfy’s Premium connector for Microsoft Power Automate lets you link Tallyfy with Office 365 and thousands of other apps by simply searching for “Tallyfy” in Power Automate and signing in with OAuth 2.0 to start automating workflows in both directions.

Footnotes

  1. Industry-standard protocol for secure delegated authorization without sharing passwords