Jobs

Jobs describe desired media output; attempts describe individual executions. Submission creates both identities and an initial fencing token while clients provide only the stable execution-plan template.

Submit a job

Validates an execution-plan template and queues a new transcoding job.

POST
/api/v1/operations/jobs201

Parameters

NameInTypeDescription
projectIdrequiredbodyUUIDProject receiving the job; the Manager derives its organization.
prioritybodyinteger (-1000..1000)Higher values are scheduled first.Default: 0
requirements.requiredCapabilitiesbodystring[]Encoder, decoder, filter, or hardware capability names.Default: []
executionPlanrequiredbodyExecutionPlanTemplateStable plan without server-generated identity or fencing fields.
The Manager generates jobId, attemptId, fencingToken, and protocol version.
Request
curl --request POST http://localhost:4400/api/v1/operations/jobs \
  --header 'authorization: Bearer ADMIN_ACCESS_TOKEN' \
  --header 'content-type: application/json' \
  --data '{
    "projectId": "c16e77c7-27d3-4b6b-9d93-4bd57b7d0d4d",
    "priority": 10,
    "requirements": { "requiredCapabilities": ["libx264", "aac"] },
    "executionPlan": {
      "input": { "uri": "s3://media/input/source.mp4" },
      "outputs": [{
        "id": "main",
        "kind": "FILE",
        "container": "mp4",
        "destinationUri": "s3://media/output/video.mp4",
        "video": { "codec": "libx264", "height": 720, "preset": "medium" },
        "audio": { "codec": "aac", "bitrateKbps": 128 }
      }],
      "transforms": { "removedSegments": [], "subtitles": [], "audioTracks": [] },
      "workspace": { "rootDirectory": "/var/lib/encode-flow/work" },
      "manifestUri": "s3://media/output/manifest.json"
    }
  }'
Response excerpt
{
  "id": "6f74a1d4-f7cd-4dca-94dc-e906d2bd93f6",
  "organizationId": "5b0c2f11-3f78-4d89-9df1-07a69c2f6c7e",
  "projectId": "c16e77c7-27d3-4b6b-9d93-4bd57b7d0d4d",
  "state": "QUEUED",
  "priority": 10,
  "workerPool": "cpu",
  "requirements": { "requiredCapabilities": ["libx264", "aac"] },
  "currentAttemptId": "bf7dd6b5-7aa7-49dc-92fe-6f0ae4366052",
  "currentAttempt": { "state": "CREATED", "progress": 0 },
  "queuedAt": "2026-09-10T09:00:00.000Z",
  "startedAt": null,
  "completedAt": null,
  "createdAt": "2026-09-10T09:00:00.000Z",
  "updatedAt": "2026-09-10T09:00:00.000Z"
}

Possible errors

400The body or execution plan is invalid.
500An unexpected persistence or dependency failure occurred.

List jobs

Returns a filtered, offset-paginated set of job summaries.

GET
/api/v1/operations/jobs200

Parameters

NameInTypeDescription
statequeryJobStateMatch one state; mutually exclusive with states.
statesqueryJobState[]Comma-separated or repeated states.
workerPoolquerycpu | nvidia | intel | amdMatch the selected worker pool.
limitqueryinteger (1..100)Maximum records to return.Default: 50
offsetqueryinteger (0..100000)Records to skip.Default: 0
Request
curl --header 'authorization: Bearer ADMIN_ACCESS_TOKEN' \
  'http://localhost:4400/api/v1/operations/jobs?states=QUEUED,RUNNING&limit=25'
Response excerpt
{
  "items": [{
    "id": "6f74a1d4-f7cd-4dca-94dc-e906d2bd93f6",
    "organizationId": "5b0c2f11-3f78-4d89-9df1-07a69c2f6c7e",
    "projectId": "c16e77c7-27d3-4b6b-9d93-4bd57b7d0d4d",
    "state": "QUEUED",
    "priority": 10,
    "workerPool": "cpu",
    "requirements": { "requiredCapabilities": ["libx264", "aac"] },
    "currentAttemptId": "bf7dd6b5-7aa7-49dc-92fe-6f0ae4366052",
    "currentAttempt": { "state": "CREATED", "progress": 0 },
    "queuedAt": "2026-09-10T09:00:00.000Z",
    "startedAt": null,
    "completedAt": null,
    "createdAt": "2026-09-10T09:00:00.000Z",
    "updatedAt": "2026-09-10T09:00:00.000Z"
  }],
  "total": 1,
  "limit": 25,
  "offset": 0
}

Possible errors

400A filter or pagination value is invalid.

Get a job

Returns the execution plan, every attempt, and current live progress.

GET
/api/v1/operations/jobs/:jobId200

Parameters

NameInTypeDescription
jobIdrequiredpathUUIDJob identifier returned at submission.
Request
curl --header 'authorization: Bearer ADMIN_ACCESS_TOKEN' http://localhost:4400/api/v1/operations/jobs/JOB_UUID
Response excerpt
{
  "id": "6f74a1d4-f7cd-4dca-94dc-e906d2bd93f6",
  "state": "RUNNING",
  "currentAttemptId": "bf7dd6b5-7aa7-49dc-92fe-6f0ae4366052",
  "executionPlan": {
    "input": { "uri": "s3://media/input/source.mp4" },
    "outputs": [{
      "id": "main",
      "kind": "FILE",
      "container": "mp4",
      "destinationUri": "s3://media/output/video.mp4",
      "video": { "codec": "libx264" }
    }]
  },
  "attempts": [{ "attemptNumber": 1, "state": "RUNNING", "progress": 42.5 }]
}

Possible errors

400jobId is not a UUID.
404No job exists with this identifier.

Cancel a job

Cancels queued work immediately or requests cancellation from its worker.

POST
/api/v1/operations/jobs/:jobId/cancel202

Parameters

NameInTypeDescription
jobIdrequiredpathUUIDJob to cancel.
For active work, the final CANCELLED state arrives asynchronously.
Request
curl --request POST --header 'authorization: Bearer ADMIN_ACCESS_TOKEN' http://localhost:4400/api/v1/operations/jobs/JOB_UUID/cancel
Response excerpt
{
  "id": "JOB_UUID",
  "state": "CANCEL_REQUESTED",
  "currentAttemptId": "ATTEMPT_UUID",
  "attempts": [{ "state": "RUNNING", "progress": 42.5 }]
}

Possible errors

400jobId is not a UUID.
404The job does not exist.
409The job is already COMPLETED or FAILED.

Filtering behavior

Use state for one state or states for a comma-separated or repeated list. Sending both is a validation error. workerPool accepts cpu, nvidia, intel, or amd.

Job summaries include the current attempt. Details include every attempt and the execution plan. Live progress may be null until the current Worker publishes an update.

Idempotency

The submission endpoint does not currently accept an idempotency key. A client that cannot determine whether a request succeeded must avoid automatically creating another job without reconciling through its own application records.

Resume output uploads

A job in WAITING_FOR_STORAGE retains completed output files on its original Worker for up to 24 hours from its first storage pause, subject to the job deadline. After correcting storage credentials or access, request POST /api/v1/operations/jobs/:jobId/resume-uploads. Tenant clients use POST /api/v1/projects/:projectId/jobs/:jobId/resume-uploads. Both return 202 and the updated job detail.

Resume keeps the attempt and destination. It can wait for the original Worker to return or have capacity. It does not renew retention or redirect artifacts to a changed bucket or endpoint. A 409 indicates that the job or attempt is not waiting for storage, retention or the job deadline expired, the original Worker is missing or disabled, or its configured destination changed. A full retry of a failed job creates another attempt and repeats encoding.

Attempt details expose recovery counts for encoding and uploads, plus uploadPausedAt, uploadPauseExpiresAt, and uploadResumeRequestedAt. Local paths, multipart identifiers, and storage credentials remain internal.