Recommendations
ZopNight analyzes your cloud resources and generates cost optimization recommendations based on usage patterns, idle detection, and best practices.
How Recommendations Work
The recommender service subscribes to resource discovery events via Redis Streams. When new or updated resources are discovered, it runs audit rules across all three cloud providers to generate actionable recommendations.
Recommendation Categories
| Category | Description |
|---|---|
idle | Resources with low or no utilization that could be stopped or terminated |
rightsizing | Resources that are over-provisioned and could use a smaller instance type |
schedule | Resources that would benefit from a start/stop schedule or autoscaler policy |
orphan | Unattached resources (volumes, snapshots, IPs) with ongoing costs |
compliance | Resources missing required tags or not following naming conventions |
discount | Commitment-based savings opportunities (Reserved Instances, Savings Plans) |
governance | Best practice violations (e.g., public access, missing encryption) |
Severity Levels
| Severity | Description |
|---|---|
| critical | High-cost waste requiring immediate attention |
| high | Significant savings opportunity |
| medium | Moderate optimization potential |
| low | Minor improvement suggestion |
| info | Informational — no direct cost impact |
List Resource Summaries
/recommendations/resourcesList distinct resources with aggregate recommendation stats. Used for the resource view.
Query Parameters
| Parameter | Description |
|---|---|
status | Filter by recommendation status (open, applied, dismissed, optimised) |
severity | Filter by severity level |
category | Filter by category |
provider | Filter by cloud provider |
resource_type | Filter by resource type (ec2, rds, disk, etc.) |
cloud_account_id | Filter by cloud account ID (comma-separated for multiple) |
search | Search by resource name or UID |
sort_by | Sort column (savings_usd, updated_at, severity). Default: savings_usd |
sort_order | Sort direction (asc, desc). Default: desc |
page | Page number (default: 1) |
size | Items per page (default: 10, max: 100) |
{
"data": {
"items": [
{
"resourceUid": "i-0abc123def456",
"resourceName": "idle-dev-server",
"resourceType": "ec2",
"provider": "aws",
"cloudAccountId": "123456789012",
"cloudAccountName": "AWS Prod",
"recommendationCount": 3,
"openCount": 2,
"totalSavingsUsd": 52.56
}
],
"total": 45,
"page": 1,
"limit": 10,
"hasMore": true
}
}List Rule Summaries
/recommendations/rulesList distinct rules with aggregate recommendation stats. Used for the rule view.
Query Parameters
Same filters as /recommendations/resources plus:
| Parameter | Description |
|---|---|
rule_id | Filter by specific rule ID (e.g., RC-212) |
{
"data": {
"items": [
{
"ruleId": "RC-212",
"title": "Azure managed disk is unattached — verify and delete if not needed",
"category": "orphan",
"severity": "low",
"resourceCount": 36,
"openCount": 35,
"totalSavingsUsd": 5.00
}
],
"total": 8,
"page": 1,
"limit": 10,
"hasMore": false
}
}List Recommendations
/recommendationsList individual recommendations with filtering and pagination. Use resource_uid or rule_id to scope to a specific group.
Query Parameters
Same filters as /recommendations/resources plus:
| Parameter | Description |
|---|---|
resource_uid | Filter by resource UID (used when expanding a resource card) |
rule_id | Filter by rule ID (used when expanding a rule card) |
{
"data": {
"items": [
{
"id": "rec_001",
"resourceUid": "i-0abc123def456",
"resourceName": "idle-dev-server",
"resourceType": "ec2",
"ruleId": "RC-001",
"title": "Idle EC2 Instance",
"description": "This instance has had less than 5% CPU utilization over the past 14 days.",
"currentCostUsd": 52.56,
"optimizedCostUsd": 0.00,
"savingsUsd": 52.56,
"status": "open",
"severity": "high",
"category": "idle",
"remediation": "Consider stopping or terminating this instance if it is not needed.",
"consoleUrl": "https://console.aws.amazon.com/ec2/home?region=us-east-1#Instances:instanceId=i-0abc123def456",
"provider": "aws",
"cloudAccountId": "123456789012",
"cloudAccountName": "AWS Prod",
"actionType": "stop",
"evidence": {
"metric": "CPUUtilization",
"windowDays": 14,
"p95": 3.1
},
"generatedAt": "2025-01-20T08:00:00Z"
}
],
"total": 36,
"page": 1,
"limit": 5,
"hasMore": true
}
}Recommendation Summary
/recommendations/summaryGet aggregate recommendation statistics.
{
"data": {
"totalOpen": 23,
"totalSavings": 1250.80,
"criticalCount": 2,
"highCount": 8,
"resourceCount": 18,
"awsResources": 10,
"gcpResources": 5,
"azureResources": 3,
"appliedCount": 12,
"dismissedCount": 5,
"optimisedCount": 3
}
}Resource Recommendations (Deprecated)
/recommendations/resources/{resourceUID}Get all recommendations for a specific resource.
Deprecated
GET /recommendations?resource_uid={resourceUID} instead, which supports pagination. Target removal: 2026-10-01.Update Recommendation
/recommendations/{recommendationID}Mark a recommendation as applied or dismissed, or reopen one that was previously applied or dismissed.
curl -X PATCH https://zopnight.com/api/recommendations/rec_001 \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{ "status": "applied" }'Valid status transitions:
open→appliedopen→dismissedapplied→open(reopen)dismissed→open(reopen)
Savings on Applied & Auto-Resolved
totalSavingsUSD field on the Applied and Auto-Resolved recommendation cards reflects realised savings, not just open opportunity. The /recommendations/summary endpoint exposes the same numbers via appliedSavingsUSD and optimisedSavingsUSD.Filter Fields
/recommendations/filter-fieldsGet available filter field values for building filter UIs.
{
"data": {
"statuses": ["open", "applied", "dismissed", "optimised"],
"severities": ["critical", "high", "medium", "low", "info"],
"categories": ["idle", "rightsizing", "schedule", "orphan", "compliance", "discount", "governance"],
"providers": ["aws", "gcp", "azure"]
}
}Provider Breakdown
/recommendations/summary/providersGet recommendation counts and savings broken down by cloud provider.
{
"data": [
{ "provider": "aws", "totalOpen": 12, "totalSavings": 820.50, "criticalCount": 1, "highCount": 5 },
{ "provider": "gcp", "totalOpen": 6, "totalSavings": 310.00, "criticalCount": 0, "highCount": 2 },
{ "provider": "azure", "totalOpen": 5, "totalSavings": 120.30, "criticalCount": 1, "highCount": 1 }
]
}Recommendation Detail
/recommendations/{recID}/detailGet full detail for a single recommendation including metrics and remediation steps.
Refresh Recommendations
/recommendations/refreshTrigger a recommendation recomputation for the organization.
Resource Intensive
Auto-Remediation Workflows
For auto-remediable rules (rightsizing, resize, oversized) a recommendation can be applied through a multi-step workflow that the provisioner executes against the cloud provider. Workflows are previewed, started, and approved through the endpoints below. See Provisioning for the apply-side detail.
/recommendations/{recID}/workflowPreview the workflow plan that would be created for this recommendation — steps, target spec, and approval gates — without persisting anything.
/recommendations/{recID}/workflowStart a remediation workflow for this recommendation. Returns a workflow job ID; poll /workflows/{jobID} for status.
/workflows/pending-approvalList workflow steps across the org that are waiting on a human approver. Used by the approvals queue widget.
/workflows/{jobID}Get a workflow's status, current step, and per-step audit trail.
/workflows/{jobID}/cancelCancel an in-flight workflow. Steps already applied are not rolled back; subsequent steps are skipped.
/workflows/{jobID}/steps/{stepName}/approveApprove a paused workflow step by its declared name. Use the by-id variant when you have the step's stable ID instead of the template name.
/workflows/{jobID}/steps/{stepName}/rejectReject a paused workflow step. The workflow halts and no further steps are dispatched.
/workflows/{jobID}/steps-by-id/{stepID}/approveApprove a paused workflow step by its stable ID. Prefer this when the UI already has the step ID — it survives template renames.
/workflows/{jobID}/steps-by-id/{stepID}/rejectReject a paused workflow step by its stable ID.
Auto-Tagging
ZopNight can predict environment tags (prod, staging, dev) and no-stop flags for resources based on naming patterns, tags, and resource characteristics.
Confidence Score
/autotaggingList auto-tagging suggestions.
{
"data": {
"items": [
{
"id": "tag_001",
"resourceUID": "i-0abc123def456",
"resourceName": "prod-api-server",
"resourceType": "aws-ec2",
"provider": "aws",
"predictedEnv": "prod",
"predictedNoStop": true,
"confidence": 92,
"reason": "Name contains 'prod', has production tags, runs 24/7"
}
],
"total": 15,
"page": 1,
"limit": 20
}
}/autotagging/acceptAccept an auto-tag suggestion and apply it.
curl -X POST https://zopnight.com/api/autotagging/accept \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"resourceUID": "i-0abc123def456",
"env": "prod",
"noStop": true
}'/autotagging/rejectReject an auto-tag suggestion.
curl -X POST https://zopnight.com/api/autotagging/reject \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{ "resourceUID": "i-0abc123def456" }'The recommender runs 337+ audit rules across AWS (155), GCP (75), and Azure (107), including six autoscaler rules (RC-ASC-001..006) that feed into VM Autoscaling. Auto-tagging lives on its own page — Auto-Tagging. See Cloud Support Matrix for provider-specific details.