Docs

API

Findings and savings from the hosted API, and monthly cost in FOCUS column names from the self-hosted application.

The hosted API

Design partners The hosted API is deployed and is open to design partners by invitation. We issue the API host and a machine client with each tenant; there is no self-service sign-up.

It is an HTTP API behind a JWT authorizer. Machine callers use the client-credentials grant with the scope findings.read. The tenant is never taken from the request: it comes from the verified token.

GET /v1/findings
GET /v1/findings/{finding_id}
GET /v1/savings
GET /v1/remediations
  • A missing or invalid token returns 401. An unknown path, or a finding that belongs to another tenant, returns 404.
  • /v1/findings returns count, total_monthly_cost and findings[], at list prices. It takes no filters yet.
  • /v1/savings reports no verified savings yet, because the hosted service does not read the Cost and Usage Report.
  • The routes that request, approve and execute a remediation exist under POST /v1/remediations with the scope approvals.write. Remediation is switched off in the hosted service, so nothing can be executed.
  • There is no hosted costs route and no hosted OpenAPI document yet.

The self-hosted API

Built, not hosted The sections below describe the API of the self-hosted application. The hosted API does not serve these paths.

OpenAPI document

A self-hosted deployment serves an OpenAPI 3.1 description at /api/v1/openapi.json on its own host. It is not served from this website.

Authentication

SchemeForConfigure (self-hosted)
Bearer tokenMachine callers. A static token issued to a named callerAPI_TOKENS=name:token,name:token
OAuth 2.0 bearer JWTMachine callers with an identity provider (client credentials)OIDC_ISSUER, OIDC_AUDIENCE
HTTP BasicPeople, during the test periodBASIC_AUTH_USERNAME, BASIC_AUTH_PASSWORD
curl -H "Authorization: Bearer $SPENDSAW_TOKEN" \
  https://<your-host>/api/v1/costs/2026-09

Monthly cost, in FOCUS names

GET /api/v1/costs/{period}

period is a calendar month, YYYY-MM. The response has one row per linked account and service, with column names and meanings from FOCUS 1.0. It is an aggregated subset, not a full FOCUS dataset.

FieldMeaning
periodThe month requested
finalizedFalse while Cost Explorer still marks the month as estimated. The totals can change until it is true
BilledCost, EffectiveCostTotals across all rows
BillingCurrencyCurrency of the amounts
rows[]One FocusCostRow per account and service

Each row carries ProviderName, BillingPeriodStart, BillingPeriodEnd (exclusive), SubAccountId, ServiceName, BilledCost, EffectiveCost and BillingCurrency, and may carry ChargePeriodStart, ChargePeriodEnd and SubAccountName.

{
  "period": "2026-09",
  "finalized": true,
  "BilledCost": 412.87,
  "EffectiveCost": 412.87,
  "BillingCurrency": "USD",
  "rows": [
    {
      "ProviderName": "AWS",
      "BillingPeriodStart": "2026-09-01T00:00:00Z",
      "BillingPeriodEnd": "2026-10-01T00:00:00Z",
      "SubAccountId": "111122223333",
      "SubAccountName": "prod-agency",
      "ServiceName": "Amazon Elastic Compute Cloud - Compute",
      "BilledCost": 187.42,
      "EffectiveCost": 187.42,
      "BillingCurrency": "USD"
    }
  ]
}

Example values are illustrative. Errors: 400 for a bad period, 401 for a missing or invalid credential, 502 when AWS could not be queried.

Findings

GET /api/v1/findings?waste_type=&account_id=&include_kept=false

Findings from the latest scan, largest saving first, as count, total_monthly_cost and findings[]. Resources protected by a keep tag are left out unless include_kept is true. The fields are described in Findings and cost sources.

Savings

GET /api/v1/savings
FieldMeaning
remediationsHow many cuts have been made
expected_monthly_savingWhat they were expected to save each month
verified_saving_to_dateWhat the Cost and Usage Report has confirmed
unverifiedHow many are still waiting for a full billing month

Errors

{"success": false, "error": "Invalid period '2026-13'; expected YYYY-MM"}

Other routes

These exist in the self-hosted application and are not part of the versioned OpenAPI document:

  • The approval flow under /api/remediations. See Risk tiers and approvals.
  • POST /api/findings/<id>/pull-request and GET /api/findings/<id>/plan-check. See Terraform pull requests.
  • GET /api/ledger and POST /api/ledger/verify for the savings ledger and the monthly verification.
  • GET /api/reports/msp/<account_id>.pdf for the white-label monthly report.

Sources: api/spec.py, app.py, security/auth.py, workers/api.py, infra/terraform/modules/api/main.tf.