Setup & Authentication
API Authentication
Setup
Before being able to utilise the CIPP API, you need to first configure an API client via CIPP-API & MCP. Once that is completed, come back to this page. You'll need the integration page still open to reference the necessary fields below for authentication.
Authentication
CIPP uses OAuth authentication to be able to connect to the API using your Application ID and Secret. You can use the PowerShell example below to connect to the API:
$CIPPAPIUrl = "https://yourcippurl.com"
$ApplicationId = "your application ID"
$ApplicationSecret = "your application secret"
$TenantId = "your tenant id"
$AuthBody = @{
client_id = $ApplicationId
client_secret = $ApplicationSecret
scope = "api://$($ApplicationId)/.default"
grant_type = 'client_credentials'
}
$token = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$TenantId/oauth2/v2.0/token" -Method POST -Body $AuthBody
$AuthHeader = @{ Authorization = "Bearer $($token.access_token)" }
Invoke-RestMethod -Uri "$CIPPAPIUrl/api/ListLogs" -Method GET -Headers $AuthHeader -ContentType "application/json"
Rate Limits and Performance
Two limits apply to every call you make:
Timeout — a single API action can run for up to 10 minutes.
Rate limit — 100 requests per 10 second window, per API client.
Both exist for the same reason. Your API calls run on the same backend that serves the CIPP interface, so no single caller should be able to tie up the workers your technicians depend on.
The rate limit behaves like this:
The window is fixed, not rolling. Your allowance resets every 10 seconds rather than trickling back as individual requests age out, so the longest you ever wait after being throttled is the remainder of the current window.
Each API client gets its own budget. A busy integration won't eat into the allowance of your other clients, or of the people working in the portal. Anything that runs hot is worth giving its own API client rather than sharing one across every automation.
Everything counts — reads and writes, on every endpoint.
Requests over the limit are refused, not queued. You get
HTTP 429 Too Many Requestsback immediately, with aRetry-Afterheader telling you how many seconds to wait. Honour it and you'll land in a fresh window on the next attempt — most HTTP clients and SDKs can be configured to do this for you.
100 requests per 10 seconds works out to 10 per second sustained, which most integrations never approach. If yours does, it's nearly always a sign the same work can be done in far fewer calls. The three techniques below are how.
Read from the reporting database
Many list endpoints accept UseReportDB=true:
Instead of calling Microsoft live, CIPP hands back data it has already collected and stored. It's dramatically quicker, it doesn't spend the tenant's Microsoft API quota, and it doesn't queue up behind whatever the portal is doing.
The trade-off is freshness. CIPP refreshes this data automatically once a day, overnight, so it can be up to 24 hours old. That's ideal for inventory, reporting, dashboards and billing reconciliation. Use a normal live call when you need to see a change that was just made.
Endpoints that support UseReportDB today:
Identity
ListGroups, ListMFAUsers
Email & Exchange
ListMailboxes, ListMailboxPermissions, ListMailboxRules, ListMailboxForwarding, ListCalendarPermissions, ListSharedMailboxAccountEnabled, ListHVEAccounts
Endpoint
ListApps, ListIntunePolicy, ListCompliancePolicies, ListAppProtectionPolicies, ListAssignmentFilters, ListIntuneScript, ListIntuneReusableSettings, ListCVEManagement
Teams & SharePoint
ListTeams, ListTeamsActivity, ListTeamsVoice, ListSites
Security & Tenant
ListMDEOnboarding, ListOAuthApps
Ask for every tenant in one call
Pass tenantFilter=AllTenants and you get a single response covering your whole estate, with every row tagged with the tenant it came from:
For an MSP with 300 tenants, that's one request instead of three hundred — and comfortably inside your rate limit rather than five minutes of careful pacing.
Batch your Graph reads
When you need live data that CIPP doesn't have a purpose-built endpoint for, POST /api/ListGraphBulkRequest lets you send many Microsoft Graph reads as one call:
Each result comes back labelled with the id you gave it. Only GET requests are batched.
Rules of thumb
Fetch a whole list once and filter it on your side, rather than calling CIPP once per user, device or mailbox.
Cache results in your own tooling. An automation polling every 15 minutes against data that only refreshes daily is making 96 identical calls a day.
Schedule large syncs outside your working hours.
Treat
429as a normal operating condition rather than an error. Wait for theRetry-Afterperiod and carry on.
Response Compression
CIPP compresses /api responses on the fly — Brotli preferred, gzip as a fallback — whenever your client says which encodings it accepts. Text-heavy responses are often 5–10× smaller on the wire: a user or group list that runs to tens of KB of JSON typically arrives in a few KB. That's faster for you to receive and lighter on the shared backend, so it's worth making sure your client asks for it.
There's nothing to enable on the server. It's negotiated per request from the Accept-Encoding header you send:
Most HTTP clients and SDKs do this automatically. Anything built on a modern HTTP stack — including
Invoke-RestMethodin PowerShell 7 and the CIPP API PowerShell module — advertisesAccept-Encodingand transparently decompresses the reply. You still get plain JSON back; there are just fewer bytes on the wire.If you call the API directly, send the header yourself:
With
curl,--compresseddoes both at once — it sends the header and decompresses the response.A client that advertises nothing is served uncompressed. That still works; it just costs you the full payload on every call.
Daily Egress Budget
Hosted CIPP instances may apply a daily egress budget — a ceiling on the total volume of API response data served to app-only clients across the whole instance in a UTC day. It's a bandwidth safeguard that complements the rate limit: a caller can move a large amount of data with slow, big requests while sitting comfortably under 100 requests per 10 seconds, and this keeps that in check. It applies only to app-only API clients — people working in the CIPP portal are never counted and never affected.
When a budget is in force and the instance has served its allowance for the day, further app-only API requests are refused:
You get
HTTP 429 Too Many Requestsback immediately.A
Retry-Afterheader — and aresetUtcfield in the response body — tell you when the budget resets, which is the next UTC midnight.The response body identifies the reason:
Two habits keep you comfortably inside a budget, and they're the same ones that keep you under the rate limit:
Advertise
Accept-Encodingso your responses are compressed. The budget counts the bytes actually sent over the wire, so a client that receives compressed responses spends its allowance many times more slowly than one taking identity.Ask for more data in fewer, leaner calls — the report database,
AllTenants, and bulk Graph patterns above all reduce the volume you pull for the same result.
Endpoint documentation
EndpointsCIPP API PowerShell Module
You can install the CIPP API PowerShell module using PowerShell 7.x. The module takes care of all the authentication for you.
You will first need to set your CIPP API Details using the following command:
You can then test its working
Further documentation for the module and each of its available functions can be found here.
Common Issues
If you are calling CIPP from an external automation platform (e.g., n8n, Rewst, Power Automate), make sure your base URL includes the
/apipath (e.g.,https://your-cipp-domain.com/api). Direct API calls need to target the Azure Functions backend, not the static frontend — without/api, your requests will hit the web interface and return HTML instead of the expected JSON responsesIf you receive 400 (Bad Request) errors when first authenticating or testing your CIPP API connection (e.g.
Invoke-CIPPRestMethod: Response status code does not indicate success: 400 (Bad Request)) your CIPP API app registration may be missing an Application ID URI.To fix this, go to Microsoft Entra ID → App registrations in your tenant and open the app registration for your CIPP API (not a separate client registration, unless your setup uses one). Navigate to Expose an API. If the Application ID URI field at the top is empty, click Add. Azure will auto-suggest a URI in the format
api://{application-id}. The default is fine, no need to customise it. Click Save.If your setup requires a custom scope (e.g.,
access_as_user), you may also need to add one under Expose an API → Add a scope and then grant that scope as an API permission on the client side.After making changes, wait a minute or two before retrying authentication since propagation isn't always instant. If the error persists, try re-consenting to the app permissions.
Feature Requests / Ideas
We value your feedback and ideas. Please raise any feature requests on GitHub.
Last updated
Was this helpful?

