> ## Documentation Index
> Fetch the complete documentation index at: https://docs.oncarbon.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Event schema

> The canonical event contract, field by field: common fields, LLM events, and tool events.

Events are a discriminated union on `type`: `"llm"` or `"tool"`. Both share the common fields below and add a type-specific `properties` object. The SDK validates events against this contract before sending; the ingest API validates again on receipt.

## Common fields

<ResponseField name="id" type="string" required>
  Client-generated UUIDv4 identifying the event. Unique within your space —
  the deduplication key. Generate it once per event and reuse it across
  retries.
</ResponseField>

<ResponseField name="type" type="&#x22;llm&#x22; | &#x22;tool&#x22;" required>
  Event type discriminator.
</ResponseField>

<ResponseField name="spaceId" type="string">
  Set by the ingest API from your API key. Any client-supplied value is
  overridden — omit it.
</ResponseField>

<ResponseField name="traceId" type="string">
  UUIDv4 shared by the events of one logical operation. See
  [Traces](/documentation/sdk/traces).
</ResponseField>

<ResponseField name="startTimeMs" type="number" required>
  Call start, milliseconds since the Unix epoch.
</ResponseField>

<ResponseField name="endTimeMs" type="number" required>
  Call end, milliseconds since the Unix epoch.
</ResponseField>

<ResponseField name="durationMs" type="number" required>
  Call duration in milliseconds, typically `endTimeMs - startTimeMs`.
</ResponseField>

<ResponseField name="status" type="object" required>
  Outcome of the call.

  <Expandable title="status fields">
    <ResponseField name="state" type="&#x22;ok&#x22; | &#x22;error&#x22;" required>
      Whether the call succeeded.
    </ResponseField>

    <ResponseField name="error" type="object">
      Failure details when `state` is `"error"`.

      <Expandable title="error fields">
        <ResponseField name="code" type="string">
          Machine-readable code, for example `rate_limit_exceeded`.
        </ResponseField>

        <ResponseField name="httpStatus" type="number">
          HTTP status returned by the upstream provider, for example `429`.
        </ResponseField>

        <ResponseField name="message" type="string">
          Human-readable description.
        </ResponseField>
      </Expandable>
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="instrumentation" type="object" required>
  Where the event came from.

  <Expandable title="instrumentation fields">
    <ResponseField name="vendor" type="&#x22;carbon&#x22;" required>
      Always `"carbon"`.
    </ResponseField>

    <ResponseField name="vendorPackage" type="&#x22;sdk&#x22;">
      Set by the Carbon SDK.
    </ResponseField>

    <ResponseField name="source" type="&#x22;openai&#x22; | &#x22;anthropic&#x22; | &#x22;vercel&#x22;" required>
      The instrumented SDK or framework.
    </ResponseField>

    <ResponseField name="sourcePackage" type="&#x22;openai&#x22; | &#x22;@anthropic-ai/sdk&#x22; | &#x22;ai&#x22;" required>
      The instrumented package.
    </ResponseField>

    <ResponseField name="sourceFunction" type="string">
      The wrapped function, for example `chat.completions.create`.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="context" type="object" required>
  Identifiers the dashboard aggregates by. The object is required but every
  field is optional — send `{}` when none apply.

  <Expandable title="context fields">
    <ResponseField name="threadId" type="string">
      Conversation or session identifier.
    </ResponseField>

    <ResponseField name="agentId" type="string">
      Agent instance identifier.
    </ResponseField>

    <ResponseField name="agentGroupId" type="string">
      Identifier for a group of related agents.
    </ResponseField>

    <ResponseField name="userId" type="string">
      End-user identifier.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="additionalProperties" type="Record<string, string | number>" required>
  Custom dimensions. Values must be strings or numbers — send `{}` when none
  apply.
</ResponseField>

## LLM events

LLM events set `type: "llm"` and carry `properties.llm`:

<ResponseField name="properties.llm.model" type="string" required>
  Model identifier as the provider names it, for example `gpt-5.4-nano` or
  `claude-haiku-4-5`.
</ResponseField>

<ResponseField name="properties.llm.apiUrl" type="string">
  The API base URL the request was served from, for example `https://api.openai.com/v1`. The ingest
  API resolves `provider` and `cost` from it; the SDK wrappers capture it
  automatically, so set it only for manual capture.
</ResponseField>

<ResponseField name="properties.llm.provider" type="string">
  The platform that executed the request, for example `openai` or
  `openrouter`. Derived by the ingest API from the API base URL — omit it.
</ResponseField>

<ResponseField name="properties.llm.creator" type="string">
  Model maker, for example `anthropic`. Derived by the ingest API from the
  model name when recognized — omit it.
</ResponseField>

<ResponseField name="properties.llm.input" type="object">
  What was sent to the model.

  <Expandable title="input fields">
    <ResponseField name="system" type="string" required>
      System prompt. Empty string when none.
    </ResponseField>

    <ResponseField name="prompt" type="string" required>
      User prompt or serialized message history.
    </ResponseField>

    <ResponseField name="tools" type="object[]" required>
      Tools offered to the model: `{ name: string, description?: string }`.
      Empty array when none.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="properties.llm.output" type="object">
  What the model returned.

  <Expandable title="output fields">
    <ResponseField name="mode" type="&#x22;generate&#x22; | &#x22;stream&#x22;" required>
      How the response was produced.
    </ResponseField>

    <ResponseField name="reasoning" type="string">
      Reasoning output, for models that expose it.
    </ResponseField>

    <ResponseField name="response" type="string">
      Text response.
    </ResponseField>

    <ResponseField name="toolCalls" type="object[]" required>
      Tool calls the model requested: `{ name: string, input?: string }` with
      `input` as the serialized arguments. Empty array when none.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="properties.llm.usage" type="object" required>
  Token usage. All fields are required — use `0` where a provider does not
  report a breakdown.

  <Expandable title="usage fields">
    <ResponseField name="inputTokens" type="number" required>
      Total input tokens.
    </ResponseField>

    <ResponseField name="inputTokenDetails" type="object" required>
      `{ uncachedTokens, cacheReadTokens, cacheWriteTokens }` — input token
      breakdown by cache behavior.
    </ResponseField>

    <ResponseField name="outputTokens" type="number" required>
      Total output tokens.
    </ResponseField>

    <ResponseField name="outputTokenDetails" type="object" required>
      `{ reasoningTokens, responseTokens }` — output token breakdown.
    </ResponseField>

    <ResponseField name="totalTokens" type="number" required>
      Input plus output tokens.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="properties.llm.cost" type="object">
  USD cost breakdown: `{ inputUncachedUsd, inputCacheReadUsd,
      inputCacheWriteUsd, outputUsd, totalUsd }`. Computed by the ingest API from
  its model catalog when the model is recognized — omit it.
</ResponseField>

## Tool events

Tool events set `type: "tool"` and carry `properties.tool`:

<ResponseField name="properties.tool.name" type="string" required>
  Tool name, for example `get_weather`.
</ResponseField>

<ResponseField name="properties.tool.input" type="string">
  Serialized tool input, typically JSON.
</ResponseField>

<ResponseField name="properties.tool.output" type="string">
  Serialized tool output, typically JSON.
</ResponseField>

## Example events

<CodeGroup>
  ```json LLM event theme={null}
  {
    "type": "llm",
    "id": "7d9f2a4e-3c1b-4f6a-9e8d-2b5c7a1f4e3d",
    "traceId": "1b6e8c2a-9d4f-4e7b-8a3c-5f2e9d1b7c4a",
    "startTimeMs": 1781176800000,
    "endTimeMs": 1781176801200,
    "durationMs": 1200,
    "status": { "state": "ok" },
    "instrumentation": {
      "vendor": "carbon",
      "source": "anthropic",
      "sourcePackage": "@anthropic-ai/sdk",
      "sourceFunction": "messages.create"
    },
    "context": { "userId": "user-481", "threadId": "thread-92" },
    "additionalProperties": { "release": "2026-06" },
    "properties": {
      "llm": {
        "model": "claude-haiku-4-5",
        "input": {
          "system": "You are concise.",
          "prompt": "What is the capital of France?",
          "tools": []
        },
        "output": {
          "mode": "generate",
          "response": "Paris.",
          "toolCalls": []
        },
        "usage": {
          "inputTokens": 18,
          "inputTokenDetails": {
            "uncachedTokens": 18,
            "cacheReadTokens": 0,
            "cacheWriteTokens": 0
          },
          "outputTokens": 3,
          "outputTokenDetails": { "reasoningTokens": 0, "responseTokens": 3 },
          "totalTokens": 21
        }
      }
    }
  }
  ```

  ```json Tool event theme={null}
  {
    "type": "tool",
    "id": "9c2e7b1f-5a4d-4c8e-b3f6-1d9a2e7c4b5f",
    "traceId": "1b6e8c2a-9d4f-4e7b-8a3c-5f2e9d1b7c4a",
    "startTimeMs": 1781176801300,
    "endTimeMs": 1781176801650,
    "durationMs": 350,
    "status": { "state": "ok" },
    "instrumentation": {
      "vendor": "carbon",
      "source": "vercel",
      "sourcePackage": "ai"
    },
    "context": { "userId": "user-481", "agentId": "travel-agent" },
    "additionalProperties": {},
    "properties": {
      "tool": {
        "name": "get_weather",
        "input": "{\"city\":\"Tokyo\"}",
        "output": "{\"city\":\"Tokyo\",\"tempC\":22}"
      }
    }
  }
  ```
</CodeGroup>
