FinOps
Track costs, set budgets, schedule resource actions, and organize resources into groups.
Overview
Four sub-resources live under client.finops:
- Costs (
client.finops.costs) -- Query spending data by month, day, or service, forecast future costs, detect anomalies, and identify savings opportunities. - Budgets (
client.finops.budgets) -- Create spending limits with alerts, pause and resume tracking, and view budget summaries. - Schedules (
client.finops.schedules) -- Automate start/stop actions on resources using cron expressions to reduce idle-time costs. - Resource Groups (
client.finops.resource_groups) -- Tag and group resources together for aggregated cost tracking.
Costs
Monthly Breakdown
from strongly import Strongly
client = Strongly()
# Get monthly costs for the current year
monthly = client.finops.costs.monthly()
for month in monthly.get("months", []):
print(f"{month['month']}: ${month['total']:.2f}")
# Specific year and number of months
monthly = client.finops.costs.monthly(year=2025, months=6)
for month in monthly.get("months", []):
print(f"{month['month']}: ${month['total']:.2f}")
Daily Breakdown
from strongly import Strongly
client = Strongly()
# Get daily costs for a date range
daily = client.finops.costs.daily(
start_date="2026-01-01",
end_date="2026-01-31",
)
for day in daily.get("days", []):
print(f"{day['date']}: ${day['total']:.2f}")
# Filter by resource type
daily = client.finops.costs.daily(
start_date="2026-01-01",
end_date="2026-01-31",
resource_type="workspace",
)
Cost Forecast
from strongly import Strongly
client = Strongly()
forecast = client.finops.costs.forecast(months=3)
print(f"Forecasted spend (next 3 months): ${forecast.get('total_forecast'):.2f}")
for month in forecast.get("months", []):
print(f" {month['month']}: ${month['forecast']:.2f} (confidence: {month.get('confidence', 'N/A')})")
Cost by Service
from strongly import Strongly
client = Strongly()
services = client.finops.costs.services(period="month")
for svc in services.get("services", []):
print(f"{svc['name']}: ${svc['total']:.2f} ({svc.get('percentage', 0):.1f}%)")
# Filter by date range
services = client.finops.costs.services(
start_date="2026-01-01",
end_date="2026-01-31",
)
Anomaly Detection
from strongly import Strongly
client = Strongly()
anomalies = client.finops.costs.anomalies(days=30, threshold=2.0)
for a in anomalies.get("anomalies", []):
print(f"{a['date']} — {a['resource']}: ${a['actual']:.2f} (expected: ${a['expected']:.2f})")
Savings Recommendations
from strongly import Strongly
client = Strongly()
savings = client.finops.costs.savings()
for rec in savings.get("recommendations", []):
print(f"{rec['category']}: {rec['description']} — save ${rec['estimated_savings']:.2f}/mo")
# Filter by category
savings = client.finops.costs.savings(category="idle-resources")
# Filter by minimum savings
savings = client.finops.costs.savings(min_savings=50.0)
Dashboard and Stats
from strongly import Strongly
client = Strongly()
# Full dashboard
dashboard = client.finops.costs.dashboard()
print(f"Current month spend: ${dashboard.get('current_month_spend'):.2f}")
print(f"Last month spend: ${dashboard.get('last_month_spend'):.2f}")
print(f"Month-over-month change: {dashboard.get('mom_change'):.1f}%")
# Summary stats for a period
stats = client.finops.costs.dashboard_stats(period="quarter")
print(f"Total spend: ${stats.get('total_spend'):.2f}")
# Top cost drivers
drivers = client.finops.costs.top_drivers(limit=5, period="month")
for d in drivers.get("drivers", []):
print(f" {d['name']}: ${d['cost']:.2f}")
Costs Method Reference
| Method | Description | Returns |
|---|---|---|
monthly(*, months=None, year=None) | Get monthly cost breakdown | dict |
daily(*, start_date=None, end_date=None, resource_type=None) | Get daily cost breakdown | dict |
forecast(*, months=None, model=None) | Forecast future costs | dict |
services(*, period=None, start_date=None, end_date=None) | Get costs by service | dict |
anomalies(*, days=None, threshold=None) | Detect cost anomalies | dict |
savings(*, category=None, min_savings=None) | Get savings recommendations | dict |
dashboard() | Get the cost dashboard | dict |
dashboard_stats(*, period=None) | Get dashboard statistics | dict |
top_drivers(*, limit=None, period=None) | Get top cost drivers | dict |
Budgets
Basic Usage
from strongly import Strongly
client = Strongly()
# List all budgets
for budget in client.finops.budgets.list():
pct = (budget.current_spend / budget.amount * 100) if budget.amount else 0
print(f"{budget.name}: ${budget.current_spend:.2f} / ${budget.amount:.2f} ({pct:.0f}%)")
Creating a Budget
from strongly import Strongly
client = Strongly()
budget = client.finops.budgets.create({
"name": "ML Team Monthly",
"description": "Monthly spending limit for the ML team",
"amount": 5000.00,
"currency": "USD",
"period": "monthly",
"scope": {
"level": "team",
"team": "ml-engineering",
},
"alerts": [
{"threshold": 0.75, "channel": "email"},
{"threshold": 0.90, "channel": "slack"},
{"threshold": 1.00, "channel": "email", "action": "notify-admin"},
],
})
print(f"Budget ID: {budget.id}")
print(f"Amount: ${budget.amount:.2f} {budget.currency}/{budget.period}")
Pausing and Resuming
from strongly import Strongly
client = Strongly()
budget_id = "budget-abc123"
# Pause tracking
paused = client.finops.budgets.pause(budget_id)
print(f"Status: {paused.status}")
# Resume tracking
resumed = client.finops.budgets.resume(budget_id)
print(f"Status: {resumed.status}")
# Reset spend counter
reset = client.finops.budgets.reset(budget_id)
print(f"Current spend: ${reset.current_spend:.2f}")
Budget Summary
from strongly import Strongly
client = Strongly()
summary = client.finops.budgets.summary()
print(f"Total budgets: {summary.get('total')}")
print(f"Over budget: {summary.get('over_budget')}")
print(f"Total allocated: ${summary.get('total_allocated'):.2f}")
print(f"Total spent: ${summary.get('total_spent'):.2f}")
Filtering and Searching
from strongly import Strongly
client = Strongly()
# Search by name
for b in client.finops.budgets.list(search="ML"):
print(b.name)
# Filter by status
for b in client.finops.budgets.list(status="active"):
print(f"{b.name}: ${b.current_spend:.2f}")
# Filter by scope level
for b in client.finops.budgets.list(scope_level="team"):
print(f"{b.name} — {b.scope}")
# Only enabled budgets
for b in client.finops.budgets.list(enabled=True):
print(b.name)
Budget Model
| Field | Type | Description |
|---|---|---|
id | str | Unique budget identifier |
name | str | Budget name |
description | str | Human-readable description |
scope | dict | Scope definition (level, team, project, etc.) |
budget | dict | Budget configuration details |
amount | float | Budget limit amount |
currency | str | Currency code (default: USD) |
period | str | Budget period (e.g., monthly, quarterly, annual) |
current_spend | float | Current spend against this budget |
status | str | Current status |
enabled | bool | Whether the budget is enabled |
organization_id | str | Owning organization |
alerts | list | Alert rules |
created_at | str | Creation timestamp |
updated_at | str | Last update timestamp |
Budgets Method Reference
| Method | Description | Returns |
|---|---|---|
list(*, search=None, status=None, scope_level=None, enabled=None, limit=50) | List budgets with optional filters | SyncPaginator[Budget] |
create(body) | Create a new budget | Budget |
retrieve(budget_id) | Get a budget by ID | Budget |
update(budget_id, body) | Update budget fields | Budget |
delete(budget_id) | Delete a budget | dict |
pause(budget_id) | Pause budget tracking | Budget |
resume(budget_id) | Resume budget tracking | Budget |
reset(budget_id) | Reset the spend counter | Budget |
summary() | Get budget summary statistics | dict |
Schedules
Schedules automate start/stop actions on resources using cron expressions. Use them to shut down idle workspaces overnight, scale down addons on weekends, or run cost-saving routines on a timer.
Basic Usage
from strongly import Strongly
client = Strongly()
# List all schedules
for sched in client.finops.schedules.list():
state = "enabled" if sched.enabled else "disabled"
print(f"{sched.name} ({state}) — next run: {sched.next_run}")
Creating a Schedule
from strongly import Strongly
client = Strongly()
sched = client.finops.schedules.create({
"name": "Stop dev workspaces overnight",
"description": "Shut down all dev workspaces at 8 PM and restart at 8 AM",
"cron": "0 20 * * 1-5",
"action": "stop",
"target": {
"resource_type": "workspace",
"tags": {"environment": "development"},
},
"scope": {
"level": "organization",
},
"enabled": True,
})
print(f"Schedule ID: {sched.id}")
print(f"Next run: {sched.next_run}")
Managing Schedule State
from strongly import Strongly
client = Strongly()
sched_id = "sched-abc123"
# Pause a schedule
paused = client.finops.schedules.pause(sched_id)
print(f"Status: {paused.status}")
# Resume it
resumed = client.finops.schedules.resume(sched_id)
print(f"Status: {resumed.status}")
# Trigger manual execution
client.finops.schedules.execute(sched_id)
print("Schedule executed manually")
Execution History
from strongly import Strongly
client = Strongly()
history = client.finops.schedules.history("sched-abc123")
for run in history.get("runs", []):
print(f"{run['executed_at']} — {run['status']} — {run.get('resources_affected', 0)} resources")
Filtering and Searching
from strongly import Strongly
client = Strongly()
# Search by name
for s in client.finops.schedules.list(search="overnight"):
print(s.name)
# Filter by status
for s in client.finops.schedules.list(status="active"):
print(f"{s.name} — next: {s.next_run}")
# Only enabled schedules
for s in client.finops.schedules.list(enabled=True):
print(f"{s.name}: {s.cron}")
Schedule Model
| Field | Type | Description |
|---|---|---|
id | str | Unique schedule identifier |
name | str | Schedule name |
description | str | Human-readable description |
scope | dict | Scope definition |
schedule | dict | Schedule configuration details |
status | str | Current status |
enabled | bool | Whether the schedule is enabled |
cron | str | Cron expression |
action | str | Action to perform (e.g., start, stop, scale) |
target | dict | Target resource definition |
organization_id | str | Owning organization |
last_run | str | Last execution timestamp |
next_run | str | Next scheduled execution |
created_at | str | Creation timestamp |
updated_at | str | Last update timestamp |
Schedules Method Reference
| Method | Description | Returns |
|---|---|---|
list(*, search=None, status=None, scope_level=None, enabled=None, limit=50) | List schedules with optional filters | SyncPaginator[Schedule] |
create(body) | Create a new schedule | Schedule |
retrieve(schedule_id) | Get a schedule by ID | Schedule |
update(schedule_id, body) | Update schedule fields | Schedule |
delete(schedule_id) | Delete a schedule | dict |
pause(schedule_id) | Pause a schedule | Schedule |
resume(schedule_id) | Resume a schedule | Schedule |
execute(schedule_id, body=None) | Trigger manual execution | dict |
history(schedule_id) | Get execution history | dict |
Resource Groups
Resource groups let you tag and organize resources for aggregated cost tracking. Group workspaces, addons, and apps by team, project, or environment.
Basic Usage
from strongly import Strongly
client = Strongly()
# List all resource groups
for group in client.finops.resource_groups.list():
print(f"{group.name}: {len(group.resources)} resources — ${group.total_cost:.2f}")
Creating a Resource Group
from strongly import Strongly
client = Strongly()
group = client.finops.resource_groups.create({
"name": "ML Infrastructure",
"description": "All resources used by the ML team",
"tags": {
"team": "ml-engineering",
"cost-center": "CC-1234",
},
})
print(f"Group ID: {group.id}")
Managing Resources
from strongly import Strongly
client = Strongly()
group_id = "rg-abc123"
# Add resources to the group
client.finops.resource_groups.add_resource(
group_id,
type="workspace",
resource_id="ws-abc123",
name="Training Workspace",
)
client.finops.resource_groups.add_resource(
group_id,
type="addon",
resource_id="addon-def456",
name="ML Database",
)
# View the group
group = client.finops.resource_groups.retrieve(group_id)
print(f"Total cost: ${group.total_cost:.2f}")
for res in group.resources:
print(f" {res.get('name')} ({res.get('type')})")
# Remove a resource
client.finops.resource_groups.remove_resource(group_id, "ws-abc123")
Filtering and Searching
from strongly import Strongly
client = Strongly()
# Search by name
for g in client.finops.resource_groups.list(search="ML"):
print(g.name)
# Filter by status
for g in client.finops.resource_groups.list(status="active"):
print(f"{g.name}: ${g.total_cost:.2f}")
ResourceGroup Model
| Field | Type | Description |
|---|---|---|
id | str | Unique group identifier |
name | str | Group name |
description | str | Human-readable description |
status | str | Current status |
organization_id | str | Owning organization |
resources | list | List of grouped resources |
tags | dict | Key-value tags |
total_cost | float | Aggregated cost of all resources in the group |
created_at | str | Creation timestamp |
updated_at | str | Last update timestamp |
Resource Groups Method Reference
| Method | Description | Returns |
|---|---|---|
list(*, search=None, status=None, limit=50) | List resource groups | SyncPaginator[ResourceGroup] |
create(body) | Create a resource group | ResourceGroup |
retrieve(group_id) | Get a group by ID | ResourceGroup |
update(group_id, body) | Update group fields | ResourceGroup |
delete(group_id) | Delete a group | dict |
add_resource(group_id, *, type, resource_id, name) | Add a resource to the group | dict |
remove_resource(group_id, resource_id) | Remove a resource from the group | dict |
Complete Example
from strongly import Strongly
def main():
client = Strongly()
# --- Review current spending ---
print("=== Cost Dashboard ===")
dashboard = client.finops.costs.dashboard()
print(f"This month: ${dashboard.get('current_month_spend'):.2f}")
print(f"Last month: ${dashboard.get('last_month_spend'):.2f}")
# Top cost drivers
drivers = client.finops.costs.top_drivers(limit=3, period="month")
print("\nTop cost drivers:")
for d in drivers.get("drivers", []):
print(f" {d['name']}: ${d['cost']:.2f}")
# --- Check for anomalies ---
print("\n=== Anomalies (last 30 days) ===")
anomalies = client.finops.costs.anomalies(days=30)
for a in anomalies.get("anomalies", []):
print(f" {a['date']} — {a['resource']}: ${a['actual']:.2f} (expected ${a['expected']:.2f})")
# --- Get savings recommendations ---
print("\n=== Savings Opportunities ===")
savings = client.finops.costs.savings()
for rec in savings.get("recommendations", []):
print(f" {rec['description']} — save ${rec['estimated_savings']:.2f}/mo")
# --- Create a budget ---
print("\n=== Creating Budget ===")
budget = client.finops.budgets.create({
"name": "Q1 GPU Budget",
"description": "GPU compute budget for Q1 2026",
"amount": 10000.00,
"currency": "USD",
"period": "quarterly",
"scope": {"level": "organization"},
"alerts": [
{"threshold": 0.80, "channel": "email"},
{"threshold": 0.95, "channel": "slack"},
],
})
print(f"Budget: {budget.name} — ${budget.amount:.2f}")
# --- Create a cost-saving schedule ---
print("\n=== Creating Schedule ===")
sched = client.finops.schedules.create({
"name": "Weekend shutdown",
"description": "Stop dev workspaces Friday evening",
"cron": "0 18 * * 5",
"action": "stop",
"target": {
"resource_type": "workspace",
"tags": {"environment": "development"},
},
"scope": {"level": "organization"},
"enabled": True,
})
print(f"Schedule: {sched.name} — next run: {sched.next_run}")
# --- Group resources for tracking ---
print("\n=== Creating Resource Group ===")
group = client.finops.resource_groups.create({
"name": "Production ML",
"description": "All production ML infrastructure",
"tags": {"team": "ml", "env": "production"},
})
print(f"Group: {group.name} (ID: {group.id})")
# Add some resources
client.finops.resource_groups.add_resource(
group.id, type="workspace", resource_id="ws-prod-1", name="Inference Server",
)
client.finops.resource_groups.add_resource(
group.id, type="addon", resource_id="addon-prod-db", name="Model Store DB",
)
updated_group = client.finops.resource_groups.retrieve(group.id)
print(f"Resources in group: {len(updated_group.resources)}")
print(f"Total cost: ${updated_group.total_cost:.2f}")
# --- Forecast ---
print("\n=== 3-Month Forecast ===")
forecast = client.finops.costs.forecast(months=3)
for month in forecast.get("months", []):
print(f" {month['month']}: ${month['forecast']:.2f}")
# --- Budget summary ---
print("\n=== Budget Summary ===")
summary = client.finops.budgets.summary()
print(f"Total budgets: {summary.get('total')}")
print(f"Over budget: {summary.get('over_budget')}")
print(f"Total allocated: ${summary.get('total_allocated'):.2f}")
if __name__ == "__main__":
main()