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? You’ll want 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. Tallyfy fills that…

Pro > Integrations

Tallyfy connects with your existing business software through twelve methods, from a full REST…

Footnotes

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