---
title: "Cancel a transcode job"
method: PATCH
path: "/v1/transcodes/{id}/cancel"
---

# Cancel a transcode job

`PATCH /v1/transcodes/{id}/cancel`

## Request

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

Cancels a transcode job that is currently `pending` or `processing`. Completed, failed, or already-canceled jobs cannot be cancelled and return 400. If the job has been handed off to the toolkit service, a best-effort cancel is also sent to the toolkit — failures there are logged but do not fail this request.

## Path parameters

- `id` string, uuid, required

## Response `200`

Job cancelled successfully

- object
  - `success` boolean, required
  - `message` string, required
  - `job` Transcode, required
    - `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

- `400`: Job is not in a cancellable state
- `401`: Missing/invalid API key
- `404`: Resource not found
- `500`: Unexpected error

---

[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)
