This is the compact developer documentation for the Closed Caption Converter API. The full version is at https://www.closedcaptionconverter.com/docs/llms-full.txt # Closed Caption Converter API > Closed Caption Converter is a REST API for converting, conforming, QCing, translating, transcribing and delivering closed caption and subtitle files in over 30 formats. ## Key facts - Base URL: `https://api.closedcaptionconverter.com` - Auth: every `/jobs` request needs both headers `x-api-key: ` and `username: `. Keep the key server-side. - Submit a job: `POST /jobs` as `multipart/form-data` with `source` (file upload or public HTTPS URL) and `config` (Job Description as a JSON string), or as `application/json` where the body is the Job Description with a `source` URL. - The response is JSON `{ id, target, status, statusMsg, qcReport, progress }`. The output file is downloaded from the signed URL in `target`; it is not embedded in the response. - If `status` is `queued` or `in progress` (transcription, alignment, very large jobs), poll `GET /jobs/{id}` until `status` is `passed` or `failed`. - Profile names must match exactly. Get the valid lists from `GET /help/profiles/source` and `GET /help/profiles/target` (no auth). `GET /help/schemas/job` returns a Job Description with all defaults. - Errors are plain-text bodies with HTTP 400, 401, 404, 429 or 500. --- # API Getting Started The Closed Caption Converter API is a REST API that provides programmatic access to the full conversion engine, including format conversion, automatic conform workflows, transcription, machine translation, and delivery. Every feature available in the web application is accessible via the API, plus additional capabilities enabled by [Access Providers](https://www.closedcaptionconverter.com/docs/access-providers-guide). ## Base URL All API requests are made to: ``` https://api.closedcaptionconverter.com ``` If your team has been provisioned with a client-specific staging or production endpoint, use the URL supplied for that environment instead of the public default above. ## Authentication Every request to the `/jobs` endpoints must include two headers: ``` x-api-key: YOUR_API_KEY username: you@example.com ``` | Header | Description | |---|---| | `x-api-key` | Your API key. | | `username` | The email address of the Closed Caption Converter account that owns the key. | Requests missing either header are rejected with `401`. Postman collections exported from the app include both headers. To generate an API key, sign in to the web application, open **Account & Billing** in the left sidebar, select the **API Keys** tab, and click **Generate Key**. Each account has one active key at a time; generating a new key replaces the previous one. API keys are not available during the free trial. Keep your API key secure. Do not include it in client-side code or commit it to version control. If a key is compromised, generate a new key from **Account & Billing → API Keys** immediately. For interactive testing without writing code, use the [API Playground](https://www.closedcaptionconverter.com/docs/api-playground) workspace. ## Endpoints | Method | Path | Auth | Description | |---|---|---|---| | `POST` | `/jobs` | Yes | Submit a job (convert, QC, translate, transcribe, align, deliver). | | `GET` | `/jobs/{id}` | Yes | Get a job's status and download links. Use this to poll asynchronous jobs. | | `DELETE` | `/jobs/{id}` | Yes | Delete a job and its stored source and output files. | | `GET` | `/help/profiles/source` | No | JSON array of every supported source (read) profile name. | | `GET` | `/help/profiles/target` | No | JSON array of every supported target (write) profile name. | | `GET` | `/help/profiles/all` | No | Mapping of profile IDs to display names. | | `GET` | `/help/profiles/extensions` | No | Source and target profiles grouped by file extension. | | `GET` | `/help/profiles/default-extensions` | No | Default file extension for each profile. | | `GET` | `/help/profiles/encodings` | No | Default character encoding for each profile. | | `GET` | `/help/schemas/job` | No | A complete Job Description object with every field set to its default value. | Profile names in a Job Description must match a supported profile exactly. If you are unsure of a name, request `/help/profiles/source` or `/help/profiles/target` rather than guessing. ## Your First Request The primary endpoint for submitting caption processing jobs is `POST /jobs`. The request body is a `multipart/form-data` payload with the following fields: | Field | Type | Description | |---|---|---| | `source` | File or URL string | The source caption file, either uploaded as binary data or provided as a public HTTPS URL. Uploads are limited to 20 MB. | | `sources` | URL strings | Multiple source URLs, for multi-source jobs such as merge or Segmentation & Conform. Repeat the field once per URL. | | `config` | JSON string | The Job Description object that instructs the API what to do with the source file. Required unless `preset_id` is supplied. | | `preset_id` | string | Optional. The ID of a saved [Job Preset](https://www.closedcaptionconverter.com/docs/api/presets). Fields in `config` override the preset's values. | You do not need to include every possible conversion parameter in `config`. Omitted values use the engine defaults or the selected profile defaults. The following example converts a SubRip (SRT) file to WebVTT using curl: ```bash curl -X POST https://api.closedcaptionconverter.com/jobs \ -H "x-api-key: YOUR_API_KEY" \ -H "username: you@example.com" \ -F "source=@/path/to/input.srt" \ -F 'config={ "job_type": "convert", "source_profile": "SubRip Video Subtitle Script", "target_profile": "WebVTT", "default_frameRate": 29.97 }' ``` ## The Job Response Every successful `POST /jobs` returns `200` with a JSON object. The output file is not embedded in the response; download it from the signed URL in `target`: ```json { "jobId": "1b0e6f1a-6a7e-4c1e-9d0b-3f5f7c2a9e11", "id": "1b0e6f1a-6a7e-4c1e-9d0b-3f5f7c2a9e11", "target": "https://storage.googleapis.com/...signed-url.../1b0e6f1a-6a7e-4c1e-9d0b-3f5f7c2a9e11.vtt", "qcReport": false, "qc_status": null, "qc_errors": null, "status": "passed", "statusMsg": "Job completed successfully", "warning": "", "progress": 100 } ``` | Field | Description | |---|---| | `id` / `jobId` | The job ID. Both fields contain the same value. | | `target` | A signed HTTPS URL for the output file, or `false` when the job has not finished yet. | | `qcReport` | The QC report object when QC is enabled, otherwise `false`. See [Automatic QC Tests](https://www.closedcaptionconverter.com/docs/api/qc-tests#qc-report) for its structure. | | `qc_status` | `pass`, `warn`, or `fail` when QC ran, otherwise `null`. See [QC status](https://www.closedcaptionconverter.com/docs/api/qc-tests#qc-status). | | `qc_errors` | Total number of QC errors found, or `null` when QC did not run. | | `status` | `passed` when the job finished, `queued` or `in progress` while it is still running, `failed` on error. | | `statusMsg` | A human-readable status message. | | `warning` | Present on some convert jobs. Non-empty when an output file was produced despite a problem (for example, no events could be decoded). | | `progress` | Completion percentage from `0` to `100`. | ### Asynchronous Jobs Most `convert`, `qc`, and `translate` jobs complete within the request and return `status: "passed"`. Long-running work returns immediately with `status: "queued"` or `status: "in progress"` and `target: false`: - `transcribe` jobs, and `align` jobs that require transcription - Very large files written to some target formats, which are processed in a background queue For these jobs, poll `GET /jobs/{id}` until `status` is `passed` (then download `target`) or `failed` (then read `statusMsg`). A polling interval of 5–15 seconds is reasonable. ```bash curl https://api.closedcaptionconverter.com/jobs/JOB_ID \ -H "x-api-key: YOUR_API_KEY" \ -H "username: you@example.com" ``` `GET /jobs/{id}` returns the stored job record, including `status`, `statusMsg`, `progress`, the job `config` as a JSON string, and signed download URLs in `target` and `source` when those files exist. ### Deleting a Job `DELETE /jobs/{id}` removes the job's stored source, output, and transcript files and marks the job as deleted: ```json { "jobId": "1b0e6f1a-6a7e-4c1e-9d0b-3f5f7c2a9e11", "id": "1b0e6f1a-6a7e-4c1e-9d0b-3f5f7c2a9e11", "deleted": true, "deletedFiles": 2 } ``` ## Submitting a Job from a URL If your source file is hosted at a public HTTPS URL (or a pre-signed URL for private cloud storage), you can pass the URL string in the `source` field instead of uploading the file directly: ```bash curl -X POST https://api.closedcaptionconverter.com/jobs \ -H "x-api-key: YOUR_API_KEY" \ -H "username: you@example.com" \ -F "source=https://your-bucket.s3.amazonaws.com/captions/input.srt" \ -F 'config={ "job_type": "convert", "source_profile": "SubRip Video Subtitle Script", "target_profile": "EBU STL" }' ``` ## Submitting a JSON Body When your sources are URLs, you can send `Content-Type: application/json` instead of multipart form data. The request body is the Job Description itself, with the source URL in `source` (or an array of URLs in `sources`) and an optional `preset_id`: ```bash curl -X POST https://api.closedcaptionconverter.com/jobs \ -H "x-api-key: YOUR_API_KEY" \ -H "username: you@example.com" \ -H "Content-Type: application/json" \ -d '{ "job_type": "convert", "source": "https://your-bucket.s3.amazonaws.com/captions/input.srt", "source_profile": "SubRip Video Subtitle Script", "target_profile": "WebVTT" }' ``` ## Using a Preset If you have saved a Job Preset in the **Job Presets** workspace, you can reference it by ID instead of passing a full `config` object. Closed Caption Converter will retrieve the stored Job Description and apply it to your source file: ```bash curl -X POST https://api.closedcaptionconverter.com/jobs \ -H "x-api-key: YOUR_API_KEY" \ -H "username: you@example.com" \ -F "source=@/path/to/input.srt" \ -F "preset_id=your-preset-id" ``` See [API — Presets](https://www.closedcaptionconverter.com/docs/api/presets) for details on creating and managing presets. ## Postman Collection A Postman collection is available directly from the Closed Caption Converter web application: - **Subtitle Converter** — configure your job, open the **Job Description** button in the page header, and click **Download Postman Collection**. - **API Playground** — configure your endpoint, source, and job description, then click **Export Postman Collection**. Both exports include pre-configured requests for file upload and URL-based submissions using your current API key, `username` header, and job configuration, and can be imported directly into Postman or any compatible REST client. ## Building with AI To give an AI coding assistant the full API reference as plain markdown, see [Build with AI](https://www.closedcaptionconverter.com/docs/api/build-with-ai). ## Errors & Rate Limits The API uses standard HTTP status codes. Error responses have a **plain-text** body describing the problem, not JSON. | Status | Meaning | Example body | |---|---|---| | `400` | Malformed request, invalid configuration, or the job failed during processing. | `No configuration found in request.` | | `401` | Missing headers, or the API key does not match the `username`. | `Invalid credentials` | | `404` | The job ID does not exist or has been deleted. | `Job not found.` | | `429` | Too many failed authentication attempts. Wait for the number of seconds in the `Retry-After` header before retrying. | `Too many requests` | | `500` | Unexpected server error. | `Internal server error` | A job that fails after it has been accepted (for example, an asynchronous transcription) is reported through `GET /jobs/{id}` with `status: "failed"` and the reason in `statusMsg`. --- # Job Types & Descriptions A Job Description is the JSON document that instructs Closed Caption Converter what to do with a caption file. It is passed as the `config` field in API requests, used by the CLI as a configuration file, and generated automatically by the web application when you configure and run a job. Every job — from a simple format conversion to a multi-step transcription and delivery workflow — is expressed as a Job Description. The **Subtitle Converter** workspace includes a **Job Description** button in the page header that opens a modal with the exact JSON sent to the API for your current configuration. You can copy it directly or export it as a Postman collection. The [API Playground](https://www.closedcaptionconverter.com/docs/api-playground) workspace also lets you edit job description JSON and export Postman collections for API testing. ## Job Description Structure Every Job Description is a JSON object. The following table describes the top-level fields: | Field | Type | Default | Description | |---|---|---|---| | `job_type` | string | `"convert"` | The type of job to perform. See Job Types below. | | `source_profile` | string | `"SubRip Video Subtitle Script"` | The profile name used to decode the source file. Must match a supported source profile name exactly. | | `target_profile` | string | `"SubRip Video Subtitle Script"` | The profile name used to encode the output file. Must match a supported target profile name exactly. | | `default_frameRate` | number | `29.97` | The frame rate used when the source format does not carry frame rate metadata. | | `default_dropFrame` | boolean | `true` | The drop-frame flag used alongside `default_frameRate`. | | `source_frameRate` | string or number | `"auto"` | The frame rate to use when reading source timecodes. Set to `"auto"` to read from the file. | | `target_frameRate` | string or number | `"auto"` | The frame rate to write to the output file. Set to `"auto"` to match the source. | | `offset` | string | `"00:00:00:00"` | SMPTE timecode offset applied to all events. | | `offset_type` | string | `"add"` | Whether to `"add"` or `"subtract"` the offset value. | | `incode` | string | `"00:00:00:00"` | Programme start timecode. All events are normalised relative to this value. Set to `"auto"` to use the first event's in-time. | | `encoding_options` | array | `[]` | Format-specific encode options. Each element is an object with `name` and `selected` properties matching a target profile's available options. Set `selected` to `"auto"` on mapped metadata fields to copy matching source header values into the target. See [Metadata Passthrough](https://www.closedcaptionconverter.com/docs/encoding-decoding-options#metadata-passthrough). | | `decoding_options` | array | `[]` | Format-specific decode options. Each element is an object with `name` and `selected` properties. | | `auto_format_options` | object | see below | Configuration for the Auto Format filter. | | `auto_correct_timing_options` | object | see below | Configuration for the Auto Correct Timing / reading speed correction panel. | | `event_gap_options` | object | see below | Configuration for the Event Gap filter. | | `remove_forced_subs` | object | see below | Configuration for the Remove Forced Subtitles filter. | | `searches` | array | `[]` | Array of Search & Replace rules. | | `segments` | array | `[]` | Array of Segmentation & Conform segment definitions. | | `timecode_mode` | string | `"exclusive"` | How segment end times and black-segment durations are interpreted: `"exclusive"` or `"inclusive"`. Inclusive adds 1 frame to each file segment's end time and each black segment's duration during conform. | | `qc` | object | see below | Automatic QC configuration: `stage` (`"pre"` or `"post"`) and a `tests` array. See [Automatic QC Tests](https://www.closedcaptionconverter.com/docs/api/qc-tests). | | `media_path` | string | `""` | URL of the audio/video file for transcription or alignment jobs. | | `webhook` | string | `""` | A URL that receives a POST callback when the job completes. | | `delivery_options` | object | see below | Output delivery configuration for storage and platform providers. | | `transcribe_options` | object | see below | Transcription configuration including provider ID and language. | | `translate_options` | object | see below | Translation configuration including provider ID, source, and target languages. | --- ## Job Types The `job_type` field determines which processing path the job follows. If you omit it, Closed Caption Converter defaults to `convert`. The supported job types are described below. ### `convert` The standard job type for all format conversion and conform workflows. The source file is decoded using the specified source profile, any configured filters are applied in order, and the result is encoded using the target profile. You can include a `qc` object to run Automatic QC alongside conversion. Findings are returned as `qcReport`, along with `qc_status` and `qc_errors`, and do not change the encoded file. ```json { "job_type": "convert", "source_profile": "Scenarist V1.0", "target_profile": "EBU STL", "default_frameRate": 29.97, "default_dropFrame": true, "encoding_options": [ { "name": "Language Code", "selected": "English" }, { "name": "Country of Origin", "selected": "Canada" } ] } ``` ### `qc` A QC-only job. Nothing is encoded. The output file is `{jobId}_report.json`. The JSON body also includes `qcReport`, `qc_status` (`pass`, `warn`, or `fail`) and `qc_errors`. `qc.tests` must contain at least one enabled test, and a source file is required. Pre-processing (`qc.stage: "pre"`, the default) QCs the first source as decoded. Post-processing (`qc.stage: "post"`) runs every source through the same processing path as a convert job — filters, conform, offset, Auto Format, and timing correction — then QCs the result at the target frame rate. In both cases, technical tests and `sequentialTiming` inspect the source file, and no caption file is encoded. In the web application this job type is labelled **Verify**. ```json { "job_type": "qc", "source_profile": "SubRip Video Subtitle Script", "qc": { "stage": "post", "tests": [ { "id": "maxCharsPerLine", "max": 32, "level": "critical", "threshold": 0 }, { "id": "maxLinesPerEvent", "max": 2, "level": "critical", "threshold": 0 }, { "id": "maxCps", "max": 25, "level": "warn", "threshold": 3 }, { "id": "sequentialTiming", "level": "critical", "threshold": 0 } ] } } ``` ### `transcribe` Sends the audio or video at `media_path` to a configured transcription Access Provider, receives the transcript, converts it into the CCPRJ format, applies any configured filters, and encodes the result to the target profile. Requires a transcription provider to be configured in `transcribe_options`. ```json { "job_type": "transcribe", "target_profile": "SubRip Video Subtitle Script", "media_path": "https://presigned-url-to/media.mp4", "transcribe_options": { "source_language": "en", "provider_id": "your-transcription-provider-id", "provider_options": { "model": "nova-2", "punctuate": true, "diarize": false, "utterances": true, "utt_split": 0.8 } } } ``` The `provider_options` object is passed directly to the transcription service. Refer to your provider's documentation for supported parameters. ### `align` Aligns an existing caption or transcript file to audio/video content using a transcription provider's forced alignment capability. Like the `transcribe` job type, this requires a `media_path` and a configured transcription provider. The source caption file provides the text and the transcription engine provides the precise timing. ```json { "job_type": "align", "source_profile": "SubRip Video Subtitle Script", "target_profile": "WebVTT", "media_path": "https://presigned-url-to/media.mp4", "transcribe_options": { "source_language": "en", "provider_id": "your-transcription-provider-id", "provider_options": { "model": "nova-2", "punctuate": true } } } ``` ### `translate` Translates the text of the source caption file into a target language using a configured translation Access Provider. Timing and formatting are preserved throughout the translation process. Closed Caption Converter handles caption-aware batching to preserve sentence context across event boundaries. ```json { "job_type": "translate", "source_profile": "SubRip Video Subtitle Script", "target_profile": "SubRip Video Subtitle Script", "translate_options": { "provider_id": "your-translation-provider-id", "source_language": "en", "target_language": "fr" } } ``` Language codes are passed directly to the translation service. Refer to your provider's documentation for supported language codes and dialects. ### `deliver` When `delivery_options` are included in a Job Description alongside another job type (such as `convert` or `transcribe`), the output file is automatically delivered to the specified storage or platform provider after processing is complete. The response still includes the standard `target` download URL, and additionally the file is written to the destination. ```json { "job_type": "convert", "source_profile": "SubRip Video Subtitle Script", "target_profile": "WebVTT", "delivery_options": { "provider_id": "your-s3-provider-id", "provider_options": { "bucket": "your-bucket-name", "region": "us-east-1", "key": "output/captions/episode01.vtt" } } } ``` --- ## Filter Configuration Filters are configured as nested objects within the Job Description. Each filter has an `enable` flag that must be set to `true` to activate it, along with its specific settings. ### Auto Format ```json "auto_format_options": { "enable": true, "max_lines": 2, "max_characters": 32, "min_duration": 1, "allow_orphan_words": false, "selective": true } ``` ### Automatic Reading Speed ```json "auto_correct_timing_options": { "enable": true, "max_cps": 25, "min_duration": 1, "max_duration": 12, "min_frame_gap": 2 } ``` ### Event Gap ```json "event_gap_options": { "enable": true, "frames": 2, "min_gap": 0, "max_gap": 6, "shot_change_aware": false, "shot_changes": [] } ``` ### Search & Replace The `searches` array contains one or more replacement rules: ```json "searches": [ { "find": "colour", "replace": "color", "regex": false, "caseSensitive": false } ] ``` ### Segmentation & Conform The `segments` array defines the regions to extract. Set `timecode_mode` to `"inclusive"` when the source system includes the last frame in its duration calculations; otherwise leave it at `"exclusive"` (the default). ```json "timecode_mode": "exclusive", "segments": [ { "incode": "01:00:00:00", "outcode": "01:15:00:00", "tcFormat": "smpte" } ] ``` ### Remove Forced Subtitles ```json "remove_forced_subs": { "enable": true, "remove": true } ``` Set `remove` to `true` to remove forced events, or `false` to keep only forced events and remove all others. ### Automatic QC Automatic QC is a list of tests in `qc.tests`. Each test has an `id`, a `level` (`critical`, `warn`, or `info`), a `threshold`, and its own parameters. The job's `qc_status` is set as follows: - `fail` if any critical test reaches its threshold; - `warn` if no critical test does, but a warning test does; - `pass` otherwise. See [Automatic QC Tests](https://www.closedcaptionconverter.com/docs/api/qc-tests) for the full test catalog, and [Filters — Automatic QC](https://www.closedcaptionconverter.com/docs/filters#automatic-qc) for the web UI. `qc.stage` controls when content tests run. Technical tests and `sequentialTiming` always inspect the source file. | `qc.stage` | Aliases | Content tests | |---|---|---| | `"pre"` (default) | `"pre-processing"` | Source captions, immediately after decode, at the source frame rate | | `"post"` | `"post-processing"` | Captions after filters and processing, immediately before encode, at the target frame rate | Values are case-insensitive. - **Which jobs:** convert, transcribe, translate, and align jobs can include a `qc` object. The report is returned as `qcReport`, along with `qc_status` and `qc_errors`, and does not change the encoded file. - **Align jobs** also attach alignment drift fields to the report. - **Transcribe jobs** skip technical and source-order tests because there is no caption source file. ```json "qc": { "stage": "pre", "tests": [ { "id": "maxCharsPerLine", "max": 42, "level": "critical", "threshold": 0 }, { "id": "maxLinesPerEvent", "max": 2, "level": "critical", "threshold": 0 }, { "id": "maxCps", "max": 20, "level": "critical", "threshold": 0 }, { "id": "minGap", "min": 2, "level": "critical", "threshold": 0 }, { "id": "frameGap", "min": 2, "minTolerance": 3, "maxTolerance": 11, "level": "warn", "threshold": 0 }, { "id": "overlap", "level": "critical", "threshold": 0 }, { "id": "sequentialTiming", "level": "critical", "threshold": 0 }, { "id": "illegalCharsNetflix", "level": "critical", "threshold": 0 }, { "id": "xmlEntities", "level": "critical", "threshold": 0 } ] } ``` The legacy `qc.content` / `qc.technical` format is still accepted and is converted to tests automatically. See [Legacy configuration](https://www.closedcaptionconverter.com/docs/api/qc-tests#legacy-configuration). ```json "qc": { "stage": "pre", "content": { "enabled": true, "maxChars": 42, "maxLines": 2, "maxCps": 20 }, "technical": { "enabled": false } } ``` --- # Example Job Description A complete Job Description with every option populated. ```json { "id": "f378dcc9-c731-4c3e-8dea-4ed7d5098873", "job_type": "convert", "custom_name": "Untitled", "delivery_options": { "provider_id": "", "provider_options": {} }, "transcribe_options": { "source_language": "", "provider_id": "", "provider_options": {} }, "translate_options": { "source_language": "", "target_language": "", "provider_id": "", "provider_options": {} }, "auto_format_options": { "enable": false, "max_lines": 2, "max_characters": 32, "min_duration": 1, "allow_orphan_words": false, "selective": true }, "auto_correct_timing_options": { "enable": false, "max_cps": 25, "min_duration": 1, "max_duration": 12, "min_frame_gap": 2 }, "event_gap_options": { "enable": false, "frames": 2, "min_gap": 0, "max_gap": 6, "shot_change_format": "seconds", "shot_changes": [], "shot_change_aware": false }, "remove_forced_subs": { "enable": false, "max_repeats": 5, "min_duration": 2, "remove": false }, "sources": [], "source": "", "target": "", "media_path": "", "audio_track": 0, "webhook": "", "reorderRtl": false, "source_profile": "ssPoliscript", "target_profile": "subRip", "source_extension": "srt", "target_extension": "srt", "encoding_options": [ { "name": "Encode Formatting", "type": "list", "values": [ true, false ], "selected": true }, { "name": "Encode Positioning", "type": "list", "values": [ true, false ], "selected": true } ], "decoding_options": [ { "name": "Code Page", "type": "list", "values": [ "auto", "ISO 8859-1 Latin", "ISO 8859-7 Greek", "ISO 8859-2 Latin Czech", "ISO 8859-6 Arabic", "ISO 8859-8 Hebrew", "ISO 8859-9 Turkish", "Windows-874 Thai", "ISO 8859-5 Cyrillic", "Big5 Traditional Chinese", "GBK Simplified Chinese", "Korean", "Japanese Shift-JIS" ], "selected": "auto" }, { "name": "Ignore Metadata", "type": "list", "values": [ true, false ], "selected": true } ], "default_frameRate": "29.97", "default_dropFrame": true, "source_frameRate": "auto", "source_dropFrame": "auto", "target_frameRate": "auto", "target_dropFrame": "auto", "source_encoding": "UTF-8", "target_encoding": "UTF-8", "tcMultiplier": 1, "timecode_format": "smpte", "timecode_reformat": "match", "fix_overlap": false, "merge_by_time": false, "convert_to_pop_on": false, "dropFrame_convert": false, "offset": "00:00:00:00", "offset_type": "add", "incode": "auto", "bom": false, "postScript": "", "eol": "auto", "xml_format": false, "embed_type": "none", "embed_language": "eng", "split_speakers_by_color": false, "remove_color": false, "speaker_prefix": "- ", "remove_formatting": false, "extract_from_source": false, "extract_from_source_profile": "mp4", "util": false, "partial": "00:00:00:00", "segments": [], "qc": { "stage": "pre", "tests": [ { "id": "maxCharsPerLine", "max": 42, "level": "critical", "threshold": 0 }, { "id": "maxLinesPerEvent", "max": 2, "level": "critical", "threshold": 0 }, { "id": "maxCps", "max": 20, "level": "critical", "threshold": 0 }, { "id": "minGap", "min": 2, "level": "critical", "threshold": 0 }, { "id": "frameGap", "min": 2, "minTolerance": 3, "maxTolerance": 11, "level": "warn", "threshold": 0 }, { "id": "overlap", "level": "critical", "threshold": 0 }, { "id": "sequentialTiming", "level": "critical", "threshold": 0 } ] }, "transcript": "", "transcript_profile": "", "position": [], "searches": [], "srcWindow": { "height": 15, "width": 32, "xPadding": 10, "yPadding": 10 }, "trgWindow": { "height": 15, "width": 32, "xPadding": 10, "yPadding": 10 } } ``` --- # Job Presets A Job Preset is a named Job Description stored in your Closed Caption Converter account. Instead of including the full JSON configuration in every API or CLI call, you can create a preset once and reference it by its assigned **Preset ID** in subsequent requests. Presets reduce the amount of code in your integration, prevent configuration drift between environments, and make it easy for teams to share standardised workflows. ## Creating a Preset Presets can be created in two ways: **From the Job Presets workspace** — open **Job Presets** in the left sidebar, click **+ New**, and enter the preset name, ID, description, and Job Configuration JSON. **From the Subtitle Converter** — configure your job exactly as you want it, open the **Backup Settings** section, and click **Save Preset**. You will be prompted for a preset name and preset ID before the configuration is stored. ## Managing Presets To review or edit an existing preset, open **Job Presets** from the left sidebar and update the **Preset Name**, **Preset ID**, **Preset Description**, or **Job Configuration** JSON. You can also copy a ready-to-use `{ "preset_id": "..." }` snippet from the table. Editing a preset changes the stored Job Description but does not affect any jobs that have already been submitted. Deleting a preset makes its ID invalid for future jobs but does not affect job history. Naming conventions are important when using many presets. A consistent naming scheme (for example, `[client]_[source-format]_to_[target-format]_[version]`) makes it easy to find the right preset without needing to inspect its contents. ## Using a Preset in the API To use a preset, pass the `preset_id` in your API request body instead of a `config` object: ```bash curl -X POST https://api.closedcaptionconverter.com/jobs \ -H "x-api-key: YOUR_API_KEY" \ -H "username: you@example.com" \ -F "source=@/path/to/input.srt" \ -F "preset_id=your-preset-id-here" ``` The server loads the stored Job Description and processes the file exactly as if you had submitted the full JSON. No additional configuration is required in the API call beyond the source file and the preset ID. You can load a preset into the [API Playground](https://www.closedcaptionconverter.com/docs/api-playground) using **Load Preset** before submitting a test job. ## Using a Preset in the CLI The CLI supports presets in the same way as the API. Pass the preset ID in the job configuration file: ```json { "preset_id": "your-preset-id-here" } ``` A network connection is required to resolve the preset from the server when using presets with the CLI. For fully offline environments, store the complete Job Description locally instead of using `preset_id`. ## Preset IDs in Code Preset IDs are UUID strings. Store them in your application's environment configuration or secrets manager rather than hardcoding them in source code. This makes it easy to swap presets between environments (development, staging, production) without changing application code. ```bash # Example: store as an environment variable CCCONVERTER_PRESET_SRT_TO_STL="abc12345-0000-0000-0000-000000000001" # Use it in a curl request curl -X POST https://api.closedcaptionconverter.com/jobs \ -H "x-api-key: YOUR_API_KEY" \ -H "username: you@example.com" \ -F "source=@/path/to/input.srt" \ -F "preset_id=$CCCONVERTER_PRESET_SRT_TO_STL" ```