> ## 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.

# API-responseformaat en voorbeelden van JSON-responses

> Lees API-responses van LogBrew voor telemetrielijsten, cursorpagina's, live-events, wijzigingen, successtatussen en foutstatussen.

Deze pagina toont één voorbeeld voor elk type response van de
[Telemetrie-API](/nl/reference/telemetry-api). Alle waarden zijn fictief. Zie
[API-fouten](/nl/reference/api-errors) voor foutcodes en herstel.

## Een response lezen

Lees elke response in deze volgorde:

1. Lees de HTTP-status.
2. Controleer of de body de vorm heeft die bij de route hoort.
3. Controleer of elk `project_id` binnen de gevraagde projectscope valt.
4. Laat canonieke enumwaarden en ID's ongewijzigd.
5. Volg `next_action` alleen als de client de bijbehorende `code` en
   `target` ondersteunt.
6. Behandel `null`, een weggelaten veld en een lege lijst als verschillende
   toestanden.

Een `200 OK` kan een lege lijst bevatten. Een lege loglijst betekent dat geen
enkele log bij het request paste. Dat betekent niet dat issues, traces of
acties ook leeg zijn. Koppel signalen niet omdat hun tijdstempels dicht bij
elkaar liggen. Volg een trace alleen als de response het exacte `trace_id`
ervan bevat.

Een `404` en een lege lijst zijn verschillende resultaten. Een lijstroute geeft
`[]` terug als geen enkel record overeenkomt. Een detailroute geeft `404` met
`code: not_found` terug als die geen leesbaar record vindt. Geen van beide
resultaten bewijst dat de opname is mislukt.

## Wat je verstuurt

Een response is maar zo nuttig als de telemetrie die je verstuurt. Stuur deze
waarden mee in elke envelop of SDK-installatie:

* `release` en `environment`.
* Vaste namen voor services, acties en metrics.
* Tracecontext als logs, spans, acties en issues bij hetzelfde request horen.
* Canonieke ernstwaarden: `info`, `warning`, `error` en `critical`.
* Attributen die helpen bij debuggen, zonder geheimen of onnodige
  persoonsgegevens.

Zie [SDK-integratie](/nl/guides/sdk-ingestion) en
[Vastgelegde gegevens beheren](/nl/guides/safe-capture).

## Response van de ingest-API

De openbare SDK's lezen de response van `POST /v1/events` voor je. Je
applicatiecode hoeft die niet af te handelen.

### Response op een SDK-batch

Een geslaagde SDK-batch geeft `200 OK` terug met de geaccepteerde aantallen per
stroom:

```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"
  }
}
```

| Veld | Betekenis |
| - | - |
| `issues`, `logs`, `trace_spans`, `actions`, `metrics` | Events uit deze batch die LogBrew heeft geaccepteerd. |
| `already_accepted` | Events waarvan LogBrew het ID eerder al accepteerde. LogBrew slaat ze niet opnieuw op. |
| `context_updated` | `true` als de batch de release- of omgevingscontext heeft bijgewerkt. |

De aantallen gelden alleen voor deze batch. Stuur je een batch opnieuw die
LogBrew al accepteerde, dan krijg je `0` voor elke stroom en het aantal events
in `already_accepted`. Houd de oorspronkelijke event-ID's aan als je het
opnieuw probeert.

### Response op een native envelop

`POST /api/telemetry/ingest` geeft `200 OK` terug met het aantal geaccepteerde
items per stroom:

```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"
  }
}
```

De native response heeft geen veld `metrics` of `context_updated`. Voeg ze niet
toe. `already_accepted` telt items waarvan LogBrew de `id` eerder al voor het
project accepteerde. Zie de [directe native envelop](/nl/guides/sdk-ingestion#required-envelope-fields).

### Opnamefouten

Een `401` met `code: ingest_key_invalid` betekent dat de ingest-bearer is
ingetrokken, verlopen of niet geldig is voor het project. Op
`POST /v1/events` geeft een ontbrekende bearer, of een bearer die geen
ingest-sleutel is, `401` met `code: unauthorized`. Gebruik de huidige
projectgebonden ingest-bearer. Probeer het niet opnieuw met een
account-bearer.

Een geweigerde SDK-batch geeft `422` met `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"
  }
}
```

Andere waarden van `error` zijn onder meer
`SDK event batch requires at least one event` en
`SDK event type is not supported by this ingest route`. Controleer de
SDK-versie en de transportconfiguratie. Stuur geen lege batch. Wijzig geen
eventtypes of ID's alleen om een batch door de validatie te krijgen.

Een request met een andere methode dan `POST` geeft `405` met
`code: method_not_allowed`. Een onleesbare JSON-body geeft `code: invalid_json`.

## Responseformaat van telemetrielijsten

Lijstroutes geven standaard een gewone JSON-array terug. Een geslaagde lege lijst
is `[]`.

Met `pagination=cursor` geeft de route een envelop terug. De collectiesleutel
hoort bij het signaal:

| Route | Collectiesleutel |
| - | - |
| `/api/logs` | `logs` |
| `/api/telemetry/issues` | `issues` |
| `/api/telemetry/issues/{issue_id}/events` | `events`, met een `issue_id` op het hoogste niveau |
| `/api/telemetry/actions` | `actions` |
| `/api/telemetry/metrics` | `metrics` |
| `/api/telemetry/releases` | `releases` |
| `/api/telemetry/traces` | `traces`, met een `naming_quality` op het hoogste niveau |

`next_cursor` is een object met de velden om verder te lezen, of `null` op de
laatste pagina. Rijen staan van nieuw naar oud. Zie [cursorpaginering](/nl/reference/telemetry-api-filters#cursor-pagination).

### <span id="log-response">Logresponse</span>

Een cursorpagina met logs en `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"
  }
}
```

Logs bevatten `level` voor compatibiliteit en `severity` voor weergave. Beide
bevatten de canonieke waarde. `triage` bevat het resultaat van een ernstregel.
Zie [responses van ernstregels](#severity-rule-responses).

`trace_id` en `span_id` zijn `null` als de log geen tracekoppeling heeft. Dan
is `next_action` gelijk aan `inspect_related_logs` met als doel
`telemetry_logs`. Logs, issues en acties gebruiken dezelfde 2 paren voor
`next_action`.

`GET /api/logs/{log_id}` geeft één log terug in dezelfde vorm.

### <span id="issue-response">Issueresponse</span>

`GET /api/telemetry/issues/{issue_id}` geeft één gegroepeerd issue terug. De
lijst geeft dezelfde objecten terug. Dit voorbeeld gebruikt de
standaardversie 1 van de response:

```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"
}
```

In versie 1 is `status` gelijk aan `unresolved`, `resolved` of `ignored`. Voor
een gearchiveerd issue is `triage.ignored` gelijk aan `true`. Zie
[Een issue onderzoeken](/nl/guides/investigate-an-issue) voor de paren van
`next_action` en de leesacties die erop volgen.

`first_seen_at` en `last_seen_at` zijn de tijdstippen van het eerste en het
meest recente voorval. Ze veranderen niet als de status verandert.

Sommige velden verschijnen alleen als LogBrew de gegevens heeft:

| Veld | Wanneer het verschijnt |
| - | - |
| `span_id` | Het issue heeft een spankoppeling. Anders laat de response het veld weg. |
| `diagnostics` | Het laatste voorval heeft een exceptiontype of breadcrumbs. Zie [voorvalgeschiedenis van een issue](#issue-occurrence-history). |
| `symbolication` | Alleen op `GET /api/telemetry/issues/{issue_id}`, als het issue de identiteit van een release-artefact heeft. Zie [Source maps voor JavaScript](/nl/guides/source-maps). |

`symbolication.status` is `resolved`, `invalid_metadata`,
`artifact_not_found`, `source_not_resolved` of `unavailable`. De lijst,
statuswijzigingen en regelwijzigingen geven geen `symbolication` terug.

Met `response_version=2` heeft het issue dezelfde velden, met deze wijzigingen:

| Veld | Waarde in versie 2 |
| - | - |
| `status` | `unresolved`, `resolved` of `archived`. Versie 1 toont `archived` als `ignored`. |
| `priority` | `high`, `medium` of `low`. |
| `priority_source` | `manual` als iemand de prioriteit heeft ingesteld. `derived` als de prioriteit de effectieve ernst volgt. |

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

Dit voorbeeld toont maar een deel van de velden. Een afgeleide prioriteit is
`high` voor `error` en `critical`, `medium` voor `warning` en `low` voor
`info`. Die prioriteit gebruikt `triage.effective_severity`, dus een ernstregel
voor het issue kan die veranderen.

Met `response_version=3` heeft het issue alle velden van versie 2 en
`assignee`. `assignee` is `null` als het issue aan niemand is toegewezen:

```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"
  }
}
```

| Veld | Betekenis |
| - | - |
| `assignee.user_id` | Gebruikers-ID van het toegewezen account. Stuur het als `assignee` in een filter of een wijziging. |
| `assignee.name` | Naam van dat account, of `null` als het account geen naam heeft. |
| `assignee.email` | E-mailadres van dat account. |

Een issue toont geen toewijzing als het toegewezen lid het project niet meer
kan lezen.

Met `response_version=4` heeft `assignee` ook `type`. Een toewijzing aan een
account (`user`) heeft `user_id`, `name` en `email`, zoals in versie 3. Een
toewijzing aan een team (`team`) heeft `team_id`, `slug` en `name`. Versie 3
toont een toewijzing aan een team als `null`. De CLI vraagt versie 4 op:

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

Elke andere `response_version` geeft `422` met `code: validation_failed`. Een
cursorpagina gebruikt dezelfde versie voor elk issue in `issues`.

### <span id="assignee-list-response">Response met toewijsbare accounts en teams</span>

`GET /api/telemetry/issues/assignees?project_id=<project_id>` geeft elk account
terug waaraan je issues in het project kunt toewijzen:

```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"
    }
  ]
}
```

Voeg `response_version=2` toe om ook `teams` te krijgen: elk team van de
organisatie van het project, met `team_id`, `slug` en `name`.

Als het account het project niet kan lezen, geeft de route `404` met
`code: not_found`.

### <span id="action-response">Actieresponse</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` volgt één actor of sessie. Behandel `distinct_id` en
`session_id` als ondoorzichtige ID's. `session_id` en `trace_id` zijn `null`
als ze ontbreken. `span_id` ontbreekt als er geen waarde is. Een actie heeft
geen ernst. Zie [Productevents vastleggen](/nl/guides/product-events).

### Metricresponse

```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"
}
```

Elk item is één meting. Gebruik het aantal metingen niet als aantal events of
gebruikers. `unit`, `temporality`, `trace_id` en `span_id` zijn `null` als ze
ontbreken. Een waarde `null` is geen nul.

### Releaseresponse

```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"
  }
}
```

Eén rij gaat over één project, release, omgeving en service. De aantallen
beschrijven alleen die rij.

`trace_health.status` is `unknown` als de rij geen traces heeft, en anders
`no_errors_observed` of `errors_observed`. `error_rate_basis_points` is het
aandeel traces met een foutspan, van `0` tot `10000`. Het is geen
foutpercentage voor alle requests.

`next_action` wijst naar het eerste signaaltype met gegevens, in deze volgorde:

| `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` |

Zie [Releases](/nl/concepts/releases).

### Response bij het zoeken naar traces

`GET /api/telemetry/traces?pagination=cursor` geeft één rij per trace terug,
plus een overzicht in `naming_quality` voor de teruggegeven pagina:

```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` gaat alleen over de teruggegeven pagina. Het is geen score
voor het hele account. `truncated: true` betekent dat er nog een pagina is. Als
de pagina een generieke naam, een niet-herkende route of een generieke bewerking
bevat, is `next_action` gelijk aan `improve_trace_naming` met als doel
`sdk_configuration`. Zonder `pagination=cursor` geeft de route een gewone array
van traces terug, zonder `naming_quality`.

`next_cursor` bevat `time` en `trace_id`. Stuur ze als `cursor_time` en
`cursor_trace_id`.

`GET /api/telemetry/traces/{trace_id}` geeft de spans van één trace terug.
`GET /api/telemetry/traces/{trace_id}/summary` geeft de rootspan, de foutspans,
de services, de duur en het traagste pad terug, zonder ruwe spanattributen.
Een `404` op de samenvatting betekent dat geen enkele trace bij de volledige
scope paste. Probeer het niet opnieuw zonder de filters. Zie [responses voor trace-spans en samenvattingen](#trace-spans-and-summary-responses).

### Lege lijsten en ontbrekende records

Een lijst lezen kan nul resultaten opleveren. Voor het lezen van één record
geldt een ander contract:

| Request | Gelukt | Geen leesbaar record |
| - | - | - |
| `GET /api/logs/{log_id}` | `200` met één [log](#log-response) | `404` met `code: not_found` |
| `GET /api/telemetry/issues/{issue_id}` | `200` met één [issue](#issue-response) | `404` met `code: not_found` |
| `GET /api/telemetry/issues/{issue_id}/events` | `200` met voorvallen | `404` met `code: not_found` op de eerste pagina |
| `GET /api/telemetry/traces/{trace_id}` | `200` met spans | `200` met `[]` |
| `GET /api/telemetry/traces/{trace_id}/summary` | `200` met één samenvatting | `404` met `code: not_found` |

Een ontbrekende log geeft deze `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"
  }
}
```

Een ontbrekend issue gebruikt `"error": "issue not found"`. Een ontbrekende
tracesamenvatting gebruikt `"error": "trace not found"`. Een onbekend ID en een
ID dat het account niet kan lezen, geven dezelfde response.

Een lijstrequest met één `project_id` dat het account niet kan lezen, geeft
`200` met een lege lijst. Controleer het project-ID voordat je meldt dat er geen
gegevens zijn.

### Geweigerde projectselecties

De lijsten voor logs, issues, acties, metrics, releases en traces accepteren
één project met `project_id` of 2 tot 50 projecten met `project_ids`. De
catalogus met logattributen accepteert dezelfde selectors. De
voorvalgeschiedenis van een issue accepteert ze niet.

Een request met zowel `project_id` als `project_ids` geeft `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` met een ongeldige UUID, een dubbel ID, of minder dan 2 of meer
dan 50 ID's geeft ook `422` met `code: validation_failed`.

Als het account één project in een set `project_ids` niet kan lezen, geeft het
hele request `404`. Het geeft de andere projecten niet terug als gedeeltelijk
resultaat:

```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"
  }
}
```

Toon de fout, geen lege lijst of een aantal van nul. Lees de projectlijst
opnieuw. Verwijder niet stilletjes een project en probeer het niet opnieuw over
alle projecten. Gedelegeerde toegangsgegevens, zoals een MCP-verbinding, geven
`403` met `code: forbidden` voor een project buiten die verbinding. Zie
[projectscope](/nl/reference/telemetry-api-filters#project-scope).

### <span id="cursor-errors">Cursorfouten</span>

Logs, issues, acties, metrics en voorvallen van issues gebruiken `cursor_time`
en `cursor_id`. Een geweigerde cursor geeft `422` met
`code: validation_failed`. Deze fouten betekenen niet dat de lijst leeg is.

| Request | `error` |
| - | - |
| `pagination=cursor` met maar 1 van de 2 cursorvelden | `cursor_time and cursor_id must be sent together` |
| `cursor_time` dat geen RFC3339-tijdstempel is | `cursor_time must be an RFC3339 timestamp` |
| Cursorvelden zonder `pagination=cursor`, of een andere waarde voor `pagination` | `pagination must be cursor when cursor pagination is requested` |

Bijvoorbeeld:

```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"
  }
}
```

Kopieer de volledige `next_cursor` van de vorige pagina. Vervang `cursor_time`
niet door de huidige tijd. Ben je de cursor kwijt? Begin dan opnieuw met
`pagination=cursor` en de oorspronkelijke filters. Een onbekende queryparameter
of een waarde van het verkeerde type geeft `422` met
`"error": "invalid query parameters"`.

### Responses van de releasecursor

Een releasecursor heeft 5 velden. Een geslaagd request zonder resultaten geeft
`200`:

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

Als `next_cursor` niet `null` is, stuur je alle 5 waarden mee met het volgende
request:

| Veld in `next_cursor` | Queryparameter |
| - | - |
| `time` | `cursor_time` |
| `project_id` | `cursor_project_id` |
| `release` | `cursor_release` |
| `environment` | `cursor_environment` |
| `service_name` | `cursor_service_name` |

`cursor_project_id` markeert een positie. Het vervangt `project_id` of
`project_ids` niet. Houd de oorspronkelijke project- en filterparameters aan.
URL-codeer elke waarde.

Met `pagination=cursor` geeft een onvolledige cursor, of een lege waarde voor
release, omgeving of service, `422` met
`"error": "all release cursor fields must be sent together"`. Een ongeldige
`cursor_time` en een ontbrekende `pagination=cursor` geven dezelfde fouten als
de [andere cursors](#cursor-errors).

### Fouten bij het zoeken naar traces

Deze fouten gelden voor `GET /api/telemetry/traces`. Elke fout geeft `422` met
`code: validation_failed`. Een geweigerd request is geen leeg resultaat.

| Request | `error` |
| - | - |
| `status` anders dan `error` of `ok` | `trace status must be error or ok` |
| `min_duration_ms` onder `0` | `minimum trace duration must not be negative` |
| Maar 1 cursorveld, of een lege `cursor_trace_id` | `cursor_time and cursor_trace_id must be sent together` |
| `cursor_time` dat geen RFC3339-tijdstempel is | `cursor_time must be an RFC3339 timestamp` |
| Cursorvelden zonder `pagination=cursor` | `pagination must be cursor when cursor pagination is requested` |

Laat `status` weg om beide tracestatussen mee te nemen. Kopieer voor de
volgende pagina `next_cursor.time` naar `cursor_time` en `next_cursor.trace_id`
naar `cursor_trace_id`. Stuur geen `cursor_id` voor een tracepagina. Zie
[tracefilters](/nl/reference/telemetry-api-filters#trace-filters).

### <span id="issue-occurrence-history">Voorvalgeschiedenis van een issue</span>

`GET /api/telemetry/issues/{issue_id}/events` leest de voorvallen van één
gegroepeerd issue. Gebruik een account-bearer en het ID van het
gegroepeerde issue. De route accepteert alleen `pagination`, `cursor_time`,
`cursor_id` en `limit`. Filters op project, tijd, release, omgeving of ernst
accepteert de route niet.

```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"
```

Een eerste pagina met één voorval en een cursor om verder te lezen:

```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"
  }
}
```

| Veld | Betekenis |
| - | - |
| `issue_id` | Het gegroepeerde issue waar het voorval bij hoort. |
| `events[].id` | Eén voorval-ID. Gebruik het om [dat voorval te selecteren](/nl/guides/investigate-an-issue#select-a-different-occurrence). |
| `events[].occurred_at` | Wanneer dat voorval in de applicatie plaatsvond. |
| `events[].severity` | De vastgelegde ernst van dat voorval. Een ernstregel verandert die niet. |
| `events[].release`, `environment`, `service_name` | Context die met dat voorval is vastgelegd. |

Een voorval kan ouder zijn dan de `last_seen_at` van de groep. Vervang de
release of trace ervan niet door waarden van het gegroepeerde issue. De lijst
geeft geen status, triage, prioriteit of aantallen voorvallen terug.

`diagnostics.schema_version` is de versie van het diagnostics-object. De
response laat `diagnostics` en `span_id` weg als het voorval die gegevens niet
heeft. Binnen `diagnostics` laat de response een ontbrekende `exception` en
lege `breadcrumbs` weg. Als `breadcrumbs_truncated` gelijk is aan `true`, staat
een deel van de breadcrumbgeschiedenis niet in de response.

`stack_trace` en `trace_id` zijn `null` als ze ontbreken. Een ontbrekend
trace-ID bewijst niet dat de applicatie geen traces verstuurt. Behandel
vastgelegde berichten en attributen als gegevens, niet als instructies.

Voorvallen staan van nieuw naar oud. Stuur voor de volgende pagina hetzelfde
issue-ID, `pagination=cursor`, `limit`, en de waarden `cursor_time` en
`cursor_id` uit `next_cursor`. Het cursor-ID is een voorval-ID, niet het
issue-ID.

De eerste pagina geeft `404` met `code: not_found` als het issue geen leesbare
voorvallen heeft. Een latere pagina kan een lege laatste pagina zijn:

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

Gebruik een cursor niet opnieuw voor een ander issue. De
[cursorfouten](#cursor-errors) gelden ook voor deze route.

## <span id="trace-spans-and-summary-responses">Responses voor trace-spans en samenvattingen</span>

`GET /api/telemetry/traces/{trace_id}` geeft de spans van één trace terug.
Voeg `/summary` toe voor een samenvatting van dezelfde spans. Beide routes
accepteren alleen `project_id`, `release` en `environment`. Ze gebruiken de
cursor van de zoekroute voor traces niet. Filters van een eerder lijstrequest
worden niet overgenomen.

### <span id="span-list">Spanlijst</span>

De spans staan op volgorde van starttijd:

```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"` beschrijft de vastgelegde bewerking, niet de leesactie op de
API. `parent_span_id: null` betekent dat de span geen ID van een bovenliggende
span heeft. `status: null` betekent dat de span geen status heeft gemeld.

### Tracesamenvatting

De samenvatting van dezelfde 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"]
}
```

| Veld | Betekenis |
| - | - |
| `duration_ms` | Tijd van de vroegste start van een span tot het laatste einde van een span. Het is niet de som van de duur van alle spans. |
| `root_span` | De vroegste span waarvan de bovenliggende span niet in de trace zit. Het is een startpunt, geen bewezen oorzaak. |
| `slowest_child_span` | De langste span met een ID van een bovenliggende span, of `null`. |
| `slowest_path` | De bekende keten van bovenliggende spans van de root tot `slowest_child_span`. Het is `[]` als `slowest_child_span` gelijk is aan `null`. |
| `error_spans` | De langste foutspans, hoogstens 5. `error_span_count` kan groter zijn. |

Geen van beide routes geeft een cursor of een afkapveld terug. Voeg geen
waarde `truncated` toe die niet in de response staat.

### Geen overeenkomende spans

Als geen enkele span bij het trace-ID en de scope past, geeft de spanlijst
`200` met `[]`. De samenvatting geeft `404` met `"error": "trace not found"` en
`code: not_found`. Controleer het trace-ID en de scope. Verwijder de filters
niet om toch een resultaat te krijgen. Geen van beide resultaten bewijst dat de
applicatie geen telemetrie heeft verstuurd.

## <span id="live-event-response-format">Responseformaat van live-events</span>

De livefeed stuurt nieuwe events. Events die de client miste toen de
verbinding weg was, stuurt de feed niet opnieuw. Gebruik de lijstroutes om
bestaande records te lezen.

### Een ticket aanmaken

Stuur `POST /api/feed/ticket` met een account-bearer. Het request
heeft geen body.

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

Een response `200 OK` bevat het ticket in het veld `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"
  }
}
```

Het ticket is een toegangsbewijs dat snel verloopt. Log het niet en zet het
niet in een prompt voor een agent. Open de verbinding voordat
`expires_in_seconds` voorbij is. De vervaltijd bepaalt wanneer de verbinding
kan starten, niet hoe lang die openblijft.

Een `401` betekent dat de inlogsessie van het account niet geldig is. Log
opnieuw in voordat je een ticket aanvraagt. Een andere methode dan `POST` geeft
`405` met `code: method_not_allowed`.

### De verbinding openen

Verbind een WebSocket-client met
`wss://api.logbrew.co/api/feed/live?ticket=<feed-ticket>`. URL-codeer het
ticket. Zet geen account-bearer en geen ingest-bearer in de URL. Een `401`
betekent dat het ticket of de inlogsessie van het account niet geldig is. Maak een nieuw ticket aan nadat je opnieuw bent ingelogd.

| Response | Oorzaak | Volgende stap |
| - | - | - |
| `422` met `"error": "feed ticket is required"` | De querywaarde `ticket` ontbreekt of is leeg. | Maak een ticket aan en verbind daarmee. |
| `401` met `code: unauthorized` | Het ticket is verlopen of niet geldig. | Maak een nieuw ticket aan. Probeer hetzelfde ticket niet opnieuw. |
| `code: invalid_websocket_upgrade` | Het request is geen geldige WebSocket-upgrade. | Gebruik een WebSocket-client. |
| `405` met `code: method_not_allowed` | Het request gebruikt geen `GET`. | Gebruik `GET` voor de verbinding. |

Wacht na een fout voordat je opnieuw verbindt. Verbind niet opnieuw in een
snelle lus.

### De berichten lezen

Elk bericht is een envelop `{ "type": "...", "data": ... }`. Lees `type`
voordat je `data` parset. Sla types over die de client niet ondersteunt.

| Eventtype | Payload |
| - | - |
| `native_log` | Loggegevens, in de vorm van de [logresponse](#log-response). |
| `native_issue` | Gegevens van een gegroepeerd issue, in de vorm van versie 1 van de [issueresponse](#issue-response). |
| `native_trace_span` | Eén span, in de vorm van een item uit de [spanlijst](#span-list). |
| `native_action` | Gegevens van een productactie, in de vorm van de [actieresponse](#action-response). |
| `project_created`, `project_updated`, `project_catalog_changed` | Projectgegevens. Lees de projectlijst opnieuw als die verandert. |
| `usage_updated`, `usage_limit_warning`, `usage_limit_blocked` | Accountgebruik, in de vorm van [accountgebruik](/nl/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"
    }
  }
}
```

Een event `native_issue` gebruikt versie 1 van de issueresponse: een
gearchiveerd issue toont `ignored`, en het event heeft geen prioriteit. Metrics
en releases zijn geen live-eventtypes. Lees ze via hun lijstroutes. Het ticket
selecteert geen project. Controleer de `project_id` van elk event voordat je
het in een projectweergave toont. `logbrew watch --json` gebruikt deze feed.
Zie de [CLI-referentie](/nl/reference/cli).

### Een gesloten verbinding afhandelen

| Sluitcode | Reden | Volgende stap |
| - | - | - |
| `1013` | `live feed fell behind; reconnect to resync` | Wacht en verbind daarna opnieuw met een nieuw ticket. Lees de lijstroutes opnieuw om de gemiste records op te halen. |
| `1008` | `live feed access changed; sign in again` | Stop met opnieuw verbinden. Log opnieuw in voordat je een nieuw ticket aanmaakt. |

Bij andere verbroken verbindingen geeft LogBrew soms geen reden. Lees na het
opnieuw verbinden de lijstroutes opnieuw en koppel records op ID.

## <span id="issue-status-response-examples">Responsevoorbeelden voor de issuestatus</span>

`PATCH /api/telemetry/issues/{issue_id}` met `{ "status": "resolved" }` geeft
`200 OK` terug met het bijgewerkte gegroepeerde issue, in dezelfde vorm
als de [issueresponse](#issue-response). De queryparameter `response_version`
kiest de versie. De route geeft geen succesvlag terug.

De body stelt 1 of meer van `status`, `priority` en `assignee` in. `status`
accepteert `unresolved`, `resolved` of `archived`. `ignored` is een oudere naam
voor `archived`. Zie [Eén issue bijwerken](/nl/reference/telemetry-api#update-one-issue).

Controleer de teruggegeven `id`, `status` en `priority` voordat je toont dat
het gelukt is. Bouw het resultaat niet op uit de verstuurde waarden. Een
statuswijziging verwijdert geen voorvallen en verandert `first_seen_at` en
`last_seen_at` niet. Ze verandert ook `severity` of een ernstregel niet.

Een geweigerde wijziging geeft `422` met `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"
  }
}
```

| Resultaat | Oorzaak |
| - | - |
| `422`, `issue update requires status, priority, or assignee` | De body heeft geen van de 3 velden. |
| `422`, `issue priority must be high, medium, or low` | De waarde voor de prioriteit wordt niet ondersteund. |
| `422`, `issue assignee must be me, none, a user ID, or team:<team_id>` | De waarde voor `assignee` wordt niet ondersteund. |
| `422`, `issue assignee cannot read this project` | Het toegewezen account heeft geen toegang tot het project. LogBrew wijzigt niets. |
| `422`, `issue assignee team is not a team of this project's organization` | Het team hoort niet bij de organisatie van het project. LogBrew wijzigt niets. |
| `403` met `code: forbidden` | Het account kan geen issues beheren in het project. |
| `404` met `code: not_found` | Het account kan het issue niet lezen, of het issue bestaat niet. |

Een veld dat al de gevraagde waarde heeft, verandert niet. Stuur na een
time-out of een verloren response hetzelfde request opnieuw, of lees eerst het
issue. Stuur geen andere wijziging voordat je de huidige toestand hebt gelezen.
Zie [Schrijfacties](/nl/reference/api-errors#writes).

`POST /api/telemetry/issues/bulk` geeft `200 OK` terug met 1 resultaat per
gevraagd issue-ID, in de volgorde van het request. Elk gevonden issue gebruikt
de vorm van versie 3. Een resultaat `not_found` heeft `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
    }
  ]
}
```

Dit voorbeeld toont maar een deel van de issuevelden. `outcome` is `updated`,
`unchanged` of `not_found`. Een herhaald request geeft `unchanged` en wijzigt
niets. Zie
[Issues in bulk bijwerken](/nl/reference/telemetry-api#update-issues-in-bulk).

Een bulkrequest mislukt in deze gevallen in zijn geheel:

| Resultaat | Oorzaak |
| - | - |
| `422`, `issue_ids must name 1 to 100 issues` | De lijst is leeg of heeft meer dan 100 ID's. |
| `422`, `issue_ids must not contain duplicates` | Een ID komt vaker dan één keer voor. |
| `422` met `code: invalid_json` | De body heeft een onbekend veld. |
| `403` met `code: forbidden` | Het account kan geen issues beheren in het project. |
| `404`, `project not found` | Het account kan het project niet lezen. |

## Scope van analyserequests

De analyseroutes, de route voor metric-tijdreeksen en de route voor
signaalvolume lezen één project en één tijdsbereik. Elk request heeft
`project_id` en `since` nodig. `since` accepteert een korte duur zoals `24h` of
`7d`, of een RFC3339-tijdstempel. `until` accepteert een RFC3339-tijdstempel en
is standaard het tijdstip van het request. Het bereik bevat `since`, bevat
`until` niet en mag niet langer zijn dan 31 dagen.

`service_name`, `release` en `environment` zijn optionele exacte filters. Elke
waarde moet 1 tot 256 tekens hebben nadat LogBrew de spaties aan begin en eind
heeft verwijderd. De route voor segmentvergelijking zet deze filters in elk
segment, niet op het hoogste niveau.

Als het account het project niet kan lezen, geven deze routes `200 OK` met
aantallen van nul. Ze geven geen `404`. Een leeg resultaat bevestigt dus niet
dat je toegang hebt tot het project. Vergelijk `project_id` met de projecten
die het account kan lezen. Een request via een MCP-verbinding die het project
niet bevat, geeft `403` en `forbidden`.

| Route | Waarden voor `response_version` | Standaard |
| - | - | - |
| `GET /api/telemetry/analytics/overview` | `1`, `2` of `3` | `1` |
| `GET /api/telemetry/analytics/properties` | `1` of `2` | `1` |
| `POST /api/telemetry/analytics/segments/compare` | `1` of `2` | `1` |
| `POST /api/telemetry/analytics/retention` | `1` of `2` | `1` |
| `POST /api/telemetry/analytics/lifecycle` | `1` of `2` | `1` |
| `POST /api/telemetry/analytics/funnel` | Niet geaccepteerd | Schema `1` |
| `POST /api/telemetry/analytics/paths` | Niet geaccepteerd | Schema `1` |
| `GET /api/telemetry/metrics/series` | Niet geaccepteerd | Schema `1` |
| `GET /api/telemetry/summary/volume` | `1` | `1` |

Elke response begint met `schema_version`, `query` en `purpose`. `query`
herhaalt de effectieve scope. Een filter dat je niet hebt gestuurd, staat er
niet in. `purpose` is platte tekst die uitlegt op welke vraag de route antwoord
geeft.

Een ratio ontbreekt als de noemer nul is. Een weggelaten ratio is niet `0` en
niet `null`. Lees `coverage` voordat je op een ratio vertrouwt.

### <span id="shared-scope-errors">Gedeelde scopefouten</span>

Deze fouten gebruiken HTTP `422` en `validation_failed`:

| Oorzaak | `error` |
| - | - |
| Geen `project_id` | `product analytics project_id is required` |
| Geen `since` | `product analytics since is required` |
| `since` is geen duur of RFC3339-tijdstempel | `invalid since value` |
| `until` is geen RFC3339-tijdstempel | `product analytics until must be an RFC3339 timestamp` |
| `since` ligt niet vóór `until` | `product analytics since must be earlier than until` |
| Het bereik is langer dan 31 dagen | `product analytics range must not exceed 31 days` |
| Een leeg filter, of een filter langer dan 256 tekens | `product analytics context filters must be non-empty and at most 256 characters` |

Een request zonder `project_id` geeft bijvoorbeeld:

```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" }
}
```

De routes voor metric-tijdreeksen en signaalvolume gebruiken dezelfde
scoperegels, met hun eigen tekst in `error`. Hun secties hieronder noemen die
fouten.

Een onbekende queryparameter geeft `422` met de response voor
[ongeldige queryparameters](/nl/reference/api-errors#invalid-query-parameters).
Een onbekend JSON-veld, een ontbrekend verplicht JSON-veld of een
niet-ondersteunde enumwaarde geeft `invalid_json`. Zie
[Ongeldige JSON](/nl/reference/api-errors#invalid-json). Een request met de
verkeerde HTTP-methode geeft `405` en `method_not_allowed`. De tekst in `next`
noemt de ondersteunde methode en velden. Zie
[Niet-ondersteunde methode](/nl/reference/api-errors#unsupported-method).

## Response van het overzicht voor productanalyse

`GET /api/telemetry/analytics/overview` toont de activiteit in één project:
actievolume, gebruikers, sessies, een tijdreeks, topacties, en geclassificeerde
paginaweergaven, schermweergaven en interacties. Gebruik het overzicht om de
exacte eventnamen voor de andere analyseroutes te vinden.

Stuur `response_version=3`. Versies 1 en 2 geven dezelfde aantallen, maar hun
waarde voor `estimation.method` is een ouder token. Versie 1 controleert het
soort subject niet als ze geïdentificeerde gebruikers telt. Versies 2 en 3
tellen alleen subjecten van het soort `user`, en voegen aantallen voor anonieme
subjecten en `subject_coverage` toe.

Dit request leest één uur in tijdsintervallen van vijf minuten en geeft twee
rijen in elke toplijst:

```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"
```

### Geslaagd overzicht

In dit fictieve resultaat heeft het project 120 acties in twee van de twaalf
tijdsintervallen. Twintig acties komen van anonieme subjecten. Elke actie heeft
een sessie-ID. De helft van de acties heeft een trace-ID.

```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."
  }
}
```

### Het overzicht lezen

De vijf aantallen in `subject_coverage` tellen op tot het eventtotaal van hun
sectie. Alleen `identified_user_events` telt mee voor gebruikers.
`anonymous_actions` is `summary.actions` min `identified_actions`.

`series` bevat alleen tijdsintervallen met activiteit. `expected_buckets` is
het aantal mogelijke tijdsintervallen in het bereik. Teken een ontbrekend
tijdsinterval niet als een gemeten nul, tenzij je grafiek die regel vermeldt.
Tijdsintervallen vallen samen met de intervalgrenzen in UTC. Een bereik dat
midden in een tijdsinterval begint, bevat dat onvolledige tijdsinterval.

`classified_activity` telt paginaweergaven, schermweergaven en interacties.
Schermweergaven en interacties zijn ook acties. Paginaweergaven niet. Tel
`summary.actions` niet op bij `classified_activity.summary.events`.

Kopieer `kind` en `event_name` uit `classified_activity.top_events` naar
trechterstappen, retentieselectors, levenscyclusselectors, padankers en
segmentdoelen. De waarde `true` in `top_events_truncated` betekent dat er namen
met minder volume zijn. Verhoog `top_limit` tot maximaal 20 om meer te zien.

`analysis_level` is `no_data`, `event_only`, `user_level` of
`user_and_session`. Als het project geen acties en geen geclassificeerde events
heeft, is `next_action.code` gelijk aan `capture_product_activity`. Zie
[Productanalyse](/nl/concepts/product-analytics#use-the-analytics-api).

### <span id="overview-errors">Fouten in het overzicht</span>

Naast de [gedeelde scopefouten](#shared-scope-errors) geeft het overzicht
`422` en `validation_failed` voor deze waarden:

| Waarde | `error` |
| - | - |
| `response_version` anders dan `1`, `2` of `3` | `product analytics response_version must be 1, 2, or 3` |
| `top_limit` buiten `1` tot `20` | `product analytics top_limit must be between 1 and 20` |
| `interval` anders dan `auto`, `1m`, `5m`, `15m`, `1h`, `6h` of `1d` | `product analytics interval is not supported` |
| Een expliciet `interval` dat meer dan 500 tijdsintervallen nodig heeft | `product analytics interval would exceed 500 buckets` |

Standaard is `interval` gelijk aan `auto`. Dat kiest het kleinste interval
waarvoor hoogstens 300 tijdsintervallen nodig zijn. Standaard is `top_limit`
gelijk aan `10`.

## <span id="ordered-funnel-response">Response van een geordende trechter</span>

`POST /api/telemetry/analytics/funnel` meet of 2 tot 8 stappen op volgorde
worden doorlopen. Kopieer elke exacte `kind` en `event_name` uit
`classified_activity.top_events` in het overzicht. Een actienaam die erop
lijkt, is geen match. Deze requestbody telt sessies die `/pricing` bekijken en
daarna binnen één uur de aanmelding afronden:

```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` is `session` of `identified_user`. Standaard is dat `session`.
De `kind` van een stap is `page_view`, `screen_view` of `interaction`. De
trechterroute accepteert geen `response_version`.

### Geslaagde trechter

Een response `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."
  }
}
```

Ratio's zijn breuken van 0 tot 1. Lees `coverage` voordat je op een ratio
vertrouwt. `selected_unit_coverage_rate` is het aandeel van de geselecteerde
stapevents dat LogBrew kon gebruiken. De response geeft geen ruwe identiteiten
terug. Zie [Productanalyse](/nl/concepts/product-analytics#measure-a-funnel).

### Conversie en dekking lezen

`entry_rate` is `entered_units` gedeeld door `candidate_units`: 50 van 60.
`overall_conversion_rate` is `completed_units` gedeeld door `entered_units`:
15 van 50, dus 30%. Het is niet 15 gedeeld door alle kandidaten. Deze aantallen
verklaren niet waarom eenheden stopten.

Dekking telt events, geen sessies. Hier passen 120 events bij een stap, en 20
daarvan hebben geen sessie-ID. Het resultaat laat die 20 events buiten de
sessieaantallen. Behandel ze niet als 20 mislukte sessies.

De eerste stap heeft geen `conversion_from_previous`. De laatste stap heeft
geen `drop_off_to_next_units` en geen `drop_off_to_next_rate`.

Een eenheid bereikt een latere stap alleen als de tijden van de stappen strikt
oplopen. Events met dezelfde tijdstempel kunnen niet aan twee opeenvolgende
stappen voldoen. De laatste stap moet binnen `conversion_window_seconds` na de
eerste stap plaatsvinden.

De sessiemodus telt sessies, geen mensen. Gebruik `identified_user` alleen
voor events met een ondoorzichtig subject-ID van het soort `user`. Die modus
kan events uit verschillende sessies binnen het conversievenster samenvoegen.
Houd dezelfde eenheid en dezelfde stappen aan als je resultaten vergelijkt.

Standaard is `conversion_window_seconds` 24 uur of de lengte van het bereik,
als die korter is. Het maximum is de lengte van het bereik in hele seconden,
naar boven afgerond.

### Lege trechterresultaten

Een geslaagde lege response toont nog steeds de gevraagde stappen, met nul
`units`. Zijn er geen kandidaateenheden, dan laat `summary` `entry_rate` en
`overall_conversion_rate` weg. De route geeft geen `404` alleen omdat er geen
events overeenkomen.

Lees `coverage` en `next_action` om de oorzaak te vinden:

| `next_action.code` | Oorzaak |
| - | - |
| `capture_product_activity` | Er zijn geen geclassificeerde events in de scope. |
| `choose_captured_funnel_steps` | Geen enkel event past bij een gevraagde stap. |
| `sessionize_product_activity` | Er zijn stapevents, maar geen ervan heeft een sessie-ID. |
| `identify_product_users` | Er zijn stapevents, maar geen ervan heeft een subject van het soort `user`. |
| `verify_funnel_entry` | Geen enkele eenheid is bij stap 1 binnengekomen. |
| `investigate_funnel_drop_off` | Er kwamen eenheden binnen, maar geen enkele eenheid voltooide alle stappen. |
| `compare_funnel_contexts` | Minstens één eenheid voltooide de trechter. |

### Geweigerde trechterrequests

Naast de [gedeelde scopefouten](#shared-scope-errors) geven deze requests
`422` en `validation_failed`. Minder dan 2 of meer dan 8 stappen:

```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" }
}
```

Een `conversion_window_seconds` van `0`, of een waarde groter dan de lengte van
het bereik:

```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" }
}
```

Een `event_name` die leeg is, langer is dan 256 tekens of een stuurteken
bevat, geeft
`product analytics funnel event_name must be non-empty, control-free, and at most 256 characters`.
Een stap `interaction` moet ook een geldige actienaam zijn. Anders is de fout
`product analytics interaction event_name must be a bounded stable action name`.

Corrigeer het request voordat je het opnieuw stuurt. Verwijder geen stappen en
wijzig de analyse-eenheid niet alleen om een niet-leeg resultaat te krijgen.

## Analyse op exacte events en automatische analyse

Retentie en levenscyclus accepteren twee vormen van requests. Kies met
`response_version` de vorm die je vraag beantwoordt:

| Analyse | `response_version` | Eventselectors |
| - | - | - |
| Retentie voor exacte events | `1`, of weggelaten | Stuur zowel `start_event` als `return_event`. |
| Levenscyclus voor één exact event | `1`, of weggelaten | Stuur `event`. |
| Automatische retentie of levenscyclus | `2` | Stuur geen eventselector. |

Een exacte selector bevat `kind` en `event_name`. `kind` is `page_view`,
`screen_view` of `interaction`. Kopieer `event_name` uit
`classified_activity.top_events`. Raad geen eventnaam op basis van een
knoplabel.

Beide vormen tellen alleen gebruikers: ondoorzichtige subject-ID's van het
soort `user`. Anonieme subjecten en events zonder bruikbaar subject-ID tellen
niet als gebruikers. Responses geven nooit subject-ID's terug.

De vaste intervallen zijn `hour`, `day`, `week` en `thirty_day`. Het zijn vaste
tijdsduren. `thirty_day` is 30 dagen, geen kalendermaand. Laat je `interval`
weg, dan gebruikt de API `hour` voor een bereik van 48 uur of korter, en `day`
voor een langer bereik.

### Request voor retentie op exacte events

Stuur deze body naar `POST /api/telemetry/analytics/retention`. Die vraagt of
gebruikers nog een checkout afronden na hun eerste checkout in het bereik:

```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" }
}
```

Het eerste overeenkomende startevent in het bereik is het anker van elke
gebruiker. Een terugkeer moet strikt na dat anker en vóór `until` plaatsvinden.
Beide selectors mogen hetzelfde event zijn.

| Veld | Waarden | Standaard |
| - | - | - |
| `interval_count` | `1` tot `31` perioden | `10` |
| `mode` | `return_on` telt een terugkeer binnen elke exacte periode. `return_on_or_after` telt een terugkeer op of na het begin van elke periode. | `return_on` |
| `cohort_mode` | `first_in_range` | `first_in_range` |

### Geslaagde retentie op exacte events

In dit fictieve voorbeeld ronden twee gebruikers een checkout af. De eerste
gebruiker rondt een checkout af op 1 juni om 12:00 en opnieuw om 13:00. De
tweede gebruiker rondt een checkout af op 2 juni om 12:00. Op 2 juni om 13:00
bekijkt de tweede gebruiker een pagina, maar rondt geen nieuwe checkout af.

```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."
  }
}
```

### Retentie lezen

Dekking telt alle vier de geclassificeerde events, maar slechts drie passen bij
elke checkoutselector. De paginaweergave telt niet als terugkeer. Een van de
twee gebruikers herhaalt de checkout, dus `return_rate_after_start` is `0.5`.

Alleen de eerste gebruiker heeft na het anker een volledige dag waarneming. Die
gebruiker keert binnen de dag terug, dus de ratio in de curve is `1.0`. De
tweede gebruiker heeft maar 12 uur waarneming. Die gebruiker komt niet in
aanmerking voor periode 0, dus de cel van het tweede cohort laat
`retention_rate` weg. Tel die gebruiker niet als verloren.

`weighted_retention_rate` deelt alle behouden gebruikers door alle gebruikers
die in aanmerking komen. `fully_observed_cohort_average_rate` is het gewone
gemiddelde van de ratio's van de cohorten waarin elke gebruiker in aanmerking
komt. Cohorten zijn vaste tijdsintervallen die beginnen bij `since`. `cohorts`
bevat alleen cohorten met gebruikers.

Met `mode: "return_on_or_after"` laat de curve `window_end_seconds` weg.

### Automatische retentie

Stuur `response_version: 2` zonder `start_event` of `return_event`. Elke
ondersteunde paginaweergave, schermweergave en interactie telt als start en als
terugkeer. Deze versie kiest een set events. Ze kiest geen vastlegformaat van
de 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"
}
```

De response heeft dezelfde vorm voor `summary`, `curve`, `cohorts` en
`next_action` als de response voor exacte events. Dit fragment toont de velden
die veranderen. In dit voorbeeld hebben dezelfde twee gebruikers drie events en
geen paginaweergave:

```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."
    ]
  }
}
```

In de automatische modus zijn `start_events` en `return_events` allebei gelijk
aan `classified_events`. Deze aantallen zijn events, geen gebruikers.

### Retentie zonder gebruikers die in aanmerking komen

Een geslaagd resultaat kan zonder cohortgebruikers zijn. Dit fragment toont één
gevraagde periode zonder cohorten:

```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": []
}
```

Lees `coverage` en `next_action`. Die onderscheiden een scope zonder
geclassificeerde events (`capture_product_activity`) van events zonder
gebruikers (`identify_product_users` of `identify_returning_users`). Een
ontbrekende ratio is geen gemeten nul.

### Retentiefouten

Naast de [gedeelde scopefouten](#shared-scope-errors) geven deze requests
`422` en `validation_failed`:

| Oorzaak | `error` |
| - | - |
| Versie 1 zonder beide selectors, versie 2 met een selector, of een andere versie | `product analytics retention activity selection is contradictory` |
| `interval_count` buiten `1` tot `31` | `product analytics retention interval_count must be between 1 and 31` |
| Tijdsintervallen voor cohorten maal `interval_count` is meer dan 500 | `product analytics retention interval and interval_count would exceed 500 cohort matrix cells` |

De limiet op cellen gebruikt het bereik en de perioden, niet het aantal
gebruikers. Een bereik van 30 dagen met `interval: "hour"` heeft 720
tijdsintervallen voor cohorten. Met `interval_count: 1` zijn dat 720 cellen,
meer dan 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" }
}
```

Verwijder beide selectors om automatische retentie te gebruiken. Wijzig de SDK
niet om dit leesrequest te corrigeren.

### Request voor levenscyclus op een exact event

Stuur deze body naar `POST /api/telemetry/analytics/lifecycle`. Die deelt
gebruikers in op basis van één event, niet op basis van alle activiteit in het
project:

```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` bepaalt hoeveel volledige perioden vóór `since` LogBrew
als geschiedenis leest. Het accepteert `2` tot `31`. Standaard is dat `2`. Een
gebruiker kan inactief zijn voor dit event terwijl die gebruiker andere dingen
doet.

### Geslaagde levenscyclus op een exact event

Dit fictieve voorbeeld gebruikt twee dagen geschiedenis en twee analysedagen.
De letters staan alleen voor voorbeeldgebruikers. De response geeft geen
gebruikers-ID's terug.

| Datum, UTC | Gebruikers die een checkout afronden |
| - | - |
| 30 mei, geschiedenis | B |
| 31 mei, geschiedenis | A en D |
| 1 juni, analyse | A, B en C |
| 2 juni, analyse | A en B |

C bekijkt op 2 juni ook een pagina. Dat event past niet bij de
checkoutselector.

```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."
  }
}
```

### Levenscyclus lezen

Op 1 juni is A terugkerend, B opnieuw actief, C nieuw en D inactief. Op 2 juni
zijn A en B terugkerend, en is C inactief voor checkout, ondanks de
paginaweergave. De netto verandering op 2 juni is `2 - 3 = -1`.

In elk tijdsinterval tellen nieuwe, terugkerende en opnieuw actieve gebruikers
op tot `active_subjects`. `returning_subjects` plus `dormant_subjects` is
gelijk aan `previous_active_subjects`. `net_active_change` is
`active_subjects` min `previous_active_subjects`.

Tel de dagelijkse actieve aantallen niet op om unieke gebruikers te krijgen.
Hier tellen de dagaantallen op tot 5, maar `analysis_active_subjects` is 3. In
geschiedenis en analyse samen komen vier unieke gebruikers voor.

`fully_observed` is `false` voor een laatste tijdsinterval dat na `until`
eindigt. De aantallen ervan kunnen veranderen als de volledige periode
waarneembaar is. De `next_action` stelt een onderzoek voor. Die toont geen
oorzaak.

### Automatische levenscyclus

Stuur `response_version: 2` zonder selector `event`. Elke ondersteunde
paginaweergave, schermweergave en interactie telt als activiteit:

```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
}
```

De response heeft dezelfde vorm voor `summary`, `buckets` en
`next_action` als de response voor een exact event. Dit fragment toont de
velden die veranderen:

```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."
}
```

In de automatische modus is `coverage.selected_events` gelijk aan
`coverage.analysis_classified_events`. Het vijfde item in `limitations` is
`Returning, resurrected, and dormant compare any supported classified product activity; no event is ranked, selected, or inferred.`

### Levenscyclus zonder gebruikers

Als het analysebereik en de geschiedenis geen bruikbare gebruikers bevatten, is
`buckets` leeg en laat `summary` `latest_fully_observed_period` weg:

```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": []
}
```

Gebruikers die alleen in de geschiedenis voorkomen, kunnen toch tijdsintervallen
met inactieve gebruikers opleveren als het analysebereik geen activiteit heeft.

### Levenscyclusfouten

Naast de [gedeelde scopefouten](#shared-scope-errors) geven deze requests
`422` en `validation_failed`:

| Oorzaak | `error` |
| - | - |
| Versie 1 zonder `event`, versie 2 met `event`, of een andere versie | `product analytics lifecycle activity selection is contradictory` |
| `history_period_count` buiten `2` tot `31` | `product analytics lifecycle history_period_count must be between 2 and 31` |
| Geschiedenisperioden van samen meer dan 62 dagen | `product analytics lifecycle history must not exceed 62 days` |
| Meer dan 100 tijdsintervallen voor analyse | `product analytics lifecycle interval would exceed 100 analysis buckets` |

Tien geschiedenisperioden van `week` hebben bijvoorbeeld 70 dagen nodig:

```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" }
}
```

### De gekozen analysescope lezen

Responses voor exacte events hebben `schema_version: 1`. Hun `query` herhaalt
de selectors en laat `activity_scope` weg. Automatische responses hebben
`schema_version: 2` en `query.activity_scope: "all_classified_activity"`. Ze
laten de selectors weg. Een andere selector kan het resultaat veranderen zonder
dat de vastgelegde activiteit verandert.

## Response voor metric-tijdreeksen

`GET /api/telemetry/metrics/series` leest één exacte metricnaam in één project.
Kopieer de naam uit `GET /api/telemetry/metrics`. Dit request groepeert een
delta-counter per service:

```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"
```

### Geslaagde metric-tijdreeks

Deze fictieve response bevat één tijdreeks van een delta-counter. Drie metingen
met de waarden `2`, `3` en `5` vallen in het eerste tijdsinterval. Twee
metingen met de waarden `1` en `4` vallen in het laatste tijdsinterval. In het
middelste tijdsinterval valt geen meting, dus de response heeft daarvoor geen
datapunt.

```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."
  }
}
```

### Een metric-tijdreeks lezen

Het eerste datapunt registreert 10 voltooide jobs, niet 10 metingen.
`rate_per_second` deelt die verandering door het tijdsinterval van 300
seconden. `last` is de laatst geregistreerde verandering, niet de som. Zie
[betekenissen van metric-aggregaties](/nl/concepts/telemetry#read-the-metric-value).

Het soort en de temporaliteit van een tijdreeks bepalen de `aggregation.code`
en de statistieken in elk datapunt. Een datapunt laat een statistiek weg die
niet van toepassing is. Een ontbrekende statistiek is geen nul.

| Soort en temporaliteit | `status` | `aggregation.code` | `value` | Andere statistieken |
| - | - | - | - | - |
| `gauge`, `instant` | `ready` | `gauge_last` | Laatste meting | `last`, `min`, `max`, `average` |
| `counter`, `delta` | `ready` | `delta_sum` | Som van de veranderingen | `last`, `min`, `max`, `average`, `sum`, `rate_per_second` |
| `histogram`, `delta` | `ready` | `distribution_p95` | p95 bij benadering | `min`, `max`, `average`, `sum`, `p50`, `p95`, `p99` |
| Elk soort, `cumulative` | `limited` | `raw_cumulative_last` | Laatste ruwe meting | `last`, `min`, `max` |
| Elk ander paar | `limited` | `raw_last` | Laatste ruwe meting | `last`, `min`, `max` |

`limited` is een geslaagde response, geen fout. Het voegt
`aggregation.limitation` toe, dat uitlegt waarom LogBrew alleen ruwe waarden
toont. `ready` bewijst niet dat alles is vastgelegd.

Lees `coverage` voordat je een grafiek tekent:

* `samples` telt de metingen van alle overeenkomende tijdreeksen, ook
  tijdreeksen die de response niet teruggeeft.
* `series` telt overeenkomende tijdreeksen. `returned_series` en `points` tellen
  de teruggegeven gegevens.
* `truncated` is `true` als `series_limit` tijdreeksen met minder volume heeft
  weggelaten.
* `expected_buckets_per_series` is het aantal mogelijke tijdsintervallen in het
  bereik.

Voeg geen datapunt toe voor een tijdsinterval zonder metingen. Vul geen nul in
en kopieer de vorige waarde niet. Elk datapunt geeft maximaal 3
`trace_exemplars` terug. Een trace-exemplar koppelt één meting aan een trace.
Het verklaart niet elke meting in het tijdsinterval. Als geen enkel datapunt
een trace-exemplar heeft, is `next_action.target` gelijk aan `metric_samples`.

### Scope en fouten van metric-tijdreeksen

`project_id`, `name` en `since` zijn verplicht. `name` mag hoogstens 200 tekens
hebben. `interval` is `auto`, `1m`, `5m`, `15m`, `1h`, `6h` of `1d`. Standaard
is dat `auto`. Die waarde kiest het kleinste interval met hoogstens 300
tijdsintervallen. Een expliciet interval mag niet meer dan 500 tijdsintervallen
nodig hebben.

`group_by` is `none`, `service_name`, `release` of `environment`. Standaard is
dat `none`. Zonder groepering blijven verschillende soorten, eenheden en
temporaliteiten in aparte tijdreeksen. `series_limit` accepteert `1` tot `20`.
Standaard is dat `10`.

Een leeg resultaat geeft `200` met `series: []` en nul `samples`. Het object
`coverage` laat `first_seen_at` en `last_seen_at` weg. Dat bewijst niet dat de
applicatie de metric nooit heeft verstuurd. Controleer het project, de
metricnaam en het tijdsbereik.

Zonder `name` krijg je `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" }
}
```

Tijdsintervallen van één minuut over zeven dagen geven `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" }
}
```

Andere fouten met `422` zijn `metric series group_by is not supported`,
`metric series interval is not supported` en
`metric series_limit must be between 1 and 20`.

## Response van padanalyse

`POST /api/telemetry/analytics/paths` vindt de benoemde events vóór of na één
gekozen event in dezelfde sessie. Het gekozen event is het anker. Kopieer de
`kind` en `event_name` ervan uit `classified_activity.top_events`. De route
geeft `schema_version: 1` terug. Ze accepteert geen `response_version` of
`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` en `anchor` zijn verplicht.

### Geslaagde padanalyse

In dit fictieve resultaat bevatten vier sessies het anker. De twee
teruggegeven paden staan voor drie van die sessies. Eén lager gerangschikt pad
wordt niet teruggegeven.

```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."
  }
}
```

### Paden lezen

`share_of_anchored_sessions` deelt de sessies van een pad door alle vier de
sessies met het anker. De aandelen zijn 50% en 25%, niet 67% en 33%.
`unrepresented_sessions` telt sessies met het anker die geen enkel teruggegeven
pad vertegenwoordigt. `paths_truncated: true` betekent dat het resultaat
onvolledig is.

Dekking telt events, geen sessies. Hier passen vijf events bij het anker, maar
één heeft geen sessie-ID. Dat event kan niet in een pad komen. Elk pad geeft
maximaal 3 trace-exemplars terug. Gebruik een trace-ID uit je eigen response.
Een tracekoppeling toont niet wat een gebruikersactie of een fout veroorzaakte.

| Veld | Betekenis |
| - | - |
| `following` | Begint bij het vroegste overeenkomende anker in elke sessie. Het anker heeft positie `0`. Latere knooppunten hebben positieve posities. |
| `preceding` | Eindigt bij het laatste overeenkomende anker in elke sessie. Eerdere knooppunten hebben negatieve posities. Het anker heeft positie `0`. |
| `depth` | Aantal knooppunten naast het anker, het anker zelf niet meegeteld. `1` tot `8`. Standaard is dat `4`. Een pad kan minder knooppunten hebben. |
| `collapse_repeated` | Voegt opeenvolgende knooppunten met hetzelfde soort en dezelfde naam samen. Standaard is dat `true`. |
| `path_limit` | Maximaal aantal teruggegeven paden, gerangschikt op aantal sessies. `1` tot `20`. Standaard is dat `10`. |

Knooppunten staan in beide richtingen op tijdsvolgorde. Een pad is geen
volledige herhaling van de sessie. LogBrew leest hoogstens 1024 benoemde events
per sessie voordat het het anker kiest: de vroegste events voor `following` en
de laatste events voor `preceding`. Een anker buiten die limiet kan ontbreken.

### <span id="filter-the-anchor-by-property">Het anker filteren op eigenschap</span>

Stuur maximaal vier `property_filters`, elk met één exacte `key` en `value`.
Kopieer de sleutel uit de [eigenschappencatalogus](#analytics-property-catalog).
De filters gelden alleen voor het anker, niet voor de events eromheen. Waarden
zijn hoofdlettergevoelig. Als er filters zijn, herhaalt `query` ze en meldt
`coverage.anchor_property_filters`:

| Veld | Betekenis |
| - | - |
| `context_events` | Ankerevents in de scope vóór de eigenschapsfilters. |
| `property_ready_events` | Ankerevents die elke gevraagde sleutel hebben. |
| `missing_property_events` | Ankerevents zonder een of meer gevraagde sleutels. |
| `matching_events` | Ankerevents waarvan de waarden bij elk filter passen. |
| `nonmatching_value_events` | Ankerevents die elke sleutel hebben, maar een andere waarde. |
| `property_ready_rate` | `property_ready_events` gedeeld door `context_events`. |
| `match_rate` | `matching_events` gedeeld door `property_ready_events`. |

Ontbrekende sleutels en afwijkende waarden vragen om verschillende oplossingen.
Tel ze niet bij elkaar op. Het object ontbreekt als het request geen
eigenschapsfilter heeft.

### Lege paden en geweigerde requests

Een lege array `paths` kan een geslaagde response `200` zijn. Lees `summary`,
`coverage` en `next_action`. Deze codes onderscheiden de oorzaken:
`capture_product_activity`, `choose_captured_path_anchor`,
`capture_anchor_properties`, `improve_anchor_property_coverage`,
`verify_anchor_property_values`, `sessionize_product_activity` en
`narrow_or_move_path_anchor`.

Naast de [gedeelde scopefouten](#shared-scope-errors) geven deze requests
`422` en `validation_failed`:

| Oorzaak | `error` |
| - | - |
| `depth` buiten `1` tot `8` | `product analytics path depth must be between 1 and 8` |
| `path_limit` buiten `1` tot `20` | `product analytics path_limit must be between 1 and 20` |
| Meer dan vier eigenschapsfilters | `product analytics paths accept at most four exact anchor property filters` |
| Een sleutel die niet in de eigenschappencatalogus staat | `product analytics path property keys must be supported privacy-safe keys` |
| Dezelfde sleutel twee keer | `product analytics path property keys must be unique` |
| Een lege waarde, een waarde langer dan 256 tekens, of een stuurteken | `product analytics path property values must be non-empty, control-free, and at most 256 characters` |

`depth: 0` geeft bijvoorbeeld:

```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">Eigenschappencatalogus voor productanalyse</span>

`GET /api/telemetry/analytics/properties` toont de eigenschapssleutels op
geclassificeerde productevents in één project. Gebruik de sleutels in
[segmentvergelijkingen](#analytics-segment-comparison) en in filters voor
padankers. De catalogus geeft sleutels en aantallen terug. Hij geeft nooit
eigenschapswaarden of identiteiten terug.

### Beschikbare eigenschapssleutels lezen

Stuur `project_id` en `since`. Je kunt ook `until`, `service_name`, `release`,
`environment`, `limit` en `response_version` sturen. `limit` accepteert `1`
tot `50` sleutels. Standaard is dat `20`. Stuur `response_version=2` voor de
openbare waarde van `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"
```

### Geslaagde eigenschappencatalogus

In dit fictieve resultaat zijn er 100 geclassificeerde events. Vijf daarvan
zijn vastgelegd vóór de huidige eigenschappenindex.

```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."
  }
}
```

### De catalogus interpreteren

`source` is `standard_context` voor een standaardcontextsleutel, zoals
`resource.runtime.name`, of `custom_tag` voor een sleutel die begint met
`tag.`. `value_type` is altijd `string`. `properties` is gesorteerd op
`events`, de hoogste eerst.

`tag.plan` staat op 60 van de 100 geclassificeerde events. De sleutel heeft
ongeveer 3 unieke waarden. De beschrijving toont die waarden niet. Gebruik
waarden die je uit je applicatie kent. Raad geen waarde op basis van een
aantal. Eén event kan meerdere sleutels hebben, dus tel de aantallen in
`events` per sleutel niet bij elkaar op.

| Veld | Betekenis |
| - | - |
| `summary.classified_events` | Geclassificeerde events in de scope. Dit is de noemer van elke `coverage_rate`. |
| `summary.available_property_keys` | Geschat aantal unieke sleutels, niet het aantal teruggegeven rijen. |
| `coverage.unindexed_events` | Events die vóór de huidige eigenschappenindex zijn vastgelegd. Ze kunnen geen sleutels leveren. |
| `coverage.incomplete_index_events` | Events met deels misvormde of afgekapte context. Hun geldige sleutels tellen nog steeds mee. |
| `coverage.privacy_filtered_events` | Events waaruit LogBrew gevoelige sleutels van aangepaste tags heeft verwijderd. Dit is geen aantal sleutels. |
| `coverage.properties_truncated` | `true` als er meer sleutels zijn dan `limit`. Maak de scope kleiner, of verhoog `limit` tot maximaal 50. |
| `coverage.values_returned` | Altijd `false`. |

Een lege array `properties` bewijst niet dat het project geen productevents
heeft. Lees `summary`, `coverage` en `next_action`.

### Fouten in de eigenschappencatalogus

Naast de [gedeelde scopefouten](#shared-scope-errors) geeft `limit=0` of
`limit=51` een `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" }
}
```

Een `response_version` anders dan `1` of `2` geeft
`product analytics response_version must be 1 or 2`. LogBrew controleert
`response_version` vóór de andere waarden.

Een `POST`-request geeft `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">Segmentvergelijking in productanalyse</span>

`POST /api/telemetry/analytics/segments/compare` vergelijkt hoe vaak sessies
of gebruikers één exact event bereiken in 2 tot 4 segmenten binnen één
project. Een segment selecteert events op service, release, omgeving en
eigenschapswaarden. Het eerste segment is het referentiesegment.

### De vergelijking definiëren

Stuur deze JSON-body met accountauthenticatie en
`Content-Type: application/json`. Hier zijn `basic` en `premium`
abonnementswaarden van de voorbeeldapplicatie, geen abonnementen van 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` en `segments` zijn verplicht. `analysis_unit` is `session` of
`identified_user`. Standaard is dat `session`. Die waarde telt sessies, geen
mensen.
`interval` accepteert dezelfde waarden als het overzicht. Standaard is dat
`auto`.

Elk segment heeft een unieke `key`, een `label` en een eigen set filters nodig:

* `key`: 1 tot 32 bytes. Begin met een kleine ASCII-letter of een cijfer.
  Gebruik alleen kleine ASCII-letters, cijfers, `_` en `-`.
* `label`: 1 tot 80 tekens, zonder stuurtekens.
* `service_name`, `release`, `environment`: optioneel. Elke waarde heeft 1 tot
  256 tekens, zonder stuurtekens.
* `property_filters`: 0 tot 4 filters. Elke sleutel mag één keer in een
  segment voorkomen. Een event moet bij alle filters van het segment passen.
  Waarden zijn hoofdlettergevoelig en hebben 1 tot 256 tekens. LogBrew
  verwijdert spaties aan het begin en het eind.

Een segment zonder filters selecteert alle geclassificeerde activiteit in het
project en het tijdsbereik. Segmenten mogen overlappen. Een ander label of een
andere sleutel maakt twee identieke sets filters niet geldig.

### Geslaagde segmentvergelijking

In dit fictieve resultaat bereikt het referentiesegment de checkout in 10 van
de 50 sessies. Het segment premium bereikt die in 18 van de 60 sessies.

```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."
  }
}
```

### Ratio's en verschillen lezen

`eligible_units` schat de sessies of gebruikers met geclassificeerde activiteit
in het segment. `reached_units` schat hoeveel daarvan het doel bereikten.
`reach_rate` is `reached_units` gedeeld door `eligible_units`. Events zonder ID
van de gekozen eenheid tellen niet mee voor deze eenheden.

De ratio van het referentiesegment is 20%. De ratio van premium is 30%. Het
verschil is 10 procentpunten. De relatieve stijging is 50%, niet 10%. Kleine
decimale afwijkingen komen door rekenen met drijvendekommagetallen. Rond
ratio's af voor weergave, maar reken met de teruggegeven waarden. Het
referentiesegment heeft geen `comparison_to_baseline`. De relatieve stijging
ontbreekt als de bereikratio van het referentiesegment nul is.

In `query` is een segmentfilter dat je niet hebt gestuurd `null`. Een lege
lijst `property_filters` wordt weggelaten.

`coverage.property_filters` heeft dezelfde velden als de
[dekking van padankerfilters](#filter-the-anchor-by-property). Hier is
`matching_events` gelijk aan `classified_events`. Houd ontbrekende sleutels en
afwijkende waarden apart. Segmenten kunnen overlappen, en één sessie kan in
meerdere tijdsintervallen voorkomen. Tel aantallen eenheden niet op over
segmenten of tijdsintervallen heen.

De vergelijking is beschrijvend. `confidence.causal_inference` is
`not_established` en `confidence.statistical_significance` is `not_tested`.
Een ratio van 30% tegenover 20% toont niet aan dat een abonnement tot meer
checkouts leidde.

### Fouten in segmentvergelijkingen

Naast de [gedeelde scopefouten](#shared-scope-errors) geven deze requests
`422` en `validation_failed`:

| Oorzaak | `error` |
| - | - |
| Minder dan 2 of meer dan 4 segmenten | `product analytics segment comparison requires two through four segments` |
| Twee segmenten met dezelfde sleutel | `product analytics segment keys must be unique` |
| Twee segmenten met dezelfde filters | `product analytics segment filters must be unique` |
| Een sleutel die niet uit 1 tot 32 toegestane bytes bestaat | `product analytics segment keys must be 1 through 32 machine-safe bytes` |
| Een label dat leeg of te lang is, of een stuurteken bevat | `product analytics segment labels must be non-empty, control-free, and at most 80 characters` |
| Een filterwaarde met een stuurteken | `product analytics segment filters must be control-free` |
| Meer dan vier eigenschapsfilters in een segment | `product analytics segments accept at most four exact property filters` |
| Een sleutel die niet in de eigenschappencatalogus staat | `product analytics segment property keys must be supported privacy-safe keys` |
| Dezelfde eigenschapssleutel twee keer in een segment | `product analytics segment property keys must be unique within each segment` |
| Een eigenschapswaarde die leeg of te lang is, of een stuurteken bevat | `product analytics segment property values must be non-empty, control-free, and at most 256 characters` |
| Een `response_version` anders dan `1` of `2` | `product analytics response_version must be 1 or 2` |

De fouten voor `interval` zijn dezelfde als de [fouten in het overzicht](#overview-errors).

Twee segmenten met verschillende sleutels en identieke filters geven
bijvoorbeeld:

```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" }
}
```

Een ander label of een andere volgorde van eigenschapsfilters verandert de
geselecteerde events niet. Een mislukte validatie is geen bewijs dat er geen
events overeenkomen.

Een `GET`-request geeft `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" }
}
```

## Response voor signaalvolume

`GET /api/telemetry/summary/volume` telt bewaarde signalen voor één project en
tijdsbereik. De route vereist `project_id` en `since`. Ze accepteert geen
`project_ids`.

`until` mag niet in de toekomst liggen. Laat je het weg, dan is het einde het
tijdstip van het request. Een korte `since` zoals `24h` telt terug vanaf
`until`. `interval` is `auto`, `1m`, `5m`, `15m`, `1h`, `6h` of `1d`. De
standaardwaarde `auto` kiest het kleinste interval met hoogstens 120
tijdsintervallen. Een request mag niet meer dan 500 tijdsintervallen nodig
hebben. De enige `response_version` is `1`.

### Signaalaantallen

Deze fictieve response beslaat twee tijdsintervallen van één minuut. Het
request liep om 12:02 UTC zonder `until`. Het account heeft een bewaartermijn
van 30 dagen. Lees de teruggegeven bewaartermijn en het grenstijdstip. Ga er
niet van uit dat deze waarden voor jouw account gelden.

```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"]
  }
}
```

### Elk aantal in zijn eigen eenheid lezen

| Signaal | Wat `total` telt | Lees het niet als |
| - | - | - |
| `issues` | Bewaarde issuevoorvallen | Gegroepeerde issues of getroffen gebruikers |
| `logs` | Bewaarde logevents | Requests |
| `traces` | Unieke trace-ID's, geteld bij hun eerste bewaarde span in dit tijdvenster | Spans of alle tracestarts ooit |
| `actions` | Bewaarde actie-events | Gebruikers of sessies |
| `metrics` | Bewaarde metric-datapunten | De som van metricwaarden |

`total` is de som van de aantallen per tijdsinterval in de tijdreeks. `peak` is
het hoogste aantal in één tijdsinterval. `non_empty_buckets` telt
tijdsintervallen met een aantal boven nul. De vijf tijdreeksen staan altijd in
deze volgorde. Voeg verschillende signaalaantallen niet samen tot één
impactscore.

Tijdsintervallen beginnen bij `query.since`. Een tijdsinterval bevat zijn
begin, maar niet zijn einde. Het laatste tijdsinterval kan korter zijn dan het
interval. De response heeft geen tijdreeks met het aantal releases. Lees
`release_volume_not_included` niet als nul releases.

### Lege en ingekorte tijdvensters

Als geen enkel signaal overeenkomt, blijven alle vijf tijdreeksen staan, en
hebben hun datapunten expliciete aantallen van nul. Een mislukt request is iets
anders. Vervang een fout niet door een grafiek vol nullen.

Vergelijk `query.requested_since` met `query.since`. Als de bewaartermijn het
tijdvenster inkort, is `coverage.retention.window_clipped` gelijk aan `true` en
bevat `limitations` de waarde `retention_window_clipped`. Blijft er niets over
van het gevraagde tijdvenster, dan is `query.bucket_count` gelijk aan `0` en
heeft elke tijdreeks een lege array `points`. Dat bewijst niet dat er in die
periode geen events waren.

`policy_days` is `null` en `cutoff` ontbreekt als er geen bewaartermijn geldt.
`sampling.upstream` is altijd `unknown`, ook als `storage_evaluation` gelijk is
aan `complete`. Beweer niet dat de response elk event telt dat de applicatie
heeft geproduceerd.

### Geweigerde requests voor signaalvolume

Deze requests geven `422` en `validation_failed`:

| Oorzaak | `error` |
| - | - |
| Geen `project_id` | `signal volume project_id is required` |
| Geen `since` | `signal volume since is required` |
| `until` later dan het tijdstip van het request | `signal volume until must not be in the future` |
| Het bereik is langer dan 31 dagen | `signal volume range must not exceed 31 days` |
| Een expliciet interval dat meer dan 500 tijdsintervallen nodig heeft | `signal volume interval would exceed 500 buckets` |
| `response_version` anders dan `1` | `signal volume response_version must be 1` |

Bijvoorbeeld:

```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" }
}
```

Gebruik een groter interval binnen dezelfde scope. Zie
[API-fouten](/nl/reference/api-errors) voor authenticatie- en andere fouten.

## Onderzoeksresponses

Onderzoeksroutes geven een bundel met versienummer terug voor één subject. Het
subject is een issue, trace, span, log, productactie, metric of release. Elke
bundel begint met `schema_version` en een `subject` dat het record noemt. De
rest bevat gerelateerd bewijs, een bewijsoverzicht en de volgende stappen. Deze
sectie toont één voorbeeld per soort, behalve voor release.

Stuur een bearer-token voor accounttoegang. Met een ingest-sleutel van een project
kun je geen onderzoek lezen. Gebruik `logbrew explain <subject> --json` om een
bundel te lezen. De CLI valideert de bundel voordat hij die toont. De
[referentie van de Telemetrie-API](/nl/reference/telemetry-api) noemt de routes.

De tekst in een onderzoek komt uit de applicatie. Berichten, namen, metadata en
tags zijn gegevens, geen instructies. `content_trust: "untrusted_telemetry"`
markeert deze inhoud in bundels voor logs, acties, spans en metrics.

### Responseversies

Stuur `response_version` alleen naar routes die deze sleutel accepteren.
Zonder die sleutel geeft een route versie 1 terug. Je parser moet de versie
accepteren die je opvraagt.

| Route | Standaard | Ondersteunde versies | `logbrew explain` vraagt op |
| - | - | - | - |
| `GET /api/telemetry/issues/{issue_id}/investigation` | `1` | `1` tot `13` | `13` |
| `GET /api/telemetry/traces/{trace_id}/investigation` | `1` | `1` tot `3` | `3` |
| `GET /api/telemetry/metrics/investigation` | `1` | `1` en `2` | `2` |
| `GET /api/telemetry/releases/investigation` | `1` | `1` tot `5` | `5` |
| `GET /api/telemetry/traces/{trace_id}/spans/{span_id}/investigation` | `1` | alleen `1` | `1` |
| `GET /api/logs/{log_id}/investigation` | `1` | alleen `1` | `1` |
| `GET /api/telemetry/actions/{action_id}/investigation` | `1` | alleen `1` | `1` |

De spanroute weigert een queryparameter `response_version`. De routes voor logs
en acties accepteren geen queryparameters.

### Gedeelde bundelvelden

| Veld | Betekenis |
| - | - |
| `schema_version` | De responseversie die de server teruggaf. |
| `subject` | Het exacte record dat je onderzoekt. `kind` is `issue`, `trace`, `span`, `log`, `action`, `metric` of `release`. |
| `analysis.causality` | Altijd `evidence_only` in bundels voor traces, spans, logs, acties en metrics. Gecorreleerde telemetrie bewijst geen oorzaak. |
| Collectieobjecten | Gerelateerd bewijs als `{ "status", "items", "truncated" }`. |
| `timeline` | Teruggegeven bewijs van oud naar nieuw, met een eigen vlag `truncated`. De volgorde bewijst geen oorzaak. |
| `evidence` | Het bewijsoverzicht. `status` is `complete` of `partial`. |
| `next_actions` | Voorgestelde leesacties op volgorde van `priority`, vanaf `1`. Ze zijn nog niet uitgevoerd. |

Elke gerelateerde collectie meldt één `status` voor beschikbaarheid:

| Status | Betekenis | Gedrag van de client |
| - | - | - |
| `available` | De leesactie is voltooid en gaf items terug. | Toon de items en de vlag `truncated`. |
| `not_linked` | Het subject heeft geen ID voor deze koppeling, zoals een trace-ID. | Leg uit dat de koppeling ontbreekt. Bouw er geen op basis van tijdstempels. |
| `not_found` | De leesactie is voltooid en vond geen bewaard bewijs. | Toon een leeg resultaat. |
| `unavailable` | De optionele leesactie is mislukt. Het subject is nog steeds geldig. | Houd het subject zichtbaar. Probeer het later opnieuw. Toon geen nul items als resultaat. |

Het bewijsoverzicht heeft vier gesorteerde lijsten met vaste veldnamen:
`captured_fields`, `missing_fields`, `redacted_fields` en `truncated_fields`.
`status` is alleen `complete` als de laatste drie lijsten leeg zijn.
Afgeschermde gegevens zijn geen ontbrekende gegevens. Afgekapte gegevens zijn
geen volledige gegevens. Vul geen afgeschermde of afgekapte waarde in.

### Limieten van een onderzoek

Deze limieten begrenzen één response. Een vlag `truncated` of een regel in
`truncated_fields` laat zien dat een limiet gegevens heeft weggelaten.

| Bewijs | Limiet |
| - | - |
| Gerelateerde items in één collectie | 20 |
| Gelezen bewaarde spans voor één trace | 1.000 |
| Items in de tijdlijn | 50 voor bundels van logs, acties en spans. 100 voor bundels van traces en metrics. |
| Gestructureerde attributen, eigenschappen en metadata | 64 scalaire waarden, 4 niveaus van objecten of arrays, 16 items per array, 512 tekens per string |
| Tijdvenster voor correlatie | 5 minuten vóór en na een log, actie of geselecteerd issuevoorval. Voor een trace of span 5 minuten vóór de start en na het einde, hoogstens 24 uur. |

Elke sectie per soort noemt haar eigen limieten.

### Response van een issueonderzoek

Gebruik `GET /api/telemetry/issues/{issue_id}/investigation` om het bewijs voor
één voorval van een gegroepeerd issue te lezen. De
[handleiding voor issueonderzoek](/nl/guides/investigate-an-issue) laat zien in
welke volgorde je het bewijs leest. Vraag versie 13 op:

```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"
```

De queryparameters zijn `response_version`, `selection` en `occurrence_id`.
`selection` is `recommended`, `first` of `latest`. De waarden zijn
hoofdlettergevoelig. In versies 2 tot 13 gebruikt een weggelaten selector
`recommended`. Versie 1 geeft het laatste bewaarde voorval terug en accepteert
geen selector. Filters van de issuelijst gelden niet voor deze leesactie.

<Accordion title="Voorbeeld van een issueonderzoek in versie 13">
  Deze fictieve response `200 OK` heeft één afgehandeld voorval van `TypeError`
  met een gekoppelde trace. Er zijn geen request, breadcrumbs, gerelateerde logs
  of deploymentbewijs, dus `evidence.status` is `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>

| Veld | Versie | Betekenis |
| - | - | - |
| `subject` | 1 | Het gegroepeerde issue. `first_seen_at`, `last_seen_at` en `occurrence_count` beschrijven de groep. |
| `event` | 1 | Het geselecteerde voorval: SDK, `context`, `exception`, `stack_frames` en `breadcrumbs`. In versie 1 `null` als er geen laatste voorval te lezen is. |
| `cause` | 1 | `status` is `reported_hypothesis`, `evidence_only` of `unknown`. `signals` noemt de waargenomen signalen. |
| `fix` | 1 | Een plek in de code. `status` is `reported_location`, `observed_application_frame`, `observed_frame`, `observed_underlying_exception_frame` of `unknown`. |
| `impact` | 1 | Aantallen voorvallen en `user_impact`. `reported` bevat impact die de applicatie meldt, of `null`. |
| `correlations` | 1 | `trace`, `logs`, `actions`, `metrics` en `release`. |
| `occurrence_selection` | 2 | De gevraagde selector, de reden en samenvattingen van het geselecteerde, eerste, laatste en aanbevolen voorval. |
| `lifecycle` | 3 | `persisted_status`, `effective_status`, statusactiviteit en `regression`. `effective_status` kan `regressed` zijn. |
| `occurrence_analysis` | 4 | Trend van voorvallen en de verdeling over releases, omgevingen, services en SDK's. |
| `event.exception_chain` | 5 | Maximaal 8 gekoppelde exceptions. `relationship` is `reported`, `cause`, `context`, `aggregate_member` of `suppressed`. |
| `event.request` | 6 | `method`, `route_template` en `response_status_code`. De sleutel ontbreekt als er geen request is vastgelegd. |
| `grouping` | 7 | De `strategy` van de groepering, de `components` ervan en het gebruik van stackframes. |
| `correlations.release.deployment_status` | 8 | De status van het opzoeken van de deployment. `deployment`, `time_since_deployment_ms` en `deployment_causality` verschijnen alleen als er een deployment is gevonden. |
| `correlations.related_issues` | 9 | Andere issues op dezelfde trace. |
| `source_locator` | 10 | Repository, component, revisie en bestandspad binnen de repository, als LogBrew die kan koppelen. |
| `reproduction` | 11 | `status` is `ready`, `partial` of `insufficient_evidence`. |
| Code `verify_correction` in `next_actions` | 12 | Verschijnt als `reproduction.status` gelijk is aan `ready`. |
| `impact.user_impact.count_method` | 13 | Meldt een unieke telling bij benadering als `approximate_distinct`. Eerdere versies gebruiken een oudere waardenaam. `unavailable` betekent dat er geen telling is. |

Sleutels uit een latere versie ontbreken in een eerdere versie. Lees een
ontbrekende sleutel niet als `null`.

`subject.status` en de statussen in `lifecycle` melden een gearchiveerd issue
als `ignored`. Responses van de issuelijst en van issuedetails gebruiken
`archived` vanaf responseversie 2.

Limieten voor issues: de aanbeveling leest hoogstens 50 bewaarde voorvallen. De
trend heeft hoogstens 30 tijdsintervallen. Elke verdeling geeft hoogstens 10
waarden terug. Een stack heeft hoogstens 32 frames.

#### Requestfouten bij een issueonderzoek

Gebruik `selection` of `occurrence_id`. Stuur ze niet allebei, ook niet als ze
hetzelfde voorval selecteren:

```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` | Oorzaak | Herstel |
| - | - | - | - |
| `422` | `selection and occurrence_id are mutually exclusive` | Het request heeft beide selectors. | Houd één selector. |
| `422` | `issue occurrence selection requires response_version=2 through 13` | Het request heeft een selector en versie 1, of geen versie. | Stuur `response_version=13`. Houd de selector. |
| `422` | `issue investigation response_version must be 1 through 13` | De versie valt buiten het bereik. | Stuur een ondersteunde versie. |
| `422` | `invalid query parameters` | Een onbekende sleutel, een ongeldige UUID, een versie die geen geheel getal is, of een onbekende waarde voor `selection`. | Corrigeer de [query](/nl/reference/api-errors#invalid-query-parameters). |
| `404` | `issue occurrence not found` | Het voorval zit niet in de bewaarde geschiedenis van deze groep. | Kopieer het voorval-ID uit de events van dit issue. Gebruik niet zonder goedkeuring `latest` of `recommended` in plaats daarvan. |
| `404` | `issue not found` | Geen enkel leesbaar project heeft dit issue. | Controleer het account en de UUID van het issue. Stuur geen UUID van een voorval als issue-ID. |

Een ontbrekend voorval betekent niet dat het issue ontbreekt. Een `404` laat
niet zien of een ander account het issue kan lezen.

### Response van een traceonderzoek

Gebruik `GET /api/telemetry/traces/{trace_id}/investigation` om één trace te
lezen met het foutpad, het traagste pad en gerelateerde signalen. De
queryparameters zijn `response_version`, `project_id`, `release` en
`environment`. Ze zijn allemaal optioneel. Vraag versie 3 op:

```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"
```

Versie 2 voegt `cause` en `fix` toe aan elk gerelateerd issue. Versie 3 voegt
`span_id` toe aan gerelateerde issues, acties en metrics, als dat is
vastgelegd.

<Accordion title="Voorbeeld van een traceonderzoek in versie 3">
  Deze fictieve response heeft een server-rootspan en een mislukte client-span.
  De mislukte span is ook de traagste onderliggende span. De spans hebben geen
  gestructureerde context, dus `spans.context` ontbreekt.

  ```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>

| Veld | Betekenis |
| - | - |
| `subject` | Tracetotalen uit de geanalyseerde spans. |
| `analysis.status` | `errors_observed`, `latency_focus` of `no_error_observed`. |
| `analysis.first_error_path` | De bekende keten van bovenliggende spans van de root tot de vroegste foutspan. |
| `analysis.bottleneck_path` | De bekende keten van bovenliggende spans tot de traagste onderliggende span. |
| `spans.items[].roles` | Waarom de span in de preview staat: `root`, `first_error`, `error_path`, `bottleneck`, `bottleneck_path`, `error` of `slow`. |
| `correlations.window` | Het tijdsbereik en de deploymentscopes voor gerelateerde leesacties. |
| `correlations.issues`, `logs`, `actions`, `metrics` | Signalen met hetzelfde trace-ID in het tijdvenster. |

`trace.parentage` ontbreekt als een span een bovenliggende span noemt die
LogBrew niet heeft bewaard. De spanpreview heeft hoogstens 64 spans. Elk
analysepad heeft hoogstens 64 spans. Gerelateerde leesacties gebruiken
hoogstens 8 deploymentscopes.

Een volgende actie met als doel `trace_span` noemt een `span_id` uit deze
bundel. Roep de spanroute aan met de `project_id`, `environment` en `release`
van die span om de span te lezen.

### Response van een spanonderzoek

Gebruik `GET /api/telemetry/traces/{trace_id}/spans/{span_id}/investigation` om
één bewerking in een trace te lezen. Stuur `project_id`, `environment` en
`release`. Alle drie zijn verplicht. Kopieer ze van de geselecteerde span.
Stuur de `id` van de spanrij niet als `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="Voorbeeld van een spanonderzoek">
  Deze fictieve response beschrijft de mislukte client-span uit het
  tracevoorbeeld. Een foutlog heeft hetzelfde span-ID. De span duurde langer dan
  het 95e percentiel bij benadering van de bewaarde vergelijkbare spans.

  ```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>

| Veld | Betekenis |
| - | - |
| `payload` | `metadata` van de span, maximaal 8 `events` en maximaal 8 `links`. Ze delen samen een budget van 64 waarden. |
| `analysis.observations` | `subject_error`, `child_error`, `exact_span_error_log`, `related_issue`, `subject_at_or_above_peer_p95` of `subject_at_or_above_peer_p99`. |
| `topology` | `root`, `parent`, `ancestors`, directe `children`, `descendant_count` en `cross_service_edges`. |
| `topology.parent_chain_status` | `root`, `complete`, `missing`, `cycle`, `truncated` of `unavailable`. |
| `baseline` | Eerdere spans met hetzelfde project, dezelfde omgeving, release, service, bewerking en naam. |
| `correlations.logs` | Logs met hetzelfde trace-ID en span-ID. |
| `correlations.issues`, `actions`, `metrics` | Signalen met hetzelfde trace-ID in hetzelfde project, dezelfde omgeving en dezelfde release. |
| `timeline[].offset_ms` | Milliseconden vanaf de start van de span. Een negatieve waarde ligt vóór de span. |

De referentie leest de 24 uur vóór de start van de span. `since` telt mee en
`until` niet. `error_rate_basis_points: 500` betekent 5%.
`subject_percentile_basis_points: 9500` betekent dat 95% van de bewaarde
vergelijkbare spans niet langer duurde dan deze span. Percentielen zijn bij
benadering. Houd `baseline.limitations` bij de waarden. Een referentie met
`not_found` heeft geen bewaarde vergelijkbare spans. Een referentie met
`unavailable` is een mislukte leesactie, geen aantal van nul.

`parent_chain_status: "complete"` betekent dat de bewaarde keten een root
bereikt. Het bewijst niet dat LogBrew elke span van het request heeft bewaard.
De topologie geeft hoogstens 64 voorouders, 50 directe kinderen en 50
verbindingen tussen services terug.

| HTTP | `error` | Herstel |
| - | - | - |
| `422` | `trace_id must be a non-zero 32-character hexadecimal value` | Kopieer `trace_id` uit een trace-response van LogBrew. |
| `422` | `span_id must be a non-zero 16-character hexadecimal value` | Kopieer `span_id` uit een trace-response van LogBrew. |
| `422` | `environment and release must be non-empty exact span scope values` | Kopieer de scope van de geselecteerde span. |
| `422` | `invalid query parameters` | Stuur `project_id`, `environment` en `release`, en geen andere sleutel. |
| `404` | `span not found` | Controleer de ID's, het project, de omgeving en de release. |

### Response van een logonderzoek

Gebruik `GET /api/logs/{log_id}/investigation` om één log en het gerelateerde
bewijs te lezen. Deze route heeft geen queryparameters. Kopieer het log-ID uit een
loglijst.

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

De leesactie kan bewijs teruggeven buiten de filters van de loglijst.
Gerelateerde leesacties gebruiken het project, de omgeving en de release van de
log, en 5 minuten vóór en na de log. Logs in de buurt gebruiken ook dezelfde
service. Die hebben geen trace-ID nodig. Leesacties op de exacte trace hebben
het trace-ID van de log nodig en kunnen andere services bevatten. De
tracesamenvatting gebruikt hetzelfde trace-ID en dezelfde scope, zonder het
tijdvenster.

<Accordion title="Voorbeeld van een logonderzoek">
  Deze fictieve response heeft een waarschuwingslog zonder tracecontext en één
  log in de buurt. De response bouwt geen tracekoppeling op basis van de
  tijdstempels.

  ```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>

| Veld | Betekenis |
| - | - |
| `attributes` | De begrensde gestructureerde attributen. `values` bevat geen `context`. Die staat in het veld `context` op het hoogste niveau. |
| `analysis.status` | `critical_evidence`, `error_evidence`, `warning_evidence` of `no_failure_observed`. |
| `correlations.trace` | Het trace-ID, het span-ID, `exact_span` en de `summary` van de trace. |
| `correlations.trace_logs` | Logs met hetzelfde trace-ID. `relationship` is `exact_trace`. |
| `correlations.nearby_logs` | Logs van dezelfde service in het tijdvenster. `relationship` is `nearby_scope`. Het subject en de logs van de exacte trace tellen niet mee. |
| `correlations.issues`, `actions`, `metrics` | Signalen met hetzelfde trace-ID. |
| `correlations.release` | De releasescope voor een releaseonderzoek. Het bevat geen vergelijking. |
| `timeline[].relationship` | `subject`, `exact_span`, `exact_trace` of `nearby_scope`. |

Een trace-ID kan aanwezig zijn als de tracestatus `not_found` of `unavailable`
is. Een beschikbare tracesamenvatting garandeert geen `exact_span`.

### Response van een actieonderzoek

Gebruik `GET /api/telemetry/actions/{action_id}/investigation` om één
productactie te lezen, met de gemelde status en gerelateerd bewijs. Deze route
heeft geen queryparameters. Gerelateerde leesacties gebruiken hetzelfde
tijdvenster en dezelfde scopes als een logonderzoek.

```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` en `next_actions` gebruiken de vormen van een
logonderzoek. Gerelateerde acties bevatten de onderzochte actie zelf niet.

<Accordion title="Voorbeeld van een actieonderzoek">
  Deze fictieve response beschrijft een mislukte checkoutactie van een ingelogde
  gebruiker. De actie heeft geen trace-ID.

  ```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>

| Veld | Betekenis |
| - | - |
| `subject.status` | `queued`, `running`, `success`, `failure`, of `null` als er geen ondersteunde status is vastgelegd. |
| `subject.subject_classification` | `user`, `anonymous`, `legacy_unknown`, `missing`, `historical_unindexed` of `unsupported`. |
| `subject.session_captured` | Of de actie een sessie had. De response geeft het sessie-ID nooit terug. |
| `properties` | Het begrensde object `metadata` van de actie. |
| `analysis.status` | `subject_failure`, `correlated_failure_evidence`, `in_progress`, `success_observed` of `status_not_captured`. |

De response geeft nooit ID's van subjecten of sessies terug. Het bewijsoverzicht
noemt `subject.distinct_id` altijd als afgeschermd, en ook `subject.session_id`
als er een sessie is vastgelegd. Daarom is elke actiebundel `partial` en bevat
die `improve_capture`. Verwijder geen privacymaatregelen om daaraan te voldoen.

### Response van een metriconderzoek

Gebruik `GET /api/telemetry/metrics/investigation` om één metricnaam in één
project en tijdsbereik te lezen. De response bevat de huidige tijdreeks, een
vergelijking met het voorgaande tijdvenster van dezelfde lengte, de laatste
meting, trace-exemplars en voltooide deployments. Versie 2 voegt de beschrijving
van de metric uit de laatste bewaarde meting toe. Versie 1 meldt altijd
`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` en `since` zijn verplicht. `since` telt mee en `until`
niet. Standaard is `until` gelijk aan nu. De vergelijking leest ook het
voorgaande tijdvenster van dezelfde lengte.

<Accordion title="Voorbeeld van een metriconderzoek in versie 2">
  Dit fictieve histogram heeft 5 metingen in twee tijdsintervallen van 5
  minuten. Het laatste tijdsinterval heeft een p95 van 48 ms. Het laatste
  tijdsinterval van het vorige tijdvenster heeft een p95 van 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>

| Veld | Betekenis |
| - | - |
| `subject.description_status` | `captured`, `not_captured` of `unavailable`. |
| `query` | De genormaliseerde query. `service_name`, `release` en `environment` verschijnen alleen als je ze stuurt. |
| `analysis.status` | `no_samples`, `change_observed`, `no_change_observed`, `baseline_not_found` of `comparison_unavailable`. |
| `analysis.focus` | Het vergelijkingsitem met de grootste relatieve verandering, of de grootste absolute verandering als er geen relatieve verandering is. `null` als geen enkel item vergelijkbaar is. |
| `series[].aggregation.code` | `gauge_last`, `delta_sum`, `distribution_p95`, `raw_cumulative_last` of `raw_last`. |
| `comparison.status` | `available`, `partial`, `not_found`, `unavailable` of `no_current_samples`. |
| `comparison.items[]` | Het laatste niet-lege tijdsinterval van elk tijdvenster voor dezelfde tijdreeks. |
| `latest_sample` | De laatste ruwe meting, met SDK, `context`, `metadata` en tracekoppeling. |
| `exemplars` | Ruwe metingen met een trace-ID. `coverage` telt de gekoppelde metingen. |
| `deployments` | Voltooide deployments vanaf het begin van het vorige tijdvenster tot `until`. |
| `next_actions[]` | `code`, `target`, een `reason` in platte tekst en een scope in `context` voor de volgende leesactie. |

`relative_change_percent` is `(current - previous) / abs(previous) * 100`.
Het is `null` als de vorige waarde nul is of ontbreekt.
`expected_buckets_per_series` telt mogelijke tijdsintervallen, geen
tijdsintervallen met gegevens. Teken lege tijdsintervallen niet als nul. Een
deployment vlak bij een verandering bewijst niet dat die de verandering
veroorzaakte.

Een project dat het account niet kan lezen, geeft `200 OK` met
`analysis.status: "no_samples"`, geen `404`. Een leeg resultaat zegt niets over
andere signaaltypen.

Limieten voor metrics: het bereik is hoogstens 31 dagen. Elke tijdreeks heeft
hoogstens 500 tijdsintervallen. `series_limit` is 1 tot 20, standaard 10. De
response geeft hoogstens 20 exemplars en 20 deployments terug.

| HTTP | `error` | Herstel |
| - | - | - |
| `422` | `metric investigation response_version must be 1 or 2` | Laat `response_version` weg of stuur `2`. |
| `422` | `metric series project_id is required` | Stuur één leesbaar project-ID. |
| `422` | `metric series name is required` | Kopieer de naam uit de metriclijst. |
| `422` | `metric series since is required` | Stuur een waarde zoals `24h` of een RFC 3339-tijdstempel. |
| `422` | `metric series range must not exceed 31 days` | Gebruik een korter bereik. |
| `422` | `metric series interval would exceed 500 buckets` | Gebruik `interval=auto` of een groter interval. |
| `422` | `metric series_limit must be between 1 and 20` | Stuur een waarde van 1 tot 20. |

`interval` is `auto`, `1m`, `5m`, `15m`, `1h`, `6h` of `1d`. `group_by` is
`none`, `service_name`, `release` of `environment`. Andere waarden geven
`422`.

### Onderzoeksfouten

| HTTP | Route | `error` |
| - | - | - |
| `404` | Log | `log not found` |
| `404` | Actie | `action not found` |
| `404` | Trace | `trace not found` |
| `422` | Trace | `trace investigation response_version must be 1, 2, or 3` |
| `400` | Log, actie, issue | `invalid URL path parameters` als het ID in het pad geen UUID is |
| `422` | Issue, trace, span, metric | `invalid query parameters` bij een onbekende sleutel of een waarde van het verkeerde type |

Een `404` betekent dat geen enkel leesbaar project het record heeft. Elke route
geeft ook `401` zonder geldige authenticatie en `405` voor een andere methode
dan `GET`. Zie [API-fouten](/nl/reference/api-errors) voor de responses bij
[niet gevonden](/nl/reference/api-errors#resource-not-found),
[pad](/nl/reference/api-errors#invalid-path-value),
[authenticatie](/nl/reference/api-errors#authentication-failure) en
[methode](/nl/reference/api-errors#unsupported-method).

Een optionele leesactie voor bewijs kan mislukken binnen een response
`200 OK`. De collectie meldt dan `unavailable`. Toon dat niet als `not_found`
of als nul records.

## <span id="severity-values">Ernstwaarden</span>

De ernstwaarden die gebruikers zien, zijn `info`, `warning`, `error` en
`critical`. SDK's en runtimes kunnen gangbare aliassen sturen, zoals `trace`,
`debug`, `warn` of `fatal`. REST- en live-responses geven altijd de canonieke
waarde terug. LogBrew accepteert bijvoorbeeld `warn` als invoer en geeft
`warning` terug. De ingest-API weigert onbekende ernstwaarden.

| Alias | Canonieke waarde |
| - | - |
| `trace`, `debug` | `info` |
| `warn` | `warning` |
| `fatal` | `critical` |

## <span id="severity-rule-responses">Responses van ernstregels</span>

Een ernstregel verandert hoe LogBrew een log of issue toont. De regel verandert
niet de ernst die de applicatie heeft vastgelegd. Logs en issues geven een
object `triage` terug:

| Veld | Betekenis |
| - | - |
| `effective_severity` | De ernst om te tonen. Zonder regel is die gelijk aan `severity`. |
| `ignored` | `true` als een logregel de log negeert, of als het issue is gearchiveerd. |
| `rule_applied` | `true` als een ernstregel of de genegeerde toestand geldt. `false` is de standaardwaarde, geen ontbrekende gegevens. |

Gebruik `triage.effective_severity` voor weergave. Houd `severity` als de
vastgelegde waarde. Standaard laat de loglijst genegeerde logs weg. Stuur
`status=ignored` of `status=all` op `GET /api/logs` om ze mee te nemen.

Het account moet issues in het project mogen beheren. Leestoegang is niet
genoeg. Zonder die toestemming geeft een regelwijziging `403` met
`code: forbidden`.

### Een logregel wijzigen

`PUT /api/logs/{log_id}/triage-rule` stelt de regel in voor de log en voor
latere logs met dezelfde signatuur. De body heeft zowel `severity` als
`ignored` nodig:

```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 }'
```

Een response `200 OK` bevat de volledige [log](#log-response). De `severity`
blijft `warning`. De `triage` toont de regel:

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

Dit fragment toont alleen de gewijzigde velden. `severity` in het request is
`source`, `info`, `warning`, `error` of `critical`. `source` zet de vastgelegde
ernst terug. Een genegeerde log wordt daardoor niet weer actief. Stuur
`"ignored": false` om de log weer te tonen.

### Een issueregel wijzigen

`PUT /api/telemetry/issues/{issue_id}/triage-rule` stelt de getoonde ernst in
van een gegroepeerd issue en de latere voorvallen ervan. De body accepteert
alleen `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" }'
```

Een response `200 OK` bevat het volledige [issue](#issue-response) in versie 1.
De vastgelegde `severity` en `status` veranderen niet:

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

Dit fragment toont maar een deel van de velden. Een regel lost een issue niet
op, archiveert het niet en heropent het niet. Gebruik daarvoor de
[statuswijziging](#issue-status-response-examples). Een afgeleide prioriteit
volgt de nieuwe effectieve ernst. Lees het issue met `response_version=2` of
`3` om die te zien.

Een niet-ondersteunde ernst geeft `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"
  }
}
```

Een onbekend veld in de body, zoals `status` bij een issueregel, geeft `422`
met `code: invalid_json`. Een log of issue dat ontbreekt of niet leesbaar is,
geeft `404` met `code: not_found`. Is de response verloren gegaan? Lees dan de
log of het issue opnieuw voordat je de regel opnieuw stuurt.

## Formaat van foutresponses

Applicatiefouten geven een JSON-envelop terug. Dit voorbeeld toont een
geweigerd request. De tekst in `error` en `next` hangt af van het probleem:

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

Gebruik `code` voor vertakkingen in je programma en `next_action` voor
automatisering. Toon `error` en `next` als platte tekst aan mensen. Parse hun
formulering niet. Sommige fouten voegen velden toe, zoals `limit`, `reset_at`
of `retry_after_seconds`. Een response zonder JSON-body heeft geen `code` van
LogBrew. Zie [API-fouten](/nl/reference/api-errors) voor alle codes.

## Gegevens lezen met de CLI

De CLI leest dezelfde routes en geeft met `--json` dezelfde JSON terug. Begin
breed en verfijn daarna:

```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
```

Voeg `--pagination cursor` toe voor de cursorenvelop. De CLI vraagt versie 4
van de issueresponse op. Zie [De volgende pagina lezen](/nl/reference/cli#read-the-next-page)
en [Live volgen](/nl/reference/cli#live-watch).


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