The process of building custom applications and tools that interact with Microsoft SharePoint, including SharePoint Online in Microsoft 365.
Hi @Titus Tolbert (Sr. Dev Operation, Hoka corp)
For high-volume uploads, the recommended pattern is to treat the SharePoint webhook as a lightweight notification trigger, not as the place where all processing should happen.
SharePoint webhook notifications only tell your application that something changed in the list or document library. They do not include the exact item-level change details, so your application still needs to call GetChanges() to determine what changed. Microsoft’s webhook reference implementation specifically uses an asynchronous pattern where the webhook receiver stores the notification in a queue, and a background worker later reads the queue, retrieves the last persisted change token, calls GetChanges(), processes the changes, and then persists the latest change token.
So yes, you should implement a queue-based architecture.
A good pattern would be:
- HTTP-triggered Azure Function receives the webhook notification
- Validate the notification if needed.
- Do not call
GetChanges()directly inside this function.- Immediately enqueue the notification and return HTTP 200 quickly.
- Use Azure Storage Queue or Azure Service Bus. - Maintain one persisted change token per list or library. - Call `GetChanges()` from the last stored token. - Process all returned changes. - Store the newest change token only after successful processing.
- Do not call
- Validate the notification if needed.
- Throttle the worker, not the webhook receiver
- Limit concurrent workers per site/list/library.
- Avoid multiple workers calling
GetChanges()for the same library at the same time.- Coalesce duplicate notifications where possible, because SharePoint may batch multiple changes into a single webhook callout during the same period. Microsoft notes that this batching is expected and helps avoid one call per changed item during bulk uploads.
- Honor SharePoint throttling responses
- When SharePoint returns HTTP 429 or 503, check the
Retry-Afterheader and wait for that duration before retrying.- Do not retry immediately, because Microsoft guidance states that throttled requests still count toward usage limits, and ignoring
Retry-Aftercan result in more throttling.
- Do not retry immediately, because Microsoft guidance states that throttled requests still count toward usage limits, and ignoring
- Use incremental polling through change tokens
- Avoid repeatedly scanning the whole library.
- Persist the last successful
changeTokenand pass it into the nextGetChanges()call so you only request changes since the last processed point. Microsoft’s webhook reference implementation calls this out as important to avoid receiving the same changes repeatedly.
- Persist the last successful
Regarding Azure Event Grid vs Service Bus:
- Service Bus is usually the better fit if you need reliable buffering, retry handling, ordering/session control, dead-letter handling, and controlled worker concurrency.
- Azure Storage Queue is also acceptable for a simpler implementation and is used in Microsoft’s webhook reference implementation.
- Event Grid can be useful for event routing, but it does not by itself solve the
GetChanges()throttling problem. You still need a worker that respectsRetry-After, limits concurrency, and persists change tokens.
Please refer:
SharePoint webhooks sample reference implementation
Avoid getting throttled or blocked in SharePoint Online
I hope this information help.
If the answer is helpful, please click "Yes" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.