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

> ## Agent Instructions
> Arcmira has three API capabilities: Search (entities, mentions, appearances, commercial intelligence), Monitors (trackers plus alert delivery), and Transcripts (read, generate, correct). Community Review is the cross-surface correction layer.
> Discover pages at https://docs.arcmira.com/llms.txt, then fetch the matching page's .md export. Each capability has a self-contained '<capability> for coding agents' page; prefer it.
> Auth: Authorization: Bearer arc_sk_... or x-api-key: arc_sk_... (x-api-key wins if both are sent). Never put keys in browser code. Check GET /v1/me for tier, scopes, and remaining rows before metered pulls.
> Search: resolve names with GET /v1/entities/lookup and pin ent_* IDs before pulling metered rows. Only person entities have appearances. Mention and recommendation rows carry canonical numeric timestamps in start_seconds/end_seconds (integer seconds; 0 means full episode); the MM:SS string fields are deprecated. Commercial routes need Pro+ tier AND the recommendations:read scope and bill 10 rows per row.
> Monitors: a tracker watches one entity; a monitor groups trackers with shared delivery (email, Slack, HMAC-signed webhooks). Create trackers with POST /v1/trackers, then attach by id: POST /v1/monitors/{id}/trackers { trackerIds: [...] }. Each fired alert occurrence debits 100 rows. Poll GET /v1/monitors/{id}/alerts?n= for recent deliveries. Send Idempotency-Key on every POST/PATCH.
> Transcripts: switch on the access field (unlocked, locked, premium_pending, not_transcribed, unauthenticated). Honor Retry-After when polling POST /v1/transcriptions jobs. Corrections (POST /v1/videos/{video_id}/corrections; kinds line_edit, speaker_reassign, speaker_identify, add_person, entity_tag, segment_rewrite) cost 0 rows; anchored kinds need revision + anchor.contentHash (djb2 base-36); handle 409 (re-anchor) and 412 (expectedSeq). segment_rewrite replaces an inclusive segment range with new segments (empty replacements array deletes; timestamps repaired server-side).
> Community Review is free (0 rows) and surface-typed: POST /v1/feedback with a type matching the surface you called, the reproducing query, and corrections targeting public IDs (ent_*, men_*, com_*). Nothing auto-applies. Do not send untyped notes.
> Errors: switch on error.code, follow doc_url, quote X-Request-Id to support. Honor Retry-After on 429. Retries of POST/PATCH must reuse the same Idempotency-Key; replays return Idempotency-Replayed: true.

# Community Review

> The cross-surface correction layer. Typed feedback for every Search result, monitor alert, and transcript, free, against the exact query you ran.

Every result-bearing surface in the Arcmira API accepts structured feedback. Community Review is how customers and their agents improve the media-intelligence graph: send what you saw, what you expected, and optionally what you think the fix is, typed to the surface it came from.

```text theme={null}
POST /v1/feedback                          Search-family surfaces and monitor alerts
POST /v1/videos/{video_id}/corrections     transcript content (six kinds)
```

## The shared model

These invariants hold across every surface:

* **Nothing auto-applies.** Submissions create pending review items; Arcmira reviewers accept as submitted, accept with changes, resolve differently, or reject. Transcript corrections are additionally *optimistic for you*: your own pending edits ride back on your transcript reads immediately.
* **Free.** Feedback and corrections cost **0 rows**, always.
* **Access follows the surface.** You can review what your key can read: commercial types need Pro+ and `recommendations:read`; everything else needs `read`.
* **Reproducible.** Every submission carries either the `query` that produced the result (Search family) or a positional anchor (`video_id` + `revision` + content hash, transcripts). Reviewers replay what you saw.
* **Targeted.** Corrections point at stable public IDs from the response: `ent_*`, `men_*`, `com_*`, segment anchors. Notes-only is fine; untyped is not.
* **Withdrawable.** Pending submissions are deletable by their author.
* **Retry-safe.** `Idempotency-Key` is supported everywhere; replays return `Idempotency-Replayed: true`.
* **Reputation accrues** to the submitting account and key over time. High-quality submitters may move through faster review paths; scope alone never grants automatic acceptance.

The index is AI-extracted and continuously reviewed. Every accepted submission improves the reviewed dataset that future extraction systems learn from.

## Search surfaces

Pick the `type` matching the surface you called (all submissions are logged for review):

| `type`             | Reviews                                                                                       | Access                        |
| ------------------ | --------------------------------------------------------------------------------------------- | ----------------------------- |
| `search`           | `/v1/search` resolutions: wrong match, missing entity (corrections may carry `observed_rank`) | `read`                        |
| `entities_search`  | `/v1/entities/search` hits: ranking, duplicates, missing results                              | `read`                        |
| `entities`         | `/v1/entities/lookup` / `/v1/entities/{id}` payloads: wrong type, stale metadata, merges      | `read`                        |
| `channels`         | `/v1/channels/{slug}` payloads                                                                | `read`                        |
| `mentions`         | `/v1/mentions` rows                                                                           | `read`                        |
| `appearances`      | Person appearance rows: `person_not_present`, `wrong_person`, `wrong_appearance_role`         | `read`                        |
| `recommendations`  | `/v1/recommendations` rows by `com_*` ID                                                      | Pro+ + `recommendations:read` |
| `channel_sponsors` | Sponsor entities on a channel (`ent_*` + `query.channel_id`)                                  | Pro+ + `recommendations:read` |

The envelope: `type`, the reproducing `query` (required), optional request context, and up to 100 `corrections`:

```bash theme={null}
curl -X POST 'https://api.arcmira.com/v1/feedback?type=mentions' \
  -H "Authorization: Bearer $ARCMIRA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "query": { "entity_name": "Mercury", "entity_type": "organization" },
    "endpoint": "/v1/mentions",
    "request_id": "req_...",
    "corrections": [{
      "id": "men_2049815",
      "issue_type": "wrong_entity",
      "suggested_change": { "entity_name": "Mercury Bank", "entity_type": "organization" },
      "notes": "These rows look attributed to the wrong Mercury entity."
    }]
  }'
```

### Issue types (entity-family corrections)

| `issue_type`                            | Use for                                                                                                                                       |
| --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `wrong_entity_type`                     | Right entity, wrong type (e.g. a company typed as a topic). `suggested_change: { "field": "type", "value": "organization" }`                  |
| `wrong_entity`                          | The row points at the wrong canonical entity entirely                                                                                         |
| `duplicate_entity` / `merge_suggestion` | Results split across variants; suggest the canonical merge (`suggested_change: { "sourceEntityId", "targetEntityId", "scopeType" }` or names) |
| `missing_result`                        | You know a result should exist; put video/channel/timestamp context in `notes`                                                                |
| `stale_metadata`                        | Website, name, or channel metadata is outdated; include a source URL                                                                          |
| `bad_ranking`                           | Duplicates or aliases ranking above the canonical entity                                                                                      |
| `wrong_classification`                  | Class-level errors on commercial rows                                                                                                         |
| `other`                                 | Escape hatch; detail in `notes`                                                                                                               |

### Reason codes (commercial corrections)

Commercial corrections (`recommendations`, `channel_sponsors`) target rows by `com_*` (or sponsor `ent_*`) and carry the new `mention_class` plus a `reason`:

| `reason`                     | Use for                                               |
| ---------------------------- | ----------------------------------------------------- |
| `false_positive_ad_read`     | Classified as paid but wasn't                         |
| `false_positive_endorsement` | An endorsement that wasn't there                      |
| `missed_ad_read`             | A real paid read the pipeline missed or misclassified |
| `missed_endorsement`         | A real endorsement the pipeline missed                |
| `wrong_classification`       | Any other class error (`ad_read` ↔ `endorsement`)     |
| `wrong_entity`               | Row attributes the wrong entity                       |
| `other`                      | Free-form; detail in `notes`                          |

Worked commercial example (a creator disputing a false paid read):

```json theme={null}
{
  "type": "recommendations",
  "query": { "entity_id": "ent_124261", "channel_id": "UC-DRzaGnL_vtBUpCFH5M0tg", "mention_class": "ad_read" },
  "corrections": [{
    "id": "com_119682",
    "mention_class": "mention",
    "reason": "false_positive_ad_read",
    "notes": "The host discussed the company while covering the market. Not a paid placement."
  }]
}
```

### Passing `query`

The request merges `query` from three sources: a URL `?query=` parameter (URL-encoded JSON), the JSON body's `query` object (overrides `?query=` on key conflicts), and loose query-string params (anything besides `type` and `query`, filling only keys the other two did not set). Prefer the body form. An empty `query` returns `400 invalid_feedback_request`.

## Monitor alerts

Alert feedback targets a **fired alert**, not the monitor's configuration (fix configuration with `PATCH /v1/monitors/{id}`). One matched appearance can produce multiple delivery rows (email + Slack + webhook), so content disputes key off the occurrence, and only delivery problems key off the delivery row. Alert rows carry `mention_id` (`men_*`) so you can pivot to the mention surface without joins.

```bash theme={null}
curl -X POST 'https://api.arcmira.com/v1/feedback?type=monitor_alert' \
  -H "Authorization: Bearer $ARCMIRA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "query": { "monitor_id": "mon_abc123", "tracker_id": "trk_9f2ab4c8d1e6", "alert_id": "<alert row id>" },
    "endpoint": "/v1/monitors/mon_abc123/alerts",
    "corrections": [{
      "id": "<alert row id>",
      "issue_type": "wrong_entity",
      "suggested_change": { "entity_id": "ent_999" },
      "notes": "Fired for the wrong OpenAI merge candidate."
    }]
  }'
```

Issue set: `false_positive_alert` (should not have fired), `wrong_entity`, `wrong_media`, `wrong_timestamp`, `duplicate_alert`, `missed_alert`, `delivery_issue` (the one delivery-row case: wrong channel, not received; `suggested_change: { "channel": ... }`), `other`.

`missed_alert` is an expectation: there is no row to target, so the correction carries evidence instead: `suggested_change: { "source_url": "https://youtube.com/watch?v=...", "approximate_timestamp_seconds": 532, "entity_id": "ent_123881" }`.

Referenced alert rows must belong to your account; unknown or foreign IDs return `404 alert_not_found`.

## Transcripts

Transcript content review runs through the corrections route, not `/v1/feedback`, because it needs revision and anchor semantics rather than a query replay. Six kinds on `POST /v1/videos/{video_id}/corrections`:

| `kind`             | Fixes                                                                                  | Anchored                                |
| ------------------ | -------------------------------------------------------------------------------------- | --------------------------------------- |
| `line_edit`        | Segment text                                                                           | yes (`revision` + `anchor.contentHash`) |
| `speaker_reassign` | Who said it, including sub-line splits                                                 | yes                                     |
| `speaker_identify` | Link a diarized voice to a person (creates a community-flagged appearance immediately) | no                                      |
| `add_person`       | Propose a new person and link the speaker in one action                                | no                                      |
| `entity_tag`       | Tag a missed entity mention as a character span                                        | yes                                     |
| `segment_rewrite`  | Structure: merge, split, or delete segment runs, timestamps repaired automatically     | yes                                     |

Full payloads, the djb2 anchor hash, the `seq` queue contract (409 re-anchor / 412 `expectedSeq`), and withdrawal routes live in [Transcripts for coding agents](/transcripts-for-coding-agents#corrections).

## Response shape

```json theme={null}
{
  "feedback_id": 84,
  "type": "recommendations",
  "query": { "channel_id": "UC-DRzaGnL_vtBUpCFH5M0tg", "mention_class": "ad_read" },
  "applied": 0,
  "unchanged": 0,
  "failed": 0,
  "logged": 1,
  "corrections": [
    {
      "item_id": "com_119682",
      "item_kind": "recommendation",
      "status": "logged",
      "reason": "false_positive_ad_read",
      "message": "Feedback recorded for review."
    }
  ]
}
```

Quote `feedback_id` in support threads. Public submissions always return per-item `status: "logged"`; the `applied` / `unchanged` / `failed` counters exist for reviewer tooling and stay `0` on the public path.

### Readback

Check where a submission stands with `GET /v1/feedback/{feedback_id}` (scope `read`; only the submitting user's keys can read it, and unknown or foreign IDs return `404 feedback_not_found`):

```json theme={null}
{
  "feedback_id": 84,
  "type": "monitor_alert",
  "status": "pending_review",
  "query": { "monitor_id": "mon_abc123", "alert_id": "..." },
  "notes": "From the OpenAI tracker.",
  "created_at": "2026-07-09 21:14:03",
  "corrections": [{
    "item_id": "...",
    "item_kind": "alert",
    "issue_type": "wrong_entity",
    "suggested_change": { "entity_id": "ent_999" },
    "status": "pending_review",
    "resolution_note": null,
    "created_at": "2026-07-09 21:14:03"
  }]
}
```

Status vocabulary, per submission and per correction: `pending_review`, `needs_information`, `accepted`, `accepted_with_changes` (accepted, but the reviewer changed or re-routed the final resolution), `rejected`, `withdrawn`, `applied` (the accepted change is live; accepted ≠ applied), `reverted`.

## Agent guidance

* Always include the surface-matching `type` and the reproducing `query`.
* Include `endpoint`, `method`, and `request_id` when you have them.
* Target rows by their public IDs from the response you actually received.
* Use `suggested_change` only when you have a concrete fix; otherwise `issue_type` + `notes`.
* Never assume application; nothing changes live data until review.
* Batch up to 100 corrections per submission, grouped by the query that produced them.
* Notes limits: 2,000 characters per correction, 4,000 on the top-level `notes`.
* Send `Idempotency-Key` on every submission.

## Errors

| Code                          | When                                                                           |
| ----------------------------- | ------------------------------------------------------------------------------ |
| `invalid_feedback_request`    | Missing `type`, empty `query`, or malformed `?query=` value                    |
| `invalid_body`                | JSON body failed validation (too many corrections, bad `reason`, malformed ID) |
| `recommendations_not_enabled` | Commercial feedback from a tier below Pro+                                     |
| `insufficient_scope`          | Key can't read the surface being reviewed                                      |
| `alert_not_found`             | A `monitor_alert` submission referenced an alert row that isn't yours          |
| `feedback_not_found`          | `GET /v1/feedback/{feedback_id}` on an ID that doesn't exist or isn't yours    |

A correction whose target ID doesn't resolve (a stale `com_*` or `men_*`) is not an error: the submission still returns 200 and the row is logged for review. Re-pull the surface if you want to confirm the ID before submitting.

See [Errors](/errors) for the envelope.
