Quickstart Guide

Run your first FFmpeg API request

This guide walks through a complete workflow — from upload to finished output — so you can make your first request and see how the pieces connect.

Before you begin

Make sure you have these ready before running your first request.

  • 1.
    API key — Get yours from the API Keys page in your dashboard.
  • 2.
    A sample video file — Any MP4, MOV, or WebM file works. We'll use video.mp4 in the examples below.
  • 3.
    Somewhere to store the output — Your processed video gets stored in a Google Cloud Storage bucket tied to your account. You'll download it via a signed URL.
  • 4.
    (Optional) Webhook URL — If you want the API to notify you when jobs finish instead of polling, set up a webhook endpoint. See the webhooks guide.

Step 1: Authenticate your request

Every API request needs your key in the Authorization header.

Set the header like this on every request:

Authorization: Bearer YOUR_API_KEY

Replace YOUR_API_KEY with your actual key. The API returns 401 Unauthorized if the key is missing or invalid.

Step 2: Submit a job

Upload your video and create a processing job. The workflow is: request upload URL → upload file → confirm upload → create transcode job.

2a. Request a presigned upload URL
Ask the API for a secure URL where you can upload your file.

Request

POST https://api.ffmpeg-micro.com/v1/upload/presigned-url
Content-Type: application/json
Authorization: Bearer YOUR_API_KEY

{
  "filename": "video.mp4",
  "contentType": "video/mp4",
  "fileSize": 12345678
}

Response

{
  "success": true,
  "result": {
    "uploadUrl": "https://storage.googleapis.com/...",
    "filename": "1234567890-video.mp4"
  }
}

Note: fileSize must be a number (bytes), not a string. The API returns 400 if you send "12345678" instead of 12345678.

2b. Upload the file
Use the presigned URL to upload your video. No API key needed for this step.

Request

PUT https://storage.googleapis.com/...
Content-Type: video/mp4

<binary file data>

Send the file as binary data in the request body. The presigned URL expires after 10 minutes.

2c. Confirm the upload
Tell the API the upload is done so it can verify the file exists and matches what you declared.

Request

POST https://api.ffmpeg-micro.com/v1/upload/confirm
Content-Type: application/json
Authorization: Bearer YOUR_API_KEY

{
  "filename": "1234567890-video.mp4",
  "fileSize": 12345678
}

Response

{
  "success": true,
  "result": {
    "fileUrl": "gs://your-bucket/1234567890-video.mp4",
    "downloadUrl": "https://storage.googleapis.com/..."
  }
}

Save the fileUrl — you'll need it to create the transcode job.

2d. Create a transcode job
Submit the processing job with your desired output format and settings.

Request

POST https://api.ffmpeg-micro.com/v1/transcodes
Content-Type: application/json
Authorization: Bearer YOUR_API_KEY

{
  "inputs": [
    { "url": "gs://your-bucket/1234567890-video.mp4" }
  ],
  "outputFormat": "mp4",
  "preset": {
    "quality": "medium",
    "resolution": "1080p"
  }
}

Response

{
  "id": "abc123-job-uuid",
  "status": "pending",
  "inputs": [
    { "url": "gs://your-bucket/1234567890-video.mp4" }
  ],
  "output_format": "mp4",
  "created_at": "2026-05-08T12:00:00Z"
}

The job starts as pending and moves to processing when a worker picks it up. Save the id — you'll use it to check status.

Step 3: Check job status or wait for webhook

Jobs run asynchronously. You can poll for status or set up a webhook to get notified when they finish.

Option A: Poll for status
Make a GET request every few seconds until status changes to completed or failed.

Request

GET https://api.ffmpeg-micro.com/v1/transcodes/abc123-job-uuid
Authorization: Bearer YOUR_API_KEY

Response (while processing)

{
  "success": true,
  "jobId": "abc123-job-uuid",
  "status": "processing",
  "createdAt": "2026-05-08T12:00:00Z"
}

Response (completed)

{
  "success": true,
  "jobId": "abc123-job-uuid",
  "status": "completed",
  "outputUrl": "gs://output-bucket/processed-video.mp4",
  "createdAt": "2026-05-08T12:00:00Z",
  "completedAt": "2026-05-08T12:02:30Z"
}
Option B: Use webhooks
The API can POST to your endpoint when jobs finish. No polling needed.

Add a webhookUrl field to your transcode request:

{
  "inputs": [{ "url": "gs://your-bucket/1234567890-video.mp4" }],
  "outputFormat": "mp4",
  "webhookUrl": "https://your-app.com/webhooks/ffmpeg"
}

When the job finishes, the API sends a POST to your webhook with the final job state. See webhook docs for payload format and retry behavior.

Step 4: Retrieve the completed output

Once the job is completed, download your processed video.

Request a download URL

GET https://api.ffmpeg-micro.com/v1/transcodes/abc123-job-uuid/download
Authorization: Bearer YOUR_API_KEY

Response

{
  "url": "https://storage.googleapis.com/...?X-Goog-Signature=..."
}

Download the file

curl -o output.mp4 "https://storage.googleapis.com/...?X-Goog-Signature=..."

The signed URL expires after 10 minutes. If it expires, just call /download again to get a fresh one.

Copy-paste examples

Complete working examples in curl, Node.js, and Python. Replace YOUR_API_KEY and run.

Full workflow in curl
#!/bin/bash
API_KEY="YOUR_API_KEY"
API_URL="https://api.ffmpeg-micro.com"
VIDEO_FILE="video.mp4"
FILE_SIZE=$(stat -f%z "$VIDEO_FILE")  # macOS; use -c%s on Linux

# Step 1: Request presigned upload URL
UPLOAD_RESPONSE=$(curl -s -X POST "$API_URL/v1/upload/presigned-url" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"filename\": \"$VIDEO_FILE\", \"contentType\": \"video/mp4\", \"fileSize\": $FILE_SIZE}")

UPLOAD_URL=$(echo "$UPLOAD_RESPONSE" | jq -r '.result.uploadUrl')
FILENAME=$(echo "$UPLOAD_RESPONSE" | jq -r '.result.filename')

echo "Upload URL: $UPLOAD_URL"
echo "Filename: $FILENAME"

# Step 2: Upload the file
curl -X PUT "$UPLOAD_URL" \
  -H "Content-Type: video/mp4" \
  --data-binary "@$VIDEO_FILE"

# Step 3: Confirm upload
CONFIRM_RESPONSE=$(curl -s -X POST "$API_URL/v1/upload/confirm" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"filename\": \"$FILENAME\", \"fileSize\": $FILE_SIZE}")

FILE_URL=$(echo "$CONFIRM_RESPONSE" | jq -r '.result.fileUrl')
echo "File URL: $FILE_URL"

# Step 4: Create transcode job
JOB_RESPONSE=$(curl -s -X POST "$API_URL/v1/transcodes" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"inputs\": [{\"url\": \"$FILE_URL\"}], \"outputFormat\": \"mp4\", \"preset\": {\"quality\": \"medium\", \"resolution\": \"1080p\"}}")

JOB_ID=$(echo "$JOB_RESPONSE" | jq -r '.id')
echo "Job ID: $JOB_ID"

# Step 5: Poll for completion
while true; do
  STATUS_RESPONSE=$(curl -s "$API_URL/v1/transcodes/$JOB_ID" \
    -H "Authorization: Bearer $API_KEY")
  STATUS=$(echo "$STATUS_RESPONSE" | jq -r '.status')
  echo "Status: $STATUS"

  if [ "$STATUS" = "completed" ]; then
    break
  elif [ "$STATUS" = "failed" ]; then
    echo "Job failed"
    exit 1
  fi

  sleep 3
done

# Step 6: Download output
DOWNLOAD_RESPONSE=$(curl -s "$API_URL/v1/transcodes/$JOB_ID/download" \
  -H "Authorization: Bearer $API_KEY")

DOWNLOAD_URL=$(echo "$DOWNLOAD_RESPONSE" | jq -r '.url')
curl -o "output.mp4" "$DOWNLOAD_URL"

echo "Download complete: output.mp4"

Common errors and how to fix them

These are the errors people hit most often when making their first request.

401 Unauthorized

Cause: Missing or invalid API key.

Fix: Check that you're sending Authorization: Bearer YOUR_API_KEY on every request. Make sure the key is active and hasn't been deleted.

400 Bad Request: fileSize must be a number

Cause: You sent "fileSize": "12345678" (string) instead of "fileSize": 12345678 (number).

Fix: Send file size as a JSON number, not a quoted string. Same for any byte count field.

400 Bad Request: Unsupported input format

Cause: You tried to upload a file type the API doesn't support (e.g., .avi with an obscure codec).

Fix: Check supported input formats. MP4, MOV, WebM, and MKV work for most cases.

400 Bad Request: Invalid output destination

Cause: You set an outputUrl pointing to a bucket or path the API can't write to.

Fix: Leave outputUrl blank to use the default output bucket. If you need a custom bucket, make sure it's configured in your account settings.

422 Unprocessable Entity: Malformed request payload

Cause: Invalid JSON or missing required fields (e.g., no inputs array).

Fix: Check the request body matches the API docs. Use a JSON validator to catch syntax errors.

Webhook not firing

Cause: Your webhook URL is unreachable, returns an error status, or times out.

Fix: Make sure the webhook endpoint is publicly accessible and returns 200 OK within 10 seconds. Check your server logs for incoming POST requests. See webhook docs for retry behavior.

Where to go next

You've made your first request. Here's what to explore next.

Ready to process your first video?

Sign up for a free account and get 100 minutes of processing time. No credit card required.