Carbon AI · B2B Attestation API
GET or POST /api/v1/inference/attest returns a modeled emissions estimate for a single inference call. POST can attach a measured energy record. The response is a demonstration payload receipt: it does not retire removal or prove physical removal.
Auth model
Today the endpoint is unauthenticated. The route sits outside /api/carbon-ai's per-IP rate limiter (see server.js B2B inference attestation block) because B2B callers legitimately issue at volume. The endpoint does honour the standard Express rate-limit exemption for B2B traffic.
API keys ship next. Issuance plan: request a key via the pilot intake form; once key-check middleware is enabled, keys are sent as Authorization: Bearer <key>. Keys are not yet enforced — start integrating now and add the header when key checking goes live.
GET responses include Cache-Control: public, max-age=60, stale-while-revalidate=3600. POST responses use Cache-Control: no-store. URLs are stable; the response shape is the contract.
Request shape
Query parameters are the GET contract. It is safe to call from a browser, server, or edge worker — no body, no signature, no SDK. Existing GET clients remain supported.
| Parameter | Type & rules |
|---|---|
model REQUIRED |
String model-class label. The simulated estimate uses one query_equivalent_inference_call with 700 W × 30 s = 5.833 Wh = 0.005833333 kWh, then PUE 1.6 = 0.009333333 kWh, and the selected grid factor. |
region REQUIRED |
String region key, normalized to lowercase: global_average, us_avg, eu_avg, uk, fr, de, in, or ie. |
tokens REQUIRED |
Integer ≥ 0. Capped internally at 1e12. Drives the kg CO₂e = tokens × per-query coefficient calculation. |
client_id |
String, optional. Echoed back on the receipt so your systems can correlate attestation IDs to your own inference logs. |
Send the same required fields as JSON. client_id is optional. The optional energy_measurement object is stored with the receipt and included in its hash.
| Field | Type & rules |
|---|---|
energy_measurement.value | Required finite JSON number ≥ 0. |
energy_measurement.unit | Required exact string: kWh or Wh. |
energy_measurement.timestamp | Required RFC 3339 date-time that parses to a valid timestamp. The response returns the normalized ISO timestamp. |
energy_measurement.model | Required non-empty string, at most 255 characters, matching the top-level model. |
energy_measurement.request_reference | Required non-empty string, at most 255 characters, retained for storage and correlation. |
Omit energy_measurement to keep legacy POST behavior; existing clients do not need to change.
curl -sS -X POST 'https://taoclimate.com/api/v1/inference/attest' \
-H 'Content-Type: application/json' \
-d '{"model":"gpt-4-class","region":"eu_avg","tokens":10000,"client_id":"org-42","energy_measurement":{"value":0.42,"unit":"kWh","timestamp":"2026-09-06T12:00:00Z","model":"gpt-4-class","request_reference":"req-42"}}' | jq
Response shape
JSON object. Every receipt carries a receipt.hash derived as h_<sha256(canonicalize(disclosureCore))> (sorted-key, no-whitespace canonicalization). The matching verify page lives at /verify/<hash>.
| Field | Description |
|---|---|
inference_id | Stable per-request ID: INF-<yyyymmdd>-<tokens>-<sha8>. |
issued_at | RFC 3339 timestamp the receipt was minted. |
client_id | Echoed back from the request, or null. |
model | Model string you sent. |
region | Region string you sent. |
tokens | Caller-supplied count used as query-equivalent workload units (after the 1e12 cap); it is not a measured physical query count. |
workloadUnit | query_equivalent_inference_call. |
kg_co2e_estimated | Estimated emissions, kg CO₂e. |
estimate_status / removal_status | demonstration_only and not_retired; no removal retirement is emitted by this endpoint. |
methodology | Simulated energy boundary, selected grid factor, per-unit estimate, basis, and version (2026.2). |
energy_measurement | Optional normalized object returned only for POST requests that supplied one: value, exact unit (kWh or Wh), normalized timestamp, matching model, and request_reference. |
receipt.hash | h_ + 64-hex sha256 of the canonicalized disclosureCore object. |
receipt.type | payload_integrity_receipt; the hash checks canonical payload integrity only. |
receipt.verifyUrl | Direct link to the public verify page at /verify/<hash>. |
receipt.attached_at | Server-side timestamp the receipt was persisted (present when DB is available). |
curl sample & example response
Run this against taoclimate.com. Pipe through jq for readability.
curl -sS 'https://taoclimate.com/api/v1/inference/attest?model=gpt-4-class®ion=eu_avg&tokens=10000' | jq
To persist measured inference energy, use the JSON POST example from the request section. Its response includes the normalized energy_measurement alongside receipt.hash and, when persistence is available, receipt.attached_at.
Example GET response — fixed inputs (model=gpt-4-class, region=eu_avg, tokens=10000) so kg_co2e_estimated = tokens × 0.009333333 × 0.231 = 21.56 kg. This is a simulated demonstration estimate; no physical removal, retirement, certificate, or verified removal is issued.
{
"inference_id": "INF-20260730-10000-abcd1234",
"issued_at": "2026-07-30T12:00:00.000Z",
"client_id": null,
"model": "gpt-4-class",
"region": "eu_avg",
"tokens": 10000,
"kg_co2e_estimated": 21.56,
"estimate_status": "demonstration_only",
"removal_status": "not_retired",
"workloadUnit": "query_equivalent_inference_call",
"estimate_note": "Simulated demonstration estimate using the caller-supplied tokens count as query-equivalent workload units; it is not a measured physical query.",
"methodology": {
"energy_per_query_kwh": 0.009333333333333334,
"energy_unit": "kWh per query-equivalent workload",
"workload_unit": "query_equivalent_inference_call",
"grid_intensity_kg_per_kwh": 0.231,
"grid_intensity_g_per_kwh": 231,
"grid_intensity_conversion": "g/kWh ÷ 1000 = kg/kWh",
"grid_intensity_source": "EEA 2023 final",
"grid_intensity_as_of": "2024-06-01",
"per_query_kg_co2e": 0.00216,
"basis": "simulated single inference-call equivalent: H100 GPU energy at 700 W for a 30-second scenario runtime, multiplied by PUE 1.6; excludes CPU, memory, networking, embodied emissions, batching effects, and provider-metered workload data; 0.009333333333333334 kWh per query-equivalent workload; grid 231 g/kWh ÷ 1000 = 0.231 kg/kWh (EEA 2023 final, 2024-06-01)",
"version": "2026.2"
},
"grid_intensity_g_per_kwh": 231,
"grid_intensity_source": "EEA 2023 final",
"receipt": {
"hash": "h_4f2c8e9a1b3d5f7c9e2a4b6d8f1c3e5a7b9d2f4c6e8a1b3d5f7c9e2a4b6d8f1c",
"type": "payload_integrity_receipt",
"verifyUrl": "https://taoclimate.com/verify/h_4f2c8e9a1b3d5f7c9e2a4b6d8f1c3e5a7b9d2f4c6e8a1b3d5f7c9e2a4b6d8f1c"
}
}
Errors & caching
Errors return a JSON body with an error string. The endpoint never throws; tokens is the only field that type-checks.
| Case | Response |
|---|---|
| Missing required input | 400 { "error": "missing required input: <model|region|tokens>" } |
| Invalid tokens | 400 { "error": "invalid tokens" } — non-numeric or negative. |
| Invalid measurement object | 400 { "error": "invalid energy measurement: object" } — null, an array, or another non-object. |
| Invalid measurement value | 400 { "error": "invalid energy measurement: value" } — missing, non-numeric, non-finite, or negative. |
| Invalid measurement unit | 400 { "error": "invalid energy measurement: unit" } — only kWh and Wh are accepted. |
| Invalid measurement timestamp | 400 { "error": "invalid energy measurement: timestamp" } — malformed or unparsable RFC 3339 date-time. |
| Invalid measurement model | 400 { "error": "invalid energy measurement: model" } — missing, blank, oversized, or different from the top-level model. |
| Invalid request reference | 400 { "error": "invalid energy measurement: request_reference" } — missing, blank, or longer than 255 characters. |
GET responses include Cache-Control: public, max-age=60, stale-while-revalidate=3600; POST responses use Cache-Control: no-store. Treat the receipt as immutable once issued: if you need to reprove against a stored hash, hit receipt.verifyUrl.
CSRD / ESRS-E1 disclosure endpoint
Pair each attestation with a top-level disclosure JSON for downstream CSRD reporting. GET /api/disclosure/csed.json?queries=N returns the same shape you can paste straight into ESRS-E1 ¶ 33 (energy) and ¶ 34 (Scope 2 market-based).
curl -sS 'https://taoclimate.com/api/disclosure/csed.json?queries=100000' | jq
Example response — fixed queries=100000 and region=global_average. The values are simulated from the shared energy/grid contract; any CDR amount is an indicative simulated procurement estimate only and no physical removal, retirement, certificate, or verification is issued.
{
"framework": "CSRD",
"standard": "ESRS E1",
"asOf": "2026-07-30",
"queriesPerDay": 100000,
"region": "global_average",
"estimateStatus": "simulated",
"demonstrationStatus": "demonstration_only",
"energyPerQueryKWh": 0.009333333333333334,
"energyUnit": "kWh per query-equivalent workload",
"workloadUnit": "query_equivalent_inference_call",
"gridIntensityGPerKWh": 432,
"gridIntensityKgPerKWh": 0.432,
"gridIntensityConversion": "g/kWh ÷ 1000 = kg/kWh",
"gridIntensitySource": "Ember Global Electricity Review 2025",
"gridIntensityAsOf": "2025-05-01",
"totalScope2MarketBasedKgCO2e": 403.2,
"methodologyVersion": "2026.2",
"measurementBoundary": "simulated single inference-call equivalent: H100 GPU energy at 700 W for a 30-second scenario runtime, multiplied by PUE 1.6; excludes CPU, memory, networking, embodied emissions, batching effects, and provider-metered workload data",
"estimatedAnnualKgCO2e": 147168,
"estimatedAnnualTonnesCO2e": 147.168,
"removalStatus": "not_retired",
"removalNote": "Simulated demonstration only: no physical carbon removal is performed or retired, no certificate is issued, and no removal is verified by this endpoint.",
"estimatedCdrProcurement": {"annualTonnesCO2e": 147.168, "annualCostEUR": 14716.8, "status": "demonstration_only"},
"dailyCostEUR": 40.32,
"annualCostEUR": 14716.8,
"costBasis": "EUR 100 per tonne indicative simulated CDR procurement estimate; not a retirement record",
"currency": "EUR",
"methodology": {
"url": "https://taoclimate.com/ai-transparency-policy",
"version": "2026.2"
},
"crossReference": {
"label": "EU AI Act aligned disclosure cross-reference",
"url": "/api/disclosure/eu-ai-act.json?queries=100000®ion=global_average"
},
"receipt": {
"hash": "h_8a1c3e5b7d9f2a4c6e8b1d3f5a7c9e2b4d6f8a1c3e5b7d9f2a4c6e8b1d3f5a7c",
"type": "payload_integrity_receipt",
"verifyUrl": "https://taoclimate.com/verify/h_8a1c3e5b7d9f2a4c6e8b1d3f5a7c9e2b4d6f8a1c3e5b7d9f2a4c6e8b1d3f5a7c"
}
}
Errors return 400 { "error": "invalid queries" } for a missing or non-numeric queries parameter. Input-sensitive successful responses return Cache-Control: no-store, no-cache, must-revalidate with equivalent no-cache headers.