Skip to content

Throttling

Microsoft Graph and SharePoint both throttle with HTTP 429 and a Retry-After header; Graph also reports how close an app is to its limit. The library reads these signals, retries with the server's delay (falling back to exponential backoff with jitter) and can pace a whole fleet proactively.

Unlike SharePoint's static service limits, Graph throttling is dynamic — evaluated per scope (per app, per tenant, per app + tenant, per resource) and per request type — so the library reacts to the signals rather than enforcing a fixed budget. The quotas below are declared on the Graph resource classes with @limit(...) (reference-only) and shown in the Bound at column.

Signals

Header Direction Meaning
Retry-After response Seconds to wait before retrying a 429/503
x-ms-throttle-limit-percentage response Share of the limit consumed (0.8–1.8); >= 1.0 means throttling
x-ms-resource-unit response The cost of this request (Identity resource units)
x-ms-throttle-scope response The throttled scope (<Scope>/<Limit>/<AppId>/<TenantId...>)
x-ms-throttle-information response Why (CPULimitExceeded, WriteLimitExceeded, ...)
x-ms-throttle-priority request low / normal / high — low is throttled first

What the library does

result = client.users.top(10).get().execute_query_retry()   # honor Retry-After + backoff
client.execute_batch(concurrency=5)                         # retries throttled sub-requests

client.with_rate_limit()          # pace a fleet from the signals (proactive)
client.with_throttle_priority("low")     # mark background work low priority

client.with_rate_limit() reads every response (including batch sub-responses) and gates the group on Retry-After, Graph's x-ms-throttle-limit-percentage and SharePoint's health score. See office365.runtime.http.throttling and office365.runtime.retry.

Best practices to avoid throttling

  • Prefer delta queries and change notifications over polling/scanning.
  • Batch related operations (JSON batching) and reduce operations per request.
  • Don't retry immediately — honor Retry-After (the fastest recovery).
  • For bulk extraction, use Microsoft Graph Data Connect (not throttled).

Quotas (reference)

The numbers below are the tested limits Graph enforces; the first one reached triggers throttling. They're declared on the model (@limit) — see the Bound at column.

Service Limit Scope Type Bound at
call records 15,000 requests / 20s app any CallRecord
call records 10,000 requests / 20s tenant any CallRecord
call records 1,500 requests / 20s app+tenant any CallRecord
call records 40 requests / 20s resource any CallRecord
cloud communications 50,000 requests / 15s app+tenant any Call
cloud communications 10,000 requests / 30s app+tenant any Presence
cloud communications 750 requests / 30s app read VirtualEvent
cloud communications 15 requests / 30s app write VirtualEvent
excel 5,000 requests / 10s app any Workbook
excel 1,500 requests / 10s app+tenant any Workbook
identity 150,000 resource_units / 20s app any DirectoryObject, SubscribedSku, Domain
identity 35,000 requests / 300s app write DirectoryObject, SubscribedSku, Domain
identity 18,000 requests / 300s tenant write DirectoryObject, SubscribedSku, Domain
identity 3,500 resource_units / 10s app+tenant any DirectoryObject, SubscribedSku, Domain
identity 3,000 requests / 150s app+tenant write DirectoryObject, SubscribedSku, Domain