# API and Job Submission This guide explains how to interact with the Encore REST API to submit transcoding jobs, monitor their progress, and manage job lifecycle. ## API Overview Encore provides a RESTful API built on Spring Data REST. The API is accessible at the base URL where your Encore instance is running (typically `http://localhost:8080` for local development). ### Interactive API Documentation Encore includes built-in Swagger UI documentation that provides an interactive interface for exploring and testing the API: - Access Swagger UI at: `http://your-encore-host:port/swagger-ui.html` - View the OpenAPI specification at: `http://your-encore-host:port/v3/api-docs` The Swagger interface allows you to view all available endpoints, see request/response schemas, and execute API calls directly from your browser. ### Authentication By default, Encore runs without authentication. If you have enabled security through the `ENCORE_SETTINGS_SECURITY_ENABLED` environment variable or configuration, you will need to provide appropriate credentials with your API requests. This is done with basic auth. Normally there are two users, 'USER' with readonly access and 'ADMIN' with full access. ## Submitting a Job ### Basic Job Submission To submit a transcoding job, send a POST request to `/encoreJobs` with a JSON payload describing the job. **Endpoint:** `POST /encoreJobs` **Content-Type:** `application/json` **Minimum Required Fields:** ```json { "profile": "your-profile-name", "outputFolder": "/path/to/output", "baseName": "output-filename", "inputs": [ { "type": "AudioVideo", "uri": "/path/to/input/file.mp4" } ] } ``` **Example with curl:** ```bash curl -X POST http://localhost:8080/encoreJobs \ -H "Content-Type: application/json" \ -d '{ "profile": "x264-high", "outputFolder": "/mnt/output/videos", "baseName": "my-video", "inputs": [ { "type": "AudioVideo", "uri": "/mnt/input/source.mp4" } ] }' ``` **Response:** The API returns the created job with its assigned ID and initial status: ```json { "id": "fb2baa17-8972-451b-bb1e-1bc773283476", "externalId": null, "profile": "x264-high", "outputFolder": "/mnt/output/videos", "baseName": "my-video", "status": "NEW", "progress": 0, "priority": 0, "createdDate": "2025-11-25T10:30:00.123456+01:00", "inputs": [ { "type": "AudioVideo", "uri": "/mnt/input/source.mp4", "params": {} } ], "_links": { "self": { "href": "http://localhost:8080/encoreJobs/fb2baa17-8972-451b-bb1e-1bc773283476" } } } ``` ## Job Fields Reference ### Required Fields These fields must be provided when creating a job: **profile** (string) - Name of the encoding profile to use for transcoding - Must match a profile configured in your Encore instance - See [Encoding Profiles](Encoding-profiles.md) for more information - Example: `"x264-high"`, `"hevc-4k"`, `"audio-aac"` **outputFolder** (string) - Directory path where output files will be written - Can be a local filesystem path (e.g., `/mnt/output/videos`) - Can be an S3 URL (e.g., `s3://my-bucket/videos/`) - See [Using Object Storage](Using-object-storage.md) for S3 configuration - The directory must be writable by the Encore process **baseName** (string) - Base filename for output files (without extension) - Output files will be named using this base plus suffixes from the profile - Example: baseName `"my-video"` might produce `"my-video_1080p.mp4"`, `"my-video_720p.mp4"` **inputs** (array of Input objects) - List of input files to process - At least one input is required - See [Input Types](#input-types) section below for detailed structure ### Optional Fields **externalId** (string, nullable) - Your own identifier for tracking this job in external systems - Encore does not use this value internally - Useful for correlating jobs with records in your application database - Example: `"user-upload-12345"` **profileParams** (object, nullable) - Key-value pairs for parameterizing SpEL expressions in your encoding profile - Allows dynamic customization of encoding settings per job - See [Profile Parametrization](Profile-parametrization.md) for details - Example: `{"targetBitrate": 5000000, "customFilter": "scale=1920:1080"}` **progressCallbackUri** (string, nullable) - URL where Encore will POST progress updates as the job encodes - Updates are sent periodically (approximately every 10 seconds during encoding) - Callback payload includes job ID, status, progress percentage, and speed - Example: `"https://myapp.example.com/api/encore-callback"` **priority** (integer, 0-100) - Queue priority for job scheduling (higher values = higher priority) - Default: `0` - Jobs with higher priority are processed before lower priority jobs in the same queue - All jobs at the same priority level are processed in FIFO order **segmentLength** (number, nullable) - Enable parallel segmented encoding by splitting the input into segments of this duration (in seconds) - Should be a multiple of your target GOP (Group of Pictures) size for best results - Improves throughput by processing segments in parallel across multiple workers - Example: `19.2` (for a 2-second GOP at 23.976fps: 48 frames / 2.5 = 19.2s) - See [Segmented Encoding](#segmented-encoding) section below **audioEncodingMode** (enum, nullable) - Controls how audio is handled during segmented encoding - Only relevant when `segmentLength` is specified - Values: - `ENCODE_WITH_VIDEO`: Audio and video encoded together in each segment (default) - `ENCODE_SEPARATELY_FULL`: Audio encoded as one full-length file, video segmented - `ENCODE_SEPARATELY_SEGMENTED`: Both audio and video segmented separately - Default: `ENCODE_WITH_VIDEO` **audioSegmentLength** (number, nullable) - Length of audio segments in seconds when using `ENCODE_SEPARATELY_SEGMENTED` mode - If not specified, Encore calculates an optimal value (typically close to 256 seconds) - Must be a multiple of the audio frame size - Example: `256.0` **seekTo** (number, nullable) - Start encoding at this position (in seconds) in the input file - Applied as an output seek (affects the final output, not input decoding) - For faster but less accurate seeking, use input-level `seekTo` instead - Example: `60.0` to skip the first minute **duration** (number, nullable) - Limit the output to this duration (in seconds) - Example: `120.0` to encode only 2 minutes of output **thumbnailTime** (number, nullable) - Extract thumbnail at this specific timestamp (in seconds) - Overrides any thumbnail time configured in the encoding profile - Example: `45.5` to capture a frame at 45.5 seconds **debugOverlay** (boolean) - When `true`, overlays encoding metadata on the video output - Useful for troubleshooting and verifying encoding settings - Default: `false` **logContext** (object) - Key-value pairs to add to the logging context (MDC) for this job - Useful for correlating log entries with external systems - Example: `{"userId": "user123", "department": "marketing"}` ### Read-Only Fields These fields are set by Encore and returned in API responses. You cannot set them when creating a job. **id** (UUID) - Unique identifier assigned to the job by Encore - Use this ID for all subsequent operations (GET, cancel, etc.) - Example: `"fb2baa17-8972-451b-bb1e-1bc773283476"` **status** (enum) - Current job status. Possible values: - `NEW`: Job created but not yet queued - `QUEUED`: Job waiting in queue for processing - `IN_PROGRESS`: Job currently being encoded - `SUCCESSFUL`: Job completed successfully - `FAILED`: Job failed with an error - `CANCELLED`: Job was cancelled **progress** (integer, 0-100) - Encoding progress percentage - Updates during IN_PROGRESS status - Always `0` for non-started jobs, `100` for completed jobs **speed** (number, nullable) - Current encoding speed relative to playback speed - Example: `2.5` means encoding at 2.5x realtime (1 hour of video encodes in 24 minutes) - Only available during IN_PROGRESS status **message** (string, nullable) - Error message if the job failed - Contains details about what went wrong - Only populated when status is FAILED **output** (array of MediaFile objects) - List of analyzed output files produced by the encoding - Includes technical metadata (codec, bitrate, resolution, duration, etc.) - Populated after successful completion **createdDate** (timestamp) - When the job was submitted - ISO 8601 format with timezone - Example: `"2025-11-25T10:30:00.123456+01:00"` **startedDate** (timestamp, nullable) - When the job started processing (changed from QUEUED to IN_PROGRESS) - `null` until the job starts **completedDate** (timestamp, nullable) - When the job completed (success, failure, or cancellation) - `null` until the job completes **segmentedEncodingInfo** (object, nullable) - Information about segmented encoding if applicable - Includes segment count, segment length, audio encoding mode, etc. - Only present when job uses segmented encoding ## Input Types Each job requires one or more inputs in the `inputs` array. Inputs can be audio-only, video-only, or combined audio/video files. ### AudioVideo Input For files containing both audio and video streams: ```json { "type": "AudioVideo", "uri": "/path/to/file.mp4", "videoLabel": "main", "audioLabel": "main", "videoFilters": [], "audioFilters": [], "dar": null, "cropTo": null, "padTo": null, "params": {}, "seekTo": null, "copyTs": false, "videoStream": null, "audioStream": null, "channelLayout": null, "probeInterlaced": true } ``` **Common Fields (all input types):** - `type`: Input type (`"AudioVideo"`, `"Video"`, or `"Audio"`) - `uri`: File path or URL to the input file (required) - `params`: FFmpeg input parameters as key-value pairs (e.g., `{"ac": "2"}` for 2 audio channels) - `seekTo`: Seek to position in seconds before decoding (faster than job-level seekTo but may be less accurate) - `copyTs`: Preserve timestamps when seeking (default: `false`) **Video-Specific Fields:** - `videoLabel`: Label to match with profile outputs (default: `"main"`) - `videoFilters`: List of FFmpeg video filters to apply (e.g., `["scale=1920:1080"]`) - `dar`: Override display aspect ratio (e.g., `"16:9"`) for anamorphic video or corrupt metadata - `cropTo`: Crop video to aspect ratio (e.g., `"1:1"` for square video) - `padTo`: Pad video to aspect ratio (e.g., `"16:9"`) - `videoStream`: Index of video stream to use (for multi-stream files) - `probeInterlaced`: Probe for interlaced content (default: `true`) **Audio-Specific Fields:** - `audioLabel`: Label to match with profile outputs (default: `"main"`) - `audioFilters`: List of FFmpeg audio filters to apply - `audioStream`: Index of audio stream to use (for multi-stream files) - `channelLayout`: Channel layout hint for mono inputs (e.g., `"5.1"`) ### Video Input For video-only files (no audio): ```json { "type": "Video", "uri": "/path/to/video.mov", "videoLabel": "main", "videoFilters": [], "dar": null, "cropTo": null, "padTo": null, "params": {}, "seekTo": null, "copyTs": false, "videoStream": null, "probeInterlaced": true } ``` ### Audio Input For audio-only files: ```json { "type": "Audio", "uri": "/path/to/audio.wav", "audioLabel": "main", "audioFilters": [], "params": {}, "seekTo": null, "copyTs": false, "audioStream": null, "channelLayout": null } ``` ### Multiple Inputs You can provide multiple inputs with different labels to create outputs from different sources. This is useful for scenarios like: - Adding a sign language video overlay (separate video input with label `"sign"`) - Encoding multiple audio languages (separate audio inputs with labels `"eng"`, `"spa"`, etc.) - Compositing multiple video sources Example with multiple inputs: ```json { "profile": "multi-audio-profile", "outputFolder": "/output", "baseName": "multilang-video", "inputs": [ { "type": "AudioVideo", "uri": "/input/main.mp4", "videoLabel": "main", "audioLabel": "english" }, { "type": "Audio", "uri": "/input/spanish-dub.wav", "audioLabel": "spanish" } ] } ``` Your encoding profile must reference these labels in its output configurations. ## Querying Jobs ### Get a Specific Job Retrieve a job by its ID: **Endpoint:** `GET /encoreJobs/{id}` ```bash curl http://localhost:8080/encoreJobs/fb2baa17-8972-451b-bb1e-1bc773283476 ``` ### List All Jobs List all jobs with pagination: **Endpoint:** `GET /encoreJobs` **Query Parameters:** - `page`: Page number (0-indexed, default: 0) - `size`: Number of items per page (default: 20) - `sort`: Sort field and direction (e.g., `createdDate,desc`) ```bash # Get first page (20 jobs) curl http://localhost:8080/encoreJobs # Get second page with 50 jobs per page, sorted by creation date descending curl "http://localhost:8080/encoreJobs?page=1&size=50&sort=createdDate,desc" ``` **Response:** ```json { "_embedded": { "encoreJobs": [ { "id": "job-uuid-1", "profile": "x264-high", "status": "SUCCESSFUL", ... }, { "id": "job-uuid-2", "profile": "hevc-4k", "status": "IN_PROGRESS", ... } ] }, "page": { "size": 20, "totalElements": 150, "totalPages": 8, "number": 0 } } ``` ### Find Jobs by Status Filter jobs by their status: **Endpoint:** `GET /encoreJobs/search/findByStatus` **Query Parameters:** - `status`: Status value (`NEW`, `QUEUED`, `IN_PROGRESS`, `SUCCESSFUL`, `FAILED`, `CANCELLED`) - `page`, `size`, `sort`: Pagination parameters (same as list all) ```bash # Find all jobs currently in progress curl "http://localhost:8080/encoreJobs/search/findByStatus?status=IN_PROGRESS" # Find all failed jobs, sorted by completion date curl "http://localhost:8080/encoreJobs/search/findByStatus?status=FAILED&sort=completedDate,desc" ``` ## Monitoring Progress ### Polling You can poll a job's status by repeatedly calling `GET /encoreJobs/{id}` to check the `status` and `progress` fields. Example polling script (bash): ```bash #!/bin/bash JOB_ID="fb2baa17-8972-451b-bb1e-1bc773283476" while true; do RESPONSE=$(curl -s http://localhost:8080/encoreJobs/$JOB_ID) STATUS=$(echo $RESPONSE | jq -r '.status') PROGRESS=$(echo $RESPONSE | jq -r '.progress') echo "Status: $STATUS, Progress: $PROGRESS%" if [[ "$STATUS" == "SUCCESSFUL" || "$STATUS" == "FAILED" || "$STATUS" == "CANCELLED" ]]; then echo "Job finished with status: $STATUS" break fi sleep 5 done ``` ### Progress Callbacks For real-time progress updates, specify a `progressCallbackUri` when creating the job. Encore will POST updates to this URL as encoding progresses. **Callback Payload:** ```json { "id": "fb2baa17-8972-451b-bb1e-1bc773283476", "status": "IN_PROGRESS", "progress": 57, "speed": 2.3, "message": null } ``` Callbacks are sent: - When status changes (e.g., NEW to QUEUED, QUEUED to IN_PROGRESS) - Periodically during encoding (approximately every 10 seconds) - When the job completes (success, failure, or cancellation) ## Cancelling Jobs Cancel a running or queued job: **Endpoint:** `POST /encoreJobs/{id}/cancel` ```bash curl -X POST http://localhost:8080/encoreJobs/fb2baa17-8972-451b-bb1e-1bc773283476/cancel ``` **Response:** - `200 OK` with body `"Ok"` if cancellation was successful - `409 Conflict` if the job cannot be cancelled (already completed) - `404 Not Found` if the job doesn't exist Jobs can be cancelled when in `NEW`, `QUEUED`, or `IN_PROGRESS` status. Jobs that are already `SUCCESSFUL`, `FAILED`, or `CANCELLED` cannot be cancelled. When cancelling an in-progress job, Encore sends a cancellation signal to the encoding process. The job status will change to `CANCELLED` once the encoder has stopped. ## Queue Status View the current state of the encoding queues: **Endpoint:** `GET /queue` ```bash curl http://localhost:8080/queue ``` **Response:** ```json [ { "name": "queue:0", "size": 5, "inProgress": 2 }, { "name": "queue:1", "size": 3, "inProgress": 1 } ] ``` This shows how many jobs are waiting in each queue and how many are currently being processed. ## Advanced Operations ### Updating a Job Spring Data REST provides PATCH and PUT endpoints for updating jobs, but in practice you should rarely need to modify jobs after creation. Most fields are either immutable by design or managed automatically by Encore. **Not recommended:** Manually changing job status or progress fields can cause inconsistencies with the queue system. ### Deleting a Job You can delete a job record from Redis: **Endpoint:** `DELETE /encoreJobs/{id}` ```bash curl -X DELETE http://localhost:8080/encoreJobs/fb2baa17-8972-451b-bb1e-1bc773283476 ``` Note that deleting a job does not cancel it if it's currently running. Always cancel a job first if needed, then delete the record. Jobs are automatically deleted from Redis after 1 week (TTL) to prevent unbounded storage growth. ## Practical Examples ### Example 1: Simple Single-Output Encode Transcode a video to H.264 with a simple profile: ```bash curl -X POST http://localhost:8080/encoreJobs \ -H "Content-Type: application/json" \ -d '{ "profile": "x264-standard", "outputFolder": "/mnt/output", "baseName": "my-video", "inputs": [ { "type": "AudioVideo", "uri": "/mnt/input/source.mov" } ] }' ``` ### Example 2: Encode with External Tracking Submit a job with an external ID and progress callback: ```bash curl -X POST http://localhost:8080/encoreJobs \ -H "Content-Type: application/json" \ -d '{ "externalId": "user-upload-789", "profile": "h264-720p", "outputFolder": "/mnt/output/user-videos", "baseName": "user789-video", "progressCallbackUri": "https://myapp.example.com/api/encore-progress", "inputs": [ { "type": "AudioVideo", "uri": "/mnt/input/user-upload.mp4" } ] }' ``` ### Example 3: Segmented Encoding for Large File Use segmented encoding to parallelize processing of a long video: ```bash curl -X POST http://localhost:8080/encoreJobs \ -H "Content-Type: application/json" \ -d '{ "profile": "x264-high", "outputFolder": "/mnt/output", "baseName": "long-video", "segmentLength": 19.2, "audioEncodingMode": "ENCODE_SEPARATELY_FULL", "inputs": [ { "type": "AudioVideo", "uri": "/mnt/input/long-source.mxf" } ] }' ``` ### Example 4: Encode with S3 Input and Output Process a file from S3 and write outputs back to S3: ```bash curl -X POST http://localhost:8080/encoreJobs \ -H "Content-Type: application/json" \ -d '{ "profile": "adaptive-bitrate-ladder", "outputFolder": "s3://my-video-bucket/outputs/", "baseName": "video-abc123", "inputs": [ { "type": "AudioVideo", "uri": "s3://my-video-bucket/uploads/source.mp4" } ] }' ``` See [Using Object Storage](Using-object-storage.md) for S3 setup details. ### Example 5: Profile Parametrization Customize encoding parameters dynamically: ```bash curl -X POST http://localhost:8080/encoreJobs \ -H "Content-Type: application/json" \ -d '{ "profile": "parameterized-profile", "outputFolder": "/mnt/output", "baseName": "custom-encode", "profileParams": { "targetWidth": 1920, "targetHeight": 1080, "targetBitrate": 8000000, "watermarkText": "PREVIEW" }, "inputs": [ { "type": "AudioVideo", "uri": "/mnt/input/source.mp4" } ] }' ``` See [Profile Parametrization](Profile-parametrization.md) for how to set up profiles that accept parameters. ### Example 6: Extract a Clip with Seek and Duration Encode only a portion of the input: ```bash curl -X POST http://localhost:8080/encoreJobs \ -H "Content-Type: application/json" \ -d '{ "profile": "h264-1080p", "outputFolder": "/mnt/output/clips", "baseName": "clip", "seekTo": 120.0, "duration": 30.0, "inputs": [ { "type": "AudioVideo", "uri": "/mnt/input/full-video.mp4" } ] }' ``` This will encode a 30-second clip starting at 2 minutes into the source. ### Example 7: High Priority Job Submit a job with elevated priority to jump the queue: ```bash curl -X POST http://localhost:8080/encoreJobs \ -H "Content-Type: application/json" \ -d '{ "profile": "x264-fast", "outputFolder": "/mnt/output", "baseName": "urgent-video", "priority": 90, "inputs": [ { "type": "AudioVideo", "uri": "/mnt/input/urgent.mp4" } ] }' ``` ## Segmented Encoding Segmented encoding improves transcoding throughput by splitting long videos into smaller segments that can be processed in parallel across multiple workers. This is particularly beneficial for: - Long-form content (movies, TV shows, live event recordings) - Distributed encoding environments with multiple worker nodes - High-priority jobs that need faster turnaround ### How It Works When you specify `segmentLength`, Encore: 1. Analyzes the input to determine total duration 2. Divides the input into segments of approximately `segmentLength` seconds each 3. Creates encoding tasks for each segment 4. Distributes tasks across available workers (or processes them sequentially if only one worker) 5. Concatenates the completed segments into final output files ### Choosing Segment Length The segment length should be a multiple of your target GOP (Group of Pictures) size to ensure clean segment boundaries without encoding artifacts. **Formula:** `segmentLength = (GOP_size_in_frames / frame_rate) * N` **Example:** For 23.976 fps video with a 2-second GOP (48 frames): - 1x GOP: `48 / 23.976 = 2.0` seconds - 10x GOP: `19.2` seconds (recommended) - 20x GOP: `38.4` seconds Longer segments mean fewer tasks (less overhead) but less parallelization. Shorter segments mean more parallelization but more overhead from task management and concatenation. **Recommended range:** 15-30 seconds for most content ### Audio Encoding Modes When using segmented encoding, you can control how audio is processed: **ENCODE_WITH_VIDEO** (default) - Audio and video encoded together in each segment - Simplest mode with fewest tasks - Good for most use cases **ENCODE_SEPARATELY_FULL** - Audio encoded once as a full-length file - Video segmented and processed in parallel - Useful when audio encoding is fast compared to video - Reduces total tasks compared to segmenting both **ENCODE_SEPARATELY_SEGMENTED** - Both audio and video segmented independently - Maximum parallelization - Audio segments use longer duration (typically ~256s) to reduce overhead - Best for very long content or when audio processing is complex ### Configuration Requirements To use segmented encoding, your Encore deployment must have: 1. A shared work directory configured (`encore-settings.shared-work-dir`) 2. All workers with access to this shared directory (local filesystem or network mount) 3. Multiple workers for parallel processing (optional but recommended) See your Encore deployment documentation for shared storage configuration. ## Troubleshooting ### Job Stays in NEW Status If a job remains in `NEW` status, check that: - Encore web application is running - Redis is accessible and healthy - Queue pollers are active (check logs) ### Job Fails Immediately Check the `message` field in the job response for error details. Common causes: - Invalid profile name - Input file not accessible - Output directory not writable or doesn't exist - Malformed input file (corrupt, unsupported codec, etc.) ### Progress Callbacks Not Received Verify that: - The `progressCallbackUri` is accessible from the Encore server - Your callback endpoint accepts POST requests with JSON payload - Firewall rules allow outbound connections from Encore - The callback endpoint URL is correct and returns 2xx status codes ### Segmented Encoding Fails For segmented encoding issues: - Verify `sharedWorkDir` is configured and writable - Check that all workers can access the shared directory - Ensure segment length is reasonable (not too short, not longer than input duration) - Review worker logs for concatenation errors ## Related Documentation - [Encoding Profiles](Encoding-profiles.md) - Learn how to create and configure encoding profiles - [Profile Parametrization](Profile-parametrization.md) - Use SpEL expressions for dynamic profile configuration - [Using Object Storage](Using-object-storage.md) - Configure S3 for input and output files