API Documentation
Run transcode.pro programmatically. Every request runs a fixed preset or an admin-published tool with documented options — there's no raw/custom-filter mode, so cost and behavior are always predictable.
Quickstart
- Create an account and verify your email.
- Go to API & Credits in your dashboard, create a key, and claim your free trial credits.
- Top up if you need more than the trial amount.
- Verify the key works before building against it —
GET /api/v1/accountwith your key should return your credit balance:
curl --request GET \
--url "https://transcode.pro/api/v1/account" \
--header "Authorization: Bearer dsk_live_your_key_here"- Make your first job request:
curl --request POST \
--url "https://transcode.pro/api/v1/jobs" \
--header "Authorization: Bearer dsk_live_your_key_here" \
--header "Content-Type: application/json" \
--data '{"input":"https://example.com/video.mp4","preset":"thumbnail"}'Response:
{
"id": "d7291197-0050-4cdb-a731-ebbc656ca765",
"status": "PROCESSING",
"creditsCharged": 1,
"balanceAfter": 19
}One request, or two?
Add "wait": 25 to the body above (max 25 seconds) and this becomes one request: we hold the connection open, keep checking the job for you, and the same response comes back with outputUrlalready in it once it's done — image, audio, or video, same mechanism. This covers the large majority of jobs, which finish in well under 25 seconds.
Skip wait(or the job is still running when it runs out — rare, usually a large file) and it's two requests: this one only returns an id and status: "PROCESSING", no download link yet — you then call GET /api/v1/jobs/:id (optionally with its own ?wait=25) to get outputUrlonce it's ready.
How to test this: the cURL tab above runs as-is in any terminal (Mac/Linux/WSL, or Windows via curl.exe or Git Bash) — just swap in your real key and file URL. No terminal? Paste the same URL, headers, and body into Postman or Insomnia as a raw JSON POST request. For an actual integration, copy the Node.js, Python, or Go tab instead — every example on this page runs unmodified once you swap in your key.
Authentication
Every request (except the two marked “No auth” below) needs an Authorization header with a Bearer key from your dashboard:
Authorization: Bearer dsk_live_...Keys are shown once, at creation — we only store a hash, so if you lose one, revoke it and create a new key. Revoking takes effect immediately on the very next request made with that key.
Endpoints
Every endpoint includes production-ready examples for cURL, Node.js, Python, and Go. Replace the sample API key, input URL, and resource IDs with your own values. Keep secret API keys in trusted server-side environments. Never expose them in browser or mobile client code.
/api/v1/account200 OKRequires API keyCheck your current credit balance.
curl --request GET \
--url "https://transcode.pro/api/v1/account" \
--header "Authorization: Bearer dsk_live_your_key_here"200 OKapplication/json{ "balanceCredits": 19 }/api/v1/tools200 OKNo authThe live, complete list of everything you can run right now: all presets (with options) plus any admin-published tools.
curl --request GET \
--url "https://transcode.pro/api/v1/tools"200 OKapplication/json{
"presets": [ { "preset": "thumbnail", "creditsPerJob": 1, "options": [...] }, ... ],
"dynamicTools": [ { "toolId": "catalog:video-filter:hqdn3d", "name": "hqdn3d", "creditsPerJob": 10 }, ... ]
}/api/v1/pricing200 OKNo authCurrent credit cost per preset.
curl --request GET \
--url "https://transcode.pro/api/v1/pricing"200 OKapplication/json{
"model": {
"creditsPerInr": 5,
"durationUnitSeconds": 60,
"minimumDurationUnits": 1,
"formula": "ceil(baseCredits * resolutionMultiplier * max(1, durationSeconds / durationUnitSeconds) * durationTierMultiplier)"
},
"pricing": [
{ "preset": "probe", "creditsPerJob": 2, "billingBasis": "flat_job", "description": "..." },
{ "preset": "transcode", "creditsPerJob": 13, "billingBasis": "per_minute_base", "description": "..." }
]
}/api/v1/uploads201 CreatedRequires API keyGet a presigned URL to upload a local file.
Free — credits are only charged when you create a job, not for uploading. Skip this entirely if your input is already reachable at a public URL.
curl --request POST \
--url "https://transcode.pro/api/v1/uploads" \
--header "Authorization: Bearer dsk_live_your_key_here" \
--header "Content-Type: application/json" \
--data '{"filename":"video.mp4","contentType":"video/mp4","sizeBytes":887988}'201 Createdapplication/json{
"mode": "single",
"key": "uploads/...",
"input": "https://...",
"url": "https://...presigned..."
}Upload the file bytes with PUT to the returned presigned url, then pass the returned input to a job.
/api/v1/jobs201 CreatedRequires API keyCreate a job. Provide either preset (+ options) or toolId — never both, never raw filters.
curl --request POST \
--url "https://transcode.pro/api/v1/jobs" \
--header "Authorization: Bearer dsk_live_your_key_here" \
--header "Content-Type: application/json" \
--data '{"input":"https://example.com/video.mp4","preset":"transcode","options":{"width":1280,"crf":23},"output":{"filename":"out.mp4"}}'201 Createdapplication/json{
"id": "d7291197-0050-4cdb-a731-ebbc656ca765",
"status": "PROCESSING",
"creditsCharged": 13,
"balanceAfter": 87
}Returns 402immediately if your balance can't cover the job's cost — nothing is charged or queued in that case. If the job already finished by the time we respond (most presets do), this response also includes outputUrl (or error) directly — check status before falling back to polling GET /api/v1/jobs/:id. Pass "wait": <seconds, max 25> in the body to have us block and retry internally instead — you only get a response once the job is done (or the wait runs out).
/api/v1/jobs/:id200 OKRequires API keyFetch a job's status and result.
Add ?wait=<seconds, max 25> to block on this specific job instead of polling it yourself.
curl --request GET \
--url "https://transcode.pro/api/v1/jobs/d7291197-0050-4cdb-a731-ebbc656ca765" \
--header "Authorization: Bearer dsk_live_your_key_here"200 OKapplication/json{
"id": "...",
"status": "COMPLETED", // QUEUED | PROCESSING | COMPLETED | FAILED | CANCELLED
"progress": 100,
"outputUrl": "https://...",
"usage": { "creditsCharged": 10 } // present once status is terminal
}frame-sample jobs return a ZIP of individual numbered frame images as outputUrl, plus a frames: [{ "index": 1, "timeSec": 0 }, ...]manifest of each frame's timestamp.
/api/v1/jobs200 OKRequires API keyList jobs created by this key.
curl --request GET \
--url "https://transcode.pro/api/v1/jobs" \
--header "Authorization: Bearer dsk_live_your_key_here"200 OKapplication/json{ "jobs": [ { "id": "...", "status": "COMPLETED", ... } ] }Presets
The fixed set of operations available to every account. Pass any of these as optionsin a preset job — anything not listed isn't configurable.
probe30 base creditsReads metadata only — no options, no output file.
Create a probe job:
curl --request POST \
--url "https://transcode.pro/api/v1/jobs" \
--header "Authorization: Bearer dsk_live_your_key_here" \
--header "Content-Type: application/json" \
--data '{"input":"https://example.com/video.mp4","preset":"probe"}'Poll GET /api/v1/jobs/:id — once COMPLETED, the source's metadata is in the usage/probe fields; there's no downloadable output for this preset.
thumbnail30 base creditsExtracts a single frame as an image.
| Option | Type | Details |
|---|---|---|
| timeSec | number | default 1 · 0–∞ — Timestamp to capture, in seconds. |
| width | integer | 16–7680 — Output width in pixels (height scales automatically). |
| format | string | default jpg · jpg / png / webp |
Create a thumbnail job:
curl --request POST \
--url "https://transcode.pro/api/v1/jobs" \
--header "Authorization: Bearer dsk_live_your_key_here" \
--header "Content-Type: application/json" \
--data '{"input":"https://example.com/video.mp4","preset":"thumbnail","options":{"timeSec":5,"width":640,"format":"jpg"}}'Poll GET /api/v1/jobs/:id — once COMPLETED, download the result from outputUrl.
audio-extract30 base creditsExtracts (and optionally re-encodes) the audio track.
| Option | Type | Details |
|---|---|---|
| format | string | default mp3 · mp3 / aac / opus / flac / wav |
| bitrate | string | — — e.g. "128k", "2500k", "5M". |
Create a audio-extract job:
curl --request POST \
--url "https://transcode.pro/api/v1/jobs" \
--header "Authorization: Bearer dsk_live_your_key_here" \
--header "Content-Type: application/json" \
--data '{"input":"https://example.com/video.mp4","preset":"audio-extract","options":{"format":"mp3","bitrate":"192k"}}'Poll GET /api/v1/jobs/:id — once COMPLETED, download the result from outputUrl.
transcode30 base creditsFull re-encode — change codec, resolution, bitrate, frame rate, or container.
| Option | Type | Details |
|---|---|---|
| videoCodec | string | default libx264 · libx264 / libx265 / libsvtav1 / h264_nvenc — Or any other codec name supported by the processing backend. |
| audioCodec | string | default aac · aac / libopus / libfdk_aac / copy |
| crf | integer | 0–63 — Quality — lower is higher quality and larger file size. |
| videoBitrate | string | — — e.g. "2500k", "5M". |
| audioBitrate | string | — — e.g. "128k". |
| width | integer | 16–7680 |
| height | integer | 16–4320 |
| fps | number | 1–240 |
| speedPreset | string | ultrafast / superfast / veryfast / faster / fast / medium / slow / slower / veryslow |
| format | string | default mp4 · mp4 / mkv / webm / mov / ts |
Create a transcode job:
curl --request POST \
--url "https://transcode.pro/api/v1/jobs" \
--header "Authorization: Bearer dsk_live_your_key_here" \
--header "Content-Type: application/json" \
--data '{"input":"https://example.com/video.mp4","preset":"transcode","options":{"width":1280,"height":720,"crf":23,"videoCodec":"libx264","format":"mp4"},"output":{"filename":"out.mp4"}}'Poll GET /api/v1/jobs/:id — once COMPLETED, download the result from outputUrl.
watermark30 base creditsOverlays an image on every frame.
| Option | Type | Details |
|---|---|---|
| overlayUrl | string | required — URL of the png/jpg/webp image to overlay. |
| position | string | default bottom-right · top-left / top-right / bottom-left / bottom-right / center |
| margin | integer | default 10 · 0–500 |
| format | string | default mp4 · mp4 / mkv / webm / mov |
Create a watermark job — input is the video, options.overlayUrl is a separate image URL to overlay:
curl --request POST \
--url "https://transcode.pro/api/v1/jobs" \
--header "Authorization: Bearer dsk_live_your_key_here" \
--header "Content-Type: application/json" \
--data '{"input":"https://example.com/video.mp4","preset":"watermark","options":{"overlayUrl":"https://example.com/logo.png","position":"bottom-right","margin":20},"output":{"filename":"watermarked.mp4"}}'Poll GET /api/v1/jobs/:id — once COMPLETED, download the result from outputUrl.
aspect-ratio30 base creditsReframes video to a target aspect ratio by padding (letterbox/pillarbox), cropping, or stretching.
| Option | Type | Details |
|---|---|---|
| target | string | default 16:9 · 16:9 / 9:16 / 1:1 / 4:3 / 21:9 |
| fit | string | default pad · pad / crop / stretch — pad = letterbox/pillarbox (no distortion), crop = fills the frame by cropping excess, stretch = forces the ratio (may distort). |
Create a aspect-ratio job:
curl --request POST \
--url "https://transcode.pro/api/v1/jobs" \
--header "Authorization: Bearer dsk_live_your_key_here" \
--header "Content-Type: application/json" \
--data '{"input":"https://example.com/video.mp4","preset":"aspect-ratio","options":{"target":"9:16","fit":"pad"}}'Poll GET /api/v1/jobs/:id — once COMPLETED, download the result from outputUrl.
fade30 base creditsFades audio in at the start and/or out at the end.
| Option | Type | Details |
|---|---|---|
| fadeIn | number | default 2 · 0–30 — Fade-in duration in seconds. |
| fadeOut | number | default 3 · 0–30 — Fade-out duration in seconds. |
Create a fade job:
curl --request POST \
--url "https://transcode.pro/api/v1/jobs" \
--header "Authorization: Bearer dsk_live_your_key_here" \
--header "Content-Type: application/json" \
--data '{"input":"https://example.com/video.mp4","preset":"fade","options":{"fadeIn":2,"fadeOut":3}}'Poll GET /api/v1/jobs/:id — once COMPLETED, download the result from outputUrl.
frame-sample56 base creditsSamples individual still frames at a low, configurable rate (e.g. 1 frame/second) and returns them bundled as a ZIP — built for feeding a bounded set of frames to an AI/vision pipeline instead of every native frame.
| Option | Type | Details |
|---|---|---|
| fps | number | default 1 · 0.1–10 — Sampling rate — 1 = one frame/second, 0.5 = one frame every 2 seconds. |
| maxFrames | integer | default 24 · 1–60 — Hard cap of 60 frames per request. |
| format | string | default jpg · jpg / png / webp |
Create a frame-sample job:
curl --request POST \
--url "https://transcode.pro/api/v1/jobs" \
--header "Authorization: Bearer dsk_live_your_key_here" \
--header "Content-Type: application/json" \
--data '{"input":"https://example.com/video.mp4","preset":"frame-sample","options":{"fps":1,"maxFrames":10,"format":"jpg"}}'Poll GET /api/v1/jobs/:id — once COMPLETED, outputUrl is a .zip of the sampled frames, and frames lists each one's timestamp.
Published tools
Beyond the fixed presets, we occasionally publish additional single-purpose tools — a specific filter or codec verified and enabled by our team. These run at fixed, pre-verified settings (no configurable options) — pass the toolId shown below instead of preset. This list is always current — fetch GET /api/v1/tools to check programmatically.
Response codes
Successful responses use JSON unless noted otherwise. Errors use { "error": "message" } with a matching HTTP status code.
| Status | Meaning |
|---|---|
| 200 | Request completed successfully. |
| 201 | Upload ticket or processing job created. |
| 400 | Invalid request body (see the error message for which field). |
| 401 | Missing, invalid, or revoked API key. |
| 402 | Insufficient credits for this job. Nothing was charged. |
| 422 | We checked your input first and it's missing what this tool needs (e.g. no audio track for audio-extract/fade, or no video track for a video tool). Nothing was charged or sent to processing. |
| 404 | Job or tool not found, or it belongs to a different key. |
| 429 | Rate limit exceeded. Follow the Retry-After response header. |
| 500 | Unexpected platform error. Retry or contact support if it persists. |
| 502 | The processing service is temporarily unavailable. Retry. |
Rate limits
Independent per key, in two buckets so polling a job doesn't compete with creating new ones:
| Bucket | Applies to | Limit |
|---|---|---|
| create | POST /api/v1/jobs, POST /api/v1/uploads | 30 / minute |
| read | GET /api/v1/jobs, GET /api/v1/jobs/:id, GET /api/v1/account | 120 / minute |
Every authenticated response includes X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset (Unix seconds) headers. Exceeding a limit returns 429 with a Retry-After header.
Pricing
Base rates come directly from the admin credit system. Full-timeline work bills exact media seconds in 60-second units with a one-unit minimum, then applies the configured resolution and duration-tier modifiers. Probe and thumbnail are flat jobs because they do not process the complete timeline. These values are live and apply equally to the API and platform tools.
| Preset | What it does | Base credits |
|---|---|---|
| custom | Raw ffmpeg args (crop, rotate, trim, loop, speed, etc.) | 30/min |
| probe | Inspect media metadata | 30/job |
| thumbnail | Extract a single frame | 30/job |
| audio-extract | Extract/convert audio track | 30/min |
| fade | Fade audio in and/or out | 30/min |
| aspect-ratio | Pad, crop, or stretch to a target aspect ratio | 30/min |
| watermark | Overlay image/text on video | 30/min |
| transcode | Re-encode video (codec/resolution/bitrate) | 30/min |
| frame-sample | Sample frames at a configurable rate, bundled as a ZIP | 56/min |
Formula: ceil(base × resolution multiplier × billable minutes × duration-tier multiplier). $1 = 100 credits.