> For the complete documentation index, see [llms.txt](https://doc.ozforensics.com/oz-knowledge/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://doc.ozforensics.com/oz-knowledge/guides/administrator-guide/telemetry/echo-oz-telemetry-receiver.md).

# Echo: Oz Telemetry Receiver

Echo is a small FastAPI + MongoDB service that works with telemetry in Oz API. It has two jobs:

1. **Ingest** – accept batches of session-lifecycle (telemetry) events from the mobile SDK (mSDK) and Web SDK (WebSDK), de-duplicate and store them.
2. **Query** – let an authorized caller retrieve a session's stored events back out, for debugging or analysis.

Echo sits alongside the main Oz API, reachable through the same ingress/reverse proxy, at `/api/event_sessions`. It doesn’t affect analyses or any other processes.

## Where the data comes from

Each SDK session buffers a structured trace of events happened on client-side. This buffer is **not** sent to Echo directly or in real time.

On the Web SDK, the flow is:

{% code title="" expandable="true" %}

```
Browser (SDK)  →  SDK's own backend (buffered, ~every 3s)
                        │
                        ▼  background cron, batched + sampled
                   POST /api/event_sessions  →  Echo  →  MongoDB
```

{% endcode %}

Mobile SDK sessions follow the same shape (event batch → `POST /api/event_sessions`), with mobile-specific event names.

This means that:

* **Delivery is batched, not real-time.** The SDK's own backend waits for a session to go idle (defaults: \~60 minutes after session open, \~10 minutes after last activity) before shipping it to Echo. Thus, a session appears in Echo with a delay.
* **Delivery can be sampled.** A configurable sampling ratio (per-tenant, defaults to sending everything) can be set to only forward a fraction of sessions, for cost/volume control.
* **Delivery is best-effort.** If the send to Echo fails, it's logged and dropped – there's no retry queue. Echo isn't an authoritative audit trail of every session, it should be treated as a debugging and analytics aid, .

## Main API methods

Main methods that Echo uses are:

* `POST /api/event_sessions` – SDKs call this to submit a batch of events.
* `GET /api/event_sessions` – query stored sessions (access-restricted to an explicit allowlist of accounts).
* `GET /healthz`, `GET /livez`, `GET /version` – health/version checks, no auth required.

If Echo is installed as an API subcomponent, its endpoints are not exposed publicly. The only exception is Docker, where they can be accessed with an echo prefix: `GET /echo/version`.

### Endpoint list

<table data-header-hidden="false" data-header-sticky><thead><tr><th>Method &#x26; path</th><th>Auth</th><th>Purpose</th></tr></thead><tbody><tr><td><code>GET /version</code></td><td>none</td><td>Echo + MongoDB version info</td></tr><tr><td><code>GET /livez</code></td><td>none</td><td>Liveness probe</td></tr><tr><td><code>GET /healthz</code></td><td>none</td><td>Readiness probe (checks Mongo connectivity)</td></tr><tr><td><code>POST /api/authorize/auth</code></td><td>body: <code>{"credentials": {"email", "password"}}</code></td><td>Login, checked against <code>users.toml</code></td></tr><tr><td><code>POST /api/authorize/refresh</code></td><td>body: <code>{"expire_token"}</code></td><td>Exchange a refresh token for a new token pair</td></tr><tr><td><code>POST /api/event_sessions</code></td><td><code>X-Forensic-Access-Token</code> header, <code>Authorization: Bearer</code>, or a JWS-signed body</td><td>Ingest a batch of session events (called by the SDKs, not normally by clients directly)</td></tr><tr><td><code>GET /api/event_sessions</code></td><td>same as above, <strong>and</strong> the caller must be in the <code>service.toml</code> allow-list</td><td>Query stored sessions. Use filters if needed: <code>session_id</code>, <code>time_created.min/max</code>, <code>time_updated.min/max</code>, <code>device_family</code>, <code>device_platform</code>, <code>sdk_version</code>, <code>bundle_id</code>, <code>sorting</code>, <code>offset</code>/<code>cursor</code>, <code>limit</code>, <code>include_count</code></td></tr></tbody></table>

Every deployment also serves interactive documentation directly from the running service: `/docs` (Swagger UI), `/redoc`, and the raw schema at `/openapi.json`. Use these to explore the exact request/response shapes rather than relying solely on this table.

## Authentication

By default, Echo uses API access token and sends telemetry to the API address. For this, it requires:

* Echo installed as subcomponent and available via `{{api_host}}/api/event_sessions`.
* The non-service JWT token used .
* Public key from API JWT key pair set in Echo.

Here is how to set Echo as a telemetry receiver in SDK. We recommend creating a separate user in Echo and configure SDK for Echo separately.

Mobile SDKs require login and password. In the `users.toml` file of Echo, set:

{% code title="users.toml" expandable="true" %}

```toml
"your_email" = "your_strong_password"
```

{% endcode %}

Web SDK needs `service_token`, not JWT. Add to the `static_tokens.toml` Echo file:

{% code title="static\_tokens.toml" expandable="true" %}

```toml
"your_email" = "your-token-one,your-token-two"
```

{% endcode %}

## Obtaining telemetry

To read telemetry, you need to add the corresponding user to the service.toml Echo file.

Example:

```
emails = "your_email,your_another_email,api-uuid"
```

### Use cases

1. Create a telemetry reader user with the login <reader@localhost.local> and password 123:

{% code title="users.toml" %}

```toml
"reader@localhost.local" = "123"
```

{% endcode %}

{% code title="service.toml" %}

```toml
emails = "reader@localhost.local"
```

{% endcode %}

2. Create a telemetry reader user with the login `reader@localhost.local` and token `token`:

{% code title="static\_tokens.toml" %}

```toml
"reader@localhost.local" = "token"
```

{% endcode %}

{% code title="service.toml" %}

```toml
emails = "reader@localhost.local"
```

{% endcode %}

3. Create a telemetry reader API user with UUID = `1111aaaa-11aa-11aa-11aa-111111aaaaaa`:

{% code title="service.toml" %}

```toml
emails = "1111aaaa-11aa-11aa-11aa-111111aaaaaa"
```

{% endcode %}

The public Oz API JWT key must be configured in Echo.

## Configuration

This reference applies to all install paths. What differs between paths is now what setting means but *how* it reaches Echo. This may be a raw environment variable in Docker/Compose or a Helm value that becomes a ConfigMap/Secret entry. Each install guide notes path-specific details; this document is the shared source of truth for meaning and defaults.

### Environment variables

Both variables are functionally required.

| Variable          | Default                      | Description                                 |
| ----------------- | ---------------------------- | ------------------------------------------- |
| `MONGODB_URL`     | `mongodb://localhost:27017/` | MongoDB connection string                   |
| `MONGODB_DB_NAME` | `dbname`                     | Database name for the `sessions` collection |

### TOML file formats

`users.toml` – login accounts (email → password):

```toml
"your_email" = "your_strong_password"
```

`static_tokens.toml` – pre-shared bearer tokens (email → comma-separated tokens):

```toml
"your_email" = "your-token-one,your-token-two"
```

`service.toml` – allowlist for `GET /api/event_sessions` (comma-separated emails or uuids):

```toml
emails = "your_email,your_another_email,uuid"
```

### Query parameter notes

* `cursor` (opaque string, returned as `next_cursor` in responses) is the recommended way to page through large result sets – it's more efficient than `offset` and mutually exclusive with it.
* `include_count` defaults to `true`; set it to `false` if you don't need the total count and want a faster response.
* `device_family` matches by substring/pattern, not exact match; `device_platform`, `sdk_version`, and `bundle_id` match exactly.

### Optional: conversion-funnel log export

Echo can optionally maintain a short-lived buffer (in Redis) of in-progress sessions and, once a session goes idle, emit one structured JSON log line summarizing its funnel result – intended for a log-shipping pipeline into your own analytics system, as an alternative to querying Echo's API directly.

This is off by default and **not wired up by either Helm chart** – turning it on requires reachable Redis plus these settings (via `envs` on the Helm paths, or plain environment variables on the Docker paths):

| Variable                            | Default                  | Purpose                                                   |
| ----------------------------------- | ------------------------ | --------------------------------------------------------- |
| `LOG_CONVERSION_ENABLED`            | `false`                  | Master switch                                             |
| `REDIS_URL`                         | `redis://localhost:6379` | Redis connection string                                   |
| `LOG_CONVERSION_SESSION_MINUTE_TTL` | `30`                     | Minutes a session is buffered before being flushed/logged |

If you want this feature, you'll need to provide your own Redis instance reachable from Echo – none of the install paths provision one for this purpose.

## Installation

We recommend using Echo in our cloud: in this case, you don’t host anything, and the installation efforts are minimal. All you need is credentials and Echo endpoint, both will be provided by Oz representative. Then, depending on SDK you use, set up echo connection.

Web SDK: by default, we send telemetry to the API URL, but if this URL is a direct path, add these parameters to the [Web Adapter configuration file](/oz-knowledge/guides/administrator-guide/configuration/web-adapter/configuration-file-settings.md):

<pre data-title="" data-expandable="true"><code>"tm_url":"your_echo_endpoint<a data-footnote-ref href="#user-content-fn-1">/api/</a>",
"tm_token":"&#x3C;TOKEN>"
</code></pre>

Mobile SDK: follow the instructions.

* [Android](/oz-knowledge/guides/developer-guide/sdk/oz-mobile-sdk/android/connecting-sdk-to-api.md)
* [iOS](/oz-knowledge/guides/developer-guide/sdk/oz-mobile-sdk/ios/connecting-sdk-to-api.md)
* [Flutter](/oz-knowledge/guides/developer-guide/sdk/oz-mobile-sdk/flutter/how-to-install-and-use-oz-flutter-plugin.md#connect-sdk-to-oz-api)

If you are going to install Echo within your infrastructure, please choose the installation option:

* [Standalone Docker](/oz-knowledge/guides/administrator-guide/telemetry/echo-oz-telemetry-receiver/standalone-docker.md)
* [Echo within API via Docker Compose](/oz-knowledge/guides/administrator-guide/telemetry/echo-oz-telemetry-receiver/docker-compose.md)
* [Standalone `oz-echo` Helm chart](/oz-knowledge/guides/administrator-guide/telemetry/echo-oz-telemetry-receiver/standalone-oz-echo-helm-chart.md)
* [`oz-echo` as a part of `api-decomposed` (oz-k8s)](/oz-knowledge/guides/administrator-guide/telemetry/echo-oz-telemetry-receiver/oz-echo-as-a-part-of-api-decomposed-oz-k8s.md)

[^1]: a required addition


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://doc.ozforensics.com/oz-knowledge/guides/administrator-guide/telemetry/echo-oz-telemetry-receiver.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
