API v1/Server-to-serverProduction

Ship your first media job in minutes.

Give MediaRuntime a fetchable media URL, request exactly the outputs you need, and receive a signed terminal webhook. Use the optional upload endpoint only when you do not already have a source URL.

Quickstart

Create, wait, then download the ZIP bundle.

The CLI accepts relative or absolute local file paths and uploads the bytes automatically. MediaRuntime also accepts a public HTTP(S) URL or a time-limited signed read URL directly. For your first run, use the CLI's --download option or an SDK's job.wait() helper to receive the canonical ZIP bundle. In production, persist job_id and consume the signed account webhook instead of polling.

cURL
Submit an existing media URL
# Submit a public or time-limited HTTPS source directly.
# Keep the URL fetchable until MediaRuntime has downloaded the input.
curl -sS -X POST "https://mediaruntime.com/v1/jobs" \
  -H "X-API-Key: $MEDIARUNTIME_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "source": "https://cdn.example.com/media/launch-trailer.mp4",
    "metadata": { "asset_id": "asset_0426", "media_type": "video" },
    "outputs": ["video.web"]
  }'

Clone a complete quickstart

Runnable Node.js and Python SDK projects, Go and PHP HTTP examples, signed webhook receivers, and Postman guidance live together in one public repository.

Browse quickstarts on GitHub
Bring your existing media URL
Set `source` to a public HTTP(S) URL or a short-lived signed read URL from storage you already use. It must remain accessible through queueing and the worker's source download. The legacy `file_url` spelling remains supported. MediaRuntime does not need to become the system of record for your source files.
Production: use your account webhook
After validating locally with `job.wait()`, persist `job.id` alongside your entity ID and consume signed terminal events at the destination configured under Account → Webhooks. The metadata you submitted is echoed back for reconciliation.
Bash
Optional upload for local bytes
# Optional: use this when you have local bytes but no fetchable source URL.
UPLOAD=$(curl -sS -X POST "https://mediaruntime.com/v1/upload-url" \
  -H "X-API-Key: $MEDIARUNTIME_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"filename":"launch-trailer.mp4","content_type":"video/mp4"}')

UPLOAD_URL=$(printf '%s' "$UPLOAD" | jq -r .upload_url)
FILE_URI=$(printf '%s' "$UPLOAD" | jq -r .file_uri)
UPLOAD_CONTENT_TYPE=$(printf '%s' "$UPLOAD" | jq -r '.upload_headers["Content-Type"]')
UPLOAD_AUTH=$(printf '%s' "$UPLOAD" | jq -r '.upload_headers.Authorization // empty')

UPLOAD_ARGS=(-H "Content-Type: $UPLOAD_CONTENT_TYPE")
if [[ -n "$UPLOAD_AUTH" ]]; then
  UPLOAD_ARGS+=(-H "Authorization: $UPLOAD_AUTH")
fi
curl -sS -X PUT "$UPLOAD_URL" "${UPLOAD_ARGS[@]}" \
  --upload-file ./launch-trailer.mp4

# Then use "$FILE_URI" as source in POST /v1/jobs.
JSON
Immediate response
{
  "job_id": "job_1320c28b72104811b075a26a99496cf6",
  "status": "QUEUED",
  "tier": "standard",
  "required_tier": "standard",
  "outputs": [{
    "alias": "video.web",
    "type": "mp4",
    "preset": "mp4_720p_h264_aac"
  }],
  "msg": "accepted"
}
Command line

Run and inspect media jobs from your terminal.

The official CLI is the fastest path for local files, production diagnostics, bundle downloads, and testing a local webhook receiver. The CLI, Node SDK, and Python SDK are stable 1.x packages whose documented interfaces follow semantic versioning. They use the same public job contract and never change the ZIP bundle model.

Bash
Install and authorize once
npm install --global @mediaruntime/cli
mediaruntime login
mediaruntime jobs list --limit 3
Browser login or environment key
`mediaruntime login` creates a dedicated revocable CLI credential and stores it in the operating-system vault. `MEDIARUNTIME_API_KEY` remains permanently supported and takes precedence whenever it is set.

Submit a local file and download the complete bundle

Pass a relative path such as ./launch.mp4 or an absolute local file path; the CLI uploads it automatically before creating the job. In an interactive terminal, a spinner shows the upload, waiting, and verified download phases. --download waits for a terminal result and publishes the canonical ZIP atomically. Existing files are preserved unless --force is explicit.

Bash
Run one idempotent job
# The CLI uploads this local file before creating the job.
# Relative paths such as ./launch.mp4 work too.
mediaruntime run "/Users/you/Videos/launch.mp4" \
  -o video.streaming \
  -o audio.transcription \
  --metadata '{"asset_id":"launch-01"}' \
  --idempotency-key 'asset:launch-01:v1' \
  --download ./launch-01.zip

Discover the live public catalog

mediaruntime capabilities summarizes aliases and features, while mediaruntime presets list returns the ordered public preset catalog. These read-only commands require neither browser login nor MEDIARUNTIME_API_KEY.

Bash
Inspect capabilities and presets
# Public discovery commands do not require login or an API key.
mediaruntime capabilities
mediaruntime presets list

# Use JSON when another tool will consume the catalog.
mediaruntime presets list --json

Run exact public presets

Use repeatable --preset for exact catalog entries such as DASH or VP9. The CLI validates every name against the live public catalog before creating the job; aliases and exact presets can be combined in request order.

Bash
Request DASH and VP9 outputs
# Preset names are validated against the live public catalog.
mediaruntime run ./launch.mp4 \
  --preset dash_ladder_v1 \
  --preset webm_vp9_1080p \
  --download ./adaptive-and-vp9.zip

Inspect and retrieve jobs

List one page of account jobs, filter by status, inspect one job, or download its retained ZIP bundle. Use the opaque cursor printed by jobs list to request the next page.

Bash
List, inspect, and download
mediaruntime jobs list --status COMPLETED --limit 20
mediaruntime jobs get job_123
mediaruntime jobs get job_123 --download ./job_123.zip

Use API keys for automation

CI, servers, and containers should inject MEDIARUNTIME_API_KEY from a secret manager. Do not place credentials in command arguments, source control, logs, or plaintext configuration files.

Bash
Non-interactive authentication
# Permanently supported for CI, servers, and containers.
export MEDIARUNTIME_API_KEY="sk_..."
mediaruntime jobs list --limit 3
Capability
Output aliases
Command contract
--output video.web
Notes
All six frozen aliases are accepted; repeat --output for multiple deliverables.
Capability
Machine output
Command contract
--json
Notes
Writes one compact URL-redacted JSON result for scripts and CI.
Capability
Safe retries
Command contract
--idempotency-key
Notes
Reuse one business key for the same logical job across process restarts.
Capability
Bundle safety
Command contract
--download / --force
Notes
Downloads only terminal bundles, verifies integrity when advertised, and refuses accidental overwrite.
Capability
Exit status
Command contract
0–9, 130
Notes
Authentication, API rejection, terminal failure, timeout, trigger, and bundle errors have distinct nonzero codes.
Bash
Send a signed local terminal event
export MEDIARUNTIME_WEBHOOK_SECRET="whsec_..."

mediaruntime trigger job.completed \
  --to http://127.0.0.1:3000/webhooks/mediaruntime
Test local webhook code without a relay
`mediaruntime trigger` signs the exact JSON bytes and posts directly to an explicit loopback URL. It supports `job.completed`, `job.failed`, and `job.rejected`; it does not register or replace the production webhook configured under Account → Webhooks.
Authentication

Keep API keys on your server.

Create a key from Account → API Keys. The raw key is shown once and belongs in your secret manager, never in browser code, mobile binaries, logs, or source control.

Header

Send X-API-Key on every /v1 request.

Storage

Store MEDIARUNTIME_API_KEY in a server-side secret manager.

Rotation

Create a replacement, deploy it, verify traffic, then revoke the old key.

X-API-Key: sk_live_…
Bash
CLI: sign in through your browser
npm install --global @mediaruntime/cli
mediaruntime login
mediaruntime jobs list --limit 3
Automation still uses API keys
`mediaruntime login` stores a dedicated revocable credential in the operating-system vault. CI, servers, SDKs, and containers should continue using `MEDIARUNTIME_API_KEY` from their secret manager; an explicit environment key takes precedence over the CLI login.
Create jobs

Make metadata do the integration work.

The production pattern used by wMedia is intentionally simple: submit an input, output recipes, and enough opaque metadata to reconnect the terminal event to your own database record.

JSON
Production-style request
{
  "source": "https://cdn.example.com/media/source.mp4",
  "metadata": {
    "producer": "my-api",
    "entity_id": "video_01J8Y4",
    "owner_id": "user_482",
    "media_type": "video",
    "trace_id": "req_f839"
  },
  "moderation": {
    "enabled": true,
    "mode": "report",
    "checks": ["sexual", "violence", "dangerous"]
  },
  "watermark": { "enabled": true },
  "outputs": [
    {
      "type": "mp4",
      "preset": "mp4_720p_h264_aac",
      "path_suffix": "web",
      "poster_time_sec": 2,
      "gif_preview": {
        "enabled": true,
        "width": 320,
        "fps": 8,
        "start_time": 2,
        "duration": 2.5
      }
    },
    {
      "type": "image",
      "preset": "image_multi_v1",
      "path_suffix": "covers",
      "images": [
        { "width": 1280, "height": 720, "mode": "fit", "format": "webp", "quality": 84 },
        { "width": 480, "height": 480, "mode": "cover", "format": "webp", "quality": 80 }
      ]
    }
  ]
}
Field
source
Type
string or object
Notes
Canonical single input: a public HTTP(S), time-limited signed HTTP(S), accessible gs:// URL, or an object containing only url.
Field
file_url
Type
string
Notes
Permanent legacy spelling of scalar source. Do not combine source and file_url.
Field
inputs
Type
array
Notes
Batch fan-out for 1–25 inputs. Each item uses canonical source; legacy file_url remains supported per item. Do not combine inputs with either single-input field.
Field
outputs
Type
array
Notes
1–10 output recipes. Each requires type; preset is strongly recommended.
Field
metadata
Type
object
Notes
Up to 32 KiB of JSON. Persisted and echoed at meta.request_metadata.
Field
moderation
Type
object
Notes
Premium visual-media checks: sexual, violence, dangerous.
Field
watermark
Type
object
Notes
Premium visual-media overlay. The account must already have a PNG logo.

Batch fan-out

Use a batch when every input needs the same outputs. Per-input metadata is merged into each child job; the parent job becomes your batch reference.

JSON
Two inputs, one output recipe
{
  "inputs": [
    {
      "source": "https://cdn.example.com/a.mp4",
      "input_id": "asset-a",
      "metadata": { "position": 0 }
    },
    {
      "source": "https://cdn.example.com/b.mp4",
      "input_id": "asset-b",
      "metadata": { "position": 1 }
    }
  ],
  "metadata": { "batch_id": "import_2026_08_09" },
  "outputs": [{ "type": "mp4", "preset": "mp4_720p_h264_aac" }]
}

Safe retries with Idempotency-Key

A timed-out request is ambiguous: the job may have been queued and only the response lost. Send an Idempotency-Key header and retrying is safe — the same key returns the original job instead of queueing and charging for a second one. Without the header, behaviour is unchanged and every POST creates a new job.

Bash
Retry the same submission safely
# One key per logical job. Generate it in your client, not inside the retry loop.
KEY=$(uuidgen)   # or a deterministic id you can regenerate: asset_0426:mp4_720p:v1

curl -sS -X POST "https://mediaruntime.com/v1/jobs" \
  -H "X-API-Key: $MEDIARUNTIME_API_KEY" \
  -H "Idempotency-Key: $KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "source": "https://example.com/source.mp4",
    "metadata": { "asset_id": "asset_0426" },
    "outputs": [{ "type": "mp4", "preset": "mp4_720p_h264_aac" }]
  }'

# Timed out? Send the exact same request again with the SAME key.
# You get the original job_id back - no second job, no second charge.
You generate the key, not us
MediaRuntime cannot tell two requests apart on its own — only your client knows a second call is a retry rather than new work. Generate one key per logical job and reuse it across every retry of that job. Generating a key inside your retry loop gives each attempt a new key and removes the protection entirely.

Key rules

  • A UUID works; a deterministic id like asset_0426:mp4_720p:v1 is better, because you can regenerate it after a crash.
  • Keys are scoped to your account and honoured for 24 hours.
  • Reusing a key with a different body returns 422 — usually one key reused across a loop.
  • A retry sent while the first is still running returns 409; retry after a short backoff.
  • Submitting the same file twice on purpose? Use two different keys.
Output presets

Choose the artifact you want the engine to produce.

Start with a frozen output alias for common jobs. Use an explicit type and preset when you need to customize the recipe; mismatched pairs can be rejected or routed incorrectly.

Frozen output aliases

Aliases are stable gateway contracts. They resolve before validation, estimation, billing, and persistence, and can be mixed with explicit output objects in the same outputs array.

Alias
video.web
Resolves to
mp4 / mp4_720p_h264_aac, JPG poster at 2s
Artifacts
720p H.264/AAC MP4 and a JPG poster
Tier
Standard
Alias
video.streaming
Resolves to
hls / hls_ladder_v1
Artifacts
HLS master, 1080p/720p variants, and segments
Tier
Standard
Alias
video.social
Resolves to
social / social_vertical_blur
Artifacts
1080×1920 MP4 with a blurred 9:16 fill
Tier
Premium
Alias
audio.web
Resolves to
audio / audio_aac_128k
Artifacts
128 kbps AAC/M4A
Tier
Standard
Alias
audio.transcription
Resolves to
audio / audio_aac_128k with base subtitles
Artifacts
AAC/M4A plus SRT and WebVTT transcripts
Tier
Standard
Alias
image.web
Resolves to
image / image_multi_v1 with two WebP renditions
Artifacts
1200×630 and 320×320 WebP renditions
Tier
Premium
JSON
Vertical social video
{
  "source": "https://cdn.example.com/landscape-interview.mp4",
  "outputs": ["video.social"]
}
What Social executes
social_vertical_blur creates a 1080×1920 H.264/AAC MP4. The source is scaled to fit without cropping; a blurred copy fills the 9:16 canvas behind it. Use it for Reels, TikTok, and Shorts. It is a Premium recipe because the vertical output is 1920 pixels high.

Video files and posters

Preset
mp4_720p_h264_aac (type: mp4)
Send
Video
Job execution
Web-ready 720p H.264/AAC MP4 with fast start. MP4 video.
Base tier
Standard
Preset
mp4_ladder_v1 (type: mp4)
Send
Video
Job execution
H.264/AAC MP4 renditions at 1080p, 720p, and 480p. 1080p MP4, 720p MP4, 480p MP4.
Base tier
Standard
Preset
transmux_mp4_fast (type: mp4)
Send
Video
Job execution
Copies compatible streams into fast-start MP4, with an optional encoded fallback. MP4 video.
Base tier
Standard
Preset
poster_frame_v1 (type: mp4)
Send
Video
Job execution
Extracts one poster frame at the requested timestamp. JPG poster.
Base tier
Standard
Preset
mp4_hevc_1080p (type: mp4)
Send
Video
Job execution
1080p HEVC/AAC MP4 with the Apple-compatible hvc1 tag. HEVC MP4.
Base tier
Premium
Preset
mp4_av1_smart (type: mp4)
Send
Video
Job execution
1080p AV1/Opus output for compression-efficient delivery. AV1 MP4.
Base tier
Premium
Preset
mov_prores_422 (type: mp4)
Send
Video
Job execution
ProRes 422 HQ/PCM MOV editing master. ProRes MOV.
Base tier
Premium

Social video

Preset
audiogram_v1 (type: social)
Send
Audio or video with audio
Job execution
Composes timed audio, fitted artwork, a high-contrast waveform, and optional supplied captions in a reserved safe band into a social-ready video. H.264/AAC audiogram MP4, caption-free poster JPEG, audiogram.json, audiogram.waveform.json.
Base tier
Premium
Preset
social_vertical_blur (type: social)
Send
Video
Job execution
Creates a 1080x1920 vertical H.264 video with a blurred fill background. vertical MP4.
Base tier
Premium

Animated GIF

Preset
gif_hq (type: gif)
Send
Image or video
Job execution
Creates a palette-optimized animated GIF. animated GIF.
Base tier
Standard

Frame extraction

Preset
contact_sheet_v1 (type: frames)
Send
Video
Job execution
Creates bounded composite review sheets with tile-to-source timestamp metadata. numbered contact-sheet images, contact_sheet.json.
Base tier
Standard
Preset
extract_frames_1 (type: frames)
Send
Video
Job execution
Extracts a numbered JPG frame sequence at one frame per second. JPG frames at 1 fps.
Base tier
Standard
Preset
extract_frames_5 (type: frames)
Send
Video
Job execution
Extracts a numbered JPG frame sequence at five frames per second. JPG frames at 5 fps.
Base tier
Standard
Preset
scene_detect_v1 (type: frames)
Send
Video
Job execution
Detects shot boundaries and exports one keyframe per scene. scene JPGs, scene timeline.
Base tier
Standard
Preset
perceptual_hash_v1 (type: frames)
Send
Video
Job execution
Samples a video and emits similarity-ready perceptual hashes. phash.json.
Base tier
Standard

Streaming

Preset
hls_ladder_v1 (type: hls)
Send
Video
Job execution
Encoded H.264/AAC HLS VOD ladder at 1080p and 720p. HLS master playlist, variant playlists, media segments.
Base tier
Standard
Preset
transmux_hls_fast (type: hls)
Send
Video
Job execution
Packages compatible streams as HLS without re-encoding, with an optional encoded fallback. HLS master playlist, variant playlist, media segments.
Base tier
Standard

MPEG-DASH streaming

Preset
dash_ladder_v1 (type: dash)
Send
Video
Job execution
Encoded H.264/AAC MPEG-DASH ladder at 1080p and 720p. DASH MPD, initialization segments, media segments.
Base tier
Standard
Preset
transmux_dash_fast (type: dash)
Send
Video
Job execution
Packages compatible streams as MPEG-DASH without re-encoding, with an optional encoded fallback. DASH MPD, initialization segments, media segments.
Base tier
Standard

WebM video

Preset
webm_vp9_1080p (type: webm)
Send
Video
Job execution
1080p VP9/Opus WebM for modern browser delivery. VP9 WebM.
Base tier
Premium

Audio

Preset
audio_copy_fast (type: audio)
Send
Audio or video with audio
Job execution
Copies a compatible audio stream without re-encoding. audio file.
Base tier
Standard
Preset
audio_aac_128k (type: audio)
Send
Audio or video with audio
Job execution
Encodes 128 kbps AAC in an M4A container. M4A audio.
Base tier
Standard
Preset
audio_mp3_128k (type: audio)
Send
Audio or video with audio
Job execution
Encodes 128 kbps MP3. MP3 audio.
Base tier
Standard
Preset
audio_opus_96k (type: audio)
Send
Audio or video with audio
Job execution
Encodes 96 kbps Opus. Opus audio.
Base tier
Standard
Preset
audio_loudnorm_aac_128k (type: audio)
Send
Audio or video with audio
Job execution
Normalizes loudness to -16 LUFS and encodes 128 kbps AAC. normalized M4A audio, loudness metrics.
Base tier
Standard
Preset
audio_trim_silence_aac_128k (type: audio)
Send
Audio or video with audio
Job execution
Trims leading and trailing silence and encodes 128 kbps AAC. trimmed M4A audio.
Base tier
Premium
Preset
audio_loudnorm_trim_aac_128k (type: audio)
Send
Audio or video with audio
Job execution
Trims boundary silence, normalizes to -16 LUFS, and encodes 128 kbps AAC. trimmed and normalized M4A audio, loudness metrics.
Base tier
Premium
Preset
audio_whisper_prep (type: audio)
Send
Audio or video with audio
Job execution
Creates 16 kHz mono PCM WAV for speech-recognition pipelines. WAV audio.
Base tier
Standard

Image derivatives

Preset
image_multi_v1 (type: image)
Send
Image or video
Job execution
Creates requested image renditions; optional JPG/WebP max_bytes constraints are verified against the final file, and content-aware smart crop is a Premium control. image renditions, image_size_limits.json when max_bytes is used, smart_crop.json when enabled.
Base tier
Standard
Preset
image_animated_webp_v1 (type: image)
Send
Video
Job execution
Creates a bounded animated WebP clip with configurable size, frame rate, duration, and loop count. animated WebP.
Base tier
Premium
Preset
image_animated_apng_v1 (type: image)
Send
Video
Job execution
Creates a bounded lossless animated PNG clip with configurable size, frame rate, duration, and loop count. animated PNG.
Base tier
Premium
Preset
image_placeholders_v1 (type: image)
Send
Image or video
Job execution
Creates standards-compatible BlurHash and ThumbHash values, explicit source/placeholder geometry, an alpha-aware dominant colour, and a byte-bounded WebP loading placeholder. placeholders.json, lqip.webp.
Base tier
Standard

Analysis and reports

Preset
compatibility_report_v1 (type: image)
Send
Video
Job execution
Evaluates a video against versioned web, mobile, social-upload, and editing profiles with rule-level evidence and corrective preset recommendations. compatibility_report.json.
Base tier
Standard
Preset
media_report_v1 (type: image)
Send
Audio, image, or video
Job execution
Inspects container, audio/video streams, GOP structure when present, and embedded metadata without transcoding. media_report.json.
Base tier
Standard
Preset
code_detect_v1 (type: frames)
Send
Image or video
Job execution
Scans a bounded opening window for QR codes and barcodes. Audio is supported when it contains embedded cover artwork. codes.json, evidence frames when codes are found.
Base tier
Standard
Stream-copy compatibility
The transmux_*_fast presets avoid a quality-changing encode when source streams are compatible with MP4, HLS, or DASH. If copy fails and fallback is enabled, the engine uses the corresponding encoded preset. Use an encoded preset directly when you require predictable codec and rendition characteristics.
Tier can rise with overrides
The table shows the base Workspace tier. Extra outputs, WebP/AVIF images, large image sets, smart crop, background removal, watermarking, moderation, advanced subtitles, or GIF previews can require Premium.
Format conversion

Use one source. Produce the formats and sidecar artifacts your product needs.

The source extension does not select the output. The type and preset choose the executable recipe, so one uploaded video can become playback video, audio-only media, transcripts, GIF previews, posters, or frame sequences in the same asynchronous job.

Source
JPG, PNG, or WebP
Deliverable
JPG, PNG, WebP, or AVIF derivatives
Recipe
image + image_multi_v1; choose images[].format, dimensions, mode, and quality. JPG/WebP can add max_bytes and min_quality for a verified hard ceiling.
Source
Video
Deliverable
Web MP4, HLS, social video, or editing master
Recipe
Choose the matching mp4, hls, or social preset.
Source
Video
Deliverable
Animated GIF, poster, or JPG frame sequence
Recipe
Use gif_hq, poster_frame_v1, extract_frames_1/5, or attach gif_preview to a video output.
Source
Video or audio
Deliverable
M4A, MP3, Opus, or speech WAV
Recipe
Choose the corresponding audio_* preset; video inputs have their audio stream extracted.
Source
Video or audio speech
Deliverable
SRT, WebVTT, or both
Recipe
Add subtitles to an audio or video output and choose srt, vtt, or both.
JSON
PNG → JPG + WebP
{
  "source": "https://cdn.example.com/media/product-photo.png",
  "metadata": {
    "media_type": "image",
    "asset_id": "product-photo-0426"
  },
  "outputs": [{
    "type": "image",
    "preset": "image_multi_v1",
    "path_suffix": "converted",
    "images": [
      { "width": 1600, "height": 1200, "mode": "fit", "format": "jpg", "quality": 88 },
      { "width": 1600, "height": 1200, "mode": "fit", "format": "webp", "quality": 82 }
    ]
  }]
}
JSON
One video → MP4 + MP3
{
  "source": "https://cdn.example.com/media/interview.mov",
  "outputs": [
    { "type": "mp4", "preset": "mp4_720p_h264_aac", "path_suffix": "web-video" },
    { "type": "audio", "preset": "audio_mp3_128k", "path_suffix": "audio-only" }
  ]
}
JSON
Video → M4A + SRT + WebVTT
{
  "source": "https://cdn.example.com/media/interview.mp4",
  "metadata": { "media_type": "video", "asset_id": "interview-0426" },
  "outputs": [{
    "type": "audio",
    "preset": "audio_aac_128k",
    "path_suffix": "audio-and-transcript",
    "subtitles": {
      "enabled": true,
      "languages": ["auto"],
      "format": "both",
      "model": "ggml-base.bin",
      "translate_to_english": false
    }
  }]
}
JSON
Video → MP4 + poster + GIF preview
{
  "source": "https://cdn.example.com/media/trailer.mp4",
  "metadata": { "media_type": "video", "asset_id": "trailer-0426" },
  "outputs": [{
    "type": "mp4",
    "preset": "mp4_720p_h264_aac",
    "path_suffix": "web",
    "poster_time_sec": 4,
    "poster_format": "jpg",
    "gif_preview": {
      "enabled": true,
      "width": 480,
      "fps": 10,
      "start_time": 4,
      "duration": 3
    }
  }]
}
JSON
Video → HLS adaptive streaming package
{
  "source": "https://cdn.example.com/media/feature-film.mp4",
  "metadata": { "media_type": "video", "asset_id": "stream-0426" },
  "outputs": [{
    "type": "hls",
    "preset": "hls_ladder_v1",
    "path_suffix": "stream"
  }]
}
JSON
Video → standalone GIF + JPG frame sequence
{
  "source": "https://cdn.example.com/media/clip.mp4",
  "metadata": { "media_type": "video", "asset_id": "clip-0426" },
  "outputs": [
    { "type": "gif", "preset": "gif_hq", "path_suffix": "animated-preview" },
    { "type": "frames", "preset": "extract_frames_1", "path_suffix": "sampled-frames" }
  ]
}
HLS is a package, not one video file
hls_ladder_v1 creates a master playlist, 1080p and 720p H.264/AAC variant playlists, and 6-second media segments. Use the reported master-playlist URL, or move the complete bundle together.
Dedicated GIF versus attached preview
gif_hq creates a full 480px, 15 fps primary GIF. gif_preview adds a shorter, explicitly timed GIF to another video output. Frame presets return numbered JPG sequences at one or five frames per second.
Every artifact stays attached to the job
Read the completed job’s output manifest or use its branded bundle URL. The audio, transcripts, poster, preview, and playback files are included without uploading the source again. Do not construct filenames or storage paths.
Estimate the complete output set
MediaRuntime estimates every requested output and feature before execution. GIF previews, WebP/AVIF derivatives, advanced subtitles, and multi-output jobs can require Premium; the API does not silently omit them.

Useful switches

audio_aac_128k returns M4A, audio_mp3_128k returns MP3, audio_opus_96k returns Opus, and audio_whisper_prep returns 16 kHz mono WAV. Set subtitles.format to srt, vtt, or both. For only one poster image, send type: mp4 with preset: poster_frame_v1 and the desired poster_time_sec.

Recipes

Start with a preset; override only what matters.

Presets keep requests readable and give the engine a stable baseline. Add explicit rendition, subtitle, preview, codec, or bitrate options only when the product requires them.

video.web → mp4_720p_h264_aac

Web MP4

Standard
Source
Video with a decodable video stream; audio is optional
Artifacts
720p H.264/AAC MP4 and a JPG poster
Node
Web MP4
// Source: Video with a decodable video stream; audio is optional
// Alias: video.web
// Preset: mp4_720p_h264_aac
// Artifacts: 720p H.264/AAC MP4 and a JPG poster
// Tier: Standard
// Testing: use job.wait(); production: persist job.id and consume the signed webhook
// npm install @mediaruntime/node
import { MediaRuntime } from "@mediaruntime/node";

const media = new MediaRuntime();
const job = await media.jobs.create({
  "source": "https://cdn.example.com/media/source.mov",
  "metadata": {
    "asset_id": "asset_0426",
    "recipe": "web-mp4"
  },
  "outputs": [
    "video.web"
  ],
  "idempotencyKey": "asset:web-mp4:v1"
});

console.log(job.id, job.status);
video.streaming → hls_ladder_v1

HLS streaming

Standard
Source
Video with a decodable video stream; audio is optional
Artifacts
Master playlist, 1080p/720p variants, and six-second media segments
Node
HLS streaming
// Source: Video with a decodable video stream; audio is optional
// Alias: video.streaming
// Preset: hls_ladder_v1
// Artifacts: Master playlist, 1080p/720p variants, and six-second media segments
// Tier: Standard
// Testing: use job.wait(); production: persist job.id and consume the signed webhook
// npm install @mediaruntime/node
import { MediaRuntime } from "@mediaruntime/node";

const media = new MediaRuntime();
const job = await media.jobs.create({
  "source": "https://cdn.example.com/media/feature.mp4",
  "metadata": {
    "asset_id": "asset_0426",
    "recipe": "hls-streaming"
  },
  "outputs": [
    "video.streaming"
  ],
  "idempotencyKey": "asset:hls:v1"
});

console.log(job.id, job.status);
video.social → social_vertical_blur

Vertical social video

Premium
Source
Landscape, square, or portrait video
Artifacts
1080×1920 H.264/AAC MP4 with a blurred 9:16 fill
Node
Vertical social video
// Source: Landscape, square, or portrait video
// Alias: video.social
// Preset: social_vertical_blur
// Artifacts: 1080×1920 H.264/AAC MP4 with a blurred 9:16 fill
// Tier: Premium
// Testing: use job.wait(); production: persist job.id and consume the signed webhook
// npm install @mediaruntime/node
import { MediaRuntime } from "@mediaruntime/node";

const media = new MediaRuntime();
const job = await media.jobs.create({
  "source": "https://cdn.example.com/media/interview.mp4",
  "metadata": {
    "asset_id": "asset_0426",
    "recipe": "vertical-social"
  },
  "outputs": [
    "video.social"
  ],
  "idempotencyKey": "asset:social:v1"
});

console.log(job.id, job.status);
image.web → image_multi_v1

Responsive image derivatives

Premium
Source
JPG, PNG, WebP, or another supported still image
Artifacts
1200×630 and 320×320 metadata-stripped WebP renditions
Node
Responsive image derivatives
// Source: JPG, PNG, WebP, or another supported still image
// Alias: image.web
// Preset: image_multi_v1
// Artifacts: 1200×630 and 320×320 metadata-stripped WebP renditions
// Tier: Premium
// Testing: use job.wait(); production: persist job.id and consume the signed webhook
// npm install @mediaruntime/node
import { MediaRuntime } from "@mediaruntime/node";

const media = new MediaRuntime();
const job = await media.jobs.create({
  "source": "https://cdn.example.com/media/product.png",
  "metadata": {
    "asset_id": "asset_0426",
    "recipe": "image-derivatives"
  },
  "outputs": [
    "image.web"
  ],
  "idempotencyKey": "asset:image-derivatives:v1"
});

console.log(job.id, job.status);
audio.transcription → audio_aac_128k

Audio plus transcript

Standard
Source
Audio, or video containing a decodable audio stream
Artifacts
128 kbps AAC/M4A plus SRT and WebVTT transcripts
Node
Audio plus transcript
// Source: Audio, or video containing a decodable audio stream
// Alias: audio.transcription
// Preset: audio_aac_128k
// Artifacts: 128 kbps AAC/M4A plus SRT and WebVTT transcripts
// Tier: Standard
// Testing: use job.wait(); production: persist job.id and consume the signed webhook
// npm install @mediaruntime/node
import { MediaRuntime } from "@mediaruntime/node";

const media = new MediaRuntime();
const job = await media.jobs.create({
  "source": "https://cdn.example.com/media/interview.mp4",
  "metadata": {
    "asset_id": "asset_0426",
    "recipe": "audio-transcript"
  },
  "outputs": [
    "audio.transcription"
  ],
  "idempotencyKey": "asset:audio-transcript:v1"
});

console.log(job.id, job.status);
video.web → mp4_720p_h264_aac

Moderation plus watermarking

Premium
Source
One image or video; this example uses video
Artifacts
Watermarked 720p MP4, JPG poster, and moderation evidence report
Node
Moderation plus watermarking
// Source: One image or video; this example uses video
// Alias: video.web
// Preset: mp4_720p_h264_aac
// Artifacts: Watermarked 720p MP4, JPG poster, and moderation evidence report
// Tier: Premium
// Testing: use job.wait(); production: persist job.id and consume the signed webhook
// npm install @mediaruntime/node
import { MediaRuntime } from "@mediaruntime/node";

const media = new MediaRuntime();
const job = await media.jobs.create({
  "source": "https://cdn.example.com/media/upload.mp4",
  "metadata": {
    "asset_id": "asset_0426",
    "recipe": "moderation-watermark"
  },
  "moderation": {
    "enabled": true,
    "mode": "report",
    "checks": [
      "sexual",
      "violence",
      "dangerous"
    ]
  },
  "watermark": {
    "enabled": true
  },
  "outputs": [
    "video.web"
  ],
  "idempotencyKey": "asset:moderation-watermark:v1"
});

console.log(job.id, job.status);
Premium feature routing
Moderation, watermarking, advanced codecs, multiple outputs, GIF previews, and some subtitle features can require Premium. The API rejects work your account cannot run rather than silently dropping features.
Watermark setup
Upload and confirm one account PNG from the Account page. Then send only { "watermark": { "enabled": true } }; MediaRuntime resolves the server-owned logo.
Reusable account policy

Version the complete processing policy, not copied request JSON.

Hosted recipes are immutable, account-scoped versions of outputs, moderation, and watermark policy. Use an unpinned name for the latest active version or `name@version` when a deployment must never move.

Bash
Discover and submit a hosted recipe
# Discover the built-in and account recipes available to this key.
mediaruntime recipes list

# A hosted recipe may be pinned to one immutable version.
mediaruntime run ./launch.mp4 \
  --recipe team-video@3 \
  --download ./launch.zip

# The raw API accepts the same reference.
curl -sS -X POST "https://mediaruntime.com/v1/jobs" \
  -H "X-API-Key: $MEDIARUNTIME_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "source": "https://cdn.example.com/media/launch.mp4",
    "recipe": "web-video@1",
    "metadata": { "asset_id": "launch-01" }
  }'
Resolved before cost and execution
The gateway materializes the exact version before validation, estimation, wallet reservation, idempotency, and dispatch. Submit, polling, and terminal webhooks carry the same recipe acknowledgement and SHA-256 digest.
Team-safe management
Owners and admins create immutable versions with optimistic locking. Archiving blocks new selection while preserving existing jobs and pinned history. Built-ins are web-video@1, social-video@1, and ai-transcription@1.
Moderation

Add layered visual-safety analysis to the job.

Moderation uses a layered pipeline for one image or video input. Report mode returns best-effort evidence and continues processing. Block mode is a fail-closed pre-engine gate: block or review rejects the job, while allow continues.

JSON
Request all visual checks
{
  "source": "https://cdn.example.com/upload.mp4",
  "metadata": { "media_type": "video", "asset_id": "asset_0426" },
  "moderation": {
    "enabled": true,
    "mode": "report",
    "checks": ["sexual", "violence", "dangerous"]
  },
  "outputs": [{
    "type": "mp4",
    "preset": "mp4_720p_h264_aac"
  }]
}
JSON
Result on the completed job and webhook
{
  "moderation": {
    "requested": {
      "enabled": true,
      "mode": "report",
      "checks": ["sexual", "violence", "dangerous"],
      "media_type": "video",
      "phase": "phase1_video_report"
    },
    "result": {
      "ok": true,
      "media_type": "video",
      "verdict": "review",
      "flagged_checks": ["violence"],
      "scores": {
        "violence": { "yes": 0.82, "no": 0.18 }
      },
      "decisions": {
        "violence": { "decision": "review", "raw_decision": "review" }
      },
      "evidence": {
        "frames_sampled": 8,
        "frames_flagged": [{
          "frame_index": 3,
          "timestamp_sec": 20,
          "verdict": "review",
          "flagged_checks": ["violence"]
        }]
      },
      "video": {
        "frame_interval_sec": 10,
        "max_frames": 24
      }
    }
  },
  "meta": {
    "moderation_result": {
      "url": "https://storage.googleapis.com/.../moderation_result.json"
    }
  },
  "usage": {
    "breakdown": { "moderation_units": 120 }
  }
}
Contract
Plan
Value
Premium
Notes
The API returns 403 unless the account is Premium or auto-upgrade is allowed.
Contract
Mode
Value
report or block
Notes
Report is observational. Block rejects block/review verdicts before the engine starts.
Contract
Checks
Value
sexual, violence, dangerous
Notes
Send one to three checks. Omitting checks selects all three.
Contract
Inputs
Value
One image or video
Notes
Audio-only inputs, batches, and Sandbox moderation are rejected.
Contract
Video sampling
Value
Fixed interval, bounded frames
Notes
The service chooses the interval and cap; read the actual values from result.video and result.evidence.
Contract
Decision
Value
allow, review, or block signal
Notes
Report mode never blocks execution. Block mode is fail-closed: allow continues; review or block ends as REJECTED.
Contract
Artifact
Value
meta/moderation_result.json
Notes
Included in the output ZIP and exposed through meta.moderation_result.url when available.
Contract
Billing
Value
Per analysed frame
Notes
One inference per frame: an image is 1 frame, a video is sampled to a cap of 24. Settled from result.evidence.frames_sampled at usage.breakdown.moderation_units.
Contract
Standalone
Value
outputs may be empty
Notes
Send outputs: [] to moderate a file without transcoding it. Billed for moderation only.
Choose observational or enforced moderation
Use report when your application owns the publish decision. Use block when MediaRuntime should reject before transcoding; a rejected job has no output bundle and bills only moderation units. Classifier decisions remain fallible, so keep a review and appeal path where appropriate.
Models can be wrong
Scores are classifier outputs, not facts. Keep the evidence, version your downstream thresholds, provide an appeal path where appropriate, and avoid fully automated high-impact decisions.
Webhooks

Verify the raw bytes before trusting the event.

Terminal events are delivered at least once and ordering is not guaranteed. Verify HMAC-SHA256, reject stale timestamps, deduplicate event_id, acknowledge quickly, and move heavy work to a queue.

JSON
COMPLETED event
{
  "event_id": "webhook_evt_job_1320c28b72104811b075a26a99496cf6",
  "job_id": "job_1320c28b72104811b075a26a99496cf6",
  "account_id": "acc_xxx",
  "status": "COMPLETED",
  "completedAt": "2026-08-09T02:41:23Z",
  "billing": { "status": "PAID", "estimatedUnits": 31 },
  "usage": { "units_total": 31, "breakdown": {} },
  "delivery": {
    "mode": "PULL",
    "retentionDays": 7,
    "expiresAt": "2026-08-16T02:41:23Z",
    "bundle": {
      "type": "zip",
      "filename": "outputs.zip",
      "download": {
        "url": "https://mediaruntime.com/v1/jobs/job_1320c28b72104811b075a26a99496cf6/bundle?token=...",
        "expiresAt": "2026-08-16T02:41:23Z"
      }
    }
  },
  "meta": {
    "engine_result_url": "https://storage.googleapis.com/...",
    "outputs_root_gs": "gs://.../jobs/acc_xxx/job_.../outputs",
    "request_metadata": {
      "producer": "my-api",
      "entity_id": "video_01J8Y4",
      "media_type": "video"
    }
  }
}
Where outputs live
Download the complete ZIP from delivery.bundle.download.url, or fetch meta.engine_result_url to enumerate individual output and artifact paths.
Node
Express raw-body verification
import express from "express";
import { MediaRuntime } from "@mediaruntime/node";

const media = new MediaRuntime();
const app = express();

// Register this route before any express.json() middleware.
app.post(
  "/webhooks/mediaruntime",
  express.raw({ type: "application/json" }),
  media.webhooks.express(async (event, _req, res) => {
    // Persist and deduplicate event.id before acknowledging.
    console.log(event.id, event.jobId, event.status);
    res.sendStatus(204);
  }),
);
Configure the endpoint in Account
Open Account → Webhooks, enter your HTTPS endpoint, and store the signing secret when it is shown. The public API integration requires only your API key and webhook signing secret.

Delivery rules

  • Return any 2xx only after signature verification and durable enqueue/deduplication.
  • Treat event_id as the idempotency key.
  • Use meta.request_metadata to find your entity without a second lookup table.
  • Download retained outputs before delivery.expiresAt.
  • A FAILED or REJECTED event has error.code/message and no usable bundle. A PARTIAL batch has error.code BATCH_PARTIAL; inspect delivery.items for each child's status and successful bundle.
Track jobs

Poll when a webhook is not practical.

Submission returns immediately with a job_id. Webhooks remain the lowest-latency way to learn a job finished, but polling is available for local development, environments without a public endpoint, reconciliation, and support questions.

cURL
Fetch one job
curl -sS "https://mediaruntime.com/v1/jobs/$JOB_ID" \
  -H "X-API-Key: $MEDIARUNTIME_API_KEY"
cURL
List your jobs
# Newest first. Filter by status and page with the cursor.
curl -sS "https://mediaruntime.com/v1/jobs?status=COMPLETED&limit=25" \
  -H "X-API-Key: $MEDIARUNTIME_API_KEY"

# Next page: pass the previous response's next_cursor
curl -sS "https://mediaruntime.com/v1/jobs?limit=25&cursor=$NEXT_CURSOR" \
  -H "X-API-Key: $MEDIARUNTIME_API_KEY"
JSON
Response fields
{
  "job_id": "job_2ee8db582cdf4a2fafb49d52218b3159",
  "status": "COMPLETED",
  "tier": {
    "requested": "premium",
    "required": "standard",
    "effective": "premium",
    "billed": "standard",
    "reasons": []
  },
  "usage": { "units_total": 4 },
  "billing": {
    "status": "PAID",
    "currency": "USD",
    "unit_price_cents": 1,
    "final_units": 4,
    "final_amount_cents": 4
  },
  "bundle": {
    "available": true,
    "download_url": "https://mediaruntime.com/v1/jobs/job_2ee8.../bundle?token=...",
    "expires_at": "2026-08-18T03:14:27Z",
    "size_bytes": 13056793,
    "retention_days": 7
  },
  "media": {
    "format": "mov,mp4,m4a,3gp,3g2,mj2",
    "duration_sec": 61.5,
    "bit_rate": 8000000,
    "video": {
      "codec": "h264",
      "profile": "High",
      "width": 1080,
      "height": 1920,
      "encoded_width": 1920,
      "encoded_height": 1080,
      "fps": 29.97,
      "rotation_deg": 90,
      "is_rotated": true,
      "orientation": "portrait"
    },
    "audio": { "codec": "aac", "sample_rate_hz": 48000, "channels": 2, "layout": "stereo" },
    "streams": { "video": 1, "audio": 1, "other": 0 }
  },
  "metadata": { "asset_id": "asset_0426", "media_type": "video" },
  "error": null,
  "completed_at": "2026-08-11T03:14:53Z"
}
Reading the tier block
requested is the tier of the API key that submitted the job. required is what the work actually needs, effective is the lane it ran on, and billed is what you were charged. A premium key running standard work shows requested: premium with billed: standard — you are charged for the work, not the key.
Reading the media block
media reports what MediaRuntime found in your input when it probed it at submit — the same probe that decides whether a job is accepted. When a job is REJECTED for an incompatible pairing, this explains why: an MP3 sent to an image output shows streams.video: 0, and a still sent to a frames output has no duration_sec. Note video.width/height are DISPLAY dimensions with rotation applied, so a portrait phone clip reads 1080x1920 even though encoded_width/encoded_height are 1920x1080. Every field is optional: a missing one means the probe did not report it, never zero.
Fetching a moderation verdict
GET /v1/jobs/{job_id}/moderation returns the verdict alone, so a client polling for a decision does not pull billing and bundle detail every time. It answers with verdict, the per-check decision and confidence, and the escalation likelihoods. A check marked review_only is advisory: it can raise a review verdict but cannot by itself block. The endpoint returns **404 when the job exists but moderation was never requested** — an empty success response would be indistinguishable from "moderated and found nothing". The thresholds behind each decision are not published.
Fetching a media report
GET /v1/jobs/{job_id}/media-report returns the media_report_v1 document without downloading the bundle. report carries it inline; an unusually large report is not stored inline, and the response then sets report to null with a download_url that still resolves, so handle both. Returns 404 when the job carries no report.
Fetching a compatibility report
GET /v1/jobs/{job_id}/compatibility-report returns the versioned compatibility_report_v1 document without downloading the ZIP. It includes five conservative profiles, rule-level expected versus actual evidence, and an existing corrective preset for incompatible profiles. This is actionable guidance, not exhaustive device certification. Handle either inline report or download_url; a job without this preset returns 404.
Fetching QR/barcode detections
GET /v1/jobs/{job_id}/codes returns the bounded code_detect_v1 scan without downloading the ZIP. It supports images, video and animated visual sources, plus audio files that contain embedded cover artwork; plain audio is rejected with a corrective message. The scan retains at most 12 sampled frames and 16 unique codes per frame. Treat every decoded_text value as untrusted text: never render it as HTML and never follow a decoded URL automatically. Evidence frames remain in the ZIP and are referenced by bundle path.
Field
status
Type
string
Notes
QUEUED, PROCESSING, COMPLETED, FAILED, REJECTED, or batch-only PARTIAL.
Field
tier
Type
object
Notes
requested / required / effective / billed, plus reasons when premium was required.
Field
usage.units_total
Type
integer
Notes
Billable units for the job.
Field
billing
Type
object
Notes
Currency, unit price, and estimated vs final units and amount.
Field
bundle.download_url
Type
string
Notes
Job-scoped, expiring bundle URL. Single-job endpoint only.
Field
media
Type
object
Notes
What the input actually was, as probed at submit. Null on older jobs.
Field
media.video.width/height
Type
integer
Notes
Display dimensions, rotation already applied.
Field
media.duration_sec
Type
number
Notes
Absent for still images, which have no timeline.
Field
metadata
Type
object
Notes
The metadata object you submitted, echoed back.
Field
error
Type
string
Notes
Populated on FAILED, REJECTED, or batch-only PARTIAL; null otherwise.

Polling rules

  • Prefer webhooks; poll only when you cannot receive one.
  • Page with next_cursor, never an offset — rows shift as jobs update.
  • A job id you do not own returns 404, the same as one that does not exist.
  • List rows omit the bundle URL; fetch the single job to download.
  • Back off between polls. A terminal status will not change.
Billing and pricing

Prepaid, pay as you go, and settled from actual usage.

Add a card, fund the wallet, and submit work without a recurring subscription. MediaRuntime reserves an estimate before execution and settles the final charge when the job reaches a terminal state.

Plan
Standard Pay-As-You-Go
Starting usage price
From $0.02
Minimum top-up
$20.00
Default auto-top-up
$20.00 at $2.00 available
Plan
Premium Pay-As-You-Go
Starting usage price
From $0.05
Minimum top-up
$60.00
Default auto-top-up
$60.00 at $5.00 available
How reservation and settlement work
Submission reserves the estimated charge plus a 15% safety buffer. Completion charges actual billable usage and releases unused reservation. Pending Stripe top-ups become wallet credit only after the signed payment webhook confirms them.
How usage is measured
Video and audio begin with media duration, then reflect requested outputs and processing. Images use processing units with a minimum billable unit per job; input bytes are not charged per MB. Multiple outputs and features such as advanced codecs, subtitles, GIFs, moderation, and watermarking can add units or require Premium. Use the job estimate for planning and the terminal billing and usage fields for reconciliation.

Wallet rules

  • Available credit equals wallet credit minus funds reserved for running jobs.
  • Insufficient available credit returns HTTP 402 before execution.
  • Auto-top-up is optional and requires a card on file.
  • A Premium-only request returns 403 when upgrade is not permitted.
Use the account's billing snapshot
The table shows public USD starting prices, not a flat price for every job. Negotiated volume accounts can carry account-specific pricing. Do not derive the final charge from duration alone; persist the estimate and terminal billing snapshot returned for the job.
Errors and retries

Retry transport failures, not invalid work.

Every response includes X-Request-Id. Errors add a normalized error object while preserving detail/message for compatibility. Log the request ID, code, and status—but never the API key, signed URLs, or request body.

Status
400
Code
invalid_request
Meaning
The request is logically invalid or the estimator rejected it.
What your integration should do
Fix the request; do not retry unchanged.
Status
401
Code
authentication_error
Meaning
The API key is invalid, expired, or revoked.
What your integration should do
Correct or rotate the key; do not blindly retry.
Status
402
Code
billing_required
Meaning
The account, wallet, or billing preflight cannot cover the job.
What your integration should do
Fund the wallet or resolve billing first.
Status
403
Code
permission_denied
Meaning
The plan, role, or feature gate does not permit the request.
What your integration should do
Change the plan/request; do not retry unchanged.
Status
404
Code
not_found
Meaning
The owned resource is absent or hidden by owner scoping.
What your integration should do
Correct the identifier; do not retry unchanged.
Status
409
Code
idempotency_in_progress / conflict
Meaning
An operation with this key is running or another active operation conflicts.
What your integration should do
Retry only when error.retryable is true.
Status
410
Code
gone
Meaning
A short-lived token expired.
What your integration should do
Obtain a fresh result or token.
Status
413
Code
request_too_large
Meaning
The HTTP request body exceeds 2 MiB.
What your integration should do
Upload media separately and send URLs only.
Status
422
Code
validation_error / idempotency_conflict / unprocessable_entity
Meaning
Validation failed or an idempotency key was reused with another body.
What your integration should do
Correct the named field or key.
Status
429
Code
rate_limited
Meaning
The account or key is rate limited.
What your integration should do
Retry with exponential backoff and jitter.
Status
500
Code
internal_error
Meaning
The gateway failed unexpectedly.
What your integration should do
Retry safely with backoff.
Status
502
Code
upstream_error
Meaning
A transient platform dependency failed.
What your integration should do
Retry safely with backoff.
Status
503
Code
service_unavailable
Meaning
A dependency or execution lane is unavailable.
What your integration should do
Retry safely with backoff.
JSON
Typical error body
{
  "error": {
    "code": "billing_required",
    "message": "Insufficient wallet balance for this job",
    "status": 402,
    "retryable": false,
    "request_id": "req_7fa01eec9b6248a5a7be2d60ff4bb978",
    "details": null
  },
  "request_id": "req_7fa01eec9b6248a5a7be2d60ff4bb978",
  "detail": "Insufficient wallet balance for this job"
}
Safe retry policy
Use error.retryable instead of independently classifying statuses. For job submission, retryable still requires the original Idempotency-Key: a lost response may hide an accepted paid job. Send a constrained X-Request-Id when you already have a trace ID, or log the generated response value for support correlation.
API reference

The small surface most integrations need.

All server-to-server endpoints below use X-API-Key. The tokenized bundle URL is the only exception because it carries its own short-lived, job-scoped credential.

Method
POST
Path
/v1/upload-url
Purpose
Optionally create a 15-minute upload target when you do not already have a fetchable media URL.
Method
POST
Path
/v1/jobs
Purpose
Queue a single-input or batch media job.
Method
GET
Path
/v1/jobs/{job_id}
Purpose
Status, tier decision, usage, billing, and bundle link for one job.
Method
GET
Path
/v1/jobs
Purpose
List your jobs, newest first. Supports ?status= and cursor paging.
Method
GET
Path
/v1/jobs/{job_id}/moderation
Purpose
Moderation verdict for one job. 404 when moderation was not requested.
Method
GET
Path
/v1/jobs/{job_id}/media-report
Purpose
Forensic media report for one job. 404 when media_report_v1 was not requested.
Method
GET
Path
/v1/jobs/{job_id}/compatibility-report
Purpose
Versioned compatibility verdict for one job. 404 when compatibility_report_v1 was not requested.
Method
GET
Path
/v1/jobs/{job_id}/codes
Purpose
Bounded QR/barcode detections and evidence references. 404 when code_detect_v1 was not requested.
Method
GET
Path
/v1/jobs/{job_id}/bundle?token=...
Purpose
Redeem the job-scoped token for a bundle; no API key is required.
Method
POST
Path
/v1/jobs/{job_id}/retry-webhook
Purpose
Retry the terminal webhook for a job you own.
Method
POST
Path
/v1/account/watermark-logo/upload-url
Purpose
Create an upload target for the account PNG logo.
Method
POST
Path
/v1/account/watermark-logo/confirm
Purpose
Confirm the logo and its placement settings.
Machine-readable contract

Use the versioned OpenAPI 3.1 document for client generation, request validation, and contract review. It contains only the supported public API surface and requires no API key.

View OpenAPI JSON