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

# Formato de respuesta de la API y ejemplos de respuestas JSON

> Interpreta las respuestas de la API de LogBrew: listas de telemetría, páginas por cursor, eventos en vivo, cambios, estados de éxito y de error.

Esta página muestra un ejemplo de cada familia de respuestas de la
[API de telemetría](/es/reference/telemetry-api). Todos los valores son
ficticios. Para los códigos de error y cómo recuperarte, consulta
[Errores de la API](/es/reference/api-errors).

## Lee una respuesta

Lee cada respuesta en este orden:

1. Lee el estado HTTP.
2. Comprueba que el cuerpo tiene la estructura propia de la ruta.
3. Comprueba que cada `project_id` está dentro del alcance de proyecto
   solicitado.
4. Conserva sin cambios los valores canónicos de los enums y los
   identificadores.
5. Sigue `next_action` solo cuando el cliente admita su `code` y su
   `target`.
6. Trata `null`, un campo omitido y una lista vacía como estados distintos.

Un `200 OK` puede contener una lista vacía. Una lista de logs vacía significa
que ningún log coincidió con la solicitud. No significa que las incidencias,
las trazas o las acciones también estén vacías. No relaciones señales porque
sus marcas de tiempo estén próximas. Sigue una traza solo cuando la respuesta
contenga su `trace_id` exacto.

Un `404` y una lista vacía son resultados distintos. Una ruta de lista
devuelve `[]` cuando ningún registro coincide. Una ruta de detalle devuelve
`404` con `code: not_found` cuando no encuentra un registro legible. Ninguno de
los dos resultados demuestra que la ingesta haya fallado.

## Qué enviar

Las respuestas solo son tan útiles como la telemetría que envías. Envía estos
valores en cada sobre o configuración del SDK:

* `release` y `environment`.
* Nombres estables para servicios, acciones y métricas.
* Contexto de la traza cuando los logs, los spans, las acciones y las
  incidencias pertenecen a la misma solicitud.
* Valores canónicos de severidad: `info`, `warning`, `error` y `critical`.
* Atributos que ayuden a depurar, sin secretos ni datos personales
  innecesarios.

Consulta [Integración del SDK](/es/guides/sdk-ingestion) y
[Controlar los datos capturados](/es/guides/safe-capture).

## Respuesta de ingesta

Los SDK públicos leen la respuesta de `POST /v1/events` por ti. El código de tu
aplicación no tiene que gestionarla.

### Respuesta de lote del SDK

Un lote del SDK aceptado devuelve `200 OK` con el número de eventos aceptados
de cada flujo:

```json theme={null}
{
  "issues": 1,
  "logs": 2,
  "trace_spans": 3,
  "actions": 1,
  "metrics": 1,
  "already_accepted": 0,
  "context_updated": true,
  "next": "review accepted telemetry in logs, issues, traces, actions, metrics, or live feed",
  "next_action": {
    "code": "review_ingested_telemetry",
    "target": "telemetry_reads"
  }
}
```

| Campo | Significado |
| - | - |
| `issues`, `logs`, `trace_spans`, `actions`, `metrics` | Eventos de este lote que LogBrew aceptó. |
| `already_accepted` | Eventos cuyo ID LogBrew ya había aceptado. LogBrew no los vuelve a guardar. |
| `context_updated` | `true` cuando el lote actualizó el contexto de release o de entorno. |

Los recuentos cubren solo este lote. Si reintentas un lote que LogBrew ya
aceptó, la respuesta devuelve `0` en cada flujo y el número de eventos en
`already_accepted`. Conserva los ID de evento originales al reintentar.

### Respuesta del sobre nativo

`POST /api/telemetry/ingest` devuelve `200 OK` con el número de elementos
aceptados de cada flujo:

```json theme={null}
{
  "issues": 0,
  "logs": 1,
  "trace_spans": 0,
  "actions": 1,
  "already_accepted": 0,
  "next": "review accepted telemetry in logs, issues, traces, actions, or live feed",
  "next_action": {
    "code": "review_ingested_telemetry",
    "target": "telemetry_reads"
  }
}
```

La respuesta nativa no tiene los campos `metrics` ni `context_updated`. No los
añadas. `already_accepted` cuenta los elementos cuyo `id` LogBrew ya había
aceptado para el proyecto. Consulta el
[sobre nativo directo](/es/guides/sdk-ingestion#required-envelope-fields).

### Errores de ingesta

Un `401` con `code: ingest_key_invalid` significa que el token bearer de ingesta
está revocado, ha caducado o no es válido para el proyecto. En
`POST /v1/events`, si falta el token bearer o no es una clave de ingesta,
la respuesta es `401` con `code: unauthorized`. Usa el token bearer de ingesta
actual del proyecto. No reintentes con un token bearer de cuenta.

Un lote del SDK rechazado devuelve `422` con `code: validation_failed`:

```json theme={null}
{
  "error": "SDK event ids must be unique within a batch",
  "code": "validation_failed",
  "next": "send release/environment context plus issue, log, span, action, or metric events from a current LogBrew SDK",
  "next_action": {
    "code": "fix_request",
    "target": "request"
  }
}
```

Otros valores de `error` son `SDK event batch requires at least one event` y
`SDK event type is not supported by this ingest route`. Comprueba la versión
del SDK y la configuración del transporte. No envíes un lote vacío. No cambies
los tipos ni los ID de los eventos solo para que un lote pase la validación.

Una solicitud con un método distinto de `POST` devuelve `405` con
`code: method_not_allowed`. Un cuerpo JSON ilegible devuelve
`code: invalid_json`.

## Formato de respuesta de las listas de telemetría

Las rutas de lista devuelven un array JSON simple de forma predeterminada. Una
lista vacía correcta es `[]`.

Con `pagination=cursor`, la ruta devuelve un sobre. La clave de la colección
corresponde a la señal:

| Ruta | Clave de la colección |
| - | - |
| `/api/logs` | `logs` |
| `/api/telemetry/issues` | `issues` |
| `/api/telemetry/issues/{issue_id}/events` | `events`, con un `issue_id` en el nivel superior |
| `/api/telemetry/actions` | `actions` |
| `/api/telemetry/metrics` | `metrics` |
| `/api/telemetry/releases` | `releases` |
| `/api/telemetry/traces` | `traces`, con un `naming_quality` en el nivel superior |

`next_cursor` es un objeto con los campos para continuar, o `null` en la última
página. Las filas van de la más reciente a la más antigua. Consulta
[paginación por cursor](/es/reference/telemetry-api-filters#cursor-pagination).

### <span id="log-response">Respuesta de logs</span>

Una página por cursor de logs con `limit=1`:

```json theme={null}
{
  "logs": [
    {
      "id": "150d1288-bec2-49ec-a036-3f7ac55f1b2d",
      "project_id": "123e4567-e89b-12d3-a456-426614174000",
      "level": "warning",
      "severity": "warning",
      "triage": {
        "effective_severity": "warning",
        "ignored": false,
        "rule_applied": false
      },
      "source": "runtime",
      "message": "checkout retry scheduled",
      "attributes": { "route": "/checkout" },
      "occurred_at": "2026-06-01T12:00:00Z",
      "environment": "production",
      "release": "api@1.2.3",
      "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
      "span_id": "00f067aa0ba902b7",
      "service_name": "checkout-api",
      "sdk_name": "@logbrew/node",
      "sdk_version": "0.1.8",
      "next_action": {
        "code": "inspect_trace",
        "target": "trace_summary"
      }
    }
  ],
  "next_cursor": {
    "time": "2026-06-01T12:00:00Z",
    "id": "150d1288-bec2-49ec-a036-3f7ac55f1b2d"
  }
}
```

Los logs incluyen `level` por compatibilidad y `severity` para mostrar. Los
dos tienen el valor canónico. `triage` guarda el resultado de una regla de
severidad. Consulta
[respuestas de las reglas de severidad](#severity-rule-responses).

`trace_id` y `span_id` son `null` cuando el log no tiene enlace a una traza. En
ese caso, `next_action` es `inspect_related_logs` con el destino
`telemetry_logs`. Los logs, las incidencias y las acciones usan los mismos 2
pares de `next_action`.

`GET /api/logs/{log_id}` devuelve un log con la misma estructura.

### <span id="issue-response">Respuesta de incidencias</span>

`GET /api/telemetry/issues/{issue_id}` devuelve una incidencia agrupada. La
lista devuelve los mismos objetos. Este ejemplo usa la versión de respuesta
predeterminada, la 1:

```json theme={null}
{
  "id": "9b2b4b3a-bd4e-4f85-a0f6-48118f037c17",
  "project_id": "123e4567-e89b-12d3-a456-426614174000",
  "fingerprint": "payment-error",
  "severity": "error",
  "triage": {
    "effective_severity": "error",
    "ignored": false,
    "rule_applied": false
  },
  "title": "PaymentError",
  "message": "payment provider timed out",
  "stack_trace": null,
  "attributes": {},
  "environment": "production",
  "release": "checkout@1.2.3",
  "service_name": "checkout-api",
  "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
  "span_id": "00f067aa0ba902b7",
  "next_action": {
    "code": "inspect_trace",
    "target": "trace_summary"
  },
  "status": "unresolved",
  "occurrence_count": 2,
  "first_seen_at": "2026-07-13T07:00:00Z",
  "last_seen_at": "2026-07-13T08:00:00Z"
}
```

En la versión 1, `status` es `unresolved`, `resolved` o `ignored`. En una
incidencia archivada, `triage.ignored` es `true`. Para ver los pares de
`next_action` y las lecturas que siguen, consulta
[Investigar una incidencia](/es/guides/investigate-an-issue).

`first_seen_at` y `last_seen_at` son las horas de la primera ocurrencia y de la
más reciente. No cambian cuando cambia el estado.

Algunos campos aparecen solo cuando LogBrew tiene los datos:

| Campo | Cuándo aparece |
| - | - |
| `span_id` | La incidencia tiene un enlace a un span. Si no, el campo se omite. |
| `diagnostics` | La última ocurrencia tiene un tipo de excepción o pasos anteriores. Consulta [historial de ocurrencias de una incidencia](#issue-occurrence-history). |
| `symbolication` | Solo en `GET /api/telemetry/issues/{issue_id}`, cuando la incidencia tiene una identidad de artefacto de release. Consulta [Mapas de origen de JavaScript](/es/guides/source-maps). |

`symbolication.status` es `resolved`, `invalid_metadata`,
`artifact_not_found`, `source_not_resolved` o `unavailable`. La lista, los
cambios de estado y los cambios de reglas no devuelven `symbolication`.

Con `response_version=2`, la incidencia tiene los mismos campos, con estos
cambios:

| Campo | Valor en la versión 2 |
| - | - |
| `status` | `unresolved`, `resolved` o `archived`. La versión 1 muestra `archived` como `ignored`. |
| `priority` | `high`, `medium` o `low`. |
| `priority_source` | `manual` cuando una persona fijó la prioridad. `derived` cuando la prioridad sigue la severidad efectiva. |

```json theme={null}
{
  "id": "9b2b4b3a-bd4e-4f85-a0f6-48118f037c17",
  "status": "archived",
  "severity": "error",
  "priority": "low",
  "priority_source": "manual"
}
```

Este ejemplo muestra solo algunos campos. Una prioridad derivada es `high` para
`error` y `critical`, `medium` para `warning` y `low` para `info`. Usa
`triage.effective_severity`, así que una regla de severidad de la incidencia
puede cambiarla.

Con `response_version=3`, la incidencia tiene todos los campos de la versión 2
y `assignee`. `assignee` es `null` cuando la incidencia no tiene responsable:

```json theme={null}
{
  "id": "9b2b4b3a-bd4e-4f85-a0f6-48118f037c17",
  "status": "unresolved",
  "priority": "high",
  "priority_source": "derived",
  "assignee": {
    "user_id": "5d6e7f80-1a2b-4c3d-8e4f-5a6b7c8d9e0f",
    "name": "Ada Example",
    "email": "ada@example.com"
  }
}
```

| Campo | Significado |
| - | - |
| `assignee.user_id` | ID de usuario del responsable. Envíalo como `assignee` en un filtro o en un cambio. |
| `assignee.name` | Nombre del responsable, o `null` cuando la cuenta no tiene nombre. |
| `assignee.email` | Dirección de correo electrónico del responsable. |

Una incidencia aparece sin responsable cuando el miembro asignado ya no puede
leer el proyecto.

Con `response_version=4`, `assignee` también tiene `type`. Un responsable
`user` tiene `user_id`, `name` y `email`, como en la versión 3. Un responsable
`team` tiene `team_id`, `slug` y `name`. La versión 3 muestra un equipo
responsable como `null`. La CLI solicita la versión 4:

```json theme={null}
{
  "assignee": {
    "type": "team",
    "team_id": "7c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
    "slug": "payments",
    "name": "Payments"
  }
}
```

Cualquier otro `response_version` devuelve `422` con
`code: validation_failed`. Una página por cursor usa la misma versión para
todas las incidencias de `issues`.

### <span id="assignee-list-response">Respuesta de la lista de responsables</span>

`GET /api/telemetry/issues/assignees?project_id=<project_id>` devuelve todas
las cuentas a las que se pueden asignar incidencias en el proyecto:

```json theme={null}
{
  "project_id": "123e4567-e89b-12d3-a456-426614174000",
  "assignees": [
    {
      "user_id": "5d6e7f80-1a2b-4c3d-8e4f-5a6b7c8d9e0f",
      "name": "Ada Example",
      "email": "ada@example.com"
    },
    {
      "user_id": "0f1e2d3c-4b5a-4968-8776-655443322110",
      "name": null,
      "email": "sam@example.com"
    }
  ]
}
```

Añade `response_version=2` para obtener también `teams`: todos los equipos de
la organización del proyecto, con `team_id`, `slug` y `name`.

Si la cuenta no puede leer el proyecto, la ruta devuelve `404` con
`code: not_found`.

### <span id="action-response">Respuesta de acciones</span>

```json theme={null}
{
  "id": "d8ee3a6f-3918-440b-96cb-14166419399a",
  "project_id": "123e4567-e89b-12d3-a456-426614174000",
  "name": "checkout_failed",
  "distinct_id": "user_123",
  "session_id": "session_456",
  "occurred_at": "2026-06-01T12:00:00Z",
  "properties": { "surface": "checkout" },
  "environment": "production",
  "release": "checkout@1.2.3",
  "service_name": "checkout-api",
  "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
  "span_id": "00f067aa0ba902b7",
  "next_action": {
    "code": "inspect_trace",
    "target": "trace_summary"
  }
}
```

`distinct_id` sigue a un actor o a una sesión. Trata `distinct_id` y
`session_id` como identificadores opacos. `session_id` y `trace_id` son `null`
cuando faltan. `span_id` se omite cuando falta. Una acción no tiene severidad.
Consulta [Captura de eventos de producto](/es/guides/product-events).

### Respuesta de métricas

```json theme={null}
{
  "id": "6f1c2d3e-4a5b-4c6d-8e7f-901234567890",
  "event_id": "metric-1",
  "project_id": "123e4567-e89b-12d3-a456-426614174000",
  "name": "http.server.duration",
  "kind": "histogram",
  "value": 12.5,
  "unit": "ms",
  "temporality": "delta",
  "attributes": {},
  "occurred_at": "2026-07-13T08:00:00Z",
  "environment": "production",
  "release": "checkout@1.2.3",
  "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
  "span_id": "00f067aa0ba902b7",
  "service_name": "checkout-api",
  "sdk_name": "@logbrew/node",
  "sdk_version": "0.1.8"
}
```

Cada elemento es una muestra. No uses el número de muestras como recuento de
eventos o de usuarios. `unit`, `temporality`, `trace_id` y `span_id` son
`null` cuando faltan. Un valor `null` no es cero.

### Respuesta de releases

```json theme={null}
{
  "project_id": "123e4567-e89b-12d3-a456-426614174000",
  "release": "api@1.2.3",
  "environment": "production",
  "service_name": "checkout-api",
  "issue_count": 3,
  "log_count": 824,
  "trace_span_count": 421,
  "action_count": 19,
  "metric_count": 87,
  "first_seen_at": "2026-06-01T12:00:00Z",
  "last_seen_at": "2026-06-01T12:15:00Z",
  "trace_health": {
    "status": "errors_observed",
    "trace_count": 42,
    "error_trace_count": 3,
    "error_rate_basis_points": 714
  },
  "next_action": {
    "code": "inspect_release_issues",
    "target": "telemetry_issues"
  }
}
```

Una fila cubre un proyecto, un release, un entorno y un servicio. Sus
recuentos describen solo esa fila.

`trace_health.status` es `unknown` cuando la fila no tiene trazas,
`no_errors_observed` o `errors_observed`. `error_rate_basis_points` es la
proporción de trazas con un span de error, de `0` a `10000`. No es una tasa de
error de todas las solicitudes.

`next_action` apunta al primer tipo de señal que tiene datos, en este orden:

| `code` | `target` |
| - | - |
| `inspect_release_issues` | `telemetry_issues` |
| `inspect_release_traces` | `trace_explorer` |
| `inspect_release_logs` | `telemetry_logs` |
| `inspect_release_actions` | `telemetry_actions` |
| `inspect_release_metrics` | `telemetry_metrics` |
| `review_release_telemetry` | `telemetry_reads` |

Consulta [Releases](/es/concepts/releases).

### Respuesta de la búsqueda de trazas

`GET /api/telemetry/traces?pagination=cursor` devuelve una fila por traza y un
comprobante `naming_quality` de la página devuelta:

```json theme={null}
{
  "traces": [
    {
      "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
      "project_ids": ["123e4567-e89b-12d3-a456-426614174000"],
      "root_span_name": "POST /checkout",
      "root_service_name": "checkout-api",
      "root_operation": "http.server",
      "span_count": 3,
      "error_span_count": 1,
      "service_count": 1,
      "started_at": "2026-06-01T12:00:00Z",
      "duration_ms": 45,
      "services": ["checkout-api"],
      "releases": ["checkout@1.2.3"],
      "environments": ["production"],
      "next_action": {
        "code": "inspect_trace",
        "target": "trace_summary"
      }
    }
  ],
  "next_cursor": null,
  "naming_quality": {
    "evaluated_traces": 1,
    "meaningful_name_traces": 1,
    "generic_name_traces": 0,
    "unmatched_route_traces": 0,
    "generic_operation_traces": 0,
    "truncated": false,
    "next_action": null
  }
}
```

`naming_quality` cubre solo la página devuelta. No es una puntuación de toda la
cuenta. `truncated: true` significa que existe otra página. Cuando la página
tiene un nombre genérico, una ruta sin coincidencia o una operación genérica,
`next_action` es `improve_trace_naming` con el destino `sdk_configuration`. Sin
`pagination=cursor`, la ruta devuelve un array simple de trazas y ningún
`naming_quality`.

`next_cursor` contiene `time` y `trace_id`. Envíalos como `cursor_time` y
`cursor_trace_id`.

`GET /api/telemetry/traces/{trace_id}` devuelve los spans de una traza.
`GET /api/telemetry/traces/{trace_id}/summary` devuelve el span raíz, los spans
de error, los servicios, la duración y la ruta más lenta, sin los atributos
sin procesar de los spans. Un `404` del resumen significa que ninguna traza
coincidió con el alcance completo. No reintentes sin los filtros. Consulta
[respuestas de spans y del resumen de una traza](#trace-spans-and-summary-responses).

### Listas vacías y registros ausentes

Una lectura de lista puede no tener coincidencias. Una lectura de detalle tiene
otro contrato:

| Solicitud | Éxito | Ningún registro legible |
| - | - | - |
| `GET /api/logs/{log_id}` | `200` con un [log](#log-response) | `404` con `code: not_found` |
| `GET /api/telemetry/issues/{issue_id}` | `200` con una [incidencia](#issue-response) | `404` con `code: not_found` |
| `GET /api/telemetry/issues/{issue_id}/events` | `200` con ocurrencias | `404` con `code: not_found` en la primera página |
| `GET /api/telemetry/traces/{trace_id}` | `200` con spans | `200` con `[]` |
| `GET /api/telemetry/traces/{trace_id}/summary` | `200` con un resumen | `404` con `code: not_found` |

Un log ausente devuelve este `404`:

```json theme={null}
{
  "error": "log not found",
  "code": "not_found",
  "next": "check the resource id or filters and retry",
  "next_action": {
    "code": "check_resource",
    "target": "resource"
  }
}
```

Una incidencia ausente usa `"error": "issue not found"`. Un resumen de traza
ausente usa `"error": "trace not found"`. Un ID desconocido y un ID que la
cuenta no puede leer devuelven la misma respuesta.

Una lista con un `project_id` que la cuenta no puede leer devuelve `200` con
una lista vacía. Comprueba el ID del proyecto antes de informar de que no hay
datos.

### Selecciones de proyectos rechazadas

Las listas de logs, incidencias, acciones, métricas, releases y trazas aceptan
un proyecto con `project_id` o de 2 a 50 proyectos con `project_ids`. El
catálogo de atributos de logs acepta los mismos selectores. El historial de
ocurrencias de una incidencia no los acepta.

Una solicitud con `project_id` y `project_ids` a la vez devuelve `422`:

```json theme={null}
{
  "error": "project_id and project_ids are mutually exclusive",
  "code": "validation_failed",
  "next": "use project_id for one project, project_ids=uuid,uuid for two to fifty projects, or omit both for all readable projects",
  "next_action": {
    "code": "fix_request",
    "target": "request"
  }
}
```

`project_ids` con un UUID no válido, un ID repetido, o menos de 2 o más de 50
ID también devuelve `422` con `code: validation_failed`.

Si la cuenta no puede leer uno de los proyectos de `project_ids`, toda la
solicitud devuelve `404`. No devuelve los demás proyectos como resultado
parcial:

```json theme={null}
{
  "error": "project selection not found",
  "code": "not_found",
  "next": "refresh readable projects and retry with only project IDs you can read",
  "next_action": {
    "code": "check_resource",
    "target": "resource"
  }
}
```

Muestra el error, no una lista vacía ni un recuento de cero. Vuelve a leer la
lista de proyectos. No quites un proyecto sin avisar y no reintentes con todos
los proyectos. Una credencial delegada, como un grant de MCP, devuelve `403`
con `code: forbidden` para un proyecto fuera de su grant. Consulta
[alcance del proyecto](/es/reference/telemetry-api-filters#project-scope).

### <span id="cursor-errors">Errores de cursor</span>

Los logs, las incidencias, las acciones, las métricas y las ocurrencias de
incidencias usan `cursor_time` y `cursor_id`. Un cursor rechazado devuelve
`422` con `code: validation_failed`. Estos errores no significan que la lista
esté vacía.

| Solicitud | `error` |
| - | - |
| `pagination=cursor` con solo 1 de los 2 campos de cursor | `cursor_time and cursor_id must be sent together` |
| `cursor_time` que no es una marca de tiempo RFC3339 | `cursor_time must be an RFC3339 timestamp` |
| Campos de cursor sin `pagination=cursor`, o con otro valor de `pagination` | `pagination must be cursor when cursor pagination is requested` |

Por ejemplo:

```json theme={null}
{
  "error": "cursor_time and cursor_id must be sent together",
  "code": "validation_failed",
  "next": "send pagination=cursor alone for the first page, then send cursor_time and cursor_id together from next_cursor",
  "next_action": {
    "code": "fix_request",
    "target": "request"
  }
}
```

Copia el `next_cursor` completo de la página anterior. No sustituyas
`cursor_time` por la hora actual. Si perdiste el cursor, empieza de nuevo con
`pagination=cursor` y los filtros originales. Una clave de consulta
desconocida o un valor de tipo incorrecto devuelve `422` con
`"error": "invalid query parameters"`.

### Respuestas con cursor de releases

Un cursor de releases tiene 5 campos. Una solicitud correcta sin coincidencias
devuelve `200`:

```json theme={null}
{
  "releases": [],
  "next_cursor": null
}
```

Cuando `next_cursor` no es `null`, envía los 5 valores en la siguiente
solicitud:

| Campo de `next_cursor` | Parámetro de consulta |
| - | - |
| `time` | `cursor_time` |
| `project_id` | `cursor_project_id` |
| `release` | `cursor_release` |
| `environment` | `cursor_environment` |
| `service_name` | `cursor_service_name` |

`cursor_project_id` marca una posición. No sustituye a `project_id` ni a
`project_ids`. Conserva los parámetros de proyecto y de filtro originales.
Codifica cada valor para URL.

Con `pagination=cursor`, un cursor parcial o un valor vacío de release,
entorno o servicio devuelve `422` con
`"error": "all release cursor fields must be sent together"`. Un `cursor_time`
no válido y la falta de `pagination=cursor` devuelven los mismos errores que
los [demás cursores](#cursor-errors).

### Errores de la búsqueda de trazas

Estos errores se aplican a `GET /api/telemetry/traces`. Cada uno devuelve
`422` con `code: validation_failed`. Una solicitud rechazada no es un
resultado vacío.

| Solicitud | `error` |
| - | - |
| `status` distinto de `error` u `ok` | `trace status must be error or ok` |
| `min_duration_ms` por debajo de `0` | `minimum trace duration must not be negative` |
| Solo 1 campo de cursor, o un `cursor_trace_id` vacío | `cursor_time and cursor_trace_id must be sent together` |
| `cursor_time` que no es una marca de tiempo RFC3339 | `cursor_time must be an RFC3339 timestamp` |
| Campos de cursor sin `pagination=cursor` | `pagination must be cursor when cursor pagination is requested` |

Para incluir los dos estados de traza, omite `status`. Para la siguiente
página, copia `next_cursor.time` en `cursor_time` y `next_cursor.trace_id` en
`cursor_trace_id`. No envíes `cursor_id` en una página de trazas. Consulta
[filtros de trazas](/es/reference/telemetry-api-filters#trace-filters).

### <span id="issue-occurrence-history">Historial de ocurrencias de una incidencia</span>

`GET /api/telemetry/issues/{issue_id}/events` lee las ocurrencias de una
incidencia agrupada. Usa un token bearer de cuenta y el ID de la incidencia
agrupada. La ruta solo acepta `pagination`, `cursor_time`, `cursor_id` y
`limit`. No acepta filtros de proyecto, tiempo, release, entorno ni severidad.

```bash theme={null}
curl --get "https://api.logbrew.co/api/telemetry/issues/$ISSUE_ID/events" \
  --header "Authorization: Bearer $LOGBREW_ACCOUNT_BEARER" \
  --data-urlencode "pagination=cursor" \
  --data-urlencode "limit=1"
```

Una primera página con una ocurrencia y un cursor para continuar:

```json theme={null}
{
  "issue_id": "d1776d70-763c-47b5-a8f1-76f593221e2b",
  "events": [
    {
      "id": "db619770-1f7c-4bd5-8310-9f171df8af47",
      "issue_id": "d1776d70-763c-47b5-a8f1-76f593221e2b",
      "project_id": "123e4567-e89b-12d3-a456-426614174000",
      "severity": "error",
      "title": "Checkout failed",
      "message": "Checkout could not complete",
      "stack_trace": null,
      "attributes": {
        "exception": {
          "type": "CheckoutError",
          "mechanism": { "type": "javascript.error", "handled": false }
        },
        "breadcrumbs": [
          {
            "timestamp": "2026-06-01T11:54:59Z",
            "category": "checkout",
            "message": "Checkout started"
          }
        ]
      },
      "diagnostics": {
        "schema_version": 1,
        "exception": {
          "type": "CheckoutError",
          "mechanism": { "type": "javascript.error", "handled": false }
        },
        "breadcrumbs": [
          {
            "timestamp": "2026-06-01T11:54:59Z",
            "category": "checkout",
            "message": "Checkout started"
          }
        ],
        "breadcrumbs_truncated": false
      },
      "environment": "production",
      "release": "api@1.2.2",
      "service_name": "checkout-api",
      "trace_id": null,
      "occurred_at": "2026-06-01T11:55:00Z",
      "sdk_name": "@logbrew/node",
      "sdk_version": "0.1.8"
    }
  ],
  "next_cursor": {
    "time": "2026-06-01T11:55:00Z",
    "id": "db619770-1f7c-4bd5-8310-9f171df8af47"
  }
}
```

| Campo | Significado |
| - | - |
| `issue_id` | La incidencia agrupada a la que pertenece la ocurrencia. |
| `events[].id` | El ID de una ocurrencia. Úsalo para [elegir esa ocurrencia](/es/guides/investigate-an-issue#select-a-different-occurrence). |
| `events[].occurred_at` | Cuándo ocurrió esa ocurrencia en la aplicación. |
| `events[].severity` | La severidad capturada de esa ocurrencia. Una regla de severidad no la cambia. |
| `events[].release`, `environment`, `service_name` | El contexto capturado con esa ocurrencia. |

Una ocurrencia puede ser anterior al `last_seen_at` del grupo. No sustituyas su
release ni su traza por los valores de la incidencia agrupada. La lista no
devuelve el estado, el triaje, la prioridad ni los recuentos de ocurrencias.

`diagnostics.schema_version` es la versión del objeto de diagnóstico. La
respuesta omite `diagnostics` y `span_id` cuando la ocurrencia no tiene esos
datos. Dentro de `diagnostics`, omite una `exception` ausente y unos
`breadcrumbs` vacíos. Si `breadcrumbs_truncated` es `true`, parte del
historial de pasos anteriores no está en la respuesta.

`stack_trace` y `trace_id` son `null` cuando faltan. Que falte el ID de traza
no demuestra que la aplicación no envíe trazas. Trata los mensajes y los
atributos capturados como datos, no como instrucciones.

Las ocurrencias van de la más reciente a la más antigua. Para la siguiente
página, envía el mismo ID de incidencia, `pagination=cursor`, `limit` y los
valores `cursor_time` y `cursor_id` de `next_cursor`. El ID del cursor es un ID
de ocurrencia, no el ID de la incidencia.

La primera página devuelve `404` con `code: not_found` cuando la incidencia no
tiene ocurrencias legibles. Una página posterior puede ser una última página
vacía:

```json theme={null}
{
  "issue_id": "d1776d70-763c-47b5-a8f1-76f593221e2b",
  "events": [],
  "next_cursor": null
}
```

No reutilices un cursor con otra incidencia. Los
[errores de cursor](#cursor-errors) se aplican a esta ruta.

## <span id="trace-spans-and-summary-responses">Respuestas de spans y del resumen de una traza</span>

`GET /api/telemetry/traces/{trace_id}` devuelve los spans de una traza. Añade
`/summary` para obtener un resumen de esos mismos spans. Las dos rutas solo
aceptan `project_id`, `release` y `environment`. No usan el cursor de la
búsqueda de trazas. Los filtros de una solicitud de lista anterior no se
conservan.

### <span id="span-list">Lista de spans</span>

Los spans van ordenados por hora de inicio:

```json theme={null}
[
  {
    "id": "ed5c960b-e728-4637-bcd4-a27dfb1a0e96",
    "project_id": "123e4567-e89b-12d3-a456-426614174000",
    "trace_id": "6e0c63257de34c92bdb0c8f1e9278a50",
    "span_id": "b37ac82563149fed",
    "parent_span_id": null,
    "name": "POST /checkout",
    "operation": "http.server",
    "status": "error",
    "started_at": "2026-06-01T12:00:00Z",
    "duration_ms": 823,
    "attributes": {},
    "environment": "production",
    "release": "api@1.2.3",
    "service_name": "checkout-api",
    "sdk_name": "@logbrew/node",
    "sdk_version": "0.1.8"
  },
  {
    "id": "0c2f7a51-4e8d-4b6a-9f13-2d7e5c8b1a90",
    "project_id": "123e4567-e89b-12d3-a456-426614174000",
    "trace_id": "6e0c63257de34c92bdb0c8f1e9278a50",
    "span_id": "7a085853722dc6d2",
    "parent_span_id": "b37ac82563149fed",
    "name": "POST /v1/charges",
    "operation": "http.client",
    "status": "error",
    "started_at": "2026-06-01T12:00:00.100Z",
    "duration_ms": 640,
    "attributes": {},
    "environment": "production",
    "release": "api@1.2.3",
    "service_name": "checkout-api",
    "sdk_name": "@logbrew/node",
    "sdk_version": "0.1.8"
  }
]
```

`status: "error"` describe la operación capturada, no la lectura de la API.
`parent_span_id: null` significa que el span no tiene ID de padre.
`status: null` significa que el span no informó de ningún estado.

### Resumen de la traza

El resumen de los mismos 2 spans:

```json theme={null}
{
  "trace_id": "6e0c63257de34c92bdb0c8f1e9278a50",
  "span_count": 2,
  "error_span_count": 2,
  "service_count": 1,
  "project_count": 1,
  "started_at": "2026-06-01T12:00:00Z",
  "duration_ms": 823,
  "root_span": {
    "span_id": "b37ac82563149fed",
    "parent_span_id": null,
    "name": "POST /checkout",
    "operation": "http.server",
    "status": "error",
    "started_at": "2026-06-01T12:00:00Z",
    "duration_ms": 823,
    "service_name": "checkout-api"
  },
  "slowest_child_span": {
    "span_id": "7a085853722dc6d2",
    "parent_span_id": "b37ac82563149fed",
    "name": "POST /v1/charges",
    "operation": "http.client",
    "status": "error",
    "started_at": "2026-06-01T12:00:00.100Z",
    "duration_ms": 640,
    "service_name": "checkout-api"
  },
  "slowest_path": [
    {
      "span_id": "b37ac82563149fed",
      "parent_span_id": null,
      "name": "POST /checkout",
      "operation": "http.server",
      "status": "error",
      "started_at": "2026-06-01T12:00:00Z",
      "duration_ms": 823,
      "service_name": "checkout-api"
    },
    {
      "span_id": "7a085853722dc6d2",
      "parent_span_id": "b37ac82563149fed",
      "name": "POST /v1/charges",
      "operation": "http.client",
      "status": "error",
      "started_at": "2026-06-01T12:00:00.100Z",
      "duration_ms": 640,
      "service_name": "checkout-api"
    }
  ],
  "error_spans": [
    {
      "span_id": "b37ac82563149fed",
      "parent_span_id": null,
      "name": "POST /checkout",
      "operation": "http.server",
      "status": "error",
      "started_at": "2026-06-01T12:00:00Z",
      "duration_ms": 823,
      "service_name": "checkout-api"
    },
    {
      "span_id": "7a085853722dc6d2",
      "parent_span_id": "b37ac82563149fed",
      "name": "POST /v1/charges",
      "operation": "http.client",
      "status": "error",
      "started_at": "2026-06-01T12:00:00.100Z",
      "duration_ms": 640,
      "service_name": "checkout-api"
    }
  ],
  "services": [
    {
      "service_name": "checkout-api",
      "span_count": 2,
      "error_span_count": 2,
      "max_duration_ms": 823
    }
  ],
  "releases": ["api@1.2.3"],
  "environments": ["production"]
}
```

| Campo | Significado |
| - | - |
| `duration_ms` | Tiempo desde el inicio del primer span hasta el final del último. No es la suma de las duraciones de los spans. |
| `root_span` | El primer span cuyo padre no está en la traza. Es un punto de partida, no una causa demostrada. |
| `slowest_child_span` | El span más largo que tiene un ID de padre, o `null`. |
| `slowest_path` | La cadena de padres conocida desde la raíz hasta `slowest_child_span`. Es `[]` cuando `slowest_child_span` es `null`. |
| `error_spans` | Los spans de error más largos, 5 como máximo. `error_span_count` puede ser mayor. |

Ninguna de las dos rutas devuelve un cursor ni un campo de truncado. No añadas
un valor `truncated` que la respuesta no contenga.

### Ningún span coincide

Cuando ningún span coincide con el ID de traza y el alcance, la lista de spans
devuelve `200` con `[]`. El resumen devuelve `404` con
`"error": "trace not found"` y `code: not_found`. Comprueba el ID de traza y
el alcance. No quites los filtros para que aparezca un resultado. Ninguno de
los dos resultados demuestra que la aplicación no haya enviado telemetría.

## <span id="live-event-response-format">Formato de respuesta de los eventos en vivo</span>

La actividad en vivo envía eventos nuevos. No vuelve a enviar los eventos que
el cliente se perdió mientras estaba desconectado. Usa las rutas de lista para
leer los registros existentes.

### Crea un ticket

Envía `POST /api/feed/ticket` con un token bearer de cuenta. La solicitud no tiene
cuerpo.

```bash theme={null}
curl --request POST "https://api.logbrew.co/api/feed/ticket" \
  --header "Authorization: Bearer $LOGBREW_ACCOUNT_BEARER"
```

Una respuesta `200 OK` contiene el ticket en el campo `ticket`:

```json theme={null}
{
  "ticket": "<feed-ticket>",
  "expires_in_seconds": 60,
  "next": "connect with GET /api/feed/live?ticket=<ticket> before the ticket expires",
  "next_action": {
    "code": "connect_live_feed",
    "target": "live_feed"
  }
}
```

El ticket es una credencial de corta duración. No lo escribas en logs ni lo
pongas en el prompt de un agente. Abre la conexión antes de que termine
`expires_in_seconds`. La caducidad limita cuándo puede empezar la conexión, no
cuánto tiempo sigue abierta.

Un `401` significa que el inicio de sesión de la cuenta no es válido. Inicia
sesión de nuevo antes de solicitar un ticket. Un método distinto de `POST`
devuelve `405` con `code: method_not_allowed`.

### Abre la conexión

Conecta un cliente WebSocket a
`wss://api.logbrew.co/api/feed/live?ticket=<feed-ticket>`. Codifica el ticket
para URL. No pongas un token bearer de cuenta ni un token bearer de ingesta en la URL. Un
`401` significa que el ticket o el inicio de sesión de la cuenta no es válido.
Crea un ticket nuevo después de volver a iniciar sesión.

| Respuesta | Causa | Siguiente paso |
| - | - | - |
| `422` con `"error": "feed ticket is required"` | Falta el valor de consulta `ticket` o está vacío. | Crea un ticket y conéctate con él. |
| `401` con `code: unauthorized` | El ticket ha caducado o no es válido. | Crea un ticket nuevo. No reintentes con el mismo ticket. |
| `code: invalid_websocket_upgrade` | La solicitud no es un upgrade de WebSocket válido. | Usa un cliente WebSocket. |
| `405` con `code: method_not_allowed` | La solicitud no usa `GET`. | Usa `GET` para la conexión. |

Espera antes de reconectarte tras un error. No te reconectes en un bucle
continuo.

### Lee los mensajes

Cada mensaje es un sobre `{ "type": "...", "data": ... }`. Lee `type` antes de
analizar `data`. Omite los tipos que el cliente no admita.

| Tipo de evento | Contenido de `data` |
| - | - |
| `native_log` | Datos del log, con la estructura de la [respuesta de logs](#log-response). |
| `native_issue` | Datos de la incidencia agrupada, con la estructura de la [respuesta de incidencias](#issue-response) de la versión 1. |
| `native_trace_span` | Un span, con la estructura de un elemento de la [lista de spans](#span-list). |
| `native_action` | Datos de la acción de producto, con la estructura de la [respuesta de acciones](#action-response). |
| `project_created`, `project_updated`, `project_catalog_changed` | Datos del proyecto. Vuelve a leer la lista de proyectos cuando cambie. |
| `usage_updated`, `usage_limit_warning`, `usage_limit_blocked` | Uso de la cuenta, con la estructura de [uso de la cuenta](/es/reference/account-api#account-usage). |

```json theme={null}
{
  "type": "native_log",
  "data": {
    "id": "150d1288-bec2-49ec-a036-3f7ac55f1b2d",
    "project_id": "123e4567-e89b-12d3-a456-426614174000",
    "level": "warning",
    "severity": "warning",
    "triage": {
      "effective_severity": "warning",
      "ignored": false,
      "rule_applied": false
    },
    "source": "runtime",
    "message": "checkout retry scheduled",
    "attributes": { "route": "/checkout" },
    "occurred_at": "2026-06-01T12:00:00Z",
    "environment": "production",
    "release": "api@1.2.3",
    "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
    "span_id": "00f067aa0ba902b7",
    "service_name": "checkout-api",
    "sdk_name": "@logbrew/node",
    "sdk_version": "0.1.8",
    "next_action": {
      "code": "inspect_trace",
      "target": "trace_summary"
    }
  }
}
```

Un evento `native_issue` usa la versión 1 de la respuesta de incidencias: una
incidencia archivada aparece como `ignored` y el evento no tiene prioridad. Las
métricas y los releases no son tipos de eventos en vivo. Léelos con sus rutas
de lista. El ticket no selecciona un proyecto. Comprueba el `project_id` de
cada evento antes de mostrarlo en la vista de un proyecto.
`logbrew watch --json` usa esta actividad. Consulta [Referencia de la CLI](/es/reference/cli).

### Gestiona una conexión cerrada

| Código de cierre | Motivo | Siguiente paso |
| - | - | - |
| `1013` | `live feed fell behind; reconnect to resync` | Espera y reconéctate con un ticket nuevo. Vuelve a leer las rutas de lista para obtener los registros que te perdiste. |
| `1008` | `live feed access changed; sign in again` | Deja de reconectarte. Inicia sesión de nuevo antes de crear un ticket nuevo. |

Otras desconexiones pueden no tener un motivo de LogBrew. Después de
reconectarte, vuelve a leer las rutas de lista y relaciona los registros por
ID.

## <span id="issue-status-response-examples">Ejemplos de respuestas de estado de incidencias</span>

`PATCH /api/telemetry/issues/{issue_id}` con `{ "status": "resolved" }`
devuelve `200 OK` con la incidencia agrupada actualizada, con la misma
estructura que la [respuesta de incidencias](#issue-response). La clave de
consulta `response_version` selecciona la versión. No devuelve un indicador de
éxito.

El cuerpo define 1 o más de estos campos: `status`, `priority` y `assignee`.
`status` acepta `unresolved`, `resolved` o `archived`. `ignored` es un nombre
antiguo de `archived`. Consulta
[Actualiza una incidencia](/es/reference/telemetry-api#update-one-issue).

Comprueba los valores devueltos de `id`, `status` y `priority` antes de
mostrar que el cambio se hizo. No construyas el resultado a partir de los
valores enviados. Un cambio de estado no elimina ocurrencias ni cambia
`first_seen_at` ni `last_seen_at`. Tampoco cambia `severity` ni una regla de
severidad.

Un cambio rechazado devuelve `422` con `code: validation_failed`:

```json theme={null}
{
  "error": "issue status must be unresolved, resolved, or archived",
  "code": "validation_failed",
  "next": "use status=unresolved, status=resolved, or status=archived",
  "next_action": {
    "code": "fix_request",
    "target": "request"
  }
}
```

| Resultado | Causa |
| - | - |
| `422`, `issue update requires status, priority, or assignee` | El cuerpo no tiene ninguno de los 3 campos. |
| `422`, `issue priority must be high, medium, or low` | El valor de prioridad no es compatible. |
| `422`, `issue assignee must be me, none, a user ID, or team:<team_id>` | El valor del responsable no es compatible. |
| `422`, `issue assignee cannot read this project` | El responsable no tiene acceso al proyecto. LogBrew no cambia nada. |
| `422`, `issue assignee team is not a team of this project's organization` | El equipo no pertenece a la organización del proyecto. LogBrew no cambia nada. |
| `403` con `code: forbidden` | La cuenta no puede gestionar incidencias en el proyecto. |
| `404` con `code: not_found` | La cuenta no puede leer la incidencia o la incidencia no existe. |

Un campo que ya tiene el valor solicitado no cambia. Tras un tiempo de espera
agotado o una respuesta perdida, vuelve a enviar la misma solicitud o lee
antes la incidencia. No envíes otro cambio antes de leer el estado actual.
Consulta [Escrituras](/es/reference/api-errors#writes).

`POST /api/telemetry/issues/bulk` devuelve `200 OK` con 1 resultado por cada
ID de incidencia solicitado, en el orden de la solicitud. Cada incidencia
encontrada usa la estructura de la versión 3. Un resultado `not_found` tiene
`issue: null`:

```json theme={null}
{
  "project_id": "123e4567-e89b-12d3-a456-426614174000",
  "results": [
    {
      "issue_id": "9b2b4b3a-bd4e-4f85-a0f6-48118f037c17",
      "outcome": "updated",
      "issue": {
        "id": "9b2b4b3a-bd4e-4f85-a0f6-48118f037c17",
        "status": "archived",
        "priority": "high",
        "priority_source": "derived",
        "assignee": null
      }
    },
    {
      "issue_id": "3f1c2d4e-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
      "outcome": "not_found",
      "issue": null
    }
  ]
}
```

Este ejemplo muestra solo algunos campos de la incidencia. `outcome` es
`updated`, `unchanged` o `not_found`. Una solicitud repetida devuelve
`unchanged` y no cambia nada. Consulta
[Actualiza incidencias en bloque](/es/reference/telemetry-api#update-issues-in-bulk).

Una solicitud en bloque falla por completo en estos casos:

| Resultado | Causa |
| - | - |
| `422`, `issue_ids must name 1 to 100 issues` | La lista está vacía o tiene más de 100 ID. |
| `422`, `issue_ids must not contain duplicates` | Un ID aparece más de una vez. |
| `422` con `code: invalid_json` | El cuerpo tiene un campo desconocido. |
| `403` con `code: forbidden` | La cuenta no puede gestionar incidencias en el proyecto. |
| `404`, `project not found` | La cuenta no puede leer el proyecto. |

## Alcance de las solicitudes de analíticas

Las rutas de analíticas, la ruta de series de métricas y la ruta de volumen de
señales leen un proyecto y un intervalo de tiempo. Cada solicitud necesita
`project_id` y `since`. `since` acepta una duración compacta como `24h` o `7d`,
o una marca de tiempo RFC3339. `until` acepta una marca de tiempo RFC3339 y,
de forma predeterminada, es la hora de la solicitud. El intervalo de tiempo
incluye `since`, excluye `until` y no puede superar 31 días.

`service_name`, `release` y `environment` son filtros exactos opcionales. Cada
valor debe tener de 1 a 256 caracteres después de que LogBrew quite los
espacios de los extremos. La ruta de comparación de segmentos pone estos
filtros dentro de cada segmento, no en el nivel superior.

Si la cuenta no puede leer el proyecto, estas rutas devuelven `200 OK` con
recuentos a cero. No devuelven `404`. Un resultado vacío no confirma el acceso
al proyecto. Compara `project_id` con los proyectos que la cuenta puede leer.
Una solicitud a través de un grant de MCP que no incluye el proyecto devuelve
`403` y `forbidden`.

| Ruta | Valores de `response_version` | Valor predeterminado |
| - | - | - |
| `GET /api/telemetry/analytics/overview` | `1`, `2` o `3` | `1` |
| `GET /api/telemetry/analytics/properties` | `1` o `2` | `1` |
| `POST /api/telemetry/analytics/segments/compare` | `1` o `2` | `1` |
| `POST /api/telemetry/analytics/retention` | `1` o `2` | `1` |
| `POST /api/telemetry/analytics/lifecycle` | `1` o `2` | `1` |
| `POST /api/telemetry/analytics/funnel` | No se acepta | Esquema `1` |
| `POST /api/telemetry/analytics/paths` | No se acepta | Esquema `1` |
| `GET /api/telemetry/metrics/series` | No se acepta | Esquema `1` |
| `GET /api/telemetry/summary/volume` | `1` | `1` |

Cada respuesta empieza con `schema_version`, `query` y `purpose`. `query`
repite el alcance efectivo. Omite los filtros que no enviaste. `purpose` es un
texto simple que explica qué responde la ruta.

Una tasa se omite cuando su denominador es cero. Una tasa omitida no es `0` ni
`null`. Lee `coverage` antes de fiarte de una tasa.

### <span id="shared-scope-errors">Errores de alcance compartidos</span>

Estos errores usan HTTP `422` y `validation_failed`:

| Causa | `error` |
| - | - |
| Falta `project_id` | `product analytics project_id is required` |
| Falta `since` | `product analytics since is required` |
| `since` no es una duración ni una marca de tiempo RFC3339 | `invalid since value` |
| `until` no es una marca de tiempo RFC3339 | `product analytics until must be an RFC3339 timestamp` |
| `since` no es anterior a `until` | `product analytics since must be earlier than until` |
| El intervalo de tiempo supera 31 días | `product analytics range must not exceed 31 days` |
| Un filtro vacío o de más de 256 caracteres | `product analytics context filters must be non-empty and at most 256 characters` |

Por ejemplo, una solicitud sin `project_id` devuelve:

```json theme={null}
{
  "error": "product analytics project_id is required",
  "code": "validation_failed",
  "next": "choose one owned project and send its project_id",
  "next_action": { "code": "fix_request", "target": "request" }
}
```

Las rutas de series de métricas y de volumen de señales usan las mismas reglas
de alcance, con su propio texto de `error`. Sus secciones, más abajo, enumeran
esos errores.

Una clave de consulta desconocida devuelve `422` con la respuesta de
[parámetros de consulta no válidos](/es/reference/api-errors#invalid-query-parameters).
Un campo JSON desconocido, la falta de un campo JSON obligatorio o un valor de
enum no admitido devuelve `invalid_json`. Consulta
[JSON no válido](/es/reference/api-errors#invalid-json). Una solicitud con un
método HTTP incorrecto devuelve `405` y `method_not_allowed`. Su texto `next`
indica el método y los campos admitidos. Consulta
[Método no admitido](/es/reference/api-errors#unsupported-method).

## Respuesta del resumen de analíticas de producto

`GET /api/telemetry/analytics/overview` muestra la actividad de un proyecto:
volumen de acciones, usuarios, sesiones, una serie temporal, las acciones
principales y las vistas de página, vistas de pantalla e interacciones
clasificadas. Úsala para encontrar los nombres exactos de los eventos que
necesitan las demás rutas de analíticas.

Envía `response_version=3`. Las versiones 1 y 2 devuelven los mismos
recuentos, pero su valor de `estimation.method` es un token antiguo. La
versión 1 no comprueba el tipo de sujeto cuando cuenta usuarios
identificados. Las versiones 2 y 3 cuentan solo los sujetos de tipo `user` y
añaden los recuentos de sujetos anónimos y `subject_coverage`.

Esta solicitud lee una hora en intervalos de cinco minutos y devuelve dos filas
en cada lista de principales:

```bash theme={null}
curl --get "https://api.logbrew.co/api/telemetry/analytics/overview" \
  --header "Authorization: Bearer $LOGBREW_ACCOUNT_BEARER" \
  --data-urlencode "project_id=<project_id>" \
  --data-urlencode "since=2026-06-01T11:00:00Z" \
  --data-urlencode "until=2026-06-01T12:00:00Z" \
  --data-urlencode "interval=5m" \
  --data-urlencode "top_limit=2" \
  --data-urlencode "response_version=3"
```

### Resumen correcto

En este resultado ficticio, el proyecto tiene 120 acciones en dos de los doce
intervalos. Veinte acciones vienen de sujetos anónimos. Todas las acciones
tienen un ID de sesión. La mitad de las acciones tiene un ID de traza.

```json theme={null}
{
  "schema_version": 3,
  "query": {
    "project_id": "11111111-1111-4111-8111-111111111111",
    "since": "2026-06-01T11:00:00Z",
    "until": "2026-06-01T12:00:00Z",
    "interval": "5m",
    "interval_seconds": 300,
    "top_limit": 2
  },
  "purpose": "Shows what people do in one project through action volume, active identified users, separately labeled anonymous subjects, explicit sessions, activity over time, top actions, and versioned page-view, screen-view, interaction, surface, and exact event-name breakdowns. Exact classified event names can be used as ordered funnel steps. It never infers people from anonymous events or relabels arbitrary unclassified telemetry as product behavior.",
  "analysis_level": "user_and_session",
  "summary": {
    "actions": 120,
    "active_identified_users": 18,
    "active_anonymous_subjects": 7,
    "sessions": 24,
    "distinct_action_names": 3,
    "actions_per_identified_user": 5.555555555555555,
    "actions_per_session": 5.0
  },
  "coverage": {
    "identified_actions": 100,
    "anonymous_actions": 20,
    "subject_coverage": {
      "index_version": 1,
      "identified_user_events": 100,
      "anonymous_subject_events": 20,
      "legacy_unknown_kind_events": 0,
      "missing_subject_events": 0,
      "historical_unindexed_events": 0
    },
    "sessionized_actions": 120,
    "traced_actions": 60,
    "identification_rate": 0.8333333333333334,
    "sessionization_rate": 1.0,
    "trace_link_rate": 0.5,
    "expected_buckets": 12,
    "returned_points": 2,
    "returned_top_actions": 2,
    "top_actions_truncated": true,
    "first_seen_at": "2026-06-01T11:00:10Z",
    "last_seen_at": "2026-06-01T11:09:50Z",
    "limitations": [
      "Typed anonymous subjects are counted separately and never contribute to active identified-user counts.",
      "Actions without a trace ID cannot link product behavior directly to trace investigation."
    ]
  },
  "estimation": {
    "unique_counts_are_approximate": true,
    "method": "approximate_distinct",
    "description": "Active identified-user, anonymous-subject, session, distinct action-name, distinct surface, and distinct exact event-name counts are approximate distinct counts. Event totals and capture-coverage counts are exact within the selected, fully evaluated query window."
  },
  "series": [
    {
      "bucket_start": "2026-06-01T11:00:00Z",
      "bucket_end": "2026-06-01T11:05:00Z",
      "actions": 50,
      "active_identified_users": 8,
      "sessions": 10,
      "identified_actions": 40,
      "sessionized_actions": 50,
      "traced_actions": 25
    },
    {
      "bucket_start": "2026-06-01T11:05:00Z",
      "bucket_end": "2026-06-01T11:10:00Z",
      "actions": 70,
      "active_identified_users": 12,
      "sessions": 14,
      "identified_actions": 60,
      "sessionized_actions": 70,
      "traced_actions": 35
    }
  ],
  "top_actions": [
    {
      "name": "checkout_started",
      "actions": 50,
      "active_identified_users": 12,
      "sessions": 14,
      "share_of_actions": 0.4166666666666667
    },
    {
      "name": "purchase_completed",
      "actions": 40,
      "active_identified_users": 9,
      "sessions": 10,
      "share_of_actions": 0.3333333333333333
    }
  ],
  "classified_activity": {
    "summary": {
      "events": 110,
      "page_views": 50,
      "screen_views": 20,
      "interactions": 40,
      "distinct_surfaces": 4,
      "distinct_event_names": 5,
      "active_identified_users": 17,
      "active_anonymous_subjects": 6,
      "sessions": 23
    },
    "coverage": {
      "classified_actions": 60,
      "unclassified_actions": 60,
      "action_classification_rate": 0.5,
      "surfaced_events": 110,
      "named_events": 110,
      "identified_events": 90,
      "subject_coverage": {
        "index_version": 1,
        "identified_user_events": 90,
        "anonymous_subject_events": 20,
        "legacy_unknown_kind_events": 0,
        "missing_subject_events": 0,
        "historical_unindexed_events": 0
      },
      "sessionized_events": 110,
      "traced_events": 55,
      "surface_rate": 1.0,
      "event_name_rate": 1.0,
      "identification_rate": 0.8181818181818182,
      "sessionization_rate": 1.0,
      "trace_link_rate": 0.5,
      "expected_buckets": 12,
      "returned_points": 2,
      "returned_top_surfaces": 2,
      "returned_top_events": 2,
      "top_surfaces_truncated": true,
      "top_events_truncated": true,
      "first_seen_at": "2026-06-01T11:00:20Z",
      "last_seen_at": "2026-06-01T11:09:40Z",
      "limitations": [
        "Only events carrying supported version-1 analytics annotations appear in classified activity; arbitrary actions and technical spans are not relabeled.",
        "Historical or unannotated actions contribute to the action summary but not to classified screen-view or interaction breakdowns.",
        "Classified events with typed anonymous subjects are counted separately and never contribute to identified-user counts.",
        "Classified events without a trace ID cannot link product behavior directly to trace investigation."
      ]
    },
    "series": [
      {
        "bucket_start": "2026-06-01T11:00:00Z",
        "bucket_end": "2026-06-01T11:05:00Z",
        "events": 45,
        "page_views": 20,
        "screen_views": 10,
        "interactions": 15
      },
      {
        "bucket_start": "2026-06-01T11:05:00Z",
        "bucket_end": "2026-06-01T11:10:00Z",
        "events": 65,
        "page_views": 30,
        "screen_views": 10,
        "interactions": 25
      }
    ],
    "top_surfaces": [
      {
        "kind": "page_view",
        "surface": "/checkout/:step",
        "events": 40,
        "active_identified_users": 12,
        "sessions": 14,
        "share_of_classified_events": 0.36363636363636365
      },
      {
        "kind": "screen_view",
        "surface": "Checkout",
        "events": 20,
        "active_identified_users": 9,
        "sessions": 10,
        "share_of_classified_events": 0.18181818181818182
      }
    ],
    "top_events": [
      {
        "kind": "page_view",
        "event_name": "/checkout/:step",
        "events": 40,
        "active_identified_users": 12,
        "sessions": 14,
        "share_of_classified_events": 0.36363636363636365
      },
      {
        "kind": "interaction",
        "event_name": "checkout_started",
        "events": 30,
        "active_identified_users": 10,
        "sessions": 12,
        "share_of_classified_events": 0.2727272727272727
      }
    ]
  },
  "next_action": {
    "code": "build_product_funnel",
    "target": "/api/telemetry/analytics/funnel",
    "reason": "Use two through eight exact keys from classified_activity.top_events to measure ordered conversion and drop-off for explicit sessions or opaque identified users."
  }
}
```

### Lee el resumen

Los cinco recuentos de `subject_coverage` suman el total de eventos de su
sección. Solo `identified_user_events` cuenta para los usuarios.
`anonymous_actions` es `summary.actions` menos `identified_actions`.

`series` contiene solo los intervalos con actividad. `expected_buckets` es el
número de intervalos posibles en el intervalo de tiempo. No dibujes un
intervalo ausente como un cero medido, salvo que tu gráfico indique esa regla.
Los intervalos se alinean con los límites de intervalo en UTC. Un intervalo de
tiempo que empieza dentro de un intervalo incluye ese intervalo parcial.

`classified_activity` cuenta las vistas de página, las vistas de pantalla y
las interacciones. Las vistas de pantalla y las interacciones también son
acciones. Las vistas de página no lo son. No sumes `summary.actions` a
`classified_activity.summary.events`.

Copia `kind` y `event_name` de `classified_activity.top_events` en los pasos
del embudo, los selectores de retención, los selectores de ciclo de vida, las
anclas de las rutas y los objetivos de los segmentos. Un valor `true` en
`top_events_truncated` significa que existen nombres con menos volumen. Sube
`top_limit` hasta 20 para ver más.

`analysis_level` es `no_data`, `event_only`, `user_level` o
`user_and_session`. Si el proyecto no tiene acciones ni eventos clasificados,
`next_action.code` es `capture_product_activity`. Consulta
[Analíticas de producto](/es/concepts/product-analytics#use-the-analytics-api).

### <span id="overview-errors">Errores del resumen</span>

Además de los [errores de alcance compartidos](#shared-scope-errors), el
resumen devuelve `422` y `validation_failed` con estos valores:

| Valor | `error` |
| - | - |
| `response_version` distinto de `1`, `2` o `3` | `product analytics response_version must be 1, 2, or 3` |
| `top_limit` fuera del rango de `1` a `20` | `product analytics top_limit must be between 1 and 20` |
| `interval` distinto de `auto`, `1m`, `5m`, `15m`, `1h`, `6h` o `1d` | `product analytics interval is not supported` |
| Un `interval` explícito que necesita más de 500 intervalos | `product analytics interval would exceed 500 buckets` |

El valor predeterminado de `interval` es `auto`. Selecciona el intervalo más
pequeño que necesite como máximo 300 intervalos. El valor predeterminado de
`top_limit` es `10`.

## <span id="ordered-funnel-response">Respuesta del embudo ordenado</span>

`POST /api/telemetry/analytics/funnel` mide cuántas unidades completan en orden
de 2 a 8 pasos. Copia cada `kind` y `event_name` exacto de
`classified_activity.top_events` en el resumen. Un nombre de acción parecido
no es una coincidencia. Este cuerpo de solicitud cuenta las sesiones que ven
`/pricing` y después completan el registro en menos de una hora:

```json theme={null}
{
  "project_id": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
  "since": "2026-08-01T00:00:00Z",
  "until": "2026-08-02T00:00:00Z",
  "environment": "production",
  "analysis_unit": "session",
  "conversion_window_seconds": 3600,
  "steps": [
    { "kind": "page_view", "event_name": "/pricing" },
    { "kind": "interaction", "event_name": "signup_completed" }
  ]
}
```

`analysis_unit` es `session` o `identified_user`. El valor predeterminado es
`session`. El `kind` de un paso es `page_view`, `screen_view` o
`interaction`. La ruta del embudo no acepta `response_version`.

### Embudo correcto

Una respuesta `200 OK`:

```json theme={null}
{
  "schema_version": 1,
  "query": {
    "project_id": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
    "since": "2026-08-01T00:00:00Z",
    "until": "2026-08-02T00:00:00Z",
    "environment": "production",
    "analysis_unit": "session",
    "conversion_window_seconds": 3600
  },
  "purpose": "Shows where explicit sessions or typed opaque user subjects enter, progress, and drop off across two through eight versioned page-view, screen-view, or interaction events. Steps must occur in order with strictly increasing timestamps inside the selected conversion window; raw session and subject identifiers are never returned.",
  "summary": {
    "candidate_units": 60,
    "entered_units": 50,
    "completed_units": 15,
    "entry_rate": 0.8333333333333334,
    "overall_conversion_rate": 0.3
  },
  "coverage": {
    "classified_events": 200,
    "named_events": 180,
    "unnamed_events": 20,
    "unit_identified_events": 160,
    "selected_step_events": 120,
    "usable_selected_step_events": 100,
    "excluded_selected_step_events": 20,
    "event_name_rate": 0.9,
    "selected_unit_coverage_rate": 0.8333333333333334,
    "limitations": [
      "Only supported version-1 classified events with exact derived names participate; arbitrary actions and technical spans are never relabeled.",
      "A unit reaches later steps only when timestamps strictly increase and the final match remains inside conversion_window_seconds from its first match.",
      "Historical or surface-less classified events without a derived event name cannot match exact funnel steps.",
      "Requested-step events without an explicit session ID are excluded from ordered unit counts.",
      "Session funnels count visits or app sessions, not unique people; use analysis_unit=identified_user only when typed user-subject coverage is sufficient."
    ]
  },
  "steps": [
    {
      "position": 1,
      "kind": "page_view",
      "event_name": "/pricing",
      "units": 50,
      "conversion_from_first": 1.0,
      "drop_off_to_next_units": 35,
      "drop_off_to_next_rate": 0.7
    },
    {
      "position": 2,
      "kind": "interaction",
      "event_name": "signup_completed",
      "units": 15,
      "conversion_from_previous": 0.3,
      "conversion_from_first": 0.3
    }
  ],
  "next_action": {
    "code": "compare_funnel_contexts",
    "target": "/api/telemetry/analytics/funnel",
    "reason": "Compare the same exact steps across bounded releases, environments, or services to locate material conversion changes."
  }
}
```

Las tasas son fracciones de 0 a 1. Lee `coverage` antes de fiarte de una tasa.
`selected_unit_coverage_rate` es la proporción de eventos de los pasos
seleccionados que LogBrew pudo usar. La respuesta no devuelve identidades sin
procesar. Consulta
[Analíticas de producto](/es/concepts/product-analytics#measure-a-funnel).

### Lee la conversión y la cobertura

`entry_rate` es `entered_units` dividido entre `candidate_units`: 50 de 60.
`overall_conversion_rate` es `completed_units` dividido entre
`entered_units`: 15 de 50, es decir, un 30 %. No es 15 dividido entre todos
los candidatos. Estos recuentos no explican por qué se detuvieron las
unidades.

La cobertura cuenta eventos, no sesiones. Aquí, 120 eventos coinciden con un
paso y 20 de ellos no tienen ID de sesión. El resultado excluye esos 20
eventos de los recuentos de sesiones. No los trates como 20 sesiones
fallidas.

El primer paso no tiene `conversion_from_previous`. El último paso no tiene
`drop_off_to_next_units` ni `drop_off_to_next_rate`.

Una unidad llega a un paso posterior solo cuando las horas de los pasos
aumentan estrictamente. Los eventos con la misma marca de tiempo no pueden
cumplir dos pasos consecutivos. El último paso debe ocurrir dentro de
`conversion_window_seconds` desde el primero.

El modo de sesión cuenta sesiones, no personas. Usa `identified_user` solo con
eventos que lleven un ID de sujeto opaco de tipo `user`. Ese modo puede unir
eventos de sesiones distintas dentro de la ventana de conversión. Mantén la
misma unidad y los mismos pasos cuando compares resultados.

El valor predeterminado de `conversion_window_seconds` es 24 horas o la
duración del intervalo de tiempo, lo que sea menor. El máximo es la duración
del intervalo de tiempo en segundos completos, redondeada hacia arriba.

### Resultados de embudo vacíos

Una respuesta vacía correcta sigue mostrando los pasos solicitados con
`units` a cero. Si no hay unidades candidatas, `summary` omite `entry_rate` y
`overall_conversion_rate`. La ruta no devuelve `404` porque ningún evento
coincida.

Lee `coverage` y `next_action` para encontrar la causa:

| `next_action.code` | Causa |
| - | - |
| `capture_product_activity` | No hay eventos clasificados en el alcance. |
| `choose_captured_funnel_steps` | Ningún evento coincide con un paso solicitado. |
| `sessionize_product_activity` | Hay eventos de los pasos, pero ninguno tiene ID de sesión. |
| `identify_product_users` | Hay eventos de los pasos, pero ninguno tiene un sujeto de tipo `user`. |
| `verify_funnel_entry` | Ninguna unidad entró en el paso 1. |
| `investigate_funnel_drop_off` | Entraron unidades, pero ninguna completó todos los pasos. |
| `compare_funnel_contexts` | Al menos una unidad completó el embudo. |

### Solicitudes de embudo rechazadas

Además de los [errores de alcance compartidos](#shared-scope-errors), estas
solicitudes devuelven `422` y `validation_failed`. Menos de 2 pasos o más de
8:

```json theme={null}
{
  "error": "product analytics funnel requires two through eight ordered steps",
  "code": "validation_failed",
  "next": "send a steps array containing 2 through 8 exact classified event selectors",
  "next_action": { "code": "fix_request", "target": "request" }
}
```

Un `conversion_window_seconds` de `0`, o un valor mayor que la duración del
intervalo de tiempo:

```json theme={null}
{
  "error": "product analytics funnel conversion window must fit inside the query range",
  "code": "validation_failed",
  "next": "use conversion_window_seconds from 1 through the selected range length",
  "next_action": { "code": "fix_request", "target": "request" }
}
```

Un `event_name` vacío, de más de 256 caracteres o con un carácter de control
devuelve
`product analytics funnel event_name must be non-empty, control-free, and at most 256 characters`.
Un paso `interaction` también debe ser un nombre de acción válido. Si no, el
error es `product analytics interaction event_name must be a bounded stable action name`.

Corrige la solicitud antes de volver a enviarla. No quites pasos ni cambies la
unidad de análisis solo para obtener un resultado que no esté vacío.

## Análisis por evento exacto y automático

La retención y el ciclo de vida aceptan dos estructuras de solicitud. Usa
`response_version` para seleccionar la estructura que responde a tu pregunta:

| Análisis | `response_version` | Selectores de evento |
| - | - | - |
| Retención de eventos exactos | `1`, u omitido | Envía `start_event` y `return_event`. |
| Ciclo de vida de un evento exacto | `1`, u omitido | Envía `event`. |
| Retención o ciclo de vida automáticos | `2` | No envíes ningún selector de evento. |

Un selector exacto contiene `kind` y `event_name`. `kind` es `page_view`,
`screen_view` o `interaction`. Copia `event_name` de
`classified_activity.top_events`. No adivines el nombre de un evento a partir
de la etiqueta de un botón.

Las dos estructuras cuentan solo usuarios: ID de sujeto opacos de tipo
`user`. Los sujetos anónimos y los eventos sin un ID de sujeto utilizable no
cuentan como usuarios. Las respuestas nunca devuelven ID de sujeto.

Los periodos fijos son `hour`, `day`, `week` y `thirty_day`. Son duraciones
fijas. `thirty_day` son 30 días, no un mes del calendario. Si omites
`interval`, la API usa `hour` para un intervalo de tiempo de 48 horas o menos,
y `day` para uno más largo.

### Solicitud de retención por evento exacto

Envía este cuerpo a `POST /api/telemetry/analytics/retention`. Pregunta si
los usuarios completan otro pago después de su primer pago en el intervalo de
tiempo:

```json theme={null}
{
  "project_id": "11111111-1111-4111-8111-111111111111",
  "since": "2026-06-01T00:00:00Z",
  "until": "2026-06-03T00:00:00Z",
  "response_version": 1,
  "interval": "day",
  "interval_count": 1,
  "mode": "return_on",
  "cohort_mode": "first_in_range",
  "start_event": { "kind": "interaction", "event_name": "checkout_completed" },
  "return_event": { "kind": "interaction", "event_name": "checkout_completed" }
}
```

El primer evento de inicio que coincide en el intervalo de tiempo es el ancla
de cada usuario. Un retorno debe ocurrir estrictamente después de esa ancla y antes
de `until`. Los dos selectores pueden ser el mismo evento.

| Campo | Valores | Valor predeterminado |
| - | - | - |
| `interval_count` | De `1` a `31` periodos | `10` |
| `mode` | `return_on` cuenta un retorno dentro de cada periodo exacto. `return_on_or_after` cuenta un retorno en el inicio de cada periodo o después. | `return_on` |
| `cohort_mode` | `first_in_range` | `first_in_range` |

### Retención por evento exacto correcta

En este ejemplo ficticio, dos usuarios completan el pago. El primer usuario
completa el pago a las 12:00 del 1 de junio y otra vez a las 13:00. El segundo
usuario completa el pago a las 12:00 del 2 de junio. A las 13:00 del 2 de
junio, el segundo usuario ve una página, pero no completa otro pago.

```json theme={null}
{
  "schema_version": 1,
  "query": {
    "project_id": "11111111-1111-4111-8111-111111111111",
    "since": "2026-06-01T00:00:00Z",
    "until": "2026-06-03T00:00:00Z",
    "start_event": { "kind": "interaction", "event_name": "checkout_completed" },
    "return_event": { "kind": "interaction", "event_name": "checkout_completed" },
    "interval": "day",
    "interval_seconds": 86400,
    "interval_count": 1,
    "mode": "return_on",
    "cohort_mode": "first_in_range"
  },
  "purpose": "Measures whether typed opaque user subjects return after their first matching start event inside the selected half-open query range. Returns must occur strictly after each subject's anchor. return_on measures one fixed subject-relative period; return_on_or_after measures from that period's threshold through the exclusive query upper bound. Eligibility-aware denominators prevent immature subjects from being reported as churned, cohorts are fixed buckets aligned to since, and raw subject identifiers are never returned.",
  "summary": {
    "cohort_subjects": 2,
    "subjects_returned_after_start": 1,
    "return_rate_after_start": 0.5,
    "non_empty_cohorts": 2,
    "periods_with_eligible_subjects": 1,
    "fully_observed_periods": 0
  },
  "coverage": {
    "classified_events": 4,
    "named_events": 4,
    "unnamed_events": 0,
    "identified_events": 4,
    "start_events": 3,
    "usable_start_events": 3,
    "excluded_start_events": 0,
    "return_events": 3,
    "usable_return_events": 3,
    "excluded_return_events": 0,
    "event_name_rate": 1.0,
    "start_identity_coverage_rate": 1.0,
    "return_identity_coverage_rate": 1.0,
    "limitations": [
      "Only application-supplied opaque subject IDs explicitly typed as users are counted. Anonymous, legacy-untyped, historical-unindexed, invalid, or absent subjects are excluded rather than inferred as people.",
      "first_in_range anchors each subject at its first matching start inside the selected range; it does not prove that event was the subject's first-ever historical start.",
      "Cohort buckets are fixed-width and aligned to the query's since value. hour, day, week, and thirty_day mean fixed elapsed durations; thirty_day is not a calendar month.",
      "Returns must match the exact selected kind and derived event name, occur strictly after the subject anchor, and remain before the exclusive query upper bound.",
      "This resource does not provide recurring-start cohorts, group retention, arbitrary property breakdowns, custom return ranges, or lifetime first-event lookup.",
      "return_on includes only subjects whose complete exact period ends by until; later subjects are excluded from that period's denominator."
    ]
  },
  "curve": [
    {
      "period": 0,
      "threshold_seconds": 0,
      "window_end_seconds": 86400,
      "eligible_subjects": 1,
      "retained_subjects": 1,
      "weighted_retention_rate": 1.0,
      "fully_observed_cohorts": 1,
      "fully_observed_cohort_average_rate": 1.0,
      "all_subjects_eligible": false
    }
  ],
  "cohorts": [
    {
      "cohort": 0,
      "started_at": "2026-06-01T00:00:00Z",
      "ended_at": "2026-06-02T00:00:00Z",
      "subjects": 1,
      "subjects_returned_after_start": 1,
      "periods": [
        {
          "period": 0,
          "eligible_subjects": 1,
          "retained_subjects": 1,
          "retention_rate": 1.0,
          "all_subjects_eligible": true
        }
      ]
    },
    {
      "cohort": 1,
      "started_at": "2026-06-02T00:00:00Z",
      "ended_at": "2026-06-03T00:00:00Z",
      "subjects": 1,
      "subjects_returned_after_start": 0,
      "periods": [
        {
          "period": 0,
          "eligible_subjects": 0,
          "retained_subjects": 0,
          "all_subjects_eligible": false
        }
      ]
    }
  ],
  "next_action": {
    "code": "extend_retention_observation_window",
    "target": "/api/telemetry/analytics/retention",
    "reason": "Move since earlier, until later, or request fewer periods when a fully observed long-term comparison is required."
  }
}
```

### Lee la retención

La cobertura cuenta los cuatro eventos clasificados, pero solo tres coinciden
con cada selector de pago. La vista de página no cuenta como retorno. Uno de
los dos usuarios repite el pago, así que `return_rate_after_start` es `0.5`.

Solo el primer usuario tiene un día completo de observación después del
ancla. Ese usuario vuelve dentro del día, así que la tasa de la curva es
`1.0`. El segundo usuario solo tiene 12 horas de observación. Ese usuario no
es apto para el periodo 0, así que la celda de la segunda cohorte omite
`retention_rate`. No cuentes a ese usuario como perdido.

`weighted_retention_rate` divide todos los usuarios retenidos entre todos los
usuarios aptos. `fully_observed_cohort_average_rate` es la media simple de las
tasas de las cohortes en las que todos los usuarios son aptos. Las cohortes
son intervalos fijos que empiezan en `since`. `cohorts` contiene solo las
cohortes que tienen usuarios.

Con `mode: "return_on_or_after"`, la curva omite `window_end_seconds`.

### Retención automática

Envía `response_version: 2` sin `start_event` ni `return_event`. Cada vista de
página, vista de pantalla e interacción admitida cuenta como inicio y como
retorno. Esta versión selecciona un conjunto de eventos. No selecciona un
formato de captura del SDK.

```json theme={null}
{
  "project_id": "11111111-1111-4111-8111-111111111111",
  "since": "2026-06-01T00:00:00Z",
  "until": "2026-06-03T00:00:00Z",
  "response_version": 2,
  "interval": "day",
  "interval_count": 1,
  "mode": "return_on",
  "cohort_mode": "first_in_range"
}
```

La respuesta tiene las mismas estructuras de `summary`, `curve`, `cohorts` y
`next_action` que la respuesta por evento exacto. Este extracto muestra los
campos que cambian. En este ejemplo, los mismos dos usuarios tienen tres
eventos y ninguna vista de página:

```json theme={null}
{
  "schema_version": 2,
  "query": {
    "project_id": "11111111-1111-4111-8111-111111111111",
    "since": "2026-06-01T00:00:00Z",
    "until": "2026-06-03T00:00:00Z",
    "activity_scope": "all_classified_activity",
    "interval": "day",
    "interval_seconds": 86400,
    "interval_count": 1,
    "mode": "return_on",
    "cohort_mode": "first_in_range"
  },
  "purpose": "Measures whether typed opaque user subjects perform any later supported classified product activity after their first such activity inside the selected half-open range. It does not choose or infer a top event. Returns must occur strictly after the anchor, anonymous and unidentified subjects remain excluded from user counts, eligibility-aware denominators prevent immature subjects from being reported as churned, and raw identifiers are never returned.",
  "coverage": {
    "classified_events": 3,
    "named_events": 3,
    "unnamed_events": 0,
    "identified_events": 3,
    "start_events": 3,
    "usable_start_events": 3,
    "excluded_start_events": 0,
    "return_events": 3,
    "usable_return_events": 3,
    "excluded_return_events": 0,
    "event_name_rate": 1.0,
    "start_identity_coverage_rate": 1.0,
    "return_identity_coverage_rate": 1.0,
    "limitations": [
      "Only application-supplied opaque subject IDs explicitly typed as users are counted. Anonymous, legacy-untyped, historical-unindexed, invalid, or absent subjects are excluded rather than inferred as people.",
      "first_in_range anchors each subject at its first supported classified activity in the range; it does not prove that activity was the subject's first-ever product activity.",
      "Cohort buckets are fixed-width and aligned to the query's since value. hour, day, week, and thirty_day mean fixed elapsed durations; thirty_day is not a calendar month.",
      "Returns are any supported classified activity strictly after the subject anchor and before the exclusive query upper bound; no event is ranked, selected, or inferred.",
      "This resource does not provide recurring-start cohorts, group retention, arbitrary property breakdowns, custom return ranges, or lifetime first-event lookup.",
      "return_on includes only subjects whose complete exact period ends by until; later subjects are excluded from that period's denominator."
    ]
  }
}
```

En el modo automático, `start_events` y `return_events` son iguales a
`classified_events`. Estos recuentos son eventos, no usuarios.

### Retención sin usuarios aptos

Un resultado correcto puede no tener usuarios en ninguna cohorte. Este
extracto muestra un periodo solicitado sin cohortes:

```json theme={null}
{
  "schema_version": 2,
  "summary": {
    "cohort_subjects": 0,
    "subjects_returned_after_start": 0,
    "non_empty_cohorts": 0,
    "periods_with_eligible_subjects": 0,
    "fully_observed_periods": 0
  },
  "curve": [
    {
      "period": 0,
      "threshold_seconds": 0,
      "window_end_seconds": 86400,
      "eligible_subjects": 0,
      "retained_subjects": 0,
      "fully_observed_cohorts": 0,
      "all_subjects_eligible": false
    }
  ],
  "cohorts": []
}
```

Lee `coverage` y `next_action`. Distinguen un alcance sin eventos
clasificados (`capture_product_activity`) de eventos sin usuarios
(`identify_product_users` o `identify_returning_users`). Una tasa ausente no
es un cero medido.

### Errores de retención

Además de los [errores de alcance compartidos](#shared-scope-errors), estas
solicitudes devuelven `422` y `validation_failed`:

| Causa | `error` |
| - | - |
| Versión 1 sin los dos selectores, versión 2 con un selector u otra versión | `product analytics retention activity selection is contradictory` |
| `interval_count` fuera del rango de `1` a `31` | `product analytics retention interval_count must be between 1 and 31` |
| Los intervalos de cohorte multiplicados por `interval_count` superan 500 | `product analytics retention interval and interval_count would exceed 500 cohort matrix cells` |

El límite de celdas depende del intervalo de tiempo y de los periodos, no del
número de usuarios. Un intervalo de tiempo de 30 días con `interval: "hour"`
tiene 720 intervalos de cohorte. Con `interval_count: 1`, son 720 celdas, más
de 500:

```json theme={null}
{
  "error": "product analytics retention interval and interval_count would exceed 500 cohort matrix cells",
  "code": "validation_failed",
  "next": "choose a wider interval, a shorter time range, or fewer retention periods",
  "next_action": { "code": "fix_request", "target": "request" }
}
```

Para usar la retención automática, quita los dos selectores. No cambies el SDK
para corregir esta solicitud de lectura.

### Solicitud de ciclo de vida por evento exacto

Envía este cuerpo a `POST /api/telemetry/analytics/lifecycle`. Clasifica a
los usuarios por un evento, no por toda la actividad del proyecto:

```json theme={null}
{
  "project_id": "11111111-1111-4111-8111-111111111111",
  "since": "2026-06-01T00:00:00Z",
  "until": "2026-06-03T00:00:00Z",
  "response_version": 1,
  "interval": "day",
  "history_period_count": 2,
  "event": { "kind": "interaction", "event_name": "checkout_completed" }
}
```

`history_period_count` define los periodos completos anteriores a `since` que
LogBrew lee como historial. Acepta de `2` a `31`. El valor predeterminado es
`2`. Un usuario puede estar inactivo para este evento mientras realiza otras
actividades.

### Ciclo de vida por evento exacto correcto

Este ejemplo ficticio usa dos días de historial y dos días de análisis. Las
letras solo identifican a usuarios de ejemplo. La respuesta no devuelve ID de
usuario.

| Fecha, UTC | Usuarios que completan el pago |
| - | - |
| 30 de mayo, historial | B |
| 31 de mayo, historial | A y D |
| 1 de junio, análisis | A, B y C |
| 2 de junio, análisis | A y B |

C también ve una página el 2 de junio. Ese evento no coincide con el selector
de pago.

```json theme={null}
{
  "schema_version": 1,
  "query": {
    "project_id": "11111111-1111-4111-8111-111111111111",
    "since": "2026-06-01T00:00:00Z",
    "until": "2026-06-03T00:00:00Z",
    "history_since": "2026-05-30T00:00:00Z",
    "event": { "kind": "interaction", "event_name": "checkout_completed" },
    "interval": "day",
    "interval_seconds": 86400,
    "history_period_count": 2,
    "expected_buckets": 2
  },
  "purpose": "Classifies typed opaque user subjects for one exact product event in each fixed analysis period. new_within_observed_history means active now with no earlier matching event inside the bounded history window; returning means active now and in the immediately previous period; resurrected means active now, inactive in the previous period, and active earlier in observed history; dormant means active in the previous period but not now. These states are disjoint, incomplete buckets are marked, and raw subject identifiers are never returned.",
  "summary": {
    "observed_subjects": 4,
    "analysis_active_subjects": 3,
    "history_only_subjects": 1,
    "returned_buckets": 2,
    "fully_observed_buckets": 2,
    "latest_fully_observed_period": 1,
    "buckets_with_resurrection": 1,
    "buckets_with_dormancy": 2
  },
  "coverage": {
    "analysis_classified_events": 6,
    "analysis_named_events": 6,
    "analysis_unnamed_events": 0,
    "analysis_identified_events": 6,
    "selected_events": 5,
    "usable_selected_events": 5,
    "usable_selected_sessionized_events": 5,
    "usable_selected_trace_linked_events": 5,
    "excluded_selected_events": 0,
    "history_selected_events": 3,
    "usable_history_selected_events": 3,
    "excluded_history_selected_events": 0,
    "event_name_rate": 1.0,
    "selected_identity_coverage_rate": 1.0,
    "selected_sessionization_rate": 1.0,
    "selected_trace_link_rate": 1.0,
    "history_identity_coverage_rate": 1.0,
    "limitations": [
      "Only application-supplied opaque subject IDs explicitly typed as users are counted. Anonymous, legacy-untyped, historical-unindexed, invalid, or absent subjects are excluded rather than inferred as people.",
      "new_within_observed_history means no earlier selected event between history_since and the current bucket. It does not prove that a subject is a lifetime-new user.",
      "Observed history contains exactly 2 complete fixed periods before since; activity before history_since is intentionally unknown.",
      "Buckets are fixed-width and aligned to since. hour, day, week, and thirty_day mean fixed elapsed durations; thirty_day is not a calendar month.",
      "Returning, resurrected, and dormant compare only the selected exact kind and derived event name. They do not infer intent, identity merges, or causality.",
      "This resource does not provide arbitrary property breakdowns, reusable cohorts, group lifecycle, lifetime first-event lookup, or per-subject lists."
    ]
  },
  "buckets": [
    {
      "period": 0,
      "started_at": "2026-06-01T00:00:00Z",
      "ended_at": "2026-06-02T00:00:00Z",
      "fully_observed": true,
      "active_subjects": 3,
      "new_within_observed_history_subjects": 1,
      "returning_subjects": 1,
      "resurrected_subjects": 1,
      "dormant_subjects": 1,
      "previous_active_subjects": 2,
      "new_share_of_active": 0.3333333333333333,
      "returning_share_of_active": 0.3333333333333333,
      "resurrected_share_of_active": 0.3333333333333333,
      "dormant_share_of_previous_active": 0.5,
      "net_active_change": 1
    },
    {
      "period": 1,
      "started_at": "2026-06-02T00:00:00Z",
      "ended_at": "2026-06-03T00:00:00Z",
      "fully_observed": true,
      "active_subjects": 2,
      "new_within_observed_history_subjects": 0,
      "returning_subjects": 2,
      "resurrected_subjects": 0,
      "dormant_subjects": 1,
      "previous_active_subjects": 3,
      "new_share_of_active": 0.0,
      "returning_share_of_active": 1.0,
      "resurrected_share_of_active": 0.0,
      "dormant_share_of_previous_active": 0.3333333333333333,
      "net_active_change": -1
    }
  ],
  "next_action": {
    "code": "investigate_lifecycle_loss",
    "target": "/api/telemetry/analytics/paths",
    "reason": "The latest complete bucket lost more prior active subjects than it added through new-within-observed-history and resurrected activity; compare bounded journeys around the selected event."
  }
}
```

### Lee el ciclo de vida

El 1 de junio, A es recurrente, B está reactivado, C es nuevo y D está
inactivo. El 2 de junio, A y B son recurrentes, y C está inactivo para el pago
a pesar de la vista de página. El cambio neto del 2 de junio es
`2 - 3 = -1`.

En cada intervalo, los usuarios nuevos, recurrentes y reactivados suman
`active_subjects`. `returning_subjects` más `dormant_subjects` es igual a
`previous_active_subjects`. `net_active_change` es `active_subjects` menos
`previous_active_subjects`.

No sumes los recuentos activos diarios para obtener usuarios distintos. Aquí,
los recuentos diarios suman 5, pero `analysis_active_subjects` es 3. Entre el
historial y el análisis aparecen cuatro usuarios distintos.

`fully_observed` es `false` en un último intervalo que termina después de
`until`. Sus recuentos pueden cambiar cuando se pueda observar el periodo
completo. `next_action` sugiere una investigación. No muestra una causa.

### Ciclo de vida automático

Envía `response_version: 2` sin el selector `event`. Cada vista de página,
vista de pantalla e interacción admitida cuenta como actividad:

```json theme={null}
{
  "project_id": "11111111-1111-4111-8111-111111111111",
  "since": "2026-06-01T00:00:00Z",
  "until": "2026-06-03T00:00:00Z",
  "response_version": 2,
  "interval": "day",
  "history_period_count": 2
}
```

La respuesta tiene las mismas estructuras de `summary`, `buckets` y
`next_action` que la respuesta por evento exacto. Este extracto muestra los
campos que cambian:

```json theme={null}
{
  "schema_version": 2,
  "query": {
    "project_id": "11111111-1111-4111-8111-111111111111",
    "since": "2026-06-01T00:00:00Z",
    "until": "2026-06-03T00:00:00Z",
    "history_since": "2026-05-30T00:00:00Z",
    "activity_scope": "all_classified_activity",
    "interval": "day",
    "interval_seconds": 86400,
    "history_period_count": 2,
    "expected_buckets": 2
  },
  "purpose": "Classifies typed opaque user subjects by any supported classified product activity in each fixed period. It does not choose or infer a top event. new_within_observed_history, returning, resurrected, and dormant remain disjoint; anonymous and unidentified subjects are excluded from user counts, incomplete buckets are marked, and raw identifiers are never returned."
}
```

En el modo automático, `coverage.selected_events` es igual a
`coverage.analysis_classified_events`. La quinta entrada de `limitations` es
`Returning, resurrected, and dormant compare any supported classified product activity; no event is ranked, selected, or inferred.`

### Ciclo de vida sin usuarios

Si ni el intervalo de tiempo del análisis ni el historial contienen usuarios
utilizables, `buckets` está vacío y `summary` omite
`latest_fully_observed_period`:

```json theme={null}
{
  "schema_version": 2,
  "summary": {
    "observed_subjects": 0,
    "analysis_active_subjects": 0,
    "history_only_subjects": 0,
    "returned_buckets": 0,
    "fully_observed_buckets": 0,
    "buckets_with_resurrection": 0,
    "buckets_with_dormancy": 0
  },
  "buckets": []
}
```

Los usuarios que aparecen solo en el historial pueden producir intervalos con
usuarios inactivos cuando el intervalo de tiempo del análisis no tiene
actividad.

### Errores del ciclo de vida

Además de los [errores de alcance compartidos](#shared-scope-errors), estas
solicitudes devuelven `422` y `validation_failed`:

| Causa | `error` |
| - | - |
| Versión 1 sin `event`, versión 2 con `event` u otra versión | `product analytics lifecycle activity selection is contradictory` |
| `history_period_count` fuera del rango de `2` a `31` | `product analytics lifecycle history_period_count must be between 2 and 31` |
| Periodos de historial de más de 62 días en total | `product analytics lifecycle history must not exceed 62 days` |
| Más de 100 intervalos de análisis | `product analytics lifecycle interval would exceed 100 analysis buckets` |

Por ejemplo, diez periodos de historial `week` necesitan 70 días:

```json theme={null}
{
  "error": "product analytics lifecycle history must not exceed 62 days",
  "code": "validation_failed",
  "next": "use fewer history periods or a narrower fixed interval",
  "next_action": { "code": "fix_request", "target": "request" }
}
```

### Lee el alcance de análisis seleccionado

Las respuestas por evento exacto tienen `schema_version: 1`. Su `query` repite
los selectores y omite `activity_scope`. Las respuestas automáticas tienen
`schema_version: 2` y `query.activity_scope: "all_classified_activity"`.
Omiten los selectores. Un selector distinto puede cambiar el resultado sin que
cambie la actividad capturada.

## Respuesta de series de métricas

`GET /api/telemetry/metrics/series` lee un nombre de métrica exacto en un
proyecto. Copia el nombre de `GET /api/telemetry/metrics`. Esta solicitud
agrupa un contador delta por servicio:

```bash theme={null}
curl --get "https://api.logbrew.co/api/telemetry/metrics/series" \
  --header "Authorization: Bearer $LOGBREW_ACCOUNT_BEARER" \
  --data-urlencode "project_id=<project_id>" \
  --data-urlencode "name=jobs.completed" \
  --data-urlencode "since=2026-06-01T12:00:00Z" \
  --data-urlencode "until=2026-06-01T12:15:00Z" \
  --data-urlencode "interval=5m" \
  --data-urlencode "group_by=service_name"
```

### Serie de métricas correcta

Esta respuesta ficticia contiene una serie de contador delta. En el primer
intervalo hay tres muestras con los valores `2`, `3` y `5`. En el último
intervalo hay dos muestras con los valores `1` y `4`. En el intervalo central
no hay ninguna muestra, así que la respuesta no tiene un punto para él.

```json theme={null}
{
  "schema_version": 1,
  "query": {
    "project_id": "11111111-1111-4111-8111-111111111111",
    "name": "jobs.completed",
    "since": "2026-06-01T12:00:00Z",
    "until": "2026-06-01T12:15:00Z",
    "interval": "5m",
    "interval_seconds": 300,
    "group_by": "service_name",
    "series_limit": 10
  },
  "purpose": "Shows how one metric changes over time without changing its meaning: gauges use sampled state, delta counters use change volume and rate, histograms use distributions, and cumulative streams stay raw when reset-safe change is ambiguous.",
  "coverage": {
    "samples": 5,
    "series": 1,
    "returned_series": 1,
    "points": 2,
    "expected_buckets_per_series": 3,
    "first_seen_at": "2026-06-01T12:00:10Z",
    "last_seen_at": "2026-06-01T12:14:50Z",
    "truncated": false
  },
  "series": [
    {
      "identity": {
        "kind": "counter",
        "unit": "{job}",
        "temporality": "delta",
        "group_by": "service_name",
        "group_value": "checkout-worker"
      },
      "status": "ready",
      "aggregation": {
        "code": "delta_sum",
        "description": "Primary value is the sum of recorded changes in each bucket; rate_per_second normalizes that change by bucket width."
      },
      "sample_count": 5,
      "points": [
        {
          "bucket_start": "2026-06-01T12:00:00Z",
          "bucket_end": "2026-06-01T12:05:00Z",
          "sample_count": 3,
          "value": 10.0,
          "last": 5.0,
          "min": 2.0,
          "max": 5.0,
          "average": 3.3333333333333335,
          "sum": 10.0,
          "rate_per_second": 0.03333333333333333,
          "trace_exemplars": ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"]
        },
        {
          "bucket_start": "2026-06-01T12:10:00Z",
          "bucket_end": "2026-06-01T12:15:00Z",
          "sample_count": 2,
          "value": 5.0,
          "last": 4.0,
          "min": 1.0,
          "max": 4.0,
          "average": 2.5,
          "sum": 5.0,
          "rate_per_second": 0.016666666666666666,
          "trace_exemplars": []
        }
      ]
    }
  ],
  "next_action": {
    "code": "inspect_metric_change",
    "target": "trace_summary",
    "reason": "Open a trace exemplar from an unusual bucket to connect the metric change to spans, errors, logs, and release context."
  }
}
```

### Lee una serie de métricas

El primer punto registra 10 tareas completadas, no 10 muestras.
`rate_per_second` divide ese cambio entre los 300 segundos del intervalo.
`last` es el último cambio registrado, no la suma. Consulta
[qué significa cada agregación de métricas](/es/concepts/telemetry#read-the-metric-value).

El tipo y la temporalidad de una serie determinan su `aggregation.code` y las
estadísticas de cada punto. Un punto omite las estadísticas que no se
aplican. Una estadística ausente no es cero.

| Tipo y temporalidad | `status` | `aggregation.code` | `value` | Otras estadísticas |
| - | - | - | - | - |
| `gauge`, `instant` | `ready` | `gauge_last` | Última muestra | `last`, `min`, `max`, `average` |
| `counter`, `delta` | `ready` | `delta_sum` | Suma de los cambios | `last`, `min`, `max`, `average`, `sum`, `rate_per_second` |
| `histogram`, `delta` | `ready` | `distribution_p95` | p95 aproximado | `min`, `max`, `average`, `sum`, `p50`, `p95`, `p99` |
| Cualquier tipo, `cumulative` | `limited` | `raw_cumulative_last` | Última muestra sin procesar | `last`, `min`, `max` |
| Cualquier otra combinación | `limited` | `raw_last` | Última muestra sin procesar | `last`, `min`, `max` |

`limited` es una respuesta correcta, no un error. Añade
`aggregation.limitation`, que explica por qué LogBrew muestra solo valores sin
procesar. `ready` no demuestra que la captura esté completa.

Lee `coverage` antes de dibujar un gráfico:

* `samples` cuenta las muestras de todas las series que coinciden, incluidas
  las series que la respuesta no devuelve.
* `series` cuenta las series que coinciden. `returned_series` y `points`
  cuentan los datos devueltos.
* `truncated` es `true` cuando `series_limit` quitó series con menos volumen.
* `expected_buckets_per_series` es el número de intervalos posibles en el
  intervalo de tiempo.

No añadas un punto para un intervalo sin muestras. No insertes un cero ni
copies el valor anterior. Cada punto devuelve hasta 3 `trace_exemplars`. Un
ejemplar de traza enlaza una muestra con una traza. No explica todas las
muestras del intervalo. Si ningún punto tiene un ejemplar de traza,
`next_action.target` es `metric_samples`.

### Alcance y errores de las series de métricas

`project_id`, `name` y `since` son obligatorios. `name` puede tener como
máximo 200 caracteres. `interval` es `auto`, `1m`, `5m`, `15m`, `1h`, `6h` o
`1d`. El valor predeterminado es `auto`, que selecciona el intervalo más
pequeño con 300 intervalos como máximo. Un intervalo explícito no puede
necesitar más de 500 intervalos.

`group_by` es `none`, `service_name`, `release` o `environment`. El valor
predeterminado es `none`. Sin agrupación, los distintos tipos, unidades y
temporalidades siguen en series separadas. `series_limit` acepta de `1` a
`20`. El valor predeterminado es `10`.

Un resultado vacío devuelve `200` con `series: []` y `samples` a cero. El
objeto `coverage` omite `first_seen_at` y `last_seen_at`. Esto no demuestra
que la aplicación nunca haya enviado la métrica. Comprueba el proyecto, el
nombre de la métrica y el intervalo de tiempo.

Si omites `name`, la respuesta es `422`:

```json theme={null}
{
  "error": "metric series name is required",
  "code": "validation_failed",
  "next": "send the exact metric name returned by /api/telemetry/metrics",
  "next_action": { "code": "fix_request", "target": "request" }
}
```

Intervalos de un minuto a lo largo de siete días devuelven `422`:

```json theme={null}
{
  "error": "metric series interval would exceed 500 buckets",
  "code": "validation_failed",
  "next": "use interval=auto or select a wider interval",
  "next_action": { "code": "fix_request", "target": "request" }
}
```

Otros errores `422` son `metric series group_by is not supported`,
`metric series interval is not supported` y
`metric series_limit must be between 1 and 20`.

## Respuesta del análisis de rutas

`POST /api/telemetry/analytics/paths` busca los eventos con nombre anteriores
o posteriores a un evento seleccionado en la misma sesión. El evento
seleccionado es el ancla. Copia su `kind` y su `event_name` de
`classified_activity.top_events`. La ruta devuelve `schema_version: 1`. No
acepta `response_version` ni `analysis_unit`.

```json theme={null}
{
  "project_id": "11111111-1111-4111-8111-111111111111",
  "since": "2026-06-01T11:00:00Z",
  "until": "2026-06-01T12:00:00Z",
  "direction": "following",
  "anchor": { "kind": "page_view", "event_name": "/checkout" },
  "depth": 2,
  "collapse_repeated": true,
  "path_limit": 2
}
```

`direction` y `anchor` son obligatorios.

### Rutas correctas

En este resultado ficticio, cuatro sesiones contienen el ancla. Las dos rutas
devueltas representan tres de esas sesiones. Una ruta peor clasificada no se
devuelve.

```json theme={null}
{
  "schema_version": 1,
  "query": {
    "project_id": "11111111-1111-4111-8111-111111111111",
    "since": "2026-06-01T11:00:00Z",
    "until": "2026-06-01T12:00:00Z",
    "direction": "following",
    "anchor": { "kind": "page_view", "event_name": "/checkout" },
    "depth": 2,
    "collapse_repeated": true,
    "path_limit": 2
  },
  "purpose": "Shows the highest-volume named product-event sequences immediately before or after one exact version-1 page view, screen view, or interaction inside explicit sessions. Following paths use the earliest matching anchor in each session; preceding paths use the latest. Optional exact property predicates classify only the anchor, while surrounding events preserve the real session journey. Results aggregate exact bounded sequences and never return raw session or subject identifiers.",
  "summary": {
    "anchored_sessions": 4,
    "represented_sessions": 3,
    "unrepresented_sessions": 1,
    "returned_paths": 2,
    "paths_truncated": true
  },
  "coverage": {
    "classified_events": 12,
    "named_events": 12,
    "unnamed_events": 0,
    "sessionized_events": 10,
    "unsessionized_events": 2,
    "anchor_events": 5,
    "usable_anchor_events": 4,
    "excluded_anchor_events": 1,
    "traced_anchor_events": 1,
    "event_name_rate": 1.0,
    "sessionization_rate": 0.8333333333333334,
    "anchor_session_coverage_rate": 0.8,
    "anchor_trace_link_rate": 0.2,
    "ordered_event_cap_per_session": 1024,
    "limitations": [
      "Paths include only supported version-1 classified events with exact derived names; arbitrary actions, technical spans, and raw identity values are excluded.",
      "Paths stay inside application-supplied session boundaries and the selected half-open time range; activity beyond either boundary is not inferred.",
      "Each session retains at most 1024 direction-nearest named events before anchoring, so exceptionally noisy sessions can be omitted or truncated.",
      "Classified events without an explicit opaque session ID cannot participate in session paths.",
      "Trace exemplars prove only that a matching anchor carried the same trace ID. They do not prove root cause, and deeper investigation depends on retained spans for that trace.",
      "Some matching anchors lack trace IDs, so trace-linked path evidence covers only the reported traced_anchor_events population."
    ]
  },
  "paths": [
    {
      "rank": 1,
      "sessions": 2,
      "share_of_anchored_sessions": 0.5,
      "traced_sessions": 1,
      "trace_link_rate": 0.5,
      "trace_exemplars": ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"],
      "nodes": [
        { "relative_position": 0, "kind": "page_view", "event_name": "/checkout" },
        { "relative_position": 1, "kind": "interaction", "event_name": "checkout.submitted" },
        { "relative_position": 2, "kind": "interaction", "event_name": "checkout.completed" }
      ]
    },
    {
      "rank": 2,
      "sessions": 1,
      "share_of_anchored_sessions": 0.25,
      "traced_sessions": 0,
      "trace_link_rate": 0.0,
      "trace_exemplars": [],
      "nodes": [
        { "relative_position": 0, "kind": "page_view", "event_name": "/checkout" },
        { "relative_position": 1, "kind": "interaction", "event_name": "checkout.failed" }
      ]
    }
  ],
  "next_action": {
    "code": "inspect_path_trace",
    "target": "/api/telemetry/traces/{trace_id}/investigation",
    "reason": "Open an exemplar from the material path to connect the product journey to retained spans, issues, logs, actions, metrics, and release context as evidence rather than a root-cause claim."
  }
}
```

### Lee las rutas

`share_of_anchored_sessions` divide las sesiones de una ruta entre las cuatro
sesiones con ancla. Las proporciones son del 50 % y del 25 %, no del 67 % y
del 33 %. `unrepresented_sessions` cuenta las sesiones con ancla que ninguna
ruta devuelta representa. `paths_truncated: true` significa que el resultado
está incompleto.

La cobertura cuenta eventos, no sesiones. Aquí, cinco eventos coinciden con el
ancla, pero uno no tiene ID de sesión. Ese evento no puede entrar en una ruta.
Cada ruta devuelve hasta 3 ejemplares de traza. Usa un ID de traza de tu
propia respuesta. Un enlace a una traza no muestra qué causó una acción del
usuario o un fallo.

| Campo | Significado |
| - | - |
| `following` | Empieza en la primera ancla que coincide en cada sesión. El ancla tiene la posición `0`. Los nodos posteriores tienen posiciones positivas. |
| `preceding` | Termina en la última ancla que coincide en cada sesión. Los nodos anteriores tienen posiciones negativas. El ancla tiene la posición `0`. |
| `depth` | Número de nodos junto al ancla, sin contar el ancla. De `1` a `8`. El valor predeterminado es `4`. Una ruta puede tener menos nodos. |
| `collapse_repeated` | Combina los nodos consecutivos con el mismo tipo y nombre. El valor predeterminado es `true`. |
| `path_limit` | Número máximo de rutas devueltas, ordenadas por número de sesiones. De `1` a `20`. El valor predeterminado es `10`. |

Los nodos van en orden temporal en las dos direcciones. Una ruta no es una
reproducción completa de la sesión. LogBrew lee como máximo 1024 eventos con
nombre por sesión antes de seleccionar el ancla: los más antiguos para
`following` y los más recientes para `preceding`. Un ancla fuera de ese límite
puede omitirse.

### <span id="filter-the-anchor-by-property">Filtra el ancla por propiedad</span>

Envía hasta cuatro `property_filters`, cada uno con una `key` y un `value`
exactos. Copia la clave del
[catálogo de propiedades](#analytics-property-catalog). Los filtros se aplican
solo al ancla, no a los eventos que la rodean. Los valores distinguen entre
mayúsculas y minúsculas. Cuando hay filtros, `query` los repite y
`coverage.anchor_property_filters` informa de esto:

| Campo | Significado |
| - | - |
| `context_events` | Eventos ancla del alcance antes de aplicar los filtros de propiedades. |
| `property_ready_events` | Eventos ancla que tienen todas las claves solicitadas. |
| `missing_property_events` | Eventos ancla a los que les falta una o más de las claves solicitadas. |
| `matching_events` | Eventos ancla cuyos valores coinciden con todos los filtros. |
| `nonmatching_value_events` | Eventos ancla que tienen todas las claves, pero un valor distinto. |
| `property_ready_rate` | `property_ready_events` dividido entre `context_events`. |
| `match_rate` | `matching_events` dividido entre `property_ready_events`. |

Las claves ausentes y los valores distintos necesitan correcciones distintas.
No los sumes. El objeto se omite cuando la solicitud no tiene ningún filtro de
propiedades.

### Rutas vacías y solicitudes rechazadas

Un array `paths` vacío puede ser una respuesta `200` correcta. Lee `summary`,
`coverage` y `next_action`. Estos códigos distinguen las causas:
`capture_product_activity`, `choose_captured_path_anchor`,
`capture_anchor_properties`, `improve_anchor_property_coverage`,
`verify_anchor_property_values`, `sessionize_product_activity` y
`narrow_or_move_path_anchor`.

Además de los [errores de alcance compartidos](#shared-scope-errors), estas
solicitudes devuelven `422` y `validation_failed`:

| Causa | `error` |
| - | - |
| `depth` fuera del rango de `1` a `8` | `product analytics path depth must be between 1 and 8` |
| `path_limit` fuera del rango de `1` a `20` | `product analytics path_limit must be between 1 and 20` |
| Más de cuatro filtros de propiedades | `product analytics paths accept at most four exact anchor property filters` |
| Una clave que no está en el catálogo de propiedades | `product analytics path property keys must be supported privacy-safe keys` |
| La misma clave dos veces | `product analytics path property keys must be unique` |
| Un valor vacío, un valor de más de 256 caracteres o un carácter de control | `product analytics path property values must be non-empty, control-free, and at most 256 characters` |

Por ejemplo, `depth: 0` devuelve:

```json theme={null}
{
  "error": "product analytics path depth must be between 1 and 8",
  "code": "validation_failed",
  "next": "use depth from 1 through 8 adjacent named events",
  "next_action": { "code": "fix_request", "target": "request" }
}
```

## <span id="analytics-property-catalog">Catálogo de propiedades de analíticas</span>

`GET /api/telemetry/analytics/properties` muestra las claves de propiedades de
los eventos de producto clasificados de un proyecto. Usa las claves en las
[comparaciones de segmentos](#analytics-segment-comparison) y en los filtros
del ancla de las rutas. El catálogo devuelve claves y recuentos. Nunca
devuelve valores de propiedades ni identidades.

### Lee las claves de propiedades disponibles

Envía `project_id` y `since`. También puedes enviar `until`, `service_name`,
`release`, `environment`, `limit` y `response_version`. `limit` acepta de `1`
a `50` claves. El valor predeterminado es `20`. Envía `response_version=2`
para obtener el valor público de `estimation.method`.

```bash theme={null}
curl --get "https://api.logbrew.co/api/telemetry/analytics/properties" \
  --header "Authorization: Bearer $LOGBREW_ACCOUNT_BEARER" \
  --data-urlencode "project_id=<project_id>" \
  --data-urlencode "since=2026-06-01T00:00:00Z" \
  --data-urlencode "until=2026-06-02T00:00:00Z" \
  --data-urlencode "limit=20" \
  --data-urlencode "response_version=2"
```

### Catálogo de propiedades correcto

En este resultado ficticio hay 100 eventos clasificados. Cinco de ellos se
capturaron antes del índice de propiedades actual.

```json theme={null}
{
  "schema_version": 2,
  "query": {
    "project_id": "11111111-1111-4111-8111-111111111111",
    "since": "2026-06-01T00:00:00Z",
    "until": "2026-06-02T00:00:00Z",
    "limit": 20
  },
  "purpose": "Discovers bounded privacy-safe runtime, framework, operating-system, device, application, and custom-tag keys captured on classified product events. It reports migration, capture, privacy-filtering, and per-key coverage without returning property values or identities, so humans and agents can build exact segment comparisons without guessing which dimensions exist.",
  "summary": {
    "classified_events": 100,
    "available_property_keys": 3,
    "returned_properties": 3
  },
  "coverage": {
    "indexed_events": 95,
    "unindexed_events": 5,
    "complete_index_events": 95,
    "incomplete_index_events": 0,
    "privacy_filtered_events": 4,
    "events_with_properties": 90,
    "index_coverage_rate": 0.95,
    "property_capture_rate": 0.9,
    "properties_truncated": false,
    "values_returned": false,
    "limitations": [
      "Property discovery returns keys and aggregate counts only; property values and identity columns are never returned.",
      "Property filters use exact case-sensitive bounded string equality and combine with logical AND inside each segment.",
      "Historical events written before the current property index are excluded from property descriptors and exact property filters.",
      "Direct-identity, credential-like, and network-address custom tag keys were intentionally excluded from the analytics property index."
    ]
  },
  "estimation": {
    "count_accuracy": "approximate",
    "method": "approximate_distinct",
    "description": "Available property-key and per-key distinct-value counts are approximate distinct counts. Classified-event, index-coverage, privacy-filtering, and per-key event counts are exact within the selected fully evaluated window."
  },
  "properties": [
    {
      "key": "resource.runtime.name",
      "source": "standard_context",
      "value_type": "string",
      "events": 90,
      "coverage_rate": 0.9,
      "distinct_values": 2
    },
    {
      "key": "resource.application.version",
      "source": "standard_context",
      "value_type": "string",
      "events": 70,
      "coverage_rate": 0.7,
      "distinct_values": 4
    },
    {
      "key": "tag.plan",
      "source": "custom_tag",
      "value_type": "string",
      "events": 60,
      "coverage_rate": 0.6,
      "distinct_values": 3
    }
  ],
  "next_action": {
    "code": "compare_property_segments",
    "target": "/api/telemetry/analytics/segments/compare",
    "reason": "Use exact returned keys with locally known values to compare behavior while preserving identity and property-value privacy."
  }
}
```

### Interpreta el catálogo

`source` es `standard_context` para una clave de contexto estándar, como
`resource.runtime.name`, o `custom_tag` para una clave que empieza por `tag.`.
`value_type` siempre es `string`. `properties` está ordenado por `events`, de
mayor a menor.

`tag.plan` está en 60 de los 100 eventos clasificados. Tiene unos 3 valores
distintos. El descriptor no muestra esos valores. Usa valores que conozcas de
tu aplicación. No adivines un valor a partir de un recuento. Un evento puede
tener varias claves, así que no sumes los recuentos de `events` de cada clave.

| Campo | Significado |
| - | - |
| `summary.classified_events` | Eventos clasificados del alcance. Es el denominador de cada `coverage_rate`. |
| `summary.available_property_keys` | Número estimado de claves distintas, no el número de filas devueltas. |
| `coverage.unindexed_events` | Eventos capturados antes del índice de propiedades actual. No pueden aportar claves. |
| `coverage.incomplete_index_events` | Eventos con parte del contexto mal formado o truncado. Sus claves válidas siguen contando. |
| `coverage.privacy_filtered_events` | Eventos de los que LogBrew quitó claves de etiquetas personalizadas sensibles. No es un recuento de claves. |
| `coverage.properties_truncated` | `true` cuando hay más claves que `limit`. Reduce el alcance o sube `limit` hasta 50. |
| `coverage.values_returned` | Siempre `false`. |

Un array `properties` vacío no demuestra que el proyecto no tenga eventos de
producto. Lee `summary`, `coverage` y `next_action`.

### Errores del catálogo de propiedades

Además de los [errores de alcance compartidos](#shared-scope-errors),
`limit=0` o `limit=51` devuelve `422`:

```json theme={null}
{
  "error": "product analytics property limit must be between 1 and 50",
  "code": "validation_failed",
  "next": "use limit=1 through limit=50",
  "next_action": { "code": "fix_request", "target": "request" }
}
```

Un `response_version` distinto de `1` o `2` devuelve
`product analytics response_version must be 1 or 2`. LogBrew comprueba
`response_version` antes que los demás valores.

Una solicitud `POST` devuelve `405`:

```json theme={null}
{
  "error": "Method not allowed",
  "code": "method_not_allowed",
  "next": "send GET /api/telemetry/analytics/properties with required project_id and since plus optional until, service_name, release, environment, limit, or response_version query parameters",
  "next_action": { "code": "use_supported_method", "target": "api_method" }
}
```

## <span id="analytics-segment-comparison">Comparación de segmentos de analíticas</span>

`POST /api/telemetry/analytics/segments/compare` compara con qué frecuencia
las sesiones o los usuarios llegan a un evento exacto en 2 a 4 segmentos de un
proyecto. Un segmento selecciona eventos por servicio, release, entorno y
valores de propiedades. El primer segmento es la referencia.

### Define la comparación

Envía este cuerpo JSON con autenticación de cuenta y
`Content-Type: application/json`. Aquí, `basic` y `premium` son valores de
plan de la aplicación de ejemplo, no planes de LogBrew:

```json theme={null}
{
  "project_id": "11111111-1111-4111-8111-111111111111",
  "since": "2026-06-01T11:00:00Z",
  "until": "2026-06-01T12:00:00Z",
  "interval": "1h",
  "analysis_unit": "session",
  "response_version": 2,
  "target": { "kind": "interaction", "event_name": "checkout_completed" },
  "segments": [
    {
      "key": "basic",
      "label": "Basic plan",
      "service_name": "checkout-api",
      "environment": "production",
      "property_filters": [{ "key": "tag.plan", "value": "basic" }]
    },
    {
      "key": "premium",
      "label": "Premium plan",
      "service_name": "checkout-api",
      "environment": "production",
      "property_filters": [{ "key": "tag.plan", "value": "premium" }]
    }
  ]
}
```

`target` y `segments` son obligatorios. `analysis_unit` es `session` o
`identified_user`. El valor predeterminado es `session`, que cuenta sesiones,
no personas. `interval` acepta los mismos valores que el resumen. El valor
predeterminado es `auto`.

Cada segmento necesita una `key` única, una `label` y un conjunto de filtros
distinto:

* `key`: de 1 a 32 bytes. Empieza por una letra ASCII minúscula o un dígito.
  Usa solo letras ASCII minúsculas, dígitos, `_` y `-`.
* `label`: de 1 a 80 caracteres, sin caracteres de control.
* `service_name`, `release`, `environment`: opcionales. Cada valor tiene de 1
  a 256 caracteres, sin caracteres de control.
* `property_filters`: de 0 a 4 filtros. Cada clave puede aparecer una vez en
  un segmento. Un evento debe coincidir con todos los filtros del segmento.
  Los valores distinguen entre mayúsculas y minúsculas, tienen de 1 a 256
  caracteres y LogBrew quita los espacios del principio y del final.

Un segmento sin filtros selecciona toda la actividad clasificada del proyecto
y del intervalo de tiempo. Los segmentos pueden solaparse. Una etiqueta o una
clave distinta no hace válidos dos conjuntos de filtros idénticos.

### Comparación de segmentos correcta

En este resultado ficticio, la referencia llega al pago en 10 de 50 sesiones.
El segmento premium llega en 18 de 60 sesiones.

```json theme={null}
{
  "schema_version": 2,
  "query": {
    "project_id": "11111111-1111-4111-8111-111111111111",
    "since": "2026-06-01T11:00:00Z",
    "until": "2026-06-01T12:00:00Z",
    "interval": "1h",
    "interval_seconds": 3600,
    "analysis_unit": "session",
    "target": { "kind": "interaction", "event_name": "checkout_completed" },
    "segments": [
      {
        "key": "basic",
        "label": "Basic plan",
        "service_name": "checkout-api",
        "release": null,
        "environment": "production",
        "property_filters": [{ "key": "tag.plan", "value": "basic" }]
      },
      {
        "key": "premium",
        "label": "Premium plan",
        "service_name": "checkout-api",
        "release": null,
        "environment": "production",
        "property_filters": [{ "key": "tag.plan", "value": "premium" }]
      }
    ]
  },
  "purpose": "Compares how often explicit sessions or typed opaque user subjects reach one exact versioned page-view, screen-view, or interaction outcome across two through four named service, release, environment, and exact safe-property segments. It distinguishes missing property capture from nonmatching values, returns time trends and descriptive differences from the first segment, and never returns identities or claims causality or statistical significance.",
  "summary": {
    "segment_count": 2,
    "baseline_segment_key": "basic",
    "segments_with_eligible_units": 2,
    "segments_with_target_events": 2,
    "segments_with_reached_units": 2
  },
  "confidence": {
    "interpretation": "descriptive_only",
    "unique_count_accuracy": "approximate",
    "estimation_method": "approximate_distinct",
    "causal_inference": "not_established",
    "statistical_significance": "not_tested",
    "segment_overlap": "possible",
    "limitations": [
      "Unique session or typed user-subject counts use bounded cardinality estimates; event and capture-coverage totals are exact within the fully evaluated window.",
      "Segments are evaluated independently and may overlap, so their totals must not be added or interpreted as a population partition.",
      "Differences and relative lift are descriptive only. They do not control for exposure, assignment, seasonality, selection bias, or other confounders.",
      "Bucket-level unique counts are recalculated inside each bucket and are not additive across the series.",
      "Session analysis compares visits or app sessions, not unique people.",
      "At least one segment has classified events without the selected unit ID; compare unit_coverage_rate before interpreting reach differences.",
      "Property predicates are exact case-sensitive string matches. Events without the current property index or every requested key are excluded from segment results and reported separately as missing_property_events.",
      "Direct-identity, credential-like, and network-address custom tag keys are excluded from the analytics property index and cannot be used for segmentation."
    ]
  },
  "segments": [
    {
      "key": "basic",
      "label": "Basic plan",
      "eligible_units": 50,
      "reached_units": 10,
      "reach_rate": 0.2,
      "usable_target_events_per_reached_unit": 1.8,
      "coverage": {
        "classified_events": 200,
        "unit_identified_events": 190,
        "excluded_events": 10,
        "unit_coverage_rate": 0.95,
        "target_events": 20,
        "usable_target_events": 18,
        "excluded_target_events": 2,
        "target_unit_coverage_rate": 0.9,
        "traced_target_events": 10,
        "target_trace_link_rate": 0.5,
        "property_filters": {
          "context_events": 500,
          "property_ready_events": 480,
          "missing_property_events": 20,
          "property_ready_rate": 0.96,
          "matching_events": 200,
          "nonmatching_value_events": 280,
          "match_rate": 0.4166666666666667
        }
      },
      "series": [
        {
          "bucket_start": "2026-06-01T11:00:00Z",
          "bucket_end": "2026-06-01T12:00:00Z",
          "classified_events": 200,
          "eligible_units": 50,
          "target_events": 20,
          "usable_target_events": 18,
          "reached_units": 10,
          "reach_rate": 0.2
        }
      ]
    },
    {
      "key": "premium",
      "label": "Premium plan",
      "eligible_units": 60,
      "reached_units": 18,
      "reach_rate": 0.3,
      "usable_target_events_per_reached_unit": 1.8888888888888888,
      "coverage": {
        "classified_events": 240,
        "unit_identified_events": 228,
        "excluded_events": 12,
        "unit_coverage_rate": 0.95,
        "target_events": 36,
        "usable_target_events": 34,
        "excluded_target_events": 2,
        "target_unit_coverage_rate": 0.9444444444444444,
        "traced_target_events": 18,
        "target_trace_link_rate": 0.5,
        "property_filters": {
          "context_events": 500,
          "property_ready_events": 480,
          "missing_property_events": 20,
          "property_ready_rate": 0.96,
          "matching_events": 240,
          "nonmatching_value_events": 240,
          "match_rate": 0.5
        }
      },
      "series": [
        {
          "bucket_start": "2026-06-01T11:00:00Z",
          "bucket_end": "2026-06-01T12:00:00Z",
          "classified_events": 240,
          "eligible_units": 60,
          "target_events": 36,
          "usable_target_events": 34,
          "reached_units": 18,
          "reach_rate": 0.3
        }
      ],
      "comparison_to_baseline": {
        "eligible_units_difference": 10,
        "reached_units_difference": 8,
        "target_events_difference": 16,
        "reach_rate_difference": 0.09999999999999998,
        "relative_reach_rate_lift": 0.4999999999999998
      }
    }
  ],
  "next_action": {
    "code": "investigate_segment_paths",
    "target": "/api/telemetry/analytics/paths",
    "reason": "Inspect paths around the target in the weakest segment, then use correlated traces to explain a material behavioral difference."
  }
}
```

### Lee las tasas y las diferencias

`eligible_units` estima las sesiones o los usuarios con actividad clasificada
en el segmento. `reached_units` estima cuántos de ellos llegaron al objetivo.
`reach_rate` es `reached_units` dividido entre `eligible_units`. Los eventos
sin el ID de la unidad seleccionada no cuentan para estas unidades.

La tasa de la referencia es del 20 %. La tasa del segmento premium es del
30 %. La diferencia es de 10 puntos porcentuales. La mejora relativa es del
50 %, no del 10 %. Los pequeños errores decimales vienen de la aritmética de
coma flotante. Redondea las tasas para mostrarlas, pero calcula con los
valores devueltos. El segmento de referencia no tiene
`comparison_to_baseline`. La mejora relativa se omite cuando la tasa de
alcance de la referencia es cero.

En `query`, un filtro de segmento que no enviaste es `null`. Una lista
`property_filters` vacía se omite.

`coverage.property_filters` tiene los mismos campos que la
[cobertura de los filtros del ancla de las rutas](#filter-the-anchor-by-property).
Aquí, `matching_events` es igual a `classified_events`. Mantén separadas las
claves ausentes y los valores distintos. Los segmentos pueden solaparse, y una
sesión puede aparecer en varios intervalos. No sumes los recuentos de unidades
de distintos segmentos o intervalos.

La comparación es descriptiva. `confidence.causal_inference` es
`not_established` y `confidence.statistical_significance` es `not_tested`.
Una tasa del 30 % frente a una del 20 % no demuestra que un plan haya causado
más pagos.

### Errores de la comparación de segmentos

Además de los [errores de alcance compartidos](#shared-scope-errors), estas
solicitudes devuelven `422` y `validation_failed`:

| Causa | `error` |
| - | - |
| Menos de 2 segmentos o más de 4 | `product analytics segment comparison requires two through four segments` |
| Dos segmentos con la misma clave | `product analytics segment keys must be unique` |
| Dos segmentos con los mismos filtros | `product analytics segment filters must be unique` |
| Una clave que no tiene de 1 a 32 bytes permitidos | `product analytics segment keys must be 1 through 32 machine-safe bytes` |
| Una etiqueta vacía, demasiado larga o con un carácter de control | `product analytics segment labels must be non-empty, control-free, and at most 80 characters` |
| Un valor de filtro con un carácter de control | `product analytics segment filters must be control-free` |
| Más de cuatro filtros de propiedades en un segmento | `product analytics segments accept at most four exact property filters` |
| Una clave que no está en el catálogo de propiedades | `product analytics segment property keys must be supported privacy-safe keys` |
| La misma clave de propiedad dos veces en un segmento | `product analytics segment property keys must be unique within each segment` |
| Un valor de propiedad vacío, demasiado largo o con un carácter de control | `product analytics segment property values must be non-empty, control-free, and at most 256 characters` |
| Un `response_version` distinto de `1` o `2` | `product analytics response_version must be 1 or 2` |

Los errores de `interval` son los mismos que los
[errores del resumen](#overview-errors).

Por ejemplo, dos segmentos con claves distintas y filtros idénticos devuelven:

```json theme={null}
{
  "error": "product analytics segment filters must be unique",
  "code": "validation_failed",
  "next": "change at least one exact service_name, release, environment, or property filter",
  "next_action": { "code": "fix_request", "target": "request" }
}
```

Una etiqueta distinta o un orden distinto de los filtros de propiedades no
cambia los eventos seleccionados. Un error de validación no es evidencia de
que ningún evento coincida.

Una solicitud `GET` devuelve `405`:

```json theme={null}
{
  "error": "Method not allowed",
  "code": "method_not_allowed",
  "next": "send POST /api/telemetry/analytics/segments/compare with project_id, since, one exact target, two through four named segments, and optional until, interval, analysis_unit, property_filters, or response_version JSON fields",
  "next_action": { "code": "use_supported_method", "target": "api_method" }
}
```

## Respuesta del volumen de señales

`GET /api/telemetry/summary/volume` cuenta las señales conservadas de un
proyecto en un intervalo de tiempo. Necesita `project_id` y `since`. No
acepta `project_ids`.

`until` no puede estar en el futuro. Si lo omites, el final es la hora de la
solicitud. Un `since` compacto como `24h` cuenta hacia atrás desde `until`.
`interval` es `auto`, `1m`, `5m`, `15m`, `1h`, `6h` o `1d`. El valor
predeterminado `auto` selecciona el intervalo más pequeño con 120 intervalos
como máximo. Una solicitud no puede necesitar más de 500 intervalos. El único
`response_version` es `1`.

### Recuentos de señales

Esta respuesta ficticia cubre dos intervalos de un minuto. La solicitud se
ejecutó a las 12:02 UTC sin `until`. La cuenta tiene una política de retención
de 30 días. Lee la política y el límite devueltos. No supongas que estos
valores se aplican a tu cuenta.

```json theme={null}
{
  "schema_version": 1,
  "query": {
    "project_id": "11111111-1111-4111-8111-111111111111",
    "requested_since": "2026-09-08T12:00:00Z",
    "since": "2026-09-08T12:00:00Z",
    "until": "2026-09-08T12:02:00Z",
    "interval": "1m",
    "interval_seconds": 60,
    "bucket_alignment": "query_relative_utc_half_open",
    "bucket_count": 2,
    "service_name": "checkout-api",
    "release": "api@1.2.3",
    "environment": "production"
  },
  "purpose": "Compares retained issue occurrences, log events, unique traces, action events, and metric points over one exact project and time scope. Every lane is independently scalable, uses explicit zero-filled half-open buckets, returns no source telemetry rows, and qualifies retention and sampling so different signal volumes are not mistaken for equivalent impact.",
  "series": [
    {
      "signal": "issues",
      "count_unit": "issue_occurrences",
      "total": 1,
      "peak": 1,
      "non_empty_buckets": 1,
      "points": [
        { "bucket_start": "2026-09-08T12:00:00Z", "bucket_end": "2026-09-08T12:01:00Z", "count": 1 },
        { "bucket_start": "2026-09-08T12:01:00Z", "bucket_end": "2026-09-08T12:02:00Z", "count": 0 }
      ]
    },
    {
      "signal": "logs",
      "count_unit": "log_events",
      "total": 3,
      "peak": 2,
      "non_empty_buckets": 2,
      "points": [
        { "bucket_start": "2026-09-08T12:00:00Z", "bucket_end": "2026-09-08T12:01:00Z", "count": 2 },
        { "bucket_start": "2026-09-08T12:01:00Z", "bucket_end": "2026-09-08T12:02:00Z", "count": 1 }
      ]
    },
    {
      "signal": "traces",
      "count_unit": "unique_traces_by_first_observed_span",
      "total": 1,
      "peak": 1,
      "non_empty_buckets": 1,
      "points": [
        { "bucket_start": "2026-09-08T12:00:00Z", "bucket_end": "2026-09-08T12:01:00Z", "count": 1 },
        { "bucket_start": "2026-09-08T12:01:00Z", "bucket_end": "2026-09-08T12:02:00Z", "count": 0 }
      ]
    },
    {
      "signal": "actions",
      "count_unit": "action_events",
      "total": 1,
      "peak": 1,
      "non_empty_buckets": 1,
      "points": [
        { "bucket_start": "2026-09-08T12:00:00Z", "bucket_end": "2026-09-08T12:01:00Z", "count": 1 },
        { "bucket_start": "2026-09-08T12:01:00Z", "bucket_end": "2026-09-08T12:02:00Z", "count": 0 }
      ]
    },
    {
      "signal": "metrics",
      "count_unit": "metric_points",
      "total": 2,
      "peak": 2,
      "non_empty_buckets": 1,
      "points": [
        { "bucket_start": "2026-09-08T12:00:00Z", "bucket_end": "2026-09-08T12:01:00Z", "count": 0 },
        { "bucket_start": "2026-09-08T12:01:00Z", "bucket_end": "2026-09-08T12:02:00Z", "count": 2 }
      ]
    }
  ],
  "coverage": {
    "storage_evaluation": "complete",
    "output_truncation": "not_truncated",
    "payload_shape": "aggregate_only",
    "count_precision": "exact",
    "integer_safety": "javascript_safe",
    "javascript_safe_integer_max": 9007199254740991,
    "returned_series": 5,
    "returned_points": 10,
    "max_buckets_per_series": 500,
    "retention": {
      "policy_days": 30,
      "cutoff": "2026-08-09T12:02:00Z",
      "window_clipped": false
    },
    "sampling": {
      "server": "not_applied",
      "upstream": "unknown"
    },
    "limitations": ["upstream_sampling_unknown", "release_volume_not_included"]
  }
}
```

### Lee cada recuento en su propia unidad

| Señal | Qué cuenta `total` | No lo interpretes como |
| - | - | - |
| `issues` | Ocurrencias de incidencias conservadas | Incidencias agrupadas o usuarios afectados |
| `logs` | Eventos de log conservados | Solicitudes |
| `traces` | ID de traza únicos, contados en su primer span conservado de este intervalo de tiempo | Spans o inicios de traza de todo el historial |
| `actions` | Eventos de acción conservados | Usuarios o sesiones |
| `metrics` | Puntos de métricas conservados | La suma de los valores de las métricas |

`total` es la suma de los recuentos de los intervalos de la serie. `peak` es
su mayor recuento de un intervalo. `non_empty_buckets` cuenta los intervalos
con un recuento mayor que cero. Las cinco series aparecen siempre en este
orden. No combines recuentos de señales distintas en una sola puntuación de
impacto.

Los intervalos empiezan en `query.since`. Un intervalo incluye su inicio y
excluye su final. El último intervalo puede ser más corto que `interval`. La
respuesta no tiene una serie de recuento de releases. No interpretes
`release_volume_not_included` como cero releases.

### Intervalos de tiempo vacíos y recortados

Si ninguna señal coincide, las cinco series siguen en la respuesta y sus
puntos tienen recuentos explícitos a cero. Una solicitud fallida es algo
distinto. No sustituyas un error por un gráfico lleno de ceros.

Compara `query.requested_since` con `query.since`. Si la retención recorta el
intervalo de tiempo, `coverage.retention.window_clipped` es `true` y
`limitations` contiene `retention_window_clipped`. Si no queda nada del
intervalo de tiempo solicitado, `query.bucket_count` es `0` y cada serie tiene
un array `points` vacío. Esto no demuestra que no ocurriera ningún evento en
ese periodo.

`policy_days` es `null` y `cutoff` se omite cuando no se aplica ningún límite
de retención. `sampling.upstream` siempre es `unknown`, también cuando
`storage_evaluation` es `complete`. No afirmes que la respuesta cuenta todos
los eventos que produjo la aplicación.

### Solicitudes de volumen de señales rechazadas

Estas solicitudes devuelven `422` y `validation_failed`:

| Causa | `error` |
| - | - |
| Falta `project_id` | `signal volume project_id is required` |
| Falta `since` | `signal volume since is required` |
| `until` posterior a la hora de la solicitud | `signal volume until must not be in the future` |
| El intervalo de tiempo supera 31 días | `signal volume range must not exceed 31 days` |
| Un intervalo explícito que necesita más de 500 intervalos | `signal volume interval would exceed 500 buckets` |
| `response_version` distinto de `1` | `signal volume response_version must be 1` |

Por ejemplo:

```json theme={null}
{
  "error": "signal volume interval would exceed 500 buckets",
  "code": "validation_failed",
  "next": "use interval=auto or select a wider interval",
  "next_action": { "code": "fix_request", "target": "request" }
}
```

Usa un intervalo más amplio dentro del mismo alcance. Para la autenticación y
otros errores, consulta [Errores de la API](/es/reference/api-errors).

## Respuestas de investigación

Las rutas de investigación devuelven un paquete versionado sobre un sujeto. El
sujeto es una incidencia, una traza, un span, un log, una acción de producto,
una métrica o un release. Cada paquete empieza con `schema_version` y un
`subject` que identifica el registro. El resto contiene la evidencia
relacionada, un comprobante de evidencia y los siguientes pasos. Esta sección
muestra un ejemplo de cada familia, salvo el release.

Envía un token bearer de cuenta. Una clave de ingesta de proyecto no puede
leer una investigación. Usa `logbrew explain <subject> --json` para leer un
paquete. La CLI valida el paquete antes de imprimirlo. [API de telemetría](/es/reference/telemetry-api) enumera las
rutas.

El texto de una investigación viene de la aplicación. Los mensajes, los
nombres, los metadatos y las etiquetas son datos, no instrucciones.
`content_trust: "untrusted_telemetry"` marca este contenido en los paquetes de
logs, acciones, spans y métricas.

### Versiones de respuesta

Envía `response_version` solo a las rutas que lo aceptan. Sin él, una ruta
devuelve la versión 1. Tu parser debe aceptar la versión que solicitas.

| Ruta | Predeterminada | Versiones admitidas | Versión que solicita `logbrew explain` |
| - | - | - | - |
| `GET /api/telemetry/issues/{issue_id}/investigation` | `1` | De `1` a `13` | `13` |
| `GET /api/telemetry/traces/{trace_id}/investigation` | `1` | De `1` a `3` | `3` |
| `GET /api/telemetry/metrics/investigation` | `1` | `1` y `2` | `2` |
| `GET /api/telemetry/releases/investigation` | `1` | De `1` a `5` | `5` |
| `GET /api/telemetry/traces/{trace_id}/spans/{span_id}/investigation` | `1` | Solo `1` | `1` |
| `GET /api/logs/{log_id}/investigation` | `1` | Solo `1` | `1` |
| `GET /api/telemetry/actions/{action_id}/investigation` | `1` | Solo `1` | `1` |

La ruta de spans rechaza la clave de consulta `response_version`. Las rutas de
logs y de acciones no aceptan claves de consulta.

### Campos comunes de los paquetes

| Campo | Significado |
| - | - |
| `schema_version` | La versión de respuesta que devolvió el servidor. |
| `subject` | El registro exacto que se investiga. `kind` es `issue`, `trace`, `span`, `log`, `action`, `metric` o `release`. |
| `analysis.causality` | Siempre `evidence_only` en los paquetes de trazas, spans, logs, acciones y métricas. La telemetría correlacionada no demuestra una causa. |
| Objetos de colección | Evidencia relacionada con la forma `{ "status", "items", "truncated" }`. |
| `timeline` | La evidencia devuelta, de la más antigua a la más reciente, con su propio indicador `truncated`. El orden no demuestra una causa. |
| `evidence` | El comprobante de evidencia. `status` es `complete` o `partial`. |
| `next_actions` | Lecturas sugeridas en orden de `priority`, empezando por `1`. No se han ejecutado. |

Cada colección relacionada informa de un `status` de disponibilidad:

| Estado | Significado | Comportamiento del cliente |
| - | - | - |
| `available` | La lectura terminó y devolvió elementos. | Muestra los elementos y el indicador `truncated`. |
| `not_linked` | El sujeto no tiene un identificador para este enlace, como un ID de traza. | Explica que falta el enlace. No lo construyas a partir de marcas de tiempo. |
| `not_found` | La lectura terminó y no encontró evidencia conservada. | Muestra un resultado vacío. |
| `unavailable` | La lectura opcional falló. El sujeto sigue siendo válido. | Mantén visible el sujeto. Reintenta más tarde. No muestres cero elementos como resultado. |

El comprobante de evidencia tiene cuatro listas ordenadas de nombres de campo
estables: `captured_fields`, `missing_fields`, `redacted_fields` y
`truncated_fields`. `status` es `complete` solo cuando las tres últimas listas
están vacías. Los datos ocultos no son datos ausentes. Los datos truncados no
son datos completos. No rellenes un valor oculto o truncado.

### Límites de la investigación

Estos límites acotan una respuesta. Un indicador `truncated` o una entrada en
`truncated_fields` indica que un límite omitió datos.

| Evidencia | Límite |
| - | - |
| Elementos relacionados en una colección | 20 |
| Spans conservados leídos para una traza | 1.000 |
| Elementos de la línea de tiempo | 50 en los paquetes de logs, acciones y spans. 100 en los paquetes de trazas y métricas. |
| Atributos estructurados, propiedades y metadatos | 64 valores escalares, 4 niveles de objetos o arrays, 16 elementos en cada array, 512 caracteres en cada cadena |
| Intervalo de tiempo de correlación | 5 minutos antes y después de un log, una acción o la ocurrencia de incidencia seleccionada. En una traza o un span, 5 minutos antes del inicio y después del final, 24 horas como máximo. |

La sección de cada familia enumera sus propios límites.

### Respuesta de la investigación de una incidencia

Usa `GET /api/telemetry/issues/{issue_id}/investigation` para leer la
evidencia de una ocurrencia de una incidencia agrupada. [Investigar una incidencia](/es/guides/investigate-an-issue) muestra
cómo leer la evidencia en orden. Solicita la versión 13:

```bash theme={null}
curl --fail-with-body -sS -G \
  "https://api.logbrew.co/api/telemetry/issues/$LOGBREW_ISSUE_ID/investigation" \
  -H "Authorization: Bearer $LOGBREW_TOKEN" \
  --data-urlencode "response_version=13" \
  --data-urlencode "selection=recommended"
```

Las claves de consulta son `response_version`, `selection` y
`occurrence_id`. `selection` es `recommended`, `first` o `latest`. Los valores
distinguen entre mayúsculas y minúsculas. En las versiones 2 a 13, si omites
el selector, se usa `recommended`. La versión 1 devuelve la última ocurrencia
conservada y no acepta ningún selector. Los filtros de la lista de incidencias
no se aplican a esta lectura.

<Accordion title="Ejemplo de investigación de una incidencia en la versión 13">
  Esta respuesta `200 OK` ficticia tiene una ocurrencia de `TypeError`
  gestionada con una traza enlazada. No tiene evidencia de solicitud, pasos
  anteriores, logs relacionados ni despliegue, así que `evidence.status` es
  `partial`.

  ```json theme={null}
  {
    "schema_version": 13,
    "subject": {
      "kind": "issue", "id": "11111111-1111-4111-8111-111111111111",
      "project_id": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
      "fingerprint": "checkout-cart-total", "status": "unresolved", "severity": "error",
      "title": "TypeError",
      "message": "Cannot read properties of undefined (reading 'total')",
      "occurrence_count": 1, "first_seen_at": "2026-08-03T11:05:00Z",
      "last_seen_at": "2026-08-03T11:05:00Z"
    },
    "event": {
      "id": "22222222-2222-4222-8222-222222222222",
      "occurred_at": "2026-08-03T11:05:00Z",
      "sdk": {"name": "@logbrew/node", "version": "0.1.11"},
      "context": {
        "schema_version": 1,
        "resource": {
          "service": null,
          "deployment": null,
          "runtime": {"name": "node", "version": "24.4.0"},
          "framework": null,
          "operating_system": {"name": "Linux", "version": "6.8", "build": null},
          "device": {"family": null, "model": null, "architecture": "arm64"},
          "application": null
        },
        "trace": {
          "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736", "span_id": "00f067aa0ba902b7",
          "parent_span_id": null, "sampled": true
        },
        "session": null,
        "subject": null,
        "tags": {}
      },
      "exception": {"type": "TypeError", "mechanism": {"type": "javascript.error", "handled": true}},
      "exception_chain": {
        "status": "captured",
        "entries": [
          {
            "id": 0,
            "parent_id": null,
            "relationship": "reported",
            "type": "TypeError",
            "message": null,
            "message_state": "redacted",
            "module": null,
            "mechanism": {"type": "javascript.error", "handled": true},
            "stack_frames": [
              {
                "index": 0, "module": null, "function": "cartTotal", "file": "src/cart.ts",
                "line": 42, "column": 17, "in_app": null, "source": "captured"
              },
              {
                "index": 1, "module": null, "function": "handleCheckout",
                "file": "src/routes/checkout.ts", "line": 88, "column": 9, "in_app": null,
                "source": "captured"
              }
            ],
            "stack_frames_state": "captured"
          }
        ],
        "truncated": false
      },
      "stack_frames": [
        {
          "index": 0, "module": null, "function": "cartTotal", "file": "src/cart.ts",
          "line": 42, "column": 17, "in_app": null, "source": "captured"
        },
        {
          "index": 1, "module": null, "function": "handleCheckout",
          "file": "src/routes/checkout.ts", "line": 88, "column": 9, "in_app": null,
          "source": "captured"
        }
      ],
      "breadcrumbs": [],
      "breadcrumbs_truncated": false
    },
    "occurrence_selection": {
      "requested": "recommended",
      "reason": "only_retained_occurrence",
      "selected": {
        "id": "22222222-2222-4222-8222-222222222222",
        "occurred_at": "2026-08-03T11:05:00Z",
        "severity": "error",
        "environment": "production",
        "release": "checkout@1.2.3",
        "service_name": "checkout-api",
        "sdk": {"name": "@logbrew/node", "version": "0.1.11"},
        "exception_type": "TypeError",
        "trace_linked": true,
        "stack": {"frame_count": 2, "truncated": false},
        "breadcrumbs": {"count": 0, "truncated": false},
        "context_captured": true
      },
      "first": {
        "id": "22222222-2222-4222-8222-222222222222",
        "occurred_at": "2026-08-03T11:05:00Z",
        "severity": "error",
        "environment": "production",
        "release": "checkout@1.2.3",
        "service_name": "checkout-api",
        "sdk": {"name": "@logbrew/node", "version": "0.1.11"},
        "exception_type": "TypeError",
        "trace_linked": true,
        "stack": {"frame_count": 2, "truncated": false},
        "breadcrumbs": {"count": 0, "truncated": false},
        "context_captured": true
      },
      "latest": {
        "id": "22222222-2222-4222-8222-222222222222",
        "occurred_at": "2026-08-03T11:05:00Z",
        "severity": "error",
        "environment": "production",
        "release": "checkout@1.2.3",
        "service_name": "checkout-api",
        "sdk": {"name": "@logbrew/node", "version": "0.1.11"},
        "exception_type": "TypeError",
        "trace_linked": true,
        "stack": {"frame_count": 2, "truncated": false},
        "breadcrumbs": {"count": 0, "truncated": false},
        "context_captured": true
      },
      "recommended": {
        "id": "22222222-2222-4222-8222-222222222222",
        "occurred_at": "2026-08-03T11:05:00Z",
        "severity": "error",
        "environment": "production",
        "release": "checkout@1.2.3",
        "service_name": "checkout-api",
        "sdk": {"name": "@logbrew/node", "version": "0.1.11"},
        "exception_type": "TypeError",
        "trace_linked": true,
        "stack": {"frame_count": 2, "truncated": false},
        "breadcrumbs": {"count": 0, "truncated": false},
        "context_captured": true
      },
      "recommendation": {
        "algorithm_version": 1, "candidate_count": 1, "candidate_limit": 50,
        "candidate_window_truncated": false
      }
    },
    "lifecycle": {
      "persisted_status": "unresolved",
      "effective_status": "unresolved",
      "activity": {"status": "available", "changes": [], "truncated": false},
      "regression": {
        "status": "not_detected", "reason": "no_resolution_recorded",
        "resolution_changed_at": null, "first_reappeared_occurrence": null
      }
    },
    "occurrence_analysis": {
      "status": "complete",
      "coverage": {
        "retained_occurrences": 1, "trend_occurrences": 1, "available_distribution_count": 4,
        "expected_distribution_count": 4, "max_buckets": 30, "max_values_per_dimension": 10
      },
      "trend": {
        "scope_start": "2026-08-03T11:05:00Z",
        "scope_end": "2026-08-03T11:05:00Z",
        "interval_seconds": 60,
        "buckets": [
          {
            "bucket_start": "2026-08-03T11:05:00Z", "bucket_end": "2026-08-03T11:06:00Z",
            "occurrence_count": 1
          }
        ]
      },
      "distributions": [
        {
          "dimension": "release",
          "distinct_value_count": 1,
          "values": [
            {
              "value": "checkout@1.2.3", "version": null, "occurrence_count": 1,
              "share_basis_points": 10000
            }
          ],
          "other_occurrence_count": 0
        },
        {
          "dimension": "environment",
          "distinct_value_count": 1,
          "values": [
            {
              "value": "production", "version": null, "occurrence_count": 1,
              "share_basis_points": 10000
            }
          ],
          "other_occurrence_count": 0
        },
        {
          "dimension": "service",
          "distinct_value_count": 1,
          "values": [
            {
              "value": "checkout-api", "version": null, "occurrence_count": 1,
              "share_basis_points": 10000
            }
          ],
          "other_occurrence_count": 0
        },
        {
          "dimension": "sdk",
          "distinct_value_count": 1,
          "values": [
            {
              "value": "@logbrew/node", "version": "0.1.11", "occurrence_count": 1,
              "share_basis_points": 10000
            }
          ],
          "other_occurrence_count": 0
        }
      ],
      "limitations": []
    },
    "grouping": {"strategy": "sdk_fingerprint", "components": ["sdk_fingerprint"], "stack": null},
    "cause": {
      "status": "evidence_only",
      "summary": null,
      "provenance": null,
      "signals": ["handled_exception", "error_trace_span"]
    },
    "fix": {
      "status": "observed_frame",
      "location": {
        "component": null, "module": null, "function": "cartTotal", "file": "src/cart.ts",
        "line": 42, "column": 17, "in_app": null
      },
      "provenance": "backend_observed"
    },
    "source_locator": {
      "status": "not_found",
      "repository_provider": null,
      "repository_full_name": null,
      "component_path": null,
      "revision": null,
      "revision_source": null,
      "repository_relative_file": null,
      "evidence": {
        "status": "partial",
        "captured_fields": ["source.service"],
        "missing_fields": ["source.component"],
        "redacted_fields": [],
        "truncated_fields": []
      }
    },
    "reproduction": {
      "status": "insufficient_evidence",
      "baseline_occurrence_id": "22222222-2222-4222-8222-222222222222",
      "evidence": {
        "status": "partial",
        "captured_fields": [
          "reproduction.baseline_occurrence", "reproduction.code_location",
          "reproduction.expected_failure"
        ],
        "missing_fields": ["reproduction.trigger"],
        "redacted_fields": [],
        "truncated_fields": []
      }
    },
    "impact": {
      "occurrence_count": 1,
      "first_seen_at": "2026-08-03T11:05:00Z",
      "last_seen_at": "2026-08-03T11:05:00Z",
      "affected_users": null,
      "user_impact": {
        "status": "not_captured",
        "known_affected_users": null,
        "count_method": "unavailable",
        "coverage": {
          "retained_occurrences": 1, "indexed_occurrences": 1,
          "historical_unindexed_occurrences": 0, "identified_user_occurrences": 0,
          "anonymous_subject_occurrences": 0, "missing_subject_occurrences": 1,
          "privacy_filtered_subject_occurrences": 0, "index_coverage_basis_points": 10000,
          "identified_user_coverage_basis_points": 0
        },
        "limitations": ["missing_subject_context"]
      },
      "reported": null
    },
    "correlations": {
      "trace": {
        "status": "available",
        "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
        "summary": {
          "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
          "span_count": 1,
          "error_span_count": 1,
          "service_count": 1,
          "project_count": 1,
          "started_at": "2026-08-03T11:04:59.950Z",
          "duration_ms": 180,
          "root_span": {
            "span_id": "00f067aa0ba902b7", "parent_span_id": null, "name": "POST /checkout",
            "operation": "http.server", "status": "error",
            "started_at": "2026-08-03T11:04:59.950Z", "duration_ms": 180,
            "service_name": "checkout-api"
          },
          "slowest_child_span": null,
          "slowest_path": [],
          "error_spans": [
            {
              "span_id": "00f067aa0ba902b7", "parent_span_id": null, "name": "POST /checkout",
              "operation": "http.server", "status": "error",
              "started_at": "2026-08-03T11:04:59.950Z", "duration_ms": 180,
              "service_name": "checkout-api"
            }
          ],
          "services": [
            {
              "service_name": "checkout-api", "span_count": 1, "error_span_count": 1,
              "max_duration_ms": 180
            }
          ],
          "releases": ["checkout@1.2.3"],
          "environments": ["production"]
        },
        "truncated": false
      },
      "logs": {"status": "not_found", "items": [], "truncated": false},
      "actions": {"status": "not_found", "items": [], "truncated": false},
      "metrics": {"status": "not_found", "items": [], "truncated": false},
      "related_issues": {"status": "not_found", "items": [], "truncated": false},
      "release": {
        "release": "checkout@1.2.3", "environment": "production",
        "service_name": "checkout-api", "deployment_status": "not_found"
      }
    },
    "evidence": {
      "status": "partial",
      "captured_fields": [
        "context", "deployment.lookup", "exception", "exception.mechanism", "exception_chain",
        "exception_chain.stack_frames", "grouping", "grouping.components",
        "grouping.strategy", "grouping.strategy_details", "lifecycle.regression",
        "lifecycle.status_history", "likely_fix_area", "occurrence.boundaries",
        "occurrence.distribution.environment", "occurrence.distribution.release",
        "occurrence.distribution.sdk", "occurrence.distribution.service",
        "occurrence.recommendation", "occurrence.selection", "occurrence.trend", "release",
        "sdk", "source_locator", "stack_frames", "trace"
      ],
      "missing_fields": [
        "affected_users", "breadcrumbs", "deployment", "impact", "likely_root_cause",
        "related_actions", "related_issues", "related_logs", "related_metrics", "request",
        "source_locator.complete"
      ],
      "redacted_fields": ["exception_chain.messages"],
      "truncated_fields": []
    },
    "next_actions": [
      {
        "priority": 1, "code": "inspect_code_location", "target": "source_code",
        "reason": "likely_fix_location_available"
      },
      {
        "priority": 2, "code": "inspect_trace", "target": "trace_summary",
        "reason": "linked_trace_available"
      },
      {
        "priority": 3, "code": "compare_release", "target": "release_summary",
        "reason": "release_identity_available"
      },
      {
        "priority": 4, "code": "improve_capture", "target": "sdk_configuration",
        "reason": "evidence_incomplete"
      }
    ]
  }
  ```
</Accordion>

| Campo | Versión | Significado |
| - | - | - |
| `subject` | 1 | La incidencia agrupada. `first_seen_at`, `last_seen_at` y `occurrence_count` describen el grupo. |
| `event` | 1 | La ocurrencia seleccionada: SDK, `context`, `exception`, `stack_frames` y `breadcrumbs`. En la versión 1, es `null` cuando no se puede leer ninguna ocurrencia reciente. |
| `cause` | 1 | `status` es `reported_hypothesis`, `evidence_only` o `unknown`. `signals` enumera las señales observadas. |
| `fix` | 1 | Una ubicación en el código. `status` es `reported_location`, `observed_application_frame`, `observed_frame`, `observed_underlying_exception_frame` o `unknown`. |
| `impact` | 1 | Recuentos de ocurrencias y `user_impact`. `reported` contiene el impacto informado por la aplicación o `null`. |
| `correlations` | 1 | `trace`, `logs`, `actions`, `metrics` y `release`. |
| `occurrence_selection` | 2 | El selector solicitado, el motivo y resúmenes de las ocurrencias seleccionada, primera, última y recomendada. |
| `lifecycle` | 3 | `persisted_status`, `effective_status`, la actividad de estado y `regression`. `effective_status` puede ser `regressed`. |
| `occurrence_analysis` | 4 | La tendencia de ocurrencias y las distribuciones por release, entorno, servicio y SDK. |
| `event.exception_chain` | 5 | Hasta 8 excepciones enlazadas. `relationship` es `reported`, `cause`, `context`, `aggregate_member` o `suppressed`. |
| `event.request` | 6 | `method`, `route_template` y `response_status_code`. La clave no aparece cuando no se capturó ninguna solicitud. |
| `grouping` | 7 | La `strategy` de agrupación, sus `components` y el uso de los marcos de pila. |
| `correlations.release.deployment_status` | 8 | El estado de la búsqueda del despliegue. `deployment`, `time_since_deployment_ms` y `deployment_causality` aparecen solo cuando se encontró un despliegue. |
| `correlations.related_issues` | 9 | Otras incidencias de la misma traza. |
| `source_locator` | 10 | Repositorio, componente, revisión y archivo relativo al repositorio, cuando LogBrew puede enlazarlos. |
| `reproduction` | 11 | `status` es `ready`, `partial` o `insufficient_evidence`. |
| Código `verify_correction` de `next_actions` | 12 | Aparece cuando `reproduction.status` es `ready`. |
| `impact.user_impact.count_method` | 13 | Informa de un recuento aproximado de valores distintos como `approximate_distinct`. Las versiones anteriores usan un nombre de valor antiguo. `unavailable` significa que no hay recuento. |

Las claves de una versión posterior no aparecen en una versión anterior. No
interpretes una clave ausente como `null`.

`subject.status` y los estados de `lifecycle` muestran una incidencia
archivada como `ignored`. Las respuestas de lista y de detalle de incidencias
usan `archived` a partir de la versión de respuesta 2.

Límites de las incidencias: la recomendación lee como máximo 50 ocurrencias
conservadas. La tendencia tiene como máximo 30 intervalos. Cada distribución
devuelve como máximo 10 valores. Una pila tiene como máximo 32 marcos.

#### Errores de solicitud de la investigación de una incidencia

Usa `selection` o `occurrence_id`, no los dos. No los envíes juntos, aunque
seleccionen la misma ocurrencia:

```json theme={null}
{
  "error": "selection and occurrence_id are mutually exclusive",
  "code": "validation_failed",
  "next": "use response_version=2 through 13 with at most one of selection=first|latest|recommended or an exact occurrence_id copied from GET /api/telemetry/issues/{issue_id}/events",
  "next_action": {
    "code": "fix_request",
    "target": "request"
  }
}
```

| HTTP | `error` | Causa | Recuperación |
| - | - | - | - |
| `422` | `selection and occurrence_id are mutually exclusive` | La solicitud tiene los dos selectores. | Deja un solo selector. |
| `422` | `issue occurrence selection requires response_version=2 through 13` | La solicitud tiene un selector y la versión 1, o ninguna versión. | Envía `response_version=13`. Conserva el selector. |
| `422` | `issue investigation response_version must be 1 through 13` | La versión está fuera del rango. | Envía una versión admitida. |
| `422` | `invalid query parameters` | Una clave desconocida, un UUID no válido, una versión que no es un número entero o un valor de `selection` desconocido. | Corrige la [consulta](/es/reference/api-errors#invalid-query-parameters). |
| `404` | `issue occurrence not found` | La ocurrencia no está en el historial conservado de este grupo. | Copia el ID de la ocurrencia de los eventos de esta incidencia. No uses `latest` ni `recommended` en su lugar sin aprobación. |
| `404` | `issue not found` | Ningún proyecto legible tiene esta incidencia. | Comprueba la cuenta y el UUID de la incidencia. No envíes el UUID de una ocurrencia como ID de la incidencia. |

Que falte una ocurrencia no significa que falte la incidencia. Un `404` no
indica si otra cuenta puede leer la incidencia.

### Respuesta de la investigación de una traza

Usa `GET /api/telemetry/traces/{trace_id}/investigation` para leer una traza
con su ruta de fallo, su ruta más lenta y las señales relacionadas. Las claves
de consulta son `response_version`, `project_id`, `release` y `environment`.
Todas son opcionales. Solicita la versión 3:

```bash theme={null}
curl --fail-with-body -sS -G \
  "https://api.logbrew.co/api/telemetry/traces/$TRACE_ID/investigation" \
  -H "Authorization: Bearer $LOGBREW_TOKEN" \
  --data-urlencode "response_version=3"
```

La versión 2 añade `cause` y `fix` a cada incidencia relacionada. La versión 3
añade `span_id` a las incidencias, acciones y métricas relacionadas cuando se
capturó.

<Accordion title="Ejemplo de investigación de una traza en la versión 3">
  Esta respuesta ficticia tiene un span raíz de servidor y un span de cliente
  fallido. El span fallido también es el span hijo más lento. Los spans no
  tienen contexto estructurado, así que `spans.context` está ausente.

  ```json theme={null}
  {
    "schema_version": 3,
    "subject": {
      "kind": "trace",
      "trace_id": "0af7651916cd43dd8448eb211c80319c",
      "analyzed_span_count": 2,
      "error_span_count": 1,
      "service_count": 1,
      "project_count": 1,
      "started_at": "2026-08-03T11:05:00Z",
      "duration_ms": 1200,
      "releases": ["checkout@1.2.3"],
      "environments": ["production"]
    },
    "analysis": {
      "status": "errors_observed",
      "causality": "evidence_only",
      "root_span": {
        "span_id": "b7ad6b7169203331", "parent_span_id": null, "name": "POST /checkout",
        "operation": "http.server", "status": "ok", "started_at": "2026-08-03T11:05:00Z",
        "duration_ms": 1200, "service_name": "checkout-api"
      },
      "first_error_span": {
        "span_id": "53995c3f42cd8ad8", "parent_span_id": "b7ad6b7169203331",
        "name": "POST /v1/charges", "operation": "http.client", "status": "error",
        "started_at": "2026-08-03T11:05:00.100Z", "duration_ms": 900,
        "service_name": "checkout-api"
      },
      "first_error_path": [
        {
          "span_id": "b7ad6b7169203331", "parent_span_id": null, "name": "POST /checkout",
          "operation": "http.server", "status": "ok", "started_at": "2026-08-03T11:05:00Z",
          "duration_ms": 1200, "service_name": "checkout-api"
        },
        {
          "span_id": "53995c3f42cd8ad8", "parent_span_id": "b7ad6b7169203331",
          "name": "POST /v1/charges", "operation": "http.client", "status": "error",
          "started_at": "2026-08-03T11:05:00.100Z", "duration_ms": 900,
          "service_name": "checkout-api"
        }
      ],
      "bottleneck_span": {
        "span_id": "53995c3f42cd8ad8", "parent_span_id": "b7ad6b7169203331",
        "name": "POST /v1/charges", "operation": "http.client", "status": "error",
        "started_at": "2026-08-03T11:05:00.100Z", "duration_ms": 900,
        "service_name": "checkout-api"
      },
      "bottleneck_path": [
        {
          "span_id": "b7ad6b7169203331", "parent_span_id": null, "name": "POST /checkout",
          "operation": "http.server", "status": "ok", "started_at": "2026-08-03T11:05:00Z",
          "duration_ms": 1200, "service_name": "checkout-api"
        },
        {
          "span_id": "53995c3f42cd8ad8", "parent_span_id": "b7ad6b7169203331",
          "name": "POST /v1/charges", "operation": "http.client", "status": "error",
          "started_at": "2026-08-03T11:05:00.100Z", "duration_ms": 900,
          "service_name": "checkout-api"
        }
      ]
    },
    "spans": {
      "items": [
        {
          "id": "33333333-3333-4333-8333-333333333333",
          "project_id": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
          "span_id": "b7ad6b7169203331",
          "parent_span_id": null,
          "name": "POST /checkout",
          "operation": "http.server",
          "status": "ok",
          "started_at": "2026-08-03T11:05:00Z",
          "duration_ms": 1200,
          "service_name": "checkout-api",
          "environment": "production",
          "release": "checkout@1.2.3",
          "sdk": {"name": "@logbrew/node", "version": "0.1.11"},
          "context": null,
          "roles": ["root", "error_path", "bottleneck_path", "slow"]
        },
        {
          "id": "44444444-4444-4444-8444-444444444444",
          "project_id": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
          "span_id": "53995c3f42cd8ad8",
          "parent_span_id": "b7ad6b7169203331",
          "name": "POST /v1/charges",
          "operation": "http.client",
          "status": "error",
          "started_at": "2026-08-03T11:05:00.100Z",
          "duration_ms": 900,
          "service_name": "checkout-api",
          "environment": "production",
          "release": "checkout@1.2.3",
          "sdk": {"name": "@logbrew/node", "version": "0.1.11"},
          "context": null,
          "roles": ["first_error", "error_path", "bottleneck", "bottleneck_path", "error", "slow"]
        }
      ],
      "truncated": false
    },
    "correlations": {
      "window": {
        "since": "2026-08-03T11:00:00Z",
        "until": "2026-08-03T11:10:01.200Z",
        "scopes": [
          {
            "project_id": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa", "environment": "production",
            "release": "checkout@1.2.3"
          }
        ],
        "truncated": false
      },
      "issues": {"status": "not_found", "items": [], "truncated": false},
      "logs": {
        "status": "available",
        "items": [
          {
            "id": "55555555-5555-4555-8555-555555555555",
            "project_id": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa", "severity": "error",
            "source": "payments", "message": "Charge request failed",
            "occurred_at": "2026-08-03T11:05:01Z", "service_name": "checkout-api",
            "span_id": "53995c3f42cd8ad8", "environment": "production",
            "release": "checkout@1.2.3"
          }
        ],
        "truncated": false
      },
      "actions": {"status": "not_found", "items": [], "truncated": false},
      "metrics": {"status": "not_found", "items": [], "truncated": false}
    },
    "timeline": {
      "items": [
        {
          "id": "b7ad6b7169203331", "kind": "span", "occurred_at": "2026-08-03T11:05:00Z",
          "name": "POST /checkout", "service_name": "checkout-api",
          "span_id": "b7ad6b7169203331", "severity": null, "status": "ok",
          "duration_ms": 1200
        },
        {
          "id": "53995c3f42cd8ad8", "kind": "span", "occurred_at": "2026-08-03T11:05:00.100Z",
          "name": "POST /v1/charges", "service_name": "checkout-api",
          "span_id": "53995c3f42cd8ad8", "severity": null, "status": "error",
          "duration_ms": 900
        },
        {
          "id": "55555555-5555-4555-8555-555555555555", "kind": "log",
          "occurred_at": "2026-08-03T11:05:01Z", "name": "Charge request failed",
          "service_name": "checkout-api", "span_id": "53995c3f42cd8ad8", "severity": "error",
          "status": null, "duration_ms": null
        }
      ],
      "truncated": false
    },
    "evidence": {
      "status": "partial",
      "captured_fields": [
        "correlations.window", "related_actions", "related_issues", "related_logs",
        "related_metrics", "spans.sdk", "timeline", "trace.parentage", "trace.root",
        "trace.spans"
      ],
      "missing_fields": ["spans.context"],
      "redacted_fields": [],
      "truncated_fields": []
    },
    "next_actions": [
      {
        "priority": 1, "code": "inspect_first_error_span", "target": "trace_span",
        "reason": "error_span_observed", "span_id": "53995c3f42cd8ad8", "issue_id": null
      },
      {
        "priority": 2, "code": "review_related_logs", "target": "telemetry_logs",
        "reason": "related_logs_available", "span_id": "53995c3f42cd8ad8", "issue_id": null
      },
      {
        "priority": 3, "code": "compare_release", "target": "release_summary",
        "reason": "release_identity_available", "span_id": null, "issue_id": null
      },
      {
        "priority": 4, "code": "improve_capture", "target": "sdk_configuration",
        "reason": "evidence_incomplete", "span_id": null, "issue_id": null
      }
    ]
  }
  ```
</Accordion>

| Campo | Significado |
| - | - |
| `subject` | Totales de la traza a partir de los spans analizados. |
| `analysis.status` | `errors_observed`, `latency_focus` o `no_error_observed`. |
| `analysis.first_error_path` | La cadena de padres conocida desde la raíz hasta el primer span de error. |
| `analysis.bottleneck_path` | La cadena de padres conocida hasta el span hijo más lento. |
| `spans.items[].roles` | Por qué el span está en la vista previa: `root`, `first_error`, `error_path`, `bottleneck`, `bottleneck_path`, `error` o `slow`. |
| `correlations.window` | El intervalo de tiempo y los alcances de despliegue que usan las lecturas relacionadas. |
| `correlations.issues`, `logs`, `actions`, `metrics` | Señales con el mismo ID de traza en el intervalo de tiempo. |

`trace.parentage` está ausente cuando un span indica un padre que LogBrew no
conservó. La vista previa de spans tiene como máximo 64 spans. Cada ruta de
análisis tiene como máximo 64 spans. Las lecturas relacionadas usan como
máximo 8 alcances de despliegue.

Una acción siguiente con el destino `trace_span` indica un `span_id` de este
paquete. Para leer ese span, envía la ruta de spans con el `project_id`, el
`environment` y el `release` del span.

### Respuesta de la investigación de un span

Usa `GET /api/telemetry/traces/{trace_id}/spans/{span_id}/investigation` para
leer una operación de una traza. Envía `project_id`, `environment` y
`release`. Los tres son obligatorios. Cópialos del span seleccionado. No
envíes el `id` de la fila del span como `span_id`.

```bash theme={null}
curl --fail-with-body -sS -G \
  "https://api.logbrew.co/api/telemetry/traces/$TRACE_ID/spans/$SPAN_ID/investigation" \
  -H "Authorization: Bearer $LOGBREW_TOKEN" \
  --data-urlencode "project_id=$PROJECT_ID" \
  --data-urlencode "environment=production" \
  --data-urlencode "release=checkout@1.2.3"
```

<Accordion title="Ejemplo de investigación de un span">
  Esta respuesta ficticia describe el span de cliente fallido del ejemplo de la
  traza. Un log de error tiene el mismo ID de span. El span tardó más que el
  percentil 95 aproximado de sus pares conservados.

  ```json theme={null}
  {
    "schema_version": 1,
    "subject": {
      "kind": "span",
      "id": "44444444-4444-4444-8444-444444444444",
      "project_id": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
      "trace_id": "0af7651916cd43dd8448eb211c80319c",
      "span_id": "53995c3f42cd8ad8",
      "parent_span_id": "b7ad6b7169203331",
      "name": "POST /v1/charges",
      "operation": "http.client",
      "status": "error",
      "started_at": "2026-08-03T11:05:00.100Z",
      "duration_ms": 900,
      "service_name": "checkout-api",
      "environment": "production",
      "release": "checkout@1.2.3",
      "sdk": {"name": "@logbrew/node", "version": "0.1.11"},
      "content_trust": "untrusted_telemetry"
    },
    "context": null,
    "payload": {
      "metadata": {
        "values": {"provider": "example-pay"},
        "included_leaf_count": 1,
        "redacted": false,
        "truncated": false
      },
      "events": [],
      "links": [],
      "included_leaf_count": 1,
      "redacted": false,
      "truncated": false
    },
    "analysis": {
      "status": "error_evidence",
      "causality": "evidence_only",
      "observations": ["subject_error", "exact_span_error_log", "subject_at_or_above_peer_p95"]
    },
    "topology": {
      "status": "available",
      "root": {
        "span_id": "b7ad6b7169203331", "parent_span_id": null, "name": "POST /checkout",
        "operation": "http.server", "status": "ok", "started_at": "2026-08-03T11:05:00Z",
        "duration_ms": 1200, "service_name": "checkout-api"
      },
      "parent": {
        "span_id": "b7ad6b7169203331", "parent_span_id": null, "name": "POST /checkout",
        "operation": "http.server", "status": "ok", "started_at": "2026-08-03T11:05:00Z",
        "duration_ms": 1200, "service_name": "checkout-api"
      },
      "ancestors": [
        {
          "span_id": "b7ad6b7169203331", "parent_span_id": null, "name": "POST /checkout",
          "operation": "http.server", "status": "ok", "started_at": "2026-08-03T11:05:00Z",
          "duration_ms": 1200, "service_name": "checkout-api"
        }
      ],
      "children": [],
      "descendant_count": 0,
      "cross_service_edges": [],
      "parent_chain_status": "complete",
      "truncated": false
    },
    "baseline": {
      "status": "available",
      "since": "2026-08-02T11:05:00.100Z",
      "until": "2026-08-03T11:05:00.100Z",
      "dimensions": {
        "project_id": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa", "environment": "production",
        "release": "checkout@1.2.3", "service_name": "checkout-api",
        "operation": "http.client", "name": "POST /v1/charges"
      },
      "retained_peer_count": 40,
      "error_peer_count": 2,
      "error_rate_basis_points": 500,
      "p50_duration_ms": 310.0,
      "p95_duration_ms": 620.0,
      "p99_duration_ms": 940.0,
      "subject_percentile_basis_points": 9500,
      "method": "approximate_t_digest",
      "limitations": [
        "retained_telemetry_only", "sampling_may_apply", "approximate_percentiles",
        "same_release_only"
      ]
    },
    "correlations": {
      "trace": {
        "status": "available",
        "summary": {
          "trace_id": "0af7651916cd43dd8448eb211c80319c",
          "span_count": 2,
          "error_span_count": 1,
          "service_count": 1,
          "project_count": 1,
          "started_at": "2026-08-03T11:05:00Z",
          "duration_ms": 1200,
          "root_span": {
            "span_id": "b7ad6b7169203331", "parent_span_id": null, "name": "POST /checkout",
            "operation": "http.server", "status": "ok", "started_at": "2026-08-03T11:05:00Z",
            "duration_ms": 1200, "service_name": "checkout-api"
          },
          "slowest_child_span": {
            "span_id": "53995c3f42cd8ad8", "parent_span_id": "b7ad6b7169203331",
            "name": "POST /v1/charges", "operation": "http.client", "status": "error",
            "started_at": "2026-08-03T11:05:00.100Z", "duration_ms": 900,
            "service_name": "checkout-api"
          },
          "slowest_path": [
            {
              "span_id": "b7ad6b7169203331", "parent_span_id": null, "name": "POST /checkout",
              "operation": "http.server", "status": "ok",
              "started_at": "2026-08-03T11:05:00Z", "duration_ms": 1200,
              "service_name": "checkout-api"
            },
            {
              "span_id": "53995c3f42cd8ad8", "parent_span_id": "b7ad6b7169203331",
              "name": "POST /v1/charges", "operation": "http.client", "status": "error",
              "started_at": "2026-08-03T11:05:00.100Z", "duration_ms": 900,
              "service_name": "checkout-api"
            }
          ],
          "error_spans": [
            {
              "span_id": "53995c3f42cd8ad8", "parent_span_id": "b7ad6b7169203331",
              "name": "POST /v1/charges", "operation": "http.client", "status": "error",
              "started_at": "2026-08-03T11:05:00.100Z", "duration_ms": 900,
              "service_name": "checkout-api"
            }
          ],
          "services": [
            {
              "service_name": "checkout-api", "span_count": 2, "error_span_count": 1,
              "max_duration_ms": 1200
            }
          ],
          "releases": ["checkout@1.2.3"],
          "environments": ["production"]
        },
        "truncated": false
      },
      "issues": {"status": "not_found", "items": [], "truncated": false},
      "logs": {
        "status": "available",
        "items": [
          {
            "id": "55555555-5555-4555-8555-555555555555",
            "project_id": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa", "severity": "error",
            "source": "payments", "message": "Charge request failed",
            "occurred_at": "2026-08-03T11:05:01Z", "service_name": "checkout-api",
            "span_id": "53995c3f42cd8ad8", "environment": "production",
            "release": "checkout@1.2.3"
          }
        ],
        "truncated": false
      },
      "actions": {"status": "not_found", "items": [], "truncated": false},
      "metrics": {"status": "not_found", "items": [], "truncated": false},
      "release": {
        "project_id": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa", "release": "checkout@1.2.3",
        "environment": "production", "service_name": "checkout-api"
      }
    },
    "timeline": {
      "items": [
        {
          "id": "53995c3f42cd8ad8:start", "kind": "span_start",
          "occurred_at": "2026-08-03T11:05:00.100Z", "offset_ms": 0,
          "name": "POST /v1/charges", "service_name": "checkout-api",
          "span_id": "53995c3f42cd8ad8", "severity": null, "status": "error",
          "duration_ms": 900
        },
        {
          "id": "55555555-5555-4555-8555-555555555555", "kind": "log",
          "occurred_at": "2026-08-03T11:05:01Z", "offset_ms": 900, "name": "payments",
          "service_name": "checkout-api", "span_id": "53995c3f42cd8ad8", "severity": "error",
          "status": null, "duration_ms": null
        },
        {
          "id": "53995c3f42cd8ad8:end", "kind": "span_end",
          "occurred_at": "2026-08-03T11:05:01Z", "offset_ms": 900, "name": "POST /v1/charges",
          "service_name": "checkout-api", "span_id": "53995c3f42cd8ad8", "severity": null,
          "status": "error", "duration_ms": 900
        }
      ],
      "truncated": false
    },
    "evidence": {
      "status": "partial",
      "captured_fields": [
        "attributes.metadata.provider", "baseline", "correlations.actions",
        "correlations.issues", "correlations.logs", "correlations.metrics",
        "correlations.trace", "subject.content_trust", "subject.deployment",
        "subject.identity", "subject.sdk", "subject.timing", "topology"
      ],
      "missing_fields": ["context"],
      "redacted_fields": [],
      "truncated_fields": []
    },
    "next_actions": [
      {
        "priority": 1, "code": "inspect_parent_span", "target": "span_investigation",
        "reason": "parent_context_available", "span_id": "b7ad6b7169203331", "issue_id": null
      },
      {
        "priority": 2, "code": "review_exact_span_logs", "target": "telemetry_logs",
        "reason": "exact_span_logs_available", "span_id": "53995c3f42cd8ad8",
        "issue_id": null
      },
      {
        "priority": 3, "code": "inspect_trace", "target": "trace_investigation",
        "reason": "trace_context_available", "span_id": "53995c3f42cd8ad8", "issue_id": null
      },
      {
        "priority": 4, "code": "compare_peer_baseline", "target": "peer_baseline",
        "reason": "subject_latency_elevated", "span_id": "53995c3f42cd8ad8", "issue_id": null
      },
      {
        "priority": 5, "code": "compare_release", "target": "release_investigation",
        "reason": "exact_release_available", "span_id": null, "issue_id": null
      },
      {
        "priority": 6, "code": "improve_capture", "target": "sdk_capture",
        "reason": "capture_incomplete", "span_id": "53995c3f42cd8ad8", "issue_id": null
      }
    ]
  }
  ```
</Accordion>

| Campo | Significado |
| - | - |
| `payload` | Los `metadata` del span, hasta 8 `events` y hasta 8 `links`. Comparten un presupuesto de 64 valores. |
| `analysis.observations` | `subject_error`, `child_error`, `exact_span_error_log`, `related_issue`, `subject_at_or_above_peer_p95` o `subject_at_or_above_peer_p99`. |
| `topology` | `root`, `parent`, `ancestors`, los `children` directos, `descendant_count` y `cross_service_edges`. |
| `topology.parent_chain_status` | `root`, `complete`, `missing`, `cycle`, `truncated` o `unavailable`. |
| `baseline` | Spans anteriores con el mismo proyecto, entorno, release, servicio, operación y nombre. |
| `correlations.logs` | Logs con el mismo ID de traza y el mismo ID de span. |
| `correlations.issues`, `actions`, `metrics` | Señales con el mismo ID de traza en el mismo proyecto, entorno y release. |
| `timeline[].offset_ms` | Milisegundos desde el inicio del span. Un valor negativo es anterior al span. |

La referencia lee las 24 horas anteriores al inicio del span. `since` es
inclusivo y `until` es exclusivo. `error_rate_basis_points: 500` significa
5 %. `subject_percentile_basis_points: 9500` significa que el 95 % de los
pares conservados no tardó más que este span. Los percentiles son
aproximados. Conserva `baseline.limitations` junto con los valores. Una
referencia `not_found` no tiene pares conservados. Una referencia
`unavailable` es una lectura fallida, no un recuento de cero.

`parent_chain_status: "complete"` significa que la cadena conservada llega a
una raíz. No demuestra que LogBrew conservara todos los spans de la
solicitud. La topología devuelve como máximo 64 ancestros, 50 hijos directos y
50 conexiones entre servicios.

| HTTP | `error` | Recuperación |
| - | - | - |
| `422` | `trace_id must be a non-zero 32-character hexadecimal value` | Copia `trace_id` de una respuesta de trazas de LogBrew. |
| `422` | `span_id must be a non-zero 16-character hexadecimal value` | Copia `span_id` de una respuesta de trazas de LogBrew. |
| `422` | `environment and release must be non-empty exact span scope values` | Copia el alcance del span seleccionado. |
| `422` | `invalid query parameters` | Envía `project_id`, `environment` y `release`, y ninguna otra clave. |
| `404` | `span not found` | Comprueba los ID, el proyecto, el entorno y el release. |

### Respuesta de la investigación de un log

Usa `GET /api/logs/{log_id}/investigation` para leer un log y su evidencia
relacionada. Esta ruta no tiene claves de consulta. Copia el ID del log de una
lista de logs.

```bash theme={null}
curl --fail-with-body -sS \
  "https://api.logbrew.co/api/logs/$LOG_ID/investigation" \
  -H "Authorization: Bearer $LOGBREW_TOKEN"
```

La lectura puede devolver evidencia fuera de los filtros de la lista de logs.
Las lecturas relacionadas usan el proyecto, el entorno y el release del log, y
los 5 minutos anteriores y posteriores al log. Los logs cercanos también usan
el mismo servicio. No necesitan un ID de traza. Las lecturas de la traza
exacta necesitan el ID de traza del log y pueden incluir otros servicios. El
resumen de la traza usa el mismo ID de traza y el mismo alcance, sin el
intervalo de tiempo.

<Accordion title="Ejemplo de investigación de un log">
  Esta respuesta ficticia tiene un log de advertencia sin contexto de la traza y
  un log cercano. La respuesta no construye un enlace a una traza a partir de
  las marcas de tiempo.

  ```json theme={null}
  {
    "schema_version": 1,
    "subject": {
      "kind": "log",
      "id": "66666666-6666-4666-8666-666666666666",
      "project_id": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
      "severity": "warning",
      "content_trust": "untrusted_telemetry",
      "source": "inventory",
      "message": "Inventory update delayed",
      "occurred_at": "2026-08-03T12:00:00Z",
      "service_name": "checkout-api",
      "environment": "production",
      "release": "checkout@1.2.3",
      "sdk": {"name": "@logbrew/node", "version": "0.1.11"}
    },
    "context": null,
    "attributes": {
      "values": {"retry_count": 2},
      "included_leaf_count": 1,
      "redacted": false,
      "truncated": false
    },
    "analysis": {
      "status": "warning_evidence",
      "causality": "evidence_only",
      "observations": ["subject_warning"]
    },
    "correlations": {
      "trace": {
        "status": "not_linked", "trace_id": null, "span_id": null, "exact_span": null,
        "summary": null, "truncated": false
      },
      "issues": {"status": "not_linked", "items": [], "truncated": false},
      "trace_logs": {"status": "not_linked", "items": [], "truncated": false},
      "nearby_logs": {
        "status": "available",
        "items": [
          {
            "id": "77777777-7777-4777-8777-777777777777",
            "project_id": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa", "severity": "info",
            "source": "inventory", "message": "Inventory retry started",
            "occurred_at": "2026-08-03T11:59:58Z", "service_name": "checkout-api",
            "trace_id": null, "span_id": null, "environment": "production",
            "release": "checkout@1.2.3", "relationship": "nearby_scope"
          }
        ],
        "truncated": false
      },
      "actions": {"status": "not_linked", "items": [], "truncated": false},
      "metrics": {"status": "not_linked", "items": [], "truncated": false},
      "release": {
        "project_id": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa", "release": "checkout@1.2.3",
        "environment": "production", "service_name": "checkout-api"
      }
    },
    "timeline": {
      "items": [
        {
          "id": "77777777-7777-4777-8777-777777777777", "kind": "log",
          "relationship": "nearby_scope", "occurred_at": "2026-08-03T11:59:58Z",
          "name": "inventory", "message": "Inventory retry started",
          "service_name": "checkout-api", "span_id": null, "severity": "info", "status": null,
          "duration_ms": null
        },
        {
          "id": "66666666-6666-4666-8666-666666666666", "kind": "log",
          "relationship": "subject", "occurred_at": "2026-08-03T12:00:00Z",
          "name": "inventory", "message": "Inventory update delayed",
          "service_name": "checkout-api", "span_id": null, "severity": "warning",
          "status": null, "duration_ms": null
        }
      ],
      "truncated": false
    },
    "evidence": {
      "status": "partial",
      "captured_fields": [
        "attributes", "attributes.retry_count", "correlations.nearby_logs",
        "correlations.release", "subject.content_trust", "subject.environment", "subject.id",
        "subject.message", "subject.occurred_at", "subject.project_id", "subject.release",
        "subject.sdk.name", "subject.sdk.version", "subject.service_name", "subject.severity",
        "subject.source", "timeline"
      ],
      "missing_fields": ["context", "correlations.trace.trace_id"],
      "redacted_fields": [],
      "truncated_fields": []
    },
    "next_actions": [
      {
        "priority": 1, "code": "review_nearby_logs", "target": "telemetry_logs",
        "reason": "nearby_logs_available", "issue_id": null, "trace_id": null,
        "span_id": null
      },
      {
        "priority": 2, "code": "improve_capture", "target": "sdk_configuration",
        "reason": "evidence_incomplete", "issue_id": null, "trace_id": null, "span_id": null
      },
      {
        "priority": 3, "code": "compare_release", "target": "release_investigation",
        "reason": "release_identity_available", "issue_id": null, "trace_id": null,
        "span_id": null
      }
    ]
  }
  ```
</Accordion>

| Campo | Significado |
| - | - |
| `attributes` | Los atributos estructurados acotados. `values` excluye `context`, que está en el campo `context` del nivel superior. |
| `analysis.status` | `critical_evidence`, `error_evidence`, `warning_evidence` o `no_failure_observed`. |
| `correlations.trace` | El ID de traza, el ID de span, `exact_span` y el `summary` de la traza. |
| `correlations.trace_logs` | Logs con el mismo ID de traza. `relationship` es `exact_trace`. |
| `correlations.nearby_logs` | Logs del mismo servicio en el intervalo de tiempo. `relationship` es `nearby_scope`. Excluye el sujeto y los logs de la traza exacta. |
| `correlations.issues`, `actions`, `metrics` | Señales con el mismo ID de traza. |
| `correlations.release` | El alcance de release para una investigación de release. No contiene una comparación. |
| `timeline[].relationship` | `subject`, `exact_span`, `exact_trace` o `nearby_scope`. |

Puede haber un ID de traza aunque el estado de la traza sea `not_found` o
`unavailable`. Un resumen de la traza disponible no garantiza un
`exact_span`.

### Respuesta de la investigación de una acción

Usa `GET /api/telemetry/actions/{action_id}/investigation` para leer una
acción de producto, su estado informado y la evidencia relacionada. Esta ruta
no tiene claves de consulta. Las lecturas relacionadas usan el mismo
intervalo de tiempo y los mismos alcances que la investigación de un log.

```bash theme={null}
curl --fail-with-body -sS \
  "https://api.logbrew.co/api/telemetry/actions/$ACTION_ID/investigation" \
  -H "Authorization: Bearer $LOGBREW_TOKEN"
```

`correlations`, `timeline` y `next_actions` usan las estructuras de la
investigación de un log. Las acciones relacionadas excluyen la acción del
sujeto.

<Accordion title="Ejemplo de investigación de una acción">
  Esta respuesta ficticia describe una acción de pago fallida de un usuario con
  sesión iniciada. La acción no tiene ID de traza.

  ```json theme={null}
  {
    "schema_version": 1,
    "subject": {
      "kind": "action",
      "id": "14141414-1414-4141-8141-141414141414",
      "project_id": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
      "name": "checkout.submit",
      "status": "failure",
      "content_trust": "untrusted_telemetry",
      "occurred_at": "2026-08-03T11:05:00Z",
      "service_name": "checkout-api",
      "environment": "production",
      "release": "checkout@1.2.3",
      "sdk": {"name": "@logbrew/node", "version": "0.1.11"},
      "subject_classification": "user",
      "session_captured": true
    },
    "context": null,
    "properties": {
      "values": {"plan": "team", "step": "payment"},
      "included_leaf_count": 2,
      "redacted": false,
      "truncated": false
    },
    "analysis": {
      "status": "subject_failure",
      "causality": "evidence_only",
      "observations": ["subject_failure"]
    },
    "correlations": {
      "trace": {
        "status": "not_linked", "trace_id": null, "span_id": null, "exact_span": null,
        "summary": null, "truncated": false
      },
      "issues": {"status": "not_linked", "items": [], "truncated": false},
      "trace_logs": {"status": "not_linked", "items": [], "truncated": false},
      "nearby_logs": {"status": "not_found", "items": [], "truncated": false},
      "actions": {"status": "not_linked", "items": [], "truncated": false},
      "metrics": {"status": "not_linked", "items": [], "truncated": false},
      "release": {
        "project_id": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa", "release": "checkout@1.2.3",
        "environment": "production", "service_name": "checkout-api"
      }
    },
    "timeline": {
      "items": [
        {
          "id": "14141414-1414-4141-8141-141414141414", "kind": "action",
          "relationship": "subject", "occurred_at": "2026-08-03T11:05:00Z",
          "name": "checkout.submit", "message": null, "service_name": "checkout-api",
          "span_id": null, "severity": null, "status": "failure", "duration_ms": null
        }
      ],
      "truncated": false
    },
    "evidence": {
      "status": "partial",
      "captured_fields": [
        "correlations.nearby_logs", "correlations.release", "properties.metadata",
        "properties.metadata.plan", "properties.metadata.step", "subject.content_trust",
        "subject.environment", "subject.id", "subject.name", "subject.occurred_at",
        "subject.project_id", "subject.release", "subject.sdk.name", "subject.sdk.version",
        "subject.service_name", "subject.session_captured", "subject.status",
        "subject.subject_classification", "timeline"
      ],
      "missing_fields": ["context", "correlations.trace.trace_id"],
      "redacted_fields": ["subject.distinct_id", "subject.session_id"],
      "truncated_fields": []
    },
    "next_actions": [
      {
        "priority": 1, "code": "inspect_analytics_paths", "target": "analytics_paths",
        "reason": "session_captured", "issue_id": null, "trace_id": null, "span_id": null
      },
      {
        "priority": 2, "code": "improve_capture", "target": "sdk_configuration",
        "reason": "evidence_incomplete", "issue_id": null, "trace_id": null, "span_id": null
      },
      {
        "priority": 3, "code": "compare_release", "target": "release_investigation",
        "reason": "release_identity_available", "issue_id": null, "trace_id": null,
        "span_id": null
      }
    ]
  }
  ```
</Accordion>

| Campo | Significado |
| - | - |
| `subject.status` | `queued`, `running`, `success`, `failure`, o `null` cuando no se capturó ningún estado admitido. |
| `subject.subject_classification` | `user`, `anonymous`, `legacy_unknown`, `missing`, `historical_unindexed` o `unsupported`. |
| `subject.session_captured` | Si la acción tenía una sesión. La respuesta nunca devuelve el ID de sesión. |
| `properties` | El objeto `metadata` acotado de la acción. |
| `analysis.status` | `subject_failure`, `correlated_failure_evidence`, `in_progress`, `success_observed` o `status_not_captured`. |

La respuesta nunca devuelve identificadores de sujeto ni de sesión. El
comprobante de evidencia siempre muestra `subject.distinct_id` como oculto, y
también `subject.session_id` cuando se capturó una sesión. Por eso, todos los
paquetes de acciones son `partial` e incluyen `improve_capture`. No quites los
controles de privacidad para cumplirlo.

### Respuesta de la investigación de una métrica

Usa `GET /api/telemetry/metrics/investigation` para leer un nombre de métrica
de un proyecto en un intervalo de tiempo. La respuesta tiene la serie actual,
una comparación con el intervalo de tiempo anterior de la misma duración, la
última muestra, los ejemplares de traza y los despliegues completados. La
versión 2 añade la descripción de la métrica a partir de la última muestra
conservada. La versión 1 siempre informa de
`description_status: "not_captured"`.

```bash theme={null}
curl --fail-with-body -sS -G \
  "https://api.logbrew.co/api/telemetry/metrics/investigation" \
  -H "Authorization: Bearer $LOGBREW_TOKEN" \
  --data-urlencode "project_id=$PROJECT_ID" \
  --data-urlencode "name=http.server.duration" \
  --data-urlencode "since=2026-08-02T12:00:00Z" \
  --data-urlencode "until=2026-08-03T12:00:00Z" \
  --data-urlencode "interval=5m" \
  --data-urlencode "group_by=service_name" \
  --data-urlencode "environment=production" \
  --data-urlencode "series_limit=12" \
  --data-urlencode "response_version=2"
```

`project_id`, `name` y `since` son obligatorios. `since` es inclusivo y
`until` es exclusivo. De forma predeterminada, `until` es el momento actual.
La comparación también lee el intervalo de tiempo anterior de la misma
duración.

<Accordion title="Ejemplo de investigación de una métrica en la versión 2">
  Este histograma ficticio tiene 5 muestras en dos intervalos de 5 minutos. El
  último intervalo tiene un p95 de 48 ms. El último intervalo del intervalo de
  tiempo anterior tiene un p95 de 24 ms.

  ```json theme={null}
  {
    "schema_version": 2,
    "subject": {
      "kind": "metric", "project_id": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
      "name": "http.server.duration", "description_status": "captured",
      "description": "Duration of one completed server request."
    },
    "query": {
      "project_id": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa", "name": "http.server.duration",
      "since": "2026-08-02T12:00:00Z", "until": "2026-08-03T12:00:00Z", "interval": "5m",
      "interval_seconds": 300, "group_by": "service_name", "environment": "production",
      "series_limit": 12
    },
    "purpose": "Explains one metric's latest application-supplied description and bounded change, compares the immediately preceding equal window, exposes one privacy-bounded latest-sample capture context, exact trace/span exemplars, and nearby completed deployments, and keeps every correlation evidence-only rather than claiming an anomaly or root cause.",
    "content_trust": "untrusted_telemetry",
    "analysis": {
      "status": "change_observed",
      "causality": "evidence_only",
      "focus": {
        "comparison_index": 0, "selection": "largest_absolute_relative_change",
        "direction": "increased", "absolute_change": 24.0, "relative_change_percent": 100.0
      }
    },
    "coverage": {
      "samples": 5, "series": 1, "returned_series": 1, "points": 2,
      "expected_buckets_per_series": 288, "first_seen_at": "2026-08-03T11:00:10Z",
      "last_seen_at": "2026-08-03T11:09:50Z", "truncated": false
    },
    "series": [
      {
        "identity": {
          "kind": "histogram", "unit": "ms", "temporality": "delta",
          "group_by": "service_name", "group_value": "checkout-api"
        },
        "status": "ready",
        "aggregation": {
          "code": "distribution_p95",
          "description": "Primary value is the approximate p95 of raw observations in each bucket; p50, p99, range, average, count, and sum preserve distribution context."
        },
        "sample_count": 5,
        "points": [
          {
            "bucket_start": "2026-08-03T11:00:00Z", "bucket_end": "2026-08-03T11:05:00Z",
            "sample_count": 2, "value": 42.0, "min": 42.0, "max": 42.0, "average": 42.0,
            "sum": 84.0, "p50": 42.0, "p95": 42.0, "p99": 42.0, "trace_exemplars": []
          },
          {
            "bucket_start": "2026-08-03T11:05:00Z",
            "bucket_end": "2026-08-03T11:10:00Z",
            "sample_count": 3,
            "value": 48.0,
            "min": 48.0,
            "max": 48.0,
            "average": 48.0,
            "sum": 144.0,
            "p50": 48.0,
            "p95": 48.0,
            "p99": 48.0,
            "trace_exemplars": ["4bf92f3577b34da6a3ce929d0e0e4736"]
          }
        ]
      }
    ],
    "comparison": {
      "status": "available",
      "method": "adjacent_equal_window_latest_bucket",
      "previous_since": "2026-08-01T12:00:00Z",
      "previous_until": "2026-08-02T12:00:00Z",
      "items": [
        {
          "identity": {
            "kind": "histogram", "unit": "ms", "temporality": "delta",
            "group_by": "service_name", "group_value": "checkout-api"
          },
          "aggregation": "distribution_p95",
          "current": {
            "bucket_start": "2026-08-03T11:05:00Z", "bucket_end": "2026-08-03T11:10:00Z",
            "sample_count": 3, "value": 48.0
          },
          "previous": {
            "bucket_start": "2026-08-02T11:55:00Z", "bucket_end": "2026-08-02T12:00:00Z",
            "sample_count": 2, "value": 24.0
          },
          "direction": "increased",
          "absolute_change": 24.0,
          "relative_change_percent": 100.0
        }
      ],
      "truncated": false,
      "limitation": "Each item compares the latest non-empty semantic bucket in adjacent equal-length windows. It is an observed value change, not seasonality-aware anomaly detection or evidence that a deployment caused the change."
    },
    "latest_sample": {
      "status": "available",
      "sample": {
        "id": "dddddddd-dddd-4ddd-8ddd-dddddddddddd",
        "kind": "histogram",
        "value": 48.0,
        "unit": "ms",
        "temporality": "delta",
        "occurred_at": "2026-08-03T11:09:50Z",
        "service_name": "checkout-api",
        "environment": "production",
        "release": "checkout@1.2.3",
        "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
        "span_id": "00f067aa0ba902b7",
        "sdk": {"name": "@logbrew/node", "version": "0.1.11"},
        "context": null,
        "metadata": {"values": {}, "included_leaf_count": 0, "redacted": false, "truncated": false}
      }
    },
    "exemplars": {
      "status": "available",
      "coverage": {
        "matching_samples": 5, "trace_linked_samples": 1, "span_linked_samples": 1,
        "returned_exemplars": 1
      },
      "items": [
        {
          "id": "dddddddd-dddd-4ddd-8ddd-dddddddddddd",
          "value": 48.0,
          "occurred_at": "2026-08-03T11:09:50Z",
          "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
          "span_id": "00f067aa0ba902b7",
          "service_name": "checkout-api",
          "environment": "production",
          "release": "checkout@1.2.3",
          "sdk": {"name": "@logbrew/node", "version": "0.1.11"}
        }
      ],
      "truncated": false
    },
    "deployments": {
      "status": "available",
      "items": [
        {
          "deployment_id": "deploy-123", "release": "checkout@1.2.3",
          "environment": "production", "service_name": "checkout-api", "status": "succeeded",
          "started_at": "2026-08-03T11:02:00Z", "finished_at": "2026-08-03T11:03:00Z",
          "commit_sha": "0123456789abcdef"
        }
      ],
      "truncated": false
    },
    "timeline": {
      "items": [
        {
          "id": "deploy-123", "kind": "deployment_finished",
          "occurred_at": "2026-08-03T11:03:00Z", "value": null, "trace_id": null,
          "span_id": null, "release": "checkout@1.2.3", "service_name": "checkout-api"
        },
        {
          "id": "dddddddd-dddd-4ddd-8ddd-dddddddddddd", "kind": "metric_exemplar",
          "occurred_at": "2026-08-03T11:09:50Z", "value": 48.0,
          "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736", "span_id": "00f067aa0ba902b7",
          "release": "checkout@1.2.3", "service_name": "checkout-api"
        }
      ],
      "truncated": false
    },
    "evidence": {
      "status": "partial",
      "captured_fields": [
        "metric.current_window_coverage", "metric.deployment_overlays", "metric.description",
        "metric.identity", "metric.latest_sample", "metric.latest_sample.kind",
        "metric.latest_sample.occurred_at", "metric.latest_sample.scope",
        "metric.latest_sample.sdk.name", "metric.latest_sample.sdk.version",
        "metric.latest_sample.span_id", "metric.latest_sample.trace_id",
        "metric.latest_sample.value", "metric.prior_window_comparison", "metric.query_scope",
        "metric.series_semantics", "metric.span_exemplars", "metric.trace_exemplars"
      ],
      "missing_fields": ["metric.latest_sample.context", "metric.latest_sample.metadata"],
      "redacted_fields": [],
      "truncated_fields": []
    },
    "next_actions": [
      {
        "priority": 1,
        "code": "inspect_exact_span",
        "target": "span_investigation",
        "reason": "Inspect the exact span that emitted a retained metric exemplar, then review its failure, latency, log, issue, action, and trace evidence.",
        "context": {
          "project_id": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
          "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736", "span_id": "00f067aa0ba902b7",
          "environment": "production", "release": "checkout@1.2.3",
          "service_name": "checkout-api"
        }
      },
      {
        "priority": 2,
        "code": "review_deployment",
        "target": "release_investigation",
        "reason": "Review release-scoped telemetry for a completed deployment inside the compared evidence window without treating temporal proximity as causality.",
        "context": {
          "project_id": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa", "trace_id": null,
          "span_id": null, "environment": "production", "release": "checkout@1.2.3",
          "service_name": "checkout-api"
        }
      }
    ]
  }
  ```
</Accordion>

| Campo | Significado |
| - | - |
| `subject.description_status` | `captured`, `not_captured` o `unavailable`. |
| `query` | La consulta normalizada. `service_name`, `release` y `environment` aparecen solo si se enviaron. |
| `analysis.status` | `no_samples`, `change_observed`, `no_change_observed`, `baseline_not_found` o `comparison_unavailable`. |
| `analysis.focus` | El elemento de la comparación con el mayor cambio relativo, o con el mayor cambio absoluto cuando no hay cambio relativo. `null` cuando ningún elemento se puede comparar. |
| `series[].aggregation.code` | `gauge_last`, `delta_sum`, `distribution_p95`, `raw_cumulative_last` o `raw_last`. |
| `comparison.status` | `available`, `partial`, `not_found`, `unavailable` o `no_current_samples`. |
| `comparison.items[]` | El último intervalo no vacío de cada intervalo de tiempo para la misma identidad de serie. |
| `latest_sample` | La última muestra sin procesar, con el SDK, `context`, `metadata` y el enlace a la traza. |
| `exemplars` | Muestras sin procesar con un ID de traza. `coverage` cuenta las muestras enlazadas. |
| `deployments` | Despliegues completados desde el inicio del intervalo de tiempo anterior hasta `until`. |
| `next_actions[]` | `code`, `target`, un `reason` en texto simple y un alcance `context` para la siguiente lectura. |

`relative_change_percent` es `(current - previous) / abs(previous) * 100`. Es
`null` cuando el valor anterior es cero o falta.
`expected_buckets_per_series` cuenta los intervalos posibles, no los
intervalos con datos. No dibujes los intervalos vacíos como cero. Un
despliegue cercano a un cambio no demuestra que lo haya causado.

Un proyecto que la cuenta no puede leer devuelve `200 OK` con
`analysis.status: "no_samples"`, no `404`. Un resultado vacío no describe
otros tipos de señales.

Límites de las métricas: el intervalo de tiempo es de 31 días como máximo.
Cada serie tiene como máximo 500 intervalos. `series_limit` va de 1 a 20, con
10 como valor predeterminado. La respuesta devuelve como máximo 20 ejemplares
y 20 despliegues.

| HTTP | `error` | Recuperación |
| - | - | - |
| `422` | `metric investigation response_version must be 1 or 2` | Omite `response_version` o envía `2`. |
| `422` | `metric series project_id is required` | Envía un ID de proyecto legible. |
| `422` | `metric series name is required` | Copia el nombre de la lista de métricas. |
| `422` | `metric series since is required` | Envía un valor como `24h` o una marca de tiempo RFC 3339. |
| `422` | `metric series range must not exceed 31 days` | Usa un intervalo de tiempo más corto. |
| `422` | `metric series interval would exceed 500 buckets` | Usa `interval=auto` o un intervalo más amplio. |
| `422` | `metric series_limit must be between 1 and 20` | Envía un valor de 1 a 20. |

`interval` es `auto`, `1m`, `5m`, `15m`, `1h`, `6h` o `1d`. `group_by` es
`none`, `service_name`, `release` o `environment`. Otros valores devuelven
`422`.

### Errores de investigación

| HTTP | Ruta | `error` |
| - | - | - |
| `404` | Log | `log not found` |
| `404` | Acción | `action not found` |
| `404` | Traza | `trace not found` |
| `422` | Traza | `trace investigation response_version must be 1, 2, or 3` |
| `400` | Log, acción, incidencia | `invalid URL path parameters` cuando el ID de la ruta no es un UUID |
| `422` | Incidencia, traza, span, métrica | `invalid query parameters` para una clave desconocida o un valor de tipo incorrecto |

Un `404` significa que ningún proyecto legible tiene el registro. Cada ruta
también devuelve `401` sin una autenticación válida y `405` con un método
distinto de `GET`. Consulta [Errores de la API](/es/reference/api-errors) para
ver las respuestas de
[recurso no encontrado](/es/reference/api-errors#resource-not-found),
[ruta](/es/reference/api-errors#invalid-path-value),
[autenticación](/es/reference/api-errors#authentication-failure) y
[método](/es/reference/api-errors#unsupported-method).

Una lectura de evidencia opcional puede fallar dentro de una respuesta
`200 OK`. En ese caso, la colección informa de `unavailable`. No lo muestres
como `not_found` ni como cero registros.

## <span id="severity-values">Valores de severidad</span>

Los valores de severidad que ven los usuarios son `info`, `warning`, `error` y
`critical`. Los SDK y los runtimes pueden enviar alias comunes como `trace`,
`debug`, `warn` o `fatal`. Las respuestas REST y en vivo siempre devuelven el
valor canónico. Por ejemplo, LogBrew acepta `warn` como entrada y devuelve
`warning`. La ingesta rechaza los valores de severidad desconocidos.

| Alias | Valor canónico |
| - | - |
| `trace`, `debug` | `info` |
| `warn` | `warning` |
| `fatal` | `critical` |

## <span id="severity-rule-responses">Respuestas de las reglas de severidad</span>

Una regla de severidad cambia cómo muestra LogBrew un log o una incidencia. No
cambia la severidad que capturó la aplicación. Los logs y las incidencias
devuelven un objeto `triage`:

| Campo | Significado |
| - | - |
| `effective_severity` | La severidad que se muestra. Sin una regla, es igual a `severity`. |
| `ignored` | `true` cuando una regla de logs ignora el log o cuando la incidencia está archivada. |
| `rule_applied` | `true` cuando se aplica una regla de severidad o el estado ignorado. `false` es el valor predeterminado, no un dato ausente. |

Usa `triage.effective_severity` para mostrar la severidad. Conserva
`severity` como valor capturado. De forma predeterminada, la lista de logs
omite los logs ignorados. Envía `status=ignored` o `status=all` en
`GET /api/logs` para incluirlos.

La cuenta debe tener permiso para gestionar incidencias en el proyecto. El
acceso de lectura no basta. Sin ese permiso, un cambio de regla devuelve `403`
con `code: forbidden`.

### Cambia una regla de logs

`PUT /api/logs/{log_id}/triage-rule` define la regla del log y de los logs
posteriores con la misma firma. El cuerpo necesita `severity` e `ignored`:

```bash theme={null}
curl --request PUT "https://api.logbrew.co/api/logs/$LOG_ID/triage-rule" \
  --header "Authorization: Bearer $LOGBREW_ACCOUNT_BEARER" \
  --header "Content-Type: application/json" \
  --data '{ "severity": "info", "ignored": true }'
```

Una respuesta `200 OK` contiene el [log](#log-response) completo. Su
`severity` sigue siendo `warning`. Su `triage` muestra la regla:

```json theme={null}
{
  "severity": "warning",
  "triage": {
    "effective_severity": "info",
    "ignored": true,
    "rule_applied": true
  }
}
```

Este extracto muestra solo los campos que cambian. En la solicitud,
`severity` es `source`, `info`, `warning`, `error` o `critical`. `source`
restaura la severidad capturada. No vuelve activo un log ignorado. Para volver
a mostrar el log, envía `"ignored": false`.

### Cambia una regla de incidencias

`PUT /api/telemetry/issues/{issue_id}/triage-rule` define la severidad que se
muestra para una incidencia agrupada y sus ocurrencias posteriores. El cuerpo
solo acepta `severity`:

```bash theme={null}
curl --request PUT "https://api.logbrew.co/api/telemetry/issues/$ISSUE_ID/triage-rule" \
  --header "Authorization: Bearer $LOGBREW_ACCOUNT_BEARER" \
  --header "Content-Type: application/json" \
  --data '{ "severity": "warning" }'
```

Una respuesta `200 OK` contiene la [incidencia](#issue-response) completa en
la versión 1. Los valores capturados de `severity` y `status` no cambian:

```json theme={null}
{
  "severity": "error",
  "status": "unresolved",
  "triage": {
    "effective_severity": "warning",
    "ignored": false,
    "rule_applied": true
  }
}
```

Este extracto muestra solo algunos campos. Una regla no resuelve, archiva ni
reabre una incidencia. Para eso, usa el
[cambio de estado](#issue-status-response-examples). Una prioridad derivada
sigue la nueva severidad efectiva. Lee la incidencia con
`response_version=2` o `3` para verla.

Una severidad no admitida devuelve `422`:

```json theme={null}
{
  "error": "triage severity must be source, info, warning, error, or critical",
  "code": "validation_failed",
  "next": "use source to restore captured severity, or choose info, warning, error, or critical",
  "next_action": {
    "code": "fix_request",
    "target": "request"
  }
}
```

Un campo desconocido en el cuerpo, como `status` en una regla de incidencias,
devuelve `422` con `code: invalid_json`. Un log o una incidencia ausente o
ilegible devuelve `404` con `code: not_found`. Si se pierde la respuesta,
vuelve a leer el log o la incidencia antes de enviar de nuevo la regla.

## Formato de respuesta de error

Los errores de la aplicación devuelven un sobre JSON. Este ejemplo muestra una
solicitud rechazada. El texto de `error` y de `next` depende del problema:

```json theme={null}
{
  "error": "<what is wrong>",
  "code": "validation_failed",
  "next": "<how to fix it>",
  "next_action": {
    "code": "fix_request",
    "target": "request"
  }
}
```

Usa `code` para las ramas del programa y `next_action` para la automatización.
Muestra `error` y `next` a las personas como texto simple. No analices su
redacción. Algunos errores añaden campos, como `limit`, `reset_at` o
`retry_after_seconds`. Una respuesta sin cuerpo JSON no tiene `code` de
LogBrew. Consulta [Errores de la API](/es/reference/api-errors) para ver todos
los códigos.

## Lee datos con la CLI

La CLI lee las mismas rutas y devuelve el mismo JSON con `--json`. Empieza con
una consulta amplia y luego acótala:

```bash theme={null}
logbrew read releases --environment production --json
logbrew read issues --release api@1.2.3 --status unresolved --json
logbrew read logs --release api@1.2.3 --since 24h --json
logbrew read actions --name checkout_failed --since 24h --json
logbrew read traces --status error --since 24h --json
logbrew read trace <trace_id> --json
```

Añade `--pagination cursor` para obtener el sobre con cursor. La CLI solicita
la versión 4 de la respuesta de incidencias. Consulta
[Lee la página siguiente](/es/reference/cli#read-the-next-page) y
[Observación en vivo](/es/reference/cli#live-watch).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.