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

# Format respons API dan contoh respons JSON

> Baca respons API LogBrew untuk daftar telemetri, halaman kursor, peristiwa langsung, perubahan data, serta status berhasil dan error.

Halaman ini memberi satu contoh untuk setiap jenis respons
[API Telemetri](/id/reference/telemetry-api). Semua nilai adalah contoh
sintetis. Untuk kode error dan cara pemulihannya, lihat
[Error API](/id/reference/api-errors).

## Baca respons

Baca setiap respons dengan urutan ini:

1. Baca status HTTP.
2. Pastikan body punya bentuk yang sesuai dengan rutenya.
3. Pastikan setiap `project_id` ada di dalam lingkup proyek yang diminta.
4. Biarkan nilai enum kanonis dan ID tetap seperti aslinya.
5. Ikuti `next_action` hanya jika klien mendukung `code` dan
   `target`-nya.
6. Perlakukan `null`, kolom yang tidak disertakan, dan daftar kosong sebagai
   status yang berbeda.

`200 OK` bisa berisi daftar kosong. Daftar log yang kosong berarti tidak ada
log yang cocok dengan permintaan. Itu tidak berarti masalah, trace, atau aksi
juga kosong. Jangan gabungkan sinyal hanya karena stempel waktunya berdekatan.
Ikuti trace hanya jika respons berisi `trace_id`-nya yang persis.

`404` dan daftar kosong adalah dua hasil yang berbeda. Rute daftar
mengembalikan `[]` jika tidak ada record yang cocok. Rute detail mengembalikan
`404` dengan `code: not_found` jika tidak menemukan record yang bisa dibaca.
Kedua hasil itu tidak membuktikan bahwa ingest gagal.

## Data yang perlu dikirim

Kegunaan respons bergantung pada telemetri yang Anda kirim. Kirim nilai
berikut di setiap envelope atau penyiapan SDK:

* `release` dan `environment`.
* Nama yang stabil untuk layanan, aksi, dan metrik.
* Konteks trace jika log, span, aksi, dan masalah berasal dari permintaan yang
  sama.
* Nilai tingkat keparahan kanonis: `info`, `warning`, `error`, dan `critical`.
* Atribut yang membantu debugging, tanpa rahasia atau data pribadi yang tidak
  perlu.

Lihat [Integrasi SDK](/id/guides/sdk-ingestion) dan
[Kendalikan data yang direkam](/id/guides/safe-capture).

## Respons ingest

SDK publik membaca respons `POST /v1/events` untuk Anda. Kode aplikasi tidak
perlu menanganinya.

### Respons batch SDK

Batch SDK yang berhasil mengembalikan `200 OK` beserta jumlah yang diterima
untuk setiap stream:

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

| Kolom | Arti |
| - | - |
| `issues`, `logs`, `trace_spans`, `actions`, `metrics` | Peristiwa dari batch ini yang diterima LogBrew. |
| `already_accepted` | Peristiwa yang ID-nya sudah diterima LogBrew sebelumnya. LogBrew tidak menyimpannya lagi. |
| `context_updated` | `true` jika batch ini memperbarui konteks rilis atau lingkungan. |

Jumlah ini hanya mencakup batch ini. Percobaan ulang untuk batch yang sudah
diterima LogBrew mengembalikan `0` untuk setiap stream, dan jumlah
peristiwanya ada di `already_accepted`. Pertahankan ID peristiwa asli saat
Anda mencoba lagi.

### Respons envelope native

`POST /api/telemetry/ingest` mengembalikan `200 OK` beserta jumlah item yang
diterima untuk setiap stream:

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

Respons native tidak punya kolom `metrics` atau `context_updated`. Jangan
tambahkan kolom itu. `already_accepted` menghitung item yang `id`-nya sudah
diterima LogBrew sebelumnya untuk proyek itu. Lihat [envelope native langsung](/id/guides/sdk-ingestion#required-envelope-fields).

### Error ingest

`401` dengan `code: ingest_key_invalid` berarti bearer ingest sudah dicabut,
kedaluwarsa, atau tidak valid untuk proyek itu. Di `POST /v1/events`,
permintaan tanpa bearer atau dengan bearer yang bukan kunci ingest
mengembalikan `401` dengan `code: unauthorized`. Gunakan bearer ingest khusus
proyek yang berlaku saat ini. Jangan mencoba lagi dengan bearer akun.

Batch SDK yang ditolak mengembalikan `422` dengan `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"
  }
}
```

Nilai `error` lain antara lain `SDK event batch requires at least one event` dan
`SDK event type is not supported by this ingest route`. Periksa versi SDK dan
konfigurasi transport. Jangan kirim batch kosong. Jangan ubah tipe peristiwa
atau ID hanya agar batch lolos validasi.

Permintaan dengan metode selain `POST` mengembalikan `405` dengan
`code: method_not_allowed`. Body JSON yang tidak bisa dibaca mengembalikan
`code: invalid_json`.

## Format respons daftar telemetri

Secara default, rute daftar mengembalikan array JSON polos. Daftar kosong yang
berhasil adalah `[]`.

Dengan `pagination=cursor`, rute mengembalikan envelope. Kunci koleksinya
sesuai dengan sinyal:

| Rute | Kunci koleksi |
| - | - |
| `/api/logs` | `logs` |
| `/api/telemetry/issues` | `issues` |
| `/api/telemetry/issues/{issue_id}/events` | `events`, dengan `issue_id` di tingkat atas |
| `/api/telemetry/actions` | `actions` |
| `/api/telemetry/metrics` | `metrics` |
| `/api/telemetry/releases` | `releases` |
| `/api/telemetry/traces` | `traces`, dengan `naming_quality` di tingkat atas |

`next_cursor` adalah objek berisi kolom lanjutan, atau `null` di halaman
terakhir. Baris diurutkan dari yang terbaru. Lihat [paginasi berbasis kursor](/id/reference/telemetry-api-filters#cursor-pagination).

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

Halaman kursor berisi log dengan `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"
  }
}
```

Log berisi `level` untuk kompatibilitas dan `severity` untuk tampilan. Keduanya
menyimpan nilai kanonis. `triage` menyimpan hasil aturan tingkat keparahan.
Lihat [respons aturan tingkat keparahan](#severity-rule-responses).

`trace_id` dan `span_id` bernilai `null` jika log tidak punya tautan trace.
Dalam kasus itu, `next_action` adalah `inspect_related_logs` dengan target
`telemetry_logs`. Log, masalah, dan aksi memakai 2 pasangan `next_action` yang
sama.

`GET /api/logs/{log_id}` mengembalikan satu log dengan bentuk yang sama.

### <span id="issue-response">Respons masalah</span>

`GET /api/telemetry/issues/{issue_id}` mengembalikan satu masalah terkelompok.
Daftarnya mengembalikan objek yang sama. Contoh ini memakai versi respons
default, yaitu versi 1:

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

Di versi 1, `status` bernilai `unresolved`, `resolved`, atau `ignored`. Untuk
masalah yang diarsipkan, `triage.ignored` bernilai `true`. Untuk pasangan
`next_action` dan pembacaan yang mengikutinya, lihat
[Investigasi masalah](/id/guides/investigate-an-issue).

`first_seen_at` dan `last_seen_at` adalah waktu kemunculan pertama dan
kemunculan terbaru. Keduanya tidak berubah saat status berubah.

Beberapa kolom hanya muncul jika LogBrew punya datanya:

| Kolom | Kapan muncul |
| - | - |
| `span_id` | Masalah punya tautan span. Jika tidak, kolom ini tidak disertakan. |
| `diagnostics` | Kemunculan terbaru punya tipe exception atau breadcrumb. Lihat [riwayat kemunculan masalah](#issue-occurrence-history). |
| `symbolication` | Hanya di `GET /api/telemetry/issues/{issue_id}`, jika masalah punya identitas artefak rilis. Lihat [Source map JavaScript](/id/guides/source-maps). |

`symbolication.status` bernilai `resolved`, `invalid_metadata`,
`artifact_not_found`, `source_not_resolved`, atau `unavailable`. Daftar,
perubahan status, dan perubahan aturan tidak mengembalikan `symbolication`.

Dengan `response_version=2`, masalah punya kolom yang sama, dengan perubahan
berikut:

| Kolom | Nilai versi 2 |
| - | - |
| `status` | `unresolved`, `resolved`, atau `archived`. Versi 1 menampilkan `archived` sebagai `ignored`. |
| `priority` | `high`, `medium`, atau `low`. |
| `priority_source` | `manual` jika seseorang menetapkan prioritas. `derived` jika prioritas mengikuti tingkat keparahan efektif. |

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

Contoh ini hanya menampilkan sebagian kolom. Prioritas turunan bernilai `high`
untuk `error` dan `critical`, `medium` untuk `warning`, dan `low` untuk `info`.
Prioritas ini memakai `triage.effective_severity`, jadi aturan tingkat
keparahan masalah bisa mengubahnya.

Dengan `response_version=3`, masalah punya semua kolom versi 2 ditambah
`assignee`. `assignee` bernilai `null` jika masalah belum punya penanggung
jawab:

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

| Kolom | Arti |
| - | - |
| `assignee.user_id` | ID pengguna penanggung jawab. Kirim sebagai `assignee` di filter atau perubahan. |
| `assignee.name` | Nama penanggung jawab, atau `null` jika akun tidak punya nama. |
| `assignee.email` | Alamat email penanggung jawab. |

Masalah tidak menampilkan penanggung jawab jika anggota yang ditugaskan tidak
bisa membaca proyek itu lagi.

Dengan `response_version=4`, `assignee` juga punya `type`. Penanggung jawab
`user` punya `user_id`, `name`, dan `email`, seperti di versi 3. Penanggung
jawab `team` punya `team_id`, `slug`, dan `name`. Versi 3 menampilkan tim
penanggung jawab sebagai `null`. CLI meminta versi 4:

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

`response_version` lain mengembalikan `422` dengan `code: validation_failed`.
Halaman kursor memakai versi yang sama untuk setiap masalah di `issues`.

### <span id="assignee-list-response">Respons daftar penanggung jawab</span>

`GET /api/telemetry/issues/assignees?project_id=<project_id>` mengembalikan
setiap akun yang bisa ditugaskan masalah di proyek itu:

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

Tambahkan `response_version=2` untuk juga mendapatkan `teams`: setiap tim di
organisasi proyek, dengan `team_id`, `slug`, dan `name`.

Jika akun tidak bisa membaca proyek itu, rute mengembalikan `404` dengan
`code: not_found`.

### <span id="action-response">Respons aksi</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` mengikuti satu pelaku atau sesi. Perlakukan `distinct_id` dan
`session_id` sebagai ID buram: jangan mengurai atau menafsirkan isinya. `session_id` dan `trace_id` bernilai `null`
jika tidak terekam. `span_id` tidak disertakan jika tidak terekam. Aksi tidak
punya tingkat keparahan. Lihat [Perekaman peristiwa produk](/id/guides/product-events).

### Respons metrik

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

Setiap item adalah satu sampel. Jangan pakai jumlah sampel sebagai jumlah
peristiwa atau jumlah pengguna. `unit`, `temporality`, `trace_id`, dan
`span_id` bernilai `null` jika tidak terekam. Nilai `null` bukan nol.

### Respons rilis

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

Satu baris mencakup satu proyek, rilis, lingkungan, dan layanan. Jumlah di
dalamnya hanya menggambarkan baris itu.

`trace_health.status` bernilai `unknown` jika baris tidak punya trace,
`no_errors_observed`, atau `errors_observed`. `error_rate_basis_points` adalah
porsi trace yang punya span error, dari `0` sampai `10000`. Nilai ini bukan
tingkat error untuk semua permintaan.

`next_action` menunjuk ke tipe sinyal pertama yang punya data, dengan urutan
ini:

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

Lihat [Rilis](/id/concepts/releases).

### Respons pencarian trace

`GET /api/telemetry/traces?pagination=cursor` mengembalikan satu baris untuk
setiap trace, ditambah catatan `naming_quality` untuk halaman yang
dikembalikan:

```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` hanya mencakup halaman yang dikembalikan. Nilai ini bukan
skor untuk seluruh akun. `truncated: true` berarti masih ada halaman lain. Jika
halaman itu punya nama generik, rute yang tidak cocok, atau operasi generik,
`next_action` adalah `improve_trace_naming` dengan target
`sdk_configuration`. Tanpa `pagination=cursor`, rute mengembalikan array trace
polos tanpa `naming_quality`.

`next_cursor` berisi `time` dan `trace_id`. Kirim keduanya sebagai
`cursor_time` dan `cursor_trace_id`.

`GET /api/telemetry/traces/{trace_id}` mengembalikan span dari satu trace.
`GET /api/telemetry/traces/{trace_id}/summary` mengembalikan root span, span
error, layanan, durasi, dan jalur paling lambat tanpa atribut span mentah. `404`
dari ringkasan berarti tidak ada trace yang cocok dengan lingkup lengkapnya.
Jangan mencoba lagi tanpa filter. Lihat [respons span dan ringkasan trace](#trace-spans-and-summary-responses).

### Daftar kosong dan record yang tidak ada

Pembacaan daftar bisa tidak punya hasil yang cocok. Pembacaan detail punya
kontrak yang berbeda:

| Permintaan | Berhasil | Tidak ada record yang bisa dibaca |
| - | - | - |
| `GET /api/logs/{log_id}` | `200` dengan satu [log](#log-response) | `404` dengan `code: not_found` |
| `GET /api/telemetry/issues/{issue_id}` | `200` dengan satu [masalah](#issue-response) | `404` dengan `code: not_found` |
| `GET /api/telemetry/issues/{issue_id}/events` | `200` dengan kemunculan | `404` dengan `code: not_found` di halaman pertama |
| `GET /api/telemetry/traces/{trace_id}` | `200` dengan span | `200` dengan `[]` |
| `GET /api/telemetry/traces/{trace_id}/summary` | `200` dengan satu ringkasan | `404` dengan `code: not_found` |

Log yang tidak ada mengembalikan `404` ini:

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

Masalah yang tidak ada memakai `"error": "issue not found"`. Ringkasan trace
yang tidak ada memakai `"error": "trace not found"`. ID yang tidak dikenal dan
ID yang tidak bisa dibaca akun mengembalikan respons yang sama.

Daftar dengan satu `project_id` yang tidak bisa dibaca akun mengembalikan
`200` dengan daftar kosong. Periksa ID proyek sebelum Anda melaporkan bahwa
tidak ada data.

### Pilihan proyek yang ditolak

Daftar log, masalah, aksi, metrik, rilis, dan trace menerima satu proyek
dengan `project_id` atau 2 sampai 50 proyek dengan `project_ids`. Katalog
atribut log menerima pemilih yang sama. Riwayat kemunculan masalah tidak
menerimanya.

Permintaan yang berisi `project_id` dan `project_ids` sekaligus mengembalikan
`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` dengan UUID yang tidak valid, ID yang berulang, atau kurang dari
2 atau lebih dari 50 ID juga mengembalikan `422` dengan `code: validation_failed`.

Jika akun tidak bisa membaca salah satu proyek di kumpulan `project_ids`,
seluruh permintaan mengembalikan `404`. Respons tidak mengembalikan proyek
lainnya sebagai hasil sebagian:

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

Tampilkan error-nya, bukan daftar kosong atau jumlah nol. Baca lagi daftar
proyek. Jangan hapus proyek diam-diam, dan jangan mencoba lagi di semua
proyek. Kredensial yang didelegasikan, seperti koneksi MCP, mengembalikan
`403` dengan `code: forbidden` untuk proyek di luar koneksinya. Lihat
[lingkup proyek](/id/reference/telemetry-api-filters#project-scope).

### <span id="cursor-errors">Error kursor</span>

Log, masalah, aksi, metrik, dan kemunculan masalah memakai `cursor_time` dan
`cursor_id`. Kursor yang ditolak mengembalikan `422` dengan
`code: validation_failed`. Error ini tidak berarti daftarnya kosong.

| Permintaan | `error` |
| - | - |
| `pagination=cursor` dengan hanya 1 dari 2 kolom kursor | `cursor_time and cursor_id must be sent together` |
| `cursor_time` yang bukan stempel waktu RFC3339 | `cursor_time must be an RFC3339 timestamp` |
| Kolom kursor tanpa `pagination=cursor`, atau dengan nilai `pagination` lain | `pagination must be cursor when cursor pagination is requested` |

Contoh:

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

Salin `next_cursor` lengkap dari halaman sebelumnya. Jangan ganti
`cursor_time` dengan waktu saat ini. Jika kursor hilang, mulai lagi dengan
`pagination=cursor` dan filter aslinya. Kunci kueri yang tidak dikenal atau
nilai dengan tipe yang salah mengembalikan `422` dengan
`"error": "invalid query parameters"`.

### Respons kursor rilis

Kursor rilis punya 5 kolom. Permintaan berhasil yang tidak punya hasil cocok
mengembalikan `200`:

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

Jika `next_cursor` bukan `null`, kirim kelima nilainya di permintaan
berikutnya:

| Kolom `next_cursor` | Parameter kueri |
| - | - |
| `time` | `cursor_time` |
| `project_id` | `cursor_project_id` |
| `release` | `cursor_release` |
| `environment` | `cursor_environment` |
| `service_name` | `cursor_service_name` |

`cursor_project_id` menandai posisi. Kolom ini tidak menggantikan `project_id`
atau `project_ids`. Pertahankan parameter proyek dan filter aslinya.
Lakukan URL-encode pada setiap nilai.

Dengan `pagination=cursor`, kursor yang tidak lengkap atau nilai rilis,
lingkungan, atau layanan yang kosong mengembalikan `422` dengan
`"error": "all release cursor fields must be sent together"`. `cursor_time`
yang tidak valid dan permintaan tanpa `pagination=cursor` mengembalikan error
yang sama dengan [kursor lainnya](#cursor-errors).

### Error pencarian trace

Error ini berlaku untuk `GET /api/telemetry/traces`. Masing-masing
mengembalikan `422` dengan `code: validation_failed`. Permintaan yang ditolak
bukan hasil kosong.

| Permintaan | `error` |
| - | - |
| `status` selain `error` atau `ok` | `trace status must be error or ok` |
| `min_duration_ms` di bawah `0` | `minimum trace duration must not be negative` |
| Hanya 1 kolom kursor, atau `cursor_trace_id` yang kosong | `cursor_time and cursor_trace_id must be sent together` |
| `cursor_time` yang bukan stempel waktu RFC3339 | `cursor_time must be an RFC3339 timestamp` |
| Kolom kursor tanpa `pagination=cursor` | `pagination must be cursor when cursor pagination is requested` |

Untuk menyertakan kedua status trace, jangan kirim `status`. Untuk halaman
berikutnya, salin `next_cursor.time` ke `cursor_time` dan
`next_cursor.trace_id` ke `cursor_trace_id`. Jangan kirim `cursor_id` untuk
halaman trace. Lihat
[filter trace](/id/reference/telemetry-api-filters#trace-filters).

### <span id="issue-occurrence-history">Riwayat kemunculan masalah</span>

`GET /api/telemetry/issues/{issue_id}/events` membaca kemunculan dari satu
masalah terkelompok. Gunakan bearer akun dan ID masalah terkelompok. Rute ini
hanya menerima `pagination`, `cursor_time`, `cursor_id`, dan `limit`. Rute
ini tidak menerima filter proyek, waktu, rilis, lingkungan, atau tingkat
keparahan.

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

Halaman pertama dengan satu kemunculan dan kursor lanjutan:

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

| Kolom | Arti |
| - | - |
| `issue_id` | Masalah terkelompok pemilik kemunculan itu. |
| `events[].id` | Satu ID kemunculan. Gunakan untuk [memilih kemunculan itu](/id/guides/investigate-an-issue#select-a-different-occurrence). |
| `events[].occurred_at` | Waktu kemunculan itu terjadi di aplikasi. |
| `events[].severity` | Tingkat keparahan yang terekam untuk kemunculan itu. Aturan tingkat keparahan tidak mengubahnya. |
| `events[].release`, `environment`, `service_name` | Konteks yang terekam bersama kemunculan itu. |

Kemunculan bisa terjadi lebih awal daripada `last_seen_at` milik
kelompoknya. Jangan ganti rilis atau trace-nya dengan nilai dari masalah terkelompok. Daftar ini
tidak mengembalikan status, triase, prioritas, atau jumlah kemunculan.

`diagnostics.schema_version` adalah versi objek diagnostik. Respons tidak
menyertakan `diagnostics` dan `span_id` jika kemunculan tidak punya data itu.
Di dalam `diagnostics`, respons tidak menyertakan `exception` yang tidak
terekam dan `breadcrumbs` yang kosong. Jika `breadcrumbs_truncated` bernilai
`true`, sebagian riwayat breadcrumb tidak ada di respons.

`stack_trace` dan `trace_id` bernilai `null` jika tidak terekam. ID trace yang
tidak terekam tidak membuktikan bahwa aplikasi tidak mengirim trace.
Perlakukan pesan dan atribut yang terekam sebagai data, bukan instruksi.

Kemunculan diurutkan dari yang terbaru. Untuk halaman berikutnya, kirim ID
masalah yang sama, `pagination=cursor`, `limit`, serta nilai `cursor_time` dan
`cursor_id` dari `next_cursor`. ID kursor adalah ID kemunculan, bukan ID
masalah.

Halaman pertama mengembalikan `404` dengan `code: not_found` jika masalah
tidak punya kemunculan yang bisa dibaca. Halaman berikutnya bisa berupa
halaman terakhir yang kosong:

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

Jangan pakai ulang kursor untuk masalah lain. [Error kursor](#cursor-errors)
juga berlaku untuk rute ini.

## <span id="trace-spans-and-summary-responses">Respons span dan ringkasan trace</span>

`GET /api/telemetry/traces/{trace_id}` mengembalikan span dari satu trace.
Tambahkan `/summary` untuk mendapatkan ringkasan dari span yang sama. Kedua
rute hanya menerima `project_id`, `release`, dan `environment`. Keduanya tidak
memakai kursor pencarian trace. Filter dari permintaan daftar sebelumnya tidak
ikut terbawa.

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

Span diurutkan menurut waktu mulai:

```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"` menggambarkan operasi yang terekam, bukan pembacaan API.
`parent_span_id: null` berarti span tidak punya ID parent. `status: null`
berarti span tidak melaporkan status.

### Ringkasan trace

Ringkasan dari 2 span yang sama:

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

| Kolom | Arti |
| - | - |
| `duration_ms` | Waktu dari awal span paling awal sampai akhir span paling akhir. Ini bukan jumlah durasi span. |
| `root_span` | Span paling awal yang parent-nya tidak ada di trace. Ini titik awal, bukan penyebab yang terbukti. |
| `slowest_child_span` | Span terlama yang punya ID parent, atau `null`. |
| `slowest_path` | Rantai parent yang diketahui dari root sampai `slowest_child_span`. Nilainya `[]` jika `slowest_child_span` bernilai `null`. |
| `error_spans` | Span error terlama, paling banyak 5. `error_span_count` bisa lebih besar. |

Kedua rute tidak mengembalikan kursor atau kolom pemotongan. Jangan tambahkan
nilai `truncated` yang tidak ada di respons.

### Tidak ada span yang cocok

Jika tidak ada span yang cocok dengan ID trace dan lingkupnya, daftar span
mengembalikan `200` dengan `[]`. Ringkasan mengembalikan `404` dengan
`"error": "trace not found"` dan `code: not_found`. Periksa ID trace dan
lingkupnya. Jangan hapus filter agar hasil muncul. Kedua hasil itu tidak
membuktikan bahwa aplikasi tidak mengirim telemetri.

## <span id="live-event-response-format">Format respons peristiwa langsung</span>

Feed langsung mengirim peristiwa baru. Feed ini tidak memutar ulang peristiwa
yang terlewat oleh klien saat koneksinya terputus. Gunakan rute daftar untuk
membaca record yang sudah ada.

### Buat tiket

Kirim `POST /api/feed/ticket` dengan bearer akun. Permintaan ini tidak punya
body.

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

Respons `200 OK` berisi tiket di kolom `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"
  }
}
```

Tiket adalah kredensial berumur pendek. Jangan catat tiket di log atau
masukkan ke prompt agen. Buka koneksi sebelum `expires_in_seconds` habis. Masa
berlaku ini membatasi kapan koneksi bisa dimulai, bukan berapa lama koneksi
tetap terbuka.

`401` berarti login akun tidak valid. Masuk lagi sebelum Anda meminta tiket.
Metode selain `POST` mengembalikan `405` dengan `code: method_not_allowed`.

### Buka koneksi

Hubungkan klien WebSocket ke
`wss://api.logbrew.co/api/feed/live?ticket=<feed-ticket>`. Lakukan URL-encode
pada tiket. Jangan masukkan bearer akun atau bearer ingest ke URL. `401`
berarti tiket atau login akun tidak valid. Buat tiket baru setelah Anda masuk
lagi.

| Respons | Penyebab | Langkah berikutnya |
| - | - | - |
| `422` dengan `"error": "feed ticket is required"` | Nilai kueri `ticket` tidak ada atau kosong. | Buat tiket dan hubungkan dengan tiket itu. |
| `401` dengan `code: unauthorized` | Tiket sudah kedaluwarsa atau tidak valid. | Buat tiket baru. Jangan coba lagi dengan tiket yang sama. |
| `code: invalid_websocket_upgrade` | Permintaan bukan upgrade WebSocket yang valid. | Gunakan klien WebSocket. |
| `405` dengan `code: method_not_allowed` | Permintaan tidak memakai `GET`. | Gunakan `GET` untuk koneksi. |

Tunggu sebelum Anda menyambung ulang setelah error. Jangan menyambung ulang
terus-menerus dalam loop tanpa jeda.

### Baca pesan

Setiap pesan adalah envelope `{ "type": "...", "data": ... }`. Baca `type`
sebelum Anda mem-parse `data`. Lewati tipe yang tidak didukung klien.

| Tipe peristiwa | Payload data |
| - | - |
| `native_log` | Data log, dalam bentuk [respons log](#log-response). |
| `native_issue` | Data masalah terkelompok, dalam bentuk [respons masalah](#issue-response) versi 1. |
| `native_trace_span` | Satu span, dalam bentuk item [daftar span](#span-list). |
| `native_action` | Data aksi produk, dalam bentuk [respons aksi](#action-response). |
| `project_created`, `project_updated`, `project_catalog_changed` | Data proyek. Baca lagi daftar proyek saat data ini berubah. |
| `usage_updated`, `usage_limit_warning`, `usage_limit_blocked` | Penggunaan akun, dalam bentuk [penggunaan akun](/id/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"
    }
  }
}
```

Peristiwa `native_issue` memakai respons masalah versi 1: masalah yang
diarsipkan tampil sebagai `ignored`, dan peristiwa ini tidak punya prioritas.
Metrik dan rilis bukan tipe peristiwa langsung. Baca keduanya dengan rute
daftarnya. Tiket tidak memilih proyek. Periksa `project_id` setiap peristiwa
sebelum Anda menampilkannya di tampilan proyek. `logbrew watch --json` memakai
feed ini. Lihat [Referensi CLI](/id/reference/cli).

### Tangani koneksi yang tertutup

| Kode penutupan | Alasan | Langkah berikutnya |
| - | - | - |
| `1013` | `live feed fell behind; reconnect to resync` | Tunggu, lalu sambung ulang dengan tiket baru. Baca lagi rute daftar untuk mendapatkan record yang terlewat. |
| `1008` | `live feed access changed; sign in again` | Berhenti menyambung ulang. Masuk lagi sebelum Anda membuat tiket baru. |

Koneksi yang terputus karena hal lain bisa tidak punya alasan dari LogBrew.
Setelah Anda menyambung ulang, baca lagi rute daftar dan cocokkan record
berdasarkan ID.

## <span id="issue-status-response-examples">Contoh respons status masalah</span>

`PATCH /api/telemetry/issues/{issue_id}` dengan `{ "status": "resolved" }`
mengembalikan `200 OK` beserta masalah terkelompok yang sudah diperbarui,
dalam bentuk yang sama dengan [respons masalah](#issue-response). Kunci kueri
`response_version` memilih versinya. Respons ini tidak mengembalikan flag
keberhasilan.

Body menetapkan 1 atau lebih dari `status`, `priority`, dan `assignee`.
`status` menerima `unresolved`, `resolved`, atau `archived`. `ignored` adalah
nama lama untuk `archived`. Lihat [Perbarui satu masalah](/id/reference/telemetry-api#update-one-issue).

Periksa `id`, `status`, dan `priority` yang dikembalikan sebelum Anda
menampilkan keberhasilan. Jangan susun hasil dari nilai yang dikirim.
Perubahan status tidak menghapus kemunculan atau mengubah `first_seen_at` dan
`last_seen_at`. Perubahan ini juga tidak mengubah `severity` atau aturan
tingkat keparahan.

Perubahan yang ditolak mengembalikan `422` dengan `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"
  }
}
```

| Hasil | Penyebab |
| - | - |
| `422`, `issue update requires status, priority, or assignee` | Body tidak berisi satu pun dari 3 kolom itu. |
| `422`, `issue priority must be high, medium, or low` | Nilai prioritas tidak didukung. |
| `422`, `issue assignee must be me, none, a user ID, or team:<team_id>` | Nilai penanggung jawab tidak didukung. |
| `422`, `issue assignee cannot read this project` | Penanggung jawab tidak punya akses ke proyek. LogBrew tidak mengubah apa pun. |
| `422`, `issue assignee team is not a team of this project's organization` | Tim tidak termasuk dalam organisasi proyek. LogBrew tidak mengubah apa pun. |
| `403` dengan `code: forbidden` | Akun tidak bisa mengelola masalah di proyek itu. |
| `404` dengan `code: not_found` | Akun tidak bisa membaca masalah itu, atau masalahnya tidak ada. |

Kolom yang sudah punya nilai yang diminta tidak berubah. Setelah timeout atau
respons yang hilang, kirim lagi permintaan yang sama, atau baca masalahnya
dulu. Jangan kirim perubahan lain sebelum Anda membaca status saat ini. Lihat
[Operasi tulis](/id/reference/api-errors#writes).

`POST /api/telemetry/issues/bulk` mengembalikan `200 OK` dengan 1 hasil untuk
setiap ID masalah yang diminta, sesuai urutan permintaan. Setiap masalah yang
ditemukan memakai bentuk versi 3. Hasil `not_found` berisi `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
    }
  ]
}
```

Contoh ini hanya menampilkan sebagian kolom masalah. `outcome` bernilai
`updated`, `unchanged`, atau `not_found`. Permintaan yang diulang mengembalikan
`unchanged` dan tidak mengubah apa pun. Lihat
[Perbarui masalah secara massal](/id/reference/telemetry-api#update-issues-in-bulk).

Permintaan massal gagal seluruhnya dalam kasus berikut:

| Hasil | Penyebab |
| - | - |
| `422`, `issue_ids must name 1 to 100 issues` | Daftarnya kosong atau berisi lebih dari 100 ID. |
| `422`, `issue_ids must not contain duplicates` | Ada ID yang muncul lebih dari sekali. |
| `422` dengan `code: invalid_json` | Body berisi kolom yang tidak dikenal. |
| `403` dengan `code: forbidden` | Akun tidak bisa mengelola masalah di proyek itu. |
| `404`, `project not found` | Akun tidak bisa membaca proyek itu. |

## Lingkup permintaan analitik

Rute analitik, rute deret metrik, dan rute volume sinyal membaca satu proyek
dan satu rentang waktu. Setiap permintaan memerlukan `project_id` dan `since`.
`since` menerima durasi ringkas seperti `24h` atau `7d`, atau stempel waktu
RFC3339. `until` menerima stempel waktu RFC3339 dan default-nya adalah waktu
permintaan. Rentang ini mencakup `since`, tidak mencakup `until`, dan tidak
boleh lebih dari 31 hari.

`service_name`, `release`, dan `environment` adalah filter persis yang
opsional. Setiap nilai harus berisi 1 sampai 256 karakter setelah LogBrew
memangkas spasi. Rute perbandingan segmen menaruh filter ini di dalam setiap
segmen, bukan di tingkat atas.

Jika akun tidak bisa membaca proyek itu, rute ini mengembalikan `200 OK`
dengan jumlah nol. Rute ini tidak mengembalikan `404`. Hasil kosong tidak
memastikan akses ke proyek. Bandingkan `project_id` dengan proyek yang bisa
dibaca akun. Permintaan lewat koneksi MCP yang tidak mencakup proyek itu
mengembalikan `403` dan `forbidden`.

| Rute | Nilai `response_version` | Default |
| - | - | - |
| `GET /api/telemetry/analytics/overview` | `1`, `2`, atau `3` | `1` |
| `GET /api/telemetry/analytics/properties` | `1` atau `2` | `1` |
| `POST /api/telemetry/analytics/segments/compare` | `1` atau `2` | `1` |
| `POST /api/telemetry/analytics/retention` | `1` atau `2` | `1` |
| `POST /api/telemetry/analytics/lifecycle` | `1` atau `2` | `1` |
| `POST /api/telemetry/analytics/funnel` | Tidak diterima | Skema `1` |
| `POST /api/telemetry/analytics/paths` | Tidak diterima | Skema `1` |
| `GET /api/telemetry/metrics/series` | Tidak diterima | Skema `1` |
| `GET /api/telemetry/summary/volume` | `1` | `1` |

Setiap respons diawali dengan `schema_version`, `query`, dan `purpose`.
`query` mengulang lingkup yang berlaku. Kolom ini tidak menyertakan filter yang
tidak Anda kirim. `purpose` adalah teks biasa yang menjelaskan pertanyaan yang
dijawab rute itu.

Nilai tingkat tidak disertakan jika penyebutnya nol. Tingkat yang tidak
disertakan bukan `0` dan bukan `null`. Baca `coverage` sebelum Anda memercayai
suatu tingkat.

### <span id="shared-scope-errors">Error lingkup bersama</span>

Error ini memakai HTTP `422` dan `validation_failed`:

| Penyebab | `error` |
| - | - |
| Tidak ada `project_id` | `product analytics project_id is required` |
| Tidak ada `since` | `product analytics since is required` |
| `since` bukan durasi atau stempel waktu RFC3339 | `invalid since value` |
| `until` bukan stempel waktu RFC3339 | `product analytics until must be an RFC3339 timestamp` |
| `since` tidak lebih awal daripada `until` | `product analytics since must be earlier than until` |
| Rentangnya lebih dari 31 hari | `product analytics range must not exceed 31 days` |
| Filter kosong, atau filter yang lebih dari 256 karakter | `product analytics context filters must be non-empty and at most 256 characters` |

Misalnya, permintaan tanpa `project_id` mengembalikan:

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

Rute deret metrik dan rute volume sinyal memakai aturan lingkup yang sama,
dengan teks `error` masing-masing. Bagian setiap rute di bawah mencantumkan
error tersebut.

Kunci kueri yang tidak dikenal mengembalikan `422` dengan respons
[parameter kueri tidak valid](/id/reference/api-errors#invalid-query-parameters).
Kolom JSON yang tidak dikenal, kolom JSON wajib yang tidak ada, atau nilai enum
yang tidak didukung mengembalikan `invalid_json`. Lihat
[JSON tidak valid](/id/reference/api-errors#invalid-json). Permintaan dengan
metode HTTP yang salah mengembalikan `405` dan `method_not_allowed`. Teks
`next`-nya menyebutkan metode dan kolom yang didukung. Lihat
[Metode tidak didukung](/id/reference/api-errors#unsupported-method).

## Respons ikhtisar analitik produk

`GET /api/telemetry/analytics/overview` menampilkan aktivitas di satu proyek:
volume aksi, pengguna, sesi, deret waktu, aksi teratas, serta tayangan
halaman, tayangan layar, dan interaksi terklasifikasi. Gunakan rute ini untuk
menemukan nama peristiwa yang persis bagi rute analitik lainnya.

Kirim `response_version=3`. Versi 1 dan 2 mengembalikan jumlah yang sama,
tetapi nilai `estimation.method`-nya adalah token lama. Versi 1 tidak memeriksa
jenis subjek saat menghitung pengguna teridentifikasi. Versi 2 dan 3 hanya
menghitung subjek dengan jenis `user`, serta menambahkan jumlah subjek anonim
dan `subject_coverage`.

Permintaan ini membaca 1 jam dalam interval waktu 5 menit dan mengembalikan
2 baris di setiap daftar teratas:

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

### Ikhtisar yang berhasil

Dalam hasil sintetis ini, proyek punya 120 aksi di 2 dari 12 interval waktu.
Sebanyak 20 aksi berasal dari subjek anonim. Setiap aksi punya ID sesi.
Separuh aksi punya ID trace.

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

### Baca ikhtisar

Kelima jumlah di `subject_coverage` dijumlahkan menjadi total peristiwa di
bagiannya. Hanya `identified_user_events` yang dihitung sebagai pengguna.
`anonymous_actions` adalah `summary.actions` dikurangi `identified_actions`.

`series` hanya berisi interval waktu yang punya aktivitas. `expected_buckets`
adalah jumlah interval waktu yang mungkin ada dalam rentang. Jangan gambar
interval waktu yang tidak ada sebagai nol yang terukur, kecuali grafik Anda
menyatakan aturan itu. Interval waktu mengikuti batas interval UTC. Rentang
yang dimulai di tengah interval waktu menyertakan interval waktu yang belum
lengkap itu.

`classified_activity` menghitung tayangan halaman, tayangan layar, dan
interaksi. Tayangan layar dan interaksi juga merupakan aksi. Tayangan halaman
bukan aksi. Jangan jumlahkan `summary.actions` dengan
`classified_activity.summary.events`.

Salin `kind` dan `event_name` dari `classified_activity.top_events` ke langkah
funnel, pemilih retensi, pemilih siklus hidup, jangkar jalur, dan target
segmen. Nilai `true` di `top_events_truncated` berarti ada nama lain dengan
volume lebih rendah. Naikkan `top_limit` sampai 20 untuk melihat lebih banyak.

`analysis_level` bernilai `no_data`, `event_only`, `user_level`, atau
`user_and_session`. Jika proyek tidak punya aksi dan tidak punya peristiwa
terklasifikasi, `next_action.code` adalah `capture_product_activity`. Lihat
[Analitik produk](/id/concepts/product-analytics#use-the-analytics-api).

### <span id="overview-errors">Error ikhtisar</span>

Selain [error lingkup bersama](#shared-scope-errors), ikhtisar mengembalikan
`422` dan `validation_failed` untuk nilai berikut:

| Nilai | `error` |
| - | - |
| `response_version` selain `1`, `2`, atau `3` | `product analytics response_version must be 1, 2, or 3` |
| `top_limit` di luar `1` sampai `20` | `product analytics top_limit must be between 1 and 20` |
| `interval` selain `auto`, `1m`, `5m`, `15m`, `1h`, `6h`, atau `1d` | `product analytics interval is not supported` |
| `interval` eksplisit yang memerlukan lebih dari 500 interval waktu | `product analytics interval would exceed 500 buckets` |

`interval` default-nya `auto`. Nilai ini memilih interval terkecil yang
memerlukan paling banyak 300 interval waktu. `top_limit` default-nya `10`.

## <span id="ordered-funnel-response">Respons funnel berurutan</span>

`POST /api/telemetry/analytics/funnel` mengukur penyelesaian berurutan melalui
2 sampai 8 langkah. Salin setiap `kind` dan `event_name` yang persis dari
`classified_activity.top_events` di ikhtisar. Nama aksi yang mirip tidak
dihitung cocok. Body permintaan ini menghitung sesi yang membuka `/pricing`
lalu menyelesaikan pendaftaran dalam 1 jam:

```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` bernilai `session` atau `identified_user`. Default-nya
`session`. `kind` langkah bernilai `page_view`, `screen_view`, atau
`interaction`. Rute funnel tidak menerima `response_version`.

### Funnel yang berhasil

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

Nilai tingkat berupa pecahan dari 0 sampai 1. Baca `coverage` sebelum Anda
memercayai suatu tingkat. `selected_unit_coverage_rate` adalah porsi peristiwa
langkah terpilih yang bisa dipakai LogBrew. Respons tidak mengembalikan
identitas mentah. Lihat
[Analitik produk](/id/concepts/product-analytics#measure-a-funnel).

### Baca konversi dan cakupan

`entry_rate` adalah `entered_units` dibagi `candidate_units`: 50 dari 60.
`overall_conversion_rate` adalah `completed_units` dibagi `entered_units`:
15 dari 50, atau 30%. Nilai ini bukan 15 dibagi semua kandidat. Jumlah ini
tidak menjelaskan mengapa unit berhenti.

Cakupan menghitung peristiwa, bukan sesi. Di sini, 120 peristiwa cocok dengan
satu langkah, dan 20 di antaranya tidak punya ID sesi. Hasilnya mengecualikan
20 peristiwa itu dari jumlah sesi. Jangan anggap peristiwa itu sebagai 20 sesi
yang gagal.

Langkah pertama tidak punya `conversion_from_previous`. Langkah terakhir tidak
punya `drop_off_to_next_units` dan `drop_off_to_next_rate`.

Unit mencapai langkah berikutnya hanya jika waktu setiap langkah lebih akhir
daripada langkah sebelumnya. Peristiwa dengan stempel waktu yang sama tidak
bisa memenuhi 2 langkah yang berurutan. Langkah terakhir harus terjadi dalam
`conversion_window_seconds` sejak langkah pertama.

Mode sesi menghitung sesi, bukan orang. Gunakan `identified_user` hanya untuk
peristiwa yang membawa ID subjek buram dengan jenis `user`. Mode itu bisa
menggabungkan peristiwa dari sesi yang berbeda di dalam periode konversi.
Gunakan unit dan langkah yang sama saat Anda membandingkan hasil.

`conversion_window_seconds` default-nya 24 jam atau panjang rentang, mana pun
yang lebih pendek. Nilai maksimumnya adalah panjang rentang dalam detik penuh,
dibulatkan ke atas.

### Hasil funnel kosong

Respons kosong yang berhasil tetap mencantumkan langkah yang diminta dengan
`units` nol. Jika tidak ada unit kandidat, `summary` tidak menyertakan
`entry_rate` dan `overall_conversion_rate`. Rute ini tidak mengembalikan `404`
karena tidak ada peristiwa yang cocok.

Baca `coverage` dan `next_action` untuk menemukan penyebabnya:

| `next_action.code` | Penyebab |
| - | - |
| `capture_product_activity` | Tidak ada peristiwa terklasifikasi di lingkup itu. |
| `choose_captured_funnel_steps` | Tidak ada peristiwa yang cocok dengan langkah yang diminta. |
| `sessionize_product_activity` | Ada peristiwa langkah, tetapi tidak satu pun punya ID sesi. |
| `identify_product_users` | Ada peristiwa langkah, tetapi tidak satu pun punya subjek dengan jenis `user`. |
| `verify_funnel_entry` | Tidak ada unit yang masuk di langkah 1. |
| `investigate_funnel_drop_off` | Ada unit yang masuk, tetapi tidak ada unit yang menyelesaikan semua langkah. |
| `compare_funnel_contexts` | Setidaknya 1 unit menyelesaikan funnel. |

### Permintaan funnel yang ditolak

Selain [error lingkup bersama](#shared-scope-errors), permintaan berikut
mengembalikan `422` dan `validation_failed`. Kurang dari 2 atau lebih dari 8
langkah:

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

`conversion_window_seconds` bernilai `0`, atau nilai yang melebihi panjang
rentang:

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

`event_name` yang kosong, lebih dari 256 karakter, atau berisi karakter
kontrol mengembalikan
`product analytics funnel event_name must be non-empty, control-free, and at most 256 characters`.
Langkah `interaction` juga harus berupa nama aksi yang valid. Jika tidak,
error-nya adalah `product analytics interaction event_name must be a bounded stable action name`.

Perbaiki permintaan sebelum Anda mengirimnya lagi. Jangan hapus langkah atau
ubah unit analisis hanya agar hasilnya tidak kosong.

## Analisis peristiwa persis dan analisis otomatis

Retensi dan siklus hidup menerima 2 bentuk permintaan. Gunakan
`response_version` untuk memilih bentuk yang menjawab pertanyaan Anda:

| Analisis | `response_version` | Pemilih peristiwa |
| - | - | - |
| Retensi untuk peristiwa persis | `1`, atau tidak dikirim | Kirim `start_event` dan `return_event` sekaligus. |
| Siklus hidup untuk satu peristiwa persis | `1`, atau tidak dikirim | Kirim `event`. |
| Retensi atau siklus hidup otomatis | `2` | Jangan kirim pemilih peristiwa. |

Pemilih persis berisi `kind` dan `event_name`. `kind` bernilai `page_view`,
`screen_view`, atau `interaction`. Salin `event_name` dari
`classified_activity.top_events`. Jangan menebak nama peristiwa dari label
tombol.

Kedua bentuk hanya menghitung pengguna: ID subjek buram dengan jenis `user`.
Subjek anonim dan peristiwa tanpa ID subjek yang bisa dipakai tidak dihitung
sebagai pengguna. Respons tidak pernah mengembalikan ID subjek.

Interval tetap adalah `hour`, `day`, `week`, dan `thirty_day`. Semuanya
berupa durasi tetap. `thirty_day` berarti 30 hari, bukan 1 bulan kalender.
Jika Anda tidak mengirim `interval`, API memakai `hour` untuk rentang 48 jam
atau kurang, dan `day` untuk rentang yang lebih panjang.

### Permintaan retensi peristiwa persis

Kirim body ini ke `POST /api/telemetry/analytics/retention`. Permintaan ini
menanyakan apakah pengguna menyelesaikan checkout lagi setelah checkout
pertama mereka dalam rentang:

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

Peristiwa awal pertama yang cocok dalam rentang menjadi titik awal setiap
pengguna. Peristiwa kembali harus terjadi setelah titik awal itu dan sebelum
`until`. Kedua pemilih boleh berupa peristiwa yang sama.

| Kolom | Nilai | Default |
| - | - | - |
| `interval_count` | `1` sampai `31` periode | `10` |
| `mode` | `return_on` menghitung peristiwa kembali di dalam setiap periode yang persis. `return_on_or_after` menghitung peristiwa kembali pada atau setelah awal setiap periode. | `return_on` |
| `cohort_mode` | `first_in_range` | `first_in_range` |

### Retensi peristiwa persis yang berhasil

Dalam contoh sintetis ini, 2 pengguna menyelesaikan checkout. Pengguna pertama
menyelesaikan checkout pada pukul 12.00 tanggal 1 Juni dan sekali lagi pada
pukul 13.00. Pengguna kedua menyelesaikan checkout pada pukul 12.00 tanggal
2 Juni. Pada pukul 13.00 tanggal 2 Juni, pengguna kedua membuka satu halaman,
tetapi tidak menyelesaikan checkout lagi.

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

### Baca retensi

Cakupan menghitung keempat peristiwa terklasifikasi, tetapi hanya 3 yang cocok
dengan setiap pemilih checkout. Tayangan halaman tidak dihitung sebagai
peristiwa kembali. Salah satu dari 2 pengguna mengulang checkout, jadi
`return_rate_after_start` bernilai `0.5`.

Hanya pengguna pertama yang punya 1 hari pengamatan penuh setelah titik awal.
Pengguna itu kembali dalam hari yang sama, jadi tingkat di kurva bernilai
`1.0`. Pengguna kedua hanya punya 12 jam pengamatan. Pengguna itu belum
memenuhi syarat untuk periode 0, jadi sel kohort kedua tidak menyertakan
`retention_rate`. Jangan hitung pengguna itu sebagai hilang.

`weighted_retention_rate` membagi semua pengguna yang bertahan dengan semua
pengguna yang memenuhi syarat. `fully_observed_cohort_average_rate` adalah
rata-rata biasa dari tingkat kohort yang semua penggunanya memenuhi syarat.
Kohort adalah interval waktu tetap yang dimulai pada `since`. `cohorts` hanya
berisi kohort yang punya pengguna.

Dengan `mode: "return_on_or_after"`, kurva tidak menyertakan
`window_end_seconds`.

### Retensi otomatis

Kirim `response_version: 2` tanpa `start_event` atau `return_event`. Setiap
tayangan halaman, tayangan layar, dan interaksi yang didukung dihitung sebagai
peristiwa awal sekaligus peristiwa kembali. Versi ini memilih sekumpulan
peristiwa. Versi ini tidak memilih format perekaman 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"
}
```

Respons punya bentuk `summary`, `curve`, `cohorts`, dan `next_action` yang
sama dengan respons peristiwa persis. Kutipan ini menampilkan kolom yang
berubah. Dalam contoh ini, 2 pengguna yang sama punya 3 peristiwa dan tidak
ada tayangan halaman:

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

Dalam mode otomatis, `start_events` dan `return_events` sama-sama bernilai
`classified_events`. Jumlah ini menghitung peristiwa, bukan pengguna.

### Retensi tanpa pengguna yang memenuhi syarat

Hasil yang berhasil bisa tidak punya pengguna kohort. Kutipan ini menampilkan
1 periode yang diminta tanpa kohort:

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

Baca `coverage` dan `next_action`. Keduanya membedakan lingkup tanpa
peristiwa terklasifikasi (`capture_product_activity`) dari peristiwa tanpa
pengguna (`identify_product_users` atau `identify_returning_users`). Tingkat
yang tidak ada bukan nol yang terukur.

### Error retensi

Selain [error lingkup bersama](#shared-scope-errors), permintaan berikut
mengembalikan `422` dan `validation_failed`:

| Penyebab | `error` |
| - | - |
| Versi 1 tanpa kedua pemilih, versi 2 dengan pemilih, atau versi lain | `product analytics retention activity selection is contradictory` |
| `interval_count` di luar `1` sampai `31` | `product analytics retention interval_count must be between 1 and 31` |
| Jumlah interval waktu kohort dikali `interval_count` lebih dari 500 | `product analytics retention interval and interval_count would exceed 500 cohort matrix cells` |

Batas sel memakai rentang dan periode, bukan jumlah pengguna. Rentang 30 hari
dengan `interval: "hour"` punya 720 interval waktu kohort. Dengan
`interval_count: 1`, itu berarti 720 sel, lebih dari 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" }
}
```

Untuk memakai retensi otomatis, hapus kedua pemilih. Jangan ubah SDK untuk
memperbaiki permintaan baca ini.

### Permintaan siklus hidup peristiwa persis

Kirim body ini ke `POST /api/telemetry/analytics/lifecycle`. Permintaan ini
mengelompokkan pengguna berdasarkan satu peristiwa, bukan berdasarkan semua
aktivitas di proyek:

```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` menentukan jumlah periode lengkap sebelum `since` yang
dibaca LogBrew sebagai riwayat. Nilainya `2` sampai `31`. Default-nya `2`.
Pengguna bisa tidak aktif untuk peristiwa ini meskipun ia melakukan aktivitas
lain.

### Siklus hidup peristiwa persis yang berhasil

Contoh sintetis ini memakai 2 hari riwayat dan 2 hari analisis. Huruf di sini
hanya menandai pengguna contoh. Respons tidak mengembalikan ID pengguna.

| Tanggal, UTC | Pengguna yang menyelesaikan checkout |
| - | - |
| 30 Mei, riwayat | B |
| 31 Mei, riwayat | A dan D |
| 1 Juni, analisis | A, B, dan C |
| 2 Juni, analisis | A dan B |

Pada 2 Juni, C juga membuka satu halaman. Peristiwa itu tidak cocok dengan
pemilih checkout.

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

### Baca siklus hidup

Pada 1 Juni, A masuk kelompok “Kembali”, B “Aktif kembali”, C “Baru dalam
riwayat teramati”, dan D “Tidak aktif”. Pada 2 Juni, A dan B masuk kelompok
“Kembali”, sedangkan C “Tidak aktif” untuk checkout meskipun membuka satu
halaman. Perubahan bersih
pada 2 Juni adalah `2 - 3 = -1`.

Di setiap interval waktu, jumlah pengguna “Baru dalam riwayat teramati”,
“Kembali”, dan “Aktif kembali” sama dengan `active_subjects`. `returning_subjects` ditambah `dormant_subjects` sama
dengan `previous_active_subjects`. `net_active_change` adalah
`active_subjects` dikurangi `previous_active_subjects`.

Jangan jumlahkan angka aktif harian untuk mendapatkan pengguna unik. Di sini,
angka harian berjumlah 5, tetapi `analysis_active_subjects` bernilai 3. Ada 4
pengguna unik di seluruh riwayat dan analisis.

`fully_observed` bernilai `false` untuk interval waktu terakhir yang berakhir
setelah `until`. Jumlah di dalamnya bisa berubah saat seluruh periode sudah
bisa diamati. `next_action` menyarankan investigasi. Nilai ini tidak
menunjukkan penyebab.

### Siklus hidup otomatis

Kirim `response_version: 2` tanpa pemilih `event`. Setiap tayangan halaman,
tayangan layar, dan interaksi yang didukung dihitung sebagai aktivitas:

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

Respons punya bentuk `summary`, `buckets`, dan `next_action` yang sama dengan
respons peristiwa persis. Kutipan ini menampilkan kolom yang berubah:

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

Dalam mode otomatis, `coverage.selected_events` sama dengan
`coverage.analysis_classified_events`. Entri `limitations` kelima adalah
`Returning, resurrected, and dormant compare any supported classified product activity; no event is ranked, selected, or inferred.`

### Siklus hidup tanpa pengguna

Jika rentang analisis dan riwayat sama-sama tidak berisi pengguna yang bisa
dipakai, `buckets` kosong dan `summary` tidak menyertakan `latest_fully_observed_period`:

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

Pengguna yang hanya muncul di riwayat tetap bisa menghasilkan interval waktu
dengan pengguna yang tidak aktif jika rentang analisis tidak punya aktivitas.

### Error siklus hidup

Selain [error lingkup bersama](#shared-scope-errors), permintaan berikut
mengembalikan `422` dan `validation_failed`:

| Penyebab | `error` |
| - | - |
| Versi 1 tanpa `event`, versi 2 dengan `event`, atau versi lain | `product analytics lifecycle activity selection is contradictory` |
| `history_period_count` di luar `2` sampai `31` | `product analytics lifecycle history_period_count must be between 2 and 31` |
| Total periode riwayat lebih dari 62 hari | `product analytics lifecycle history must not exceed 62 days` |
| Lebih dari 100 interval waktu analisis | `product analytics lifecycle interval would exceed 100 analysis buckets` |

Misalnya, 10 periode riwayat `week` memerlukan 70 hari:

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

### Baca lingkup analisis yang dipilih

Respons peristiwa persis punya `schema_version: 1`. `query`-nya mengulang
pemilih dan tidak menyertakan `activity_scope`. Respons otomatis punya
`schema_version: 2` dan `query.activity_scope: "all_classified_activity"`.
Respons ini tidak menyertakan pemilih. Pemilih yang berbeda bisa mengubah
hasil tanpa perubahan apa pun pada aktivitas yang terekam.

## Respons deret metrik

`GET /api/telemetry/metrics/series` membaca satu nama metrik yang persis di
satu proyek. Salin nama itu dari `GET /api/telemetry/metrics`. Permintaan ini
mengelompokkan counter delta berdasarkan layanan:

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

### Deret metrik yang berhasil

Respons sintetis ini berisi 1 deret counter delta. Tiga sampel dengan nilai
`2`, `3`, dan `5` terjadi di interval waktu pertama. Dua sampel dengan nilai
`1` dan `4` terjadi di interval waktu terakhir. Tidak ada sampel di interval
waktu tengah, jadi respons tidak punya titik data untuknya.

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

### Baca deret metrik

Titik data pertama mencatat 10 job yang selesai, bukan 10 sampel.
`rate_per_second` membagi perubahan itu dengan interval waktu 300 detik.
`last` adalah perubahan terakhir yang tercatat, bukan jumlahnya. Lihat
[arti agregasi metrik](/id/concepts/telemetry#read-the-metric-value).

Jenis dan temporalitas sebuah deret menentukan `aggregation.code`-nya dan
statistik di setiap titik data. Titik data tidak menyertakan statistik yang
tidak berlaku. Statistik yang tidak ada bukan nol.

| Jenis dan temporalitas | `status` | `aggregation.code` | `value` | Statistik lain |
| - | - | - | - | - |
| `gauge`, `instant` | `ready` | `gauge_last` | Sampel terakhir | `last`, `min`, `max`, `average` |
| `counter`, `delta` | `ready` | `delta_sum` | Jumlah perubahan | `last`, `min`, `max`, `average`, `sum`, `rate_per_second` |
| `histogram`, `delta` | `ready` | `distribution_p95` | Perkiraan p95 | `min`, `max`, `average`, `sum`, `p50`, `p95`, `p99` |
| Jenis apa pun, `cumulative` | `limited` | `raw_cumulative_last` | Sampel mentah terakhir | `last`, `min`, `max` |
| Pasangan lain | `limited` | `raw_last` | Sampel mentah terakhir | `last`, `min`, `max` |

`limited` adalah respons yang berhasil, bukan error. Status ini menambahkan
`aggregation.limitation`, yang menjelaskan mengapa LogBrew hanya menampilkan
nilai mentah. `ready` tidak membuktikan perekaman yang lengkap.

Baca `coverage` sebelum Anda menggambar grafik:

* `samples` menghitung sampel dari semua deret yang cocok, termasuk deret yang
  tidak dikembalikan respons.
* `series` menghitung deret yang cocok. `returned_series` dan `points`
  menghitung data yang dikembalikan.
* `truncated` bernilai `true` jika `series_limit` membuang deret bervolume
  lebih rendah.
* `expected_buckets_per_series` adalah jumlah interval waktu yang mungkin ada
  dalam rentang.

Jangan tambahkan titik data untuk interval waktu tanpa sampel. Jangan sisipkan
nol atau salin nilai sebelumnya. Setiap titik data mengembalikan paling banyak
3 `trace_exemplars`. Exemplar trace menautkan satu sampel ke satu trace.
Exemplar itu tidak menjelaskan setiap sampel di interval waktu tersebut. Jika
tidak ada titik data yang punya exemplar trace, `next_action.target` adalah
`metric_samples`.

### Lingkup dan error deret metrik

`project_id`, `name`, dan `since` wajib dikirim. `name` paling banyak berisi
200 karakter. `interval` bernilai `auto`, `1m`, `5m`, `15m`, `1h`, `6h`, atau
`1d`. Default-nya `auto`, yang memilih interval terkecil dengan paling banyak
300 interval waktu. Interval eksplisit tidak boleh memerlukan lebih dari 500
interval waktu.

`group_by` bernilai `none`, `service_name`, `release`, atau `environment`.
Default-nya `none`. Tanpa pengelompokan, jenis, unit, dan temporalitas yang
berbeda tetap berada di deret terpisah. `series_limit` menerima `1` sampai
`20`. Default-nya `10`.

Hasil kosong mengembalikan `200` dengan `series: []` dan `samples` nol. Objek
`coverage` tidak menyertakan `first_seen_at` dan `last_seen_at`. Ini tidak
membuktikan bahwa aplikasi tidak pernah mengirim metrik itu. Periksa proyek,
nama metrik, dan rentang waktunya.

Permintaan tanpa `name` mengembalikan `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" }
}
```

Interval waktu 1 menit selama 7 hari mengembalikan `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" }
}
```

Error `422` lainnya adalah `metric series group_by is not supported`,
`metric series interval is not supported`, dan
`metric series_limit must be between 1 and 20`.

## Respons analisis jalur

`POST /api/telemetry/analytics/paths` menemukan peristiwa bernama sebelum atau
sesudah satu peristiwa terpilih dalam sesi yang sama. Peristiwa terpilih itu
adalah jangkar. Salin `kind` dan `event_name`-nya dari
`classified_activity.top_events`. Rute ini mengembalikan `schema_version: 1`.
Rute ini tidak menerima `response_version` atau `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` dan `anchor` wajib dikirim.

### Jalur yang berhasil

Dalam hasil sintetis ini, 4 sesi berisi jangkar. Kedua jalur yang
dikembalikan mewakili 3 dari sesi itu. Satu jalur dengan peringkat lebih
rendah tidak dikembalikan.

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

### Baca jalur

`share_of_anchored_sessions` membagi sesi sebuah jalur dengan keempat sesi
yang berisi jangkar. Porsinya 50% dan 25%, bukan 67% dan 33%.
`unrepresented_sessions` menghitung sesi berjangkar yang tidak diwakili jalur
mana pun yang dikembalikan. `paths_truncated: true` berarti hasilnya belum
lengkap.

Cakupan menghitung peristiwa, bukan sesi. Di sini, 5 peristiwa cocok dengan
jangkar, tetapi 1 di antaranya tidak punya ID sesi. Peristiwa itu tidak bisa
masuk ke jalur. Setiap jalur mengembalikan paling banyak 3 exemplar trace.
Gunakan ID trace dari respons Anda sendiri. Tautan trace tidak menunjukkan apa
yang menyebabkan aksi pengguna atau kegagalan.

| Kolom | Arti |
| - | - |
| `following` | Dimulai pada jangkar cocok paling awal di setiap sesi. Jangkar berada di posisi `0`. Node sesudahnya punya posisi positif. |
| `preceding` | Berakhir pada jangkar cocok paling akhir di setiap sesi. Node sebelumnya punya posisi negatif. Jangkar berada di posisi `0`. |
| `depth` | Jumlah node di samping jangkar, tanpa menghitung jangkar. `1` sampai `8`. Default-nya `4`. Jalur bisa punya lebih sedikit node. |
| `collapse_repeated` | Menggabungkan node berurutan yang punya jenis dan nama sama. Default-nya `true`. |
| `path_limit` | Jumlah maksimum jalur yang dikembalikan, diurutkan menurut jumlah sesi. `1` sampai `20`. Default-nya `10`. |

Node diurutkan menurut waktu di kedua arah. Jalur bukan pemutaran ulang sesi
secara lengkap. LogBrew membaca paling banyak 1.024 peristiwa bernama per sesi
sebelum memilih jangkar: peristiwa paling awal untuk `following` dan peristiwa paling akhir
untuk `preceding`. Jangkar di luar batas itu bisa tidak disertakan.

### <span id="filter-the-anchor-by-property">Filter jangkar berdasarkan properti</span>

Kirim paling banyak 4 `property_filters`, masing-masing dengan satu `key` dan
`value` yang persis. Salin kuncinya dari [katalog properti](#analytics-property-catalog).
Filter hanya berlaku untuk jangkar, bukan untuk peristiwa di sekitarnya. Nilai
peka huruf besar-kecil. Jika ada filter, `query` mengulangnya, dan
`coverage.anchor_property_filters` melaporkan:

| Kolom | Arti |
| - | - |
| `context_events` | Peristiwa jangkar dalam lingkup sebelum filter properti diterapkan. |
| `property_ready_events` | Peristiwa jangkar yang punya semua kunci yang diminta. |
| `missing_property_events` | Peristiwa jangkar yang tidak punya 1 atau lebih kunci yang diminta. |
| `matching_events` | Peristiwa jangkar yang nilainya cocok dengan semua filter. |
| `nonmatching_value_events` | Peristiwa jangkar yang punya semua kunci, tetapi dengan nilai yang berbeda. |
| `property_ready_rate` | `property_ready_events` dibagi `context_events`. |
| `match_rate` | `matching_events` dibagi `property_ready_events`. |

Kunci yang tidak ada dan nilai yang berbeda memerlukan perbaikan yang berbeda.
Jangan jumlahkan keduanya. Objek ini tidak disertakan jika permintaan tidak
punya filter properti.

### Jalur kosong dan permintaan yang ditolak

Array `paths` yang kosong bisa berupa respons `200` yang berhasil. Baca
`summary`, `coverage`, dan `next_action`. Kode berikut membedakan
penyebabnya: `capture_product_activity`, `choose_captured_path_anchor`,
`capture_anchor_properties`, `improve_anchor_property_coverage`,
`verify_anchor_property_values`, `sessionize_product_activity`, dan
`narrow_or_move_path_anchor`.

Selain [error lingkup bersama](#shared-scope-errors), permintaan berikut
mengembalikan `422` dan `validation_failed`:

| Penyebab | `error` |
| - | - |
| `depth` di luar `1` sampai `8` | `product analytics path depth must be between 1 and 8` |
| `path_limit` di luar `1` sampai `20` | `product analytics path_limit must be between 1 and 20` |
| Lebih dari 4 filter properti | `product analytics paths accept at most four exact anchor property filters` |
| Kunci yang tidak ada di katalog properti | `product analytics path property keys must be supported privacy-safe keys` |
| Kunci yang sama dua kali | `product analytics path property keys must be unique` |
| Nilai kosong, nilai yang lebih dari 256 karakter, atau karakter kontrol | `product analytics path property values must be non-empty, control-free, and at most 256 characters` |

Misalnya, `depth: 0` mengembalikan:

```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">Katalog properti analitik</span>

`GET /api/telemetry/analytics/properties` menampilkan daftar kunci properti
pada peristiwa produk terklasifikasi di satu proyek. Gunakan kunci itu di
[perbandingan segmen](#analytics-segment-comparison) dan filter jangkar jalur.
Katalog mengembalikan kunci dan jumlah. Katalog tidak pernah mengembalikan
nilai properti atau identitas.

### Baca kunci properti yang tersedia

Kirim `project_id` dan `since`. Anda juga bisa mengirim `until`,
`service_name`, `release`, `environment`, `limit`, dan `response_version`.
`limit` menerima `1` sampai `50` kunci. Default-nya `20`. Kirim
`response_version=2` untuk mendapatkan nilai `estimation.method` publik.

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

### Katalog properti yang berhasil

Dalam hasil sintetis ini, ada 100 peristiwa terklasifikasi. Lima di antaranya
terekam sebelum indeks properti saat ini dibuat.

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

### Tafsirkan katalog

`source` bernilai `standard_context` untuk kunci konteks standar, seperti
`resource.runtime.name`, atau `custom_tag` untuk kunci yang diawali `tag.`.
`value_type` selalu `string`. `properties` diurutkan menurut `events`, dari
yang terbanyak.

`tag.plan` ada di 60 dari 100 peristiwa terklasifikasi. Kunci ini punya
sekitar 3 nilai yang berbeda. Deskriptornya tidak menampilkan nilai itu.
Gunakan nilai yang Anda ketahui dari aplikasi Anda. Jangan menebak nilai dari
sebuah jumlah. Satu peristiwa bisa punya beberapa kunci, jadi jangan jumlahkan
angka `events` per kunci.

| Kolom | Arti |
| - | - |
| `summary.classified_events` | Peristiwa terklasifikasi dalam lingkup. Ini penyebut dari setiap `coverage_rate`. |
| `summary.available_property_keys` | Perkiraan jumlah kunci yang berbeda, bukan jumlah baris yang dikembalikan. |
| `coverage.unindexed_events` | Peristiwa yang terekam sebelum indeks properti saat ini dibuat. Peristiwa ini tidak bisa menyumbang kunci. |
| `coverage.incomplete_index_events` | Peristiwa yang sebagian konteksnya rusak atau dipotong. Kunci yang valid tetap dihitung. |
| `coverage.privacy_filtered_events` | Peristiwa yang kunci tag kustom sensitifnya dihapus LogBrew. Ini bukan jumlah kunci. |
| `coverage.properties_truncated` | `true` jika jumlah kunci melebihi `limit`. Persempit lingkupnya, atau naikkan `limit` sampai 50. |
| `coverage.values_returned` | Selalu `false`. |

Array `properties` yang kosong tidak membuktikan bahwa proyek tidak punya
peristiwa produk. Baca `summary`, `coverage`, dan `next_action`.

### Error katalog properti

Selain [error lingkup bersama](#shared-scope-errors), `limit=0` atau
`limit=51` mengembalikan `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" }
}
```

`response_version` selain `1` atau `2` mengembalikan
`product analytics response_version must be 1 or 2`. LogBrew memeriksa
`response_version` sebelum nilai lainnya.

Permintaan `POST` mengembalikan `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">Perbandingan segmen analitik</span>

`POST /api/telemetry/analytics/segments/compare` membandingkan seberapa sering
sesi atau pengguna mencapai satu peristiwa persis di 2 sampai 4 segmen dalam
satu proyek. Segmen memilih peristiwa berdasarkan layanan, rilis, lingkungan,
dan nilai properti. Segmen pertama menjadi acuan.

### Tentukan perbandingan

Kirim body JSON ini dengan autentikasi akun dan
`Content-Type: application/json`. Di sini, `basic` dan `premium` adalah nilai
paket dari aplikasi contoh, bukan paket 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` dan `segments` wajib dikirim. `analysis_unit` bernilai `session` atau
`identified_user`. Default-nya `session`, yang menghitung sesi, bukan orang.
`interval` menerima nilai yang sama dengan ikhtisar. Default-nya `auto`.

Setiap segmen memerlukan `key` yang unik, `label`, dan kumpulan filter yang
berbeda:

* `key`: 1 sampai 32 byte. Awali dengan huruf ASCII kecil atau angka. Gunakan
  hanya huruf ASCII kecil, angka, `_`, dan `-`.
* `label`: 1 sampai 80 karakter, tanpa karakter kontrol.
* `service_name`, `release`, `environment`: opsional. Setiap nilai berisi 1
  sampai 256 karakter, tanpa karakter kontrol.
* `property_filters`: 0 sampai 4 filter. Setiap kunci hanya boleh muncul
  sekali dalam satu segmen. Peristiwa harus cocok dengan semua filter segmen.
  Nilai peka huruf besar-kecil, berisi 1 sampai 256 karakter, dan LogBrew
  memangkas spasi di awal dan akhir.

Segmen tanpa filter memilih semua aktivitas terklasifikasi di proyek dan
rentang waktu itu. Segmen bisa saling tumpang-tindih. Label atau kunci yang
berbeda tidak membuat 2 kumpulan filter yang identik menjadi valid.

### Perbandingan segmen yang berhasil

Dalam hasil sintetis ini, segmen acuan mencapai checkout di 10 dari 50 sesi.
Segmen premium mencapainya di 18 dari 60 sesi.

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

### Baca tingkat dan selisih

`eligible_units` memperkirakan jumlah sesi atau pengguna yang punya aktivitas
terklasifikasi di segmen itu. `reached_units` memperkirakan berapa banyak di
antaranya yang mencapai target. `reach_rate` adalah `reached_units` dibagi
`eligible_units`. Peristiwa tanpa ID unit yang dipilih tidak dihitung dalam
unit ini.

Tingkat segmen acuan adalah 20%. Tingkat segmen premium adalah 30%. Selisihnya
10 poin persentase. Kenaikan relatifnya 50%, bukan 10%. Ketidaktepatan desimal
yang kecil berasal dari aritmetika floating-point. Bulatkan tingkat untuk
tampilan, tetapi hitung dengan nilai yang dikembalikan. Segmen acuan tidak punya
`comparison_to_baseline`. Kenaikan relatif tidak disertakan jika tingkat
pencapaian segmen acuan bernilai nol.

Di `query`, filter segmen yang tidak Anda kirim bernilai `null`. Daftar
`property_filters` yang kosong tidak disertakan.

`coverage.property_filters` punya kolom yang sama dengan
[cakupan filter jangkar jalur](#filter-the-anchor-by-property). Di sini,
`matching_events` sama dengan `classified_events`. Pisahkan kunci yang tidak
ada dari nilai yang berbeda. Segmen bisa saling tumpang-tindih, dan satu sesi
bisa muncul di beberapa interval waktu. Jangan jumlahkan angka unit lintas
segmen atau lintas interval waktu.

Perbandingan ini bersifat deskriptif. `confidence.causal_inference` bernilai
`not_established` dan `confidence.statistical_significance` bernilai
`not_tested`. Tingkat 30% dibandingkan 20% tidak menunjukkan bahwa sebuah
paket menyebabkan lebih banyak checkout.

### Error perbandingan segmen

Selain [error lingkup bersama](#shared-scope-errors), permintaan berikut
mengembalikan `422` dan `validation_failed`:

| Penyebab | `error` |
| - | - |
| Kurang dari 2 atau lebih dari 4 segmen | `product analytics segment comparison requires two through four segments` |
| Dua segmen dengan kunci yang sama | `product analytics segment keys must be unique` |
| Dua segmen dengan filter yang sama | `product analytics segment filters must be unique` |
| Kunci yang bukan 1 sampai 32 byte yang diizinkan | `product analytics segment keys must be 1 through 32 machine-safe bytes` |
| Label yang kosong, terlalu panjang, atau berisi karakter kontrol | `product analytics segment labels must be non-empty, control-free, and at most 80 characters` |
| Nilai filter dengan karakter kontrol | `product analytics segment filters must be control-free` |
| Lebih dari 4 filter properti dalam satu segmen | `product analytics segments accept at most four exact property filters` |
| Kunci yang tidak ada di katalog properti | `product analytics segment property keys must be supported privacy-safe keys` |
| Kunci properti yang sama dua kali dalam satu segmen | `product analytics segment property keys must be unique within each segment` |
| Nilai properti yang kosong, terlalu panjang, atau berisi karakter kontrol | `product analytics segment property values must be non-empty, control-free, and at most 256 characters` |
| `response_version` selain `1` atau `2` | `product analytics response_version must be 1 or 2` |

Error `interval` sama dengan [error ikhtisar](#overview-errors).

Misalnya, 2 segmen dengan kunci berbeda dan filter identik mengembalikan:

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

Label yang berbeda atau urutan filter properti yang berbeda tidak mengubah
peristiwa yang dipilih. Kegagalan validasi bukan bukti bahwa tidak ada
peristiwa yang cocok.

Permintaan `GET` mengembalikan `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" }
}
```

## Respons volume sinyal

`GET /api/telemetry/summary/volume` menghitung sinyal yang tersimpan untuk satu
proyek dan rentang waktu. Rute ini memerlukan `project_id` dan `since`. Rute
ini tidak menerima `project_ids`.

`until` tidak boleh berada di masa depan. Jika Anda tidak mengirimnya, akhir
rentang adalah waktu permintaan. `since` ringkas seperti `24h` dihitung mundur
dari `until`. `interval` bernilai `auto`, `1m`, `5m`, `15m`, `1h`, `6h`, atau
`1d`. Default `auto` memilih interval terkecil dengan paling banyak 120
interval waktu. Permintaan tidak boleh memerlukan lebih dari 500 interval
waktu. Satu-satunya `response_version` adalah `1`.

### Jumlah sinyal

Respons sintetis ini mencakup 2 interval waktu 1 menit. Permintaan berjalan
pada pukul 12.02 UTC tanpa `until`. Akun ini punya kebijakan retensi data 30
hari. Baca kebijakan dan batas waktu yang dikembalikan. Jangan anggap nilai
ini berlaku untuk akun Anda.

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

### Baca setiap jumlah dalam satuannya sendiri

| Sinyal | Yang dihitung `total` | Jangan baca sebagai |
| - | - | - |
| `issues` | Kemunculan masalah yang tersimpan | Masalah terkelompok atau pengguna yang terdampak |
| `logs` | Peristiwa log yang tersimpan | Permintaan |
| `traces` | ID trace unik, dihitung pada span tersimpan pertamanya di rentang waktu ini | Span atau jumlah trace yang dimulai sepanjang masa |
| `actions` | Peristiwa aksi yang tersimpan | Pengguna atau sesi |
| `metrics` | Titik data metrik yang tersimpan | Jumlah nilai metrik |

`total` adalah jumlah angka interval waktu dalam deret itu. `peak` adalah
angka interval waktu terbesarnya. `non_empty_buckets` menghitung interval
waktu yang angkanya di atas nol. Kelima deret selalu muncul dengan urutan ini.
Jangan gabungkan jumlah sinyal yang berbeda menjadi satu skor dampak.

Interval waktu dimulai pada `query.since`. Interval waktu mencakup awalnya dan
tidak mencakup akhirnya. Interval waktu terakhir bisa lebih pendek daripada
panjang interval. Respons tidak punya deret jumlah rilis. Jangan baca
`release_volume_not_included` sebagai nol rilis.

### Rentang waktu kosong dan dipersingkat

Jika tidak ada sinyal yang cocok, kelima deret tetap ada, dan titik datanya
berisi angka nol yang eksplisit. Permintaan yang gagal berbeda. Jangan ganti
error dengan grafik berisi nol.

Bandingkan `query.requested_since` dengan `query.since`. Jika retensi data
mempersingkat rentang waktu, `coverage.retention.window_clipped` bernilai
`true` dan `limitations` berisi `retention_window_clipped`. Jika tidak ada
bagian rentang waktu yang diminta yang tersisa, `query.bucket_count` bernilai
`0` dan setiap deret punya array `points` yang kosong. Ini tidak membuktikan
bahwa tidak ada peristiwa yang terjadi di periode itu.

`policy_days` bernilai `null` dan `cutoff` tidak disertakan jika tidak ada
batas retensi yang berlaku. `sampling.upstream` selalu bernilai `unknown`,
juga saat `storage_evaluation` bernilai `complete`. Jangan klaim bahwa respons
menghitung setiap peristiwa yang dihasilkan aplikasi.

### Permintaan volume sinyal yang ditolak

Permintaan berikut mengembalikan `422` dan `validation_failed`:

| Penyebab | `error` |
| - | - |
| Tidak ada `project_id` | `signal volume project_id is required` |
| Tidak ada `since` | `signal volume since is required` |
| `until` lebih lambat daripada waktu permintaan | `signal volume until must not be in the future` |
| Rentangnya lebih dari 31 hari | `signal volume range must not exceed 31 days` |
| Interval eksplisit yang memerlukan lebih dari 500 interval waktu | `signal volume interval would exceed 500 buckets` |
| `response_version` selain `1` | `signal volume response_version must be 1` |

Contoh:

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

Gunakan interval yang lebih lebar dalam lingkup yang sama. Untuk kegagalan
autentikasi dan kegagalan lain, lihat [Error API](/id/reference/api-errors).

## Respons investigasi

Rute investigasi mengembalikan paket bukti berversi untuk satu subjek. Subjek
itu berupa masalah, trace, span, log, aksi produk, metrik, atau rilis. Setiap
paket diawali dengan `schema_version` dan `subject` yang menyebutkan
record-nya. Sisanya berisi bukti terkait, catatan bukti, dan langkah
berikutnya. Bagian ini menampilkan satu contoh untuk setiap jenis, kecuali
rilis.

Kirim bearer akses akun. Kunci ingest proyek tidak bisa membaca investigasi.
Gunakan `logbrew explain <subject> --json` untuk membaca paket. CLI
memvalidasi paket sebelum mencetaknya.
Referensi [API Telemetri](/id/reference/telemetry-api) mencantumkan rutenya.

Teks investigasi berasal dari aplikasi. Pesan, nama, metadata, dan tag adalah
data, bukan instruksi. `content_trust: "untrusted_telemetry"` menandai konten
ini di paket log, aksi, span, dan metrik.

### Versi respons

Kirim `response_version` hanya ke rute yang menerimanya. Tanpa kunci itu, rute
mengembalikan versi 1. Parser Anda harus menerima versi yang Anda minta.

| Rute | Default | Versi yang didukung | Versi yang diminta `logbrew explain` |
| - | - | - | - |
| `GET /api/telemetry/issues/{issue_id}/investigation` | `1` | `1` sampai `13` | `13` |
| `GET /api/telemetry/traces/{trace_id}/investigation` | `1` | `1` sampai `3` | `3` |
| `GET /api/telemetry/metrics/investigation` | `1` | `1` dan `2` | `2` |
| `GET /api/telemetry/releases/investigation` | `1` | `1` sampai `5` | `5` |
| `GET /api/telemetry/traces/{trace_id}/spans/{span_id}/investigation` | `1` | Hanya `1` | `1` |
| `GET /api/logs/{log_id}/investigation` | `1` | Hanya `1` | `1` |
| `GET /api/telemetry/actions/{action_id}/investigation` | `1` | Hanya `1` | `1` |

Rute span menolak kunci kueri `response_version`. Rute log dan rute aksi tidak
menerima kunci kueri apa pun.

### Kolom paket bersama

| Kolom | Arti |
| - | - |
| `schema_version` | Versi respons yang dikembalikan server. |
| `subject` | Record persis yang sedang diinvestigasi. `kind` bernilai `issue`, `trace`, `span`, `log`, `action`, `metric`, atau `release`. |
| `analysis.causality` | Selalu `evidence_only` di paket trace, span, log, aksi, dan metrik. Telemetri yang berkorelasi tidak membuktikan penyebab. |
| Objek koleksi | Bukti terkait dalam bentuk `{ "status", "items", "truncated" }`. |
| `timeline` | Bukti yang dikembalikan, dari yang terlama sampai yang terbaru, dengan flag `truncated`-nya sendiri. Urutan ini tidak membuktikan penyebab. |
| `evidence` | Catatan bukti. `status` bernilai `complete` atau `partial`. |
| `next_actions` | Pembacaan yang disarankan, diurutkan menurut `priority` mulai dari `1`. Pembacaan ini belum dijalankan. |

Setiap koleksi terkait melaporkan satu `status` ketersediaan:

| Status | Arti | Perilaku klien |
| - | - | - |
| `available` | Pembacaan selesai dan mengembalikan item. | Tampilkan item dan flag `truncated`. |
| `not_linked` | Subjek tidak punya ID untuk tautan ini, misalnya ID trace. | Jelaskan tautan yang tidak ada. Jangan bangun tautan dari stempel waktu. |
| `not_found` | Pembacaan selesai dan tidak menemukan bukti yang tersimpan. | Tampilkan hasil kosong. |
| `unavailable` | Pembacaan opsional gagal. Subjeknya tetap valid. | Tetap tampilkan subjek. Coba lagi nanti. Jangan tampilkan nol item sebagai hasil. |

Catatan bukti punya 4 daftar terurut berisi nama kolom yang stabil:
`captured_fields`, `missing_fields`, `redacted_fields`, dan
`truncated_fields`. `status` bernilai `complete` hanya jika 3 daftar terakhir
kosong. Data yang disamarkan bukan data yang tidak terekam. Data yang dipotong
bukan data yang lengkap. Jangan isi nilai yang disamarkan atau dipotong.

### Batas investigasi

Batas berikut membatasi satu respons. Flag `truncated` atau entri
`truncated_fields` menunjukkan bahwa sebuah batas membuang sebagian data.

| Bukti | Batas |
| - | - |
| Item terkait dalam satu koleksi | 20 |
| Span tersimpan yang dibaca untuk satu trace | 1.000 |
| Item timeline | 50 untuk paket log, aksi, dan span. 100 untuk paket trace dan metrik. |
| Atribut terstruktur, properti, dan metadata | 64 nilai skalar, 4 tingkat objek atau array, 16 item di setiap array, 512 karakter di setiap string |
| Rentang waktu korelasi | 5 menit sebelum dan sesudah log, aksi, atau kemunculan masalah yang dipilih. Untuk trace atau span, 5 menit sebelum awal dan sesudah akhir, paling lama 24 jam. |

Setiap bagian jenis paket mencantumkan batasnya sendiri.

### Respons investigasi masalah

Gunakan `GET /api/telemetry/issues/{issue_id}/investigation` untuk membaca
bukti dari satu kemunculan masalah terkelompok.
Panduan [Investigasi masalah](/id/guides/investigate-an-issue) menunjukkan cara
membaca bukti secara berurutan. Minta versi 13:

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

Kunci kuerinya adalah `response_version`, `selection`, dan `occurrence_id`.
`selection` bernilai `recommended`, `first`, atau `latest`. Nilainya peka
huruf besar-kecil. Di versi 2 sampai 13, pemilih yang tidak dikirim memakai
`recommended`. Versi 1 mengembalikan kemunculan tersimpan terbaru dan tidak
menerima pemilih. Filter daftar masalah tidak berlaku untuk pembacaan ini.

<Accordion title="Contoh investigasi masalah versi 13">
  Respons `200 OK` sintetis ini punya satu kemunculan `TypeError` yang ditangani,
  dengan trace yang tertaut. Respons ini tidak punya bukti permintaan,
  breadcrumb, log terkait, atau deployment, jadi `evidence.status` bernilai
  `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>

| Kolom | Versi | Arti |
| - | - | - |
| `subject` | 1 | Masalah terkelompok. `first_seen_at`, `last_seen_at`, dan `occurrence_count` menggambarkan kelompoknya. |
| `event` | 1 | Kemunculan yang dipilih: SDK, `context`, `exception`, `stack_frames`, dan `breadcrumbs`. Di versi 1, bernilai `null` jika kemunculan terbaru tidak bisa dibaca. |
| `cause` | 1 | `status` bernilai `reported_hypothesis`, `evidence_only`, atau `unknown`. `signals` mencantumkan sinyal yang teramati. |
| `fix` | 1 | Lokasi kode. `status` bernilai `reported_location`, `observed_application_frame`, `observed_frame`, `observed_underlying_exception_frame`, atau `unknown`. |
| `impact` | 1 | Jumlah kemunculan dan `user_impact`. `reported` berisi dampak yang dilaporkan aplikasi atau `null`. |
| `correlations` | 1 | `trace`, `logs`, `actions`, `metrics`, dan `release`. |
| `occurrence_selection` | 2 | Pemilih yang diminta, alasannya, dan ringkasan kemunculan yang dipilih, pertama, terbaru, dan direkomendasikan. |
| `lifecycle` | 3 | `persisted_status`, `effective_status`, aktivitas status, dan `regression`. `effective_status` bisa bernilai `regressed`. |
| `occurrence_analysis` | 4 | Tren kemunculan serta distribusi rilis, lingkungan, layanan, dan SDK. |
| `event.exception_chain` | 5 | Paling banyak 8 exception yang tertaut. `relationship` bernilai `reported`, `cause`, `context`, `aggregate_member`, atau `suppressed`. |
| `event.request` | 6 | `method`, `route_template`, dan `response_status_code`. Kunci ini tidak ada jika tidak ada permintaan yang terekam. |
| `grouping` | 7 | `strategy` pengelompokan, `components`-nya, dan penggunaan stack frame. |
| `correlations.release.deployment_status` | 8 | Status pencarian deployment. `deployment`, `time_since_deployment_ms`, dan `deployment_causality` hanya muncul jika deployment ditemukan. |
| `correlations.related_issues` | 9 | Masalah lain pada trace yang sama. |
| `source_locator` | 10 | Repositori, komponen, revisi, dan file relatif terhadap repositori, jika LogBrew bisa menautkannya. |
| `reproduction` | 11 | `status` bernilai `ready`, `partial`, atau `insufficient_evidence`. |
| Kode `next_actions` `verify_correction` | 12 | Muncul jika `reproduction.status` bernilai `ready`. |
| `impact.user_impact.count_method` | 13 | Melaporkan perkiraan jumlah unik sebagai `approximate_distinct`. Versi sebelumnya memakai nama nilai yang lebih lama. `unavailable` berarti tidak ada jumlah. |

Kunci dari versi yang lebih baru tidak ada di versi yang lebih lama. Jangan
baca kunci yang tidak ada sebagai `null`.

`subject.status` dan status di `lifecycle` melaporkan masalah yang diarsipkan
sebagai `ignored`. Respons daftar dan detail masalah memakai `archived` di
versi respons 2 dan yang lebih baru.

Batas masalah: rekomendasi membaca paling banyak 50 kemunculan yang tersimpan.
Tren punya paling banyak 30 interval waktu. Setiap distribusi mengembalikan
paling banyak 10 nilai. Stack punya paling banyak 32 frame.

#### Error permintaan investigasi masalah

Gunakan `selection` atau `occurrence_id`, salah satunya saja. Jangan kirim
keduanya, meskipun keduanya memilih kemunculan yang sama:

```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` | Penyebab | Pemulihan |
| - | - | - | - |
| `422` | `selection and occurrence_id are mutually exclusive` | Permintaan berisi kedua pemilih. | Pertahankan satu pemilih. |
| `422` | `issue occurrence selection requires response_version=2 through 13` | Permintaan berisi pemilih dan versi 1, atau tanpa versi. | Kirim `response_version=13`. Pertahankan pemilihnya. |
| `422` | `issue investigation response_version must be 1 through 13` | Versinya di luar rentang. | Kirim versi yang didukung. |
| `422` | `invalid query parameters` | Kunci yang tidak dikenal, UUID yang tidak valid, versi yang bukan bilangan bulat, atau nilai `selection` yang tidak dikenal. | Perbaiki [kueri](/id/reference/api-errors#invalid-query-parameters). |
| `404` | `issue occurrence not found` | Kemunculan itu tidak ada di riwayat tersimpan kelompok ini. | Salin ID kemunculan dari peristiwa masalah ini. Jangan memakai `latest` atau `recommended` sebagai gantinya tanpa persetujuan. |
| `404` | `issue not found` | Tidak ada proyek yang bisa dibaca yang punya masalah ini. | Periksa akun dan UUID masalah. Jangan kirim UUID kemunculan sebagai ID masalah. |

Kemunculan yang tidak ada tidak berarti masalahnya juga tidak ada. `404` tidak
menunjukkan apakah akun lain bisa membaca masalah itu.

### Respons investigasi trace

Gunakan `GET /api/telemetry/traces/{trace_id}/investigation` untuk membaca satu
trace beserta jalur kegagalannya, jalur paling lambatnya, dan sinyal terkait.
Kunci kuerinya adalah `response_version`, `project_id`, `release`, dan
`environment`. Semuanya opsional. Minta versi 3:

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

Versi 2 menambahkan `cause` dan `fix` ke setiap masalah terkait. Versi 3
menambahkan `span_id` ke masalah, aksi, dan metrik terkait jika `span_id`
terekam.

<Accordion title="Contoh investigasi trace versi 3">
  Respons sintetis ini punya root span server dan span klien yang gagal. Span
  yang gagal itu juga merupakan child span paling lambat. Kedua span tidak
  punya konteks terstruktur, jadi `spans.context` tidak terekam.

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

| Kolom | Arti |
| - | - |
| `subject` | Total trace dari span yang dianalisis. |
| `analysis.status` | `errors_observed`, `latency_focus`, atau `no_error_observed`. |
| `analysis.first_error_path` | Rantai parent yang diketahui dari root sampai span error paling awal. |
| `analysis.bottleneck_path` | Rantai parent yang diketahui sampai child span paling lambat. |
| `spans.items[].roles` | Alasan span ada di pratinjau: `root`, `first_error`, `error_path`, `bottleneck`, `bottleneck_path`, `error`, atau `slow`. |
| `correlations.window` | Rentang waktu dan lingkup deployment yang dipakai untuk pembacaan terkait. |
| `correlations.issues`, `logs`, `actions`, `metrics` | Sinyal dengan ID trace yang sama dalam rentang waktu itu. |

`trace.parentage` tidak terekam jika span menyebut parent yang tidak disimpan
LogBrew. Pratinjau span berisi paling banyak 64 span. Setiap jalur analisis
berisi paling banyak 64 span. Pembacaan terkait memakai paling banyak 8
lingkup deployment.

Langkah berikutnya dengan target `trace_span` menyebutkan `span_id` dari paket
ini. Untuk membaca span itu, kirim rute span dengan `project_id`,
`environment`, dan `release` milik span tersebut.

### Respons investigasi span

Gunakan `GET /api/telemetry/traces/{trace_id}/spans/{span_id}/investigation`
untuk membaca satu operasi dalam trace. Kirim `project_id`, `environment`, dan
`release`. Ketiganya wajib dikirim. Salin nilainya dari span yang dipilih.
Jangan kirim `id` baris span sebagai `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="Contoh investigasi span">
  Respons sintetis ini menggambarkan span klien yang gagal dari contoh trace.
  Satu log error punya ID span yang sama. Span ini berjalan lebih lama daripada
  perkiraan persentil ke-95 dari span sejenis yang tersimpan.

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

| Kolom | Arti |
| - | - |
| `payload` | `metadata` span, paling banyak 8 `events`, dan paling banyak 8 `links`. Ketiganya berbagi satu jatah 64 nilai. |
| `analysis.observations` | `subject_error`, `child_error`, `exact_span_error_log`, `related_issue`, `subject_at_or_above_peer_p95`, atau `subject_at_or_above_peer_p99`. |
| `topology` | `root`, `parent`, `ancestors`, `children` langsung, `descendant_count`, dan `cross_service_edges`. |
| `topology.parent_chain_status` | `root`, `complete`, `missing`, `cycle`, `truncated`, atau `unavailable`. |
| `baseline` | Span sebelumnya dengan proyek, lingkungan, rilis, layanan, operasi, dan nama yang sama. |
| `correlations.logs` | Log dengan ID trace dan ID span yang sama. |
| `correlations.issues`, `actions`, `metrics` | Sinyal dengan ID trace yang sama di proyek, lingkungan, dan rilis yang sama. |
| `timeline[].offset_ms` | Milidetik sejak span dimulai. Nilai negatif berarti lebih awal daripada span. |

Acuan membaca 24 jam sebelum span dimulai. `since` inklusif dan `until`
eksklusif. `error_rate_basis_points: 500` berarti 5%.
`subject_percentile_basis_points: 9500` berarti 95% span sejenis yang
tersimpan tidak berjalan lebih lama daripada span ini. Persentil bersifat
perkiraan. Sertakan `baseline.limitations` bersama nilainya. Acuan
`not_found` tidak punya span sejenis yang tersimpan. Acuan `unavailable`
adalah pembacaan yang gagal, bukan jumlah nol.

`parent_chain_status: "complete"` berarti rantai yang tersimpan mencapai
root. Ini tidak membuktikan bahwa LogBrew menyimpan setiap span dari
permintaan itu. Topologi mengembalikan paling banyak 64 ancestor, 50 child
langsung, dan 50 edge lintas layanan.

| HTTP | `error` | Pemulihan |
| - | - | - |
| `422` | `trace_id must be a non-zero 32-character hexadecimal value` | Salin `trace_id` dari respons trace LogBrew. |
| `422` | `span_id must be a non-zero 16-character hexadecimal value` | Salin `span_id` dari respons trace LogBrew. |
| `422` | `environment and release must be non-empty exact span scope values` | Salin lingkupnya dari span yang dipilih. |
| `422` | `invalid query parameters` | Kirim `project_id`, `environment`, dan `release`, tanpa kunci lain. |
| `404` | `span not found` | Periksa ID, proyek, lingkungan, dan rilisnya. |

### Respons investigasi log

Gunakan `GET /api/logs/{log_id}/investigation` untuk membaca satu log dan
bukti terkaitnya. Rute ini tidak punya kunci kueri. Salin ID log dari daftar
log.

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

Pembacaan ini bisa mengembalikan bukti di luar filter daftar log. Pembacaan
terkait memakai proyek, lingkungan, dan rilis log itu, serta 5 menit sebelum
dan sesudah log. Log di sekitarnya juga memakai layanan yang sama dan
tidak memerlukan ID trace. Pembacaan trace persis memerlukan ID trace log dan
bisa mencakup layanan lain. Ringkasan trace memakai ID trace dan lingkup yang
sama, tanpa rentang waktu.

<Accordion title="Contoh investigasi log">
  Respons sintetis ini punya log peringatan tanpa konteks trace dan satu log di
  sekitarnya. Respons tidak membangun tautan trace dari stempel waktu.

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

| Kolom | Arti |
| - | - |
| `attributes` | Atribut terstruktur yang dibatasi. `values` tidak menyertakan `context`, yang ada di kolom `context` tingkat atas. |
| `analysis.status` | `critical_evidence`, `error_evidence`, `warning_evidence`, atau `no_failure_observed`. |
| `correlations.trace` | ID trace, ID span, `exact_span`, dan `summary` trace. |
| `correlations.trace_logs` | Log dengan ID trace yang sama. `relationship` bernilai `exact_trace`. |
| `correlations.nearby_logs` | Log dari layanan yang sama dalam rentang waktu itu. `relationship` bernilai `nearby_scope`. Tidak menyertakan subjek dan log trace persis. |
| `correlations.issues`, `actions`, `metrics` | Sinyal dengan ID trace yang sama. |
| `correlations.release` | Lingkup rilis untuk investigasi rilis. Kolom ini tidak berisi perbandingan. |
| `timeline[].relationship` | `subject`, `exact_span`, `exact_trace`, atau `nearby_scope`. |

ID trace bisa ada meskipun status trace bernilai `not_found` atau
`unavailable`. Ringkasan trace yang tersedia tidak menjamin adanya
`exact_span`.

### Respons investigasi aksi

Gunakan `GET /api/telemetry/actions/{action_id}/investigation` untuk membaca
satu aksi produk, status yang dilaporkannya, dan bukti terkait. Rute ini tidak
punya kunci kueri. Pembacaan terkait memakai rentang waktu dan lingkup yang
sama dengan investigasi log.

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

`correlations`, `timeline`, dan `next_actions` memakai bentuk investigasi log.
Aksi terkait tidak menyertakan aksi subjek.

<Accordion title="Contoh investigasi aksi">
  Respons sintetis ini menggambarkan aksi checkout yang gagal dari pengguna yang
  sudah masuk. Aksi ini tidak punya ID trace.

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

| Kolom | Arti |
| - | - |
| `subject.status` | `queued`, `running`, `success`, `failure`, atau `null` jika tidak ada status yang didukung yang terekam. |
| `subject.subject_classification` | `user`, `anonymous`, `legacy_unknown`, `missing`, `historical_unindexed`, atau `unsupported`. |
| `subject.session_captured` | Apakah aksi itu punya sesi. Respons tidak pernah mengembalikan ID sesi. |
| `properties` | Objek `metadata` aksi yang dibatasi. |
| `analysis.status` | `subject_failure`, `correlated_failure_evidence`, `in_progress`, `success_observed`, atau `status_not_captured`. |

Respons tidak pernah mengembalikan ID subjek atau ID sesi. Catatan bukti
selalu mencantumkan `subject.distinct_id` sebagai disamarkan, dan juga
`subject.session_id` jika sesi terekam. Karena itu, setiap paket aksi bernilai
`partial` dan menyertakan `improve_capture`. Jangan hapus kontrol privasi
hanya untuk memenuhinya.

### Respons investigasi metrik

Gunakan `GET /api/telemetry/metrics/investigation` untuk membaca satu nama
metrik di satu proyek dan rentang waktu. Respons berisi deret saat ini,
perbandingan dengan rentang waktu sebelumnya yang sama panjang, sampel
terbaru, exemplar trace, dan deployment yang sudah selesai. Versi 2
menambahkan deskripsi metrik dari sampel tersimpan terbaru. Versi 1 selalu
melaporkan `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`, dan `since` wajib dikirim. `since` inklusif dan `until`
eksklusif. `until` default-nya adalah waktu saat ini. Perbandingan juga
membaca rentang waktu sebelumnya yang sama panjang.

<Accordion title="Contoh investigasi metrik versi 2">
  Histogram sintetis ini punya 5 sampel di 2 interval waktu 5 menit. Interval
  waktu terbaru punya p95 sebesar 48 ms. Interval waktu terbaru di rentang
  waktu sebelumnya punya p95 sebesar 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>

| Kolom | Arti |
| - | - |
| `subject.description_status` | `captured`, `not_captured`, atau `unavailable`. |
| `query` | Kueri yang sudah dinormalisasi. `service_name`, `release`, dan `environment` hanya muncul jika dikirim. |
| `analysis.status` | `no_samples`, `change_observed`, `no_change_observed`, `baseline_not_found`, atau `comparison_unavailable`. |
| `analysis.focus` | Item perbandingan dengan perubahan relatif terbesar, atau perubahan absolut terbesar jika tidak ada perubahan relatif. Bernilai `null` jika tidak ada item yang bisa dibandingkan. |
| `series[].aggregation.code` | `gauge_last`, `delta_sum`, `distribution_p95`, `raw_cumulative_last`, atau `raw_last`. |
| `comparison.status` | `available`, `partial`, `not_found`, `unavailable`, atau `no_current_samples`. |
| `comparison.items[]` | Interval waktu tidak kosong terbaru dari setiap rentang waktu untuk identitas deret yang sama. |
| `latest_sample` | Sampel mentah terbaru, dengan SDK, `context`, `metadata`, dan tautan trace. |
| `exemplars` | Sampel mentah yang punya ID trace. `coverage` menghitung sampel yang tertaut. |
| `deployments` | Deployment yang sudah selesai sejak awal rentang waktu sebelumnya sampai `until`. |
| `next_actions[]` | `code`, `target`, `reason` berupa teks biasa, dan lingkup `context` untuk pembacaan berikutnya. |

`relative_change_percent` adalah `(current - previous) / abs(previous) * 100`.
Nilainya `null` jika nilai sebelumnya nol atau tidak ada.
`expected_buckets_per_series` menghitung interval waktu yang mungkin ada, bukan interval waktu yang punya
data. Jangan gambar interval waktu kosong sebagai nol. Deployment yang terjadi
di dekat suatu perubahan tidak membuktikan bahwa deployment itu menyebabkan
perubahan tersebut.

Proyek yang tidak bisa dibaca akun mengembalikan `200 OK` dengan
`analysis.status: "no_samples"`, bukan `404`. Hasil kosong tidak
menggambarkan tipe sinyal lain.

Batas metrik: rentang paling lama 31 hari. Setiap deret punya paling banyak
500 interval waktu. `series_limit` bernilai 1 sampai 20, dengan default 10.
Respons mengembalikan paling banyak 20 exemplar dan 20 deployment.

| HTTP | `error` | Pemulihan |
| - | - | - |
| `422` | `metric investigation response_version must be 1 or 2` | Jangan kirim `response_version`, atau kirim `2`. |
| `422` | `metric series project_id is required` | Kirim satu ID proyek yang bisa dibaca. |
| `422` | `metric series name is required` | Salin nama dari daftar metrik. |
| `422` | `metric series since is required` | Kirim nilai seperti `24h` atau stempel waktu RFC 3339. |
| `422` | `metric series range must not exceed 31 days` | Gunakan rentang yang lebih pendek. |
| `422` | `metric series interval would exceed 500 buckets` | Gunakan `interval=auto` atau interval yang lebih lebar. |
| `422` | `metric series_limit must be between 1 and 20` | Kirim nilai dari 1 sampai 20. |

`interval` bernilai `auto`, `1m`, `5m`, `15m`, `1h`, `6h`, atau `1d`.
`group_by` bernilai `none`, `service_name`, `release`, atau `environment`.
Nilai lain mengembalikan `422`.

### Error investigasi

| HTTP | Rute | `error` |
| - | - | - |
| `404` | Log | `log not found` |
| `404` | Aksi | `action not found` |
| `404` | Trace | `trace not found` |
| `422` | Trace | `trace investigation response_version must be 1, 2, or 3` |
| `400` | Log, aksi, masalah | `invalid URL path parameters` jika ID di path bukan UUID |
| `422` | Masalah, trace, span, metrik | `invalid query parameters` untuk kunci yang tidak dikenal atau nilai dengan tipe yang salah |

`404` berarti tidak ada proyek yang bisa dibaca yang punya record itu. Setiap
rute juga mengembalikan `401` tanpa autentikasi yang valid dan `405` untuk
metode selain `GET`. Lihat [Error API](/id/reference/api-errors) untuk respons
[tidak ditemukan](/id/reference/api-errors#resource-not-found),
[path](/id/reference/api-errors#invalid-path-value),
[autentikasi](/id/reference/api-errors#authentication-failure), dan
[metode](/id/reference/api-errors#unsupported-method).

Pembacaan bukti opsional bisa gagal di dalam respons `200 OK`. Dalam kasus
itu, koleksinya melaporkan `unavailable`. Jangan tampilkan sebagai
`not_found` atau sebagai nol record.

## <span id="severity-values">Nilai tingkat keparahan</span>

Nilai tingkat keparahan yang tampil ke pengguna adalah `info`, `warning`,
`error`, dan `critical`. SDK dan runtime bisa mengirim alias umum seperti
`trace`, `debug`, `warn`, atau `fatal`. Respons REST dan respons langsung
selalu mengembalikan nilai kanonis. Misalnya, LogBrew menerima `warn` sebagai
input dan mengembalikan `warning`. Ingest menolak nilai tingkat keparahan yang
tidak dikenal.

| Alias | Nilai kanonis |
| - | - |
| `trace`, `debug` | `info` |
| `warn` | `warning` |
| `fatal` | `critical` |

## <span id="severity-rule-responses">Respons aturan tingkat keparahan</span>

Aturan tingkat keparahan mengubah cara LogBrew menampilkan log atau masalah.
Aturan ini tidak mengubah tingkat keparahan yang direkam aplikasi. Log dan
masalah mengembalikan objek `triage`:

| Kolom | Arti |
| - | - |
| `effective_severity` | Tingkat keparahan yang ditampilkan. Tanpa aturan, nilainya sama dengan `severity`. |
| `ignored` | `true` jika aturan log mengabaikan log itu, atau jika masalahnya diarsipkan. |
| `rule_applied` | `true` jika aturan tingkat keparahan atau status diabaikan berlaku. `false` adalah nilai default, bukan data yang tidak terekam. |

Gunakan `triage.effective_severity` untuk tampilan. Pertahankan `severity`
sebagai nilai yang terekam. Secara default, daftar log tidak menyertakan log
yang diabaikan. Kirim `status=ignored` atau `status=all` di `GET /api/logs`
untuk menyertakannya.

Akun harus punya izin untuk mengelola masalah di proyek itu. Akses baca tidak
cukup. Tanpa izin itu, perubahan aturan mengembalikan `403` dengan
`code: forbidden`.

### Ubah aturan log

`PUT /api/logs/{log_id}/triage-rule` menetapkan aturan untuk log itu dan untuk
log berikutnya dengan signature yang sama. Body memerlukan `severity` dan
`ignored` sekaligus:

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

Respons `200 OK` berisi [log](#log-response) lengkap. `severity`-nya tetap
`warning`. `triage`-nya menampilkan aturan itu:

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

Kutipan ini hanya menampilkan kolom yang berubah. `severity` di permintaan
bernilai `source`, `info`, `warning`, `error`, atau `critical`. `source`
memulihkan tingkat keparahan yang terekam. Nilai ini tidak membuat log yang
diabaikan aktif kembali. Untuk menampilkan log itu lagi, kirim
`"ignored": false`.

### Ubah aturan masalah

`PUT /api/telemetry/issues/{issue_id}/triage-rule` menetapkan tingkat
keparahan yang ditampilkan untuk masalah terkelompok dan kemunculan
berikutnya. Body hanya menerima `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" }'
```

Respons `200 OK` berisi [masalah](#issue-response) lengkap dalam versi 1.
`severity` dan `status` yang terekam tidak berubah:

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

Kutipan ini hanya menampilkan sebagian kolom. Aturan tidak menyelesaikan,
mengarsipkan, atau membuka kembali masalah. Gunakan
[perubahan status](#issue-status-response-examples) untuk itu. Prioritas
turunan mengikuti tingkat keparahan efektif yang baru. Baca masalah itu dengan
`response_version=2` atau `3` untuk melihatnya.

Tingkat keparahan yang tidak didukung mengembalikan `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"
  }
}
```

Kolom body yang tidak dikenal, seperti `status` pada aturan masalah,
mengembalikan `422` dengan `code: invalid_json`. Log atau masalah yang tidak
ada atau tidak bisa dibaca mengembalikan `404` dengan `code: not_found`. Jika
respons hilang, baca lagi log atau masalahnya sebelum Anda mengirim aturan itu
lagi.

## Format respons error

Error aplikasi mengembalikan envelope JSON. Contoh ini menampilkan permintaan
yang ditolak; teks `error` dan `next` bergantung pada jenis error-nya:

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

Gunakan `code` untuk percabangan program dan `next_action` untuk otomatisasi.
Tampilkan `error` dan `next` sebagai teks biasa untuk dibaca orang. Jangan mem-parse
kata-katanya. Beberapa error menambahkan kolom, seperti `limit`, `reset_at`,
atau `retry_after_seconds`. Respons tanpa body JSON tidak punya `code`
LogBrew. Lihat [Error API](/id/reference/api-errors) untuk semua kode.

## Baca data dengan CLI

CLI membaca rute yang sama dan mengembalikan JSON yang sama dengan `--json`.
Mulai secara luas, lalu persempit:

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

Tambahkan `--pagination cursor` untuk mendapatkan envelope kursor. CLI meminta
versi respons masalah 4. Lihat [Baca halaman berikutnya](/id/reference/cli#read-the-next-page)
dan [Pantauan langsung](/id/reference/cli#live-watch).


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