Model-Based Simulation for Validation · CarbonLayer API

A stable receipt for a simulated request.

Create an account and key to inspect simulated decision receipts from /api/inference. This endpoint does not call a model provider or report model cost; its route and latency fields are illustrative metadata, and impact data is unavailable. For separate model-based cost and latency scenarios, use the Playground, which can make one direct provider call when configured.

1. Authenticate
Use a personal cai_… key as a bearer token. Unknown or revoked keys return JSON errors.
2. POST a request
Send a prompt, simulated model label, token budget, and latency preference. The request is persisted with your credential scope.
3. Read the boundary
Every new receipt says simulated, false for provider calls, and unavailable for impact data.

Request

Make the first call.

The URL below is a visibly sample placeholder. Replace it with the deployed origin and your real key.

bash
curl --request POST "https://your-carbonlayer-domain/api/inference" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Draft a status update for a city sustainability team.",
    "model": "claude-sonnet",
    "tokens": 800,
    "preferLowLatency": false
  }'

Response

Parse a simulated receipt.

The response contains request attribution, the echoed output, the seeded route target, latency, and explicit status fields. It contains no environmental values, baselines, savings, SCI, or cost claims. The telemetryAttributes object contains CarbonLayer-specific OpenTelemetry-compatible route and status extensions, not official OpenTelemetry semantic conventions; it does not imply an OpenTelemetry SDK or exporter.

json
{
  "id": "receipt_example_123",
  "createdAt": "2026-10-03T12:00:00.000Z",
  "model": "claude-sonnet",
  "tokens": 800,
  "response": "Draft a status update for a city sustainability team.",
  "device": {
    "id": "dev_eu_north_1",
    "name": "Oslo Harbour Hydro Cluster",
    "region": "eu-north-1",
    "country": "Norway",
    "lat": 59.91,
    "lng": 10.75,
    "latencyMs": 78
  },
  "latencyMs": 78,
  "source": "synthetic",
  "degraded": false,
  "simulationStatus": "simulated",
  "modelProviderCalled": false,
  "impactDataStatus": "unavailable",
  "telemetryAttributes": {
    "carbonlayer.route.device.id": "dev_eu_north_1",
    "carbonlayer.route.region": "eu-north-1",
    "carbonlayer.route.latency_ms": 78,
    "carbonlayer.route.source": "synthetic",
    "carbonlayer.route.degraded": false
  }
}

OpenTelemetry

Add receipt attributes to a span.

This Node.js snippet posts to /api/inference and copies the receipt’s telemetryAttributes onto a span. Install @opentelemetry/api and initialize your own SDK and exporter. CarbonLayer returns the attributes; it does not install an SDK or export spans.

js
import {
  SpanStatusCode,
  trace,
} from '@opentelemetry/api';

const baseUrl =
  process.env.CARBONLAYER_BASE_URL;
const apiKey =
  process.env.CARBONLAYER_API_KEY;
const tracer = trace.getTracer(
  'carbonlayer-consumer',
);

export async function recordInference() {
  return tracer.startActiveSpan(
    'inference',
    async (span) => {
      try {
        const response = await fetch(
          baseUrl + '/api/inference',
          {
            method: 'POST',
            headers: {
              authorization:
                'Bearer ' + apiKey,
              'content-type':
                'application/json',
            },
            body: JSON.stringify({
              prompt: 'Summarize a report.',
              model: 'claude-sonnet',
              tokens: 800,
            }),
          },
        );
        if (!response.ok) {
          throw new Error(
            'Inference failed: HTTP ' +
              response.status,
          );
        }

        const receipt =
          await response.json();
        span.setAttributes(
          receipt.telemetryAttributes,
        );
        return receipt;
      } catch (error) {
        span.setStatus({
          code: SpanStatusCode.ERROR,
        });
        throw error;
      } finally {
        span.end();
      }
    },
  );
}

Emitted by current receipts

Current receipts emit carbonlayer.route.device.id, carbonlayer.route.region, carbonlayer.route.latency_ms, carbonlayer.route.source, and carbonlayer.route.degraded. The source key is omitted only when a legacy record has a null source. These are CarbonLayer extensions, not official OpenTelemetry semantic conventions.

Impact attributes are unavailable

Current receipts set impactDataStatus to unavailable and omit impact attributes. The contract maps carbonlayer.impact.carbon_grams, carbonlayer.impact.water_ml, carbonlayer.impact.energy_kwh, carbonlayer.impact.renewable_pct, carbonlayer.impact.baseline_carbon_grams, carbonlayer.impact.baseline_water_ml, carbonlayer.impact.saved_carbon_grams, and carbonlayer.impact.saved_water_ml only when a finite, non-null legacy value exists. Missing values are omitted; no environmental measurement is available.

Route and latency values are simulated, illustrative metadata: they do not describe production routing or measured server duration. Names outside this contract, including proposed fields, are unsupported; do not add them to the span.

Contract notes

What the prototype does not claim.

  • This /api/inference prototype does not call a model provider; output is an echo of the trimmed prompt.
  • The separate cost playground can make one direct provider call when configured; it does not route live workloads or add a provider to this API endpoint.
  • Impact data is unavailable because request-level serving-stack telemetry and approved methodology inputs are not wired.
  • No returned value is measured, an estimate, an SCI score, a baseline, a savings claim, or a monetary cost. Per-inference environmental values, energy allocation, baselines, and savings remain unavailable.
  • Routing and latency are illustrative prototype metadata and are not a physical edge-site promise.

Errors

Auth and validation stay JSON.

json
{
  "error": "missing_credentials",
  "message": "Send Authorization: Bearer <API_KEY> or x-api-key: <API_KEY>."
}

Invalid request bodies return HTTP 400 with an errors object. Valid requests return HTTP 201. The Evidence-Based Framework (Pending Final Coefficient Verification) is available as Methodology v1.0; read the /methodology release record for its boundary and evidence requirements.

The researcher-reported water summary is not independently verified. The full ledger and source PDF are absent, so no candidate water values or confirmed water-impact claims are published.