Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Important
APIs under the /beta version are subject to change. Use of these APIs in production applications is not supported.
The Microsoft 365 Copilot Cost Management API helps administrators govern and observe tenant consumption of Copilot and AI credits through Microsoft Graph, rooted at /copilot/costManagement. The contract is unit-aware and credit-denominated. It covers the tenant credit balance snapshot, spending policy management, group audience scoping, per-service settings, notify-only threshold alerts and their recipients, per-user consumption balances, the review of users' credit requests, and usage reports that break down consumption by user, security group, governed service, and funding class.
The API is credit-denominated and deliberately excludes purchase forecasts. It doesn't return any currency, invoice, price, or settlement amounts.
Key capabilities
- Read the tenant-wide credit balance snapshot, with one row per billing method.
- Create, read, update, and delete spending policies that cap Copilot Credits consumption for an audience.
- Scope a policy to every user in the tenant (
allUsersSpendingPolicy) or to selected groups (selectedGroupsSpendingPolicy). - Manage a policy's group audience through
$refreference links. - Configure per-service settings that govern or exclude individual AI services within a policy.
- Configure notify-only threshold alerts and manage their recipients.
- Diagnose a user's per-service consumption balance and understand why a user can or can't consume a service.
- List, review, approve, or reject users' requests for Copilot credits, individually or in bulk.
- Report consumption for one completed UTC day by user, security group, and governed service, with ranking and paging.
- Report a calendar month's consumption by funding class (prepaid, pay-as-you-go, unbilled overage, and non-billable).
- Read one user's raw usage detail over a timestamp window, broken down by service and session.
Example scenarios
- An administrator sets a monthly credit cap for a pilot group and alerts admins when usage reaches 80 percent.
- An administrator adds or removes a governed service on an existing policy.
- A support administrator diagnoses why a user can no longer consume a service by reading that user's per-service balance.
- A FinOps reader lists the tenant's enabled spending policies and reviews their configured limits.
- An AI administrator reviews pending credit requests for Work IQ and approves them in bulk.
- A FinOps analyst splits yesterday's consumption by service to see where credits went across AI experiences.
- A billing administrator closes a month by reviewing its consumption by funding class, including unbilled overage.
- A FinOps analyst or business unit lead ranks the highest-consuming users or security groups for a day.
- A support administrator inspects one user's raw usage sessions over a time window.
Personas and roles
Target personas include the AI Administrator and License Administrator for policy management; the FinOps/Global Reader and Billing Administrator for reads; and the Support/Helpdesk administrator for per-user diagnostics. For usage reports, target personas include the FinOps analyst and Billing Administrator for the service and funding reports, and the FinOps analyst and business unit (BU) lead for the user and group rankings. Creating a spending policy also requires the Billing Administrator or Global Administrator directory role at runtime.
Billing Administrators, Global Administrators, AI Administrators, Global Readers, and AI Readers can read credit requests. Global Administrators, Billing Administrators, and AI Administrators can approve or reject them.
Permissions
This API uses the CopilotCostManagement-* permission family. Most operations support only delegated (work or school account) permissions. The tenant credit balance read (getTenantCreditBalance) also supports the CopilotCostManagement.Read.All application permission, and the service and funding usage reports also support the CopilotCostManagement-Reports.Read.All and CopilotCostManagement.Read.All application permissions. Personal Microsoft accounts aren't supported. Choose the least privileged permission for each operation.
Important
Some Microsoft 365 Copilot Cost Management permissions might not yet appear in the API permission picker in the Microsoft Entra admin center. Normal administrator-consent and API authorization requirements still apply.
For delegated access, request the least-privileged permission listed for the operation by its fully qualified scope name in your app's authentication flow, for example https://graph.microsoft.com/CopilotCostManagement-Reports.Read.All for aggregate service or funding reports. An authorized tenant administrator can grant consent through a tenant-specific administrator consent request using your app's client ID, registered redirect URI, and the same scope name, without first selecting the permission in the picker.
This scope-name flow applies only to delegated permissions; it does not configure or grant application permissions.
| Permission | Operations |
|---|---|
CopilotCostManagement.Read.All |
Read the tenant credit balance snapshot. Also read all usage reports with delegated permissions. Application access applies only to the tenant credit balance and the service and funding usage reports. |
CopilotCostManagement-Reports.Read.All |
Read aggregate service and funding usage reports. |
CopilotCostManagement-Policy.Read.All |
Read spending policies, per-service settings, alert thresholds, and recipients. |
CopilotCostManagement-Policy.ReadWrite.All |
Create, update, and delete policies, service settings, alerts, and recipients. |
CopilotCostManagement-Assignment.Read.All |
Read a policy's group audience. |
CopilotCostManagement-Assignment.ReadWrite.All |
Add and remove a policy's group audience. |
CopilotCostManagement-UserData.Read.All |
Read a named user's balance diagnostics, including consumption and the selected spendingPolicyId. Also read user and group usage records and raw per-user usage detail, including services, sessions, native session identifiers, and first and last activity timestamps. |
CopilotCostManagement-CreditReq.Read.All |
Read credit requests. |
CopilotCostManagement-CreditReq.ReadWrite.All |
Read credit requests and approve or reject them. |
API list
| Operation | HTTP method | Description |
|---|---|---|
| Get tenant credit balance | GET /copilot/costManagement/getTenantCreditBalance |
Get the tenant-wide credit balance snapshot. |
| List spendingPolicies | GET /copilot/costManagement/spendingPolicies |
Get a list of spending policies. |
| Create spendingPolicy | POST /copilot/costManagement/spendingPolicies |
Create a new spending policy. |
| Get spendingPolicy | GET /copilot/costManagement/spendingPolicies/{id} |
Retrieve a spending policy. |
| Update spendingPolicy | PATCH /copilot/costManagement/spendingPolicies/{id} |
Update a spending policy. |
| Delete spendingPolicy | DELETE /copilot/costManagement/spendingPolicies/{id} |
Delete a spending policy. |
| List assignedGroups | GET /copilot/costManagement/spendingPolicies/{id}/microsoft.graph.selectedGroupsSpendingPolicy/assignedGroups |
List the groups assigned to a policy. |
| Add assignedGroup | POST /copilot/costManagement/spendingPolicies/{id}/microsoft.graph.selectedGroupsSpendingPolicy/assignedGroups/$ref |
Add a group reference to a policy. |
| Remove assignedGroup | DELETE /copilot/costManagement/spendingPolicies/{id}/microsoft.graph.selectedGroupsSpendingPolicy/assignedGroups/{groupId}/$ref |
Remove a group reference. |
| List spendingPolicyServiceSettings | GET /copilot/costManagement/spendingPolicies/{id}/serviceSettings |
List the service settings of a policy. |
| Create spendingPolicyServiceSetting | POST /copilot/costManagement/spendingPolicies/{id}/serviceSettings |
Add a service to a policy. |
| Get spendingPolicyServiceSetting | GET /copilot/costManagement/spendingPolicies/{id}/serviceSettings/{serviceId} |
Retrieve a service setting. |
| Update spendingPolicyServiceSetting | PATCH /copilot/costManagement/spendingPolicies/{id}/serviceSettings/{serviceId} |
Update a service setting. |
| Get costManagementAlertSetting | GET /copilot/costManagement/spendingPolicies/{id}/emailThresholdSettings |
Retrieve the alert configuration of a policy. |
| Update costManagementAlertSetting | PATCH /copilot/costManagement/spendingPolicies/{id}/emailThresholdSettings |
Create or update the alert configuration. |
| Delete costManagementAlertSetting | DELETE /copilot/costManagement/spendingPolicies/{id}/emailThresholdSettings |
Delete the alert configuration. |
| List recipients | GET /copilot/costManagement/spendingPolicies/{id}/emailThresholdSettings/recipients |
List the alert recipients. |
| Add recipient | POST /copilot/costManagement/spendingPolicies/{id}/emailThresholdSettings/recipients/$ref |
Add an alert recipient. |
| Remove recipient | DELETE /copilot/costManagement/spendingPolicies/{id}/emailThresholdSettings/recipients/{userId}/$ref |
Remove an alert recipient. |
| Get costManagementUserBalance | GET /copilot/costManagement/userBalances/{userId} |
Retrieve a user's consumption balance. |
| List costManagementUserServiceBalances | GET /copilot/costManagement/userBalances/{userId}/serviceBalances |
List a user's per-service balance rows. |
| Get costManagementUserServiceBalance | GET /copilot/costManagement/userBalances/{userId}/serviceBalances/{serviceId} |
Retrieve one service's balance row for a user. |
| List creditRequests | GET /copilot/costManagement/creditRequests |
List the tenant's credit requests. |
| Get creditRequest | GET /copilot/costManagement/creditRequests/{id} |
Retrieve a credit request. |
| Update creditRequest | PATCH /copilot/costManagement/creditRequests/{id} |
Approve or reject a credit request. |
| Batch record decisions | POST /copilot/costManagement/creditRequests/batchRecordDecisions |
Approve or reject credit requests in bulk. |
| List costManagementUserUsageRecords | GET /copilot/costManagement/usageReports/userUsageRecords |
List reported consumption per user for one completed UTC day. |
| Get costManagementUserUsageRecord | GET /copilot/costManagement/usageReports/userUsageRecords/{userId} |
Retrieve one user's reported consumption for one completed UTC day. |
| List costManagementGroupUsageRecords | GET /copilot/costManagement/usageReports/groupUsageRecords |
List reported consumption per security group for one completed UTC day. |
| Get costManagementGroupUsageRecord | GET /copilot/costManagement/usageReports/groupUsageRecords/{groupId} |
Retrieve one security group's reported consumption for one completed UTC day. |
| List costManagementServiceUsageRecords | GET /copilot/costManagement/usageReports/serviceUsageRecords |
List reported consumption per governed service for one completed UTC day. |
| Get costManagementServiceUsageRecord | GET /copilot/costManagement/usageReports/serviceUsageRecords/{serviceId} |
Retrieve one service's reported consumption for one completed UTC day. |
| List costManagementFundingUsageRecords | GET /copilot/costManagement/usageReports/fundingUsageRecords |
List reported consumption per funding class for a calendar month. |
| Get costManagementUserUsageDetail | GET /copilot/costManagement/usageReports/userUsageDetails/{userId} |
Retrieve one user's raw usage detail over a timestamp window. |
| List costManagementUserUsageServiceDetails | GET /copilot/costManagement/usageReports/userUsageDetails/{userId}/services |
List one user's raw consumption by governed service. |
| List costManagementUserUsageSessionDetails | GET /copilot/costManagement/usageReports/userUsageDetails/{userId}/sessions |
List one user's raw usage grouped by session. |
Concurrency and removal semantics
- To mutate an existing policy and its child resources (service settings and reference links), include an
If-Matchheader with the parent policy's ETag. Service settings and reference links don't have their own ETag. The parent policy manages concurrency and appears asparentEtagon a service setting. When you create a policy, it has no existing ETag and doesn't useIf-Match. - The
serviceSettingscollection doesn't supportDELETE. Setstatetodisabledto remove a service. The entry stays in that state. - Manage the
assignedGroupsandrecipientsrelationships as reference navigation properties with$refadd and remove. - Credit requests carry their own strong ETag, returned as
@odata.etagand in theETagresponse header. Update creditRequest requires anIf-Matchheader; the batchRecordDecisions action takes a per-itemetaginstead. - A credit request decision that matches the current state is a no-op that preserves the ETag,
decisionBy, and timestamps. The ETag is still checked, so a same-state decision with a stale ETag fails withpreconditionFailed. - Credit requests can't be created or deleted through the API. Users create them outside Microsoft Graph, and the service retains them according to its retention policy.
Usage report time selectors and paging
Usage reports live under /copilot/costManagement/usageReports. Every usage report request requires a time selector, supplied as query parameters. Requests without the required selectors are rejected with a 400 unsupportedQuery response.
| Selector family | Parameters | Format | Used by |
|---|---|---|---|
| Completed UTC day | startDate, endDate |
Date, YYYY-MM-DD. Inclusive start and exclusive end. endDate must equal startDate plus one day, and its UTC midnight must not be later than the current time. |
User, group, and service usage records (list and get) |
| Calendar month | month |
String, YYYY-MM. Date ranges are rejected. |
Funding usage records |
| Timestamp window | startDateTime, endDateTime |
DateTimeOffset, UTC ISO 8601, up to seven fractional digits. Inclusive start and exclusive end. Currently, startDateTime must be earlier than endDateTime, endDateTime can't be later than the current time, the window can be at most 24 hours long, and the window can't cross a UTC calendar-month boundary. The end can equal midnight UTC on the first day of the next month. |
User usage detail, and its services and sessions |
Invalid selectors are rejected, not clamped. Current-day, future, and multi-day ranges on the completed-UTC-day reports return a 400 response, as do timestamp windows that currently don't meet the timestamp-window limits in the table. Validation doesn't enforce an oldest permitted startDate or month.
- Paging. The user, group, and service usage records and the user usage sessions use server-driven paging with
$skiptoken;$skipisn't supported. Follow the complete@odata.nextLinkURL unchanged. The continuation keeps the original selectors, filter, and order, but it isn't a point-in-time snapshot. Later pages read current data, so rows can repeat or be missed between pages. AnextLinkwhose dates differ from the original request is rejected with a400response. On the user, group, and service usage records,$topaccepts an integer from 1 through 100 with a default of 10, and values outside that range are rejected, not capped. The user usage sessions have a separate default page size of 20 and a maximum of 100. Funding usage records and the user usage services aren't paged. - Filtering. The user, group, and service usage records support
$filteronuserId,groupId, andserviceIdrespectively, by using only theeqoperator. Other operators, such asin, aren't supported. - Ordering. Only
consumedQuantitysupports$orderby. Ties are broken internally, and ordering on the dimension key isn't supported. - Units. Every quantity carries a
unit, currentlycopilotCredit. No currency, invoice, price, or settlement amounts are returned. - Processed versus raw.
userUsageRecordsreturns processed consumption for one completed UTC day that you can rank across users.userUsageDetailsreturns one user's raw, billable-flagged usage over a timestamp window, with service and session breakdowns. The two measurements, including theirsessionCountvalues, aren't guaranteed to be equal. - Not-readable parents.
GET /copilot/costManagement/usageReportsreturns a404response and carries no data.GET /copilot/costManagement/usageReports/userUsageDetailsisn't listable; read the detail by user ID instead.
Error conditions
Error responses use the standard OData error and innerError envelope. The innerError.code reports workload-specific conditions, while the standard OData error.code reports generic conditions. Row-level security runs before lookup, so an out-of-scope tenant resource returns a 404 response instead of a 403 response.
| Condition | HTTP | Error code |
|---|---|---|
| Caller lacks the required permission or a qualifying directory role | 403 | Authorization_RequestDenied |
| Unsupported query option or malformed request | 400 | invalidRequest, unsupportedQuery |
Usage report time selector is missing, malformed, or incompatible; a user, group, or service range doesn't select exactly one completed UTC day; $top on the user, group, or service usage records is outside 1 through 100; a user usage detail window's start isn't earlier than its end, its end is later than the current time, it's longer than 24 hours, or it crosses a UTC calendar-month boundary; or a continuation token is invalid or mismatched |
400 | unsupportedQuery |
| A keyed usage report read has no represented usage. This response isn't proof of zero consumption or of whether the user or group exists. | 404 | usageDataUnavailable |
| Removing the last assigned group would leave the policy with no assigned audience | 409 | lastAssignedGroup |
| Another non-disabled tenant-wide policy already governs the same service | 409 | allUsersServiceConflict |
| A group-scoped policy shares both an assigned group and an enabled service with another non-disabled policy | 409 | groupServiceConflict |
| Disabling the last enabled service on a policy that has service settings | 409 | atLeastOneServiceRequired |
| Alert threshold value out of range (percentage thresholds must be an integer 1-100) | 400 | invalidAlertThreshold |
| PATCHing any field on a policy that isn't in an editable state | 400 | policyNotEditableWhilePending |
| Unknown or invalid service ID | 400 | invalidService |
| Alerting enabled with no recipient linked, or removing the last recipient while alerting is enabled | 400 | alertRecipientsRequired |
| Alert recipient reference doesn't resolve to a real user in the tenant directory | 400 | alertRecipientNotFound |
| Supplying a server-managed field on PATCH | 400 | invalidRequest |
Stale If-Match on a mutating operation |
412 | preconditionFailed |
Missing If-Match on a credit request update |
428 | preconditionRequired |
Malformed, weak (W/), or * If-Match on a credit request update |
400 | invalidRequest |
| Conflicting concurrent state transition | 409 | invalidTransition |
| Upstream evaluator failed for every service, so no balance row could be produced | 503 | sourceUnavailable |
| Credit request ID doesn't exist | 404 | itemNotFound |
| Invalid bulk decision payload, such as an empty list, more than 100 items, or duplicate request IDs | 400 | invalidRequest |
| Unsupported credit request state transition on update | 400 | invalidRequest |
| Credit request list or count dependency failure | 503 | serviceNotAvailable |
| Usage report source failed. Don't treat this response as zero consumption. | 503 | sourceUnavailable |
API throttling. Honor the Retry-After header. |
429 | tooManyRequests |
The batchRecordDecisions action returns per-item failures in a 200 OK response, not as HTTP errors.