Developers
The Transcoder API
Upload source files, get adaptive HLS, captions, thumbnails and downloadable MP4s, all programmatically. Everything the dashboard does is available over a simple REST API.
Base URL
https://api.transcode.procd.cc/api/v1
Introduction
The API is JSON over HTTPS. Successful responses are wrapped in a data field; errors in an error field. All timestamps are ISO-8601. You authenticate with an API key created from your dashboard.
// success{ "data": { /* ... */ } }// error{ "error": { "message": "Human-readable reason" } }
Authentication
Create one or more keys in Dashboard → API keys. A key is shown once on creation, so store it securely. You can set an expiry and delete keys at any time.
Send your key as a header, either way works:
# preferredcurl https://api.transcode.procd.cc/api/v1/video/user-videos \-H "x-api-key: vtk_your_key_here"# or as a bearer tokencurl https://api.transcode.procd.cc/api/v1/video/user-videos \-H "Authorization: Bearer vtk_your_key_here"
Keys inherit your account's permissions and limits. Revoking a key stops it working immediately.
Limits
- · Up to 5 videos per account (lifetime).
- · Up to 1 GB per file.
- · Up to 5 concurrent transcodes.
Need more, or an on-prem deployment? Email hello@ayushsharma.me.
Upload a video
Uploads go straight to object storage via a presigned POST, so bytes never pass through the API. It's a two-step flow.
Step 1: request an upload URL
Query params: fileType (MIME, required), fileName (original name, optional but recommended).
curl "https://api.transcode.procd.cc/api/v1/upload/upload-videos?fileType=video/mp4&fileName=clip.mp4" \-H "x-api-key: $API_KEY"
{"data": {"url": "https://<bucket>.s3.<region>.amazonaws.com","fields": {"Content-Type": "video/mp4","x-amz-meta-userId": "...","bucket": "...","X-Amz-Algorithm": "...","X-Amz-Credential": "...","X-Amz-Date": "...","key": "uploads/<userId>/video-<uuid>","Policy": "...","X-Amz-Signature": "..."}}}
Step 2: POST the file to storage
Send a multipart form to url with every returned field, then the file last. A 204 means success.
# echo each field from the response as -F flags, file lastcurl -X POST "$UPLOAD_URL" \-F key="$KEY" \-F Content-Type="video/mp4" \-F x-amz-meta-userId="$USER_ID" \-F X-Amz-Algorithm="$ALG" \-F X-Amz-Credential="$CRED" \-F X-Amz-Date="$DATE" \-F Policy="$POLICY" \-F X-Amz-Signature="$SIG" \-F file=@clip.mp4
Once uploaded, transcoding starts automatically. Poll the video's status (next sections).
Status lifecycle
A video moves through these states:
signed_url_generated -> upload URL issued, awaiting the fileuploaded -> file received, queuedtranscoding -> ffmpeg is laddering renditions + captionstranscoded -> ready: HLS, MP4 downloads, captions, thumbnailerror -> processing failed
List & fetch videos
curl https://api.transcode.procd.cc/api/v1/video/user-videos -H "x-api-key: $API_KEY"
{"video_id": "0b3a927e-...","s3_key": "uploads/<userId>/video-<uuid>","original_filename": "clip.mp4","status": "transcoded","transcoded_urls": ["<userId>/video-<uuid>/1920x1080_hls/index.m3u8", "..."],"master_playlist_url": "<userId>/video-<uuid>/master.m3u8","is_public": false,"created_at": "2026-06-06T08:00:00.000Z"}
curl "https://api.transcode.procd.cc/api/v1/video/user-video?s3_key=$KEY" -H "x-api-key: $API_KEY"
Thumbnails
Returns a short-lived signed image URL. The first call generates and caches it.
curl "https://api.transcode.procd.cc/api/v1/video/thumbnail?video_id=$ID" -H "x-api-key: $API_KEY"# { "data": { "url": "https://<cdn>/.../thumbnail.jpg?Expires=..." } }
Transcription
Captions are generated automatically. If no speech was detected, available is false.
{"data": {"available": true,"language": "en","languages": ["en"],"cues": [{ "start": 0.0, "end": 2.4, "text": "Hello and welcome." }]}}
Downloads
Get a per-quality MP4 (remuxed on demand) or a zip of all qualities. First mint a short-lived download token, then hit the download endpoint with it.
# 1) mint a token (valid ~10 min)TOKEN=$(curl -s "https://api.transcode.procd.cc/api/v1/video/download-token?video_id=$ID" \-H "x-api-key: $API_KEY" | jq -r .data.token)# 2) download a single quality as MP4curl -L "https://api.transcode.procd.cc/api/v1/download/video?video_id=$ID&quality=1080p&token=$TOKEN" -o clip-1080p.mp4# 3) or all qualities as a zipcurl -L "https://api.transcode.procd.cc/api/v1/download/all?video_id=$ID&token=$TOKEN" -o clip-all.zip
Valid quality values are the video's rendition heights, e.g. 2160p, 1080p, 720p, 360p.
Visibility & embeds
Make a video public to enable embedding. Body: { "video_id": "...", "is_public": true }.
curl -X PATCH https://api.transcode.procd.cc/api/v1/video/visibility \-H "x-api-key: $API_KEY" \-H "Content-Type: application/json" \-d '{"video_id":"'$ID'","is_public":true}'
Once public, embed it anywhere with an iframe:
<iframesrc="https://transcode.procd.cc/embed/<video_id>"width="640" height="360"style="border:0;border-radius:12px"allow="autoplay; fullscreen; picture-in-picture"allowfullscreen></iframe>
Errors
Standard HTTP status codes; the body always carries a message.
400 Bad request / validation error401 Missing, invalid, or expired API key403 Forbidden (e.g. limit reached, not your resource)404 Not found500 Server error
{ "error": { "message": "API key expired" } }
Questions or higher limits? hello@ayushsharma.me