---
title: "Get a transcode"
method: GET
path: "/v1/transcodes/{id}"
---

# Get a transcode

`GET /v1/transcodes/{id}`

## Request

- Base URL: `https://api.ffmpeg-micro.com`
- URL: `https://api.ffmpeg-micro.com/v1/transcodes/{id}`
- Auth: HTTP bearer

## Path parameters

- `id` string, uuid, required

## Response `200`

OK

- Transcode
  - `id` string, uuid, required
  - `status` 'pending' | 'processing' | 'completed' | 'failed' | 'canceled', required: Job lifecycle: `pending` (created, awaiting pickup) → `processing` → `completed` | `failed`; a user cancellation sets `canceled` (US spelling). Note there is no `queued` status — new jobs start as `pending`.
  - `inputs` object[]: Array of processed input metadata, populated at enqueue from the media probe.
    - `url` string: GCS URL of the (possibly re-hosted) input
    - `filename` string
    - `duration` number: Seconds; 0 for still images
    - `format` string
    - `size_bytes` union: File size in bytes, as a decimal string the way the media probe reports it (`"991017"`; `"0"` when the probe gave no size). Older jobs may carry an integer. Parse it as a number before doing arithmetic.
      - integer
      - string
    - `downloadUrl` string: Short-lived signed HTTPS URL for the input
    - `options` object[]: Per-input FFmpeg options as submitted
  - `outputs` object[]: Output file records, populated on completion
    - `url` string: gs:// URL of the output file
    - `filename` string
    - `size_bytes` integer
    - `format` string
  - `output_format` string, required: Output format as submitted — the value is stored verbatim, so a job created with `jpg` or `MP4` reads back exactly that way (validation is case/alias-insensitive; canonical values are mp4, webm, mov, avi, mp3, m4a, aac, wav, ogg, opus, flac, jpeg, png, gif, webp). Rows with `job_type: transcribe` carry `srt`.
  - `job_type` 'transcode' | 'transcribe': Discriminator — transcode and transcribe jobs share this resource shape and both appear in `GET /v1/transcodes` listings (there is no job_type filter). Transcribe rows additionally carry `media_url`.
  - `billable_minutes` number: Billable minutes, metered per second on input duration (a 19-second job bills 0.3167). Not an integer.
  - `duration_seconds` number: While the job is pending/processing: the billable input span (sum of input durations after trim options such as `-ss`/`-t`). Once completed: replaced by the measured duration of the OUTPUT file, which can differ from the input span (e.g. loops run longer). Billing always uses the input-side value.
  - `processing_time_seconds` number, nullable: Wall-clock processing time measured by the toolkit; null until completed
  - `queue_position` integer, nullable: Jobs waiting in the job's toolkit lane at acceptance, this one included: the accepting worker's queue length right after this job was enqueued, so 1 means it was next in line. Set once at acceptance and never updated: a rough "how far back was I", not a live counter. Once `started_at` is set the job is no longer waiting, whatever this says. Null on jobs accepted before the field existed, or when the toolkit's accept response carried no queue length.
  - `lane` 'short' | 'long' | 'heavy' | 'null', nullable: The processing lane the job runs in. Jobs with many large inputs (more than five 4K frames' worth of pixels in total) go to `heavy`, a service with more memory. Otherwise, inputs longer than two minutes (by probed length or requested output span) go to `long`; everything else is `short`. Each lane is a separate service, so nothing in one can delay a job in another. Null on jobs accepted before lanes existed.
  - `started_at` string, date-time, nullable: When the toolkit began executing the job. Set as soon as encoding starts, so null means the job is still waiting in its lane and non-null with status `processing` means it is encoding now. If that start signal was missed, it is filled from the completion or failure report. `started_at - created_at` is submission-to-start and includes the gateway's own download and probe before dispatch, so it is an upper bound on queue wait, not the wait itself.
  - `error_message` string, nullable: Populated when status is `failed`, and also on user cancellation (`canceled` jobs carry "Job canceled by user") — do not treat non-null error_message alone as job failure.
  - `error_category` 'processing_limit' | 'file_size' | 'quota' | 'upload' | 'storage' | 'validation' | 'processing' | 'transient' | 'unknown': Machine classification derived from error_message (generated column). Only meaningful when status is `failed`; jobs with no error carry `unknown`, never null. `processing_limit` is reserved for a job stopped at a per-job processing ceiling; no deployed release emits it yet (the ceiling ships separately).
  - `completed_at` string, date-time, nullable: Set on successful completion only — failed jobs keep this null
  - `metadata` object: Job metadata object. Caller-supplied metadata from the create request is echoed under `metadata.user` (JSON object, max 8 KB serialized). The object also carries internal keys written by the service (e.g. preset details, request origin, download token for the anonymous "Try It" flow) — treat keys other than `user` as opaque and unstable.
    - `user` object
  - `ffmpeg_options` object: Final FFmpeg options used (audit trail)
    - `source` 'preset' | 'raw_options' | 'virtual_options' | 'defaults': How the options were derived. `raw_options`: the caller's `options`, sanitized. `virtual_options`: the caller's `options` included a virtual option (for example `@text-overlay`) that the gateway expanded. `preset`: a named preset. `defaults`: neither options nor a preset was given.
    - `options` object[]: The normalized option list handed to FFmpeg, in order.
      - `option` string, required: FFmpeg flag (e.g. `-c:v`, `-crf`, `-f`)
      - `argument` union: Flag value. Omitted (never null) for flag-only options (`-an`, `-vn`, `-shortest`) and whenever the caller sent null, so a bare flag serializes without one.
        - string
        - number
    - `preset` object, nullable
  - `output_url` string, nullable: Populated when status = completed
  - `created_at` string, date-time, required
  - `updated_at` string, date-time
  - `user_id` string: Internal user identifier resolved from API key
  - `input_url` string: [DEPRECATED] Use inputs array instead

## Other responses

- `401`: Missing/invalid API key
- `404`: Resource not found

---

[API](https://skmtc.dev/ffmpeg-micro/apis/ffmpeg-micro-api.md) · [All operations](https://skmtc.dev/ffmpeg-micro/apis/ffmpeg-micro-api/llms.txt) · [OpenAPI document](https://skmtc.dev/ffmpeg-micro/apis/ffmpeg-micro-api/revisions/64bb930ff345?raw)
