API reference
Every operation you can call with an access key, with its arguments, the fields it returns, and an example.
Each operation below lists the permission it needs, its arguments, and the fields you can ask for. Send them to POST https://v2.opslyft.com/api/api with your key. See API for authentication and conventions.
| Operation | What it returns | Needs |
|---|---|---|
myAccess | What your key can do | Any key |
dimensions | What you can group and filter cost by | cost.view |
filters / filterValuePage | The values of a dimension | cost.view |
costQuery | Cost, grouped, filtered, and over time | cost.view |
anomalyList / anomaly | Cost anomalies | monitor.view |
atlasInventory / atlasInventoryGroup / atlasResource | Live resources | atlas.view |
getBudgets / getBudgetById / budgetForecasts / budgetDailySpend | Budgets and their forecasts | budget.view |
tickets / ticket | Tickets for cost work | ticket.view |
Your key
myAccess
What your key can do: the modules your organisation has turned on, the permissions the key holds, and its grants.
query {
myAccess {
customerId
modules
keys
grants { roleName scope expiresAt }
}
}Prop
Type
Cost
Cost works in three steps: find the dimensions you can use, look up the values you want to filter on, then run a cost query.
dimensions
What you can group and filter cost by, and which cost types each provider supports. It reads no data, so it's fast.
query {
dimensions(providers: ["aws", "azure"]) {
dimensions { key label providers kind cardinality }
costTypes { provider costTypes { costType supported reason } }
}
}Arguments: providers: [String!]!.
Returns a DimensionCatalog:
Prop
Type
Tags are dimensions too: group or filter by tag:<name>, for example tag:team. See Dimensions for what each one means.
filters
The values of one or more dimensions over a date range. Leave dimensions out to get every low-cardinality dimension at once.
query {
filters(
providers: ["aws"]
dateRange: { from: "2026-09-01", to: "2026-10-01" }
dimensions: ["service_name"]
search: "elastic"
) {
provider dimension values totalCount error
}
}Prop
Type
Returns one entry per provider and dimension: provider, dimension, values, totalCount, and error (set when that provider doesn't have the dimension; the others still answer).
filterValuePage
One page of values for one dimension on one provider, sorted by value. Use it for high-cardinality dimensions such as resource IDs.
Arguments: provider: String!, dimension: String!, dateRange: EngineDateRange!, search: String, pageNo: Int, pageSize: Int.
Returns: values: [String!]! and totalCount: Int!.
costQuery
Cost for any slice: grouped by up to several dimensions, filtered, as a total or over time, and compared with another period.
query Cost($req: CostQueryInput!) {
costQuery(request: $req) {
rows
total
meta {
pagination { totalCount nextCursor }
warnings
}
}
}Example: EC2 and RDS cost by account in September, top 10.
{
"req": {
"providers": ["aws"],
"dateRange": { "from": "2026-09-01", "to": "2026-10-01" },
"groupBy": ["sub_account_name"],
"filterSets": [
{ "filters": [
{ "key": "service_name", "op": "in", "values": ["Amazon Elastic Compute Cloud", "Amazon Relational Database Service"] }
] }
],
"topN": 10
}
}Response:
{
"data": {
"costQuery": {
"rows": [
{ "sub_account_name": "prod-main", "cost": 31002.1 },
{ "sub_account_name": "data-platform", "cost": 9870.4 }
],
"total": { "cost": 48210.55 },
"meta": { "pagination": { "totalCount": 12, "nextCursor": null }, "warnings": [] }
}
}
}Request
Prop
Type
A filter is { key, op, values }. op is in (the default), notIn, like, notLike, ilike (not case-sensitive), or notIlike. The like family takes one pattern with % wildcards.
Response
Prop
Type
Paging and sorting
Pages hold 1,000 rows by default. To get the next page, send the nextCursor you were given as pagination.cursor. A null cursor means you have everything.
{ "pagination": { "cursor": "eyJ…", "pageSize": 1000 } }Sort with pagination.sortKey (cost, or with compareRange: oldCost, variance, or percentOfChange) and sortDir (asc or desc). A cursor only works with the query it came from.
More examples
{
"req": {
"providers": ["aws"],
"dateRange": { "from": "2026-01-01", "to": "2026-10-30" },
"groupBy": ["service_name"],
"granularity": "month",
"topN": 10
}
}Each row has service_name, bucket (the first day of the month), and cost. For cost per provider, run one query per provider, or send several providers with no groupBy for a combined total.
{
"req": {
"providers": ["aws"],
"dateRange": { "from": "2026-10-01", "to": "2026-10-30" },
"compareRange": { "from": "2026-09-01", "to": "2026-09-30" },
"groupBy": ["tag:team"],
"pagination": { "sortKey": "variance", "sortDir": "desc" }
}
}Rows have cost and oldCost, biggest increase first.
{
"req": {
"providers": ["aws"],
"dateRange": { "from": "2026-09-01", "to": "2026-10-01" },
"groupBy": ["service_name"],
"filterSets": [{ "filters": [{ "key": "sub_account_name", "op": "notIn", "values": ["sandbox"] }] }]
}
}Anomalies
anomalyList
Cost anomalies that were active in a date range, with their impact, state, and recent daily series.
query {
anomalyList(
range: { start: "2026-10-01", end: "2026-10-30" }
clouds: ["aws"]
queue: needs
) {
total
rows {
key service account cloud severity kind state
impactPerDay costToDate pctChange startedAt endedAt owner
currency { code }
}
}
}Prop
Type
Returns rows, total (matches before filters), and countsByQueue. Each row (AnomalyRow) includes:
Prop
Type
anomaly
One anomaly in full.
Arguments: key: String!.
Returns: row (as above), rca (the likely cause), explanation (why it was flagged, in plain words), activity, comments, and dimensions.
Atlas inventory
Atlas is your live inventory: what exists now, polled every few hours. Costs are per month, amortised.
Atlas filters use conditions { k, op, v }. Conditions in a list must all match; any list may match. k is one of Service, Provider, State, Account, Team, Region, Type, Signal, Age, Cost/mo, or Resource. op is is, is not, includes, >, <, or is empty.
{ "filters": [[
{ "k": "Signal", "op": "is", "v": ["Idle"] },
{ "k": "Cost/mo", "op": ">", "v": ["50"] }
]] }atlasInventory
Resources grouped by a field, with counts and cost per group, and the top resources in each.
query Inventory($filters: [[AtlasConditionInput!]!]) {
atlasInventory(filters: $filters, groupBy: "Service", rowsPerGroup: 5) {
currency
total
groups {
key label count cost hasMore
rows { id name service provider account region state team cost ageDays signals }
}
}
}Prop
Type
Returns: currency, total (matching resources), freshness (when the inventory was read), groups (each with key, label, count, cost, rows, and hasMore), and facets (the values each field can take).
Each resource (AtlasResource) has id, name, service, provider, type, account, accountId, region, team, state, ageDays, createdAt, cost (per month), and signals (such as Idle, Underused, Orphaned, Stopped, Untagged).
atlasInventoryGroup
The rest of one group, page by page. Use it when a group in atlasInventory has hasMore: true.
Arguments: the same filters, search, and groupBy, plus group: String! (the group's key), offset: Int, and limit: Int.
Returns: rows and hasMore.
atlasResource
Everything Atlas knows about one resource.
Arguments: id: ID! (from atlasInventory).
Returns an AtlasResourceDetail with the resource's identity and arn, its cost basis, owner attribution, utilization, recent activity, facts, and attributes.
Budgets
The auth argument
getBudgets and getBudgetById take a required auth argument from an older version of the API. Your key in the header is what counts; pass any string, for example auth: { accessToken: "header" }.
getBudgets
The budgets your key can see.
query {
getBudgets(auth: { accessToken: "header" }, page: 1, limit: 50) {
total_count
data {
budget_id budget_name budget budget_utilization periodicity
account_owner account_manager created_at
}
}
}Arguments: auth: MulticloudAuth!, page: Int (default 1), limit: Int (omit to get every budget).
Returns: total_count and data, a list of Budget:
Prop
Type
getBudgetById
One budget.
Arguments: auth: MulticloudAuth!, budget_id: ID!.
Returns: a Budget, as above.
budgetForecasts
This period's forecast for every budget your key can see.
query {
budgetForecasts {
budgetId status periodStart periodEnd dataDate
amount spent forecast pct breachDate sev driver
}
}Returns a list of BudgetForecast:
Prop
Type
budgetDailySpend
Daily spend by service for one budget this period.
Arguments: budgetId: ID!.
Returns: a list of { date, service, cost }.
Tickets
tickets
Tickets for cost work: optimisation findings, anomalies, and budgets turned into tasks.
query {
tickets {
total
currency
tickets {
id ref title team owner priority state stateLabel
moneyAtStake moneyKind monthlyAtStake dueAt breached verified createdAt
}
}
}Arguments: filters: [[AtlasConditionInput!]!], the same condition format as Atlas.
Returns: total, currency, and tickets, each with:
Prop
Type
ticket
One ticket with its full history.
Arguments: id: ID!.
Returns a TicketDetail.
Not available with access keys yet
These parts of OpsLyft can't be used with an access key yet. They need a signed-in person:
- Canvases, datasets, and saved Cost Explorer views
- Dimension Studio, and cost queries on an allocation
- Changes: triaging anomalies, creating or editing budgets, and creating or moving tickets
Use the MCP allocation tools for Dimension Studio.