# Subtly API reference

> Create asynchronous transcription and subtitle translation jobs for a Subtly workspace using prepaid USD credits. Transcription rates are Whisper Large v3: $0.10 per audio hour; Whisper Large v3 Turbo: $0.04 per audio hour, with a 15-second minimum. Translation rates are Quality: $10.00 per 1M source characters per target language; Fast: $5.00 per 1M source characters per target language, with a 225-character minimum per target language.

Full OpenAPI 3.1 document: [/openapi.json](/openapi.json). Interactive reference: [/docs/api](/docs/api).

Base URL: `https://subtly.app`

## Authentication

Create a workspace API key in Subtly, then send it as `Authorization: Bearer <API_KEY>`. Keys are tenant-scoped. The public API does not enforce per-key scopes.

## Transcriptions

Create and manage audio or video transcription jobs.

### GET /api/v1/transcriptions

**List the most recent 50 transcription jobs**

Returns up to 50 jobs in this API key's workspace, newest first. This endpoint does not accept pagination parameters. Bearer API keys are limited to 120 read requests per minute and 20 create or cancel requests per minute. A `429` response includes `Retry-After`; a `503` can indicate the limiter is unavailable.

Responses:

- 200: The most recent jobs for this resource type.
- 401: The bearer API key is missing or invalid.
- 429: The API key exceeded its per-minute limit.
- 503: Rate limiting or a required service is temporarily unavailable.

### POST /api/v1/transcriptions

**Create a transcription**

Queues an audio or video transcription. Raw upload extensions are .aac, .flac, .m4a, .mp3, .mp4, .mpeg, .mpg, .mov, .m4v, .mkv, .ogg, .opus, .wav, .webm, .wma, .avi. Spoken-language codes are documented in GET /api/v1/languages; large-v3 and large-v3-turbo share that catalog, with auto detection available. Public rates are Whisper Large v3: $0.10 per audio hour; Whisper Large v3 Turbo: $0.04 per audio hour. Each new transcription has a 15-second billed minimum; longer files are billed by actual duration, not in fixed 15-second blocks. The JSON body limit is 1 MiB; raw uploads are limited to 4 GiB. JSON requests use an optional Idempotency-Key header; raw uploads require it when filename is present. Bearer API keys are limited to 120 read requests per minute and 20 create or cancel requests per minute. A `429` response includes `Retry-After`; a `503` can indicate the limiter is unavailable.

Parameters:

- `X-Caption-Webhook-Delivery` (header): Set to suppress to disable all callbacks for this job. Otherwise, subscriptions belong to the authenticated API key's integration. The choice is captured at acceptance and must stay the same on idempotent retries. Clients cannot choose another integration.
- `Idempotency-Key` (header): Optional for JSON requests. Required when `filename` selects raw upload mode, so an interrupted upload can be retried safely.
- `filename` (query): Include this to select raw streaming upload mode, for example filename=meeting.wav. The value becomes the uploaded filename; omit it when sending JSON. Idempotency-Key is required when filename is present.
- `model` (query): Transcription model. Defaults to `large-v3`; `large-v3-turbo` is also available.
- `language` (query): Spoken language code. For large-v3 and large-v3-turbo, use one of the codes in GET /api/v1/languages or auto for detection.

Request body: application/json, application/octet-stream, audio/*, video/*

Responses:

- 202: The job was accepted for asynchronous processing.
- 400: The JSON body is invalid, a required upload idempotency key is missing, or the request fails validation.
- 401: The bearer API key is missing or invalid.
- 402: The workspace does not have enough prepaid USD credits.
- 413: The JSON body exceeds 1 MiB, the media upload exceeds 4 GiB, or the subtitle/text upload exceeds 10 MiB.
- 415: Raw upload mode does not accept multipart form data.
- 429: The API key exceeded its per-minute limit.
- 503: Rate limiting, billing configuration, or a required service is temporarily unavailable.

### GET /api/v1/transcriptions/{id}

**Get a transcription job**

Returns a job and its recent progress events, non-expired artifacts, and webhook delivery attempts. Results are private downloads and expire 24 hours after completion. Bearer API keys are limited to 120 read requests per minute and 20 create or cancel requests per minute. A `429` response includes `Retry-After`; a `503` can indicate the limiter is unavailable.

Parameters:

- `id` (path, required): The job UUID.

Responses:

- 200: The job detail.
- 401: The bearer API key is missing or invalid.
- 404: No matching job exists in this workspace.
- 429: The API key exceeded its per-minute limit.
- 503: Rate limiting or a required service is temporarily unavailable.

### DELETE /api/v1/transcriptions/{id}

**Cancel a transcription job**

Requests cancellation. A terminal or already-finished job returns 409 ALREADY_FINISHED; a cancellation still pending with the worker returns 202. Bearer API keys are limited to 120 read requests per minute and 20 create or cancel requests per minute. A `429` response includes `Retry-After`; a `503` can indicate the limiter is unavailable.

Parameters:

- `id` (path, required): The job UUID.

Responses:

- 200: Cancellation was recorded.
- 202: Cancellation is still pending with the worker.
- 401: The bearer API key is missing or invalid.
- 404: No matching job exists in this workspace.
- 409: The job is already finished.
- 429: The API key exceeded its per-minute limit.
- 503: Rate limiting or a required service is temporarily unavailable.

### GET /api/v1/transcriptions/{id}/artifacts/{artifactId}

**Download a transcription artifact**

Streams an unexpired managed artifact as a file download. A 404 means the job or artifact is missing, belongs to a different workspace, or has expired. Bearer API keys are limited to 120 read requests per minute and 20 create or cancel requests per minute. A `429` response includes `Retry-After`; a `503` can indicate the limiter is unavailable.

Parameters:

- `id` (path, required): The job UUID.
- `artifactId` (path, required): The artifact UUID from the job detail.

Responses:

- 200: The artifact file. The response includes Content-Disposition and the stored content type.
- 401: The bearer API key is missing or invalid.
- 404: The job or artifact does not exist or has expired.
- 409: Managed artifact download is unavailable for this job.
- 429: The API key exceeded its per-minute limit.
- 502: The storage service failed to return the artifact.
- 503: Rate limiting or a required service is temporarily unavailable.

## Translations

Create and manage subtitle and text translation jobs.

### GET /api/v1/translations

**List the most recent 50 translation jobs**

Returns up to 50 jobs in this API key's workspace, newest first. This endpoint does not accept pagination parameters. Bearer API keys are limited to 120 read requests per minute and 20 create or cancel requests per minute. A `429` response includes `Retry-After`; a `503` can indicate the limiter is unavailable.

Responses:

- 200: The most recent jobs for this resource type.
- 401: The bearer API key is missing or invalid.
- 429: The API key exceeded its per-minute limit.
- 503: Rate limiting or a required service is temporarily unavailable.

### POST /api/v1/translations

**Create a subtitle translation**

Queues a subtitle or text translation. URL, inline source_text, and raw uploads accept VTT, SRT, TXT, and Subtly JSON; to translate audio or video, first create a transcription, then pass its completed job ID as source_job_id. The source_job_id must have an available VTT artifact in this API key's workspace. Use source and target language codes from GET /api/v1/languages. Quality and Fast share the same catalog; translation does not support auto-detection. URL and inline inputs require source_language; source-job requests default to the transcription's language. The source language cannot also be a target. Rates are Quality: $10.00 per 1M source characters per target language; Fast: $5.00 per 1M source characters per target language. Each target language has a 225-character minimum; only targets with successful output are charged. Count Unicode code points in source caption text, including spaces and punctuation. Timestamps, cue IDs, and formatting do not count. For timed subtitles, HTML entities are decoded before counting, and cue boundaries add no characters. Untimed text counts literal Unicode code points within each paragraph; blank paragraph separators do not count. JSON requests are limited to 1 MiB; raw subtitle/text uploads are limited to 10 MiB. Untimed text supports txt and json outputs only. JSON requests use an optional Idempotency-Key header; source_url, source_text, and raw uploads require it. Bearer API keys are limited to 120 read requests per minute and 20 create or cancel requests per minute. A `429` response includes `Retry-After`; a `503` can indicate the limiter is unavailable.

Parameters:

- `X-Caption-Webhook-Delivery` (header): Set to suppress to disable all callbacks for this job. Otherwise, subscriptions belong to the authenticated API key's integration. The choice is captured at acceptance and must stay the same on idempotent retries. Clients cannot choose another integration.
- `Idempotency-Key` (header): Optional for JSON requests. Required when `filename` selects raw upload mode, so an interrupted upload can be retried safely.
- `filename` (query): Include this to select raw streaming upload mode, for example filename=captions.vtt. The value becomes the uploaded filename; omit it when sending JSON. Idempotency-Key is required when filename is present.
- `language` (query): Source subtitle language from GET /api/v1/languages. Defaults to en. auto-detection is not available, and the source language cannot be a target.
- `target_languages` (query): One or more target language codes from GET /api/v1/languages. The source language cannot be included. Defaults to `zh-CN,es,hi,de`.
- `formats` (query): Comma-separated output formats. Defaults to `vtt`; available formats are `vtt`, `srt`, `json`, and `txt`.
- `model` (query): Translation model. `google/translategemma-12b-it` is Fast (the default); `google/translategemma-27b-it` is Quality.

Request body: application/json, application/octet-stream, text/vtt

Responses:

- 202: The job was accepted for asynchronous processing.
- 400: The JSON body is invalid, a required upload idempotency key is missing, or the request fails validation.
- 401: The bearer API key is missing or invalid.
- 402: The workspace does not have enough prepaid USD credits.
- 413: The JSON body exceeds 1 MiB, the media upload exceeds 4 GiB, or the subtitle/text upload exceeds 10 MiB.
- 415: Raw upload mode does not accept multipart form data.
- 429: The API key exceeded its per-minute limit.
- 503: Rate limiting, billing configuration, or a required service is temporarily unavailable.

### GET /api/v1/translations/{id}

**Get a translation job**

Returns a job and its recent progress events, non-expired artifacts, and webhook delivery attempts. Results are private downloads and expire 24 hours after completion. Bearer API keys are limited to 120 read requests per minute and 20 create or cancel requests per minute. A `429` response includes `Retry-After`; a `503` can indicate the limiter is unavailable.

Parameters:

- `id` (path, required): The job UUID.

Responses:

- 200: The job detail.
- 401: The bearer API key is missing or invalid.
- 404: No matching job exists in this workspace.
- 429: The API key exceeded its per-minute limit.
- 503: Rate limiting or a required service is temporarily unavailable.

### DELETE /api/v1/translations/{id}

**Cancel a translation job**

Requests cancellation. A terminal or already-finished job returns 409 ALREADY_FINISHED; a cancellation still pending with the worker returns 202. Bearer API keys are limited to 120 read requests per minute and 20 create or cancel requests per minute. A `429` response includes `Retry-After`; a `503` can indicate the limiter is unavailable.

Parameters:

- `id` (path, required): The job UUID.

Responses:

- 200: Cancellation was recorded.
- 202: Cancellation is still pending with the worker.
- 401: The bearer API key is missing or invalid.
- 404: No matching job exists in this workspace.
- 409: The job is already finished.
- 429: The API key exceeded its per-minute limit.
- 503: Rate limiting or a required service is temporarily unavailable.

### GET /api/v1/translations/{id}/artifacts/{artifactId}

**Download a translation artifact**

Streams an unexpired managed artifact as a file download. A 404 means the job or artifact is missing, belongs to a different workspace, or has expired. Bearer API keys are limited to 120 read requests per minute and 20 create or cancel requests per minute. A `429` response includes `Retry-After`; a `503` can indicate the limiter is unavailable.

Parameters:

- `id` (path, required): The job UUID.
- `artifactId` (path, required): The artifact UUID from the job detail.

Responses:

- 200: The artifact file. The response includes Content-Disposition and the stored content type.
- 401: The bearer API key is missing or invalid.
- 404: The job or artifact does not exist or has expired.
- 409: Managed artifact download is unavailable for this job.
- 429: The API key exceeded its per-minute limit.
- 502: The storage service failed to return the artifact.
- 503: Rate limiting or a required service is temporarily unavailable.

## Languages

Discover supported language codes for transcription and translation.

### GET /api/v1/languages

**List supported languages**

Returns the language codes and names available for public transcription and translation models. This read-only discovery endpoint is public and does not require an API key. Each listed model shares the language coverage shown in its catalog. Whisper transcription uses `zh` for Chinese; translation uses `zh-CN` and `zh-TW`. Translation has no auto-detection, defaults the source language to `en`, and requires source and target languages to differ.

Responses:

- 200: Language names and codes, public model IDs and labels, and language-selection constraints.
