Overview
Search resolves entities and pulls evidence from Arcmira’s media index (long-form video and podcasts on YouTube).- Base URL:
https://api.arcmira.com, all paths under/v1. - Auth:
Authorization: Bearer arc_sk_...orx-api-key: arc_sk_.... If both are sent,x-api-keywins. - Scope: all endpoints on this page need
read(present on every key). Commercial endpoints additionally need a Pro+ tier AND therecommendations:readscope; verify withGET /v1/me→recommendations_api_enabledandscopes. - Billing: lookups and searches are free. Mention/appearance rows cost 1 row each from the shared monthly pool (the first 5 rows of each distinct pull are free). Commercial rows bill at 10 rows each.
GET /v1/mecosts 0 rows; checkusage.rows_remainingbefore large pulls. - Five entity types:
person,organization,product,topic,channel. Onlypersonhas appearances.
Minimal working example
Endpoints
GET /v1/entities/lookup: resolve to a canonical ID
Exact resolution. Passname (+ optional type) or id. Follows merge chains; response is { "entity": { id, name, type, merged_from_id, route, ... } }. merged_from_id is non-null when the input was an alias. Free. Missing entities: 404 entity_not_found.
GET /v1/entities/search: ranked discovery
Fuzzy, ranked, free.q (required, min 2 chars), type, has_recommendations_data=true, limit (1-25, default 10). Single page, no cursor. Ordered by appearance_count desc. Rows include recommendations_summary only for Pro+ callers with recommendations:read; other callers get the same row without that field (no error).
GET /v1/search: resolve a name to a single entity
Single-result name resolution for a free-textq (+ optional type). Returns the best match as { found: true, ... } or { found: false }. The entity.id here is a raw number; prefix it as ent_{id} for the entities endpoints, or use lookup, which returns the public form. Single result, no pagination. Free. Use entities/search for ranked lists; use lookup when you already know the exact name or ID.
GET /v1/entities/: read canonical metadata
{ "entity": { id, canonical_id, name, type, url, image_url, appearance_count, is_canonical, merged_from_id, route } }. On organization/product entities, Pro+ + recommendations:read callers also get a recommendations_summary aggregate block (0 rows). appearance_count counts indexed mention/appearance rows for any entity type.
GET /v1/entities/cards: batched compact cards
ids as a comma-separated list of raw integer entity IDs (ids=12,844,1032, 1-50 of them); the ent_* form is not accepted here. Returns compact card objects under the requested IDs; unknown IDs are silently dropped. Free.
GET /v1/mentions: evidence rows
The primary evidence surface. At least one ofentity_id or entity_name is required; if both are sent, entity_id wins.
| Parameter | Type | Default | Description |
|---|---|---|---|
entity_id | string | — | Canonical ent_*. Mutually exclusive with entity_name. Prefer this. |
entity_name | string | — | Human-readable name; pair with entity_type to disambiguate. |
entity_type | enum | — | person, organization, product, topic, channel. |
channel_id | string | — | Restrict to one YouTube channel ID (UC...). |
channel_name | string | — | Substring match on source channel name. |
q | string | — | Free text over description, media title, entity name, channel name. |
sentiment | enum | — | positive, neutral, negative. |
is_appearance | boolean | — | Person entities only; true on a non-person returns 400 appearances_person_only. |
date_from / date_to | ISO date | — | Inclusive bounds on published_at. |
details | enum | — | full attaches commercial rows per mention. Pro+ + recommendations:read; charges premium rate per attached item. |
limit | int | 20 | 1-100. |
cursor | string | — | Opaque, from prior next_cursor. |
GET /v1/entities//mentions: entity-scoped variant
Identical shape and filters (minusentity_*); the entity rides in the path. Preferred for production: explicit, no URL-encoded names.
GET /v1/people//appearances: person appearances
The appearance subset for one person. Person-only: the equivalent route for any other type returns400 appearances_person_only.
Documented exception: this route and the related-entity lists below return { items, total, offset, limit, hasMore } (camelCase, offset-based, with a total) instead of the standard { data, has_more, next_cursor } envelope. No cursor is returned, so pages past the first are not reachable here today. For appearance rows with standard pagination, date filters, and the mention-row shape, prefer GET /v1/mentions?entity_id=...&is_appearance=true.
Related-entity lists
q (substring), field, sort, order. One row each. Same { items, total, ... } exception shape as appearances above; raise limit (max 100) and narrow with q instead of paging.
Commercial endpoints (Pro+ + recommendations:read)
mention_class (ad_read|endorsement|mention|all, default all), min_confidence (default 0.7), include_disputed (default false), min_ad_reads (sponsors, default 3), status (sponsors: active|lapsed|ended|uncertain). Full narrative: Commercial intelligence.
Response schema
Mention row (the shape you will parse most):| Field | Type | Notes |
|---|---|---|
id | string | Public men_* form. Use it in Community Review corrections. |
start_seconds / end_seconds | number | null | Integer seconds; read these. 0 means the full episode, no specific moment. Null when the analyzer could not locate the mention in time. |
start_timestamp / end_timestamp | string | null | Deprecated MM:SS (or HH:MM:SS) strings, kept until a changelog-announced removal. Same information as the seconds fields. |
sentiment_score | number | null | Raw [-1, 1], null when not computed. sentiment is the bucketed label (positive > 0.2, negative < -0.2, else neutral). |
is_appearance | boolean | Always false for non-person entities. |
confidence | number | Extraction confidence [0, 1]. |
source_channel | object | null | Null when the video has not been linked to a channel entity (including some YouTube rows). |
next_cursor | string | null | Null when has_more is false. Opaque; pass back verbatim. |
details=full, each row gains recommendations: { items: [...] } where items carry com_* IDs, mention_class, verbatim_quote, promo_code, and timestamps (start_seconds/end_seconds plus the deprecated MM:SS strings); items is [] when nothing matches.
Errors
Envelope on every error:| Code | HTTP | When |
|---|---|---|
invalid_query | 400 | Param validation failed; error.message has the validator output. |
appearances_person_only | 400 | Appearance surface or is_appearance=true on a non-person. Use mentions instead. |
invalid_api_key | 401 | Missing, malformed, disabled, or internal (arc_int_*) key. |
quota_exceeded | 402 | Monthly rows exhausted and on-demand disabled. |
insufficient_scope | 403 | Key lacks the needed scope (message names it). |
recommendations_not_enabled | 403 | Commercial route on a tier below Pro+, regardless of scope. |
entity_not_found | 404 | ID or name did not resolve. |
channel_not_found | 404 | Sponsors called with a channel ID that has no indexed media. |
rate_limit_exceeded | 429 | Honor Retry-After. |
error.code, never on error.message. Quote X-Request-Id to support.
Rate limits & idempotency
- Per-key fixed 60-second window: free 60/min, paid (incl. Ultra) 240, teams/enterprise 600. Headers on every authenticated response:
RateLimit-Limit,RateLimit-Remaining,RateLimit-Reset; 429s addRetry-After. - Every data endpoint on this page is
GET: noIdempotency-Keyneeded, retries are safe. The one write isPOST /v1/feedbackbelow; sendIdempotency-Keyon it.
Community Review
Every result on this page is disputable, free (0 rows), viaPOST /v1/feedback. Pick the type matching the surface you called, echo the reproducing query, and target rows by public ID:
| You called | type | Correction targets |
|---|---|---|
/v1/search | search | The resolved ent_* (or a missing_result); for bad_ranking, suggested_change carries observed_rank/expected_rank |
/v1/entities/search | entities_search | ent_* hits; issue_type: bad_ranking, wrong_entity_type, duplicate_entity, merge_suggestion, missing_result |
/v1/entities/lookup, /v1/entities/{id} | entities | The ent_*; wrong_entity_type, stale_metadata, merge_suggestion |
/v1/mentions | mentions | men_* rows; wrong_entity, missing_result |
/v1/people/{slug}/appearances | appearances | Appearance rows; person_not_present, wrong_person, wrong_appearance_role |
/v1/recommendations | recommendations | com_* rows; reason: false_positive_ad_read, missed_ad_read, wrong_classification, … |
/v1/channels/{id}/sponsors | channel_sponsors | Sponsor ent_* with query.channel_id |
GET /v1/feedback/{feedback_id}.
Idempotency-Key. Up to 100 corrections per submission. Full catalog: Community Review.
Common mistakes
Wrong parameters and patterns frequently generated for this API. Do not use the left column.| Wrong | Correct |
|---|---|
Authorization: arc_sk_... (bare key) | Authorization: Bearer arc_sk_... or x-api-key: arc_sk_... |
Using an arc_int_* session key | v1 rejects internal keys; use an arc_sk_* API key |
Pulling mentions by entity_name in production | Resolve once with /v1/entities/lookup, cache ent_*, pass entity_id |
GET /v1/organizations/{slug}/appearances | Appearances are person-only; use /v1/mentions?entity_id=... |
is_appearance=true with a non-person entity | Returns 400 appearances_person_only; omit it |
Parsing start_timestamp as a number | Read start_seconds/end_seconds (integer seconds); the legacy start_timestamp strings are deprecated |
Calling /v1/recommendations with only read scope | Needs Pro+ tier AND recommendations:read; check /v1/me first |
Passing ent_* IDs to /v1/entities/cards | That endpoint takes raw integers only (ids=12,844); strip the prefix |
Decoding or constructing cursor values | Cursors are opaque; pass next_cursor back verbatim |
Branching on error.message | Switch on error.code; follow doc_url |
Patterns and gotchas
- Resolve-then-pull: lookups are free, metered rows are not; never burn rows on an ambiguous name.
recommendations_summaryblocks are aggregates and cost 0 rows; row-level pulls are what bill.details=fullmultiplies cost (mention rows + 10 rows per attached commercial item); use only when you need the overlay.- Merge-aware queries: querying a canonical
ent_*includes rows from entities merged into it. If results look split across variants, that is amerge_suggestionfor Community Review, not a client-side join. has_more: falsemeansnext_cursor: null; stop paging.- Watch
RateLimit-Remainingwhile iterating; back off before hitting 429. - Every response carries
X-Request-Id; log it.