Developer Reference

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.

Read the methodology →

Request pilot access →

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

GET /api/v1/inference/attest

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.
POST /api/v1/inference/attest

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.

FieldType & rules
energy_measurement.valueRequired finite JSON number ≥ 0.
energy_measurement.unitRequired exact string: kWh or Wh.
energy_measurement.timestampRequired RFC 3339 date-time that parses to a valid timestamp. The response returns the normalized ISO timestamp.
energy_measurement.modelRequired non-empty string, at most 255 characters, matching the top-level model.
energy_measurement.request_referenceRequired 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_idStable per-request ID: INF-<yyyymmdd>-<tokens>-<sha8>.
issued_atRFC 3339 timestamp the receipt was minted.
client_idEchoed back from the request, or null.
modelModel string you sent.
regionRegion string you sent.
tokensCaller-supplied count used as query-equivalent workload units (after the 1e12 cap); it is not a measured physical query count.
workloadUnitquery_equivalent_inference_call.
kg_co2e_estimatedEstimated emissions, kg CO₂e.
estimate_status / removal_statusdemonstration_only and not_retired; no removal retirement is emitted by this endpoint.
methodologySimulated energy boundary, selected grid factor, per-unit estimate, basis, and version (2026.2).
energy_measurementOptional normalized object returned only for POST requests that supplied one: value, exact unit (kWh or Wh), normalized timestamp, matching model, and request_reference.
receipt.hashh_ + 64-hex sha256 of the canonicalized disclosureCore object.
receipt.typepayload_integrity_receipt; the hash checks canonical payload integrity only.
receipt.verifyUrlDirect link to the public verify page at /verify/<hash>.
receipt.attached_atServer-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&region=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.

View OpenAPI spec →

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.

CaseResponse
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

View OpenAPI spec →

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.