Public API — SaaS
The API is exclusively available for our paying customers, allowing them to interact with the platform programmatically.
Check the following information to get acquainted with the PerfectScale rate-limiting policy and authentication process.
The PerfectScale public API is a premium feature available only with our EXPERT package for PerfectScale’s paying customers. Contact [email protected] to learn more about how to gain access to this feature.
PerfectScale API implements a rate-limiting policy to ensure fair usage and maintain the quality of service. The rate limit is set at 10 requests per minute per client.
Authentication
To interact with the PerfectScale API, a token is required. To get the token, follow the steps below:
-
Retrieve Client Credentials:
- Go to https://app.perfectscale.io.
- Click on your user avatar located at the bottom left corner of the page.
- Select Organization Settings from the menu.
- In the pop-up window, navigate to the API Tokens tab.
- Click on Generate Token.
- Assign a Read Only Role to the new token.
- Upon creation, you will be provided with a
client_id(Client ID) andclient_secret(Secret Key).
-
Obtain Access Token:
- Make a POST request to the Authentication Endpoint with the following payload:
{"client_id": "your_client_id","client_secret": "your_client_secret"}- The API will respond with a token payload, which will contain your access token.
-
Access Other Endpoints:
- With the obtained access token, you can make authorized requests to other endpoints of the PerfectScale API. Include the token in the Authorization header of your HTTP requests as follows:
Authorization: Bearer your_access_token
Authentication endpoint
Server: https://api.app.perfectscale.io/public/v1
Authentication (auth): http — bearer — JWT
POST /auth/public_auth
Public authentication for clients
This endpoint allows clients to authenticate using their client credentials.
Request body
application/json (required): object
| Property | Type | Required | Description |
|---|---|---|---|
| client_id | string | Yes | The client identifier issued to the client during the registration process. |
| client_secret | string | Yes | The client secret issued to the client during the registration process. |
Responses
| Status | Description | Body |
|---|---|---|
| 200 | Authentication successful | application/json: object |
| 400 | Bad request, client credentials are missing or incorrect. | |
| 401 | Unauthorized, client authentication failed. | |
| 500 | Internal server error |
200 application/json body
| Property | Type | Required | Description |
|---|---|---|---|
| access_token | string | No | Access token to be used for subsequent requests. |
| expires_in | integer | No | The number of seconds the token will be valid. |
Workload
A representation of a workload within a Kubernetes cluster.
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | A unique identifier for the workload, usually following a namespace-type-name convention. |
| name | string | Yes | A human-readable name for the workload. |
| type | string | Yes | The type of Kubernetes workload. Common types include Deployment, StatefulSet, and DaemonSet, but other string values can also be used to represent custom or extended workload types. |
| namespace | string | Yes | The Kubernetes namespace in which the workload resides. |
| firstSeen | string · date-time | Yes | The timestamp when the workload was first observed, formatted as an ISO 8601 date-time string. |
| lastSeen | string · date-time | Yes | The timestamp when the workload was last observed, formatted as an ISO 8601 date-time string. |
| runningMinutes | integer | Yes | The total number of minutes the workload has been running. |
| replicasCounts | ReplicasCounts | Yes | |
| resilienceLevel | "low", "medium", "high", "highest" | Yes | The resilience level of the workload, indicating its tolerance to failures or disruptions (configured on Perfectscale side). |
| muteStatus | MuteStatus | Yes | |
| costAnalysis | CostAnalysis | Yes | |
| workloadLabels | object | Yes | Key-value pairs representing kubernets labels associated with the workload. |
| indicators | array of Indicator | Yes | A list of indicators providing insights into the performance and health of the workload. |
| containers | object | Yes | An object holding detailed information about each container within the workload. |
ReplicasCounts
An object representing the count statistics of replicas for a workload over a month period.
| Property | Type | Required | Description |
|---|---|---|---|
| maxCount | integer | Yes | The maximum count of replicas observed for the workload during the month period. |
| avgCount | integer | Yes | The average count of replicas observed for the workload during the month period. |
MuteStatus
The mute status of a workload, indicating whether the workload is currently muted and when it will become unmuted.
| Property | Type | Required | Description |
|---|---|---|---|
| isMuted | boolean | Yes | Indicates whether the workload is currently muted. |
| muteExpiry | string · date-time | No | The date and time when the workload will automatically become unmuted. If null, the mute status does not expire automatically. |
Resources
Metrics detailing the resource allocation in terms of memory and CPU.
| Property | Type | Required | Description |
|---|---|---|---|
| memoryRequestMiB | number · double | Yes | The amount of memory requested for the workload in MiB. |
| memoryLimitMiB | number · double | Yes | The maximum amount of memory that can be allocated for the workload in MiB. |
| cpuRequestCores | number · double | Yes | The amount of CPU resources requested for the workload in cores. |
| cpuLimitCores | number · double | Yes | The maximum amount of CPU resources that can be allocated for the workload in cores. |
Past30DaysCostAnalysis
Metrics detailing the total and wasted costs associated with the workload's resource consumption.
| Property | Type | Required | Description |
|---|---|---|---|
| totalCost | number · double | Yes | The total cost incurred by the workload's resource consumption. |
| wastedCost | number · double | Yes | The cost attributed to over-provisioned or inefficiently utilized resources. |
Projected30DaysCostAnalysis
Metrics detailing the projected costs, recommended costs, and projected waste associated with the workload's resource consumption.
| Property | Type | Required | Description |
|---|---|---|---|
| projectedCost | number · double | Yes | The projected cost of the workload's resource consumption for the next 30 days. |
| recommendedCost | number · double | Yes | The recommended cost based on optimized resource allocation. |
| projectedWaste | number · double | Yes | The projected cost waste due to over-provisioned or inefficiently utilized resources for the next 30 days. |
CostAnalysis
Analysis of the costs associated with the workload's resource consumption over the past 30 days and projected for the next 30 days.
| Property | Type | Required | Description |
|---|---|---|---|
| past30Days | Past30DaysCostAnalysis | Yes | |
| projected30Days | Projected30DaysCostAnalysis | Yes |
Indicator
An object representing key performance indicators that provide insights into the performance and health of the workload or container.
| Property | Type | Required | Description |
|---|---|---|---|
| name | "OOM", "CpuThrottling", "CpuRequestNotSet", "MemRequestNotSet", "MemLimitNotSet", "UnderProvisionedMemRequest", "UnderProvisionedMemLimit", "UnderProvisionedCpuRequest", "UnderProvisionedCpuLimit", "OverProvisionedCpuRequest", "OverProvisionedMemRequest", "RestartsObserved" | Yes | The name of the indicator representing a specific aspect of performance or health. |
| type | "none", "risk", "waste" | Yes | The type of indicator, categorizing it as either a risk, waste, or no issue (none). |
| severityLevel | 0, 1, 2, 3 | Yes | The severity level of the indicator, ranging from 0 (no issue) to 3 (critical issue). |
Container
Detailed information about a specific container within the workload, including its performance indicators and usage statistics.
| Property | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | The name of the container. |
| runningMinutes | integer | Yes | The total number of minutes the container has been running. |
| indicators | array of Indicator | Yes | A list of indicators providing insights into the performance and health of the container. |
| resources | object | Yes | The resource allocation details for the workload, including the current and recommended by PerfectScale allocation. |
| resources.current | Resources | Yes | |
| resources.recommended | Resources | Yes | |
| usage | object | Yes | An object representing the resource usage statistics of a container, broken down into CPU and memory consumption. |
| usage.cpuCores | Percentiles | Yes | |
| usage.memoryMiB | Percentiles | Yes |
Percentiles
An object representing percentile statistics of resource usage, providing insights into the distribution of usage values over a certain period.
| Property | Type | Required | Description |
|---|---|---|---|
| p90 | number · double | Yes | The 90th percentile value of resource usage, indicating that 90% of the usage values are below this value and 10% are above. |
| p95 | number · double | Yes | The 95th percentile value of resource usage, indicating that 95% of the usage values are below this value and 5% are above. |
| p100 | number · double | Yes | The 100th percentile value (or maximum value) of resource usage observed during the specified period. |
Download OpenAPI specification
Clusters endpoint
GET /clusters
Server: https://api.app.perfectscale.io/public/v1
Authentication (auth): http — bearer — JWT
GET /clusters
Responses
| Status | Description | Body |
|---|---|---|
| 200 | OK | application/json: object |
200 application/json body
| Property | Type | Required | Description |
|---|---|---|---|
| data | array of Cluster | Yes |
Cluster
| Property | Type | Required | Description |
|---|---|---|---|
| uid | string · nullable | Yes | |
| name | string | Yes | |
| cloud | ClusterCloud | No | |
| region | string · nullable | No | |
| createdAt | string · date-time | Yes | |
| lastTransmittedAt | string · date-time | Yes |
ClusterCloud
"aws", "gcp", "azure"
Download OpenAPI specification
GET /clusters/{cluster_uid}
Server: https://api.app.perfectscale.io/public/v1
Authentication (auth): http — bearer — JWT
GET /clusters/{cluster_uid}
Parameters
| Name | Location | Required | Type | Description |
|---|---|---|---|---|
| cluster_uid | path | Yes | string | |
| period | query | No | string | The period for which carbon emission is calculated |
Responses
| Status | Description | Body |
|---|---|---|
| 200 | OK | application/json: object |
200 application/json body
| Property | Type | Required | Description |
|---|---|---|---|
| data | ClusterDetail | Yes |
ClusterDetail
| Property | Type | Required | Description |
|---|---|---|---|
| uid | string · nullable | Yes | |
| name | string | Yes | |
| cloud | ClusterCloud | No | |
| region | string · nullable | No | |
| createdAt | string · date-time | Yes | |
| lastTransmittedAt | string · date-time | Yes | |
| emission | object | Yes |
ClusterCloud
"aws", "gcp", "azure"
Download OpenAPI specification
Workloads endpoint
Ensure that the following request includes the cluster_uid parameter, as it is mandatory. Follow the instructions provided to obtain this value.
GET /clusters/{cluster_uid}/workloads
List all workloads in a specified cluster
Server: https://api.app.perfectscale.io/public/v1
Authentication (auth): http — bearer — JWT
GET /clusters/{cluster_uid}/workloads
List all workloads in a specified cluster
Parameters
| Name | Location | Required | Type | Description |
|---|---|---|---|---|
| cluster_uid | path | Yes | string | The unique identifier for the cluster |
| period | query | No | TimeWindow | The period for which data is calculated |
| expandEphemeralWorkloads | query | No | boolean | By default, short-lived ephemeral workloads in large clusters are collapsed into a single aggregate row named "Collapsed Ephemeral Pods" (namespace "EphemeralPods", type "-") carrying their summed cost and no recommendations. The aggregate row has empty-string values for resilienceLevel, optimizationPolicy, cpuOptimizationPolicy, memoryOptimizationPolicy and optimizationPolicyTimeWindow, a single placeholder container named "-", and firstSeen/lastSeen spanning the collapsed workloads. Collapse eligibility is evaluated within the requested period's data window, so the same cluster may collapse for one period and not another. Set to true to return the full, uncollapsed workload list. |
Responses
| Status | Description | Body |
|---|---|---|
| 200 | A list of workloads | application/json: object |
| 404 | Cluster not found | |
| 500 | Internal server error |
200 application/json body
| Property | Type | Required | Description |
|---|---|---|---|
| meta | object | Yes | |
| meta.count | integer | Yes | The total number of workloads in the specified cluster. |
| data | array of Workload | Yes |
TimeWindow
The time period for which the data is calculated (from 1h to 30d).
"1h", "4h", "12h", "1d", "3d", "7d", "14d", "30d"
Workload
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | A unique identifier for the workload, usually following a namespace-type-name convention. |
| name | string | Yes | A human-readable name for the workload. |
| type | string | Yes | The type of Kubernetes workload. Common types include Deployment, StatefulSet, and DaemonSet, but other string values can also be used to represent custom or extended workload types. |
| namespace | string | Yes | The Kubernetes namespace in which the workload resides. |
| firstSeen | string · date-time | Yes | The timestamp when the workload was first observed. |
| lastSeen | string · date-time | Yes | The timestamp when the workload was last observed. |
| runningMinutes | integer | Yes | The total number of minutes the workload has been running. |
| replicasCounts | ReplicasCounts | Yes | |
| resilienceLevel | "low", "medium", "high", "highest" | Yes | Deprecated: Use optimizationPolicy instead. The resilience level of the workload (configured on Perfectscale side). Mapping to optimizationPolicy values: - low → maxSavings - medium → balanced - high → extraHeadroom - highest → maxHeadroom |
| optimizationPolicy | OptimizationPolicy | Yes | The optimization policy applied to the workload. |
| optimizationPolicyTimeWindow | OptimizationPolicyTimeWindow | Yes | The time window for optimization policy. |
| cpuOptimizationPolicy | OptimizationPolicy | Yes | The CPU-specific optimization policy. |
| memoryOptimizationPolicy | OptimizationPolicy | Yes | The memory-specific optimization policy. |
| memoryRequestEqualsLimit | boolean | Yes | Whether memory request equals limit is enabled. |
| muteStatus | MuteStatus | Yes | |
| costAnalysis | CostAnalysis | Yes | |
| workloadLabels | object | Yes | Key-value pairs representing kubernets labels associated with the workload. |
| indicators | array of Indicator | Yes | A list of indicators providing insights into the performance and health of the workload. |
| containers | array of Container | Yes | An object holding detailed information about each container within the workload. |
ReplicasCounts
An object representing the count statistics of replicas for a workload over a month period.
| Property | Type | Required | Description |
|---|---|---|---|
| maxCount | integer | Yes | The maximum count of replicas observed for the workload during the month period. |
| avgCount | integer | Yes | The average count of replicas observed for the workload during the month period. |
OptimizationPolicy
The optimization policy determining resource allocation strategy.
"balanced", "extraHeadroom", "maxHeadroom", "maxSavings"
OptimizationPolicyTimeWindow
The time window for optimization policy.
"14d", "21d", "30d", "45d", "policyDefault"
MuteStatus
| Property | Type | Required | Description |
|---|---|---|---|
| isMuted | boolean | Yes | Indicates whether the workload is currently muted. |
| expires | string · date-time · nullable | Yes | The date and time when the workload will automatically become unmuted. If null, the mute status does not expire automatically. |
CostAnalysis
Analysis of the costs associated with the workload's resource consumption for the requested period.
| Property | Type | Required | Description |
|---|---|---|---|
| past30Days | PastPeriodCostAnalysis | Yes | Cost analysis data for a 30-day window when an explicit period is requested (including period=30d). When no period is specified the default 28-day window is used for backward compatibility. |
| pastPeriod | PastPeriodCostAnalysis | Yes | |
| next30Days | NextPeriodCostAnalysis | Yes | Projected cost data for a 30-day window when an explicit period is requested (including period=30d). When no period is specified the default 28-day window is used for backward compatibility. |
| nextPeriod | NextPeriodCostAnalysis | Yes |
PastPeriodCostAnalysis
Metrics detailing the total and wasted costs associated with the workload's resource consumption over the analysed period.
| Property | Type | Required | Description |
|---|---|---|---|
| totalCost | number · double | Yes | The total cost incurred by the workload's resource consumption. |
| wastedCost | number · double | Yes | The cost attributed to over-provisioned or inefficiently utilized resources. |
| costPerHour | number · double | Yes | The cost of the workload per hour. |
NextPeriodCostAnalysis
Metrics detailing the cost increase and potential savings associated with the workload's upcoming potential resource consumption.
| Property | Type | Required | Description |
|---|---|---|---|
| costIncrease | number · double | Yes | The workload total cost increase. |
| potentialSavings | number · double | Yes | The potential savings for the workload. |
Indicator
An object representing key performance indicators that provide insights into the performance and health of the workload or container.
| Property | Type | Required | Description |
|---|---|---|---|
| name | "OOM", "CpuThrottling", "CpuRequestNotSet", "MemRequestNotSet", "MemLimitNotSet", "UnderProvisionedMemRequest", "UnderProvisionedMemLimit", "UnderProvisionedCpuRequest", "UnderProvisionedCpuLimit", "OverProvisionedCpuRequest", "OverProvisionedMemRequest", "RestartsObserved" | Yes | The name of the indicator representing a specific aspect of performance or health. |
| type | "none", "risk", "waste" | Yes | The type of indicator, categorizing it as either a risk, waste, or no issue (none). |
| severityLevel | 0, 1, 2, 3 | Yes | The severity level of the indicator, ranging from 0 (no issue) to 3 (critical issue). |
Container
Detailed information about a specific container within the workload, including its performance indicators and usage statistics.
| Property | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | The name of the container. |
| runningMinutes | integer | Yes | The total number of minutes the container has been running. |
| indicators | array of Indicator | Yes | A list of indicators providing insights into the performance and health of the container. |
| resources | object | Yes | The resource allocation details for the workload, including the current and recommended by PerfectScale allocation. |
| resources.current | Resources | Yes | |
| resources.recommended | Resources | Yes | |
| usage | object | Yes | An object representing the resource usage statistics of a container, broken down into CPU and memory consumption. |
| usage.cpuCores | Percentiles | Yes | |
| usage.memoryMiB | Percentiles | Yes |
Resources
Metrics detailing the resource allocation in terms of memory and CPU.
| Property | Type | Required | Description |
|---|---|---|---|
| memoryRequestMiB | number · double | Yes | The amount of memory requested for the workload in MiB. |
| memoryLimitMiB | number · double | Yes | The maximum amount of memory that can be allocated for the workload in MiB. |
| cpuRequestCores | number · double | Yes | The amount of CPU resources requested for the workload in cores. |
| cpuLimitCores | number · double | Yes | The maximum amount of CPU resources that can be allocated for the workload in cores. |
Percentiles
An object representing percentile statistics of resource usage, providing insights into the distribution of usage values over a certain period.
| Property | Type | Required | Description |
|---|---|---|---|
| p90 | number · double | Yes | The 90th percentile value of resource usage, indicating that 90% of the usage values are below this value and 10% are above. |
| p95 | number · double | Yes | The 95th percentile value of resource usage, indicating that 95% of the usage values are below this value and 5% are above. |
| p100 | number · double | Yes | The 100th percentile value (or maximum value) of resource usage observed during the specified period. |
Download OpenAPI specification
Infrafit endpoint
The InfraFit API turns PerfectScale recommendations into automation-ready JSON, making it easy to embed cost and resource optimization directly into engineering workflows.
You can seamlessly use it for scheduled optimization checks, pre-deployment CI/CD guardrails, automated PRs, and continuous remediation.
For Karpenter, the API can return a ready-to-apply NodePool configuration, enabling teams to move from recommendation to implementation without manually translating dashboard insights into infrastructure code.
List all node groups with infra-fit data and recommendations
Returns node groups for a cluster, each containing utilization metrics, cost data, risk indicators, and actionable recommendations (instance-type or Karpenter configuration changes). Tenant resolved from service token.
Server: https://api.app.perfectscale.io/public/v1
Authentication (auth): http — bearer — JWT
GET /clusters/{clusterUid}/node-groups
List all node groups with infra-fit data and recommendations
Returns node groups for a cluster, each containing utilization metrics, cost data, risk indicators, and actionable recommendations (instance-type or Karpenter configuration changes). Tenant resolved from service token.
Parameters
| Name | Location | Required | Type | Description |
|---|---|---|---|---|
| clusterUid | path | Yes | string | Cluster unique identifier |
| period | query | No | InfraFitPeriod | Window for the node group's own utilization/idle-cost metrics (CPU, memory, running minutes, unrecognized-group detection). Does not affect recommendation savings/pricing math, which always uses a fixed 30-day window regardless of this value. Default P30D. |
| recommendationLimit | query | No | integer | Max recommended node types per regular group (Karpenter always returns full change set) |
| hasRecommendations | query | No | boolean | Filter: true=only groups with actionable recs, false=only without, omit=all |
| includeMuted | query | No | boolean | Include muted recommendations |
| autoscalerType | query | No | InfraFitAutoscalerType | Filter by autoscaler type (e.g. cluster_autoscaler, karpenter) |
| pageSize | query | No | integer | Number of items per page (default 50, max 500) |
| pageToken | query | No | string | Opaque cursor token for pagination |
Responses
| Status | Description | Body |
|---|---|---|
| 200 | List of node groups | application/json: object |
| 400 | Invalid parameters | application/problem+json: Problem |
| 500 | Internal server error | application/problem+json: Problem |
200 application/json body
| Property | Type | Required | Description |
|---|---|---|---|
| data | array of InfraFitNodeGroup | Yes | |
| meta | InfraFitMeta | Yes |
InfraFitPeriod
Analysis time period for infra-fit data.
"PT1H", "PT4H", "PT12H", "P1D", "P3D", "P1W", "P2W", "P4W", "P30D", "P45D"
InfraFitAutoscalerType
Autoscaler managing a node group
"karpenter", "cluster_autoscaler", "unknown"
InfraFitNodeGroup
A node group with utilization metrics, cost data, and recommendations.
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Node pool identifier used in single-group requests |
| architectures | array of InfraFitArchitecture | Yes | CPU architectures present in the group |
| reservations | array of InfraFitReservation | Yes | Reservation types present in the group |
| autoscalerType | InfraFitAutoscalerType | Yes | Autoscaler managing this group |
| nodes | InfraFitNodes | Yes | |
| runningMinutes | integer | Yes | Total running minutes across all nodes in the period |
| pods | InfraFitPods | Yes | |
| cost | InfraFitCost | Yes | |
| cpu | InfraFitCpuStats | Yes | |
| mem | InfraFitMemStats | Yes | |
| gpu | InfraFitGpuStats / null | Yes | |
| seen | InfraFitSeenTimestamps | Yes | |
| labels | object | Yes | Kubernetes labels on the node group |
| nodeTypes | array of InfraFitNodeType | Yes | Instance types running in this group |
| recommendations | InfraFitRecommendations | Yes |
InfraFitArchitecture
CPU architecture of nodes in an InfraFit node group
"amd64", "arm64"
InfraFitReservation
Reservation type of nodes in an InfraFit node group
"on_demand", "spot", "reserved"
InfraFitNodes
Node count statistics for the analysis period
| Property | Type | Required | Description |
|---|---|---|---|
| min | integer | Yes | Minimum observed node count in the period |
| max | integer | Yes | Maximum observed node count in the period |
| avg | number · double | Yes | Average node count in the period |
InfraFitPods
Pod count statistics for the node group
| Property | Type | Required | Description |
|---|---|---|---|
| capacity | integer | Yes | Maximum number of pods the node group can schedule |
| allocatable | integer | Yes | Maximum number of pods allocatable on the node group (Kubernetes limit per node × node count) |
| avgCount | number · double | Yes | Average number of pods running in the group |
InfraFitCost
Cost breakdown for the analysis period
| Property | Type | Required | Description |
|---|---|---|---|
| hourly | Money | Yes | |
| timeframe | Money | Yes | |
| idle | InfraFitCostIdle | Yes |
Money
Monetary amount with currency
| Property | Type | Required | Description |
|---|---|---|---|
| amount | string | Yes | Decimal string representation of the amount (e.g. "100.50") |
| currency | string | Yes | ISO 4217 currency code (e.g. "USD") |
InfraFitCostIdle
Idle cost breakdown by resource type
| Property | Type | Required | Description |
|---|---|---|---|
| total | Money | Yes | |
| cpu | Money | Yes | |
| gpu | Money / null | Yes | |
| mem | Money | Yes |
InfraFitCpuStats
CPU utilization statistics (cores)
| Property | Type | Required | Description |
|---|---|---|---|
| requested | object | Yes | CPU cores requested statistics |
| requested.minCores | number · double | Yes | Minimum CPU cores requested over the requested period |
| requested.maxCores | number · double | Yes | Maximum CPU cores requested over the requested period |
| requested.avgCores | number · double | Yes | Time-weighted median CPU cores requested over the requested period (single aggregate, not per-datapoint) |
| requested.p80Cores | number · double | Yes | 80th percentile CPU cores requested over the requested period |
| requested.p95Cores | number · double | Yes | 95th percentile CPU cores requested over the requested period |
| requested.p99Cores | number · double | Yes | 99th percentile CPU cores requested over the requested period |
| requested.p999Cores | number · double | Yes | 99.9th percentile CPU cores requested over the requested period |
| used | object | Yes | CPU cores used statistics |
| used.minCores | number · double | Yes | Minimum CPU cores used over the requested period |
| used.maxCores | number · double | Yes | Maximum CPU cores used over the requested period |
| used.avgCores | number · double | Yes | Time-weighted median CPU cores used over the requested period (single aggregate, not per-datapoint) |
| used.p80Cores | number · double | Yes | 80th percentile CPU cores used over the requested period |
| used.p95Cores | number · double | Yes | 95th percentile CPU cores used over the requested period |
| used.p99Cores | number · double | Yes | 99th percentile CPU cores used over the requested period |
| used.p999Cores | number · double | Yes | 99.9th percentile CPU cores used over the requested period |
| idleCores | number · double | Yes | Idle (unallocated) CPU cores — max(0, allocatable − avg used) |
InfraFitMemStats
Memory utilization statistics (MiB)
| Property | Type | Required | Description |
|---|---|---|---|
| requested | object | Yes | Memory requested statistics |
| requested.minMiB | number · double | Yes | Minimum memory requested in MiB over the requested period |
| requested.maxMiB | number · double | Yes | Maximum memory requested in MiB over the requested period |
| requested.avgMiB | number · double | Yes | Time-weighted median memory requested in MiB over the requested period (single aggregate, not per-datapoint) |
| requested.p80MiB | number · double | Yes | 80th percentile memory requested in MiB over the requested period |
| requested.p95MiB | number · double | Yes | 95th percentile memory requested in MiB over the requested period |
| requested.p99MiB | number · double | Yes | 99th percentile memory requested in MiB over the requested period |
| requested.p999MiB | number · double | Yes | 99.9th percentile memory requested in MiB over the requested period |
| used | object | Yes | Memory used statistics |
| used.minMiB | number · double | Yes | Minimum memory used in MiB over the requested period |
| used.maxMiB | number · double | Yes | Maximum memory used in MiB over the requested period |
| used.avgMiB | number · double | Yes | Time-weighted median memory used in MiB over the requested period (single aggregate, not per-datapoint) |
| used.p80MiB | number · double | Yes | 80th percentile memory used in MiB over the requested period |
| used.p95MiB | number · double | Yes | 95th percentile memory used in MiB over the requested period |
| used.p99MiB | number · double | Yes | 99th percentile memory used in MiB over the requested period |
| used.p999MiB | number · double | Yes | 99.9th percentile memory used in MiB over the requested period |
| idleMiB | number · double | Yes | Idle (unallocated) memory in MiB — max(0, allocatable − avg used) |
InfraFitGpuStats
GPU utilization statistics
| Property | Type | Required | Description |
|---|---|---|---|
| idle | InfraFitIdleGpu | Yes | |
| requested | InfraFitGpuSample | Yes | |
| used | InfraFitGpuSample | Yes | |
| architectures | array of string | Yes | GPU architectures present in the group (e.g. ampere, hopper), sorted |
| sharingType | array of string | Yes | Active GPU sharing mechanisms in lower_snake_case (e.g. "full", "time_slicing", "mps", "mig") |
InfraFitIdleGpu
Idle (unallocated) GPU resources
| Property | Type | Required | Description |
|---|---|---|---|
| units | number · double | Yes | Idle (unallocated) GPU units — max(0, allocatable − avg used) |
| memoryMiB | number · double | Yes | Idle (unallocated) GPU memory in MiB — max(0, capacity − avg used) |
InfraFitGpuSample
GPU sample statistics (time-weighted medians and percentiles)
| Property | Type | Required | Description |
|---|---|---|---|
| avgUnits | number · double | Yes | Time-weighted median GPU units |
| minUnits | number · double | Yes | Minimum GPU units over the period |
| maxUnits | number · double | Yes | Maximum GPU units over the period |
| p80Units | number · double | Yes | 80th percentile GPU units over the period |
| p95Units | number · double | Yes | 95th percentile GPU units over the period |
| p99Units | number · double | Yes | 99th percentile GPU units over the period |
| p999Units | number · double | Yes | 99.9th percentile GPU units over the period |
| avgMemoryMiB | number · double | Yes | Time-weighted median GPU memory in MiB |
| minMemoryMiB | number · double | Yes | Minimum GPU memory in MiB over the period |
| maxMemoryMiB | number · double | Yes | Maximum GPU memory in MiB over the period |
| p80MemoryMiB | number · double | Yes | 80th percentile GPU memory in MiB over the period |
| p95MemoryMiB | number · double | Yes | 95th percentile GPU memory in MiB over the period |
| p99MemoryMiB | number · double | Yes | 99th percentile GPU memory in MiB over the period |
| p999MemoryMiB | number · double | Yes | 99.9th percentile GPU memory in MiB over the period |
InfraFitSeenTimestamps
First and last observed timestamps
| Property | Type | Required | Description |
|---|---|---|---|
| firstTime | string · date-time | Yes | When first observed (RFC 3339 UTC) |
| lastTime | string · date-time | Yes | When last observed (RFC 3339 UTC) |
InfraFitNodeType
Instance type breakdown within a node group
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Instance type identifier (matches instance.type) |
| instance | InfraFitInstanceInfo | Yes | |
| isSpot | boolean | Yes | Whether this instance type runs on spot/preemptible capacity |
| nodes | InfraFitNodes | Yes | |
| cost | InfraFitCost | Yes | |
| runningMinutes | integer | Yes | Total running minutes across all nodes of this instance type in the period |
| pods | InfraFitPods | Yes | |
| cpu | InfraFitCpuStats | Yes | |
| mem | InfraFitMemStats | Yes | |
| gpu | InfraFitNodeTypeGpu / null | Yes | |
| seen | InfraFitSeenTimestamps | Yes |
InfraFitInstanceInfo
Instance type identity and capacity
| Property | Type | Required | Description |
|---|---|---|---|
| type | string | Yes | Cloud instance type identifier (e.g. m5.2xlarge) |
| family | string | Yes | Instance family prefix shared by related instance types (e.g. m5) |
| architecture | InfraFitArchitecture / null | Yes | CPU architecture of this instance type (null when unknown) |
| cpu | InfraFitInstanceCpu | Yes | |
| mem | InfraFitInstanceMem | Yes | |
| gpu | InfraFitInstanceGpu / null | Yes | GPU capacity, null for non-GPU instance types |
InfraFitInstanceCpu
CPU capacity for an instance type
| Property | Type | Required | Description |
|---|---|---|---|
| capacityCores | number · double | Yes | vCPU count per instance |
| allocatableCores | number · double | Yes | Allocatable vCPU per instance after Kubernetes system-reserved resources are subtracted |
InfraFitInstanceMem
Memory capacity for an instance type
| Property | Type | Required | Description |
|---|---|---|---|
| capacityMiB | number · double | Yes | Memory capacity per instance in MiB |
| allocatableMiB | number · double | Yes | Allocatable memory per instance in MiB after Kubernetes system-reserved resources are subtracted |
InfraFitInstanceGpu
GPU capacity for an instance type
| Property | Type | Required | Description |
|---|---|---|---|
| capacityUnits | number · double | Yes | GPU unit count per instance |
| allocatableUnits | number · double | Yes | Allocatable GPU units per instance after Kubernetes system-reserved resources are subtracted |
| memCapacityMiB | number · double | Yes | Total GPU memory capacity per instance in MiB |
InfraFitNodeTypeGpu
GPU stats for an instance type
| Property | Type | Required | Description |
|---|---|---|---|
| idle | InfraFitIdleGpu | Yes | |
| requested | InfraFitGpuSample | Yes | |
| used | InfraFitGpuSample | Yes | |
| architectures | array of string | Yes | GPU architectures present in the instance type (e.g. ampere, hopper), sorted |
InfraFitRecommendations
Discriminated recommendations object. Routed by autoscalerType: cluster_autoscaler/managed → standard, karpenter → karpenter. Always present, never omitted.
InfraFitStandardRecommendations / InfraFitKarpenterRecommendations
InfraFitStandardRecommendations
Recommendations for Cluster-Autoscaler and managed node groups
| Property | Type | Required | Description |
|---|---|---|---|
| type | "standard" | Yes | |
| hasChanges | boolean | Yes | Whether any instance type changes are recommended |
| nodeTypes | array of InfraFitRecommendedNodeType | Yes | Recommended instance types, capped at recommendationLimit |
InfraFitRecommendedNodeType
A recommended instance type replacement
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Unique identifier for this recommendation entry (matches instanceType) |
| instanceType | string | Yes | Recommended cloud instance type identifier (e.g. m6g.xlarge) |
| instanceFamily | string | Yes | Instance family prefix of the recommended type (e.g. m6g) |
| hourlyCost | Money | Yes | |
| estimatedSavings | Money | Yes | |
| estimatedSavingsPct | number · double | Yes | Savings as percentage of current group cost |
| nodeCount | integer | Yes | Recommended number of nodes of this type |
InfraFitKarpenterRecommendations
Recommendations for Karpenter-managed node pools
| Property | Type | Required | Description |
|---|---|---|---|
| type | "karpenter" | Yes | |
| hasChanges | boolean | Yes | Whether any configuration changes are recommended |
| currentConfig | object | Yes | Current raw Karpenter NodePool CR (full JSON) |
| recommendedConfig | object | Yes | Patched NodePool CR with all recommended changes applied |
| changes | array of InfraFitKarpenterChange | Yes | Structured change set (always full, not capped by recommendationLimit) |
InfraFitKarpenterChange
A single Karpenter configuration change recommendation
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Unique identifier for this change entry (matches path) |
| title | string | Yes | Human-readable change title |
| path | string | Yes | JSONPath (RFC 9535 syntax) into the NodePool CR. Nested keys and array equality-filter selectors are supported, e.g. ".spec.disruption.consolidationPolicy" or ".spec.template.spec.requirements[?(@.key=="node.kubernetes.io/instance-type")]". |
| operation | string | Yes | Change operation: "replace", "merge", or "remove". An empty operation is treated as "replace"; a replace with a null recommendedValue removes the field. |
| currentValue | object | Yes | Current value at the path (string, number, boolean, array, object, or null) |
| recommendedValue | object | Yes | Recommended value (string, number, boolean, array, object, or null) |
| rationale | string | Yes | Human-readable explanation for this change |
InfraFitMeta
Response metadata for InfraFit endpoints
| Property | Type | Required | Description |
|---|---|---|---|
| timeframe | string | Yes | Analysis period echoed from the period query parameter (e.g. "P30D") |
| pagination | PaginationMeta | No | Cursor-based pagination metadata. Present in list responses; omitted for single-item responses. |
PaginationMeta
Cursor-based pagination metadata for list responses.
| Property | Type | Required | Description |
|---|---|---|---|
| next | string,null | Yes | Opaque cursor token for the next page, or null if this is the last page |
| prev | string,null | Yes | Opaque cursor token for the previous page, or null if this is the first page |
| pageSize | integer | Yes | Number of items per page used for this response |
Problem
RFC 9457 Problem Details error body, served as application/problem+json. code is a stable machine-readable identifier (e.g. filter_key_not_supported, not_found, internal_error); retryable indicates whether retrying the same request may succeed without client-side changes.
| Property | Type | Required | Description |
|---|---|---|---|
| type | string | Yes | URI reference identifying the problem type. |
| title | string | Yes | Short, human-readable summary of the problem type. |
| status | integer | Yes | HTTP status code generated by the origin server for this occurrence of the problem. |
| detail | string | No | Human-readable explanation specific to this occurrence of the problem. |
| instance | string | No | URI reference identifying the specific occurrence of the problem. |
| code | string | Yes | Stable machine-readable error code. |
| retryable | boolean | Yes | Whether retrying the same request may succeed without client-side changes. |
Download OpenAPI specification
Get a single node group with infra-fit data and recommendations
Returns a single node group by name. Same shape as one item from the list endpoint. Returns 404 if the group does not exist in the cluster.
Server: https://api.app.perfectscale.io/public/v1
Authentication (auth): http — bearer — JWT
GET /clusters/{clusterUid}/node-groups/{nodeGroupName}
Get a single node group with infra-fit data and recommendations
Returns a single node group by name. Same shape as one item from the list endpoint. Returns 404 if the group does not exist in the cluster.
Parameters
| Name | Location | Required | Type | Description |
|---|---|---|---|---|
| clusterUid | path | Yes | string | Cluster unique identifier |
| nodeGroupName | path | Yes | string | Node group name |
| period | query | No | InfraFitPeriod | Window for the node group's own utilization/idle-cost metrics (CPU, memory, running minutes, unrecognized-group detection). Does not affect recommendation savings/pricing math, which always uses a fixed 30-day window regardless of this value. Default P30D. |
| recommendationLimit | query | No | integer | Max recommended node types per group (Karpenter always returns full change set) |
Responses
| Status | Description | Body |
|---|---|---|
| 200 | Single node group | application/json: object |
| 400 | Invalid parameters | application/problem+json: Problem |
| 404 | Cluster or node group not found | application/problem+json: Problem |
| 500 | Internal server error | application/problem+json: Problem |
200 application/json body
| Property | Type | Required | Description |
|---|---|---|---|
| data | InfraFitNodeGroup | Yes | |
| meta | InfraFitMeta | Yes |
InfraFitPeriod
Analysis time period for infra-fit data.
"PT1H", "PT4H", "PT12H", "P1D", "P3D", "P1W", "P2W", "P4W", "P30D", "P45D"
InfraFitNodeGroup
A node group with utilization metrics, cost data, and recommendations.
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Node pool identifier used in single-group requests |
| architectures | array of InfraFitArchitecture | Yes | CPU architectures present in the group |
| reservations | array of InfraFitReservation | Yes | Reservation types present in the group |
| autoscalerType | InfraFitAutoscalerType | Yes | Autoscaler managing this group |
| nodes | InfraFitNodes | Yes | |
| runningMinutes | integer | Yes | Total running minutes across all nodes in the period |
| pods | InfraFitPods | Yes | |
| cost | InfraFitCost | Yes | |
| cpu | InfraFitCpuStats | Yes | |
| mem | InfraFitMemStats | Yes | |
| gpu | InfraFitGpuStats / null | Yes | |
| seen | InfraFitSeenTimestamps | Yes | |
| labels | object | Yes | Kubernetes labels on the node group |
| nodeTypes | array of InfraFitNodeType | Yes | Instance types running in this group |
| recommendations | InfraFitRecommendations | Yes |
InfraFitArchitecture
CPU architecture of nodes in an InfraFit node group
"amd64", "arm64"
InfraFitReservation
Reservation type of nodes in an InfraFit node group
"on_demand", "spot", "reserved"
InfraFitAutoscalerType
Autoscaler managing a node group
"karpenter", "cluster_autoscaler", "unknown"
InfraFitNodes
Node count statistics for the analysis period
| Property | Type | Required | Description |
|---|---|---|---|
| min | integer | Yes | Minimum observed node count in the period |
| max | integer | Yes | Maximum observed node count in the period |
| avg | number · double | Yes | Average node count in the period |
InfraFitPods
Pod count statistics for the node group
| Property | Type | Required | Description |
|---|---|---|---|
| capacity | integer | Yes | Maximum number of pods the node group can schedule |
| allocatable | integer | Yes | Maximum number of pods allocatable on the node group (Kubernetes limit per node × node count) |
| avgCount | number · double | Yes | Average number of pods running in the group |
InfraFitCost
Cost breakdown for the analysis period
| Property | Type | Required | Description |
|---|---|---|---|
| hourly | Money | Yes | |
| timeframe | Money | Yes | |
| idle | InfraFitCostIdle | Yes |
Money
Monetary amount with currency
| Property | Type | Required | Description |
|---|---|---|---|
| amount | string | Yes | Decimal string representation of the amount (e.g. "100.50") |
| currency | string | Yes | ISO 4217 currency code (e.g. "USD") |
InfraFitCostIdle
Idle cost breakdown by resource type
| Property | Type | Required | Description |
|---|---|---|---|
| total | Money | Yes | |
| cpu | Money | Yes | |
| gpu | Money / null | Yes | |
| mem | Money | Yes |
InfraFitCpuStats
CPU utilization statistics (cores)
| Property | Type | Required | Description |
|---|---|---|---|
| requested | object | Yes | CPU cores requested statistics |
| requested.minCores | number · double | Yes | Minimum CPU cores requested over the requested period |
| requested.maxCores | number · double | Yes | Maximum CPU cores requested over the requested period |
| requested.avgCores | number · double | Yes | Time-weighted median CPU cores requested over the requested period (single aggregate, not per-datapoint) |
| requested.p80Cores | number · double | Yes | 80th percentile CPU cores requested over the requested period |
| requested.p95Cores | number · double | Yes | 95th percentile CPU cores requested over the requested period |
| requested.p99Cores | number · double | Yes | 99th percentile CPU cores requested over the requested period |
| requested.p999Cores | number · double | Yes | 99.9th percentile CPU cores requested over the requested period |
| used | object | Yes | CPU cores used statistics |
| used.minCores | number · double | Yes | Minimum CPU cores used over the requested period |
| used.maxCores | number · double | Yes | Maximum CPU cores used over the requested period |
| used.avgCores | number · double | Yes | Time-weighted median CPU cores used over the requested period (single aggregate, not per-datapoint) |
| used.p80Cores | number · double | Yes | 80th percentile CPU cores used over the requested period |
| used.p95Cores | number · double | Yes | 95th percentile CPU cores used over the requested period |
| used.p99Cores | number · double | Yes | 99th percentile CPU cores used over the requested period |
| used.p999Cores | number · double | Yes | 99.9th percentile CPU cores used over the requested period |
| idleCores | number · double | Yes | Idle (unallocated) CPU cores — max(0, allocatable − avg used) |
InfraFitMemStats
Memory utilization statistics (MiB)
| Property | Type | Required | Description |
|---|---|---|---|
| requested | object | Yes | Memory requested statistics |
| requested.minMiB | number · double | Yes | Minimum memory requested in MiB over the requested period |
| requested.maxMiB | number · double | Yes | Maximum memory requested in MiB over the requested period |
| requested.avgMiB | number · double | Yes | Time-weighted median memory requested in MiB over the requested period (single aggregate, not per-datapoint) |
| requested.p80MiB | number · double | Yes | 80th percentile memory requested in MiB over the requested period |
| requested.p95MiB | number · double | Yes | 95th percentile memory requested in MiB over the requested period |
| requested.p99MiB | number · double | Yes | 99th percentile memory requested in MiB over the requested period |
| requested.p999MiB | number · double | Yes | 99.9th percentile memory requested in MiB over the requested period |
| used | object | Yes | Memory used statistics |
| used.minMiB | number · double | Yes | Minimum memory used in MiB over the requested period |
| used.maxMiB | number · double | Yes | Maximum memory used in MiB over the requested period |
| used.avgMiB | number · double | Yes | Time-weighted median memory used in MiB over the requested period (single aggregate, not per-datapoint) |
| used.p80MiB | number · double | Yes | 80th percentile memory used in MiB over the requested period |
| used.p95MiB | number · double | Yes | 95th percentile memory used in MiB over the requested period |
| used.p99MiB | number · double | Yes | 99th percentile memory used in MiB over the requested period |
| used.p999MiB | number · double | Yes | 99.9th percentile memory used in MiB over the requested period |
| idleMiB | number · double | Yes | Idle (unallocated) memory in MiB — max(0, allocatable − avg used) |
InfraFitGpuStats
GPU utilization statistics
| Property | Type | Required | Description |
|---|---|---|---|
| idle | InfraFitIdleGpu | Yes | |
| requested | InfraFitGpuSample | Yes | |
| used | InfraFitGpuSample | Yes | |
| architectures | array of string | Yes | GPU architectures present in the group (e.g. ampere, hopper), sorted |
| sharingType | array of string | Yes | Active GPU sharing mechanisms in lower_snake_case (e.g. "full", "time_slicing", "mps", "mig") |
InfraFitIdleGpu
Idle (unallocated) GPU resources
| Property | Type | Required | Description |
|---|---|---|---|
| units | number · double | Yes | Idle (unallocated) GPU units — max(0, allocatable − avg used) |
| memoryMiB | number · double | Yes | Idle (unallocated) GPU memory in MiB — max(0, capacity − avg used) |
InfraFitGpuSample
GPU sample statistics (time-weighted medians and percentiles)
| Property | Type | Required | Description |
|---|---|---|---|
| avgUnits | number · double | Yes | Time-weighted median GPU units |
| minUnits | number · double | Yes | Minimum GPU units over the period |
| maxUnits | number · double | Yes | Maximum GPU units over the period |
| p80Units | number · double | Yes | 80th percentile GPU units over the period |
| p95Units | number · double | Yes | 95th percentile GPU units over the period |
| p99Units | number · double | Yes | 99th percentile GPU units over the period |
| p999Units | number · double | Yes | 99.9th percentile GPU units over the period |
| avgMemoryMiB | number · double | Yes | Time-weighted median GPU memory in MiB |
| minMemoryMiB | number · double | Yes | Minimum GPU memory in MiB over the period |
| maxMemoryMiB | number · double | Yes | Maximum GPU memory in MiB over the period |
| p80MemoryMiB | number · double | Yes | 80th percentile GPU memory in MiB over the period |
| p95MemoryMiB | number · double | Yes | 95th percentile GPU memory in MiB over the period |
| p99MemoryMiB | number · double | Yes | 99th percentile GPU memory in MiB over the period |
| p999MemoryMiB | number · double | Yes | 99.9th percentile GPU memory in MiB over the period |
InfraFitSeenTimestamps
First and last observed timestamps
| Property | Type | Required | Description |
|---|---|---|---|
| firstTime | string · date-time | Yes | When first observed (RFC 3339 UTC) |
| lastTime | string · date-time | Yes | When last observed (RFC 3339 UTC) |
InfraFitNodeType
Instance type breakdown within a node group
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Instance type identifier (matches instance.type) |
| instance | InfraFitInstanceInfo | Yes | |
| isSpot | boolean | Yes | Whether this instance type runs on spot/preemptible capacity |
| nodes | InfraFitNodes | Yes | |
| cost | InfraFitCost | Yes | |
| runningMinutes | integer | Yes | Total running minutes across all nodes of this instance type in the period |
| pods | InfraFitPods | Yes | |
| cpu | InfraFitCpuStats | Yes | |
| mem | InfraFitMemStats | Yes | |
| gpu | InfraFitNodeTypeGpu / null | Yes | |
| seen | InfraFitSeenTimestamps | Yes |
InfraFitInstanceInfo
Instance type identity and capacity
| Property | Type | Required | Description |
|---|---|---|---|
| type | string | Yes | Cloud instance type identifier (e.g. m5.2xlarge) |
| family | string | Yes | Instance family prefix shared by related instance types (e.g. m5) |
| architecture | InfraFitArchitecture / null | Yes | CPU architecture of this instance type (null when unknown) |
| cpu | InfraFitInstanceCpu | Yes | |
| mem | InfraFitInstanceMem | Yes | |
| gpu | InfraFitInstanceGpu / null | Yes | GPU capacity, null for non-GPU instance types |
InfraFitInstanceCpu
CPU capacity for an instance type
| Property | Type | Required | Description |
|---|---|---|---|
| capacityCores | number · double | Yes | vCPU count per instance |
| allocatableCores | number · double | Yes | Allocatable vCPU per instance after Kubernetes system-reserved resources are subtracted |
InfraFitInstanceMem
Memory capacity for an instance type
| Property | Type | Required | Description |
|---|---|---|---|
| capacityMiB | number · double | Yes | Memory capacity per instance in MiB |
| allocatableMiB | number · double | Yes | Allocatable memory per instance in MiB after Kubernetes system-reserved resources are subtracted |
InfraFitInstanceGpu
GPU capacity for an instance type
| Property | Type | Required | Description |
|---|---|---|---|
| capacityUnits | number · double | Yes | GPU unit count per instance |
| allocatableUnits | number · double | Yes | Allocatable GPU units per instance after Kubernetes system-reserved resources are subtracted |
| memCapacityMiB | number · double | Yes | Total GPU memory capacity per instance in MiB |
InfraFitNodeTypeGpu
GPU stats for an instance type
| Property | Type | Required | Description |
|---|---|---|---|
| idle | InfraFitIdleGpu | Yes | |
| requested | InfraFitGpuSample | Yes | |
| used | InfraFitGpuSample | Yes | |
| architectures | array of string | Yes | GPU architectures present in the instance type (e.g. ampere, hopper), sorted |
InfraFitRecommendations
Discriminated recommendations object. Routed by autoscalerType: cluster_autoscaler/managed → standard, karpenter → karpenter. Always present, never omitted.
InfraFitStandardRecommendations / InfraFitKarpenterRecommendations
InfraFitStandardRecommendations
Recommendations for Cluster-Autoscaler and managed node groups
| Property | Type | Required | Description |
|---|---|---|---|
| type | "standard" | Yes | |
| hasChanges | boolean | Yes | Whether any instance type changes are recommended |
| nodeTypes | array of InfraFitRecommendedNodeType | Yes | Recommended instance types, capped at recommendationLimit |
InfraFitRecommendedNodeType
A recommended instance type replacement
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Unique identifier for this recommendation entry (matches instanceType) |
| instanceType | string | Yes | Recommended cloud instance type identifier (e.g. m6g.xlarge) |
| instanceFamily | string | Yes | Instance family prefix of the recommended type (e.g. m6g) |
| hourlyCost | Money | Yes | |
| estimatedSavings | Money | Yes | |
| estimatedSavingsPct | number · double | Yes | Savings as percentage of current group cost |
| nodeCount | integer | Yes | Recommended number of nodes of this type |
InfraFitKarpenterRecommendations
Recommendations for Karpenter-managed node pools
| Property | Type | Required | Description |
|---|---|---|---|
| type | "karpenter" | Yes | |
| hasChanges | boolean | Yes | Whether any configuration changes are recommended |
| currentConfig | object | Yes | Current raw Karpenter NodePool CR (full JSON) |
| recommendedConfig | object | Yes | Patched NodePool CR with all recommended changes applied |
| changes | array of InfraFitKarpenterChange | Yes | Structured change set (always full, not capped by recommendationLimit) |
InfraFitKarpenterChange
A single Karpenter configuration change recommendation
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Unique identifier for this change entry (matches path) |
| title | string | Yes | Human-readable change title |
| path | string | Yes | JSONPath (RFC 9535 syntax) into the NodePool CR. Nested keys and array equality-filter selectors are supported, e.g. ".spec.disruption.consolidationPolicy" or ".spec.template.spec.requirements[?(@.key=="node.kubernetes.io/instance-type")]". |
| operation | string | Yes | Change operation: "replace", "merge", or "remove". An empty operation is treated as "replace"; a replace with a null recommendedValue removes the field. |
| currentValue | object | Yes | Current value at the path (string, number, boolean, array, object, or null) |
| recommendedValue | object | Yes | Recommended value (string, number, boolean, array, object, or null) |
| rationale | string | Yes | Human-readable explanation for this change |
InfraFitMeta
Response metadata for InfraFit endpoints
| Property | Type | Required | Description |
|---|---|---|---|
| timeframe | string | Yes | Analysis period echoed from the period query parameter (e.g. "P30D") |
| pagination | PaginationMeta | No | Cursor-based pagination metadata. Present in list responses; omitted for single-item responses. |
PaginationMeta
Cursor-based pagination metadata for list responses.
| Property | Type | Required | Description |
|---|---|---|---|
| next | string,null | Yes | Opaque cursor token for the next page, or null if this is the last page |
| prev | string,null | Yes | Opaque cursor token for the previous page, or null if this is the first page |
| pageSize | integer | Yes | Number of items per page used for this response |
Problem
RFC 9457 Problem Details error body, served as application/problem+json. code is a stable machine-readable identifier (e.g. filter_key_not_supported, not_found, internal_error); retryable indicates whether retrying the same request may succeed without client-side changes.
| Property | Type | Required | Description |
|---|---|---|---|
| type | string | Yes | URI reference identifying the problem type. |
| title | string | Yes | Short, human-readable summary of the problem type. |
| status | integer | Yes | HTTP status code generated by the origin server for this occurrence of the problem. |
| detail | string | No | Human-readable explanation specific to this occurrence of the problem. |
| instance | string | No | URI reference identifying the specific occurrence of the problem. |
| code | string | Yes | Stable machine-readable error code. |
| retryable | boolean | Yes | Whether retrying the same request may succeed without client-side changes. |
Download OpenAPI specification
List unevictable pods in a cluster
Returns the pods from the latest pre-computed unevictable-pods snapshot for the cluster (no request-time recompute). Tenant resolved from the auth token; a cluster belonging to another tenant returns 404.
Server: https://api.app.perfectscale.io/public/v1
Authentication (auth): http — bearer — JWT
GET /clusters/{clusterUid}/unevictable-pods
List unevictable pods in a cluster
Returns the pods from the latest pre-computed unevictable-pods snapshot for the cluster (no request-time recompute). Tenant resolved from the auth token; a cluster belonging to another tenant returns 404.
Parameters
| Name | Location | Required | Type | Description |
|---|---|---|---|---|
| clusterUid | path | Yes | string | Cluster unique identifier |
| filter | query | No | string | Composite filter expression: clauses of the form key[:op]:value joined by | (AND); op is optional and defaults to eq; comma-separate values within a clause for an IN match, e.g. filter=namespace:payments|blockedCostHourly:gte:10. Supported keys for this endpoint: namespace (eq), blockedCostHourly (eq/gte/lte, compares numerically on the underlying cost value, not the serialized Money object), reasonCode (eq), nodeGroup (eq), labels.<key> (eq). labels.<key> matches against the pod's Kubernetes labels — for example filter=labels.team:payments matches pods labeled team=payments. An unsupported key returns 400 with code: "filter_key_not_supported". Mute-status filtering is handled by the separate mute parameter, not this filter. |
| mute | query | No | "exclude", "include", "only" | Muted-finding handling: exclude (default) hides pods whose workload has a dismissal rule; include returns all pods, flagging muted ones via mute/mutedByRule on each reason; only returns exclusively muted pods, for auditing what's been silenced. |
| sortBy | query | No | "blockedCostHourly" | Field to sort results by. blockedCostHourly sorts numerically on the underlying cost value, not the serialized Money object. Unset falls back to a stable but unspecified order (currently pod UID). Ties are always broken by UID for stable pagination. |
| sortOrder | query | No | "asc", "desc" | Sort direction, applied only when sortBy is set. |
| pageSize | query | No | integer | Number of items per page (default 50, max 500) |
| pageToken | query | No | string | Opaque cursor token for pagination |
Responses
| Status | Description | Body |
|---|---|---|
| 200 | List of unevictable pods | application/json: object |
| 202 | Raw snapshot exists but is still being processed | application/json: object |
| 400 | Invalid parameters | application/problem+json: Problem |
| 404 | Cluster or snapshot not found | application/problem+json: Problem |
| 422 | Raw snapshot exists but processing failed | application/problem+json: Problem |
| 500 | Internal server error | application/problem+json: Problem |
200 application/json body
| Property | Type | Required | Description |
|---|---|---|---|
| data | array of UnevictablePod | Yes | |
| meta | object | Yes | |
| meta.pagination | PaginationMeta | Yes | |
| meta.snapshotTime | string · date-time | Yes | Timestamp (RFC 3339, UTC) of the snapshot the data was read from |
| meta.algorithmVersion | string | Yes | Version of the unevictable-detection algorithm/library used to produce the snapshot |
| meta.summary | UnevictableSummary | Yes |
202 application/json body
| Property | Type | Required | Description |
|---|---|---|---|
| data | UnevictablePodsStatus | Yes |
UnevictablePod
A single unevictable pod from the latest pre-computed snapshot for the cluster. Returned both as a list item and as the single-pod detail response — the detail response additionally populates siblingPodNames.
| Property | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | |
| namespace | string | Yes | |
| id | string | Yes | |
| workload | UnevictableWorkloadRef | Yes | |
| reasons | array of UnevictableReason | Yes | Empty = pod is evictable; non-empty = unevictable. |
| phase | string | Yes | |
| startTime | string · date-time | Yes | Pod creation timestamp (RFC 3339 UTC). |
| labels | object | No | |
| annotations | object | No | |
| spec | UnevictablePodSpec | No | |
| blockedNodeCount | integer | No | Number of nodes this pod blocks from scaling down. |
| blockedNodes | array of string | No | Names of the nodes this pod pins. |
| blockedCostHourly | Money | No | Hourly cost of the blocked nodes (Total Blocked Cost). Filtering (blockedCostHourly:gte:<amount>) and sorting compare numerically on the underlying cost value, not the serialized Money object. |
| clusterUid | string | No | |
| mute | boolean | No | True when the pod's workload is muted by a dismissal rule, muting all of its reasons. |
| siblingPodNames | array of string | No | Names of other pods of the same workload id in this snapshot. Populated only by the single-pod detail endpoint. |
UnevictableWorkloadRef
Identity of the pod's top-level owning workload.
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Canonical workload id (namespace-kind-name) of the top-level controller. |
| name | string | No | Denormalized workload name for display. |
| type | string | Yes | Kubernetes workload kind (e.g. Deployment, StatefulSet, DaemonSet). |
UnevictableReason
| Property | Type | Required | Description |
|---|---|---|---|
| reason | string | Yes | Short reason code (e.g. "Topology-Locked", "PDB Violation"). |
| reasonCode | UnevictableReasonCode / null | No | Stable slug derived from the display reason. Null for unrecognised reasons. |
| details | string | Yes | Human-readable explanation. |
| remediation | UnevictableRemediation | No | |
| mute | boolean | No | True when this reason is covered by a dismissal rule and therefore muted. |
| mutedByRule | UnevictableMutedByRule / null | No |
UnevictableReasonCode
Stable canonical identifier for an unevictable reason. Decoupled from the mutable display string.
"opt_out_annotation", "pod_disruption_budget", "strict_affinity", "strict_anti_affinity", "topology_locked", "taints_not_tolerated", "local_node_storage", "static_mirror_pod"
UnevictableRemediation
Reason-specific fix. current/recommended spec and the yaml diff are null for partial/informational cases.
| Property | Type | Required | Description |
|---|---|---|---|
| fixSummary | string | Yes | One-line plain-language fix. |
| risk | "none", "low", "medium", "high" | Yes | |
| confidence | "low", "medium", "high" | Yes | |
| currentSpec | string,null | No | Rendered YAML of the current spec; null for partial/informational cases. |
| recommendedSpec | string,null | No | Rendered YAML of the recommended spec; null for partial/informational cases. |
| yamlDiff | string,null | No | Unified diff string; null when there is no clean diff. |
UnevictableMutedByRule
Summary of the dismissal rule that suppressed this finding.
| Property | Type | Required | Description |
|---|---|---|---|
| note | string,null | No | |
| createdBy | string | Yes | Email of the user who created the rule. |
| createTime | string · date-time | Yes | When the rule was created (RFC 3339 UTC) |
UnevictablePodSpec
Raw Kubernetes PodSpec fields used by detection, verbatim from the pod.
| Property | Type | Required | Description |
|---|---|---|---|
| node | string,null | No | Node the pod is scheduled on (spec.nodeName); null for Pending pods. |
| nodeGroup | string | No | Node group the pod's node belongs to; empty if the node's node group is unresolved. |
| priority | integer | No | Kubernetes pod scheduling priority (spec.priority, from the pod's PriorityClass). |
| nodeSelector | object | No | |
| affinity | UnevictablePodAffinity | No | |
| tolerations | array of UnevictablePodToleration | No | |
| containers | array of UnevictablePodContainer | No | |
| volumes | array of UnevictablePodVolume | No | |
| topologySpreadConstraints | array of UnevictablePodTopologySpreadConstraint | No | |
| ownerReferences | array of UnevictablePodOwnerReference | No | The pod's metadata.ownerReferences, as the subset of fields described above. Omitted when the pod has no owner (e.g. static/mirror pods — see the static_mirror_pod reason code). |
UnevictablePodAffinity
Simplified affinity block — only the sub-fields used by detection are modelled.
| Property | Type | Required | Description |
|---|---|---|---|
| nodeAffinity | object | No | |
| podAffinity | object | No | |
| podAntiAffinity | object | No |
UnevictablePodToleration
| Property | Type | Required | Description |
|---|---|---|---|
| key | string | Yes | |
| operator | string | Yes | |
| value | string | No | |
| effect | string | Yes |
UnevictablePodContainer
| Property | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | |
| image | string | Yes | |
| cpuRequestCores | number,null · double | No | CPU requested for the container, in cores; null if unset. |
| cpuLimitCores | number,null · double | No | CPU limit for the container, in cores; null if unset. |
| memoryRequestMiB | number,null · double | No | Memory requested for the container, in MiB; null if unset. |
| memoryLimitMiB | number,null · double | No | Memory limit for the container, in MiB; null if unset. |
| gpuRequest | integer,null | No | GPU units requested for the container (e.g. nvidia.com/gpu); null if unset. GPU requests/limits are always whole units. |
| gpuLimit | integer,null | No | GPU units the container is limited to (e.g. nvidia.com/gpu); null if unset. GPU requests/limits are always whole units. |
UnevictablePodVolume
| Property | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | |
| hostPath | string | No | |
| emptyDir | string | No | |
| pvcClaimName | string | No |
UnevictablePodTopologySpreadConstraint
| Property | Type | Required | Description |
|---|---|---|---|
| maxSkew | integer · int32 | Yes | |
| topologyKey | string | Yes | |
| whenUnsatisfiable | string | Yes | |
| labelSelector | object | No |
UnevictablePodOwnerReference
A subset of the pod's Kubernetes OwnerReference fields (apiVersion, kind, name, controller) used for ownership detection; not a complete copy of metadata.ownerReferences (e.g. uid is omitted).
| Property | Type | Required | Description |
|---|---|---|---|
| apiVersion | string | Yes | |
| kind | string | Yes | |
| name | string | Yes | |
| controller | boolean,null | No | True when this reference is the pod's managing controller. |
Money
Monetary amount with currency
| Property | Type | Required | Description |
|---|---|---|---|
| amount | string | Yes | Decimal string representation of the amount (e.g. "100.50") |
| currency | string | Yes | ISO 4217 currency code (e.g. "USD") |
PaginationMeta
Cursor-based pagination metadata for list responses.
| Property | Type | Required | Description |
|---|---|---|---|
| next | string,null | Yes | Opaque cursor token for the next page, or null if this is the last page |
| prev | string,null | Yes | Opaque cursor token for the previous page, or null if this is the first page |
| pageSize | integer | Yes | Number of items per page used for this response |
UnevictableSummary
Aggregate pod/node counts for the snapshot backing the listing response.
| Property | Type | Required | Description |
|---|---|---|---|
| totalPods | integer | Yes | Total number of pods observed in the snapshot. |
| unevictablePods | integer | Yes | Number of pods detected as unevictable in the snapshot. |
| mute | integer | Yes | Number of unevictable findings muted by a dismissal rule in this snapshot. |
| totalNodes | integer | Yes | Total number of nodes observed in the snapshot. |
| autoscalerType | string | No | Detected autoscaler, rolled up from per-node detection (canonical values, e.g. "cluster_autoscaler", "karpenter", "castai", "eks_auto_mode"). Omitted if not detected. Results written before PSD-9016 may carry the legacy hyphenated "cluster-autoscaler". |
UnevictablePodsStatus
Snapshot processing status, returned on 202 (still processing) and 422 (processing failed) instead of pod/report data.
| Property | Type | Required | Description |
|---|---|---|---|
| status | "processing", "failed" | Yes |
Problem
RFC 9457 Problem Details error body, served as application/problem+json. code is a stable machine-readable identifier (e.g. filter_key_not_supported, not_found, internal_error); retryable indicates whether retrying the same request may succeed without client-side changes.
| Property | Type | Required | Description |
|---|---|---|---|
| type | string | Yes | URI reference identifying the problem type. |
| title | string | Yes | Short, human-readable summary of the problem type. |
| status | integer | Yes | HTTP status code generated by the origin server for this occurrence of the problem. |
| detail | string | No | Human-readable explanation specific to this occurrence of the problem. |
| instance | string | No | URI reference identifying the specific occurrence of the problem. |
| code | string | Yes | Stable machine-readable error code. |
| retryable | boolean | Yes | Whether retrying the same request may succeed without client-side changes. |
Download OpenAPI specification
Per-pod unevictable report — one row per pod, with all its reasons combined
Issues view — one row per pod, carrying all of that pod's unevictable reasons. Served from the latest pre-computed snapshot (no request-time recompute). Tenant resolved from the auth token; a cluster belonging to another tenant returns 404.
Server: https://api.app.perfectscale.io/public/v1
Authentication (auth): http — bearer — JWT
GET /clusters/{clusterUid}/unevictable-report
Per-pod unevictable report — one row per pod, with all its reasons combined
Issues view — one row per pod, carrying all of that pod's unevictable reasons. Served from the latest pre-computed snapshot (no request-time recompute). Tenant resolved from the auth token; a cluster belonging to another tenant returns 404.
Parameters
| Name | Location | Required | Type | Description |
|---|---|---|---|---|
| clusterUid | path | Yes | string | Cluster unique identifier |
| filter | query | No | string | Composite filter expression: clauses of the form key[:op]:value joined by | (AND); op is optional and defaults to eq; comma-separate values within a clause for an IN match. Supported keys for this endpoint: namespace (eq), blockedCostHourly (eq/gte/lte, compares numerically on the underlying cost value, not the serialized Money object), nodeGroup (eq), labels.<key> (eq). labels.<key> matches against the pod's Kubernetes labels — for example filter=labels.team:payments matches pods labeled team=payments. An unsupported key returns 400 with code: "filter_key_not_supported". Mute-status filtering is handled by the separate mute parameter, not this filter. |
| mute | query | No | "exclude", "include", "only" | Muted-finding handling: exclude (default) hides rows whose workload has a dismissal rule; include returns all rows, flagged via mute; only returns exclusively muted rows, for auditing what's been silenced. |
| sortBy | query | No | "blockedCostHourly" | Field to sort results by. blockedCostHourly sorts numerically on the underlying cost value, not the serialized Money object. Unset falls back to a stable but unspecified order (currently pod UID). Ties are always broken by UID for stable pagination. |
| sortOrder | query | No | "asc", "desc" | Sort direction, applied only when sortBy is set. |
| pageSize | query | No | integer | Number of items per page (default 50, max 500) |
| pageToken | query | No | string | Opaque cursor token for pagination |
Responses
| Status | Description | Body |
|---|---|---|
| 200 | List of unevictable pod issue rows | application/json: object |
| 202 | Raw snapshot exists but is still being processed | application/json: object |
| 400 | Invalid parameters | application/problem+json: Problem |
| 404 | Cluster or snapshot not found | application/problem+json: Problem |
| 422 | Raw snapshot exists but processing failed | application/problem+json: Problem |
| 500 | Internal server error | application/problem+json: Problem |
200 application/json body
| Property | Type | Required | Description |
|---|---|---|---|
| data | array of UnevictableReportRow | Yes | |
| meta | object | Yes | |
| meta.pagination | PaginationMeta | Yes | |
| meta.snapshotTime | string · date-time | Yes | Timestamp (RFC 3339, UTC) of the snapshot the data was read from |
| meta.algorithmVersion | string | Yes | Version of the unevictable-detection algorithm/library used to produce the snapshot |
| meta.summary | UnevictableSummary | Yes |
202 application/json body
| Property | Type | Required | Description |
|---|---|---|---|
| data | UnevictablePodsStatus | Yes |
UnevictableReportRow
One row of the per-pod issues view — a single unevictable pod with all its reasons combined.
| Property | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | |
| id | string | Yes | |
| workload | UnevictableWorkloadRef | Yes | |
| namespace | string | Yes | |
| labels | object | No | |
| node | string,null | No | Node the pod is scheduled on; null for Pending pods. |
| nodeGroup | string | No | Node group the pod's node belongs to; empty if the node's node group is unresolved. |
| reasons | array of UnevictableReason | Yes | All unevictable reasons for this pod. |
| mute | boolean | Yes | True when the pod's workload is muted by a dismissal rule, muting all of its reasons. |
| priority | integer | No | Kubernetes pod scheduling priority (from the pod's PriorityClass); same value as UnevictablePod.spec.priority. |
| blockedCostHourly | Money | No | Hourly cost of the blocked nodes. Filtering (blockedCostHourly:gte:<amount>) and sorting compare numerically on the underlying cost value, not the serialized Money object. |
UnevictableWorkloadRef
Identity of the pod's top-level owning workload.
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Canonical workload id (namespace-kind-name) of the top-level controller. |
| name | string | No | Denormalized workload name for display. |
| type | string | Yes | Kubernetes workload kind (e.g. Deployment, StatefulSet, DaemonSet). |
UnevictableReason
| Property | Type | Required | Description |
|---|---|---|---|
| reason | string | Yes | Short reason code (e.g. "Topology-Locked", "PDB Violation"). |
| reasonCode | UnevictableReasonCode / null | No | Stable slug derived from the display reason. Null for unrecognised reasons. |
| details | string | Yes | Human-readable explanation. |
| remediation | UnevictableRemediation | No | |
| mute | boolean | No | True when this reason is covered by a dismissal rule and therefore muted. |
| mutedByRule | UnevictableMutedByRule / null | No |
UnevictableReasonCode
Stable canonical identifier for an unevictable reason. Decoupled from the mutable display string.
"opt_out_annotation", "pod_disruption_budget", "strict_affinity", "strict_anti_affinity", "topology_locked", "taints_not_tolerated", "local_node_storage", "static_mirror_pod"
UnevictableRemediation
Reason-specific fix. current/recommended spec and the yaml diff are null for partial/informational cases.
| Property | Type | Required | Description |
|---|---|---|---|
| fixSummary | string | Yes | One-line plain-language fix. |
| risk | "none", "low", "medium", "high" | Yes | |
| confidence | "low", "medium", "high" | Yes | |
| currentSpec | string,null | No | Rendered YAML of the current spec; null for partial/informational cases. |
| recommendedSpec | string,null | No | Rendered YAML of the recommended spec; null for partial/informational cases. |
| yamlDiff | string,null | No | Unified diff string; null when there is no clean diff. |
UnevictableMutedByRule
Summary of the dismissal rule that suppressed this finding.
| Property | Type | Required | Description |
|---|---|---|---|
| note | string,null | No | |
| createdBy | string | Yes | Email of the user who created the rule. |
| createTime | string · date-time | Yes | When the rule was created (RFC 3339 UTC) |
Money
Monetary amount with currency
| Property | Type | Required | Description |
|---|---|---|---|
| amount | string | Yes | Decimal string representation of the amount (e.g. "100.50") |
| currency | string | Yes | ISO 4217 currency code (e.g. "USD") |
PaginationMeta
Cursor-based pagination metadata for list responses.
| Property | Type | Required | Description |
|---|---|---|---|
| next | string,null | Yes | Opaque cursor token for the next page, or null if this is the last page |
| prev | string,null | Yes | Opaque cursor token for the previous page, or null if this is the first page |
| pageSize | integer | Yes | Number of items per page used for this response |
UnevictableSummary
Aggregate pod/node counts for the snapshot backing the listing response.
| Property | Type | Required | Description |
|---|---|---|---|
| totalPods | integer | Yes | Total number of pods observed in the snapshot. |
| unevictablePods | integer | Yes | Number of pods detected as unevictable in the snapshot. |
| mute | integer | Yes | Number of unevictable findings muted by a dismissal rule in this snapshot. |
| totalNodes | integer | Yes | Total number of nodes observed in the snapshot. |
| autoscalerType | string | No | Detected autoscaler, rolled up from per-node detection (canonical values, e.g. "cluster_autoscaler", "karpenter", "castai", "eks_auto_mode"). Omitted if not detected. Results written before PSD-9016 may carry the legacy hyphenated "cluster-autoscaler". |
UnevictablePodsStatus
Snapshot processing status, returned on 202 (still processing) and 422 (processing failed) instead of pod/report data.
| Property | Type | Required | Description |
|---|---|---|---|
| status | "processing", "failed" | Yes |
Problem
RFC 9457 Problem Details error body, served as application/problem+json. code is a stable machine-readable identifier (e.g. filter_key_not_supported, not_found, internal_error); retryable indicates whether retrying the same request may succeed without client-side changes.
| Property | Type | Required | Description |
|---|---|---|---|
| type | string | Yes | URI reference identifying the problem type. |
| title | string | Yes | Short, human-readable summary of the problem type. |
| status | integer | Yes | HTTP status code generated by the origin server for this occurrence of the problem. |
| detail | string | No | Human-readable explanation specific to this occurrence of the problem. |
| instance | string | No | URI reference identifying the specific occurrence of the problem. |
| code | string | Yes | Stable machine-readable error code. |
| retryable | boolean | Yes | Whether retrying the same request may succeed without client-side changes. |
Download OpenAPI specification
Get a single unevictable pod
Full detail for one pod (all reasons with the full remediation object), served from the latest pre-computed snapshot (no request-time recompute). Tenant resolved from the auth token; a cluster belonging to another tenant, or a pod not present in the latest snapshot, returns 404.
Server: https://api.app.perfectscale.io/public/v1
Authentication (auth): http — bearer — JWT
GET /clusters/{clusterUid}/unevictable-pods/{podUid}
Get a single unevictable pod
Full detail for one pod (all reasons with the full remediation object), served from the latest pre-computed snapshot (no request-time recompute). Tenant resolved from the auth token; a cluster belonging to another tenant, or a pod not present in the latest snapshot, returns 404.
Parameters
| Name | Location | Required | Type | Description |
|---|---|---|---|---|
| clusterUid | path | Yes | string | Cluster unique identifier |
| podUid | path | Yes | string | Pod unique identifier |
Responses
| Status | Description | Body |
|---|---|---|
| 200 | Single unevictable pod, returned directly (no envelope) | application/json: UnevictablePod |
| 202 | Raw snapshot exists but is still being processed, returned directly (no envelope) | application/json: UnevictablePodsStatus |
| 404 | Cluster or snapshot not found, or no pod with this uid in the latest snapshot | application/problem+json: Problem |
| 422 | Raw snapshot exists but processing failed | application/problem+json: Problem |
| 500 | Internal server error | application/problem+json: Problem |
UnevictablePod
A single unevictable pod from the latest pre-computed snapshot for the cluster. Returned both as a list item and as the single-pod detail response — the detail response additionally populates siblingPodNames.
| Property | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | |
| namespace | string | Yes | |
| id | string | Yes | |
| workload | UnevictableWorkloadRef | Yes | |
| reasons | array of UnevictableReason | Yes | Empty = pod is evictable; non-empty = unevictable. |
| phase | string | Yes | |
| startTime | string · date-time | Yes | Pod creation timestamp (RFC 3339 UTC). |
| labels | object | No | |
| annotations | object | No | |
| spec | UnevictablePodSpec | No | |
| blockedNodeCount | integer | No | Number of nodes this pod blocks from scaling down. |
| blockedNodes | array of string | No | Names of the nodes this pod pins. |
| blockedCostHourly | Money | No | Hourly cost of the blocked nodes (Total Blocked Cost). Filtering (blockedCostHourly:gte:<amount>) and sorting compare numerically on the underlying cost value, not the serialized Money object. |
| clusterUid | string | No | |
| mute | boolean | No | True when the pod's workload is muted by a dismissal rule, muting all of its reasons. |
| siblingPodNames | array of string | No | Names of other pods of the same workload id in this snapshot. Populated only by the single-pod detail endpoint. |
UnevictableWorkloadRef
Identity of the pod's top-level owning workload.
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Canonical workload id (namespace-kind-name) of the top-level controller. |
| name | string | No | Denormalized workload name for display. |
| type | string | Yes | Kubernetes workload kind (e.g. Deployment, StatefulSet, DaemonSet). |
UnevictableReason
| Property | Type | Required | Description |
|---|---|---|---|
| reason | string | Yes | Short reason code (e.g. "Topology-Locked", "PDB Violation"). |
| reasonCode | UnevictableReasonCode / null | No | Stable slug derived from the display reason. Null for unrecognised reasons. |
| details | string | Yes | Human-readable explanation. |
| remediation | UnevictableRemediation | No | |
| mute | boolean | No | True when this reason is covered by a dismissal rule and therefore muted. |
| mutedByRule | UnevictableMutedByRule / null | No |
UnevictableReasonCode
Stable canonical identifier for an unevictable reason. Decoupled from the mutable display string.
"opt_out_annotation", "pod_disruption_budget", "strict_affinity", "strict_anti_affinity", "topology_locked", "taints_not_tolerated", "local_node_storage", "static_mirror_pod"
UnevictableRemediation
Reason-specific fix. current/recommended spec and the yaml diff are null for partial/informational cases.
| Property | Type | Required | Description |
|---|---|---|---|
| fixSummary | string | Yes | One-line plain-language fix. |
| risk | "none", "low", "medium", "high" | Yes | |
| confidence | "low", "medium", "high" | Yes | |
| currentSpec | string,null | No | Rendered YAML of the current spec; null for partial/informational cases. |
| recommendedSpec | string,null | No | Rendered YAML of the recommended spec; null for partial/informational cases. |
| yamlDiff | string,null | No | Unified diff string; null when there is no clean diff. |
UnevictableMutedByRule
Summary of the dismissal rule that suppressed this finding.
| Property | Type | Required | Description |
|---|---|---|---|
| note | string,null | No | |
| createdBy | string | Yes | Email of the user who created the rule. |
| createTime | string · date-time | Yes | When the rule was created (RFC 3339 UTC) |
UnevictablePodSpec
Raw Kubernetes PodSpec fields used by detection, verbatim from the pod.
| Property | Type | Required | Description |
|---|---|---|---|
| node | string,null | No | Node the pod is scheduled on (spec.nodeName); null for Pending pods. |
| nodeGroup | string | No | Node group the pod's node belongs to; empty if the node's node group is unresolved. |
| priority | integer | No | Kubernetes pod scheduling priority (spec.priority, from the pod's PriorityClass). |
| nodeSelector | object | No | |
| affinity | UnevictablePodAffinity | No | |
| tolerations | array of UnevictablePodToleration | No | |
| containers | array of UnevictablePodContainer | No | |
| volumes | array of UnevictablePodVolume | No | |
| topologySpreadConstraints | array of UnevictablePodTopologySpreadConstraint | No | |
| ownerReferences | array of UnevictablePodOwnerReference | No | The pod's metadata.ownerReferences, as the subset of fields described above. Omitted when the pod has no owner (e.g. static/mirror pods — see the static_mirror_pod reason code). |
UnevictablePodAffinity
Simplified affinity block — only the sub-fields used by detection are modelled.
| Property | Type | Required | Description |
|---|---|---|---|
| nodeAffinity | object | No | |
| podAffinity | object | No | |
| podAntiAffinity | object | No |
UnevictablePodToleration
| Property | Type | Required | Description |
|---|---|---|---|
| key | string | Yes | |
| operator | string | Yes | |
| value | string | No | |
| effect | string | Yes |
UnevictablePodContainer
| Property | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | |
| image | string | Yes | |
| cpuRequestCores | number,null · double | No | CPU requested for the container, in cores; null if unset. |
| cpuLimitCores | number,null · double | No | CPU limit for the container, in cores; null if unset. |
| memoryRequestMiB | number,null · double | No | Memory requested for the container, in MiB; null if unset. |
| memoryLimitMiB | number,null · double | No | Memory limit for the container, in MiB; null if unset. |
| gpuRequest | integer,null | No | GPU units requested for the container (e.g. nvidia.com/gpu); null if unset. GPU requests/limits are always whole units. |
| gpuLimit | integer,null | No | GPU units the container is limited to (e.g. nvidia.com/gpu); null if unset. GPU requests/limits are always whole units. |
UnevictablePodVolume
| Property | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | |
| hostPath | string | No | |
| emptyDir | string | No | |
| pvcClaimName | string | No |
UnevictablePodTopologySpreadConstraint
| Property | Type | Required | Description |
|---|---|---|---|
| maxSkew | integer · int32 | Yes | |
| topologyKey | string | Yes | |
| whenUnsatisfiable | string | Yes | |
| labelSelector | object | No |
UnevictablePodOwnerReference
A subset of the pod's Kubernetes OwnerReference fields (apiVersion, kind, name, controller) used for ownership detection; not a complete copy of metadata.ownerReferences (e.g. uid is omitted).
| Property | Type | Required | Description |
|---|---|---|---|
| apiVersion | string | Yes | |
| kind | string | Yes | |
| name | string | Yes | |
| controller | boolean,null | No | True when this reference is the pod's managing controller. |
Money
Monetary amount with currency
| Property | Type | Required | Description |
|---|---|---|---|
| amount | string | Yes | Decimal string representation of the amount (e.g. "100.50") |
| currency | string | Yes | ISO 4217 currency code (e.g. "USD") |
UnevictablePodsStatus
Snapshot processing status, returned on 202 (still processing) and 422 (processing failed) instead of pod/report data.
| Property | Type | Required | Description |
|---|---|---|---|
| status | "processing", "failed" | Yes |
Problem
RFC 9457 Problem Details error body, served as application/problem+json. code is a stable machine-readable identifier (e.g. filter_key_not_supported, not_found, internal_error); retryable indicates whether retrying the same request may succeed without client-side changes.
| Property | Type | Required | Description |
|---|---|---|---|
| type | string | Yes | URI reference identifying the problem type. |
| title | string | Yes | Short, human-readable summary of the problem type. |
| status | integer | Yes | HTTP status code generated by the origin server for this occurrence of the problem. |
| detail | string | No | Human-readable explanation specific to this occurrence of the problem. |
| instance | string | No | URI reference identifying the specific occurrence of the problem. |
| code | string | Yes | Stable machine-readable error code. |
| retryable | boolean | Yes | Whether retrying the same request may succeed without client-side changes. |
Download OpenAPI specification
List unevictable muted workloads for a cluster
Read-only list of workloads that have an active mute (dismissal) rule for the cluster. Rules are created and removed via the web app / user API only; this endpoint does not expose write operations. Tenant resolved from the auth token; a cluster belonging to another tenant returns 404.
Server: https://api.app.perfectscale.io/public/v1
Authentication (auth): http — bearer — JWT
GET /clusters/{clusterUid}/unevictable-muted-workloads
List unevictable muted workloads for a cluster
Read-only list of workloads that have an active mute (dismissal) rule for the cluster. Rules are created and removed via the web app / user API only; this endpoint does not expose write operations. Tenant resolved from the auth token; a cluster belonging to another tenant returns 404.
Parameters
| Name | Location | Required | Type | Description |
|---|---|---|---|---|
| clusterUid | path | Yes | string | Cluster unique identifier |
| pageSize | query | No | integer | Number of items per page (default 50, max 500) |
| pageToken | query | No | string | Opaque cursor token for pagination |
Responses
| Status | Description | Body |
|---|---|---|
| 200 | List of muted workloads for the cluster | application/json: object |
| 400 | Invalid parameters | application/problem+json: Problem |
| 404 | Cluster not found | application/problem+json: Problem |
| 500 | Internal server error | application/problem+json: Problem |
200 application/json body
| Property | Type | Required | Description |
|---|---|---|---|
| data | array of UnevictableMutedWorkload | Yes | |
| meta | object | Yes | |
| meta.pagination | PaginationMeta | Yes |
UnevictableMutedWorkload
| Property | Type | Required | Description |
|---|---|---|---|
| clusterUid | string | Yes | |
| id | string | Yes | Canonical workload id (namespace-kind-name) of the top-level controller. |
| namespace | string | No | |
| workloadName | string | No | Denormalized workload name for display. |
| note | string | No | |
| createdBy | string | Yes | Email of the user who created the rule. |
| createTime | string · date-time | Yes | When the rule was created (RFC 3339 UTC) |
| updateTime | string · date-time | Yes | When the rule was last updated (RFC 3339 UTC) |
PaginationMeta
Cursor-based pagination metadata for list responses.
| Property | Type | Required | Description |
|---|---|---|---|
| next | string,null | Yes | Opaque cursor token for the next page, or null if this is the last page |
| prev | string,null | Yes | Opaque cursor token for the previous page, or null if this is the first page |
| pageSize | integer | Yes | Number of items per page used for this response |
Problem
RFC 9457 Problem Details error body, served as application/problem+json. code is a stable machine-readable identifier (e.g. filter_key_not_supported, not_found, internal_error); retryable indicates whether retrying the same request may succeed without client-side changes.
| Property | Type | Required | Description |
|---|---|---|---|
| type | string | Yes | URI reference identifying the problem type. |
| title | string | Yes | Short, human-readable summary of the problem type. |
| status | integer | Yes | HTTP status code generated by the origin server for this occurrence of the problem. |
| detail | string | No | Human-readable explanation specific to this occurrence of the problem. |
| instance | string | No | URI reference identifying the specific occurrence of the problem. |
| code | string | Yes | Stable machine-readable error code. |
| retryable | boolean | Yes | Whether retrying the same request may succeed without client-side changes. |
Download OpenAPI specification
Infrafit GitHub actions
The InfraFit GitHub Action turns PerfectScale Karpenter NodePool recommendations into ready-to-review pull requests. It fetches recommendations from the PerfectScale API, maps them to the matching Karpenter YAML files in your repository, applies the changes, and opens a PR with the diff. You can create one PR per cluster or combine changes into a single PR.
If a recommendation cannot be applied automatically, the action creates a GitHub issue instead, so no recommendation is missed.
The action never changes a live cluster. All changes are proposed through pull requests, and your existing review and approval process remains the control point.
How it helps:
- Reduces manual work. Recommendations are delivered as ready-to-review YAML changes instead of requiring engineers to update files by hand.
- Keeps recommendations actionable. Changes appear directly in GitHub, where engineering teams already manage infrastructure work.
- Fits GitOps workflows. Every change is reviewable, attributable, and recorded in git history. Engineers can approve, edit, or close each PR.
- Requires no new infrastructure. The action runs on existing GitHub Actions runners and supports Anthropic, OpenAI, Amazon Bedrock, GitHub Copilot, Azure OpenAI, and OpenAI-compatible endpoints.
- Keeps configuration aligned over time. Run the action on a schedule to continuously update Karpenter configuration as workload behavior changes.
Access more information about Infrafit GitHub actions here.
How to get cluster_uid
There are two options available to obtain the cluster_uid.
- Get cluster_uid directly from PerfectScale UI:
-
Go to the
Overviewtab -
Click the three-dot button located next to the needed cluster

Get cluster UID
-
Click the
Copy Cluster UIDbutton -> now, your cluster_uid is copied.
Cluster UID copied
-
- Get cluster_uid with the following command:
kubectl get namespace kube-system -o=jsonpath='{.metadata.uid}'
- Get the full list of clusters via API and extract cluster_uids from it.
Automation Audit Log Endpoint
The Automation Audit Log provides visibility into all actions performed by PerfectScale automation. This endpoint allows teams to programmatically access, retrieve, and filter audit logs and seamlessly integrate them into their existing systems or tools.
The Automation Audit Log shows data from the last 30 days.
Get Automation Audit Logs with Cursor Pagination
Retrieves a list of automation audit log entries within a specified time range, using cursor-based pagination.
Server: https://api.app.perfectscale.io/public/v1
Authentication (auth): http — bearer — JWT
POST /automation/audit_logs
Get Automation Audit Logs with Cursor Pagination
Retrieves a list of automation audit log entries within a specified time range, using cursor-based pagination.
Request body
application/json: object
| Property | Type | Required | Description |
|---|---|---|---|
| from | string · date-time | No | The start of the time range in ISO 8601 format with UTC timezone (e.g., "2025-09-17T00:00:00Z"). If omitted, defaults to 00:00:00 UTC of the day that is 30 days ago from today. Constraints: - Must be in UTC timezone (ends with 'Z' or has '+00:00' offset) - Cannot be in the future - Cannot be before 00:00:00 UTC of 30 days ago from today - Must be before 'to' date when both are provided - Must be different from 'to' date Example: If today is 2025-10-17, the earliest allowed value is "2025-09-17T00:00:00Z" |
| to | string · date-time | No | The end of the time range in ISO 8601 format with UTC timezone (e.g., "2025-10-17T23:59:59Z"). If omitted, defaults to the current time in UTC. Constraints: - Must be in UTC timezone (ends with 'Z' or has '+00:00' offset) - Cannot be in the future - Must be after 'from' date when both are provided - Must be different from 'from' date |
| page_size | integer | No | The maximum number of items to return. Defaults to 1000. Must be between 1 and 5000. Default: 1000 Minimum: 1 Maximum: 5000 |
| page_token | string | No | An opaque token from the 'next' or 'prev' field in the response's pagination object, used to fetch the next/previous page. The token encodes both the boundary position and the page direction. Preferred over the deprecated 'after'/'before' fields. |
| after | string | No | Deprecated: use 'page_token' instead. An opaque token from the 'next' field in the response's pagination object, used to fetch the next page. |
| before | string | No | Deprecated: use 'page_token' instead. An opaque token from the 'prev' field in the response's pagination object, used to fetch the previous page. |
| cluster_uids | array of string | No | Filter by cluster UIDs. Accepts multiple cluster UIDs to filter the audit logs. |
| namespaces | array of string | No | Filter by Kubernetes namespaces. Accepts multiple namespaces to filter the audit logs. |
Responses
| Status | Description | Body |
|---|---|---|
| 200 | OK | application/json: object |
200 application/json body
| Property | Type | Required | Description |
|---|---|---|---|
| data | array of AutomationLogEntry | Yes | |
| meta | object | Yes | |
| meta.pagination | Pagination | No |
AutomationLogEntry
| Property | Type | Required | Description |
|---|---|---|---|
| started_at | string · date-time | Yes | Timestamp when the action started. |
| cluster_name | string | Yes | Name of the cluster. |
| cluster_uid | string | Yes | ID of the cluster. |
| workload_id | string | Yes | ID of the workload. |
| workload_name | string | Yes | Name of the workload. |
| workload_type | string | Yes | Type of deployment. |
| namespace | string | Yes | Namespace of the workload. |
| labels | object | Yes | Labels associated with the workload. |
| container | AutomatedLogsContainer | Yes | |
| executed | ExecutionType | Yes | |
| workload_indicators | array of Indicator | No | Workload-level indicators addressed by the automation change. |
AutomatedLogsContainer
Properties of the container.
| Property | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | Name of the container. |
| cpu | AutomatedLogsContainerCpu | Yes | |
| memory | AutomatedLogsContainerMemory | Yes | |
| indicators | array of Indicator | No | Container-level indicators addressed by the automation change. |
AutomatedLogsContainerCpu
CPU related properties.
| Property | Type | Required | Description |
|---|---|---|---|
| cpuCoresRequest | integer · int64 | Yes | Request of cpu before apply of automation. |
| recommendCpuCoresRequest | integer · int64 | Yes | Request of cpu after apply of automation. |
| cpuCoresLimits | integer · int64 | Yes | Limit of cpu before apply of automation. |
| recommendCpuCoresLimits | integer · int64 | Yes | Limit of cpu after apply of automation. |
| cpuRequestImpact | integer · int64 | Yes | Impact of automation on cpu request value. |
| cpuLimitImpact | integer · int64 | Yes | Impact of automation on cpu limit value. |
| cpuRequestChangePercent | number · double | Yes | Single instance cpu request change in %. |
| cpuLimitChangePercent | number · double | Yes | Single instance cpu limit change in %. |
| cpuRequestChangeAbsolute | integer · int64 | Yes | Single instance cpu request absolute value change. |
| cpuLimitChangeAbsolute | integer · int64 | Yes | Single instance cpu limit absolute value change. |
AutomatedLogsContainerMemory
Memory related properties.
| Property | Type | Required | Description |
|---|---|---|---|
| memMiBRequest | integer · int64 | Yes | Request of memory before apply of automation. |
| recommendMemMiBRequest | integer · int64 | Yes | Request of memory after apply of automation. |
| memMiBLimits | integer · int64 | Yes | Limit of memory before apply of automation. |
| recommendMemMiBLimits | integer · int64 | Yes | Limit of memory after apply of automation. |
| memMiBRequestImpact | integer · int64 | Yes | Impact of automation on memory request value. |
| memMiBLimitImpact | integer · int64 | Yes | Impact of automation on memory limit value. |
| memRequestChangePercent | number · double | Yes | Single instance memory request change in %. |
| memLimitChangePercent | number · double | Yes | Single instance memory limit change in %. |
| memMiBRequestChangeAbsolute | integer · int64 | Yes | Single instance memory request absolute value change. |
| memMiBLimitChangeAbsolute | integer · int64 | Yes | Single instance memory limit absolute value change. |
Indicator
A risk/waste signal addressed by an automation change.
| Property | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | Indicator name. |
| type | string | Yes | Indicator type (e.g. risk, waste, none). |
| severity | integer | Yes | Severity level (0 = none, higher = more severe). |
ExecutionType
"regular-eviction", "inplace-resize", "cleanup"
Pagination
| Property | Type | Required | Description |
|---|---|---|---|
| has_next | boolean | Yes | Deprecated: derive from 'next' (true when 'next' is non-null). |
| next | string · nullable | Yes | An opaque token to be used in the 'page_token' parameter to fetch the next page. |
| has_prev | boolean | Yes | Deprecated: derive from 'prev' (true when 'prev' is non-null). |
| prev | string · nullable | Yes | An opaque token to be used in the 'page_token' parameter to fetch the previous page. |
| page_size | integer | Yes | The maximum number of items to return. Defaults to 1000. Must be between 1 and 5000. |
Download OpenAPI specification
Deleting an API Token
In certain situations, you may find it necessary to delete an API token.
Follow these easy steps:
- Click on the
Profilebutton in the bottom left corner and selectOrganization Settings. - In the pop-up window, navigate to the
API Tokenstab. - Click the hamburger on the right-hand side, select
Delete API Token, and click theDeletebutton.

Delete API token
Deleting a cluster
The endpoint removes the cluster from PerfectScale without deleting the cluster itself.
There may be situations where you need to remove a cluster from PerfectScale. You can seamlessly delete a cluster using Public API:
DELETE /clusters/{cluster_uid}
Server: https://api.app.perfectscale.io/public/v1
Authentication (auth): http — bearer — JWT
DELETE /clusters/{cluster_uid}
Parameters
| Name | Location | Required | Type | Description |
|---|---|---|---|---|
| cluster_uid | path | Yes | string |
Responses
| Status | Description | Body |
|---|---|---|
| 200 | OK | |
| 404 | NotFound |
Download OpenAPI specification
How to get cluster UID
To get a cluster UID with a few clicks, navigate to the Overview tab, hover over the needed cluster, and click the three dots button. Then click Copy Cluster UID so that it will be automatically copied to the clipboard.

Get cluster UID
How to list all cluster UIDs
You can seamlessly list all the clusters' UIDs of the tenant by using the following API:
Server: https://api.app.perfectscale.io/public/v1
Authentication (auth): http — bearer — JWT
GET /clusters
List all clusters for a tenant
Responses
| Status | Description | Body |
|---|---|---|
| 200 | A list of all clusters | application/json: object |
| 400 | Bad Request | |
| 401 | Unauthorized | |
| 500 | Internal server error |
200 application/json body
| Property | Type | Required | Description |
|---|---|---|---|
| data | array of Cluster | Yes |
Cluster
A Kubernetes cluster basic information.
| Property | Type | Required | Description |
|---|---|---|---|
| uid | string | No | A unique identifier for the cluster. If it hasn't sent any information yet, value will be null |
| name | string | No | Name for the cluster. This is the name assigned when creating the cluster in PerfectScale Overview page |
| cloud | string | No | Cloud name - free text assigned when creating or updating the cluster in PerfectScale Overview page |
| region | string | No | Region name - free text assigned when creating or updating the cluster in PerfectScale Overview page |
| createdAt | string · date-time | No | The timestamp when the cluster was created, formatted as an ISO 8601 date-time string. |
| lastTransmittedAt | string · date-time | No | The timestamp when the cluster transmitted data for the last time, formatted as an ISO 8601 date-time string. |
Workload
A representation of a workload within a Kubernetes cluster.
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | A unique identifier for the workload, usually following a namespace-type-name convention. |
| name | string | Yes | A human-readable name for the workload. |
| type | string | Yes | The type of Kubernetes workload. Common types include Deployment, StatefulSet, and DaemonSet, but other string values can also be used to represent custom or extended workload types. |
| namespace | string | Yes | The Kubernetes namespace in which the workload resides. |
| firstSeen | string · date-time | Yes | The timestamp when the workload was first observed, formatted as an ISO 8601 date-time string. |
| lastSeen | string · date-time | Yes | The timestamp when the workload was last observed, formatted as an ISO 8601 date-time string. |
| runningMinutes | integer | Yes | The total number of minutes the workload has been running. |
| replicasCounts | ReplicasCounts | Yes | |
| resilienceLevel | "low", "medium", "high", "highest" | Yes | The resilience level of the workload, indicating its tolerance to failures or disruptions (configured on Perfectscale side). |
| muteStatus | MuteStatus | Yes | |
| costAnalysis | CostAnalysis | Yes | |
| workloadLabels | object | Yes | Key-value pairs representing kubernets labels associated with the workload. |
| indicators | array of Indicator | Yes | A list of indicators providing insights into the performance and health of the workload. |
| containers | object | Yes | An object holding detailed information about each container within the workload. |
ReplicasCounts
An object representing the count statistics of replicas for a workload over a month period.
| Property | Type | Required | Description |
|---|---|---|---|
| maxCount | integer | Yes | The maximum count of replicas observed for the workload during the month period. |
| avgCount | integer | Yes | The average count of replicas observed for the workload during the month period. |
MuteStatus
The mute status of a workload, indicating whether the workload is currently muted and when it will become unmuted.
| Property | Type | Required | Description |
|---|---|---|---|
| isMuted | boolean | Yes | Indicates whether the workload is currently muted. |
| muteExpiry | string · date-time | No | The date and time when the workload will automatically become unmuted. If null, the mute status does not expire automatically. |
Resources
Metrics detailing the resource allocation in terms of memory and CPU.
| Property | Type | Required | Description |
|---|---|---|---|
| memoryRequestMiB | number · double | Yes | The amount of memory requested for the workload in MiB. |
| memoryLimitMiB | number · double | Yes | The maximum amount of memory that can be allocated for the workload in MiB. |
| cpuRequestCores | number · double | Yes | The amount of CPU resources requested for the workload in cores. |
| cpuLimitCores | number · double | Yes | The maximum amount of CPU resources that can be allocated for the workload in cores. |
Past30DaysCostAnalysis
Metrics detailing the total and wasted costs associated with the workload's resource consumption.
| Property | Type | Required | Description |
|---|---|---|---|
| totalCost | number · double | Yes | The total cost incurred by the workload's resource consumption. |
| wastedCost | number · double | Yes | The cost attributed to over-provisioned or inefficiently utilized resources. |
CostAnalysis
Analysis of the costs associated with the workload's resource consumption over the past 30 days and projected for the next 30 days.
| Property | Type | Required | Description |
|---|---|---|---|
| past30Days | Past30DaysCostAnalysis | Yes | |
| costIncrease | number · double | Yes | The increased cost associated with the workload. |
Indicator
An object representing key performance indicators that provide insights into the performance and health of the workload or container.
| Property | Type | Required | Description |
|---|---|---|---|
| name | "OOM", "CpuThrottling", "CpuRequestNotSet", "MemRequestNotSet", "MemLimitNotSet", "UnderProvisionedMemRequest", "UnderProvisionedMemLimit", "UnderProvisionedCpuRequest", "UnderProvisionedCpuLimit", "OverProvisionedCpuRequest", "OverProvisionedMemRequest", "RestartsObserved" | Yes | The name of the indicator representing a specific aspect of performance or health. |
| type | "none", "risk", "waste" | Yes | The type of indicator, categorizing it as either a risk, waste, or no issue (none). |
| severityLevel | 0, 1, 2, 3 | Yes | The severity level of the indicator, ranging from 0 (no issue) to 3 (critical issue). |
Container
Detailed information about a specific container within the workload, including its performance indicators and usage statistics.
| Property | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | The name of the container. |
| runningMinutes | integer | Yes | The total number of minutes the container has been running. |
| indicators | array of Indicator | Yes | A list of indicators providing insights into the performance and health of the container. |
| resources | object | Yes | The resource allocation details for the workload, including the current and recommended by PerfectScale allocation. |
| resources.current | Resources | Yes | |
| resources.recommended | Resources | Yes | |
| usage | object | Yes | An object representing the resource usage statistics of a container, broken down into CPU and memory consumption. |
| usage.cpuCores | Percentiles | Yes | |
| usage.memoryMiB | Percentiles | Yes |
Percentiles
An object representing percentile statistics of resource usage, providing insights into the distribution of usage values over a certain period.
| Property | Type | Required | Description |
|---|---|---|---|
| p90 | number · double | Yes | The 90th percentile value of resource usage, indicating that 90% of the usage values are below this value and 10% are above. |
| p95 | number · double | Yes | The 95th percentile value of resource usage, indicating that 95% of the usage values are below this value and 5% are above. |
| p100 | number · double | Yes | The 100th percentile value (or maximum value) of resource usage observed during the specified period. |