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

# Problems

> GET /problems for the ranked root-cause list, per-problem detail and evidence, and the feedback endpoints that steer discovery.

Problems are recurring root causes that Moda discovers by grouping signals (frustrations, tool failures, and other detections) across conversations. Signal attributions land within minutes, and the ranked list is updated automatically as evidence accumulates. These endpoints mirror the [Problems dashboard](/dashboard/problems) and add a feedback channel that steers discovery.

Problem IDs are UUIDs. If a problem was merged into another, its old ID still resolves — responses report the surviving ID in `problem_id` and set `alias_resolved: true`.

## GET /problems

The ranked problem list with coverage and freshness metadata.

### Query parameters

<ParamField query="days_back" type="integer" default="30">
  1–90. Bounds which computation runs count toward the list.
</ParamField>

<ParamField query="limit" type="integer" default="25">
  1–25. This endpoint's cap is 25.
</ParamField>

### Response fields

<ResponseField name="summary" type="object">
  `days_back`, `open_problems`, `reopened`, `total_problems`, `signals_attributed`, `explained_coverage_pct`.
</ResponseField>

<ResponseField name="remainder" type="object">
  The tenant-wide coverage meter: `attributed_signals`, `unexplained_signals`, `coverage_pct`, `historically_attributed_signals`, `historical_coverage_pct`.
</ResponseField>

<ResponseField name="problems" type="array">
  The trusted ranked list — only rows whose `verification_status` is `current`, ordered by rank. Each row has `problem_id`, `display_name`, `cause_statement`, `lifecycle` (`open`, `fixed_monitoring`, `reopened`, `resolved`), `rank_score`, `rubric_version`, `total_attributions`, `family_weighted_count`, `affected_users`, `affected_conversations`, `agg_prm_delta`, `abandonment_rate`, `recency_score`, `trend_score`, `multi_family`, `family_counts`, `coverage_overall`, `coverage_by_family`, `audit_pass_rate` (or `null`), `verification_status`, `verified_causal_version`.
</ResponseField>

<ResponseField name="untrusted" type="array">
  Same row shape as `problems`, for rows whose verification is `failed`, `unverified`, or `stale`. They are still live problems and still visible, but never ranked. Treat `failed` and `unverified` rows as hypotheses; `stale` rows rank again after re-verification.
</ResponseField>

<ResponseField name="hierarchy" type="object">
  `macros[]` — macro themes grouping leaf problems (`problem_id`, `display_name`, `display_description`, `tier`, `child_count`, `children[]`) — and `unparented_leaf_count`.
</ResponseField>

<ResponseField name="emerging" type="array">
  Provisional problems not yet in the ranked list: `problem_id`, `display_name`, `display_description`, `family` (or `null`), `evidence_support` (`report_backed_members`, `attribution_count`), `verification_status`, `provisional: true`.
</ResponseField>

<ResponseField name="freshness" type="object">
  When things were last computed: `book_computed_at`, `latest_assignment_at`, `lag_seconds`, `discovery` (latest session stats or `null`), `verification` (counts by status), `remainder_backlog` (`pending_groups`, `pending_mass`).
</ResponseField>

<ResponseField name="feedback_pending" type="integer">
  Feedback rows submitted but not yet applied.
</ResponseField>

### Example

```bash theme={"dark"}
curl "https://moda.dev/api/v1/data/problems?days_back=30&limit=1" \
  -H "x-api-key: YOUR_MODA_API_KEY"
```

```json theme={"dark"}
{
  "summary": {
    "days_back": 30,
    "open_problems": 6,
    "reopened": 1,
    "total_problems": 8,
    "signals_attributed": 412,
    "explained_coverage_pct": 71.4
  },
  "remainder": {
    "attributed_signals": 412,
    "unexplained_signals": 165,
    "coverage_pct": 71.4,
    "historically_attributed_signals": 447,
    "historical_coverage_pct": 77.5
  },
  "problems": [
    {
      "problem_id": "3f6b0a52-9d1c-4e7a-b2f8-6c0d5e4a3b21",
      "display_name": "Ticket creation fails on urgent priority",
      "cause_statement": "The create_ticket tool is called with priority values the ticketing API rejects, so refund escalations silently fail.",
      "lifecycle": "open",
      "rank_score": 0.92,
      "rubric_version": 4,
      "total_attributions": 61,
      "family_weighted_count": 48.5,
      "affected_users": 37,
      "affected_conversations": 44,
      "agg_prm_delta": -0.18,
      "abandonment_rate": 0.27,
      "recency_score": 0.81,
      "trend_score": 0.34,
      "multi_family": true,
      "family_counts": { "tool_failure": 42, "emotion": 19 },
      "coverage_overall": 0.71,
      "coverage_by_family": { "tool_failure": 0.84, "emotion": 0.52 },
      "audit_pass_rate": 0.93,
      "verification_status": "current",
      "verified_causal_version": 3
    }
  ],
  "untrusted": [],
  "hierarchy": {
    "macros": [
      {
        "problem_id": "9a2e7c14-5b3f-4d80-a6e1-2f7b8c9d0e13",
        "display_name": "Ticketing integration reliability",
        "display_description": "Failures and workarounds in the ticketing tool chain.",
        "tier": "macro",
        "child_count": 2,
        "children": ["3f6b0a52-9d1c-4e7a-b2f8-6c0d5e4a3b21", "b4c8d1e6-0f2a-4357-9b8c-7d6e5f4a3b2c"]
      }
    ],
    "unparented_leaf_count": 3
  },
  "emerging": [],
  "freshness": {
    "book_computed_at": "2026-08-14T03:12:44",
    "latest_assignment_at": "2026-08-14T11:05:09",
    "lag_seconds": 28345,
    "discovery": {
      "latest_session_ts": "2026-08-14T03:10:02",
      "groups_total": 21,
      "groups_processed": 18,
      "groups_skipped": 3,
      "saturation": false,
      "stop_reason": "exhausted"
    },
    "verification": { "live_total": 8, "current": 6, "stale": 1, "failed": 0, "unverified": 1 },
    "remainder_backlog": { "pending_groups": 3, "pending_mass": 41 }
  },
  "feedback_pending": 1
}
```

<Note>
  This example is trimmed for readability: with `limit=1` only the top-ranked row is shown, and the `untrusted` rows implied by the `verification` counts (`stale: 1`, `unverified: 1`) are omitted.
</Note>

## GET /problems/:id

Full detail for one problem. Returns `200` with `found: false` for an unknown or malformed ID — not `404`.

### Response fields

<ResponseField name="found" type="boolean">
  `false` when the ID does not resolve to a problem; all other blocks are then empty or `null`.
</ResponseField>

<ResponseField name="problem_id / requested_problem_id / alias_resolved" type="string / string / boolean">
  The surviving problem ID, the ID you requested, and whether a merged-away ID was folded to its survivor.
</ResponseField>

<ResponseField name="header" type="object | null">
  The same row shape as the list on `GET /problems`.
</ResponseField>

<ResponseField name="rubric" type="object | null">
  The latest problem definition: `version`, `cause_statement`, `display_name`, `display_description`, `lifecycle`, `parent_problem_id`, `change_reason`, `match_criteria`, `counter_examples`, `scope_hints`, `updated_at`, `tier` (`macro` or `leaf`), `provisional`, `affected_surface`, `causal_content_version`.
</ResponseField>

<ResponseField name="trend" type="array">
  Rank history: `{run_ts, rank_score, total_attributions, rubric_version, coverage_overall}` per computation run, newest first.
</ResponseField>

<ResponseField name="sub_problems" type="array">
  Child problems for macro problems: `{problem_id, display_name, cause_statement, lifecycle, version}`.
</ResponseField>

<ResponseField name="verification" type="object">
  `audit_pass_rate`, `judge_audit` (`{passed, total}`), `counterfactual_replay` (`{passed, total}`), and `samples[]` — individual verification checks with `kind`, `passed`, `rubric_version`, `conversation_id`, `segment_id`, `rationale`, `verified_at`.
</ResponseField>

<ResponseField name="evidence" type="array">
  A first page of evidence rows (see [`/problems/:id/evidence`](#get-problemsidevidence) for the full paginated set and field list).
</ResponseField>

<ResponseField name="affected_conversations" type="array">
  `{conversation_id, user_id, signal_count, family_counts, last_signal_at}` rollups.
</ResponseField>

<ResponseField name="remainder" type="object">
  The same tenant-wide coverage meter as the list endpoint.
</ResponseField>

<ResponseField name="investigation_reports" type="object">
  First page of investigation reports: `{items[], has_more, next_cursor}` (full set on [`/problems/:id/reports`](#get-problemsidreports)).
</ResponseField>

<ResponseField name="confidence" type="object">
  Verification confidence for the current problem version: `current_rubric_version`, `causal_content_version`, `verification_status`, `audited_causal_content_version`, per-version breakdowns (`current`, `stale`), and passed/failed `samples`.
</ResponseField>

<ResponseField name="change_history" type="array">
  Lineage events: `{problem_id, event_id, event_kind, related_problem_id, rubric_version, causal_content_version, reason, created_ts}`.
</ResponseField>

<ResponseField name="impact_identity" type="object">
  `known_users`, `unknown_identity_conversations`, `total_conversations`, `identity_coverage_pct` — impact is split so conversations without a known user are never reported as zero users.
</ResponseField>

<ResponseField name="hierarchy" type="object">
  `tier`, `parent` (or `null`), `children[]`.
</ResponseField>

<ResponseField name="dossier" type="object | null">
  Precomputed narrative blocks (`executive_summary`, `causal_chain`, `suggested_investigation`, `representative_story_keys`, `limitations`) plus computation metadata. `null` until a dossier has been generated.
</ResponseField>

<ResponseField name="stories" type="array">
  Representative examples, each `{story_kind, evidence, verification}` where `story_kind` is one of `top_confidence`, `ground_truth_passed`, `disputed`, `replay_verified`, `newest`.
</ResponseField>

### Example

```bash theme={"dark"}
curl "https://moda.dev/api/v1/data/problems/3f6b0a52-9d1c-4e7a-b2f8-6c0d5e4a3b21" \
  -H "x-api-key: YOUR_MODA_API_KEY"
```

```json theme={"dark"}
{
  "found": true,
  "problem_id": "3f6b0a52-9d1c-4e7a-b2f8-6c0d5e4a3b21",
  "requested_problem_id": "3f6b0a52-9d1c-4e7a-b2f8-6c0d5e4a3b21",
  "alias_resolved": false,
  "header": { "problem_id": "3f6b0a52-9d1c-4e7a-b2f8-6c0d5e4a3b21", "display_name": "Ticket creation fails on urgent priority", "lifecycle": "open", "rank_score": 0.92, "verification_status": "current" },
  "rubric": {
    "version": 4,
    "cause_statement": "The create_ticket tool is called with priority values the ticketing API rejects, so refund escalations silently fail.",
    "display_name": "Ticket creation fails on urgent priority",
    "display_description": "Escalations fail when the agent passes 'urgent' as a ticket priority.",
    "lifecycle": "open",
    "parent_problem_id": "9a2e7c14-5b3f-4d80-a6e1-2f7b8c9d0e13",
    "change_reason": "Narrowed match criteria after false positives on timeout errors.",
    "match_criteria": { "tool_name": "create_ticket", "error_pattern": "priority" },
    "counter_examples": [],
    "scope_hints": [],
    "updated_at": "2026-08-14T03:11:57",
    "tier": "leaf",
    "provisional": false,
    "affected_surface": "ticketing integration",
    "causal_content_version": 3
  },
  "trend": [
    { "run_ts": "2026-08-14T03:12:44", "rank_score": 0.92, "total_attributions": 61, "rubric_version": 4, "coverage_overall": 0.71 }
  ],
  "sub_problems": [],
  "verification": {
    "audit_pass_rate": 0.93,
    "judge_audit": { "passed": 14, "total": 15 },
    "counterfactual_replay": { "passed": 4, "total": 4 },
    "samples": []
  },
  "evidence": [
    {
      "attribution_id": "e19c3d47-8a2b-4f60-95c1-3d2e1f0a9b87",
      "conversation_id": "conv_9f2c41d08ab37e51",
      "segment_id": "c7e5a1d2-4f6b-5a38-9c21-8b0e3d47f6a9",
      "anchor_signal_id": "8c1d2e3f-4a5b-6c7d-8e9f-0a1b2c3d4e5f",
      "anchor_msg_index": 7,
      "signal_family": "tool_failure",
      "signal_type": "validation_error",
      "confidence": 0.9,
      "causal_rationale": "The failure occurs on every escalation where the agent sets priority to 'urgent'.",
      "door": "rubric_match",
      "replay_verified": true,
      "evidence_snippet": "{\"excerpt\":\"create_ticket failed: 422 Unprocessable Entity\",\"families\":[\"tool_failure\"],\"line\":\"priority must be one of low, normal, high\",\"anchor\":{\"family\":\"tool_failure\",\"type\":\"validation_error\",\"msg_index\":7},\"door\":\"rubric_match\",\"mechanism\":\"invalid enum value\"}",
      "dedup_count": 1,
      "user_id": "user_4821",
      "assigned_at": "2026-08-14T09:52:30",
      "snippet_parsed": {
        "excerpt": "create_ticket failed: 422 Unprocessable Entity",
        "families": ["tool_failure"],
        "line": "priority must be one of low, normal, high",
        "anchor": { "family": "tool_failure", "type": "validation_error", "msg_index": 7 },
        "door": "rubric_match",
        "mechanism": "invalid enum value"
      },
      "snippet_legacy_raw_text": false,
      "report_id": "a7b6c5d4-e3f2-4109-8765-4321fedcba98"
    }
  ],
  "affected_conversations": [
    { "conversation_id": "conv_9f2c41d08ab37e51", "user_id": "user_4821", "signal_count": 3, "family_counts": { "tool_failure": 2, "emotion": 1 }, "last_signal_at": "2026-08-14T09:52:30" }
  ],
  "remainder": { "attributed_signals": 412, "unexplained_signals": 165, "coverage_pct": 71.4, "historically_attributed_signals": 447, "historical_coverage_pct": 77.5 },
  "investigation_reports": { "items": [], "has_more": true, "next_cursor": "eyJ0cyI6IjIwMjYtMDgtMTMifQ" },
  "confidence": {
    "current_rubric_version": 4,
    "causal_content_version": 3,
    "verification_status": "current",
    "audited_causal_content_version": 3,
    "current": { "causal_content_version": 3, "kinds": { "judge_audit": { "pass_rate": 0.93, "n": 15, "latest_ts": "2026-08-14T03:12:01" }, "ground_truth": null, "counterfactual_replay": { "pass_rate": 1, "n": 4, "latest_ts": "2026-08-14T03:12:20" } } },
    "stale": null,
    "samples": { "passed": [], "failed": [] }
  },
  "change_history": [],
  "impact_identity": { "known_users": 37, "unknown_identity_conversations": 5, "total_conversations": 44, "identity_coverage_pct": 88.6 },
  "hierarchy": { "tier": "leaf", "parent": { "problem_id": "9a2e7c14-5b3f-4d80-a6e1-2f7b8c9d0e13", "display_name": "Ticketing integration reliability", "tier": "macro" }, "children": [] },
  "dossier": null,
  "stories": []
}
```

<Note>
  The example trims `header` to a few fields for readability; the live response returns the complete list-row shape documented under `GET /problems`.
</Note>

## GET /problems/:id/reports

Investigation reports for one problem, keyset-paginated.

### Query parameters

<ParamField query="limit" type="integer" default="20">
  1–50.
</ParamField>

<ParamField query="cursor" type="string">
  The `next_cursor` from a previous page.
</ParamField>

Each report has `report_id`, `conversation_id`, `segment_id`, `status` (`investigated`, `no_problem`, or `rejected`), `problem_found`, `mechanism`, `narrative`, `citations[]` (`{path, ref, quote}`), `signals_explained`, `signals_total`, `signals_explained_ids[]`, `signals_unexplained_ids[]`, `suspected_surface`, `severity`, `confidence`, `primary_family`, `investigated_at`.

```bash theme={"dark"}
curl "https://moda.dev/api/v1/data/problems/3f6b0a52-9d1c-4e7a-b2f8-6c0d5e4a3b21/reports?limit=1" \
  -H "x-api-key: YOUR_MODA_API_KEY"
```

```json theme={"dark"}
{
  "problem_id": "3f6b0a52-9d1c-4e7a-b2f8-6c0d5e4a3b21",
  "requested_problem_id": "3f6b0a52-9d1c-4e7a-b2f8-6c0d5e4a3b21",
  "reports": [
    {
      "report_id": "a7b6c5d4-e3f2-4109-8765-4321fedcba98",
      "conversation_id": "conv_9f2c41d08ab37e51",
      "segment_id": "c7e5a1d2-4f6b-5a38-9c21-8b0e3d47f6a9",
      "status": "investigated",
      "problem_found": true,
      "mechanism": "create_ticket rejects the 'urgent' priority enum; the agent never surfaces the error to the user.",
      "narrative": "The user asked for an escalation. The agent called create_ticket with priority 'urgent', which the ticketing API rejects with a 422. The agent then told the user the ticket was created.",
      "citations": [
        { "path": "conversation", "ref": "msg 7", "quote": "422 Unprocessable Entity: field 'priority' must be one of low, normal, high" }
      ],
      "signals_explained": 2,
      "signals_total": 3,
      "signals_explained_ids": ["8c1d2e3f-4a5b-6c7d-8e9f-0a1b2c3d4e5f"],
      "signals_unexplained_ids": ["1f2e3d4c-5b6a-7980-1234-56789abcdef0"],
      "suspected_surface": "ticketing integration",
      "severity": "high",
      "confidence": 0.88,
      "primary_family": "tool_failure",
      "investigated_at": "2026-08-14T02:58:41"
    }
  ],
  "pagination": { "limit": 1, "has_more": true, "next_cursor": "eyJ0cyI6IjIwMjYtMDgtMTMifQ" }
}
```

## GET /problems/:id/conversations

Conversations attributed to one problem, keyset-paginated, with per-conversation counts and an anchor for deep-linking.

### Query parameters

<ParamField query="limit" type="integer" default="25">
  1–50.
</ParamField>

<ParamField query="cursor" type="string">
  The `next_cursor` from a previous page.
</ParamField>

<ParamField query="family" type="string">
  Filter to one signal family (for example `tool_failure`, `emotion`).
</ParamField>

<ParamField query="door" type="string">
  How the conversation joined the problem: `rubric_match` or `local_causal_chain`.
</ParamField>

```bash theme={"dark"}
curl "https://moda.dev/api/v1/data/problems/3f6b0a52-9d1c-4e7a-b2f8-6c0d5e4a3b21/conversations?limit=1" \
  -H "x-api-key: YOUR_MODA_API_KEY"
```

```json theme={"dark"}
{
  "problem_id": "3f6b0a52-9d1c-4e7a-b2f8-6c0d5e4a3b21",
  "requested_problem_id": "3f6b0a52-9d1c-4e7a-b2f8-6c0d5e4a3b21",
  "family": null,
  "door": null,
  "conversations": [
    {
      "conversation_id": "conv_9f2c41d08ab37e51",
      "user_id": "user_4821",
      "attribution_count": 3,
      "families": { "tool_failure": 2, "emotion": 1 },
      "first_anchor_at": "2026-08-14T09:31:41",
      "last_anchor_at": "2026-08-14T09:52:30",
      "latest_anchor": {
        "segment_id": "c7e5a1d2-4f6b-5a38-9c21-8b0e3d47f6a9",
        "anchor_signal_id": "8c1d2e3f-4a5b-6c7d-8e9f-0a1b2c3d4e5f",
        "anchor_msg_index": 7
      }
    }
  ],
  "pagination": { "limit": 1, "has_more": true, "next_cursor": "eyJ0cyI6IjIwMjYtMDgtMTQifQ" }
}
```

Use `latest_anchor.anchor_msg_index` with [`/conversations/:id/context`](/data-api/conversations#get-conversationsidcontext) to read the moment the signal fired.

## GET /problems/:id/evidence

All evidence attributions for one problem, keyset-paginated. Rows have the same shape as the `evidence` block on `GET /problems/:id`: `attribution_id`, `conversation_id`, `segment_id`, `anchor_signal_id`, `anchor_msg_index`, `signal_family`, `signal_type`, `confidence`, `causal_rationale`, `door`, `replay_verified` (or `null`), `evidence_snippet`, `dedup_count`, `user_id`, `assigned_at`, `snippet_parsed` (structured parse of `evidence_snippet`, `null` for legacy raw-text rows), `snippet_legacy_raw_text`, `report_id` (or `null` for fast-lane rows).

### Query parameters

<ParamField query="limit" type="integer" default="25">
  1–50.
</ParamField>

<ParamField query="cursor" type="string">
  The `next_cursor` from a previous page.
</ParamField>

```bash theme={"dark"}
curl "https://moda.dev/api/v1/data/problems/3f6b0a52-9d1c-4e7a-b2f8-6c0d5e4a3b21/evidence?limit=25" \
  -H "x-api-key: YOUR_MODA_API_KEY"
```

## POST /problems/:id/feedback

Records feedback on a problem. Feedback does not edit the problem directly — it is incorporated automatically. `mark_fixed` also arms automatic reopening if the problem recurs. This is the endpoint behind `moda problem-feedback`.

### Body fields

<ParamField body="action" type="string" required>
  One of `mark_fixed`, `dismiss`, `flag_attribution`, `rename`.
</ParamField>

<ParamField body="reason" type="string">
  Up to 2,000 characters. **Required** for `dismiss` and `flag_attribution`.
</ParamField>

<ParamField body="attribution_id" type="string">
  **Required** for `flag_attribution`. A non-UUID value returns `400`; a UUID that does not belong to this problem returns `404`.
</ParamField>

<ParamField body="new_display_name" type="string">
  Up to 255 characters. **Required** for `rename`.
</ParamField>

<ParamField body="actor" type="string" default="data-api">
  Recorded as the acting identity, up to 255 characters.
</ParamField>

<Note>
  This endpoint is idempotent: `feedback_id` is derived deterministically from the payload, so resubmitting identical feedback while it is still pending returns the same `feedback_id` with `duplicate: true` and records nothing new. Safe to retry.
</Note>

```bash theme={"dark"}
curl -X POST "https://moda.dev/api/v1/data/problems/3f6b0a52-9d1c-4e7a-b2f8-6c0d5e4a3b21/feedback" \
  -H "x-api-key: YOUR_MODA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"action": "mark_fixed", "reason": "Priority enum fixed in ticketing client v2.4.1", "actor": "release-bot"}'
```

```json theme={"dark"}
{
  "success": true,
  "feedback_id": "c2d4e6f8-0a1b-4c3d-9e8f-7a6b5c4d3e2f",
  "problem_id": "3f6b0a52-9d1c-4e7a-b2f8-6c0d5e4a3b21",
  "action": "mark_fixed",
  "status": "pending",
  "duplicate": false
}
```

A malformed (non-UUID) problem ID returns `400`.

## GET /problems/:id/feedback

Feedback history for one problem, with pending/consumed state.

```bash theme={"dark"}
curl "https://moda.dev/api/v1/data/problems/3f6b0a52-9d1c-4e7a-b2f8-6c0d5e4a3b21/feedback" \
  -H "x-api-key: YOUR_MODA_API_KEY"
```

```json theme={"dark"}
{
  "problem_id": "3f6b0a52-9d1c-4e7a-b2f8-6c0d5e4a3b21",
  "requested_problem_id": "3f6b0a52-9d1c-4e7a-b2f8-6c0d5e4a3b21",
  "feedback": [
    {
      "feedback_id": "c2d4e6f8-0a1b-4c3d-9e8f-7a6b5c4d3e2f",
      "feedback_kind": "mark_fixed",
      "reason": "Priority enum fixed in ticketing client v2.4.1",
      "attribution_id": null,
      "new_display_name": "",
      "actor": "release-bot",
      "status": "pending",
      "consumed_by_run_id": null,
      "created_at": "2026-08-14T12:02:19.000Z"
    }
  ],
  "pending_count": 1
}
```

## POST /feedback

General feedback about data quality — a wrong cluster label, a mismatched frustration cause, missing data. This is separate from [problem feedback](#post-problemsidfeedback) (which `moda problem-feedback` sends): it flags issues with what the Data API returned, and it is what `moda feedback` sends. Returns `202`.

### Body fields

<ParamField body="category" type="string" required>
  One of `bad_cluster_label`, `mismatched_frustration`, `missing_data`, `noisy_data`, `wrong_tool_failure`, `incorrect_loop`, `api_quirk`, `other`.
</ParamField>

<ParamField body="severity" type="string" default="low">
  One of `info`, `low`, `medium`, `high`.
</ParamField>

<ParamField body="note" type="string">
  Up to 4,000 characters describing what looked wrong.
</ParamField>

<ParamField body="source" type="string">
  One of `cli`, `sdk`, `ui`.
</ParamField>

<ParamField body="agent" type="string">
  The agent submitting the feedback, up to 64 characters.
</ParamField>

<ParamField body="cli_version" type="string">
  Up to 32 characters.
</ParamField>

<ParamField body="refs" type="object">
  Free-form references, for example `{"conversation_id": "...", "tool_name": "..."}`.
</ParamField>

<ParamField body="command_context" type="object">
  Free-form context about the command or query that produced the suspect result.
</ParamField>

<Warning>
  Unlike problem feedback, this endpoint is **not** idempotent — every request creates a new feedback record with a random `feedback_id`. Do not retry it automatically.
</Warning>

```bash theme={"dark"}
curl -X POST "https://moda.dev/api/v1/data/feedback" \
  -H "x-api-key: YOUR_MODA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "category": "bad_cluster_label",
    "severity": "low",
    "note": "Cluster node_47 is labeled Refund requests but contains mostly invoice questions.",
    "source": "sdk",
    "refs": { "cluster_id": "node_47" }
  }'
```

```json theme={"dark"}
{
  "feedback_id": "f0e1d2c3-b4a5-4968-8776-5544332211aa",
  "submitted_at": "2026-08-14 12:05:31.482"
}
```

## Next steps

* [Dashboard: Problems](/dashboard/problems) — the same problem book as a kanban with dossiers.
* [Signals](/data-api/signals) — the raw detections that problems are built from.
* [Conversations](/data-api/conversations) — read the context around any evidence anchor.
