Motor de recomendaciones personalizadas de Azure que ayuda a los usuarios a seguir los procedimientos recomendados para optimizar las implementaciones de Azure.
Hello JAVIER FERNANDEZ ROZAS (INYCOM)
The Benefit Recommendations API doesn't decide "single vs shared" from the URL path it decides it from the $filter=properties/scope query parameter. And that filter has a default value ofShared. So even when you pass /subscriptions/{sub_id} as the billing scope, if you don't explicitly override the filter, the API keeps returning the tenant/enrollment‑wide (Shared) recommendation, which is why you see the "same recommendation" repeated across subscriptions.
Per the official REST API reference, the $filter parameter for benefitRecommendations supports:
-
properties/scope→ allowed valuesSingleorShared(default =Shared) -
properties/lookBackPeriod→Last7Days/Last30Days/Last60Days(default =Last60Days) -
properties/term→P1Y/P3Y(default =P3Y) -
properties/subscriptionId -
properties/resourceGroup
That's the same API surface (2025-03-01) that the Azure portal and Advisor consume the portal simply passes scope=Single when it shows you the per‑subscription tiles, which is why the portal/Advisor shows individual recommendations but your raw API call doesn't.
As a workaround, please follow below resolution:
Add properties/scope eq 'Single' to the $filter. That is the missing piece.
- Correct request for a subscription‑specific recommendation.
GET https://management.azure.com/subscriptions/{sub_id}/providers/Microsoft.CostManagement/benefitRecommendations
?api-version=2025-03-01
&$filter=properties/scope eq 'Single' and properties/term eq 'P3Y' and properties/lookBackPeriod eq 'Last30Days'
&$expand=properties/usage,properties/allRecommendationDetails
Key points:
-
billingScopein the URL must be/subscriptions/{sub_id}as you're doing or/subscriptions/{sub_id}/resourceGroups/{rg}for RG scope, or the billing account/billing profile path for EA/MCA level. -
$filter=properties/scope eq 'Single'this is the fix. Without it, the API silently defaults toShared, which is generated at the enrollment/billing‑profile level and therefore looks identical across every subscription you query. - Optionally pass
properties/subscriptionIdin the filter if you want to further scope, and adjustterm(P1Y/P3Y) andlookBackPeriod(Last7Days/Last30Days/Last60Days) to match what the portal is showing you. - Use
$expand=properties/usage,properties/allRecommendationDetailsif you want the same rich detail (hourly usage, alternative commitments) that the portal shows.
Why the portal/Advisor "seemed" to have recommendations but the API didn't:
Azure Advisor and the "Buy a savings plan" experience surface both the Shared recommendation and the Single (per‑subscription) recommendation, and they call the API twice once with scope=Shared and once with scope=Single. Your integration was only ever getting the Shared side of that pair, so the per‑subscription numbers appeared to be "missing" when in reality they simply weren't requested.
Things to double‑check if Single still returns nothing for a given subscription.
Even with scope=Single, a subscription won't get an individual recommendation if:
- There isn't enough eligible savings‑plan compute usage in that subscription over the chosen lookback window (7/30/60 days). Recommendations are only produced when the simulation shows net savings vs. pay‑as‑you‑go otherwise Azure omits it.
- A recent purchase (savings plan or reservation) was made allow at least 7 days for the recommendation engine to refresh before comparing portal vs. API output.
- The signed‑in principal is missing Cost Management Reader / Billing Reader on that subscription in which case you may get a 403, or an empty result on some subscriptions but not others.
If you want a fast way to validate this on your side without writing code from scratch, the community Get-BenefitRecommendations.ps1 script wraps exactly this API (2025-03-01), lets you pick BillingScope, LookBackPeriod, and Term, and returns the same JSON you'd get via REST useful for confirming that Single scope now returns per‑subscription data before you patch your integration.
Thanks,
Suchitra.