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

# Query logs

> Returns a LogQuery builder scoped to one patient.

```python theme={null}
olira.logs(patient_id: str) -> LogQueryResult
```

**Requires scope:** `sdk:state-read`

Chain filter, projection, ordering, and aggregation methods, then call a terminal to run: .execute() → LogQueryResult, .count() → int, .single() / .maybe\_single() → dict. Filter paths must be rooted at type, timestamp, trace, or payload — other roots return 422. Add .with\_count() to include total\_count and has\_more in the response (one extra server-side COUNT op, opt-in). Server cap: limit ≤ 1000 per request — paginate with .limit(1000).offset(n) for larger result sets.

## Parameters

<ParamField body="patient_id" type="str" required>
  Olira patient id.
</ParamField>

## Returns

`LogQueryResult` — Iterable, indexable result. Call .as\_logs() to parse rows into typed LogEntry when no .select() was used.

<ResponseField name="count" type="int">
  Rows returned in this page.
</ResponseField>

<ResponseField name="rows" type="list[dict]">
  Projected or raw log dicts.
</ResponseField>

<ResponseField name="total_count" type="int | None">
  Total matching rows across all pages. Only set when .with\_count() was used.
</ResponseField>

<ResponseField name="has_more" type="bool | None">
  True when more rows exist beyond this page. Only set when .with\_count() was used.
</ResponseField>

<ResponseField name="patient_id" type="str | None">
  Echo of the queried patient id.
</ResponseField>

<ResponseField name="organization_id" type="str | None">
  Set on population queries.
</ResponseField>

## Raises

| Exception         | When                                                                                                                  |
| ----------------- | --------------------------------------------------------------------------------------------------------------------- |
| `ValidationError` | Unknown operator (client-side check), or HTTP 422 from the server (invalid field root, unsupported op, limit > 1000). |
| `AuthError`       | HTTP 401 or 403 — invalid API key or insufficient OAuth scope for this endpoint.                                      |
| `ServerError`     | HTTP 409 (e.g. conflicting external identifier) or repeated 5xx after retries; includes status\_code when applicable. |
| `RateLimitError`  | HTTP 429 — rate limited; check retry\_after (seconds).                                                                |
| `NetworkError`    | Connection timeout, DNS failure, or read error after retries.                                                         |

<RequestExample>
  ```python Python theme={null}
  import olira
  from olira import F

  olira.init(api_key="YOUR_API_KEY")

  # Filter, order, limit
  rows = (
      olira.logs("8a4fde23-0f1b-4c2a-9d7e-b36c1a5f0e82")
          .eq("type", "symptom_report")
          .gt("payload.score", 4)
          .order("timestamp", desc=True)
          .limit(50)
          .execute()
  )
  for row in rows:
      print(row["timestamp"], row["payload"])

  # .with_count() — total_count + has_more in one request (opt-in)
  rows = (
      olira.logs("8a4fde23-0f1b-4c2a-9d7e-b36c1a5f0e82")
          .eq("type", "symptom_report")
          .with_count()
          .limit(50)
          .execute()
  )
  print(rows.total_count, rows.has_more)   # e.g. 5000, True

  # Paginate through all matches (server cap: 1000/request)
  offset, all_rows = 0, []
  while True:
      batch = olira.logs("8a4fde23-0f1b-4c2a-9d7e-b36c1a5f0e82").eq("type", "symptom_report").limit(1000).offset(offset).execute()
      all_rows.extend(batch.rows)
      if len(batch) < 1000:
          break
      offset += 1000

  # Other patterns
  rows = olira.logs("8a4fde23-0f1b-4c2a-9d7e-b36c1a5f0e82").or_(F("payload.score").gt(7), F("type").eq("mood_report")).limit(10).execute()
  n    = olira.logs("8a4fde23-0f1b-4c2a-9d7e-b36c1a5f0e82").eq("type", "symptom_report").count()
  row  = olira.logs("8a4fde23-0f1b-4c2a-9d7e-b36c1a5f0e82").eq("type", "demographics").order("timestamp", desc=True).limit(1).maybe_single()
  ```

  ```http HTTP theme={null}
  POST /v1/state/8a4fde23-0f1b-4c2a-9d7e-b36c1a5f0e82/logs/query
  Authorization: Bearer YOUR_API_KEY
  Content-Type: application/json

  {
    "filter": [
      {"field": "type", "op": "eq", "value": "symptom_report"},
      {"field": "payload.score", "op": "gt", "value": 4}
    ],
    "order": [{"field": "timestamp", "desc": true}],
    "limit": 25
  }
  ```
</RequestExample>

<ResponseExample>
  ```python 200 theme={null}
  LogQueryResult(
      count=3,
      rows=[
          {"id": "log-1", "type": "symptom_report", "timestamp": "2026-01-14T12:00:00Z", "payload": {"score": 7}},
          {"id": "log-2", "type": "symptom_report", "timestamp": "2026-01-13T09:00:00Z", "payload": {"score": 5}},
          {"id": "log-3", "type": "symptom_report", "timestamp": "2026-01-12T08:00:00Z", "payload": {"score": 6}},
      ],
      patient_id="8a4fde23-0f1b-4c2a-9d7e-b36c1a5f0e82",
      organization_id=None,
  )
  ```

  ```json 401 theme={null}
  {
    "error": true,
    "status_code": 401,
    "error_type": "authentication_error",
    "message": "Could not validate credentials",
    "details": [
      {
        "type": "authentication_error",
        "message": "Could not validate credentials"
      }
    ],
    "timestamp": "2026-05-06T12:00:00+00:00"
  }
  ```

  ```json 403 theme={null}
  {
    "error": true,
    "status_code": 403,
    "error_type": "authorization_error",
    "message": "Insufficient OAuth scope for this endpoint",
    "details": [
      {
        "type": "authorization_error",
        "message": "Insufficient OAuth scope for this endpoint"
      }
    ],
    "timestamp": "2026-05-06T12:00:00+00:00"
  }
  ```

  ```json 404 theme={null}
  {
    "error": true,
    "status_code": 404,
    "error_type": "not_found_error",
    "message": "Patient not found",
    "details": [
      {
        "type": "not_found_error",
        "message": "Patient not found"
      }
    ],
    "timestamp": "2026-05-06T12:00:00+00:00"
  }
  ```

  ```json 422 theme={null}
  {
    "error": true,
    "status_code": 422,
    "error_type": "validation_error",
    "message": "Request validation failed (1 error)",
    "details": [
      {
        "type": "missing",
        "message": "Field required",
        "field": "patient_id",
        "location": ["body", "patient_id"],
        "input_value": null
      }
    ],
    "timestamp": "2026-05-06T12:00:00+00:00"
  }
  ```

  ```json 429 theme={null}
  {
    "error": true,
    "status_code": 429,
    "error_type": "server_error",
    "message": "Rate limit exceeded",
    "details": [
      {
        "type": "rate_limit",
        "message": "Too many requests; retry after backoff"
      }
    ],
    "timestamp": "2026-05-06T12:00:00+00:00"
  }
  ```

  ```json 500 theme={null}
  {
    "error": true,
    "status_code": 500,
    "error_type": "internal_server_error",
    "message": "An internal server error occurred",
    "details": [
      {
        "type": "internal_server_error",
        "message": "An unexpected error occurred while processing your request"
      }
    ],
    "timestamp": "2026-05-06T12:00:00+00:00"
  }
  ```
</ResponseExample>
