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®ion=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_hoursandcost_usdover the whole window per rawresource_type(ec2,s3,lambda,rds, …), with theservice_typeit rolls up to. One entry per type that has carbon or cost data, sorted byresource_type. Same filters as every other view; the entries sum tototalup to floating-point rounding. An untracked type (e.g.alloydb) can appear here with cost only, and it is still a validresource_typefilter.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_usdand distinctresource_countfor the entire period.buckets(only whenfrequencyis set): thetotalmetrics 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_datebut 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_countis the number of distinct resources with carbon data in that bucket, so bucket counts do not sum tototal.resource_count.co2e_grams,watt_hoursandcost_usddo sum tototal.- 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.