Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Analyze Azure subscriptions to find cost savings via orphaned resources, rightsizing, and usage data
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
cost-query/workflow.md
1# Cost Query Workflow23Use this workflow when the user wants to **understand their costs** — breakdowns, trends, totals, top spenders.45## Step 1: Determine Scope67Identify the Azure scope for the cost query from the Scope Reference table in the main [SKILL.md](../SKILL.md#scope-reference-shared-across-all-workflows).89## Step 2: Choose Report Type1011| Type | Description |12|------|-------------|13| `ActualCost` | Actual billed costs including purchases |14| `AmortizedCost` | Reservation/savings plan costs spread across usage period |15| `Usage` | Usage-based cost data |1617## Step 3: Set Timeframe1819Use a preset timeframe (e.g., `MonthToDate`, `TheLastMonth`, `TheLastYear`) or `Custom` with a `timePeriod` object.2021> ⚠️ **Warning:** Key time period guardrails:22> - **Daily granularity**: max **31 days**23> - **Monthly/None granularity**: max **12 months**24> - `Custom` timeframe **requires** a `timePeriod` object with `from` and `to` dates25> - Future dates in historical queries are silently adjusted (see guardrails for details)26>27> See [guardrails.md](./guardrails.md) for the complete set of validation rules.2829## Step 4: Configure Dataset3031Define granularity, aggregation, grouping, filtering, and sorting in the `dataset` object.3233- **Granularity**: `None`, `Daily`, or `Monthly`34- **Aggregation**: Use `Sum` on `Cost` or `PreTaxCost` for total cost35- **Grouping**: Up to **2** `GroupBy` dimensions (e.g., `ServiceName`, `ResourceGroupName`)36- **Filtering**: Use `dimensions` or `tags` filters with `name`, `operator` (`In`, `Equal`, `Contains`), and `values` fields37- **Sorting**: Order results by cost or dimension columns3839> 💡 **Tip:** Not all dimensions are available at every scope. See [dimensions-by-scope.md](./dimensions-by-scope.md) for the availability matrix.4041For the full request body schema, see [request-body-schema.md](./request-body-schema.md).4243## Step 5: Construct and Execute the API Call4445Use `az rest` to call the Cost Management Query API.4647**Create cost query file:**4849Create `temp/cost-query.json` with:50```json51{52"type": "ActualCost",53"timeframe": "MonthToDate",54"dataset": {55"granularity": "None",56"aggregation": {57"totalCost": {58"name": "Cost",59"function": "Sum"60}61},62"grouping": [63{64"type": "Dimension",65"name": "ServiceName"66}67]68}69}70```7172**Execute cost query:**73```powershell74# Create temp folder75New-Item -ItemType Directory -Path "temp" -Force7677# Query using REST API (more reliable than az costmanagement query)78az rest --method post `79--url "<scope>/providers/Microsoft.CostManagement/query?api-version=2023-11-01" `80--headers "ClientType=GitHubCopilotForAzure" `81--body '@temp/cost-query.json'82```8384## Step 6: Handle Pagination and Errors8586- The API returns a maximum of **5,000 rows** per page (default: 1,000).87- If `nextLink` is present in the response, follow it to retrieve additional pages.88- Handle rate limiting (HTTP 429) by checking all `x-ms-ratelimit-microsoft.costmanagement-*-retry-after` headers in the response. Wait for the longest value before retrying. Do not send further requests to the same scope until the retry-after duration has elapsed.8990See [error-handling.md](./error-handling.md) for the full error reference.9192## Key Guardrails9394| Rule | Constraint |95|------|-----------|96| Daily granularity max range | 31 days |97| Monthly/None granularity max range | 12 months |98| Absolute API max range | 37 months |99| Max GroupBy dimensions | 2 |100| ResourceId grouping scope | Subscription and resource group only — not supported at billing account, management group, or higher scopes |101| Max rows per page | 5,000 |102| Custom timeframe | Requires `timePeriod` with `from`/`to` |103| Filter and/or | Must have at least 2 expressions |104105## Examples106107**Cost by service for the current month:**108109```powershell110az rest --method post `111--url "/subscriptions/<subscription-id>/providers/Microsoft.CostManagement/query?api-version=2023-11-01" `112--headers "ClientType=GitHubCopilotForAzure" `113--body '{114"type": "ActualCost",115"timeframe": "MonthToDate",116"dataset": {117"granularity": "None",118"aggregation": {119"totalCost": { "name": "Cost", "function": "Sum" }120},121"grouping": [122{ "type": "Dimension", "name": "ServiceName" }123]124}125}'126```127128For more examples including daily trends, tag-based filtering, and multi-dimension queries, see [examples.md](./examples.md).129130## Error Handling131132| HTTP Status | Error | Remediation |133|-------------|-------|-------------|134| 400 | Invalid request body | Check schema, date ranges, and dimension compatibility. |135| 401 | Unauthorized | Verify authentication (`az login`). |136| 403 | Forbidden | Ensure Cost Management Reader role on scope. |137| 404 | Scope not found | Verify scope URL and resource IDs. |138| 429 | Too many requests | Check all `x-ms-ratelimit-microsoft.costmanagement-*-retry-after` headers (`qpu`, `entity`, `tenant`). Wait for the **longest** value. **Max 3 retries.** |139| 503 | Service unavailable | Check [Azure Status](https://status.azure.com). |140141See [error-handling.md](./error-handling.md) for detailed error handling including rate limit headers and retry strategies.142