Plans & limits
Workspace plans
| Plan | Transcription jobs / month | Indexing credits / month | Clip credits / month | Thumbnail credits / month | Semantic search queries / month | Queue priority | Per-video length | |
|---|---|---|---|---|---|---|---|---|
free | 10 (resets on your billing period) | 100 (1 credit per txt_… indexed) | 1,000 (1 credit per clip in input.options.maxClips) | 100 (1 credit per variant in input.options.thumbnailCount; max 3 per job) | 1,000 | low | Up to 1 hour | |
enterprise | Unlimited (fair use) | Unlimited | Unlimited | Unlimited | Unlimited | Unlimited | high | Up to 1 hour by default; longer media available on request |
New workspaces default to free. Enterprise is assigned manually — contact your account team. Plan is reflected on each job as priority (set at creation, not overridable in the request body).
Free-plan monthly credit caps are configured in platform settings (billing.free on GET /v1/platform/config for admins). Public read: GET /v1/billing/limits. With a workspace API key, GET /v1/workspace or GET /v1/workspace/usage returns workspace-wide usage.services[]. GET /v1/projects/{projectId}/usage returns per-project consumption and optional project caps.
Monthly submission quota
Billable actions consume workspace credits for the current billing period (see GET /v1/workspace/usage):
POST /v1/jobswithserviceType: transcription— 1 credit per job.POST /v1/jobswithserviceType: indexer— 1 credit pertranscriptionIdininput.transcriptionIds(up to 50 per job).POST /v1/jobswithserviceType: clip_generation— 1 credit per clip requested ininput.options.maxClips(default and cap from platform settings — live values:GET /v1/jobs/policy?serviceType=clip_generation). A job asking for 5 clips consumes 5 credits at create time.POST /v1/jobswithserviceType: thumbnail— 1 credit per variant ininput.options.thumbnailCount(1–3; maximum 3 variants per job).POST /v1/jobswithserviceType: metadata— 1 credit per job.POST /v1/catalog/search— 1 credit per search request (response fields such asgroupCount,groups[], and camelCaseresults[]hits — see Semantic search → Search transcriptions).
Credits are reserved when the API accepts the request (job queued or search executed). Failed jobs after queueing still count toward usage.
When a service's monthly cap is reached, the API returns 403 with error.code: quotaExceeded. The message names the billable service and remaining credits (camelCase envelope; snake_case service id in the message text):
{
"data": null,
"error": {
"code": "quotaExceeded",
"message": "ai_search credit limit: need 1, 0 remaining this period; resets at 2026-06-01T00:00:00.000Z"
},
"metadata": { ... }
}Transcription, indexer, clips, thumbnail, and metadata jobs use the same pattern (transcription credit limit, indexer credit limit, clip_generation credit limit, thumbnail credit limit, metadata credit limit). Check balances before bulk index or search loops via GET /v1/workspace/usage (services[] with used, limit, and remaining).
This is an envelope error (not job.error). Integrators should surface it before polling. See Errors.
API rate limits (project & workspace keys)
Programmatic callers using project or workspace API keys share per-key HTTP rate limits (rolling one-minute window). Dashboard JWT sessions and platform admin routes are not capped this way — job volume is gated by monthly quota instead.
| Methods | Limit (per API key) |
|---|---|
GET, HEAD | 10,000 / minute |
POST, PUT, PATCH, DELETE | 50 / minute |
Read and write counters are independent — heavy polling on GET /v1/jobs/… does not consume your write budget. On exceed, the API returns 429 with error.code: rateLimited.
Max source duration & word timings
Max source duration is configured in platform settings (default 1 hour). Sources longer than this fail with duration_exceeded. Word-level timings are stored through the same limit — longer jobs return segments without per-word timings.
The worker rejects sources longer than this limit before transcription runs. Duration is checked from local media after download. Configure the limit in platform admin settings (transcription.maxSourceDurationSec).
Live values: GET /v1/transcription/policy → data.plans.free.maxSourceDurationSec and data.plans.enterprise.maxSourceDurationSec. There is no duration field on POST /v1/jobs — invalid length is discovered asynchronously. Poll the job; on failure, status is failed and error.code is duration_exceeded.
{
"code": "duration_exceeded",
"message": "Video duration 7200.0s exceeds limit 3600s (checked at local_probe)"
}Transcript size
Completed transcripts are stored in MongoDB with a BSON size guard (default ~15 MiB estimated before write). Extremely long or word-dense outputs fail at persist time with transcript_too_large on the job — the job ends failed even if the engine finished transcribing.
{
"code": "transcript_too_large",
"message": "Transcription payload is too large to store (estimated 18.42 MB, limit 15.0 MB, pre_persist)"
}The public Transcript API still returns full segments (and words when stored). See Transcripts.
Job failure codes
When status is failed, read error (code + message). Full segment text is never on the Job object — use resultSummary / Transcripts API on success only. For how error relates to lastError, stage errors, and retries, see Jobs → Job failures & retries.
| error.code | Typical cause |
|---|---|
duration_exceeded | Source longer than the worker max duration. |
transcript_too_large | Transcript BSON estimate or Mongo 16 MB limit on persist. |
processing_failed | Engine, download, or worker misconfiguration (missing API keys, network, etc.). |
Inspect progress[] for stage-level failed events and nested error objects — especially for early download failures.