Skip to main content

Arcmira Python SDK

The official Python client for the Arcmira API, with synchronous and asynchronous clients, typed responses, and cursor pagination.

pip install arcmira

Set ARCMIRA_API_KEY before you import the client, or pass api_key to it.

First call

Reads take ids. Resolve a name to an id, then read with the id.

from arcmira import Arcmira

client = Arcmira()
match = client.entities.resolve(q="Ramp", type="organization")
ramp = match.best or match.suggested
if ramp is None:
    raise LookupError(match.note)
for mention in client.mentions.list(entity_id=ramp.id, after="2026-09-01", before="2026-10-01"):
    print(mention.media.video_id, mention.start_seconds, mention.description)

entities.resolve answers one of three ways. best is a certain match. suggested is the likeliest row, with a reason, when no row is certain. ask lists the options when several rows fit, and best and suggested are both None. For a show, pass type="channel" and use best.youtube_channel_id as channel_id.

A name where an id belongs raises BadRequestError with the code id_required. Its message names the parameter and the resolve call.

Dates

Every dated read takes after and before. The window is half-open, [after, before). Each accepts an ISO date (2026-09-01) or a datetime with an offset (2026-09-01T00:00:00Z), read in UTC. Each dated read echoes the window it applied in window.

Premium transcripts

A Premium read is one call. It answers 200 ready when the account owns the transcript. Otherwise it buys the whole video within the account's plan and answers 202 pending with the job. Included credits are spent first, then the account's on-demand budget. The budget is the approval, so the call takes no price ceiling.

Read again after Retry-After. Repeated reads join the same purchase and never buy twice.

import time
from arcmira import Arcmira

client = Arcmira()
for _ in range(60):
    read = client.transcripts.with_raw_response.get("dQw4w9WgXcQ", quality="premium")
    if read.data.state == "ready":
        for line in read.data.lines:
            print(line.start, line.text)
        break
    if read.data.state == "failed":
        raise RuntimeError(f"{read.data.last_attempt.status}: {read.data.last_attempt.error}")
    time.sleep(int(read.headers.get("retry-after") or read.data.job.next_poll_seconds or 10))

read.data is a TranscriptResult, discriminated on state. ready carries the transcript. pending carries job, with eta_seconds, next_poll_seconds and charge. failed means the last purchase failed or was refunded; it carries job and last_attempt, buys nothing, and retry=True buys it again. Without with_raw_response, client.transcripts.get(...) returns the same union without the status and headers.

A quote is free and changes nothing.

quote = client.transcripts.quote("dQw4w9WgXcQ")
print(quote.quote.rows, quote.charge.amount, quote.charge.from_, quote.max_on_demand_cents)

client.transcripts.list_requests() lists past purchases with their state.

A read without quality="premium" returns captions and buys nothing.

Errors

A refusal raises a typed error from arcmira.errors. Each derives from arcmira.core.api_error.ApiError and carries status_code, headers and body. body.error holds type, code, message, param, gate, unlock, details, doc_url and request_id. Switch on type and gate first. Codes inside a type can grow.

Status Error Example codes
400 BadRequestError invalid_query, id_required, invalid_cursor
401 UnauthorizedError invalid_api_key
402 PaymentRequiredError quota_exceeded, spend_limit_exceeded
403 ForbiddenError paid_plan_required, freshness_requires_paid
404 NotFoundError entity_not_found
409 ConflictError tracker_already_exists
429 TooManyRequestsError rate_limited
500, 503 InternalServerError, ServiceUnavailableError

A priced refusal carries the price in error.details.quote. Nothing is charged.

from arcmira.errors import ForbiddenError, PaymentRequiredError

try:
    client.transcripts.get("dQw4w9WgXcQ", quality="premium")
except (PaymentRequiredError, ForbiddenError) as refusal:
    error = refusal.body.error
    print(error.code, error.details.quote.rows, error.unlock.url)

str(refusal) reads 402 quota_exceeded: <message>. A duplicate tracker carries the existing id in error.details.existing_id.

Pagination

mentions.list, recommendations.list, channels.videos.list and transcripts.list_requests return pagers. Iterate them and they follow next_cursor for you. Cursors are opaque. Keep the filters the same between pages.

for episode in client.channels.videos.list("UC-DRzaGnL_vtBUpCFH5M0tg", limit=10):
    print(episode.video_id)

Each page body names its rows: mentions, recommendations, episodes or requests. The alert lists (monitors.alerts.list, trackers.alerts.list) return one page of alerts, newest first. Pass a larger limit to read further.

Async

AsyncArcmira has the same methods to await. Paginated methods return async iterators after you await the first page.

from arcmira import AsyncArcmira

async def ramp_sponsorships():
    client = AsyncArcmira()
    async for row in await client.recommendations.list(entity_id="ent_14", class_="sponsored"):
        print(row.class_, row.media.video_id, row.start_seconds)

class is a Python keyword, so the parameter and the field are spelled class_. The wire name stays class.

Methods

Each method has the full parameter list in the generated reference.

Group Methods
entities resolve, get, momentum
mentions list, count
recommendations list
transcripts search, get, quote, list_requests
channels coverage, videos.list, sponsors.list
monitors list, create, update, delete, rotate_webhook_secret, trackers.list, trackers.add, entities.add, alerts.list
trackers list, create, update, delete, alerts.list
integrations slack.list
feedback submit, get
me get, update_settings
health check

transcripts.search returns spoken passages from GET /v1/search. Its filters take ids too.

To follow an entity you have an id for, call monitors.entities.add(monitor_id, entity_ids=["ent_14"]). To watch an exact name before it is indexed, call trackers.create(entity_name="Ramp", entity_type="organization"). A channel tracker takes the YouTube channel id as entity_name.

See CHANGELOG.md for what changed from 0.3.

Agents

The Arcmira MCP server gives AI agents the same data at https://mcp.arcmira.com/mcp. llms.txt describes this package for agents.

Regenerate and verify

Run bash scripts/generate.sh with Node 22 or newer, Python 3, Docker, and Fern access for the arcmira organization. Generation pins Fern CLI 5.131.1 and Python generator 5.31.0, disables CLI version redirection and telemetry, and reads fern/openapi.json. fern/method-names.json names the group and method of every operation by operationId. An operation without a name, or a name for an operation the document lacks, fails the build. The overlay combines the transcript read's success schemas into TranscriptResult and rejects unknown or ambiguous cursor collections. Generated source is never edited by hand. scripts/overrides/api_error.py holds the ApiError text, and the installer copies it back after every generation.

uv sync
uv run python -m unittest discover -s tests -v
uv build

The tests use a local HTTP server that returns the bodies the API sends. They check both client variants, the ready and pending reads, typed refusals with their quote, the query and body each call sends, and opaque pagination. No live API key or purchase is required.

License

Apache-2.0. See LICENSE.

Metadata

Release files for arcmira 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for arcmira 0.4.0
File Size Uploaded
arcmira-0.4.0.tar.gz 139.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for arcmira 0.4.0
File Interpreter ABI Platform
arcmira-0.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 463.6 kB

Release files / arcmira-0.4.0.tar.gz

Download URL arcmira-0.4.0.tar.gz
Size 139.2 kB
Tags Source
SHA-256 checksum
How to use checksums
e1f37b87958e940c6410408b06a6d8c2f137481679ab71cfb618050aa467d0c2
BLAKE2b-256 checksum
How to use checksums
71f51917283a38b46ff4d26783ab83c0c5fcf9e4166cb460e39eae195ac5534a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.22 {"installer":{"name":"uv","version":"0.12.22","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / arcmira-0.4.0-py3-none-any.whl

Download URL arcmira-0.4.0-py3-none-any.whl
Size 324.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
199e472c097026e94f407439b2ada2ab4bc06c9438ff70df058329075cb8f834
BLAKE2b-256 checksum
How to use checksums
1c80d75e7d3e9aa3dffc1b7bcbd46791e9412ad86eeebbe267a6beeafa22f310
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.22 {"installer":{"name":"uv","version":"0.12.22","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

0.4.3

2 release files

0.4.2

2 release files

0.4.1

2 release files

This release

0.4.0 This release

2 release files

0.3.0

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page