---
title: "What each log subject is, and what it can and cannot do"
method: GET
path: "/api/v1/logs/subjects"
tags: ["logs"]
---

# What each log subject is, and what it can and cannot do

`GET /api/v1/logs/subjects`

The subject registry as data, so the UI never hardcodes a capability.

Every gap in the capability matrix was introduced by a change that shipped one
channel and left the others, and the frontend then encoded that gap by hand:
``isTextReevalDisabled = channel === "text"`` outlived the PR that made text
re-evaluation work by five phases, and its tooltip still cited that PR as
pending. A control drawn from this response cannot outlive the truth, because
there is only one declaration behind it.

No tenant data is involved — the registry is identical for every caller — so
the response is a pure function of module-level declarations.

## Response `200`

Successful Response

- LogSubjectRegistryResponse — Every subject, in the order operators see them.
  - `subjects` LogSubjectDescriptor[], required
    - `key` 'voice' | 'text' | 'email' | 'booking', required
    - `label` string, required — Human-readable and singular, for operator-facing messages.
    - `id_field` string, required — The attribute a detail route addresses a row by. Voice is the only subject keyed on a provider id (`external_id`) rather than the primary key, and a client that assumes `id` breaks every existing shared call link.
    - `capabilities` string[], required — Capabilities this subject supports, sorted by value.
    - `unsupported_reason` object, required — Operator-facing copy for every capability NOT in `capabilities`. Together the two cover the capability enum exactly — the registry is total, so a client can always say *why* a control is missing rather than drawing a dead button.
    - `compiled_filters` string[], required — Universal filters this subject actually narrows on, sorted.
    - `unsupported_filters` object, required — Universal filters this subject accepts but does not narrow on, each with the reason the list echoes back as `ignored_filters`.
    - `unsupported_columns` object, required — Catalog columns this subject cannot populate, each with a reason. Withheld from the catalog so no column renders an em dash on every row.
    - `column_field_overrides` object, required — Catalog columns the list row carries under a different field name. Only the exceptions appear; the rule is that a column key is its own field.
  - `capability_keys` string[], required — Every capability name the registry knows, sorted. Served so a client can iterate the capability space without keeping its own copy of the enum — the copy that would silently miss a ninth member.

## Other responses

- `401` — Authentication required
- `403` — Missing the VIEW_CALL_LOGS permission

---

[API](https://skmtc.dev/getanana/apis/cleon-api.md) · [All operations](https://skmtc.dev/getanana/apis/cleon-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/getanana/cleon-api/revisions/c0f54348e251/schema)
