Search Documentation
Search across all documentation pages
Delayed Jobs

Overview

By default, transcoding jobs start encoding immediately after the input file is probed. The delayed start workflow adds a confirmation step: the job pauses after probing, gives you the estimated cost, and waits for explicit confirmation before proceeding.

This is useful when you need to:

  • Show end users the transcoding cost before charging them
  • Implement approval workflows for expensive jobs
  • Validate estimated costs against a budget before committing
  • Let users review input metadata (duration, resolution, codecs) before encoding

How It Works

The delayed job workflow has three phases:

Create (delayed_start: true)
  |
  v
Pending --> Probing --> Awaiting Confirmation
                              |
                      [Review estimated cost]
                              |
                 +------------+------------+
                 |                         |
              Confirm                   Cancel
                 |                         |
                 v                         v
            Processing              Canceled
                 |
                 v
            Completed
  1. Create — Submit the job with delayed_start: true. Status is pending.
  2. Probe — Transcodely analyzes the input file to determine duration, resolution, and codec information. Status moves to probing, then awaiting_confirmation.
  3. Confirm or Cancel — Review the estimated cost and either confirm the job to start encoding, or cancel it to avoid charges.

Step 1: Create a Delayed Job

Set delayed_start to true in your create request:

curl -X POST https://api.transcodely.com/transcodely.v1.JobService/Create 
  -H "Content-Type: application/json" 
  -H "Authorization: Bearer {{API_KEY}}" 
  -H "X-Organization-ID: {{ORG_ID}}" 
  -d '{
    "input_origin_id": "ori_input12345",
    "input_path": "uploads/my-video.mp4",
    "output_origin_id": "ori_output6789",
    "delayed_start": true,
    "outputs": [
      {
        "type": "mp4",
        "video": [{ "codec": "h264", "resolution": "1080p", "quality": "standard" }]
      },
      {
        "type": "hls",
        "video": [
          { "codec": "h264", "resolution": "1080p", "quality": "standard" },
          { "codec": "h264", "resolution": "720p", "quality": "standard" },
          { "codec": "h264", "resolution": "480p", "quality": "economy" }
        ]
      }
    ],
    "webhook_url": "https://yourapp.com/webhooks/transcodely"
  }'

The response confirms the job was created with delayed_start enabled:

{
  "job": {
    "id": "job_a1b2c3d4e5f6",
    "status": "pending",
    "delayed_start": true,
    "outputs": [
      { "id": "out_mp4_001", "status": "pending", "progress": 0 },
      { "id": "out_hls_002", "status": "pending", "progress": 0 }
    ],
    "metadata": {},
    "created_at": "2026-02-28T10:30:00Z"
  }
}

Step 2: Wait for Probing to Complete

The job automatically transitions through probing to awaiting_confirmation. You can poll the job status or use webhooks to be notified.

Polling

curl -X POST https://api.transcodely.com/transcodely.v1.JobService/Get 
  -H "Content-Type: application/json" 
  -H "Authorization: Bearer {{API_KEY}}" 
  -H "X-Organization-ID: {{ORG_ID}}" 
  -d '{ "id": "job_a1b2c3d4e5f6" }'

When the status is awaiting_confirmation, the response includes estimated costs and input metadata:

{
  "job": {
    "id": "job_a1b2c3d4e5f6",
    "status": "awaiting_confirmation",
    "delayed_start": true,
    "total_estimated_cost": 0.3455,
    "currency": "EUR",
    "input_metadata": {
      "duration_seconds": 120,
      "width": 1920,
      "height": 1080,
      "framerate": 30.0,
      "video_codec": "h264",
      "audio_codec": "aac",
      "file_size_bytes": 52428800
    },
    "outputs": [
      {
        "id": "out_mp4_001",
        "status": "pending",
        "estimated_cost": 0.12
      },
      {
        "id": "out_hls_002",
        "status": "pending",
        "estimated_cost": 0.2255,
        "variant_pricing": [
          { "index": 0, "resolution": "1080p", "estimated_cost": 0.106 },
          { "index": 1, "resolution": "720p", "estimated_cost": 0.0795 },
          { "index": 2, "resolution": "480p", "estimated_cost": 0.04 }
        ]
      }
    ],
    "probed_at": "2026-02-28T10:30:15Z"
  }
}

Using Watch for Real-Time Updates

Instead of polling, you can use the Watch RPC to stream status updates:

const stream = jobClient.watch({ id: "job_a1b2c3d4e5f6" });

for await (const response of stream) {
  if (response.job?.status === "awaiting_confirmation") {
    console.warn("Estimated cost:", response.job.totalEstimatedCost);
    // Show cost to user, prompt for confirmation
    break;
  }
}

Step 3: Review the Estimate

Before confirming, review the cost breakdown:

FieldDescription
total_estimated_costSum of all output estimated costs
currencyISO 4217 currency code (e.g., EUR)
outputs[].estimated_costPer-output cost
outputs[].variant_pricing[]Per-variant cost breakdown (for ABR outputs)
input_metadataSource file properties (duration, resolution, codecs)

Estimated costs are calculated using locked pricing snapshots captured at job creation time. This means the price will not change between creation and confirmation, even if Transcodely updates its pricing in the interim.


Step 4: Confirm or Cancel

Confirm the Job

To proceed with encoding:

curl -X POST https://api.transcodely.com/transcodely.v1.JobService/Confirm 
  -H "Content-Type: application/json" 
  -H "Authorization: Bearer {{API_KEY}}" 
  -H "X-Organization-ID: {{ORG_ID}}" 
  -d '{ "id": "job_a1b2c3d4e5f6" }'

The job status transitions to processing and encoding begins:

{
  "job": {
    "id": "job_a1b2c3d4e5f6",
    "status": "processing",
    "delayed_start": true,
    "confirmed_at": "2026-02-28T10:31:00Z"
  }
}

Cancel the Job

If the estimated cost is too high or the input is not what was expected, cancel the job:

curl -X POST https://api.transcodely.com/transcodely.v1.JobService/Cancel 
  -H "Content-Type: application/json" 
  -H "Authorization: Bearer {{API_KEY}}" 
  -H "X-Organization-ID: {{ORG_ID}}" 
  -d '{ "id": "job_a1b2c3d4e5f6" }'

Canceled jobs incur no encoding charges. The only cost is the brief probing phase.


Implementation Example

Here is a typical integration pattern for delayed jobs in a web application:

import { createOrgApiClient } from "$lib/api/client";
import { JobService } from "$lib/gen/transcodely/v1/job_connect";

const jobClient = createOrgApiClient(JobService);

// 1. Create the delayed job
const { job } = await jobClient.create({
  inputOriginId: "ori_input12345",
  inputPath: "uploads/my-video.mp4",
  outputOriginId: "ori_output6789",
  delayedStart: true,
  outputs: [
    {
      type: "mp4",
      video: [{ codec: "h264", resolution: "1080p", quality: "standard" }],
    },
  ],
});

// 2. Poll until awaiting confirmation
let current = job;
while (current.status !== "awaiting_confirmation") {
  await new Promise((resolve) => setTimeout(resolve, 2000));
  const response = await jobClient.get({ id: current.id });
  current = response.job;
}

// 3. Show cost to user and get approval
const approved = await showCostApprovalDialog(current.totalEstimatedCost, current.currency);

// 4. Confirm or cancel
if (approved) {
  await jobClient.confirm({ id: current.id });
} else {
  await jobClient.cancel({ id: current.id });
}

When to Use Delayed Jobs

ScenarioRecommended
User-uploaded content with pay-per-use billingYes
Internal batch processing with fixed budgetsYes
Automated pipelines with predictable inputsNo, use immediate start
Preview generation for quick feedbackNo, use immediate start
High-value content requiring cost approvalYes