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

# Usage, Traces & Span

> Query token usage, costs, traces and spans using the Netra Usage API 

The Netra SDK exposes a `usage` client that lets you query:

* Session-level usage (tokens, requests, cost)
* Tenant-level usage
* Lists of **traces** within a time range
* Lists of **spans** for a given trace\
  \
  This page shows how to use `Netra.usage` to retrieve usage and tracing data and how to work efficiently with pagination.

## Getting Started

The `usage` client is available on the main `Netra` entry point

### Session Usage

Use `get_session_usage` to fetch usage for a single session between a start and end time.

<CodeGroup>
  ```python python theme={null}
  from netra import Netra

  Netra.init(app_name="sample-app")

  session_usage = Netra.usage.get_session_usage(
      session_id="b8a359f8-f28c-4e88-839f-c5db103e9943",
      start_time="2025-10-18T11:20:20.723Z",
      end_time="2025-11-30T11:20:20.723Z",
  )

  if session_usage:
      print("Session:", session_usage.session_id)
      print("Tokens:", session_usage.token_count)
      print("Requests:", session_usage.request_count)
      print("Total cost (USD):", session_usage.total_cost)
  ```
</CodeGroup>

<CodeGroup>
  ```python python theme={null}
  get_session_usage(
      session_id: str,
      start_time: str,
      end_time: str,
  ) -> SessionUsageData | Any
  ```
</CodeGroup>

**Parameters**

* `session_id: str`\
  Unique identifier of the session whose usage you want to retrieve.
* `start_time: str`\
  Start of the time window to consider for this session’s usage.\
  Must be an ISO 8601 UTC timestamp (e.g. `"2025-11-16T00:00:00Z"`).
* `end_time: str`\
  End of the time window to consider for this session’s usage.\
  Must be an ISO 8601 UTC timestamp.

### Tenant Usage

Use `get_tenant_usage` to fetch aggregated usage for a tenant.

<CodeGroup>
  ```python python theme={null}
  from netra import Netra

  Netra.init(app_name="sample-app")

  tenant_usage = Netra.usage.get_tenant_usage(
      tenant_id="AceTech",
      start_time="2025-10-18T11:20:20.723Z",
      end_time="2025-11-30T11:20:20.723Z",
  )

  if tenant_usage:
      print("Tenant:", tenant_usage.tenant_id)
      print("Org:", tenant_usage.organisation_id)
      print("Tokens:", tenant_usage.token_count)
      print("Requests:", tenant_usage.request_count)
      print("Sessions:", tenant_usage.session_count)
      print("Total cost (USD):", tenant_usage.total_cost)
  ```
</CodeGroup>

<CodeGroup>
  ```python python theme={null}
  get_tenant_usage(
      tenant_id: str,
      start_time: str,
      end_time: str,
  ) -> TenantUsageData | Any
  ```
</CodeGroup>

**Parameters**

* `tenant_id: str`\
  Identifier of the tenant (e.g. customer organization or account).
* `start_time: str`\
  Start of the time window for aggregating tenant usage, in ISO 8601 UTC.
* `end_time: str`\
  End of the time window for aggregating tenant usage, in ISO 8601 UTC.

## **Listing Traces**

Use `list_traces` to query traces for a time range with optional search and pagination.

<CodeGroup>
  ```python python theme={null}
  from netra import Netra

  Netra.init(app_name="sample-app")

  traces_page = Netra.usage.list_traces(
      start_time="2025-10-18T11:20:20.723Z",
      end_time="2025-11-30T11:20:20.723Z",
      tenant_id="AceTech",
  	user_id="Jerina",
  	session_id="b8a359f8-f28c-4e88-839f-c5db103e9943"
      limit=10,                      # page size
      cursor=None,                   # first page
      direction="down",              # or "up"
      sort_field="start_time",
      sort_order="desc",
  )

  for trace in traces_page.traces:
      print(trace.id, trace.name, trace.total_tokens, trace.total_cost)

  print("Has next page?", traces_page.has_next_page)
  print("Next cursor:", traces_page.next_cursor)

  if traces_page.has_next_page and page.next_cursor:
      next_page = Netra.usage.list_traces(
          start_time="2025-10-18T11:20:20.723Z",
          end_time="2025-11-30T11:20:20.723Z",
          tenant_id="AceTech",
  		user_id="Jerina",
  		session_id="b8a359f8-f28c-4e88-839f-c5db103e9943"
          limit=10,
          cursor=traces_page.next_cursor,
          direction="down",
          sort_field="start_time",
          sort_order="desc",
      )
  ```
</CodeGroup>

<CodeGroup>
  ```python python theme={null}
  list_traces(
      start_time: str,
      end_time: str,
      tenant_id: Optional[str] = None,
  	user_id: Optional[str] = None,
  	session_id: Optional[str] = None,
      limit: Optional[int] = None,
      cursor: Optional[str] = None,
      direction: Optional[Literal["up", "down"]] = "down",
      sort_field: Optional[str] = None,
      sort_order: Optional[Literal["asc", "desc"]] = None,
  ) -> TracesPage | Any
  ```
</CodeGroup>

**Parameters**

* `start_time: str`\
  Required. Start of the time range to search for traces (ISO 8601 UTC).
* `end_time: str`\
  Required. End of the time range to search for traces (ISO 8601 UTC).
* `session_id: Optional[str]`\
  Optional `session_id` used to filter the list
* `user_id: Optional[str]`\
  Optional `user_id` used to filter the list
* `tenant_id: Optional[str]`\
  Optional `tenant_id` used to filter the list
* `limit: Optional[int]`\
  Maximum number of traces to return in this page.\
  If `None`, the backend default is used.
* `cursor: Optional[str]`\
  Opaque pagination cursor from a previous page.\
  Use `None` for the first page.
* `direction: Optional[Literal["up", "down"]]`\
  Pagination direction relative to the cursor:
  * `"down"`: fetch newer/forward in time.
  * `"up"`: fetch older/backwards in time.\
    Defaults to `"down"`.
* `sort_field: Optional[str]`\
  Name of the field used for sorting traces (e.g. `"start_time"`).\
  If `None`, backend default sorting is applied.
* `sort_order: Optional[Literal["asc", "desc"]]`\
  Sort order for `sort_field`: ascending or descending.\
  If `None`, backend default order is used.

If you want to **stream over all pages** until completion, use the iterators.

<CodeGroup>
  ```python python theme={null}
  for trace in Netra.usage.iter_traces(
      start_time="2025-10-18T11:20:20.723Z",
      end_time="2025-11-30T11:20:20.723Z",
      tenant_id="AceTech",
  	user_id="Jerina",
  	session_id="b8a359f8-f28c-4e88-839f-c5db103e9943"
      limit=10,              # per-page size
      direction="down",
      sort_field="start_time",
      sort_order="desc",
  ):
      
      print(trace.id, trace.name, trace.total_cost)
  ```
</CodeGroup>

<CodeGroup>
  ```python python theme={null}
  iter_traces(
      start_time: str,
      end_time: str,
      tenant_id: Optional[str] = None,
  	user_id: Optional[str] = None,
  	session_id: Optional[str] = None,
      limit: Optional[int] = None,
      cursor: Optional[str] = None,
      direction: Optional[Literal["up", "down"]] = "down",
      sort_field: Optional[str] = None,
      sort_order: Optional[Literal["asc", "desc"]] = None,
  ) -> Iterator[TraceSummary]
  ```
</CodeGroup>

**Parameters**

* `start_time: str`\
  Required. Time window start (ISO 8601 UTC) for traces to iterate over.
* `end_time: str`\
  Required. Time window end (ISO 8601 UTC) for traces to iterate over.
* `session_id: Optional[str]`\
  Optional `session_id` used to filter the list
* `user_id: Optional[str]`\
  Optional `user_id` used to filter the list
* `tenant_id: Optional[str]`\
  Optional `tenant_id` used to filter the list
* `limit: Optional[int]`\
  Per‑page size when fetching traces.\
  Controls how many traces are fetched in each backend call.
* `cursor: Optional[str]`\
  Optional starting cursor.
  * `None`: start from the first page.
  * Not‑`None`: resume from a specific position.
* `direction: Optional[Literal["up", "down"]]`\
  Pagination direction per page, as in

  list\_traces.
* `sort_field: Optional[str]`\
  Field to sort by when fetching traces.
* `sort_order: Optional[Literal["asc", "desc"]]`\
  Sort order for `sort_field`.
* Handles pagination automatically using `TracesPage.has_next_page` and `TracesPage.next_cursor`.
* Stops when there are no more pages or if the backend returns an unexpected payload.

## **Listing Spans for a Trace**

Use `list_spans_by_trace_id` to fetch spans within a single trace, with optional search and pagination.

<CodeGroup>
  ```python python theme={null}
  from netra import Netra

  Netra.init(app_name="sample-app")

  spans_page = Netra.usage.list_spans_by_trace_id(
      trace_id="728c1de6fa4c53de143a7d7fef33ff91",
      direction="down",
      limit=10,
      span_name="openai.chat",
  )

  for span in spans_page.spans:
      print(span.id, span.name, span.kind, span.latency_ms)

  print("Has next page?", spans_page.has_next_page)
  print("Next cursor:", spans_page.next_cursor)
  ```
</CodeGroup>

<CodeGroup>
  ```python python theme={null}
  list_spans_by_trace_id(
      trace_id: str,
      cursor: Optional[str] = None,
      direction: Optional[Literal["up", "down"]] = "down",
      limit: Optional[int] = None,
      search: Optional[str] = None,
  ) -> SpansPage | Any
  ```
</CodeGroup>

**Parameters**

* `trace_id: str`\
  Required trace identifier whose spans should be listed.
* `cursor: Optional[str]`\
  Opaque pagination cursor from a previous spans page.\
  Use `None` to start from the first page.
* `direction: Optional[Literal["up", "down"]]`\
  Pagination direction relative to cursor:
  * `"down"`: move forward.
  * `"up"`: move backward.\
    Defaults to `"down"`.
* `limit: Optional[int]`\
  Maximum number of spans to return in this page.
* `span_name: Optional[str]`\
  Optional `span_name` used to filter the list

Use `iter_spans_by_trace_id` to walk all spans of a given trace across multiple pages.

<CodeGroup>
  ```python python theme={null}
  from netra import Netra

  Netra.init(app_name="sample-app")

  for span in Netra.usage.iter_spans_by_trace_id(
      trace_id="728c1de6fa4c53de143a7d7fef33ff91",
      direction="down",
      limit=100,
      span_name="generation_pipeline",
  ):
      print(
          "Span:",span.id,
          "name=", span.name,
          "kind=", span.kind,
          "duration_ms=", span.latency_ms,
      )
  ```
</CodeGroup>

<CodeGroup>
  ```python python theme={null}
  iter_spans_by_trace_id(
      trace_id: str,
      cursor: Optional[str] = None,
      direction: Optional[Literal["up", "down"]] = "down",
      limit: Optional[int] = None,
      span_name: Optional[str] = None,
  ) -> Iterator[TraceSpan]
  ```
</CodeGroup>

**Parameters**

* `trace_id: str`\
  Required. ID of the trace whose spans you want to iterate over.
* `cursor: Optional[str]`\
  Optional starting cursor for iteration.\
  `None` means start from the first spans page.
* `direction: Optional[Literal["up", "down"]]`\
  Pagination direction on each page, as above.
* `limit: Optional[int]`\
  Per‑page span count when streaming spans.
* `span_name: Optional[str]`\
  Optional `span_name` used to filter the list

## **When to Use Which API**

* `get_session_usage`**/** `get_tenant_usage`\
  High-level reporting: tokens, requests, and cost per session or tenant.
* `list_traces`**/** `iter_traces`\
  Explore what traces exist in a time window, optionally filtered by session, user, or tenant.
* `list_spans_by_trace_id`**/** `iter_spans_by_trace_id`\
  Drill into a single trace to understand all spans (tools, generations, workflows, etc.) that occurred within it.

Together, these APIs give you a complete picture of usage and tracing data,.
