From cc5c461aae1a511c37c911fadb6096daa37d2756 Mon Sep 17 00:00:00 2001 From: Zeal Caiden Date: Sun, 4 Oct 2026 12:37:23 -0700 Subject: [PATCH 1/2] 0.4.1: paid reads read as metered usage of your plan A Premium read uses credits from the plan, then the on-demand budget set in the dashboard. The README, CHANGELOG and llms.txt say so, and the 0.4.0 CHANGELOG entry is reworded in place. Version 0.4.1 in VERSION, _package.py and the User-Agent. --- CHANGELOG.md | 8 ++++++-- README.md | 12 ++++++------ VERSION | 2 +- llms.txt | 2 +- src/arcmira/_package.py | 2 +- src/arcmira/core/client_wrapper.py | 2 +- 6 files changed, 16 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 460cc0a..14d1af6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 0.4.1 + +Paid reads use credits from your plan, then your on-demand budget. + ## 0.4.0 Generated from the v1 document of 2026-10-02. The document dropped from 88 operations to 36. Routes that left it still serve over HTTP, but the SDK no longer has methods for them. @@ -15,9 +19,9 @@ Added. Breaking changes from 0.3. -- Premium is one read. `transcripts.get(video_id, quality="premium")` answers `ready` (200) when the account owns the transcript. Otherwise it buys the whole video within the plan and the account's on-demand budget and answers `pending` (202) with the `job` and a `Retry-After` header. Read again after `Retry-After`. Repeated reads join the same purchase and never buy twice. When the last purchase for the video failed or was refunded, the read answers `failed` (200) with the `job` and `last_attempt` and buys nothing; pass `retry=True` to buy it again. `TranscriptResult` is now `TranscriptResult_Ready | TranscriptResult_Pending | TranscriptResult_Failed`. Priced refusals carry one `RefusedQuote` type. The `preparation_required` state and `TranscriptResult_PreparationRequired` are gone. +- Premium is one read. `transcripts.get(video_id, quality="premium")` answers `ready` (200) when the account owns the transcript. Otherwise it starts transcribing the whole video, using credits from the plan and then the account's on-demand budget, and answers `pending` (202) with the `job` and a `Retry-After` header. Read again after `Retry-After`. Repeated reads join the same job and never use credits twice. When the last transcription of the video failed or was refunded, the read answers `failed` (200) with the `job` and `last_attempt` and uses no credits; pass `retry=True` to transcribe it again, which uses credits again. `TranscriptResult` is now `TranscriptResult_Ready | TranscriptResult_Pending | TranscriptResult_Failed`. Priced refusals carry one `RefusedQuote` type. The `preparation_required` state and `TranscriptResult_PreparationRequired` are gone. - `transcripts.prepare_and_wait` is removed, along with `PreparationError`, `PreparationFailedError`, `PreparationTimeoutError` and `PremiumUnavailableError`. Loop on `transcripts.get(..., quality="premium")` until `state == "ready"`. The README has the loop. -- `transcripts.request` and `transcripts.status` are removed, with the `TranscriptRequestSubmitResponse` type. The Premium read buys and reports its own job. `transcripts.list_requests` still lists past purchases. +- `transcripts.request` and `transcripts.status` are removed, with the `TranscriptRequestSubmitResponse` type. The Premium read starts and reports its own job. `transcripts.list_requests` still lists past Premium transcriptions. - A Premium refusal raises from the read itself. `PaymentRequiredError` (402) carries `quota_exceeded` or `spend_limit_exceeded`, and `ForbiddenError` (403) carries `paid_plan_required`. Nothing is charged. - Error extras moved under `error.details`. `body.quote` is now `body.error.details.quote`, `body.existing_request_id` is `body.error.details.existing_request_id`, and `body.existing_id` (409 `tracker_already_exists`) is `body.error.details.existing_id`. - Reads take ids. `mentions.list` and `recommendations.list` require `entity_id` (`ent_N`), and `channel_id` takes a YouTube channel id (`UC` plus 22 characters). `entity_name`, `entity_type` and `channel_name` are gone. A name where an id belongs raises `BadRequestError` with code `id_required` and names the parameter. Resolve names first with `entities.resolve`. diff --git a/README.md b/README.md index 2212946..1fe491a 100644 --- a/README.md +++ b/README.md @@ -36,9 +36,9 @@ Every dated read takes `after` and `before`. The window is half-open, `[after, b ## 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. +A Premium read is one call. It answers 200 `ready` when the account owns the transcript. Otherwise it starts transcribing the whole video and answers 202 `pending` with the job. The read uses credits from your plan, then your on-demand budget. You set that budget in the dashboard, and it 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. +Read again after `Retry-After`. Repeated reads join the same job and never use credits twice. ```python import time @@ -60,7 +60,7 @@ else: The timeout only stops this polling loop. It does not cancel the job. Resume with the same video id and `quality="premium"`; do not set `retry=True` while the job is pending. -`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. +`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 transcription failed or was refunded; it carries `job` and `last_attempt` and uses no credits. `retry=True` transcribes it again and uses credits again. Without `with_raw_response`, `client.transcripts.get(...)` returns the same union without the status and headers. A quote is free and changes nothing. @@ -69,9 +69,9 @@ 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. +`client.transcripts.list_requests()` lists past Premium transcriptions with their state. -A read without `quality="premium"` returns captions and buys nothing. +A read without `quality="premium"` returns captions and starts no transcription. ## Errors @@ -166,7 +166,7 @@ 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. +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. They need no live API key and use no credits. ## License diff --git a/VERSION b/VERSION index 1d0ba9e..267577d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.4.0 +0.4.1 diff --git a/llms.txt b/llms.txt index 3127c0a..24279b7 100644 --- a/llms.txt +++ b/llms.txt @@ -33,7 +33,7 @@ for mention in client.mentions.list(entity_id=ramp.id, after="2026-09-01", befor ## Premium transcripts -`client.transcripts.get(video_id, quality="premium")` is one read. It answers `state == "ready"` (200) with the transcript, or `state == "pending"` (202) with `job` and a `Retry-After` header. Read again after `Retry-After` or `job.next_poll_seconds`. Repeated reads join the same purchase and never buy twice. The read spends included credits first, then the account's on-demand budget. `client.transcripts.quote(video_id)` is free and shows the price. Use `client.transcripts.with_raw_response.get(...)` for the status code and headers. +`client.transcripts.get(video_id, quality="premium")` is one read. It answers `state == "ready"` (200) with the transcript, or `state == "pending"` (202) with `job` and a `Retry-After` header. Read again after `Retry-After` or `job.next_poll_seconds`. Repeated reads join the same job and never use credits twice. A read of a video not transcribed yet uses credits from the plan, then the account's on-demand budget. `client.transcripts.quote(video_id)` is free and shows how many credits the read uses. Use `client.transcripts.with_raw_response.get(...)` for the status code and headers. ## Errors diff --git a/src/arcmira/_package.py b/src/arcmira/_package.py index 7e829cd..e6ad8e4 100644 --- a/src/arcmira/_package.py +++ b/src/arcmira/_package.py @@ -1,5 +1,5 @@ # Written by scripts/install-generated.py from VERSION. -__version__ = '0.4.0' +__version__ = '0.4.1' homepage = "https://arcmira.com" docs = "https://arcmira.com/docs" api_base = "https://api.arcmira.com/v1" diff --git a/src/arcmira/core/client_wrapper.py b/src/arcmira/core/client_wrapper.py index 61542a6..9643212 100644 --- a/src/arcmira/core/client_wrapper.py +++ b/src/arcmira/core/client_wrapper.py @@ -33,7 +33,7 @@ def get_headers(self) -> typing.Dict[str, str]: import platform headers: typing.Dict[str, str] = { - "User-Agent": "arcmira/0.4.0", + "User-Agent": "arcmira/0.4.1", "X-Fern-Language": "Python", "X-Fern-Runtime": f"python/{platform.python_version()}", "X-Fern-Platform": f"{platform.system().lower()}/{platform.release()}", From b2ce9d5d8dfc4a0b8ddf5bd8fb2aabaf5da2ef37 Mon Sep 17 00:00:00 2001 From: Zeal Caiden Date: Sun, 4 Oct 2026 12:51:43 -0700 Subject: [PATCH 2/2] Regenerate from the live v1 document (PR 716): paid reads use credits from your plan --- fern/openapi.json | 358 ++++++++++-------- reference.md | 16 +- .../update_settings_me_request_transcripts.py | 2 +- src/arcmira/monitors/client.py | 8 +- src/arcmira/monitors/raw_client.py | 8 +- src/arcmira/transcripts/client.py | 28 +- src/arcmira/transcripts/raw_client.py | 28 +- ...hannel_sponsors_response_access_details.py | 10 + ...entity_momentum_response_access_details.py | 10 + src/arcmira/types/error_error_details.py | 10 + src/arcmira/types/me_response.py | 2 +- src/arcmira/types/monitor.py | 2 +- src/arcmira/types/refused_quote.py | 4 +- src/arcmira/types/refused_quote_charge.py | 2 +- src/arcmira/types/transcript_failed.py | 4 +- .../types/transcript_failed_last_attempt.py | 4 +- src/arcmira/types/transcript_job.py | 8 +- src/arcmira/types/transcript_job_charge.py | 8 +- .../types/transcript_purchase_quote.py | 2 +- .../transcript_purchase_quote_upgrade.py | 2 +- src/arcmira/types/transcript_quote.py | 2 +- ...ipt_request_list_response_requests_item.py | 4 + src/arcmira/types/transcript_response.py | 4 +- .../transcript_response_access_details.py | 10 + .../types/transcript_response_range.py | 2 +- ...anscript_search_response_access_details.py | 10 + 26 files changed, 330 insertions(+), 218 deletions(-) diff --git a/fern/openapi.json b/fern/openapi.json index d6fded7..1984364 100644 --- a/fern/openapi.json +++ b/fern/openapi.json @@ -2,6 +2,7 @@ "openapi": "3.1.0", "info": { "title": "Arcmira API", + "description": "Search YouTube transcripts for timestamped passages. Find mentions of people, organizations, products and topics; research channel sponsors and recommendations; retrieve creator captions or Premium transcripts with speaker identification; and monitor entities for new mentions. Official API guides: https://arcmira.com/docs. An explicit Premium read uses credits from the account's plan, then its on-demand budget.", "version": "1.0.0", "contact": { "name": "Arcmira", @@ -13,6 +14,10 @@ "url": "https://api.arcmira.com" } ], + "externalDocs": { + "description": "Official Arcmira API documentation", + "url": "https://arcmira.com/docs" + }, "components": { "headers": { "X-Request-Id": { @@ -328,6 +333,14 @@ "existing_id": { "type": "string", "description": "On tracker_already_exists, the existing tracker id. Reuse it instead of creating another tracker." + }, + "limit": { + "type": "integer", + "description": "On tracker_limit, the trackers the plan holds." + }, + "count": { + "type": "integer", + "description": "On tracker_limit, the trackers the account holds now." } }, "description": "Machine data the refusal carries for you to act on. Present only on the codes that name a field here." @@ -587,7 +600,7 @@ { "code": "spend_limit_exceeded", "type": "quota_exceeded", - "description": "The purchase would take on-demand spending past the account or seat spend limit this period. Nothing was charged. Raise the limit or wait for the next period, then send a new intent." + "description": "The request would take on-demand usage past the account or seat spend limit this period. Nothing was charged. Raise the limit or wait for the next period, then read again or send a new intent." }, { "code": "team_not_found", @@ -599,6 +612,11 @@ "type": "conflict_error", "description": "The account already tracks this entity. error.details.existing_id identifies the existing tracker." }, + { + "code": "tracker_limit", + "type": "permission_error", + "description": "The plan's tracker limit is reached. error.details carries limit and count." + }, { "code": "tracker_not_found", "type": "not_found", @@ -945,11 +963,11 @@ "amount", "from" ], - "description": "What the purchase would charge at the current balance. Absent when no current price could be read." + "description": "What the request would charge at the current balance. Absent when no current price could be read." }, "max_on_demand_cents": { "type": "integer", - "description": "The on-demand money, in whole cents, this purchase needs beyond included credits at the current balance." + "description": "The on-demand usage, in whole cents, this request needs beyond the plan's credits at the current balance." } } } @@ -965,7 +983,7 @@ }, "rows": { "type": "integer", - "description": "Total unlock cost in rows: 75 rows per 15-minute block." + "description": "Rows the whole video uses, 75 rows per 15-minute block." } }, "required": [ @@ -973,6 +991,123 @@ "rows" ] }, + "TranscriptionJob": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Transcription request id (UUID)." + }, + "video_id": { + "type": "string", + "description": "YouTube video id (11 characters)." + }, + "state": { + "type": "string", + "enum": [ + "pending", + "ready", + "failed", + "refunded" + ], + "description": "Coarse outcome: pending until the Premium transcript is servable (ready), the job failed, or it was refunded." + }, + "status": { + "type": "string", + "enum": [ + "queued", + "downloading", + "transcribing", + "analyzing", + "complete", + "failed", + "refund_pending", + "refunded" + ], + "description": "Request status. Values: queued (accepted; audio download not started), downloading (fetching the video audio), transcribing (premium speech-to-text is running), analyzing (entity/commercial analysis is running), complete (premium transcript is servable via GET /v1/transcripts/{video_id}), failed (rejected intent, or a legacy request needing accounting review), refund_pending (refund transaction must still complete), refunded (terminal failure; the charged rows were returned and the unlock this request granted was revoked)." + }, + "stage": { + "type": [ + "string", + "null" + ], + "enum": [ + "queued", + "transcribing", + "analyzing", + null + ], + "description": "User-facing stage: downloading folds into transcribing. Values: queued (waiting to start), transcribing (downloading or transcribing), analyzing (analysis running). Null for terminal statuses and refund_pending." + }, + "charge": { + "type": "object", + "properties": { + "unit": { + "type": "string", + "enum": [ + "credits" + ] + }, + "amount": { + "type": "number", + "description": "Credits this job charged. 0 when a prior unlock made it free." + }, + "from": { + "type": "string", + "enum": [ + "included", + "on_demand", + "mixed" + ], + "description": "Where the credits came from. included is the plan's credits, on_demand is the on-demand budget, mixed is both. Present once the job is funded." + } + }, + "required": [ + "unit", + "amount" + ], + "description": "What the job charged. Absent only on legacy requests." + }, + "eta_seconds": { + "type": "integer", + "description": "Estimated seconds until completion, re-derived from live pipeline telemetry on every poll. Only present while the request is in flight; absent on refund_pending, which has no completion ETA." + }, + "next_poll_seconds": { + "type": "integer", + "description": "Seconds to sleep before the next poll (also sent as the Retry-After header). Only present while the request is in flight." + }, + "error": { + "type": "string", + "description": "Failure reason. Only present when state is failed or refunded, or status is refund_pending." + }, + "refunded": { + "type": "boolean", + "description": "True when the charge was returned. Only present when state is failed or refunded, or status is refund_pending (false until the refund lands)." + }, + "created_at": { + "type": "string", + "description": "When the request was submitted." + }, + "completed_at": { + "type": "string", + "description": "When the request reached a terminal status. Absent while in flight." + }, + "status_url": { + "type": "string", + "description": "Absolute URL to read again for this job: GET /v1/transcripts/{video_id}?quality=premium, which answers 202 while it transcribes, 200 ready once it is done, and 200 failed if it failed." + } + }, + "required": [ + "id", + "video_id", + "state", + "status", + "stage", + "created_at", + "status_url" + ], + "description": "A Premium transcript job with its processing state, charge and URL for reading the transcript again." + }, "HealthResponse": { "type": "object", "properties": { @@ -1136,7 +1271,7 @@ }, "tier": { "type": "string", - "description": "Plan tier, e.g. free, hobby, pro, enterprise." + "description": "Plan tier, e.g. free, pro, pro_plus, ultra, enterprise." }, "scopes": { "type": "array", @@ -3039,6 +3174,14 @@ "existing_id": { "type": "string", "description": "On tracker_already_exists, the existing tracker id. Reuse it instead of creating another tracker." + }, + "limit": { + "type": "integer", + "description": "On tracker_limit, the trackers the plan holds." + }, + "count": { + "type": "integer", + "description": "On tracker_limit, the trackers the account holds now." } }, "description": "Machine data the refusal carries for you to act on. Present only on the codes that name a field here." @@ -3382,6 +3525,14 @@ "existing_id": { "type": "string", "description": "On tracker_already_exists, the existing tracker id. Reuse it instead of creating another tracker." + }, + "limit": { + "type": "integer", + "description": "On tracker_limit, the trackers the plan holds." + }, + "count": { + "type": "integer", + "description": "On tracker_limit, the trackers the account holds now." } }, "description": "Machine data the refusal carries for you to act on. Present only on the codes that name a field here." @@ -3888,6 +4039,14 @@ "existing_id": { "type": "string", "description": "On tracker_already_exists, the existing tracker id. Reuse it instead of creating another tracker." + }, + "limit": { + "type": "integer", + "description": "On tracker_limit, the trackers the plan holds." + }, + "count": { + "type": "integer", + "description": "On tracker_limit, the trackers the account holds now." } }, "description": "Machine data the refusal carries for you to act on. Present only on the codes that name a field here." @@ -4748,7 +4907,7 @@ "notify_frequency": { "type": "string", "default": "realtime", - "description": "Delivery cadence. Values: realtime (deliver immediately), hourly (hourly digest), daily (daily digest). Free tier is limited to daily." + "description": "Delivery cadence. Values: realtime (deliver immediately), hourly (hourly digest), daily (daily digest)." }, "digest_day": { "type": "string", @@ -5743,11 +5902,11 @@ "start", "end" ], - "description": "Echoed when you sent start and end. Lines overlapping the window are returned. On captions only the window is billed; Premium retrieval is free." + "description": "Echoed when you sent start and end. Lines overlapping the window are returned. On captions only the window is billed. An explicit Premium read is charged for the whole video, from the account's plan credits and then its on-demand budget; the window only trims the returned content." }, "rows_billed": { "type": "integer", - "description": "Rows this call charged. 0 on a repeat of the same video, quality, language, and range inside the 7 day dedupe window, and always 0 on Premium retrieval." + "description": "Caption retrieval rows charged by this call. 0 on a repeat of the same video, quality, language, and range inside the 7 day dedupe window. Premium responses report 0 here even when the read was charged for the whole video; this field does not report Premium charges." }, "as_of": { "type": [ @@ -5757,7 +5916,14 @@ "description": "When the transcript was produced." }, "premium_job": { - "$ref": "#/components/schemas/TranscriptionJob" + "allOf": [ + { + "$ref": "#/components/schemas/TranscriptionJob" + }, + { + "description": "Your open Premium transcript job for this video, when captions were served while it transcribes." + } + ] }, "access": { "type": "object", @@ -5872,6 +6038,14 @@ "existing_id": { "type": "string", "description": "On tracker_already_exists, the existing tracker id. Reuse it instead of creating another tracker." + }, + "limit": { + "type": "integer", + "description": "On tracker_limit, the trackers the plan holds." + }, + "count": { + "type": "integer", + "description": "On tracker_limit, the trackers the account holds now." } }, "description": "Machine data the refusal carries for you to act on. Present only on the codes that name a field here." @@ -6077,123 +6251,6 @@ "generated" ] }, - "TranscriptionJob": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "Transcription request id (UUID)." - }, - "video_id": { - "type": "string", - "description": "YouTube video id (11 characters)." - }, - "state": { - "type": "string", - "enum": [ - "pending", - "ready", - "failed", - "refunded" - ], - "description": "Coarse outcome: pending until the Premium transcript is servable (ready), the purchase failed, or it was refunded." - }, - "status": { - "type": "string", - "enum": [ - "queued", - "downloading", - "transcribing", - "analyzing", - "complete", - "failed", - "refund_pending", - "refunded" - ], - "description": "Request status. Values: queued (accepted; audio download not started), downloading (fetching the video audio), transcribing (premium speech-to-text is running), analyzing (entity/commercial analysis is running), complete (premium transcript is servable via GET /v1/transcripts/{video_id}), failed (rejected intent or legacy purchase requiring accounting review), refund_pending (refund transaction must still complete), refunded (terminal failure; the charged rows were returned and the unlock this submission bought was revoked)." - }, - "stage": { - "type": [ - "string", - "null" - ], - "enum": [ - "queued", - "transcribing", - "analyzing", - null - ], - "description": "User-facing stage: downloading folds into transcribing. Values: queued (waiting to start), transcribing (downloading or transcribing), analyzing (analysis running). Null for terminal statuses and refund_pending." - }, - "charge": { - "type": "object", - "properties": { - "unit": { - "type": "string", - "enum": [ - "credits" - ] - }, - "amount": { - "type": "number", - "description": "Credits this purchase charged. 0 when a prior unlock made it free." - }, - "from": { - "type": "string", - "enum": [ - "included", - "on_demand", - "mixed" - ], - "description": "Where the credits came from: the included allowance, on-demand usage, or both. Present once the purchase is funded." - } - }, - "required": [ - "unit", - "amount" - ], - "description": "What the purchase charged. Present on durable purchases; absent only on legacy requests." - }, - "eta_seconds": { - "type": "integer", - "description": "Estimated seconds until completion, re-derived from live pipeline telemetry on every poll. Only present while the request is in flight; absent on refund_pending, which has no completion ETA." - }, - "next_poll_seconds": { - "type": "integer", - "description": "Seconds to sleep before the next poll (also sent as the Retry-After header). Only present while the request is in flight." - }, - "error": { - "type": "string", - "description": "Failure reason. Only present when state is failed or refunded, or status is refund_pending." - }, - "refunded": { - "type": "boolean", - "description": "True when the charge was returned. Only present when state is failed or refunded, or status is refund_pending (false until the refund lands)." - }, - "created_at": { - "type": "string", - "description": "When the request was submitted." - }, - "completed_at": { - "type": "string", - "description": "When the request reached a terminal status. Absent while in flight." - }, - "status_url": { - "type": "string", - "description": "Absolute URL to read again for this job: GET /v1/transcripts/{video_id}?quality=premium, which answers 202 while it transcribes, 200 ready once it is done, and 200 failed if it failed." - } - }, - "required": [ - "id", - "video_id", - "state", - "status", - "stage", - "created_at", - "status_url" - ], - "description": "Your open Premium purchase for this video, when captions were served while it transcribes." - }, "TranscriptFailed": { "type": "object", "properties": { @@ -6218,7 +6275,7 @@ "$ref": "#/components/schemas/TranscriptionJob" }, { - "description": "The last Premium purchase for this video. Its state is failed or refunded, or its status is refund_pending while the refund settles." + "description": "The last Premium transcript job for this video. Its state is failed or refunded, or its status is refund_pending while the refund settles." } ] }, @@ -6232,7 +6289,7 @@ "refund_pending", "refunded" ], - "description": "How the last purchase ended: failed, refunded (the charge was returned), or refund_pending (the refund is still settling)." + "description": "How the last job ended: failed, refunded (the charge was returned), or refund_pending (the refund is still settling)." }, "error": { "type": "string", @@ -6243,11 +6300,11 @@ "status", "error" ], - "description": "The failed purchase in brief: job.status and job.error." + "description": "The failed job in brief, as job.status and job.error." }, "note": { "type": "string", - "description": "What to do next: read again with retry=true to buy the video again, or wait while the refund settles." + "description": "The next step. Read again with retry=true to start a new Premium transcript, or wait while the refund settles." } }, "required": [ @@ -6283,7 +6340,7 @@ "$ref": "#/components/schemas/TranscriptionJob" }, { - "description": "The Premium purchase this read started or joined. Read this transcript again after Retry-After (job.status_url is that read); later reads join the same purchase." + "description": "The Premium transcript job this read started or joined. Read this transcript again after Retry-After (job.status_url is that read); later reads join the same job." } ] } @@ -6330,7 +6387,7 @@ "label", "href" ], - "description": "Present when eligible is false: the plan checkout that can buy this transcript, as a button label and an absolute link." + "description": "Present when eligible is false. Names the plan that includes Premium transcripts, as a button label and an absolute link to its checkout." }, "quote": { "$ref": "#/components/schemas/TranscriptQuote" @@ -6416,7 +6473,8 @@ "title" ] } - ] + ], + "description": "A Premium transcript job with its processing state, charge and URL for reading the transcript again." }, "description": "Your requests in descending creation time and id order, up to the requested limit." }, @@ -6646,7 +6704,7 @@ "captions", "premium" ], - "description": "Default transcript quality for this account: captions or premium. premium reads require an existing purchase. Owned transcripts remain readable after a plan downgrade; new purchases require an eligible plan." + "description": "Default transcript quality for this account: captions or premium. As a default, premium reads only transcripts the account already owns. Owned transcripts remain readable after a plan downgrade; starting new ones requires an eligible plan." }, "language": { "type": "string", @@ -8799,7 +8857,7 @@ "hourly", "daily" ], - "description": "Delivery cadence. Default realtime. Values: realtime (as analysis completes), hourly (hourly digest), daily (daily digest). Free-tier email delivery is coerced to daily regardless of the value sent." + "description": "Delivery cadence. Default realtime. Values: realtime (as analysis completes), hourly (hourly digest), daily (daily digest)." }, "digest_day": { "type": "string", @@ -9006,7 +9064,7 @@ "hourly", "daily" ], - "description": "Delivery cadence. Default realtime. Values: realtime (as analysis completes), hourly (hourly digest), daily (daily digest). Free-tier email delivery is coerced to daily regardless of the value sent." + "description": "Delivery cadence. Default realtime. Values: realtime (as analysis completes), hourly (hourly digest), daily (daily digest)." }, "digest_day": { "type": "string", @@ -10466,7 +10524,7 @@ ], "operationId": "get_transcript", "summary": "Get a video transcript", - "description": "Caption retrieval costs one row per started 15 minutes. quality=premium is one read: an owned transcript answers 200 ready at zero rows; otherwise this call buys the whole video within the account's plan and on-demand budget, included credits first and then on-demand money up to the account limit, and answers 202 pending with the job and Retry-After until the transcript is ready. Read again after Retry-After; repeated reads join the same purchase and never buy twice. When the last purchase for the video failed, the read answers 200 state failed with the job and last_attempt and buys nothing; retry=true buys it again. When the plan or the budget blocks, 403 paid_plan_required (with unlock) or 402 quota_exceeded or spend_limit_exceeded carries the price in quote and nothing is charged. A default-premium account with nothing owned reads captions with a note. start/end only trim the returned content; language selects caption tracks, timestamps=false returns paragraphs. Premium lines carry speaker and index, and the body carries speakers and revision.", + "description": "Caption reads use one row per started 15 minutes. quality=premium is one read. An owned transcript answers 200 ready at zero rows. Otherwise this call starts a Premium transcript of the whole video, using credits from the account's plan first and then the account's on-demand budget up to its limit, and answers 202 pending with the job and Retry-After until the transcript is ready. Read again after Retry-After; repeated reads join the same job and never charge twice. When the last Premium transcript for the video failed, the read answers 200 state failed with the job and last_attempt and charges nothing; retry=true starts a new one. When the plan or the budget blocks, 403 paid_plan_required (with unlock) or 402 quota_exceeded or spend_limit_exceeded carries the price in quote and nothing is charged. A default-premium account with nothing owned reads captions with a note. start/end only trim the returned content; language selects caption tracks, timestamps=false returns paragraphs. Premium lines carry speaker and index, and the body carries speakers and revision.", "security": [ { "bearerAuth": [] @@ -10490,10 +10548,10 @@ "captions", "premium" ], - "description": "captions reads creator or automatic captions at 1 row per started 15 minutes. premium is one read: an owned transcript returns 200 state ready at zero rows; otherwise the read buys the whole video within the account's plan and on-demand budget (included credits first, then on-demand money up to the account limit) and returns 202 state pending with the job until it is ready. When the last purchase for the video failed it answers 200 state failed and buys again only with retry=true. 402 quota_exceeded or spend_limit_exceeded and 403 paid_plan_required carry the price in quote. It never substitutes captions. Default captions unless changed in account settings." + "description": "captions reads creator or automatic captions at 1 row per started 15 minutes. premium is one read. An owned transcript returns 200 state ready at zero rows. Otherwise the read starts a Premium transcript of the whole video, using credits from the account's plan first and then the account's on-demand budget up to its limit, and returns 202 state pending with the job until it is ready. When the last Premium transcript for the video failed it answers 200 state failed and starts a new one only with retry=true. 402 quota_exceeded or spend_limit_exceeded and 403 paid_plan_required carry the price in quote. It never substitutes captions. Default captions unless changed in account settings." }, "required": false, - "description": "captions reads creator or automatic captions at 1 row per started 15 minutes. premium is one read: an owned transcript returns 200 state ready at zero rows; otherwise the read buys the whole video within the account's plan and on-demand budget (included credits first, then on-demand money up to the account limit) and returns 202 state pending with the job until it is ready. When the last purchase for the video failed it answers 200 state failed and buys again only with retry=true. 402 quota_exceeded or spend_limit_exceeded and 403 paid_plan_required carry the price in quote. It never substitutes captions. Default captions unless changed in account settings.", + "description": "captions reads creator or automatic captions at 1 row per started 15 minutes. premium is one read. An owned transcript returns 200 state ready at zero rows. Otherwise the read starts a Premium transcript of the whole video, using credits from the account's plan first and then the account's on-demand budget up to its limit, and returns 202 state pending with the job until it is ready. When the last Premium transcript for the video failed it answers 200 state failed and starts a new one only with retry=true. 402 quota_exceeded or spend_limit_exceeded and 403 paid_plan_required carry the price in quote. It never substitutes captions. Default captions unless changed in account settings.", "name": "quality", "in": "query" }, @@ -10524,10 +10582,10 @@ "null" ], "minimum": 0, - "description": "Window start in seconds from the beginning of the video. Send start and end together. On captions the window bills only its own started 15-minute blocks; on Premium it trims an already purchased transcript; this GET does not charge." + "description": "Window start in seconds from the beginning of the video. Send start and end together. On captions the window bills only its own started 15-minute blocks; on Premium it trims the returned content. An explicit Premium read is charged for the whole video from the account's plan credits and then its on-demand budget; a window does not reduce that charge." }, "required": false, - "description": "Window start in seconds from the beginning of the video. Send start and end together. On captions the window bills only its own started 15-minute blocks; on Premium it trims an already purchased transcript; this GET does not charge.", + "description": "Window start in seconds from the beginning of the video. Send start and end together. On captions the window bills only its own started 15-minute blocks; on Premium it trims the returned content. An explicit Premium read is charged for the whole video from the account's plan credits and then its on-demand budget; a window does not reduce that charge.", "name": "start", "in": "query" }, @@ -10548,10 +10606,10 @@ { "schema": { "type": "boolean", - "description": "Premium only; captions with retry=true returns invalid_query. When the last Premium purchase for this video failed, a read answers 200 state failed with the job and last_attempt and buys nothing; retry=true buys it again under the same quote, budget and one-purchase rules as the first read. While that refund is still settling (job.status refund_pending) even retry=true answers state failed. Without a failed purchase it changes nothing." + "description": "Premium only; captions with retry=true returns invalid_query. When the last Premium transcript for this video failed, a read answers 200 state failed with the job and last_attempt and charges nothing; retry=true starts a new one under the same quote, budget and one-job-per-video rules as the first read. While that refund is still settling (job.status refund_pending) even retry=true answers state failed. Without a failed job it changes nothing." }, "required": false, - "description": "Premium only; captions with retry=true returns invalid_query. When the last Premium purchase for this video failed, a read answers 200 state failed with the job and last_attempt and buys nothing; retry=true buys it again under the same quote, budget and one-purchase rules as the first read. While that refund is still settling (job.status refund_pending) even retry=true answers state failed. Without a failed purchase it changes nothing.", + "description": "Premium only; captions with retry=true returns invalid_query. When the last Premium transcript for this video failed, a read answers 200 state failed with the job and last_attempt and charges nothing; retry=true starts a new one under the same quote, budget and one-job-per-video rules as the first read. While that refund is still settling (job.status refund_pending) even retry=true answers state failed. Without a failed job it changes nothing.", "name": "retry", "in": "query" }, @@ -10581,7 +10639,7 @@ ], "responses": { "200": { - "description": "state ready: the transcript (video, quality, source, language, languages, lines or paragraphs, speakers and revision on Premium, rows_billed, as_of, note). state failed (Premium only): the last purchase for this video failed; job and last_attempt say why, nothing was bought, and retry=true buys again.", + "description": "state ready: the transcript (video, quality, source, language, languages, lines or paragraphs, speakers and revision on Premium, rows_billed, as_of, note). state failed (Premium only): the last Premium transcript for this video failed; job and last_attempt say why, nothing was charged, and retry=true starts a new one.", "headers": { "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" @@ -10622,7 +10680,7 @@ } }, "202": { - "description": "state pending: the Premium purchase this read started or joined is in flight; job carries its status and poll interval. No transcript content yet.", + "description": "state pending: the Premium transcript this read started or joined is in flight; job carries its status and poll interval. No transcript content yet.", "headers": { "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" @@ -10655,7 +10713,7 @@ "$ref": "#/components/responses/AuthenticationError" }, "402": { - "description": "quota_exceeded or spend_limit_exceeded. The plan allows Premium but the included credits and the on-demand budget do not cover this video; quote carries the refused price and nothing was charged.", + "description": "quota_exceeded or spend_limit_exceeded. The plan includes Premium but the credits left on the plan and the on-demand budget do not cover this video; quote carries the refused price and nothing was charged.", "headers": { "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" @@ -10673,7 +10731,7 @@ } }, "403": { - "description": "paid_plan_required. error.unlock names the plan that buys Premium; quote carries the price.", + "description": "paid_plan_required. error.unlock names the plan that includes Premium; quote carries the price.", "headers": { "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" @@ -10729,8 +10787,8 @@ "Transcripts" ], "operationId": "quote_transcription", - "summary": "Quote a whole-video Premium purchase", - "description": "Optional free quote: the price a Premium read of this video would charge right now, as rows and credits, where the credits would come from, and max_on_demand_cents, the on-demand money the read would need beyond included credits within the account limit. It does not reserve funds or start generation. A video with no known duration, or one past the 12 hour cap, answers 400 invalid_query with param video_id.", + "summary": "Quote a whole-video Premium transcript", + "description": "Optional free quote: what a Premium read of this video would use right now, as rows and credits, where the credits would come from, and max_on_demand_cents, the on-demand budget the read would need beyond the plan's credits within the account limit. It does not reserve credits or budget and does not start a transcript. A video with no known duration, or one past the 12 hour cap, answers 400 invalid_query with param video_id.", "security": [ { "bearerAuth": [] @@ -10804,7 +10862,7 @@ ], "operationId": "list_transcriptions", "summary": "List your transcription requests", - "description": "Your transcription requests in descending creation time and id order. limit defaults to 20 and accepts 1–100. Follow next_cursor with the same video_id, limit and credential; has_more is false and next_cursor is null on the last page. A traversal excludes requests inserted after its first page. Each entry has the same shape as the status poll plus a `title` field (the video title, null when unknown). The scheduled reconciler advances requests; reading this list never dispatches work or changes billing. In-flight entries carry `eta_seconds` and `next_poll_seconds`.", + "description": "Your transcription requests in descending creation time and id order. limit defaults to 20 and accepts 1–100. Follow next_cursor with the same video_id, limit and credential; has_more is false and next_cursor is null on the last page. A traversal excludes requests inserted after its first page. Each entry is a Premium transcript job with its processing and billing state, a `status_url` for the Premium transcript GET, and a `title` field (the video title, null when unknown). The scheduled reconciler advances requests; reading this list never dispatches work or changes billing. In-flight entries carry `eta_seconds` and `next_poll_seconds`.", "security": [ { "bearerAuth": [] diff --git a/reference.md b/reference.md index 2f8c711..bbbf5ce 100644 --- a/reference.md +++ b/reference.md @@ -1244,7 +1244,7 @@ client.transcripts.search(
-Caption retrieval costs one row per started 15 minutes. quality=premium is one read: an owned transcript answers 200 ready at zero rows; otherwise this call buys the whole video within the account's plan and on-demand budget, included credits first and then on-demand money up to the account limit, and answers 202 pending with the job and Retry-After until the transcript is ready. Read again after Retry-After; repeated reads join the same purchase and never buy twice. When the last purchase for the video failed, the read answers 200 state failed with the job and last_attempt and buys nothing; retry=true buys it again. When the plan or the budget blocks, 403 paid_plan_required (with unlock) or 402 quota_exceeded or spend_limit_exceeded carries the price in quote and nothing is charged. A default-premium account with nothing owned reads captions with a note. start/end only trim the returned content; language selects caption tracks, timestamps=false returns paragraphs. Premium lines carry speaker and index, and the body carries speakers and revision. +Caption reads use one row per started 15 minutes. quality=premium is one read. An owned transcript answers 200 ready at zero rows. Otherwise this call starts a Premium transcript of the whole video, using credits from the account's plan first and then the account's on-demand budget up to its limit, and answers 202 pending with the job and Retry-After until the transcript is ready. Read again after Retry-After; repeated reads join the same job and never charge twice. When the last Premium transcript for the video failed, the read answers 200 state failed with the job and last_attempt and charges nothing; retry=true starts a new one. When the plan or the budget blocks, 403 paid_plan_required (with unlock) or 402 quota_exceeded or spend_limit_exceeded carries the price in quote and nothing is charged. A default-premium account with nothing owned reads captions with a note. start/end only trim the returned content; language selects caption tracks, timestamps=false returns paragraphs. Premium lines carry speaker and index, and the body carries speakers and revision.
@@ -1293,7 +1293,7 @@ client.transcripts.get(
-**quality:** `typing.Optional[GetTranscriptsRequestQuality]` — captions reads creator or automatic captions at 1 row per started 15 minutes. premium is one read: an owned transcript returns 200 state ready at zero rows; otherwise the read buys the whole video within the account's plan and on-demand budget (included credits first, then on-demand money up to the account limit) and returns 202 state pending with the job until it is ready. When the last purchase for the video failed it answers 200 state failed and buys again only with retry=true. 402 quota_exceeded or spend_limit_exceeded and 403 paid_plan_required carry the price in quote. It never substitutes captions. Default captions unless changed in account settings. +**quality:** `typing.Optional[GetTranscriptsRequestQuality]` — captions reads creator or automatic captions at 1 row per started 15 minutes. premium is one read. An owned transcript returns 200 state ready at zero rows. Otherwise the read starts a Premium transcript of the whole video, using credits from the account's plan first and then the account's on-demand budget up to its limit, and returns 202 state pending with the job until it is ready. When the last Premium transcript for the video failed it answers 200 state failed and starts a new one only with retry=true. 402 quota_exceeded or spend_limit_exceeded and 403 paid_plan_required carry the price in quote. It never substitutes captions. Default captions unless changed in account settings.
@@ -1317,7 +1317,7 @@ client.transcripts.get(
-**start:** `typing.Optional[float]` — Window start in seconds from the beginning of the video. Send start and end together. On captions the window bills only its own started 15-minute blocks; on Premium it trims an already purchased transcript; this GET does not charge. +**start:** `typing.Optional[float]` — Window start in seconds from the beginning of the video. Send start and end together. On captions the window bills only its own started 15-minute blocks; on Premium it trims the returned content. An explicit Premium read is charged for the whole video from the account's plan credits and then its on-demand budget; a window does not reduce that charge.
@@ -1333,7 +1333,7 @@ client.transcripts.get(
-**retry:** `typing.Optional[bool]` — Premium only; captions with retry=true returns invalid_query. When the last Premium purchase for this video failed, a read answers 200 state failed with the job and last_attempt and buys nothing; retry=true buys it again under the same quote, budget and one-purchase rules as the first read. While that refund is still settling (job.status refund_pending) even retry=true answers state failed. Without a failed purchase it changes nothing. +**retry:** `typing.Optional[bool]` — Premium only; captions with retry=true returns invalid_query. When the last Premium transcript for this video failed, a read answers 200 state failed with the job and last_attempt and charges nothing; retry=true starts a new one under the same quote, budget and one-job-per-video rules as the first read. While that refund is still settling (job.status refund_pending) even retry=true answers state failed. Without a failed job it changes nothing.
@@ -1373,7 +1373,7 @@ client.transcripts.get(
-Optional free quote: the price a Premium read of this video would charge right now, as rows and credits, where the credits would come from, and max_on_demand_cents, the on-demand money the read would need beyond included credits within the account limit. It does not reserve funds or start generation. A video with no known duration, or one past the 12 hour cap, answers 400 invalid_query with param video_id. +Optional free quote: what a Premium read of this video would use right now, as rows and credits, where the credits would come from, and max_on_demand_cents, the on-demand budget the read would need beyond the plan's credits within the account limit. It does not reserve credits or budget and does not start a transcript. A video with no known duration, or one past the 12 hour cap, answers 400 invalid_query with param video_id.
@@ -1446,7 +1446,7 @@ client.transcripts.quote(
-Your transcription requests in descending creation time and id order. limit defaults to 20 and accepts 1–100. Follow next_cursor with the same video_id, limit and credential; has_more is false and next_cursor is null on the last page. A traversal excludes requests inserted after its first page. Each entry has the same shape as the status poll plus a `title` field (the video title, null when unknown). The scheduled reconciler advances requests; reading this list never dispatches work or changes billing. In-flight entries carry `eta_seconds` and `next_poll_seconds`. +Your transcription requests in descending creation time and id order. limit defaults to 20 and accepts 1–100. Follow next_cursor with the same video_id, limit and credential; has_more is false and next_cursor is null on the last page. A traversal excludes requests inserted after its first page. Each entry is a Premium transcript job with its processing and billing state, a `status_url` for the Premium transcript GET, and a `title` field (the video title, null when unknown). The scheduled reconciler advances requests; reading this list never dispatches work or changes billing. In-flight entries carry `eta_seconds` and `next_poll_seconds`.
@@ -1737,7 +1737,7 @@ client.monitors.create(
-**notify_frequency:** `typing.Optional[CreateMonitorsRequestNotifyFrequency]` — Delivery cadence. Default realtime. Values: realtime (as analysis completes), hourly (hourly digest), daily (daily digest). Free-tier email delivery is coerced to daily regardless of the value sent. +**notify_frequency:** `typing.Optional[CreateMonitorsRequestNotifyFrequency]` — Delivery cadence. Default realtime. Values: realtime (as analysis completes), hourly (hourly digest), daily (daily digest).
@@ -1989,7 +1989,7 @@ client.monitors.update(
-**notify_frequency:** `typing.Optional[UpdateMonitorsRequestNotifyFrequency]` — Delivery cadence. Default realtime. Values: realtime (as analysis completes), hourly (hourly digest), daily (daily digest). Free-tier email delivery is coerced to daily regardless of the value sent. +**notify_frequency:** `typing.Optional[UpdateMonitorsRequestNotifyFrequency]` — Delivery cadence. Default realtime. Values: realtime (as analysis completes), hourly (hourly digest), daily (daily digest).
diff --git a/src/arcmira/me/types/update_settings_me_request_transcripts.py b/src/arcmira/me/types/update_settings_me_request_transcripts.py index 8229ebd..aeb3630 100644 --- a/src/arcmira/me/types/update_settings_me_request_transcripts.py +++ b/src/arcmira/me/types/update_settings_me_request_transcripts.py @@ -14,7 +14,7 @@ class UpdateSettingsMeRequestTranscripts(UniversalBaseModel): quality: typing.Optional[UpdateSettingsMeRequestTranscriptsQuality] = pydantic.Field(default=None) """ - Default transcript quality for this account: captions or premium. premium reads require an existing purchase. Owned transcripts remain readable after a plan downgrade; new purchases require an eligible plan. + Default transcript quality for this account: captions or premium. As a default, premium reads only transcripts the account already owns. Owned transcripts remain readable after a plan downgrade; starting new ones requires an eligible plan. """ language: typing.Optional[str] = pydantic.Field(default=None) diff --git a/src/arcmira/monitors/client.py b/src/arcmira/monitors/client.py index 37a962e..79f3fa6 100644 --- a/src/arcmira/monitors/client.py +++ b/src/arcmira/monitors/client.py @@ -99,7 +99,7 @@ def create( Desired email recipients. External recipients must confirm before delivery. Free includes one additional recipient per monitor; paid plans allow up to 20 total. Default []. notify_frequency : typing.Optional[CreateMonitorsRequestNotifyFrequency] - Delivery cadence. Default realtime. Values: realtime (as analysis completes), hourly (hourly digest), daily (daily digest). Free-tier email delivery is coerced to daily regardless of the value sent. + Delivery cadence. Default realtime. Values: realtime (as analysis completes), hourly (hourly digest), daily (daily digest). digest_day : typing.Optional[str] Digest day of week. Default "monday". Consulted only by weekly digests, which are dashboard-configured today; inert for API-set frequencies. @@ -239,7 +239,7 @@ def update( Desired email recipients. External recipients must confirm before delivery. Free includes one additional recipient per monitor; paid plans allow up to 20 total. Default []. notify_frequency : typing.Optional[UpdateMonitorsRequestNotifyFrequency] - Delivery cadence. Default realtime. Values: realtime (as analysis completes), hourly (hourly digest), daily (daily digest). Free-tier email delivery is coerced to daily regardless of the value sent. + Delivery cadence. Default realtime. Values: realtime (as analysis completes), hourly (hourly digest), daily (daily digest). digest_day : typing.Optional[str] Digest day of week. Default "monday". Consulted only by weekly digests, which are dashboard-configured today; inert for API-set frequencies. @@ -456,7 +456,7 @@ async def create( Desired email recipients. External recipients must confirm before delivery. Free includes one additional recipient per monitor; paid plans allow up to 20 total. Default []. notify_frequency : typing.Optional[CreateMonitorsRequestNotifyFrequency] - Delivery cadence. Default realtime. Values: realtime (as analysis completes), hourly (hourly digest), daily (daily digest). Free-tier email delivery is coerced to daily regardless of the value sent. + Delivery cadence. Default realtime. Values: realtime (as analysis completes), hourly (hourly digest), daily (daily digest). digest_day : typing.Optional[str] Digest day of week. Default "monday". Consulted only by weekly digests, which are dashboard-configured today; inert for API-set frequencies. @@ -612,7 +612,7 @@ async def update( Desired email recipients. External recipients must confirm before delivery. Free includes one additional recipient per monitor; paid plans allow up to 20 total. Default []. notify_frequency : typing.Optional[UpdateMonitorsRequestNotifyFrequency] - Delivery cadence. Default realtime. Values: realtime (as analysis completes), hourly (hourly digest), daily (daily digest). Free-tier email delivery is coerced to daily regardless of the value sent. + Delivery cadence. Default realtime. Values: realtime (as analysis completes), hourly (hourly digest), daily (daily digest). digest_day : typing.Optional[str] Digest day of week. Default "monday". Consulted only by weekly digests, which are dashboard-configured today; inert for API-set frequencies. diff --git a/src/arcmira/monitors/raw_client.py b/src/arcmira/monitors/raw_client.py index e4241d5..47b9e7a 100644 --- a/src/arcmira/monitors/raw_client.py +++ b/src/arcmira/monitors/raw_client.py @@ -170,7 +170,7 @@ def create( Desired email recipients. External recipients must confirm before delivery. Free includes one additional recipient per monitor; paid plans allow up to 20 total. Default []. notify_frequency : typing.Optional[CreateMonitorsRequestNotifyFrequency] - Delivery cadence. Default realtime. Values: realtime (as analysis completes), hourly (hourly digest), daily (daily digest). Free-tier email delivery is coerced to daily regardless of the value sent. + Delivery cadence. Default realtime. Values: realtime (as analysis completes), hourly (hourly digest), daily (daily digest). digest_day : typing.Optional[str] Digest day of week. Default "monday". Consulted only by weekly digests, which are dashboard-configured today; inert for API-set frequencies. @@ -489,7 +489,7 @@ def update( Desired email recipients. External recipients must confirm before delivery. Free includes one additional recipient per monitor; paid plans allow up to 20 total. Default []. notify_frequency : typing.Optional[UpdateMonitorsRequestNotifyFrequency] - Delivery cadence. Default realtime. Values: realtime (as analysis completes), hourly (hourly digest), daily (daily digest). Free-tier email delivery is coerced to daily regardless of the value sent. + Delivery cadence. Default realtime. Values: realtime (as analysis completes), hourly (hourly digest), daily (daily digest). digest_day : typing.Optional[str] Digest day of week. Default "monday". Consulted only by weekly digests, which are dashboard-configured today; inert for API-set frequencies. @@ -915,7 +915,7 @@ async def create( Desired email recipients. External recipients must confirm before delivery. Free includes one additional recipient per monitor; paid plans allow up to 20 total. Default []. notify_frequency : typing.Optional[CreateMonitorsRequestNotifyFrequency] - Delivery cadence. Default realtime. Values: realtime (as analysis completes), hourly (hourly digest), daily (daily digest). Free-tier email delivery is coerced to daily regardless of the value sent. + Delivery cadence. Default realtime. Values: realtime (as analysis completes), hourly (hourly digest), daily (daily digest). digest_day : typing.Optional[str] Digest day of week. Default "monday". Consulted only by weekly digests, which are dashboard-configured today; inert for API-set frequencies. @@ -1234,7 +1234,7 @@ async def update( Desired email recipients. External recipients must confirm before delivery. Free includes one additional recipient per monitor; paid plans allow up to 20 total. Default []. notify_frequency : typing.Optional[UpdateMonitorsRequestNotifyFrequency] - Delivery cadence. Default realtime. Values: realtime (as analysis completes), hourly (hourly digest), daily (daily digest). Free-tier email delivery is coerced to daily regardless of the value sent. + Delivery cadence. Default realtime. Values: realtime (as analysis completes), hourly (hourly digest), daily (daily digest). digest_day : typing.Optional[str] Digest day of week. Default "monday". Consulted only by weekly digests, which are dashboard-configured today; inert for API-set frequencies. diff --git a/src/arcmira/transcripts/client.py b/src/arcmira/transcripts/client.py index c7fdd25..a65cc3d 100644 --- a/src/arcmira/transcripts/client.py +++ b/src/arcmira/transcripts/client.py @@ -133,7 +133,7 @@ def get( request_options: typing.Optional[RequestOptions] = None, ) -> TranscriptResult: """ - Caption retrieval costs one row per started 15 minutes. quality=premium is one read: an owned transcript answers 200 ready at zero rows; otherwise this call buys the whole video within the account's plan and on-demand budget, included credits first and then on-demand money up to the account limit, and answers 202 pending with the job and Retry-After until the transcript is ready. Read again after Retry-After; repeated reads join the same purchase and never buy twice. When the last purchase for the video failed, the read answers 200 state failed with the job and last_attempt and buys nothing; retry=true buys it again. When the plan or the budget blocks, 403 paid_plan_required (with unlock) or 402 quota_exceeded or spend_limit_exceeded carries the price in quote and nothing is charged. A default-premium account with nothing owned reads captions with a note. start/end only trim the returned content; language selects caption tracks, timestamps=false returns paragraphs. Premium lines carry speaker and index, and the body carries speakers and revision. + Caption reads use one row per started 15 minutes. quality=premium is one read. An owned transcript answers 200 ready at zero rows. Otherwise this call starts a Premium transcript of the whole video, using credits from the account's plan first and then the account's on-demand budget up to its limit, and answers 202 pending with the job and Retry-After until the transcript is ready. Read again after Retry-After; repeated reads join the same job and never charge twice. When the last Premium transcript for the video failed, the read answers 200 state failed with the job and last_attempt and charges nothing; retry=true starts a new one. When the plan or the budget blocks, 403 paid_plan_required (with unlock) or 402 quota_exceeded or spend_limit_exceeded carries the price in quote and nothing is charged. A default-premium account with nothing owned reads captions with a note. start/end only trim the returned content; language selects caption tracks, timestamps=false returns paragraphs. Premium lines carry speaker and index, and the body carries speakers and revision. Parameters ---------- @@ -141,7 +141,7 @@ def get( YouTube video id, 11 characters. quality : typing.Optional[GetTranscriptsRequestQuality] - captions reads creator or automatic captions at 1 row per started 15 minutes. premium is one read: an owned transcript returns 200 state ready at zero rows; otherwise the read buys the whole video within the account's plan and on-demand budget (included credits first, then on-demand money up to the account limit) and returns 202 state pending with the job until it is ready. When the last purchase for the video failed it answers 200 state failed and buys again only with retry=true. 402 quota_exceeded or spend_limit_exceeded and 403 paid_plan_required carry the price in quote. It never substitutes captions. Default captions unless changed in account settings. + captions reads creator or automatic captions at 1 row per started 15 minutes. premium is one read. An owned transcript returns 200 state ready at zero rows. Otherwise the read starts a Premium transcript of the whole video, using credits from the account's plan first and then the account's on-demand budget up to its limit, and returns 202 state pending with the job until it is ready. When the last Premium transcript for the video failed it answers 200 state failed and starts a new one only with retry=true. 402 quota_exceeded or spend_limit_exceeded and 403 paid_plan_required carry the price in quote. It never substitutes captions. Default captions unless changed in account settings. language : typing.Optional[str] Comma-separated caption language priority list, at most 5, tried in order (e.g. "de,en"). Use asr for the first automatic track and asr- for a specific one. Default en. languages[] in the response lists every track the video offers. @@ -150,13 +150,13 @@ def get( false returns paragraphs[] of { start, text, speaker? } instead of lines[], for reading rather than citing. Default true. start : typing.Optional[float] - Window start in seconds from the beginning of the video. Send start and end together. On captions the window bills only its own started 15-minute blocks; on Premium it trims an already purchased transcript; this GET does not charge. + Window start in seconds from the beginning of the video. Send start and end together. On captions the window bills only its own started 15-minute blocks; on Premium it trims the returned content. An explicit Premium read is charged for the whole video from the account's plan credits and then its on-demand budget; a window does not reduce that charge. end : typing.Optional[float] Window end in seconds, greater than start and no greater than the video duration. Send start and end together. retry : typing.Optional[bool] - Premium only; captions with retry=true returns invalid_query. When the last Premium purchase for this video failed, a read answers 200 state failed with the job and last_attempt and buys nothing; retry=true buys it again under the same quote, budget and one-purchase rules as the first read. While that refund is still settling (job.status refund_pending) even retry=true answers state failed. Without a failed purchase it changes nothing. + Premium only; captions with retry=true returns invalid_query. When the last Premium transcript for this video failed, a read answers 200 state failed with the job and last_attempt and charges nothing; retry=true starts a new one under the same quote, budget and one-job-per-video rules as the first read. While that refund is still settling (job.status refund_pending) even retry=true answers state failed. Without a failed job it changes nothing. refresh : typing.Optional[bool] Captions only; Premium with refresh=true returns invalid_query. Refetch the caption track from YouTube instead of serving the stored copy. Available only for videos outside our index; a pipeline-owned video refuses it with invalid_query. @@ -167,7 +167,7 @@ def get( Returns ------- TranscriptResult - state ready: the transcript (video, quality, source, language, languages, lines or paragraphs, speakers and revision on Premium, rows_billed, as_of, note). state failed (Premium only): the last purchase for this video failed; job and last_attempt say why, nothing was bought, and retry=true buys again. + state ready: the transcript (video, quality, source, language, languages, lines or paragraphs, speakers and revision on Premium, rows_billed, as_of, note). state failed (Premium only): the last Premium transcript for this video failed; job and last_attempt say why, nothing was charged, and retry=true starts a new one. Examples -------- @@ -197,7 +197,7 @@ def quote( self, video_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> TranscriptPurchaseQuote: """ - Optional free quote: the price a Premium read of this video would charge right now, as rows and credits, where the credits would come from, and max_on_demand_cents, the on-demand money the read would need beyond included credits within the account limit. It does not reserve funds or start generation. A video with no known duration, or one past the 12 hour cap, answers 400 invalid_query with param video_id. + Optional free quote: what a Premium read of this video would use right now, as rows and credits, where the credits would come from, and max_on_demand_cents, the on-demand budget the read would need beyond the plan's credits within the account limit. It does not reserve credits or budget and does not start a transcript. A video with no known duration, or one past the 12 hour cap, answers 400 invalid_query with param video_id. Parameters ---------- @@ -235,7 +235,7 @@ def list_requests( request_options: typing.Optional[RequestOptions] = None, ) -> SyncPager[TranscriptRequestListResponseRequestsItem, TranscriptRequestListResponse]: """ - Your transcription requests in descending creation time and id order. limit defaults to 20 and accepts 1–100. Follow next_cursor with the same video_id, limit and credential; has_more is false and next_cursor is null on the last page. A traversal excludes requests inserted after its first page. Each entry has the same shape as the status poll plus a `title` field (the video title, null when unknown). The scheduled reconciler advances requests; reading this list never dispatches work or changes billing. In-flight entries carry `eta_seconds` and `next_poll_seconds`. + Your transcription requests in descending creation time and id order. limit defaults to 20 and accepts 1–100. Follow next_cursor with the same video_id, limit and credential; has_more is false and next_cursor is null on the last page. A traversal excludes requests inserted after its first page. Each entry is a Premium transcript job with its processing and billing state, a `status_url` for the Premium transcript GET, and a `title` field (the video title, null when unknown). The scheduled reconciler advances requests; reading this list never dispatches work or changes billing. In-flight entries carry `eta_seconds` and `next_poll_seconds`. Parameters ---------- @@ -401,7 +401,7 @@ async def get( request_options: typing.Optional[RequestOptions] = None, ) -> TranscriptResult: """ - Caption retrieval costs one row per started 15 minutes. quality=premium is one read: an owned transcript answers 200 ready at zero rows; otherwise this call buys the whole video within the account's plan and on-demand budget, included credits first and then on-demand money up to the account limit, and answers 202 pending with the job and Retry-After until the transcript is ready. Read again after Retry-After; repeated reads join the same purchase and never buy twice. When the last purchase for the video failed, the read answers 200 state failed with the job and last_attempt and buys nothing; retry=true buys it again. When the plan or the budget blocks, 403 paid_plan_required (with unlock) or 402 quota_exceeded or spend_limit_exceeded carries the price in quote and nothing is charged. A default-premium account with nothing owned reads captions with a note. start/end only trim the returned content; language selects caption tracks, timestamps=false returns paragraphs. Premium lines carry speaker and index, and the body carries speakers and revision. + Caption reads use one row per started 15 minutes. quality=premium is one read. An owned transcript answers 200 ready at zero rows. Otherwise this call starts a Premium transcript of the whole video, using credits from the account's plan first and then the account's on-demand budget up to its limit, and answers 202 pending with the job and Retry-After until the transcript is ready. Read again after Retry-After; repeated reads join the same job and never charge twice. When the last Premium transcript for the video failed, the read answers 200 state failed with the job and last_attempt and charges nothing; retry=true starts a new one. When the plan or the budget blocks, 403 paid_plan_required (with unlock) or 402 quota_exceeded or spend_limit_exceeded carries the price in quote and nothing is charged. A default-premium account with nothing owned reads captions with a note. start/end only trim the returned content; language selects caption tracks, timestamps=false returns paragraphs. Premium lines carry speaker and index, and the body carries speakers and revision. Parameters ---------- @@ -409,7 +409,7 @@ async def get( YouTube video id, 11 characters. quality : typing.Optional[GetTranscriptsRequestQuality] - captions reads creator or automatic captions at 1 row per started 15 minutes. premium is one read: an owned transcript returns 200 state ready at zero rows; otherwise the read buys the whole video within the account's plan and on-demand budget (included credits first, then on-demand money up to the account limit) and returns 202 state pending with the job until it is ready. When the last purchase for the video failed it answers 200 state failed and buys again only with retry=true. 402 quota_exceeded or spend_limit_exceeded and 403 paid_plan_required carry the price in quote. It never substitutes captions. Default captions unless changed in account settings. + captions reads creator or automatic captions at 1 row per started 15 minutes. premium is one read. An owned transcript returns 200 state ready at zero rows. Otherwise the read starts a Premium transcript of the whole video, using credits from the account's plan first and then the account's on-demand budget up to its limit, and returns 202 state pending with the job until it is ready. When the last Premium transcript for the video failed it answers 200 state failed and starts a new one only with retry=true. 402 quota_exceeded or spend_limit_exceeded and 403 paid_plan_required carry the price in quote. It never substitutes captions. Default captions unless changed in account settings. language : typing.Optional[str] Comma-separated caption language priority list, at most 5, tried in order (e.g. "de,en"). Use asr for the first automatic track and asr- for a specific one. Default en. languages[] in the response lists every track the video offers. @@ -418,13 +418,13 @@ async def get( false returns paragraphs[] of { start, text, speaker? } instead of lines[], for reading rather than citing. Default true. start : typing.Optional[float] - Window start in seconds from the beginning of the video. Send start and end together. On captions the window bills only its own started 15-minute blocks; on Premium it trims an already purchased transcript; this GET does not charge. + Window start in seconds from the beginning of the video. Send start and end together. On captions the window bills only its own started 15-minute blocks; on Premium it trims the returned content. An explicit Premium read is charged for the whole video from the account's plan credits and then its on-demand budget; a window does not reduce that charge. end : typing.Optional[float] Window end in seconds, greater than start and no greater than the video duration. Send start and end together. retry : typing.Optional[bool] - Premium only; captions with retry=true returns invalid_query. When the last Premium purchase for this video failed, a read answers 200 state failed with the job and last_attempt and buys nothing; retry=true buys it again under the same quote, budget and one-purchase rules as the first read. While that refund is still settling (job.status refund_pending) even retry=true answers state failed. Without a failed purchase it changes nothing. + Premium only; captions with retry=true returns invalid_query. When the last Premium transcript for this video failed, a read answers 200 state failed with the job and last_attempt and charges nothing; retry=true starts a new one under the same quote, budget and one-job-per-video rules as the first read. While that refund is still settling (job.status refund_pending) even retry=true answers state failed. Without a failed job it changes nothing. refresh : typing.Optional[bool] Captions only; Premium with refresh=true returns invalid_query. Refetch the caption track from YouTube instead of serving the stored copy. Available only for videos outside our index; a pipeline-owned video refuses it with invalid_query. @@ -435,7 +435,7 @@ async def get( Returns ------- TranscriptResult - state ready: the transcript (video, quality, source, language, languages, lines or paragraphs, speakers and revision on Premium, rows_billed, as_of, note). state failed (Premium only): the last purchase for this video failed; job and last_attempt say why, nothing was bought, and retry=true buys again. + state ready: the transcript (video, quality, source, language, languages, lines or paragraphs, speakers and revision on Premium, rows_billed, as_of, note). state failed (Premium only): the last Premium transcript for this video failed; job and last_attempt say why, nothing was charged, and retry=true starts a new one. Examples -------- @@ -473,7 +473,7 @@ async def quote( self, video_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> TranscriptPurchaseQuote: """ - Optional free quote: the price a Premium read of this video would charge right now, as rows and credits, where the credits would come from, and max_on_demand_cents, the on-demand money the read would need beyond included credits within the account limit. It does not reserve funds or start generation. A video with no known duration, or one past the 12 hour cap, answers 400 invalid_query with param video_id. + Optional free quote: what a Premium read of this video would use right now, as rows and credits, where the credits would come from, and max_on_demand_cents, the on-demand budget the read would need beyond the plan's credits within the account limit. It does not reserve credits or budget and does not start a transcript. A video with no known duration, or one past the 12 hour cap, answers 400 invalid_query with param video_id. Parameters ---------- @@ -519,7 +519,7 @@ async def list_requests( request_options: typing.Optional[RequestOptions] = None, ) -> AsyncPager[TranscriptRequestListResponseRequestsItem, TranscriptRequestListResponse]: """ - Your transcription requests in descending creation time and id order. limit defaults to 20 and accepts 1–100. Follow next_cursor with the same video_id, limit and credential; has_more is false and next_cursor is null on the last page. A traversal excludes requests inserted after its first page. Each entry has the same shape as the status poll plus a `title` field (the video title, null when unknown). The scheduled reconciler advances requests; reading this list never dispatches work or changes billing. In-flight entries carry `eta_seconds` and `next_poll_seconds`. + Your transcription requests in descending creation time and id order. limit defaults to 20 and accepts 1–100. Follow next_cursor with the same video_id, limit and credential; has_more is false and next_cursor is null on the last page. A traversal excludes requests inserted after its first page. Each entry is a Premium transcript job with its processing and billing state, a `status_url` for the Premium transcript GET, and a `title` field (the video title, null when unknown). The scheduled reconciler advances requests; reading this list never dispatches work or changes billing. In-flight entries carry `eta_seconds` and `next_poll_seconds`. Parameters ---------- diff --git a/src/arcmira/transcripts/raw_client.py b/src/arcmira/transcripts/raw_client.py index 55c23ea..c582ff4 100644 --- a/src/arcmira/transcripts/raw_client.py +++ b/src/arcmira/transcripts/raw_client.py @@ -235,7 +235,7 @@ def get( request_options: typing.Optional[RequestOptions] = None, ) -> HttpResponse[TranscriptResult]: """ - Caption retrieval costs one row per started 15 minutes. quality=premium is one read: an owned transcript answers 200 ready at zero rows; otherwise this call buys the whole video within the account's plan and on-demand budget, included credits first and then on-demand money up to the account limit, and answers 202 pending with the job and Retry-After until the transcript is ready. Read again after Retry-After; repeated reads join the same purchase and never buy twice. When the last purchase for the video failed, the read answers 200 state failed with the job and last_attempt and buys nothing; retry=true buys it again. When the plan or the budget blocks, 403 paid_plan_required (with unlock) or 402 quota_exceeded or spend_limit_exceeded carries the price in quote and nothing is charged. A default-premium account with nothing owned reads captions with a note. start/end only trim the returned content; language selects caption tracks, timestamps=false returns paragraphs. Premium lines carry speaker and index, and the body carries speakers and revision. + Caption reads use one row per started 15 minutes. quality=premium is one read. An owned transcript answers 200 ready at zero rows. Otherwise this call starts a Premium transcript of the whole video, using credits from the account's plan first and then the account's on-demand budget up to its limit, and answers 202 pending with the job and Retry-After until the transcript is ready. Read again after Retry-After; repeated reads join the same job and never charge twice. When the last Premium transcript for the video failed, the read answers 200 state failed with the job and last_attempt and charges nothing; retry=true starts a new one. When the plan or the budget blocks, 403 paid_plan_required (with unlock) or 402 quota_exceeded or spend_limit_exceeded carries the price in quote and nothing is charged. A default-premium account with nothing owned reads captions with a note. start/end only trim the returned content; language selects caption tracks, timestamps=false returns paragraphs. Premium lines carry speaker and index, and the body carries speakers and revision. Parameters ---------- @@ -243,7 +243,7 @@ def get( YouTube video id, 11 characters. quality : typing.Optional[GetTranscriptsRequestQuality] - captions reads creator or automatic captions at 1 row per started 15 minutes. premium is one read: an owned transcript returns 200 state ready at zero rows; otherwise the read buys the whole video within the account's plan and on-demand budget (included credits first, then on-demand money up to the account limit) and returns 202 state pending with the job until it is ready. When the last purchase for the video failed it answers 200 state failed and buys again only with retry=true. 402 quota_exceeded or spend_limit_exceeded and 403 paid_plan_required carry the price in quote. It never substitutes captions. Default captions unless changed in account settings. + captions reads creator or automatic captions at 1 row per started 15 minutes. premium is one read. An owned transcript returns 200 state ready at zero rows. Otherwise the read starts a Premium transcript of the whole video, using credits from the account's plan first and then the account's on-demand budget up to its limit, and returns 202 state pending with the job until it is ready. When the last Premium transcript for the video failed it answers 200 state failed and starts a new one only with retry=true. 402 quota_exceeded or spend_limit_exceeded and 403 paid_plan_required carry the price in quote. It never substitutes captions. Default captions unless changed in account settings. language : typing.Optional[str] Comma-separated caption language priority list, at most 5, tried in order (e.g. "de,en"). Use asr for the first automatic track and asr- for a specific one. Default en. languages[] in the response lists every track the video offers. @@ -252,13 +252,13 @@ def get( false returns paragraphs[] of { start, text, speaker? } instead of lines[], for reading rather than citing. Default true. start : typing.Optional[float] - Window start in seconds from the beginning of the video. Send start and end together. On captions the window bills only its own started 15-minute blocks; on Premium it trims an already purchased transcript; this GET does not charge. + Window start in seconds from the beginning of the video. Send start and end together. On captions the window bills only its own started 15-minute blocks; on Premium it trims the returned content. An explicit Premium read is charged for the whole video from the account's plan credits and then its on-demand budget; a window does not reduce that charge. end : typing.Optional[float] Window end in seconds, greater than start and no greater than the video duration. Send start and end together. retry : typing.Optional[bool] - Premium only; captions with retry=true returns invalid_query. When the last Premium purchase for this video failed, a read answers 200 state failed with the job and last_attempt and buys nothing; retry=true buys it again under the same quote, budget and one-purchase rules as the first read. While that refund is still settling (job.status refund_pending) even retry=true answers state failed. Without a failed purchase it changes nothing. + Premium only; captions with retry=true returns invalid_query. When the last Premium transcript for this video failed, a read answers 200 state failed with the job and last_attempt and charges nothing; retry=true starts a new one under the same quote, budget and one-job-per-video rules as the first read. While that refund is still settling (job.status refund_pending) even retry=true answers state failed. Without a failed job it changes nothing. refresh : typing.Optional[bool] Captions only; Premium with refresh=true returns invalid_query. Refetch the caption track from YouTube instead of serving the stored copy. Available only for videos outside our index; a pipeline-owned video refuses it with invalid_query. @@ -269,7 +269,7 @@ def get( Returns ------- HttpResponse[TranscriptResult] - state ready: the transcript (video, quality, source, language, languages, lines or paragraphs, speakers and revision on Premium, rows_billed, as_of, note). state failed (Premium only): the last purchase for this video failed; job and last_attempt say why, nothing was bought, and retry=true buys again. + state ready: the transcript (video, quality, source, language, languages, lines or paragraphs, speakers and revision on Premium, rows_billed, as_of, note). state failed (Premium only): the last Premium transcript for this video failed; job and last_attempt say why, nothing was charged, and retry=true starts a new one. """ _response = self._client_wrapper.httpx_client.request( f"v1/transcripts/{encode_path_param(video_id)}", @@ -396,7 +396,7 @@ def quote( self, video_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> HttpResponse[TranscriptPurchaseQuote]: """ - Optional free quote: the price a Premium read of this video would charge right now, as rows and credits, where the credits would come from, and max_on_demand_cents, the on-demand money the read would need beyond included credits within the account limit. It does not reserve funds or start generation. A video with no known duration, or one past the 12 hour cap, answers 400 invalid_query with param video_id. + Optional free quote: what a Premium read of this video would use right now, as rows and credits, where the credits would come from, and max_on_demand_cents, the on-demand budget the read would need beyond the plan's credits within the account limit. It does not reserve credits or budget and does not start a transcript. A video with no known duration, or one past the 12 hour cap, answers 400 invalid_query with param video_id. Parameters ---------- @@ -510,7 +510,7 @@ def list_requests( request_options: typing.Optional[RequestOptions] = None, ) -> SyncPager[TranscriptRequestListResponseRequestsItem, TranscriptRequestListResponse]: """ - Your transcription requests in descending creation time and id order. limit defaults to 20 and accepts 1–100. Follow next_cursor with the same video_id, limit and credential; has_more is false and next_cursor is null on the last page. A traversal excludes requests inserted after its first page. Each entry has the same shape as the status poll plus a `title` field (the video title, null when unknown). The scheduled reconciler advances requests; reading this list never dispatches work or changes billing. In-flight entries carry `eta_seconds` and `next_poll_seconds`. + Your transcription requests in descending creation time and id order. limit defaults to 20 and accepts 1–100. Follow next_cursor with the same video_id, limit and credential; has_more is false and next_cursor is null on the last page. A traversal excludes requests inserted after its first page. Each entry is a Premium transcript job with its processing and billing state, a `status_url` for the Premium transcript GET, and a `title` field (the video title, null when unknown). The scheduled reconciler advances requests; reading this list never dispatches work or changes billing. In-flight entries carry `eta_seconds` and `next_poll_seconds`. Parameters ---------- @@ -841,7 +841,7 @@ async def get( request_options: typing.Optional[RequestOptions] = None, ) -> AsyncHttpResponse[TranscriptResult]: """ - Caption retrieval costs one row per started 15 minutes. quality=premium is one read: an owned transcript answers 200 ready at zero rows; otherwise this call buys the whole video within the account's plan and on-demand budget, included credits first and then on-demand money up to the account limit, and answers 202 pending with the job and Retry-After until the transcript is ready. Read again after Retry-After; repeated reads join the same purchase and never buy twice. When the last purchase for the video failed, the read answers 200 state failed with the job and last_attempt and buys nothing; retry=true buys it again. When the plan or the budget blocks, 403 paid_plan_required (with unlock) or 402 quota_exceeded or spend_limit_exceeded carries the price in quote and nothing is charged. A default-premium account with nothing owned reads captions with a note. start/end only trim the returned content; language selects caption tracks, timestamps=false returns paragraphs. Premium lines carry speaker and index, and the body carries speakers and revision. + Caption reads use one row per started 15 minutes. quality=premium is one read. An owned transcript answers 200 ready at zero rows. Otherwise this call starts a Premium transcript of the whole video, using credits from the account's plan first and then the account's on-demand budget up to its limit, and answers 202 pending with the job and Retry-After until the transcript is ready. Read again after Retry-After; repeated reads join the same job and never charge twice. When the last Premium transcript for the video failed, the read answers 200 state failed with the job and last_attempt and charges nothing; retry=true starts a new one. When the plan or the budget blocks, 403 paid_plan_required (with unlock) or 402 quota_exceeded or spend_limit_exceeded carries the price in quote and nothing is charged. A default-premium account with nothing owned reads captions with a note. start/end only trim the returned content; language selects caption tracks, timestamps=false returns paragraphs. Premium lines carry speaker and index, and the body carries speakers and revision. Parameters ---------- @@ -849,7 +849,7 @@ async def get( YouTube video id, 11 characters. quality : typing.Optional[GetTranscriptsRequestQuality] - captions reads creator or automatic captions at 1 row per started 15 minutes. premium is one read: an owned transcript returns 200 state ready at zero rows; otherwise the read buys the whole video within the account's plan and on-demand budget (included credits first, then on-demand money up to the account limit) and returns 202 state pending with the job until it is ready. When the last purchase for the video failed it answers 200 state failed and buys again only with retry=true. 402 quota_exceeded or spend_limit_exceeded and 403 paid_plan_required carry the price in quote. It never substitutes captions. Default captions unless changed in account settings. + captions reads creator or automatic captions at 1 row per started 15 minutes. premium is one read. An owned transcript returns 200 state ready at zero rows. Otherwise the read starts a Premium transcript of the whole video, using credits from the account's plan first and then the account's on-demand budget up to its limit, and returns 202 state pending with the job until it is ready. When the last Premium transcript for the video failed it answers 200 state failed and starts a new one only with retry=true. 402 quota_exceeded or spend_limit_exceeded and 403 paid_plan_required carry the price in quote. It never substitutes captions. Default captions unless changed in account settings. language : typing.Optional[str] Comma-separated caption language priority list, at most 5, tried in order (e.g. "de,en"). Use asr for the first automatic track and asr- for a specific one. Default en. languages[] in the response lists every track the video offers. @@ -858,13 +858,13 @@ async def get( false returns paragraphs[] of { start, text, speaker? } instead of lines[], for reading rather than citing. Default true. start : typing.Optional[float] - Window start in seconds from the beginning of the video. Send start and end together. On captions the window bills only its own started 15-minute blocks; on Premium it trims an already purchased transcript; this GET does not charge. + Window start in seconds from the beginning of the video. Send start and end together. On captions the window bills only its own started 15-minute blocks; on Premium it trims the returned content. An explicit Premium read is charged for the whole video from the account's plan credits and then its on-demand budget; a window does not reduce that charge. end : typing.Optional[float] Window end in seconds, greater than start and no greater than the video duration. Send start and end together. retry : typing.Optional[bool] - Premium only; captions with retry=true returns invalid_query. When the last Premium purchase for this video failed, a read answers 200 state failed with the job and last_attempt and buys nothing; retry=true buys it again under the same quote, budget and one-purchase rules as the first read. While that refund is still settling (job.status refund_pending) even retry=true answers state failed. Without a failed purchase it changes nothing. + Premium only; captions with retry=true returns invalid_query. When the last Premium transcript for this video failed, a read answers 200 state failed with the job and last_attempt and charges nothing; retry=true starts a new one under the same quote, budget and one-job-per-video rules as the first read. While that refund is still settling (job.status refund_pending) even retry=true answers state failed. Without a failed job it changes nothing. refresh : typing.Optional[bool] Captions only; Premium with refresh=true returns invalid_query. Refetch the caption track from YouTube instead of serving the stored copy. Available only for videos outside our index; a pipeline-owned video refuses it with invalid_query. @@ -875,7 +875,7 @@ async def get( Returns ------- AsyncHttpResponse[TranscriptResult] - state ready: the transcript (video, quality, source, language, languages, lines or paragraphs, speakers and revision on Premium, rows_billed, as_of, note). state failed (Premium only): the last purchase for this video failed; job and last_attempt say why, nothing was bought, and retry=true buys again. + state ready: the transcript (video, quality, source, language, languages, lines or paragraphs, speakers and revision on Premium, rows_billed, as_of, note). state failed (Premium only): the last Premium transcript for this video failed; job and last_attempt say why, nothing was charged, and retry=true starts a new one. """ _response = await self._client_wrapper.httpx_client.request( f"v1/transcripts/{encode_path_param(video_id)}", @@ -1002,7 +1002,7 @@ async def quote( self, video_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> AsyncHttpResponse[TranscriptPurchaseQuote]: """ - Optional free quote: the price a Premium read of this video would charge right now, as rows and credits, where the credits would come from, and max_on_demand_cents, the on-demand money the read would need beyond included credits within the account limit. It does not reserve funds or start generation. A video with no known duration, or one past the 12 hour cap, answers 400 invalid_query with param video_id. + Optional free quote: what a Premium read of this video would use right now, as rows and credits, where the credits would come from, and max_on_demand_cents, the on-demand budget the read would need beyond the plan's credits within the account limit. It does not reserve credits or budget and does not start a transcript. A video with no known duration, or one past the 12 hour cap, answers 400 invalid_query with param video_id. Parameters ---------- @@ -1116,7 +1116,7 @@ async def list_requests( request_options: typing.Optional[RequestOptions] = None, ) -> AsyncPager[TranscriptRequestListResponseRequestsItem, TranscriptRequestListResponse]: """ - Your transcription requests in descending creation time and id order. limit defaults to 20 and accepts 1–100. Follow next_cursor with the same video_id, limit and credential; has_more is false and next_cursor is null on the last page. A traversal excludes requests inserted after its first page. Each entry has the same shape as the status poll plus a `title` field (the video title, null when unknown). The scheduled reconciler advances requests; reading this list never dispatches work or changes billing. In-flight entries carry `eta_seconds` and `next_poll_seconds`. + Your transcription requests in descending creation time and id order. limit defaults to 20 and accepts 1–100. Follow next_cursor with the same video_id, limit and credential; has_more is false and next_cursor is null on the last page. A traversal excludes requests inserted after its first page. Each entry is a Premium transcript job with its processing and billing state, a `status_url` for the Premium transcript GET, and a `title` field (the video title, null when unknown). The scheduled reconciler advances requests; reading this list never dispatches work or changes billing. In-flight entries carry `eta_seconds` and `next_poll_seconds`. Parameters ---------- diff --git a/src/arcmira/types/channel_sponsors_response_access_details.py b/src/arcmira/types/channel_sponsors_response_access_details.py index a1c1166..068459c 100644 --- a/src/arcmira/types/channel_sponsors_response_access_details.py +++ b/src/arcmira/types/channel_sponsors_response_access_details.py @@ -18,6 +18,16 @@ class ChannelSponsorsResponseAccessDetails(UniversalBaseModel): On tracker_already_exists, the existing tracker id. Reuse it instead of creating another tracker. """ + limit: typing.Optional[int] = pydantic.Field(default=None) + """ + On tracker_limit, the trackers the plan holds. + """ + + count: typing.Optional[int] = pydantic.Field(default=None) + """ + On tracker_limit, the trackers the account holds now. + """ + if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 else: diff --git a/src/arcmira/types/entity_momentum_response_access_details.py b/src/arcmira/types/entity_momentum_response_access_details.py index ab55f58..064cd1e 100644 --- a/src/arcmira/types/entity_momentum_response_access_details.py +++ b/src/arcmira/types/entity_momentum_response_access_details.py @@ -18,6 +18,16 @@ class EntityMomentumResponseAccessDetails(UniversalBaseModel): On tracker_already_exists, the existing tracker id. Reuse it instead of creating another tracker. """ + limit: typing.Optional[int] = pydantic.Field(default=None) + """ + On tracker_limit, the trackers the plan holds. + """ + + count: typing.Optional[int] = pydantic.Field(default=None) + """ + On tracker_limit, the trackers the account holds now. + """ + if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 else: diff --git a/src/arcmira/types/error_error_details.py b/src/arcmira/types/error_error_details.py index f1b7e72..625cccd 100644 --- a/src/arcmira/types/error_error_details.py +++ b/src/arcmira/types/error_error_details.py @@ -18,6 +18,16 @@ class ErrorErrorDetails(UniversalBaseModel): On tracker_already_exists, the existing tracker id. Reuse it instead of creating another tracker. """ + limit: typing.Optional[int] = pydantic.Field(default=None) + """ + On tracker_limit, the trackers the plan holds. + """ + + count: typing.Optional[int] = pydantic.Field(default=None) + """ + On tracker_limit, the trackers the account holds now. + """ + if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 else: diff --git a/src/arcmira/types/me_response.py b/src/arcmira/types/me_response.py index 2fa101a..6b829be 100644 --- a/src/arcmira/types/me_response.py +++ b/src/arcmira/types/me_response.py @@ -42,7 +42,7 @@ class MeResponse(UniversalBaseModel): tier: str = pydantic.Field() """ - Plan tier, e.g. free, hobby, pro, enterprise. + Plan tier, e.g. free, pro, pro_plus, ultra, enterprise. """ scopes: typing.List[str] = pydantic.Field() diff --git a/src/arcmira/types/monitor.py b/src/arcmira/types/monitor.py index 54dd865..9855072 100644 --- a/src/arcmira/types/monitor.py +++ b/src/arcmira/types/monitor.py @@ -37,7 +37,7 @@ class Monitor(UniversalBaseModel): notify_frequency: typing.Optional[str] = pydantic.Field(default=None) """ - Delivery cadence. Values: realtime (deliver immediately), hourly (hourly digest), daily (daily digest). Free tier is limited to daily. + Delivery cadence. Values: realtime (deliver immediately), hourly (hourly digest), daily (daily digest). """ digest_day: typing.Optional[str] = pydantic.Field(default=None) diff --git a/src/arcmira/types/refused_quote.py b/src/arcmira/types/refused_quote.py index 1e7b401..42ec5d5 100644 --- a/src/arcmira/types/refused_quote.py +++ b/src/arcmira/types/refused_quote.py @@ -15,12 +15,12 @@ class RefusedQuote(TranscriptQuote): charge: typing.Optional[RefusedQuoteCharge] = pydantic.Field(default=None) """ - What the purchase would charge at the current balance. Absent when no current price could be read. + What the request would charge at the current balance. Absent when no current price could be read. """ max_on_demand_cents: typing.Optional[int] = pydantic.Field(default=None) """ - The on-demand money, in whole cents, this purchase needs beyond included credits at the current balance. + The on-demand usage, in whole cents, this request needs beyond the plan's credits at the current balance. """ if IS_PYDANTIC_V2: diff --git a/src/arcmira/types/refused_quote_charge.py b/src/arcmira/types/refused_quote_charge.py index 5f55051..f32cbfd 100644 --- a/src/arcmira/types/refused_quote_charge.py +++ b/src/arcmira/types/refused_quote_charge.py @@ -12,7 +12,7 @@ class RefusedQuoteCharge(UniversalBaseModel): """ - What the purchase would charge at the current balance. Absent when no current price could be read. + What the request would charge at the current balance. Absent when no current price could be read. """ unit: RefusedQuoteChargeUnit diff --git a/src/arcmira/types/transcript_failed.py b/src/arcmira/types/transcript_failed.py index fc94468..8745ad0 100644 --- a/src/arcmira/types/transcript_failed.py +++ b/src/arcmira/types/transcript_failed.py @@ -15,12 +15,12 @@ class TranscriptFailed(UniversalBaseModel): job: TranscriptJob last_attempt: TranscriptFailedLastAttempt = pydantic.Field() """ - The failed purchase in brief: job.status and job.error. + The failed job in brief, as job.status and job.error. """ note: str = pydantic.Field() """ - What to do next: read again with retry=true to buy the video again, or wait while the refund settles. + The next step. Read again with retry=true to start a new Premium transcript, or wait while the refund settles. """ if IS_PYDANTIC_V2: diff --git a/src/arcmira/types/transcript_failed_last_attempt.py b/src/arcmira/types/transcript_failed_last_attempt.py index 032bc87..7a58d8a 100644 --- a/src/arcmira/types/transcript_failed_last_attempt.py +++ b/src/arcmira/types/transcript_failed_last_attempt.py @@ -9,12 +9,12 @@ class TranscriptFailedLastAttempt(UniversalBaseModel): """ - The failed purchase in brief: job.status and job.error. + The failed job in brief, as job.status and job.error. """ status: TranscriptFailedLastAttemptStatus = pydantic.Field() """ - How the last purchase ended: failed, refunded (the charge was returned), or refund_pending (the refund is still settling). + How the last job ended: failed, refunded (the charge was returned), or refund_pending (the refund is still settling). """ error: str = pydantic.Field() diff --git a/src/arcmira/types/transcript_job.py b/src/arcmira/types/transcript_job.py index 398209e..5a76d6d 100644 --- a/src/arcmira/types/transcript_job.py +++ b/src/arcmira/types/transcript_job.py @@ -12,7 +12,7 @@ class TranscriptJob(UniversalBaseModel): """ - Your open Premium purchase for this video, when captions were served while it transcribes. + A Premium transcript job with its processing state, charge and URL for reading the transcript again. """ id: str = pydantic.Field() @@ -27,12 +27,12 @@ class TranscriptJob(UniversalBaseModel): state: TranscriptJobState = pydantic.Field() """ - Coarse outcome: pending until the Premium transcript is servable (ready), the purchase failed, or it was refunded. + Coarse outcome: pending until the Premium transcript is servable (ready), the job failed, or it was refunded. """ status: TranscriptJobStatus = pydantic.Field() """ - Request status. Values: queued (accepted; audio download not started), downloading (fetching the video audio), transcribing (premium speech-to-text is running), analyzing (entity/commercial analysis is running), complete (premium transcript is servable via GET /v1/transcripts/{video_id}), failed (rejected intent or legacy purchase requiring accounting review), refund_pending (refund transaction must still complete), refunded (terminal failure; the charged rows were returned and the unlock this submission bought was revoked). + Request status. Values: queued (accepted; audio download not started), downloading (fetching the video audio), transcribing (premium speech-to-text is running), analyzing (entity/commercial analysis is running), complete (premium transcript is servable via GET /v1/transcripts/{video_id}), failed (rejected intent, or a legacy request needing accounting review), refund_pending (refund transaction must still complete), refunded (terminal failure; the charged rows were returned and the unlock this request granted was revoked). """ stage: typing.Optional[TranscriptJobStage] = pydantic.Field(default=None) @@ -42,7 +42,7 @@ class TranscriptJob(UniversalBaseModel): charge: typing.Optional[TranscriptJobCharge] = pydantic.Field(default=None) """ - What the purchase charged. Present on durable purchases; absent only on legacy requests. + What the job charged. Absent only on legacy requests. """ eta_seconds: typing.Optional[int] = pydantic.Field(default=None) diff --git a/src/arcmira/types/transcript_job_charge.py b/src/arcmira/types/transcript_job_charge.py index e4b1c24..607f440 100644 --- a/src/arcmira/types/transcript_job_charge.py +++ b/src/arcmira/types/transcript_job_charge.py @@ -12,13 +12,13 @@ class TranscriptJobCharge(UniversalBaseModel): """ - What the purchase charged. Present on durable purchases; absent only on legacy requests. + What the job charged. Absent only on legacy requests. """ unit: TranscriptJobChargeUnit amount: float = pydantic.Field() """ - Credits this purchase charged. 0 when a prior unlock made it free. + Credits this job charged. 0 when a prior unlock made it free. """ from_: typing_extensions.Annotated[ @@ -26,11 +26,11 @@ class TranscriptJobCharge(UniversalBaseModel): FieldMetadata(alias="from"), pydantic.Field( alias="from", - description="Where the credits came from: the included allowance, on-demand usage, or both. Present once the purchase is funded.", + description="Where the credits came from. included is the plan's credits, on_demand is the on-demand budget, mixed is both. Present once the job is funded.", ), ] = None """ - Where the credits came from: the included allowance, on-demand usage, or both. Present once the purchase is funded. + Where the credits came from. included is the plan's credits, on_demand is the on-demand budget, mixed is both. Present once the job is funded. """ if IS_PYDANTIC_V2: diff --git a/src/arcmira/types/transcript_purchase_quote.py b/src/arcmira/types/transcript_purchase_quote.py index 643d6fc..83e63cc 100644 --- a/src/arcmira/types/transcript_purchase_quote.py +++ b/src/arcmira/types/transcript_purchase_quote.py @@ -18,7 +18,7 @@ class TranscriptPurchaseQuote(UniversalBaseModel): eligible: bool upgrade: typing.Optional[TranscriptPurchaseQuoteUpgrade] = pydantic.Field(default=None) """ - Present when eligible is false: the plan checkout that can buy this transcript, as a button label and an absolute link. + Present when eligible is false. Names the plan that includes Premium transcripts, as a button label and an absolute link to its checkout. """ quote: TranscriptQuote diff --git a/src/arcmira/types/transcript_purchase_quote_upgrade.py b/src/arcmira/types/transcript_purchase_quote_upgrade.py index a061675..c6f63ae 100644 --- a/src/arcmira/types/transcript_purchase_quote_upgrade.py +++ b/src/arcmira/types/transcript_purchase_quote_upgrade.py @@ -8,7 +8,7 @@ class TranscriptPurchaseQuoteUpgrade(UniversalBaseModel): """ - Present when eligible is false: the plan checkout that can buy this transcript, as a button label and an absolute link. + Present when eligible is false. Names the plan that includes Premium transcripts, as a button label and an absolute link to its checkout. """ label: str diff --git a/src/arcmira/types/transcript_quote.py b/src/arcmira/types/transcript_quote.py index 1781ac2..622bb4e 100644 --- a/src/arcmira/types/transcript_quote.py +++ b/src/arcmira/types/transcript_quote.py @@ -14,7 +14,7 @@ class TranscriptQuote(UniversalBaseModel): rows: int = pydantic.Field() """ - Total unlock cost in rows: 75 rows per 15-minute block. + Rows the whole video uses, 75 rows per 15-minute block. """ if IS_PYDANTIC_V2: diff --git a/src/arcmira/types/transcript_request_list_response_requests_item.py b/src/arcmira/types/transcript_request_list_response_requests_item.py index 1014f22..e02b31e 100644 --- a/src/arcmira/types/transcript_request_list_response_requests_item.py +++ b/src/arcmira/types/transcript_request_list_response_requests_item.py @@ -8,6 +8,10 @@ class TranscriptRequestListResponseRequestsItem(TranscriptJob): + """ + A Premium transcript job with its processing state, charge and URL for reading the transcript again. + """ + title: typing.Optional[str] = pydantic.Field(default=None) """ Video title for display. Null when unknown. diff --git a/src/arcmira/types/transcript_response.py b/src/arcmira/types/transcript_response.py index c554e3b..dcc7b59 100644 --- a/src/arcmira/types/transcript_response.py +++ b/src/arcmira/types/transcript_response.py @@ -60,12 +60,12 @@ class TranscriptResponse(UniversalBaseModel): range: typing.Optional[TranscriptResponseRange] = pydantic.Field(default=None) """ - Echoed when you sent start and end. Lines overlapping the window are returned. On captions only the window is billed; Premium retrieval is free. + Echoed when you sent start and end. Lines overlapping the window are returned. On captions only the window is billed. An explicit Premium read is charged for the whole video, from the account's plan credits and then its on-demand budget; the window only trims the returned content. """ rows_billed: int = pydantic.Field() """ - Rows this call charged. 0 on a repeat of the same video, quality, language, and range inside the 7 day dedupe window, and always 0 on Premium retrieval. + Caption retrieval rows charged by this call. 0 on a repeat of the same video, quality, language, and range inside the 7 day dedupe window. Premium responses report 0 here even when the read was charged for the whole video; this field does not report Premium charges. """ as_of: typing.Optional[str] = pydantic.Field(default=None) diff --git a/src/arcmira/types/transcript_response_access_details.py b/src/arcmira/types/transcript_response_access_details.py index 52e7138..619e05e 100644 --- a/src/arcmira/types/transcript_response_access_details.py +++ b/src/arcmira/types/transcript_response_access_details.py @@ -18,6 +18,16 @@ class TranscriptResponseAccessDetails(UniversalBaseModel): On tracker_already_exists, the existing tracker id. Reuse it instead of creating another tracker. """ + limit: typing.Optional[int] = pydantic.Field(default=None) + """ + On tracker_limit, the trackers the plan holds. + """ + + count: typing.Optional[int] = pydantic.Field(default=None) + """ + On tracker_limit, the trackers the account holds now. + """ + if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 else: diff --git a/src/arcmira/types/transcript_response_range.py b/src/arcmira/types/transcript_response_range.py index bc67bb1..fb6e24d 100644 --- a/src/arcmira/types/transcript_response_range.py +++ b/src/arcmira/types/transcript_response_range.py @@ -8,7 +8,7 @@ class TranscriptResponseRange(UniversalBaseModel): """ - Echoed when you sent start and end. Lines overlapping the window are returned. On captions only the window is billed; Premium retrieval is free. + Echoed when you sent start and end. Lines overlapping the window are returned. On captions only the window is billed. An explicit Premium read is charged for the whole video, from the account's plan credits and then its on-demand budget; the window only trims the returned content. """ start: float diff --git a/src/arcmira/types/transcript_search_response_access_details.py b/src/arcmira/types/transcript_search_response_access_details.py index b44e22f..2c966dd 100644 --- a/src/arcmira/types/transcript_search_response_access_details.py +++ b/src/arcmira/types/transcript_search_response_access_details.py @@ -18,6 +18,16 @@ class TranscriptSearchResponseAccessDetails(UniversalBaseModel): On tracker_already_exists, the existing tracker id. Reuse it instead of creating another tracker. """ + limit: typing.Optional[int] = pydantic.Field(default=None) + """ + On tracker_limit, the trackers the plan holds. + """ + + count: typing.Optional[int] = pydantic.Field(default=None) + """ + On tracker_limit, the trackers the account holds now. + """ + if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 else: