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

# Commercial intelligence

> Ad reads, endorsements, and channel sponsors. The commercial evidence layer behind /v1/recommendations and /v1/channels/{id}/sponsors (Pro+).

Commercial intelligence is Arcmira's paid-evidence layer: a second extraction pipeline that classifies on-camera commercial activity into paid **ad reads**, organic **endorsements**, and lower-signal commercial **mentions**, then rolls recurring relationships up into per-channel **sponsor lists**. In API terms it is two endpoint families: `GET /v1/recommendations` (row-level evidence) and `GET /v1/channels/{channel_id}/sponsors` (the rollup).

<Warning>
  Commercial intelligence requires a **Pro+ tier** (`pro_plus`, `ultra`, `teams`, `enterprise`) AND the `recommendations:read` scope. Lower tiers get `403 recommendations_not_enabled` regardless of scope; correctly tiered keys missing the scope get `403 insufficient_scope`. Check `/v1/me` → `recommendations_api_enabled` before calling, and manage plans from [Pricing](https://arcmira.com/pricing).
</Warning>

## When to use

* **You sell sponsorships or negotiate them.** Pull a channel's recurring advertisers before a negotiation: "who already sponsors TBPN, at what cadence, since when?" Never go into a sponsorship negotiation blind.
* **You model competitor spend.** Row-level ad reads carry verbatim quotes, promo codes, and offers: "every Ramp ad read across business podcasts this year, with the codes they ran."
* **You find organic champions.** Endorsements are unpaid recommendations from hosts and guests: "which shows organically endorsed Figma after the IPO?"
* **You build advertiser dashboards.** Re-expose the classification, confidence, and dispute machinery in your own product.

## The two universes

Arcmira runs two independent extraction pipelines:

| Universe   | Endpoint              | What it answers                                   | Cost         |
| ---------- | --------------------- | ------------------------------------------------- | ------------ |
| Mentions   | `/v1/mentions`        | "Where was this entity *talked about*?"           | 1 row each   |
| Commercial | `/v1/recommendations` | "Where was this entity *paid for* or *endorsed*?" | 10 rows each |

Different prompts, different quality rules, different false-positive profiles. They are deliberately not joined into one result set; [`/v1/mentions?details=full`](/search-for-coding-agents#get-v1mentions-evidence-rows) attaches matching commercial rows to mention rows, but the populations stay distinct.

## Classification

Every commercial row carries a `mention_class`:

| Class         | Definition                                                                                                  |
| ------------- | ----------------------------------------------------------------------------------------------------------- |
| `ad_read`     | A paid sponsor read. Typically explicit ("this episode is brought to you by..."), often with a promo code.  |
| `endorsement` | An organic recommendation from a host or guest. No money involved; the speaker vouches for it.              |
| `mention`     | A lower-signal commercial reference that didn't meet the `ad_read`/`endorsement` bar. Surfaced for context. |

Quality rules baked into the pipeline: entities with fewer than 3 ad reads on a channel are one-offs, not sponsors (tunable via `min_ad_reads`); a singleton `ad_read` with no sponsor language is downgraded to `mention`; canonical entity merges are followed automatically; rows with `conflict_status: "disputed"` are excluded unless you pass `include_disputed=true`.

## Recommendations: row-level evidence

```text theme={null}
GET /v1/recommendations
GET /v1/entities/{id}/recommendations
```

Exactly one of `entity_id` or `entity_name` is required (the entity-scoped form takes it from the path).

<CodeGroup>
  ```typescript TypeScript theme={null}
  const res = await fetch(
    'https://api.arcmira.com/v1/recommendations?entity_id=ent_14&mention_class=ad_read&limit=25',
    { headers: { Authorization: `Bearer ${process.env.ARCMIRA_API_KEY}` } },
  );
  const { data, has_more, next_cursor } = await res.json();
  ```

  ```python Python theme={null}
  import os, httpx

  r = httpx.get(
      'https://api.arcmira.com/v1/recommendations',
      params={'entity_id': 'ent_14', 'mention_class': 'ad_read', 'limit': 25},
      headers={'Authorization': f"Bearer {os.environ['ARCMIRA_API_KEY']}"},
  )
  body = r.json()
  ```

  ```bash cURL theme={null}
  curl 'https://api.arcmira.com/v1/recommendations?entity_id=ent_14&mention_class=ad_read&limit=25' \
    -H "Authorization: Bearer $ARCMIRA_API_KEY"
  ```
</CodeGroup>

| Parameter                     | Default | Description                                                       |
| ----------------------------- | ------- | ----------------------------------------------------------------- |
| `entity_id` / `entity_name`   | —       | Canonical `ent_*` or a name (pair names with `entity_type`).      |
| `channel_id` / `channel_name` | —       | Restrict to one channel (YouTube `UC...` ID) or a name substring. |
| `mention_class`               | `all`   | `ad_read`, `endorsement`, `mention`, or `all`.                    |
| `min_confidence`              | `0.7`   | Float in `[0, 1]`.                                                |
| `include_disputed`            | `false` | Include rows whose classification is disputed.                    |
| `date_from` / `date_to`       | —       | Inclusive ISO-date bounds on `published_at`.                      |
| `limit` / `cursor`            | 20 / —  | Standard cursor pagination.                                       |

```json Response row theme={null}
{
  "id": "com_119682",
  "recommendation_id": 119682,
  "mention_class": "ad_read",
  "entity": { "id": "ent_124261", "name": "Bezel", "type": "organization" },
  "media": {
    "video_id": "DRZatti6mVM",
    "title": "...",
    "published_at": "2025-12-17",
    "channel_id": "UC-DRzaGnL_vtBUpCFH5M0tg",
    "source_channel": { "id": "ent_6", "name": "TBPN" }
  },
  "start_timestamp": "12:34",
  "end_timestamp": "13:02",
  "start_seconds": 754,
  "end_seconds": 782,
  "verbatim_quote": "...",
  "promo_code": "BEZEL20",
  "offer": null,
  "sentiment": 0.8,
  "sentiment_score": 0.8,
  "confidence": 0.95,
  "speaker_role": "host",
  "conflict_status": null,
  "resolution": null
}
```

* `id` is the public `com_*` form: pass it to [Community Review](/feedback) to dispute a row.
* Read `start_seconds`/`end_seconds` (integer seconds; `0` means the full episode). The `start_timestamp`/`end_timestamp` `MM:SS` strings are deprecated and will be removed after a changelog-announced sunset.
* `sentiment_score` is the raw `[-1, 1]` number, matching mention rows. The `sentiment` field carries the same number and is deprecated; read `sentiment_score`.
* `promo_code` and `offer` are nullable, populated when the extractor found explicit codes or offers in the quote.
* `speaker_role` distinguishes host reads from guest recommendations.
* `conflict_status`/`resolution` surface cross-pass classification conflicts; disputed rows are excluded by default.

## Channel sponsors: the rollup

```text theme={null}
GET /v1/channels/{channel_id}/sponsors
```

`{channel_id}` is a YouTube channel ID (`UC-DRzaGnL_vtBUpCFH5M0tg`), not an `ent_*`.

| Parameter      | Default | Description                                                                                                                                    |
| -------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `min_ad_reads` | `3`     | Minimum `ad_read` rows for an entity to count as recurring. 1 surfaces every one-off; 5-10 focuses on long-running relationships. Range 1-100. |
| `status`       | (any)   | Filter by advertiser status: `active`, `lapsed`, `ended`, `uncertain`.                                                                         |
| `limit`        | `100`   | 1-200, ordered by ad-read count descending.                                                                                                    |

```json Response (truncated) theme={null}
{
  "channel": { "id": "ent_6", "youtube_channel_id": "UC-DRzaGnL_vtBUpCFH5M0tg", "name": "TBPN" },
  "sponsors": [
    {
      "entity": { "id": "ent_14", "name": "Ramp", "type": "organization" },
      "ad_reads": 227,
      "videos": 197,
      "first_seen": "2025-02-01",
      "last_seen": "2026-04-24",
      "sponsor_status": { "status": "active", "ad_count": 80, "first_ad_date": "2025-02-01", "last_ad_date": "2026-04-24" }
    }
  ],
  "meta": { "min_ad_reads": 3, "count": 40 }
}
```

* `channel.id` is `null` when there is no canonical entity for the channel; `youtube_channel_id` is always present.
* `sponsor_status` is `null` for entities not in the known-advertiser registry; when present, `status` is `active`, `lapsed`, `ended`, or `uncertain`.
* `meta.count` is the returned page size, not a global total.

Pivot from a sponsor of interest to its row-level evidence:

```bash theme={null}
curl 'https://api.arcmira.com/v1/recommendations?entity_id=ent_14&channel_id=UC-DRzaGnL_vtBUpCFH5M0tg&mention_class=ad_read&limit=25' \
  -H "Authorization: Bearer $ARCMIRA_API_KEY"
```

## Discovery and teasers

* `GET /v1/entities/search?has_recommendations_data=true` restricts discovery to entities with commercial signal (free).
* Entity reads on `organization`/`product` entities include a `recommendations_summary` aggregate for entitled callers (totals, unique shows, first/last seen, `channels_as_sponsor`). Zero rows.
* Channel reads include a teaser under `recommendations_summary`: `recommendations_summary.sponsor_count` is visible to **every** caller (a discoverability signal); `recommendations_summary.top_sponsors` appears only with Pro+ and `recommendations:read`.

## Billing

Every row returned by `/v1/recommendations` and every sponsor in `/v1/channels/{id}/sponsors` bills at **10 rows** (versus 1 for a standard mention row). `recommendations_summary` blocks and teasers cost zero rows. `details=full` on mentions charges the mention row plus 10 rows per attached commercial item. See [Usage, limits & billing](/usage-and-billing).

## Community Review

Commercial rows are exactly where you should push back: a false paid read hurts a brand, a missed one hurts a negotiation. Dispute rows by `com_*` ID, sponsors by `ent_*` + channel, for free:

```bash theme={null}
curl -X POST 'https://api.arcmira.com/v1/feedback?type=recommendations' \
  -H "Authorization: Bearer $ARCMIRA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "query": { "entity_id": "ent_124261", "mention_class": "ad_read" },
    "corrections": [{
      "id": "com_119682",
      "mention_class": "mention",
      "reason": "false_positive_ad_read",
      "notes": "Host was discussing the product organically. No sponsor language, no code."
    }]
  }'
```

Reason codes: `false_positive_ad_read`, `false_positive_endorsement`, `missed_ad_read`, `missed_endorsement`, `wrong_classification`, `wrong_entity`, `other`. Commercial review uses the same access as the data (Pro+ + `recommendations:read`); nothing auto-applies. Full catalog: [Community Review](/feedback).

## Errors

| Code                          | When                                                                    |
| ----------------------------- | ----------------------------------------------------------------------- |
| `recommendations_not_enabled` | Tier below Pro+ (independent of scope).                                 |
| `insufficient_scope`          | Pro+ key missing `recommendations:read`.                                |
| `entity_not_found`            | `entity_id`/`entity_name` didn't resolve.                               |
| `channel_not_found`           | No indexed media for the channel ID (use the `UC...` form, not a slug). |
| `invalid_query`               | Param validation failed; see `error.message`.                           |

## Next

* [Try it in the playground](/api-reference/recommendations/search-recommendations-across-media)
* [Search](/search): the free evidence layer these rows enrich.
* [Community Review](/feedback): the correction contract for every commercial surface.
