Skip to main content
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.
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):
typeReviewsAccess
search/v1/search resolutions: wrong match, missing entity (corrections may carry observed_rank)read
entities_search/v1/entities/search hits: ranking, duplicates, missing resultsread
entities/v1/entities/lookup / /v1/entities/{id} payloads: wrong type, stale metadata, mergesread
channels/v1/channels/{slug} payloadsread
mentions/v1/mentions rowsread
appearancesPerson appearance rows: person_not_present, wrong_person, wrong_appearance_roleread
recommendations/v1/recommendations rows by com_* IDPro+ + recommendations:read
channel_sponsorsSponsor 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:
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_typeUse for
wrong_entity_typeRight entity, wrong type (e.g. a company typed as a topic). suggested_change: { "field": "type", "value": "organization" }
wrong_entityThe row points at the wrong canonical entity entirely
duplicate_entity / merge_suggestionResults split across variants; suggest the canonical merge (suggested_change: { "sourceEntityId", "targetEntityId", "scopeType" } or names)
missing_resultYou know a result should exist; put video/channel/timestamp context in notes
stale_metadataWebsite, name, or channel metadata is outdated; include a source URL
bad_rankingDuplicates or aliases ranking above the canonical entity
wrong_classificationClass-level errors on commercial rows
otherEscape 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:
reasonUse for
false_positive_ad_readClassified as paid but wasn’t
false_positive_endorsementAn endorsement that wasn’t there
missed_ad_readA real paid read the pipeline missed or misclassified
missed_endorsementA real endorsement the pipeline missed
wrong_classificationAny other class error (ad_readendorsement)
wrong_entityRow attributes the wrong entity
otherFree-form; detail in notes
Worked commercial example (a creator disputing a false paid read):
{
  "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.
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:
kindFixesAnchored
line_editSegment textyes (revision + anchor.contentHash)
speaker_reassignWho said it, including sub-line splitsyes
speaker_identifyLink a diarized voice to a person (creates a community-flagged appearance immediately)no
add_personPropose a new person and link the speaker in one actionno
entity_tagTag a missed entity mention as a character spanyes
segment_rewriteStructure: merge, split, or delete segment runs, timestamps repaired automaticallyyes
Full payloads, the djb2 anchor hash, the seq queue contract (409 re-anchor / 412 expectedSeq), and withdrawal routes live in Transcripts for coding agents.

Response shape

{
  "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):
{
  "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

CodeWhen
invalid_feedback_requestMissing type, empty query, or malformed ?query= value
invalid_bodyJSON body failed validation (too many corrections, bad reason, malformed ID)
recommendations_not_enabledCommercial feedback from a tier below Pro+
insufficient_scopeKey can’t read the surface being reviewed
alert_not_foundA monitor_alert submission referenced an alert row that isn’t yours
feedback_not_foundGET /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 for the envelope.