M365 Show -  Microsoft 365 Digital Workplace Daily
M365 Show with Mirko Peters - Microsoft 365 Digital Workplace Daily
Viva Connections: Automate What You Thought Was Manual
0:00
-22:47

Viva Connections: Automate What You Thought Was Manual

Ever wondered why your Viva deployment feels half-finished, despite all the hype? Most organizations barely scratch the surface of what Viva APIs can actually do. Today, we're going deep—I'll show you how to automate your own custom learning modules, auto-publish organization-wide news, and weave your company knowledge straight into Viva Topics using real API calls.

If you're tired of manual data entry and want to make Viva work for your business—not the other way around—you’re in the right place.

Breaking the Authentication Barrier: Real-World API Access Without Headaches

If you’ve ever tried to connect to a Viva API and hit that brick wall of an authentication failure, you’re not alone. Most folks start out with the docs right in front of them, thinking it’s going to be a quick afternoon project. You plug in your client ID, pop a request over to Azure AD for a token, try to call the endpoint, and—boom—“Unauthorized.” Not a helpful ‘try this’ message. Just that cold, dead stop that leaves you tracing your code one line at a time. I’ve seen experienced M365 engineers, people who live and breathe Graph, get stuck here and start questioning if they’ve misunderstood basic OAuth. There’s that temptation to blame yourself, or the docs, or the universe, but the truth is, Viva’s API story is just trickier than a lot of the standard Microsoft stuff.

Even with the official documentation, you can follow every step and still find yourself adrift. One moment you’re thinking, “This should be the same as calling Microsoft Graph,” and the next you’re sifting through thirty tabs on delegated permissions, application scopes, admin consent, and secret registration. What makes it even messier is the split between Graph and native Viva endpoints. Some endpoints live under the wider Graph umbrella, but others—especially the ones for deeper automation of Topics or Learning—require their own specific permissions and scopes. You might get a token that works perfectly for /me or /users or SharePoint content, then hit a wall when sending that same token to a Viva endpoint. And the error messages sometimes read like they were output by a machine learning model on its first day—just cryptic enough to be unhelpful, but not weird enough to give you something to Google.

Let’s talk permissions, because this is where most roadblocks pop up. There’s that classic Azure portal screen, littered with toggles for Delegated and Application Permissions. It’s not enough to pick one at random. If you go with Delegated, your requests will only work in the context of whoever’s signed in—which is fine for testing, not great for scheduled automations. Application permissions are what most orgs want for real automation, but getting them approved can take days or weeks if your security team is strict. There’s usually at least one back-and-forth, some tense emails about ‘why do you need this,’ and—if Conditional Access is in play—an extra check that mysteriously blocks access at runtime without a clear error. I’ve seen orgs burn a full sprint just trying to land one permission in the right place, all while the project manager asks for status updates.

Too often, it comes down to one missing permission that someone assumed got granted. A classic case: a mid-sized company tried to orchestrate custom Topic publishing. Everything looked stamped ‘success’ in the portal. Service principal was set up, secret configured, scopes listed as granted, but every single automation job failed. After hours of log-chasing, it turned out one obscure “Viva Topics.Manage” permission was missing from the app registration. No warning, just silent failure. The fix was simple once they found it—add the permission, re-consent, restart the workflow. But they’d lost an entire week to a box left unchecked.

The technical side isn’t just about picking the right permissions, though. There are real choices about how you authenticate the app itself. A year ago, everyone was using client secrets. Fast, simple, but a little weak on security. More orgs moved to certificates—they’re more secure and easier to rotate, but also more prone to subtle failures if you don’t manage the certificate stores or key vaults carefully. Recently, there’s been a shift away from allowing client secrets altogether, especially with Microsoft tightening default tenant security. Some tenants block older auth flows outright. If you’re scripting in PowerShell or writing a quick C# connector, you’ll need to pay close attention to exactly which secret or certificate your app expects. Miss a step, and you’ll either get a warning about not finding the right credential, or worse, another generic “Unauthorized” message.

When you’re actually laying down code, even a working sample might trip you up the first time. Picture a C# console app with MSAL built in. You authenticate, fetch the token, call the endpoint—and you get a 403 forbidden. Dig into the network trace, and you’ll spot the scope line: maybe it’s missing the exact “https://yourtenant.viva.microsoft.com/.default” permission, or you’re using a Graph token for something that needs the native endpoint. It only takes one mismatch to trigger a silent error.

The best way forward is always to ask for the least possible privilege. It’s tempting to just tick every box and ask for global admin consent, but your security team will call foul, and honestly—it’s unnecessary risk. Focus on the specific scopes your workflow actually needs. If you’re just writing Topics, don’t ask for user profile access. Go minimal. That’s the approach that stands up in a proper security review, and it’s more likely to avoid breakage six months from now after a global policy change.

If you’ve been locked out before, chances are it wasn’t your code. It was a missing app registration, a half-approved permission, or a certificate upload that expired last week and no one noticed. Start with a checklist: target the right endpoint, use the minimal required scope, confirm consent has actually landed, and if you use certificates, set renewals and automate the check. That’s the real bulletproof flow—nothing fancy, but it survives a security audit and keeps your automation running even when tenant settings shift underneath you.

Once you’ve broken through that authentication wall, everything opens up. With solid access, you’re finally able to automate—and the first place to see real impact is automating Viva Topics. This is where the manual drudgery finally starts to disappear.

Custom Knowledge, No Manual Entry: Automating Viva Topics at Scale

If you’ve spent any time poking through a freshly turned-on Viva Topics Center, you already know the punchline. Most of the time, you’ll find a handful of automatically-generated pages and then a lot of blank spaces. The search bar turns up quirky projects, acronyms no one remembers, and about half a page of boilerplate. Everything else? Empty or out of date. It’s not that your company lacks knowledge worth sharing—it’s that nobody’s got the time or patience to stay on top of it. The typical knowledge manager holds out for a month or two, gamely filling in cards and nudging coworkers to pitch in, but eventually, manual curation stalls out. Even with the best intentions, this is grunt work. No one lines up to type out project overviews or track down expertise every time a new team spins up.

So why don’t more organizations just automate the bulk of it? You can technically create Topics by calling the API, but here’s where reality asserts itself. The docs are thin, especially when it comes to real examples, and error messages range from vague to downright misleading. You’ll send a beautifully structured POST request, see a “201 Created” in the response, and pat yourself on the back—until you check the Topics Center and your new topic is nowhere to be found. If you try to trace what vanished, you’ll get little help from the logs. Most folks lose hours to this stage, convinced the API simply doesn’t work as promised.

Here’s what’s actually going on. Viva Topics is strict about required fields, and even stricter about metadata. Most of the time, invisible topics happen because a single field is missing, or a property is in the wrong publishing state. You’ve got to hit the right balance between mandatory and optional details. If you skip type or context cues, or leave out alternate names, that’s a recipe for “create but not display.” And if you don’t explicitly set the publishing status—think draft versus published—it’s going to stay hidden. The API will happily take your data, but the system quietly shelves it, waiting for an admin, or a workflow, to hit Publish. Until then, you’ve filled the database, but your knowledge doesn’t surface.

It’s a big difference when you see it done right. Think about a manufacturing company that was tired of generic, half-filled topic pages. Before, their Topic Center was an empty shell, apart from a few scattered topics about HR policies and leadership. Then, they built a bulk upload tool—just a simple service running on Azure Functions—pulling details from their internal SharePoint archives. They mapped core concepts and key projects into the topic schema, piped it into the endpoint, and published at scale. The overnight result? Suddenly, their knowledge center lit up. Project teams didn’t need to guess who’d run an initiative three years ago—every concept page pulled real descriptions, owner lists, and related content, all automated. The transformation was hard to miss, not because of flashy UI, but because people finally found answers when they searched.

Let’s quickly break down what actually matters inside the API call. The endpoint for creating a Topic sits inside the Graph universe, but it expects rigorous structure. You need the right JSON payload—title, description, alternative names, and at least one reference. What surprises most folks is that the “state” property needs to be set to “published.” Leave it as “draft” or skip it, and no end user will ever see your hard work. Same goes for referencing owners and relevant files. Too sparse, and you’ll run into problems with visibility.

Here’s what a typical C# POST for pushing a topic looks like in practice. Spin up an HttpClient, point to the /topics endpoint, and set your authorization header with that working token—use the minimal permissions you set up earlier. The content body carries the details: title, summary, alternate names, plus a published state. Wrap the call in a try-catch, since throttling can pop up if you go too fast. If you get hit with a 429, back off and retry after the suggested interval—Viva’s APIs can be touchy if you hammer them even a little too hard.

When you scale up—let’s say you want to publish not ten, but 400 topics in one shot—you hit new friction. These APIs aren’t built for mass ingestion all at once. If you queue hundreds of parallel requests, you’ll either blow past rate limits or start running into unexplained “Too Many Requests” responses. The right move is to batch calls—spread them out using Task.Delay or a similar throttling pattern, and handle each response individually. Keep a log. If a POST fails on one topic, don’t let it grind your whole batch to a halt; log it, tag the ID, and move on.

And it’s worth double-checking what’s gone live once you’re done. Nine times out of ten, if a new flood of topics isn’t showing up, it comes back to missing metadata or a slip in the publishing state—not a network glitch or a token issue. Get those fields right and suddenly, your Topics Center isn’t an empty promise—it’s searchable, up-to-date, and actually useful.

But knowledge at scale isn’t just about static pages stored in a portal. It’s about making information actionable, pushing expertise and learning out to the people who need it. Imagine not only automating what lands in Topics, but sending custom training materials from any platform straight into Viva Learning—without clicking through endless UI. That’s where the real power of automation starts to show.

From LMS Silos to Seamless Learning: Pushing External Content Into Viva Learning

If you’ve ever tracked down the perfect compliance course or product tutorial—only to find out it’s buried four logins deep in a legacy LMS—you know how frustrating learning silos can be. Every organization picks up a handful of different platforms over the years: a mainline LMS for HR training, a vendor solution for role-based certifications, and a few niche sites for onboarding. Employees end up juggling a bunch of passwords and, more often than not, missing out on resources they didn’t even know existed. The result? Hard work gets hidden away, and people settle for what’s visible inside Viva Learning—even when your org could offer a lot more.

Microsoft’s promise sounds great: “bring all your learning content into one place.” In reality, out-of-the-box integrations cover only the biggest learning vendors. When you ask most admins how they get third-party courses into Viva Learning, the answer is usually either “manually, one at a time,” or a long pause followed by “We’re working on it.” Clicking through upload screens for each video, link, and quiz is a recipe for burnout, not to mention it’s unscalable if you’ve collected content from three or four different platforms. Nobody has time to map out 300 course titles—manually formatting metadata, aligning course IDs, and making sure it all appears where it should. There might be a “sync” button, but it rarely covers the long tail of training material your teams actually care about.

But there’s a way forward if you’re willing to put in some groundwork with the APIs. The main trick is knowing what endpoint gives you bulk control. Microsoft quietly exposes a Graph endpoint for learningProvider resources—a kind of gateway for pushing content packages at scale. The catch is that it expects a pretty tight data structure: the learningContent object needs unique IDs, titles, descriptions, linked resource URIs, expected durations, and more. Get the format wrong—even a field that’s an integer instead of a string—and your data lands with an error. “Unsupported media type” and “property mismatch” become familiar enemies. Worse, if you leave out required tags or author information, the API accepts the upload but flunks it in the background. You see success, but the content never appears in anyone’s feed.

Here’s a scenario that plays out in mid-sized orgs all the time. The training manager feels ambitious—she wants all 300 vendor onboarding modules in one searchable place. She pulls the export from the LMS: CSV with course names, links, and topics. With some scripting, she converts the CSV to JSON and starts posting in batches using the API. Everything looks fine for the first few uploads, but after the hundredth call, she starts getting what look like random failures. No error code that matches what’s in the documentation—just a generic “request limit exceeded” or a flat-out timeout. StackOverflow, of course, is no help. There’s no walkthrough for this edge case.

That’s where automation saves the day. You can tackle batch uploads with a straightforward PowerShell script. Start by importing your CSV—PowerShell’s Import-Csv cmdlet is more forgiving than Excel and doesn’t eat special characters. For each row, build a JSON object that hits the required fields: title, externalId, webUrl, thumbnail, completion criteria. Then, loop through the rows and call the Graph endpoint with an authenticated POST request for each content item. It’s important to pause every handful of uploads—use Start-Sleep or a throttling function—because hitting the endpoint too quickly almost always triggers a rate limit. As each post runs, check the HTTP status code and log both failed and successful entries. Flag entries with missing fields; PowerShell can kick back errors in real time and let you fix the CSV before retrying.

What really derails most migrations is data quality. An empty “description” field might not break a single upload—but it’ll guarantee the learning module falls to the bottom or simply never surfaces in searches. Typo in a URL? The content appears, but generates a 404 for end users. Mismatched completion settings? Good luck getting it assigned in a formal learning path. Inconsistent metadata slows everything down, forcing manual fixes that defeat the point of automation. I’ve seen teams upload half their catalog successfully, only to spend days debugging why the other half went dark—usually because of duplicate IDs or malformed URIs that weren’t caught in the first pass.

Error handling and logging make a world of difference. Instead of just running a batch and hoping for the best, set up your script to catch non-200 responses, output the exact error message, and tag every failed item with a line number from the source CSV. You’ll spot patterns right away—maybe every Italian language resource is missing a required tag, or all files from a specific vendor are over the allowed size limit. When the logging’s tight, fixing and re-uploading that set is painless.

Give it an afternoon, and you’ll go from a half-empty Learning catalog to a library where every employee at least has a fighting chance of finding the right resource, regardless of where it originated. Tagging, assigning, and surfacing third-party and homegrown content starts to feel realistic. When an onboarding manager auto-assigns a compliance pathway and it pops up in someone’s Teams feed—pulled straight from your external LMS—that’s automation actually working as promised.

Now, if you can automate something as finicky as learning content across different platforms, imagine the impact of doing the same for company-wide announcements. That’s the leverage you get with Viva Connections, and it’s where automation starts to directly shape your internal communications.

Automating Announcements: Programmatic Posts in Viva Connections Without the Headaches

If you’ve ever posted a news announcement in SharePoint and then played that waiting game for it to bubble up in Viva Connections, you know it can feel like shouting into the void. The announcement finally appears… days later, and by then half the team has missed it or moved on. Everyone’s seen these bottlenecks. Manual posts show up sporadically, vary in formatting, and if your comms team is busy with other channels, things go stale fast. The bigger the company, the more announcements pile up—events, new hires, policy changes, project launches. If you just rely on people remembering to log in, fudge with the right tags, and follow the right steps every time, the process falls apart.

So, what if you could automate it? I’m talking about programmatic posts that land at just the right moment, formatted exactly how you want, and push straight to the right audience. Not a nice-to-have gadget—actually making sure the information shows up where your people are working. But here’s where it gets tricky. Microsoft’s API documentation for Viva Connections posting looks clear on the surface: you craft some JSON, call the endpoint, and you’re done. But if you’ve tried this in practice, you already know that it’s not that smooth. Most people run their first test, paste in what looks like all the right properties, and get back an error that’s as cryptic as anything I’ve seen from M365 services. Sometimes nothing returns at all—just a failed post that vanishes from the audit logs too.

Let’s look at what goes sideways most often. Comm teams plug in their carefully written announcement, aim it at the API, and then—radio silence. No notifications, no cards in Teams, nothing on the Connections dashboard. They go searching through admin logs, only to find something vague like “Input payload invalid” or “Validation failed.” Most of these issues boil down to the structure of your JSON. Connections expects specifics: title, summary, author, exactly-formatted links, target audiences, and the sometimes-elusive engagement configuration that tells the system where and how to deliver the card. Leave just one field ill-defined—forget to encode the audience as an array, use a bad image URI, make the summary two characters too long—and the whole post is rejected. No gentle fallback, just an invisible error that’s only obvious in hindsight when leadership asks why nobody saw their quarterly update.

What actually works comes down to precision in your payload. Say you want to target the finance team, tag a policy update, and include a link that pops open in Teams mobile as well as desktop. The announcement JSON you need looks like a modest novel—sections for the card title, summary, “deep link” URIs, target email domains or Azure AD group IDs, expiration dates, and the delivery priority. Connections’ API expects camelCase, and anything you send that’s underspecified or has a mismatch—like “audience” as a string instead of an array—will trip it up. It’s easy to assume you only need the required fields you see in the UI, but the API side triple-checks for format, supported image sizes, and more.

I’ve seen a C# workflow that actually nails this, with the core structure built using strongly typed objects matching the API schema. The key is catching responses, not just sending requests. Wrap your HttpClient call in a try-catch, check the HTTP status codes, and log both success and failure returns. When you get a 400 Bad Request, the error body often contains a pointer—“Invalid audience format” or “Card expiryDate cannot be in the past”—you have to parse that and address it before resubmitting. And since API rate limits do kick in, especially if you’re doing posts alongside other automation, build in exponential backoff logic. If a request fails due to throttling, pause and try again, up to a safe maximum. There’s no silver bullet for massive pushes, but the goal is reliability. Each message must land, even if the system gets busy.

When you scale out to an entire company, this starts to matter a lot more. It’s not just about whether one post makes it through. If you’ve got a thousand users—maybe half on desktop, half on mobile, a few still going through the Outlook version of Connections—your automation needs to account for channel syncs and device lag. Sometimes a post needs to go out at 8am local time in five regions. Build logic that checks delivery status, maybe even queries read receipts if you care about compliance. It’s not all about the push—what matters is confirmation that the right people actually saw it.

You also can’t skate by on security. Automating posts means automated risk. If the system gets compromised or a rogue script goes public, there’s a chance confidential information could go wider than you want. The answer is least-privilege permissions in Azure: tie your automation to a dedicated, locked-down service principal, limit its scope so only certain channels or audiences can be targeted, and audit API calls so you can roll back anything rogue. For extra protection, consider approval workflows for high-impact posts—an automated card only goes live once reviewed.

When you see this put into practice, it changes the feel of your Connections. The dashboard isn’t stale or random anymore—it becomes a live, up-to-date feed that people actually notice and respond to. Announcements connect directly with their audience, without waiting for someone to click “Publish” in a SharePoint site. If the API call fails, your script flags it, retries, sends a Teams alert, or even triggers an approval workflow if needed. The result is a streamlined communication setup—automated, precise, and reliably on target.

That’s automation working as it should. Now, with Topics, Learning, and Connections all running smoother and more visible—what could be next for your Viva deployment? The landscape looks completely different when manual work steps out of the equation.

Conclusion

If you’ve spent years working around the defaults, it’s a shock to see what opens up when you plug into Viva’s APIs. Manual entry and missed connections aren’t inevitable—or even normal—when the right automation is in place. Whether it’s surfacing learning content, making company knowledge actually show up, or pushing out targeted news, the difference is real. If you spotted even one idea you want to try, stay tuned. Share your own war stories or successes below—the more real-world examples, the better this community gets. Automation isn’t a trend. It’s the baseline for anyone building a modern M365 environment.

Discussion about this episode

User's avatar