Skip to content

API Reference

The Ambra Spectrum API serves pre-computed carbon footprint data. All endpoints return JSON.

Base URL

https://api.ambra.nodera.fr

Paths below are relative to it (for example https://api.ambra.nodera.fr/v1/carbon/footprint).


Authentication

Every request (except /health) requires a Bearer token in the Authorization header:

Authorization: Bearer my-ambra-api-key

Endpoints

GET /health

Liveness probe. No authentication required.

curl https://api.ambra.nodera.fr/health

Response 200 OK:

{
  "status": "healthy"
}

GET /v1/carbon/footprint

Returns pre-computed carbon footprint data points grouped by resource.

Query parameters

Parameter Required Type Default Description
start_date yes string ISO 8601 datetime. Start of the query window (inclusive).
end_date yes string ISO 8601 datetime. End of the query window (exclusive). Capped at the current UTC time if set in the future.
provider no string all Filter by cloud provider: aws, gcp, or azure.
region no string all Filter by cloud region (e.g. eu-west-3).
resource_type no string all Filter by raw resource type (e.g. ec2, s3, lambda), the same values the response returns in resource_type. Accepts tracked types plus any type present in your inventory. Anything else returns 400 resource_type_unknown.
tag no string Filter by resource tag in key:value format. Repeatable for multiple tags (OR logic).
page no integer 1 Page number (1-indexed). Each page contains up to 1000 data points.
detail no boolean false When true, each data point includes the raw source metrics (CPU utilisation, storage, etc.) alongside the carbon estimate.

Example request

curl -s "https://api.ambra.nodera.fr/v1/carbon/footprint?start_date=2025-07-01T00:00:00Z&end_date=2025-07-02T00:00:00Z&provider=aws&region=eu-west-3" \
  -H "Authorization: Bearer my-ambra-api-key"

Response 200 OK

{
  "query": {
    "start_date": "2025-07-01T00:00:00Z",
    "end_date": "2025-07-02T00:00:00Z",
    "filters": {
      "provider": "aws",
      "region": "eu-west-3",
      "tags": []
    }
  },
  "pagination": {
    "page": 1,
    "total_pages": 1,
    "page_size": 1000
  },
  "resources": [
    {
      "resource_id": "i-0abc123def456789",
      "resource_type": "ec2",
      "service_type": "vm",
      "provider": "aws",
      "region": "eu-west-3",
      "resource_subtype": "t3.small",
      "tags": {
        "env": "production",
        "team": "backend"
      },
      "data_points": [
        {
          "timestamp": "2025-07-01T12:00:00Z",
          "granularity": "5min",
          "resource_subtype": "t3.small",
          "co2e_grams": 0.0342,
          "watt_hours": 0.583,
          "intensity_gco2_kwh": 58.7,
          "intensity_source": "nodera_api",
          "data_source": "collector"
        }
      ],
      "summary": {
        "total_co2e_grams": 0.0342,
        "avg_cpu_pct": null
      }
    }
  ]
}

Detail mode

When detail=true, each data point includes cpu_pct_avg and a metrics array with the raw values that drove the carbon calculation:

{
  "timestamp": "2025-07-01T12:00:00Z",
  "granularity": "5min",
  "resource_subtype": "t3.small",
  "co2e_grams": 0.0342,
  "watt_hours": 0.583,
  "intensity_gco2_kwh": 58.7,
  "intensity_source": "nodera_api",
  "data_source": "collector",
  "cpu_pct_avg": 12.4,
  "metrics": [
    { "name": "cpu_utilization_avg_pct", "value": 12.4, "unit": "%" },
    { "name": "cpu_utilization_max_pct", "value": 28.1, "unit": "%" },
    { "name": "cpu_utilization_min_pct", "value": 3.2, "unit": "%" }
  ]
}

Empty result set

When no data matches the query, the API returns an empty resources array (not a 404):

{
  "query": { "..." : "..." },
  "pagination": { "page": 1, "total_pages": 1, "page_size": 1000 },
  "resources": []
}

GET /v1/carbon/aggregations

Returns pre-aggregated carbon data broken down by month, service type, tag, and quarter. Designed for dashboards and reporting.

Query parameters

Parameter Required Type Default Description
start_date yes string ISO 8601 datetime. Any instant is accepted — windows need not align to calendar months; edge buckets of every view are clipped to the window.
end_date yes string ISO 8601 datetime, inclusive. Must be after start_date and not in the future.
provider no string all Filter by cloud provider: aws, gcp, or azure.
region no string all Filter by cloud region (e.g. eu-west-3).
tag no string Filter by resource tag in key:value format. Repeatable (OR logic).
scope_basis no string location_based location_based or market_based. Market-based is accepted for forward compatibility but does not yet change behaviour.
timezone no string UTC IANA timezone name (e.g. Europe/Paris). Controls calendar day / week / month / quarter alignment.
resource_type no string all Filter by raw resource type (e.g. ec2, s3, lambda). Accepts any tracked type plus any type present in your inventory, including untracked ones such as alloydb. Anything else returns 400 resource_type_unknown, and the error message lists both sets.
resource_id no string all Filter by the cloud provider's resource identifier.
frequency no string daily, weekly, monthly or quarterly. When set, adds the buckets view (see below). Omit it and the response shape is unchanged.

Example request

curl -s "https://api.ambra.nodera.fr/v1/carbon/aggregations?start_date=2025-01-01T00:00:00Z&end_date=2025-03-31T23:59:59Z" \
  -H "Authorization: Bearer my-ambra-api-key"

Response 200 OK

{
  "query": {
    "start_date": "2025-01-01T00:00:00+0000",
    "end_date": "2025-03-31T23:59:59+0000",
    "filters": {
      "provider": null,
      "region": null,
      "tags": []
    },
    "scope_basis": "location_based",
    "timezone": "UTC"
  },
  "views": {
    "by_month_by_service": [
      { "month": "2025-01", "service_type": "vm", "co2e_grams": 123.45 },
      { "month": "2025-01", "service_type": "storage", "co2e_grams": 67.89 },
      { "month": "2025-02", "service_type": "vm", "co2e_grams": 110.20 },
      { "month": "2025-02", "service_type": "storage", "co2e_grams": 71.34 }
    ],
    "by_resource_type": [
      { "resource_type": "ec2", "service_type": "vm",      "co2e_grams": 233.65, "watt_hours": 21.3, "cost_usd": 4.10 },
      { "resource_type": "s3",  "service_type": "storage", "co2e_grams": 139.23, "watt_hours": 12.6, "cost_usd": 0.85 }
    ],
    "by_month_by_tag": [
      { "month": "2025-01", "tag": "env:production", "co2e_grams": 100.0 },
      { "month": "2025-02", "tag": "env:production", "co2e_grams": 95.5 }
    ],
    "by_quarter": [
      { "quarter": "2025-Q1", "co2e_grams": 500.0 }
    ],
    "total": {
      "co2e_grams": 500.0
    }
  },
  "meta": {
    "computed_at": "2025-04-01T08:00:00Z",
    "intensity_source": "nodera_api",
    "methodology_version": "ambra_spectrum_methodology_v1.2"
  }
}

Views breakdown:

  • by_month_by_service: Cross-product of all months and service types in the period, zero-filled for missing combinations.
  • by_resource_type: co2e_grams, watt_hours and cost_usd over the whole window per raw resource_type (ec2, s3, lambda, rds, …), with the service_type it rolls up to. One entry per type that has carbon or cost data, sorted by resource_type. Same filters as every other view; the entries sum to total up to floating-point rounding. An untracked type (e.g. alloydb) can appear here with cost only, and it is still a valid resource_type filter.
  • by_month_by_tag: Only non-zero (month, tag) combinations.
  • by_quarter: All quarters in the range, zero-filled if empty.
  • total: co2e_grams, watt_hours, cost_usd and distinct resource_count for the entire period.
  • buckets (only when frequency is set): the total metrics resampled server-side at that cadence. Same filters as every other view.

frequency and the buckets view

curl -s "https://api.ambra.nodera.fr/v1/carbon/aggregations?start_date=2025-03-29T00:00:00Z&end_date=2025-04-08T23:59:59Z&frequency=weekly" \
  -H "Authorization: Bearer my-ambra-api-key"

Adds "frequency": "weekly" to the query block and this view:

"buckets": [
  { "period": "2025-03-24", "co2e_grams": 10.0,  "watt_hours": 1.0,  "cost_usd": 1.0, "resource_count": 1 },
  { "period": "2025-03-31", "co2e_grams": 65.0,  "watt_hours": 6.5,  "cost_usd": 2.0, "resource_count": 2 },
  { "period": "2025-04-07", "co2e_grams": 240.0, "watt_hours": 24.0, "cost_usd": 4.0, "resource_count": 2 }
]
frequency period label Bucket boundaries (in timezone)
daily YYYY-MM-DD (the day) Local midnight to midnight (23 h / 25 h on DST days).
weekly YYYY-MM-DD (the ISO week's Monday) Monday 00:00 to next Monday 00:00.
monthly YYYY-MM (as by_month_by_service) Calendar month.
quarterly YYYY-Qn (as by_quarter) Calendar quarter.
  • Every bucket overlapping the window is returned in chronological order, zero-filled when empty, so the series has no gaps.
  • The first and last buckets are clipped to start_date / end_date but keep their nominal label (e.g. a window starting on a Saturday yields a first weekly bucket labelled with the preceding Monday that holds only Saturday and Sunday).
  • resource_count is the number of distinct resources with carbon data in that bucket, so bucket counts do not sum to total.resource_count. co2e_grams, watt_hours and cost_usd do sum to total.
  • A request may produce at most 1000 buckets (about 2.7 years of daily buckets); beyond that it fails with too_many_buckets.

Service types: vm, storage, container, serverless, database, ai_inference, ml_workload.

GET /v1/resources

Full resource inventory, one entry per resource, whether or not Ambra computes carbon for it. start_date / end_date (default: trailing 30 days) only scope the carbon and cost summaries. They never hide a resource.

Filters: provider, region, resource_type, tag (repeatable key:value), tracking_status (tracked_with_data, tracked_no_data, not_tracked), page.

Each resource carries two type fields:

Field Example Description
resource_type ec2 Raw type as stored by the collector. The resource_type filter uses the same vocabulary, so any value returned here can be sent back as a filter.
service_type vm The normalised service family it rolls up to (as in by_month_by_service). Untracked types fall back to the raw value.

Contract change

Before this change /v1/resources and /v1/carbon/footprint returned the service type (e.g. vm) in resource_type, which could not be sent back as a filter. Both now return the raw type (e.g. ec2), and the service type moved to the new service_type field. Clients that read resource_type as a service family (e.g. the Web App resource table) must switch to service_type.

Projected cost

Cloud billing reports cost per day, about 24–48 hours late. The collector stores an hourly projected cost (gross, USD) for the hours billing has not settled yet. The endpoints that return it are not available yet; cost_usd above is billed cost only.

Billing cut-off. For each cloud provider, the cut-off is the start of the latest UTC day that has any billed cost, across all of that provider's resources. Days before the cut-off are settled for every resource of that provider: billed cost is final and nothing is projected, including for resources that were never billed. The cut-off day itself is provisional (the provider may still add cost to it), so it is projected, and so is every hour after it, up to the latest collection. Billed cost counts before the cut-off and projected cost from it on. Projections older than 72 hours are never made, and projected rows are kept after the bill lands so their accuracy can be tracked.

Method Applies to How
list_price_usage EC2, GCE and GKE nodes, S3, regional GCS buckets, Lambda, Fargate, Cloud SQL (MySQL / PostgreSQL) without settled billing Collected usage × on-demand list price: running hours, GB stored per storage class, GB-seconds, vCPU-hours
run_rate Every other resource with settled billed cost, whose billing reaches the last 3 days Average billed hourly cost over the settled days of the trailing 7 days, for complete hours only

Not priced from list prices (run_rate once billed, no projection before the first settled bill): Cloud Functions, Cloud Run, RDS and Aurora (engine not collected; includes Multi-AZ, Oracle, SQL Server), Cloud SQL SQL Server and Enterprise Plus, Cloud SQL instances that already have settled billed cost (HA and edition are not collected), GCS dual- and multi-region buckets, GCE custom machine types, GKE Autopilot, GCP Batch, persistent disks, and resources Ambra collects no usage metrics for.

Known limits: Lambda is priced as x86_64 (arm64 is overstated by about 20%). Request charges, Fargate memory, data transfer, disks attached to VMs (including boot disks and the disks of stopped instances), support and tax are not projected, so projected cost understates the eventual bill for those items. Discounts (committed use, Savings Plans, credits) are not applied.


Response field reference

Resource object (footprint)

Field Type Description
resource_id string The cloud provider's resource identifier.
resource_type string Raw type as stored by the collector (e.g. ec2, s3, lambda). Same vocabulary as the resource_type filter.
service_type string Normalised service family it rolls up to: vm, storage, container, serverless, database, ai_inference, ml_workload.
provider string aws, gcp, or azure.
region string Cloud region (e.g. eu-west-3).
resource_subtype string or null Provider-specific detail (e.g. t3.small for an EC2 instance).
tags object Key-value pairs from the cloud resource's tags.
data_points array Carbon estimate data points within the query window.
summary object Aggregated totals for this resource across all returned data points.

Data point object

Field Type Description
timestamp string ISO 8601 UTC timestamp of the measurement window.
granularity string Measurement granularity (e.g. 5min). Matches the source metric period.
resource_subtype string or null Instance type at the time of measurement.
co2e_grams float Estimated CO₂e emissions in grams.
watt_hours float Estimated energy consumption in watt-hours.
intensity_gco2_kwh float Grid carbon intensity used (gCO₂/kWh).
intensity_source string nodera_api (hourly intensity) or static_fallback (annual average).
data_source string collector (real monitoring data) or estimated (50% CPU assumption).
cpu_pct_avg float or null Average CPU utilisation (only when detail=true).
metrics array or null Raw source metrics (only when detail=true).

Aggregation meta object

Field Type Description
computed_at string ISO 8601 UTC timestamp when the aggregation was computed.
intensity_source string Most common intensity source across the result set.
methodology_version string Methodology version identifier.

Pagination object (footprint only)

Field Type Description
page integer Current page number.
total_pages integer Total number of pages available.
page_size integer Maximum data points per page (1000).

Errors

All errors return this structure:

{
  "error": {
    "code": "<error_code>",
    "message": "<human-readable description>",
    "request_id": "req_abc123def456"
  }
}

Common errors (all endpoints)

Status Code Cause
401 missing_api_key Authorization header is missing or malformed.
401 invalid_api_key Token does not match.

Footprint errors

Status Code Cause
422 invalid_date_range Unparseable date, or start_date >= end_date.
422 invalid_provider Provider is not aws, gcp, or azure.
400 invalid_tag_format Tag string missing : separator.

Aggregation errors

Status Code Cause
422 invalid_report_period start_date or end_date is not a parseable ISO 8601 datetime.
422 start_after_end start_date >= end_date.
422 end_date_in_future end_date is after current UTC time.
422 invalid_timezone Unknown IANA timezone name.
422 scope_basis_unsupported Value is not location_based or market_based.
422 provider_unknown Provider is not aws, gcp, or azure.
422 too_many_tags Period contains more than 500 unique tags.
422 too_many_buckets frequency over the requested window yields more than 1000 buckets.
400 frequency_unknown frequency is not daily, weekly, monthly or quarterly.
400 invalid_tag_format Tag string missing : separator.
429 too_many_requests More than 5 concurrent aggregation requests. Includes Retry-After header.

Pagination

Footprint responses are paginated by data points (not by resources). Each page contains up to 1000 data points. A single resource may appear on multiple pages if it has many data points in the query window.

Use the page query parameter to navigate. Check pagination.total_pages in the response to determine how many pages are available.

Aggregation responses are not paginated.