Why polling OneDrive fails for Teams transcripts

Sales calls live in Teams; CRM needs the transcripts. Polling OneDrive looks simple and breaks in production — here is the event-driven path that holds up.

Context: Anonymized production engagement · domain: GTM / meetings

The problem

Sales calls are recorded in Microsoft Teams. After the call, the business needs a usable transcript — or at least a reliable pointer to one — so notes can land in the CRM without someone rewatching the recording.

The naive framing is a file problem: “transcripts appear somewhere in OneDrive or SharePoint; find new files and process them.” That framing is almost true, and almost true is where automation goes to die.

I was mapping a production path from meeting → transcript → CRM note. The RevOps lead wanted fewer manual write-ups. IT wanted something that would not burn API quota or leave silent gaps when a folder layout changed. Both were right.

What people usually try

Most first drafts look like this:

  1. Pick a folder (or a set of folders) where Teams / the transcript pipeline is believed to drop files.
  2. Schedule a flow every few minutes — often every five — that lists children, filters by name or modified time, and processes anything “new.”
  3. Write a processed flag somewhere (filename rename, a side table, a tag) so the same file is not summarized twice.
  4. Hope the folder structure stays stable.

On a quiet demo day this can look fine. In production it accumulates failure modes that are boring and expensive:

  • Quota burn. List-files on a schedule is chatty. You pay for empty polls, retries, and every path that re-walks the same tree when someone reorganizes sites.
  • Missed files. A file that appears and is moved, or that lands under a path the filter does not cover, never enters the pipeline. The schedule keeps succeeding; the business still has gaps.
  • Duplicate processing. Clock skew, partial writes, “modified” timestamps that change when metadata is touched, and two workers racing the same list all create double notes or half-updated records.
  • Silent structural drift. Teams and SharePoint layouts are not your product. When IT renames a library, changes retention, or adjusts how recordings are stored, the poll keeps green and the feed goes empty.

Polling is not wrong because it is old. It is wrong because it turns a *change* problem into a *scan* problem, and scanning is a bad model for sparse, high-value events.

What we implemented instead

We treated transcript availability as an event, not a folder to babysit.

At a high level:

  • Subscribe to Microsoft Graph change notifications (webhooks) on the transcript source the tenant already uses — the resource that represents “something new appeared here,” not a custom crawl of every library.
  • On notification, resolve the item, confirm it is a transcript (or a recording we still need to request a transcript for), and hand a stable item identity into the processing workflow.
  • Keep subscription lifecycle explicit: create, renew before expiry, alert when renewal fails. Graph subscriptions are not fire-and-forget.
  • Process with idempotency keys derived from the item identity (and, where useful, a content version), so a redelivery does not create a second CRM note.
  • Push a structured handoff into the CRM path only after the transcript is ready enough to summarize — not on the first partial notification.

No tenant IDs, workflow IDs, or portal IDs belong in a public note. The design point is simple: react to change; do not invent change by scanning.

That does not remove all complexity. You still need auth scopes that match least privilege, a secure notification endpoint, validation of Graph’s handshake, and a clear path for backfill when a subscription was down. Backfill is a deliberate catch-up job, not the primary loop.

What broke / what we learned

The honest failure mode that bit us was not “webhooks are magic.” It was subscription expiry.

Graph change subscriptions expire. If you do not renew them on a schedule with monitoring, notifications stop. The rest of the system can look healthy: the CRM workflow still runs when triggered; dashboards that only count successful runs stay green; sales still has meetings. What you lose is the signal that a new transcript exists.

We learned to treat subscription keep-alive as a first-class production concern — same class as secret rotation or queue depth — not as a one-time setup checkbox. Renewal jobs need their own alerts. A silent stop is worse than a loud failure, because nobody opens a ticket for “nothing happened.”

A second, related lesson: notification delivery is at-least-once in spirit. Design for duplicates from day one. If your “process transcript” step is not idempotent, the first retry storm will invent extra CRM activity and erode trust with the people who live in that CRM.

Takeaway for operators

  • Do not poll OneDrive/SharePoint for Teams transcripts as your primary path. You will burn quota, miss edge cases, and go blind when folder structure drifts.
  • Prefer Graph change notifications with explicit subscription renewal and alerting. The event is the unit of work; scanning is for recovery.
  • Make processing idempotent on a stable item identity. Webhooks and retries will redeliver; your CRM should not invent a second note.

---

*Dealing with this in production? The AI Systems Diagnostic is the starting point.*