Hello everyone and welcome to another episode of Microsoft Knowledge Nuggets here on M365.
FM, I'm your host, Mirko Peters.
Today's topic is one that almost everyone building with Microsoft 365 has heard of,
but very few people can explain clearly what exactly are graph webhooks.
Why should you care about them instead of doing things the old way?
Imagine you're expecting an important letter.
You walk to your mailbox. It's empty.
You walk back. 10 minutes later, you check again.
Still nothing. You do this all day wasting time and energy.
That's polling.
Now imagine a different world.
The mailman rings your doorbell the moment a letter arrives.
You don't check. You wait for the ring. That's a webhook.
By the end of this episode, you'll understand what graph webhooks are.
Why they replace constant checking and how the pieces fit together.
The polling problem. Let's break this down.
To understand why webhooks matter, you need to understand why polling hurts.
Here's how most applications work today.
Your app needs an answer.
It asks Microsoft Graph, "Hey, any new users?"
Graph responds, "Nope."
So your app waits a bit then asks again.
Any new users now?
Still no. Over and over. This process is polling.
Think of it like constantly calling a friend to ask if they have news.
You dial, they pick up, you check, they say no, you hang up.
Then you call again five minutes later.
And again, you're burning their time and your own.
You're probably annoying them.
Now imagine thousands of apps doing this to Microsoft Graph at the same time.
Every app polling every few minutes, asking the same questions,
getting the same answers. That's a lot of noise.
Microsoft has a name for when you poll too aggressively,
throttling, or as some developers call it, "graph jail."
When you send too many requests, Microsoft says,
"Okay, you're done for a while."
They limit how many calls your app makes,
once your throttleed everything slows down.
The legitimate request pile up, your app stops working properly.
You have no idea when you'll be let out.
How many requests are we talking about?
Say your app pulls every five minutes for user changes.
That works out to 12 requests per hour.
Over a full day, that's 208 requests.
And that's just for one resource.
If you're also polling for groups, files, messages, and calendar events,
you rack up thousands of unnecessary requests per day.
Most of them return nothing.
Zero changes, but you still made the call.
And here's the thing, even if you poll every five minutes,
you're still not getting real-time updates.
A change could happen one minute after your last poll.
You won't know about it for another four minutes.
You're wasting resources and still missing the window.
Now, contrast that with an event-driven approach.
Instead of calling Microsoft Graph every few minutes,
you wait for Microsoft Graph to call you.
You set up a listener, when something changes,
Graph sends you a notification.
You don't dial. You pick up when the phone rings.
What are web hooks?
So what exactly is a web hook?
Here's the simplest definition.
A web hook is an HTTP request sent automatically when something happens.
You don't ask for it.
The server just pushes it to you.
Think of it like a doorbell.
You don't stand outside checking every few minutes.
You install a doorbell.
When someone arrives, they ring it.
You hear the ring and answer.
The doorbell does the watching for you.
Web hooks are sometimes called reverse APIs.
With a normal API, your app makes a request and the server responds.
Your app is in control.
With a web hook, the server sends the request to your app.
The server is in control.
It pushes data instead of waiting for you to ask.
Now Microsoft Graph uses web hooks too,
but Microsoft calls them change notifications.
It's the same thing, just a different name.
When something changes in Microsoft 365,
Graph sends an HTTP post to a URL you provide.
That post contains information about what changed.
There are a lot of things you can get notified about.
A new user created in your tenant, a file updated in SharePoint,
a message sent in Teams, a calendar event that changes,
or a group that gets a new member.
All of these can trigger a notification.
Here's a real example, say you run a company with a time tracking system.
When a new employee joins, you want to create an account automatically.
Without web hooks, you pull the user's endpoint every few minutes checking for new people.
With web hooks, you subscribe to user creation events.
When someone joins, Graph sends your app a notification.
Your app receives it, validates it, and creates the account.
Or within seconds, no polling, no wasted requests.
Another example, you have a SharePoint document library where receipts get uploaded.
Without web hooks, you pull the library constantly.
With web hooks, Graph tells you the moment a file is added.
Your app grabs it, checks if it's a receipt, and processes it automatically.
That's the power of web hooks.
Instead of your app constantly asking anything new,
you let the system tell you when something happens.
It's more efficient, more reliable, and much faster.
How Microsoft Graph Webhooks work.
Now you know what web hooks are and why polling is the problem.
Let's look at how Microsoft Graph Webhooks actually work,
because the flow is simpler than you might think.
It comes down to three things, a subscription, a notification, and your end point.
First, you create a subscription, you tell Microsoft Graph,
"Hey, I want to know when this specific thing changes."
You give Graph the details of what to watch and where to send the news.
Think of it like signing up for an alert.
You tell the system what you care about and you give it your contact info.
Second, Microsoft Graph watches that resource.
It monitors for changes.
When something happens, like a user created, a file updated, or a message arrives,
Graph notices.
Third, Graph sends a notification.
It files off an HTTP post to the URL you provided.
That post contains information about what changed.
Your end point receives it and your application processes it.
So the high level flow is simple.
You subscribe.
Graph watches.
Graph sends a post when something changes.
Let's break down those three building blocks a bit more.
The subscription is your request to be alerted.
It's like saying, "I want to know whenever a new user is added to my tenant."
You send that request to Microsoft Graph and Graph stores it.
From that point on, Graph is watching on your behalf.
The notification is the alert itself, an HTTP post that Graph sends to your endpoint.
The post body contains details about the change, like what resource changed, what type of change
happened, and when it happened.
Your endpoint is the door you leave open.
It's a URL on your server, configured to receive these post requests.
It just needs to listen and respond fast.
That's it.
No complex logic required at the receiving end.
Just catch the notification, acknowledge it, and process it.
Now compare this to polling.
With polling, your app sends hundreds of get requests, each asking anything new.
Most of the time the answer is no.
With webhooks, there's just one post.
The notification.
That's it.
One message instead of hundreds.
The efficiency difference is enormous, and your endpoint doesn't need to be complicated.
It just needs to be publicly accessible, speak HTTPS, and respond quickly.
We'll talk about what quickly means in a bit.
But the core idea is simple.
Your endpoint listens, Graph calls, you respond, and done.
Creating a subscription.
So how do you actually set one of these up?
Let's walk through creating a subscription step by step.
You start by sending an HTTP post request to a specific URL on Microsoft Graph.
That URL is HTTPS, Graph.
Microsoft.com v1.0, subscriptions.
You're posting straight to the subscriptions endpoint.
Inside that request body, you include the details of what you want to subscribe to.
There are four key fields you need to provide.
First is notification URL.
This is your endpoint's URL.
The place where Microsoft Graph will send the notifications.
It has to be HTTPS and it has to be publicly accessible because Graph needs to reach it
from the internet.
Second is resource.
This tells Graph what you want to watch.
You specify the Microsoft Graph resource path.
For example, users if you want to watch for user changes or me, male folders, inbox messages
if you want to watch for new emails in your inbox.
The resource tells Graph exactly what you care about.
Third is change type.
This tells Graph what kind of changes to notify you about.
You can specify created, updated, deleted, or any combination.
So if you only care about new users being created, you set change type to create it.
If you care about updates too, you set it to create it, updated.
Fourth is expiration date time.
This is when the subscription expires because subscriptions don't last forever.
You set a date and time and Graph stops sending notifications after that point.
The maximum duration depends on the resource you're watching.
For users and groups, the max is about three days.
For drive items in SharePoint or OneDrive, it can be up to 30 days.
You need to check the documentation for each resource type.
There's also an optional field worth mentioning.
Client state.
This is a secret string you create.
It can be anything you want.
A random string, a good, whatever you choose.
Microsoft Graph includes this value in every notification it sends to your endpoint.
And you use it to verify that the notification actually came from your subscription.
If someone tries to send fake notifications to your endpoint, the client state won't match
and you can reject it immediately.
It's a simple security measure, but it's important.
Creating a subscription is like signing up for a newspaper delivery.
You give the newspaper your address.
That's your notification URL.
You tell them what sections you want, that's your resource and change type, and you tell
them how long you want the delivery to continue.
That's your expiration date time.
The newspaper handles the rest.
But here's the thing, subscriptions expire.
You can't create one and forget about it.
After the expiration date time passes, Graph stops sending notifications and your subscription
is gone.
If you want to keep receiving notifications, you need to renew the subscription before it
expires by sending a patch request to the subscription endpoint with a new expiration
date time.
So creating a subscription is the first step, but it's not the last.
You need to manage the life cycle.
We'll talk more about that later.
The validation handshake.
Before your subscription goes live, there's one step you can't skip.
Microsoft Graph doesn't just accept your subscription request and start sending notifications.
It first needs to confirm your endpoint is real and ready to receive them.
Here's how it works.
When you send your post request to create a subscription, Microsoft Graph immediately fires
off a test post to your notification URL.
That test post includes a query parameter called validation token.
It's just a random string.
Your endpoint needs to grab that token and send it back as a plain text response and you
have to do it within 10 seconds.
Think of it like a courier delivering a package.
They show up at your door and ask, is this the right address?
Can you confirm?
You have to sign for it.
If you don't, they walk away.
The courier doesn't leave the package.
They just leave.
But that's exactly what's happening here.
Microsoft Graph is saying, I'm about to send you important notifications.
Prove you're the right person at the right address.
Your endpoint responds by echoing back the validation token, which tells Graph, yes,
I'm here.
I'm listening.
Send me the notifications.
Now here's where a lot of developers trip up.
The validation token must be returned as plain text, not JSON, not HTML, plain text.
And the response must have a content type header set to text plain.
If you send it back wrapped in JSON or encoded in anyway, the validation fails.
Your subscription won't be created.
Microsoft Graph returns an error and you're stuck wondering what went wrong.
There's another technical detail worth knowing.
Microsoft Graph's validation service doesn't reliably support TLS 1.3.
It negotiates TLS 1.2.
So if your endpoint only accepts TLS 1.3 connections, the validation handshake fails before your
application code even runs.
You need to make sure your endpoint supports TLS 1.2, at least for the validation step.
After that, you can enforce whatever TLS version you want for the actual notifications.
The good news is this validation handshake only happens once per subscription.
It's not something your endpoint has to handle every time a notification arrives, just the
first time.
Once Graph confirms your endpoint is real, it trusts it for the life of that subscription.
So you only need to get this right once.
Handling notifications and security.
Once the validation handshake goes through and your subscription goes live, Microsoft Graph
starts sending those notifications.
So what do those actually look like in practice?
When something changes, Graph sends an HTTP post to your endpoint with a JSON object in
the body.
That object contains the resource that changed the type of change that created, updated,
or deleted, and a timestamp.
It also includes the client state value you set when you created the subscription.
That's your secret string your way of knowing the message is real.
So here's the first thing to do when a notification arrives.
Validate that client state.
Compare the value in the notification against the secret you stored when you created the
subscription.
If they don't match, discard it immediately.
Because it could be a fake.
Someone trying to trick your system into processing bad data.
This matters because your endpoint lives on the public internet.
Anyone who knows your URL could send a post to it.
Without client state validation, you'd have no way to tell the difference between a real
Microsoft Graph notification and a fake one.
It's a simple check, but it's your first line of defense.
Once you've confirmed the notification is legit, you need to respond fast.
Microsoft Graph expects a 200 level HTTP response within three seconds.
If you take longer graph notices, and if it happens too often, graph starts treating you
differently.
Here's how the throttling works.
If more than 10% of your responses exceed the three second window in any 10 minute period,
Microsoft Graph marks your endpoint as slow.
When that happens, new notifications get delayed by 10 minutes.
They still arrive eventually, but you lose real time delivery.
If things get worse, with more than 15% of your responses exceeding 10 seconds, graph marks
your endpoint as drop.
In that state, notifications are dropped entirely for 10 minutes.
Here's the scary part.
Drop notifications cannot be recovered.
They're gone, and you'll never get them back.
Think of it like a busy phone line.
If you don't pick up quickly, the caller tries again later.
But if you never pick up, eventually the caller gives up.
Microsoft Graph is the caller, and your endpoint is the phone.
You can't pick up fast or risk losing the message.
So what's the best practice here?
Acknowledge immediately and process asynchronously.
Your endpoint should validate the client state, accept the notification, and return it 200 or
202 responses as fast as possible.
Then push the notification into a queue for background processing.
And Azure queue, a service bus, even a simple database table.
The point is to get out of the response cycle quickly and let your background workers handle
the heavy lifting.
And one more security reminder, your endpoint must be HTTPS.
No exceptions, Microsoft Graph will not send notifications to an HTTP endpoint.
And your endpoint must be publicly accessible if it's behind a firewall or a VPN Graph
can't reach it.
For development, you can use tools like en-groc to create a public tunnel to your local
machine.
But in production, your endpoint needs to live somewhere, Graph can find it.
Keeping notifications alive, life cycle.
So you've got your subscription setup, notifications are flowing, and everything looks good.
But here's something that catches a lot of people off guard.
Your subscription has an expiration date.
It doesn't last forever, depending on what resource you're watching.
The maximum subscription duration is usually between three and seven days.
For some resources like drive items and SharePoint, you can get up to 30 days.
But the point is, it's not permanent.
You cannot create a subscription and forget about it.
Think of it like a magazine subscription.
You sign up, you start receiving issues and everything's great.
But if you don't renew before the subscription runs out, the issue stops coming.
Same thing here.
If your subscription expires, Microsoft Graph stops sending notifications.
And you might not realize it until you wonder why nothing's happening.
So you need a renewal strategy, the way you renew is simple.
Send a patch request to the subscription endpoint using the subscription ID and update the
expiration date time to a new future date.
That extends the life of the subscription.
You can do this as many times as you want, as long as you do it before the current expiration
passes.
Now, Microsoft Graph actually helps you hear with something called life cycle notifications.
When you create a subscription, you can provide a separate URL called the life cycle notification
URL.
Microsoft Graph sends alerts to that URL when certain things happen.
Like when your subscription is about to expire, when your access token is about to run out,
or when the permissions on your app change.
These life cycle notifications give you a heads up.
You don't have to guess when your subscription is going to die.
Graph tells you, hey, your subscription expires in a few hours.
You might want to renew.
It's like getting a reminder from your magazine publisher that your subscription is about
to end.
Very helpful if you're paying attention.
But what happens if things go wrong anyway?
Maybe your endpoint goes down for a while or notifications get dropped because you were too
slow.
What then?
That's where Delta query comes in.
Delta query is a separate feature of Microsoft Graph that lets you ask, what changed since the
last time I checked?
And it returns only the changes, nothing else.
Here's how it works.
The first time you run a Delta query on a resource, say, users, graph returns all the users
in your tenant.
But it also returns something extra, a special link called a Delta link.
You save that link.
The next time you run the same query, you use that Delta link.
And instead of getting all users again, you get only the ones that changed since your last
request.
New users, updated users, deleted users.
That's it.
Think of it like reading a what's new list instead of reading the entire encyclopedia every
time, much faster, much less data.
Now here's the smart pattern.
Combine web hooks with Delta query.
Use web hooks to tell you when something changed.
Then use Delta query to find out exactly what changed.
Let me explain why that matters.
Web hooks are fast, but they're not perfect.
Notifications can get lost.
Subscriptions can expire and your endpoint can go down.
But Delta query is reliable.
You can run it any time.
And it gives you a complete list of changes since your last check.
So even if you miss a notification, you can catch up.
And here's the typical flow.
Set up a web hook subscription for user changes.
Run an initial Delta query to get the baseline state and save the Delta link.
When a web hook arrives telling you a user changed, run a Delta query using your saved
Delta link.
That gives you the exact change.
Process it.
Then save the new Delta link from that response.
Next time a web hook comes in, repeat the process.
And if you ever miss a notification or if your subscription expires, just run the Delta
query again.
You'll get everything you missed.
It's a safety net.
Web hooks give you speed and Delta query gives you reliability.
Together, they're a powerful combination.
Real world example and next steps.
Imagine a new employee joins your company tomorrow.
Someone in HR creates their account in Microsoft Entra ID and that single action kicks off
a chain reaction.
If you've set up a web hook subscription for user changes, Microsoft Graph notices instantly
and fires a post to your endpoint.
Here's what happens next.
Your endpoint receives the notification, validates the client state, and if it matches your secret,
you know it's legit.
To return a 202 accepted response within three seconds, acknowledging the notification,
and then your background worker picks it up.
The worker Caesar user was created, but the notification doesn't include all the details,
so it runs a Delta query using your saved Delta link.
That returns the new user's full information, name, email, department, job title, manager,
everything you need.
Now your worker takes that information and creates an account for the new employee in
your third party time tracking system.
It sends a welcome email.
It adds them to the appropriate distribution lists.
All of this happens within seconds of HR creating the account in Entra ID, no polling,
no manual steps, no delays.
Think about the alternative.
Without web hooks, you'd have to poll the user's endpoint every few minutes, hundreds of requests
per day, and even then you might not catch the new user for several minutes.
With web hooks, it's instant.
One notification, one Delta query done.
That's the real value.
Your system becomes faster, more efficient, and less likely to hit throttling limits.
Instead of constantly asking Graph for updates, you let Graph tell you when something happens.
It's a fundamental shift in how you build integrations.
So here's what I want you to try.
Think about one process you're currently polling for.
Maybe you're checking for new emails in a shared mailbox.
Maybe you're watching for file changes in a SharePoint library.
Maybe your monitoring user updates for your HR system could a web hook replace that polling?
In most cases, the answer is yes.
And you don't need to build everything from scratch.
Tools like Azure Functions can host your web hook endpoint with minimal code.
Power Automate can handle subscriptions and notifications without writing a single line.
Even logic apps can process web hook payloads.
The infrastructure is there.
You just need to use it.
So here's the core idea in plain English.
Stop polling.
Start listening.
Web hooks let you move from constantly asking Microsoft Graph for updates to getting notified
instantly when something changes.
That shift transforms your system from one that wastes, calls, and risks throttling to one
that's fast, efficient, and reliable.
Instead of thousands of unnecessary requests per day, you get one notification per change.
Instead of waiting minutes to find out about an update, you know, within seconds.
Instead of worrying about hitting GraphJail, you work within the system the way it was designed.
So if you're building integrations with Microsoft 365, web hooks are the smarter path.
They make your system faster.
They make it less likely to be throttled.
And they give you real time awareness of what's happening in your tenant.
That's it for this episode of Microsoft Knowledge Nuggets.
Subscribe on your favorite podcast platform and share this with someone starting their journey
with Microsoft Graph.
I'm Mirko Peters.