Skip to content

DocsGuides

Read media metadata

Read the container, duration and streams of a file with ffprobe, without encoding anything.

POST /v1/probe reads one file with ffprobe and answers its container, duration and streams: codec, size, frame rate, rotation, bitrate, audio channels and sample rate. Nothing is encoded.

The request#

bash
curl "$VIDEXO_API_URL/v1/probe" \
  -H "Authorization: Bearer $VIDEXO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "input": "https://example.com/talk.mp4"
}'

The API waits up to 25 seconds for the job to end. Most probes end well within that. The answer is the job, with what ffprobe read in probe:

JSON
{
  "id": "job_3k9x0c2mfq8w1n7r5t4b6v2z",
  "state": "succeeded",
  "kind": "operations",
  "operation": "probe",
  "spec": {
    "inputs": {
      "source": {
        "url": "https://videxo.io/samples/talk.mp4"
      }
    },
    "outputs": [
      {
        "name": "metadata",
        "type": "metadata",
        "input": "source",
        "filename": "metadata.json",
        "format": "json"
      }
    ]
  },
  "command": null,
  "input_files": null,
  "output_files": null,
  "ffmpeg_command": null,
  "steps": [
    {
      "tool": "ffprobe",
      "inputs": [
        "source"
      ],
      "outputs": [
        "metadata"
      ],
      "command": null
    }
  ],
  "webhook_url": null,
  "metadata": {},
  "progress": null,
  "error": null,
  "outputs": [
    {
      "alias": "out_metadata",
      "name": "metadata",
      "filename": "metadata.json",
      "size_bytes": 612,
      "sha256": "9f2c4e1a7b3d5f60c8e2a4b6d8f0e1c3a5b7d9f1e3c5a7b9d1f3e5c7a9b1d3f5",
      "content_type": "application/json",
      "expires_at": "2026-11-05T12:01:09.000Z",
      "download_url": "https://api.videxo.io/v1/files/job_3k9x0c2mfq8w1n7r5t4b6v2z/out_video?account=acc_example&expires=1793797269&signature=example",
      "download_url_expires_at": "2026-11-04T13:01:09.000Z",
      "deleted_at": null
    }
  ],
  "usage": {
    "seconds": 1,
    "input_bytes": 48000000,
    "output_bytes": 612,
    "credits": 1,
    "bill": {
      "lines": [
        {
          "kind": "metadata",
          "credits": 0
        }
      ],
      "data": {
        "input_bytes": 48000000,
        "output_bytes": 612,
        "credits": 0.48
      },
      "processing": {
        "seconds": 1,
        "included_seconds": 0,
        "credits": 0.167
      }
    }
  },
  "created_at": "2026-11-04T12:00:00.000Z",
  "started_at": "2026-11-04T12:00:01.000Z",
  "finished_at": "2026-11-04T12:00:04.000Z",
  "probe": {
    "container": "mov,mp4,m4a,3gp,3g2,mj2",
    "duration": 62.4,
    "start_time": 0,
    "size_bytes": 48000000,
    "bit_rate": 6153846,
    "tags": {
      "major_brand": "isom",
      "creation_time": "2026-10-30T09:12:00.000000Z"
    },
    "streams": [
      {
        "index": 0,
        "type": "video",
        "codec": "h264",
        "profile": "High",
        "duration": 62.4,
        "bit_rate": 6000000,
        "width": 1920,
        "height": 1080,
        "rotation": 0,
        "fps": 29.97,
        "pixel_format": "yuv420p",
        "frames": 1870,
        "cover_art": false,
        "tags": {
          "language": "eng"
        }
      },
      {
        "index": 1,
        "type": "audio",
        "codec": "aac",
        "profile": "LC",
        "duration": 62.38,
        "bit_rate": 128000,
        "channels": 2,
        "channel_layout": "stereo",
        "sample_rate": 48000,
        "tags": {
          "language": "eng"
        }
      }
    ]
  }
}
  • 200: the job ended. When it succeeded, probe holds the document.
  • 202: the job is still queued or running, and probe is null. Read the job with GET /v1/jobs/{id}, or wait for its webhook. The document is the job's output file, metadata.json.

Send ?wait=false to answer at once without waiting: 202, or 200 if the job has already ended. A job's input is fetched in full before it is read, so a large file takes as long as its download.

What the document says#

FieldMeaning
containerffprobe's name for the format, such as mov,mp4,m4a,3gp,3g2,mj2.
durationSeconds: the latest end among the container and its streams, from the start of the file.
start_timeThe seconds the file starts at. Most files start at 0.
size_bytes, bit_rateOf the whole file.
tagsTags from a fixed list (below).
streamsAt most 64, in file order.

Every stream has index, type (video, audio, subtitle, data or attachment), codec, profile, duration, bit_rate and tags.

  • A video stream adds width and height as stored, rotation (degrees clockwise to display it), fps (the average frame rate), pixel_format, frames and cover_art. cover_art is true for an attached picture, such as album art, which is not a video.
  • An audio stream adds channels, channel_layout and sample_rate.

A value the file does not state, or states in a form we do not accept, is null. New fields may be added; the ones here keep their meaning.

Tags#

Only these tags are copied: title, artist, album, album_artist, composer, genre, date, creation_time, comment, description, copyright, encoder, language, handler_name, major_brand, track and disc. Each value is at most 256 characters, with control characters removed. Location and device tags are never copied.

With other outputs#

A metadata output reads an input in a job with any other outputs, and the input is fetched once for all of them. It takes name, type, input and filename, and writes <name>.json:

bash
curl "$VIDEXO_API_URL/v1/jobs" \
  -H "Authorization: Bearer $VIDEXO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "inputs": {
    "talk": "https://example.com/talk.mp4"
  },
  "outputs": [
    {
      "name": "web",
      "preset": "web-720p"
    },
    {
      "name": "info",
      "type": "metadata"
    }
  ]
}'

The document is an output file like any other, with a download link. command and ffmpeg_command on the job describe the ffmpeg part only. When every output is metadata, no ffmpeg runs and command, input_files, output_files and ffmpeg_command are null.

What it refuses#

ffprobe's own options are not part of the API: no field reaches its arguments, and a field the output does not take is 400 invalid_request. It reads the same single-file formats as ffmpeg does here (Command rules), and never opens another file or address a file names. A playlist, a concat list or anything else that is not one of those formats fails the job with processing_failed and the reason media_unreadable.

Credits#

A metadata output adds no credits of its own. Its job pays for the input as fetched and the document as stored as data, and at least 1 credit (Limits per plan).