Carbon AI · B2B Attestation API
GET /api/v1/inference/attest mints a Hashbon-shaped carbon-neutral receipt for a single inference call an external AI provider ran. One request, one receipt, every gram removed against Tao's verified CDR portfolio.
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.
All responses include Cache-Control: public, max-age=60, stale-while-revalidate=3600. URLs are stable; the response shape is the contract.
Request shape
Query parameters are the entire contract. The endpoint is a plain GET so it is safe to call from a browser, server, or edge worker — no body, no signature, no SDK.
| Parameter | Type & rules |
|---|---|
model REQUIRED |
String. gpt-4-class is recognised (0.0007 kg CO₂e per query). Any other model string falls through to the widget default — the call still succeeds, the math still adds up. |
region REQUIRED |
String. E.g. EU, US, APAC. Echoed verbatim into the receipt. |
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. |
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 | Token count used (after the 1e12 cap). |
kg_co2e_estimated | Estimated emissions, kg CO₂e. |
kg_co2_removed | Removed against verified CDR. Equal to kg_co2e_estimated today. |
removal_project_id | Tao portfolio project backing the removal (e.g. TAO-UKR-HEMP-MRV-2026). |
methodology | Per-query coefficient (0.0007 kg CO₂e), basis (market-based Scope 2; 0.3 kWh × PUE 1.6 × grid 0.45 kg/kWh), version (2026.1). |
receipt.hash | h_ + 64-hex sha256 of the canonicalized disclosureCore object. |
receipt.chain | Receipt chain identifier: hashbon:taoclimate:v1. |
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&tokens=10000' | jq
Example response — fixed inputs (model=gpt-4-class, region=EU, tokens=10000) so kg_co2e_estimated = tokens × 0.0007 = 7. The receipt hash below is illustrative; yours will differ because issued_at rolls daily.
{
"inference_id": "INF-20260730-10000-abcd1234",
"issued_at": "2026-07-30T12:00:00.000Z",
"client_id": null,
"model": "gpt-4-class",
"region": "EU",
"tokens": 10000,
"kg_co2e_estimated": 7,
"kg_co2_removed": 7,
"removal_project_id": "TAO-UKR-HEMP-MRV-2026",
"methodology": {
"per_query_kg_co2e": 0.0007,
"basis": "market-based Scope 2; 0.3 kWh × PUE 1.6 × grid 0.45 kg/kWh",
"version": "2026.1"
},
"receipt": {
"hash": "h_4f2c8e9a1b3d5f7c9e2a4b6d8f1c3e5a7b9d2f4c6e8a1b3d5f7c9e2a4b6d8f1c",
"chain": "hashbon:taoclimate:v1",
"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. |
Successful responses include Cache-Control: public, max-age=60, stale-while-revalidate=3600. 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 so totalScope2MarketBasedKgCO2e = 70, verifiedRemovalKgCO2e = 2,555 t/yr, unitCostEUR = 7/day. Date stamps below are illustrative placeholders; the day-rolling asOf, RCPT-<yyyymmdd>-<n> and verifiedRemovalReceiptId are emitted fresh per call — capture them on your side.
{
"framework": "CSRD",
"standard": "ESRS E1",
"asOf": "2026-07-30",
"queriesPerDay": 100000,
"totalScope2MarketBasedKgCO2e": 70,
"methodologyVersion": "2026.1",
"measurementBoundary": "operational energy consumption of inference workload; market-based Scope 2 over daily interval; 0.3 kWh × PUE 1.6 × grid 0.45 kg/kWh",
"verifiedRemovalKgCO2e": 25550,
"verifiedRemovalAttestation": "Hashbon-attested receipt",
"verifiedRemovalReceiptId": "RCPT-20260730-100000",
"unitCostEUR": 7,
"unitCostBasis": "EUR/day at EUR 100 per tonne verified CDR procurement, matching widget line \"cr-line-eur-day\"",
"currency": "EUR",
"methodology": {
"url": "https://taoclimate.com/ai-transparency-policy",
"version": "2026.1"
},
"crossReference": {
"label": "EU AI Act aligned disclosure cross-reference",
"url": "https://taoclimate.com/eu-ai-act"
},
"certificate": {
"hash": "h_8a1c3e5b7d9f2a4c6e8b1d3f5a7c9e2b4d6f8a1c3e5b7d9f2a4c6e8b1d3f5a7c",
"chain": "hashbon:taoclimate:v1",
"verifyUrl": "https://taoclimate.com/verify/h_8a1c3e5b7d9f2a4c6e8b1d3f5a7c9e2b4d6f8a1c3e5b7d9f2a4c6e8b1d3f5a7c"
}
}
Errors return 400 { "error": "invalid queries" } for a missing or non-numeric queries parameter. Successful responses cache for public, max-age=300, stale-while-revalidate=3600.