---
name: Rendi
description: Use when building video processing workflows, automating FFmpeg commands at scale, generating thumbnails, transcoding, trimming, merging, extracting audio, burning subtitles, or overlaying watermarks. Reach for Rendi when you need to run FFmpeg commands without managing servers or installation.
metadata:
    mintlify-proj: rendi
    version: "1.0"
---

# Rendi Skill

Rendi is a cloud FFmpeg API that runs FFmpeg commands without installation or server management. Submit an FFmpeg command via HTTP, Rendi processes it on auto-scaling infrastructure, and returns the output files. All examples use REST endpoints; you can call them from Python, Node.js, cURL, or no-code platforms like Make, n8n, and Zapier.

## Product summary

Rendi is FFmpeg as a Service — a REST API for running FFmpeg commands in the cloud. Send a command with input file URLs and output file names; Rendi processes it and stores results on its CDN. Key files and endpoints:

- **API base**: `https://api.rendi.dev/v1`
- **Authentication**: `X-API-KEY` header (get from https://app.rendi.dev/sign-up)
- **Core endpoints**: `/run-ffmpeg-command`, `/run-chained-ffmpeg-commands`, `/commands/{id}`, `/files/*`
- **File naming**: Input keys use `in_*` prefix (e.g., `in_1`, `in_video`); output keys use `out_*` prefix (e.g., `out_1`, `out_gif`). Reference them as `{{in_1}}` / `{{out_1}}` placeholders in the FFmpeg command.
- **Docs**: https://rendi.dev/docs
- **OpenAPI spec**: https://www.rendi.dev/docs/api-reference/openapi.json
- **FFmpeg cheatsheet**: https://github.com/rendi-api/ffmpeg-cheatsheet

## When to use

Reach for Rendi when:

- **Building video processing workflows** — thumbnails, transcoding, trimming, merging, audio extraction, subtitle burning, watermarking
- **Scaling FFmpeg without infrastructure** — no Docker, no server management, no installation headaches
- **Integrating with automation platforms** — Make, n8n, Zapier, or custom code (Python, Node.js, etc.)
- **Processing long videos or long-running jobs** — no time limits, no video length limits
- **Chaining multiple FFmpeg operations** — use chained commands to reduce latency and round-trips
- **Working with dynamic inputs/outputs** — image sequences, HLS playlists, compressed folders, multi-file outputs
- **Agents building video features** — MCP server available for Claude Code, Cursor, VS Code Copilot, Codex, Gemini CLI

Do not use Rendi for: real-time streaming, local file processing (Rendi needs HTTP-accessible URLs), or operations that don't involve FFmpeg.

## Quick reference

### API Request Structure

```json
{
  "input_files": {
    "in_1": "https://example.com/video.mp4",
    "in_2": "https://example.com/audio.mp3"
  },
  "output_files": {
    "out_1": "output.mp4"
  },
  "ffmpeg_command": "-i {{in_1}} -i {{in_2}} -c:v libx264 -c:a aac {{out_1}}",
  "vcpu_count": 8,
  "max_command_run_seconds": 300,
  "metadata": {"key": "value"}
}
```

### Essential Endpoints

| Endpoint | Method | Purpose |
|----------|--------|---------|
| `/run-ffmpeg-command` | POST | Submit a single FFmpeg command |
| `/run-chained-ffmpeg-commands` | POST | Submit multiple commands; outputs from earlier steps feed later ones |
| `/commands/{command_id}` | GET | Poll command status (QUEUED → PROCESSING → SUCCESS/FAILED) |
| `/commands` | GET | List all commands |
| `/files/store-file` | POST | Store intermediate files or probe input files with FFprobe |
| `/files/{file_id}` | GET | Retrieve file metadata and status |
| `/files/{file_id}` | DELETE | Delete a stored file |
| `/commands/{command_id}/files` | DELETE | Delete all output files from a command |

### File Naming Rules

- **Input keys**: Must start with `in_` (e.g., `in_1`, `in_video`, `in_audio`)
- **Output keys**: Must start with `out_` (e.g., `out_1`, `out_gif`, `out_mp4`)
- **Placeholders in command**: Use `{{in_1}}`, `{{out_1}}` (double curly braces)
- **Output file names**: Alphanumeric + underscores + period for extension (e.g., `output_1.mp4`)
- **Special flag**: Use `"output_files": "OUTPUT_FOLDER"` to create a compressed ZIP of all outputs

### Common FFmpeg Patterns

| Task | Command Pattern |
|------|-----------------|
| Generate thumbnail | `-i {{in_1}} -ss 00:00:17 -vframes 1 {{out_1}}` |
| Extract audio | `-i {{in_1}} -q:a 0 -map a {{out_1}}` |
| Trim clip | `-i {{in_1}} -ss 00:00:10 -to 00:00:30 -c copy {{out_1}}` |
| Merge videos | `-f concat -safe 0 -i list.txt -c copy {{out_1}}` (requires concat demuxer) |
| Compress video | `-i {{in_1}} -crf 28 -c:a aac -b:a 128k {{out_1}}` |
| Transcode | `-i {{in_1}} -c:v libx264 -c:a aac {{out_1}}` |
| Burn subtitles | `-i {{in_1}} -vf subtitles={{in_2}} {{out_1}}` |
| Overlay watermark | `-i {{in_1}} -i {{in_2}} -filter_complex overlay=10:10 {{out_1}}` |

### Input URL Sources

Any publicly accessible HTTP/HTTPS URL works:
- Google Drive share links (public or signed)
- Dropbox public links
- S3 (public or signed URLs)
- Google Cloud Storage (public or signed URLs)
- Rendi storage URLs (from previous commands)
- Any CDN or web server

### Response Fields (on SUCCESS)

```json
{
  "command_id": "uuid",
  "status": "SUCCESS",
  "total_processing_seconds": 8.5,
  "ffmpeg_command_run_seconds": 5.2,
  "vcpu_count": 8,
  "output_files": {
    "out_1": {
      "file_id": "uuid",
      "storage_url": "https://storage.rendi.dev/...",
      "size_mbytes": 1.5,
      "file_type": "video",
      "file_format": "mp4",
      "width": 1920,
      "height": 1080,
      "duration": 10.5
    }
  }
}
```

## Decision guidance

### When to use polling vs webhooks

| Scenario | Use | Why |
|----------|-----|-----|
| Job expected < 30 seconds | Polling (`GET /commands/{id}`) | Lower latency, simpler code |
| Job expected > 30 seconds | Webhooks | Eliminates polling overhead; Rendi calls your endpoint when done |
| Real-time feedback needed | Polling | Webhooks only fire on completion |
| Serverless/stateless context | Webhooks | Polling requires persistent connection |

**Webhook setup**: Configure in dashboard → Configuration tab. Rendi retries on failure (5s, 5m, 30m, 2h, 5h, 10h, 10h). Endpoint must respond within 15 seconds.

### When to use chained commands vs separate calls

| Scenario | Use | Why |
|----------|-----|-----|
| Multi-step pipeline (e.g., trim → compress → watermark) | Chained commands | Single round-trip, lower latency, outputs auto-feed |
| Independent operations | Separate calls | Simpler logic, easier to retry individual steps |
| Need intermediate file storage | Separate calls + `store-file` | Chained commands don't persist intermediates |

### When to use compressed folders vs individual files

| Scenario | Use | Why |
|----------|-----|-----|
| Single input/output | Individual files | Simpler, faster |
| Image sequences, HLS playlists, custom fonts | `input_compressed_folder` | FFmpeg needs multiple files; ZIP handles it |
| Multi-file output (e.g., frame extraction) | `"output_files": "OUTPUT_FOLDER"` | Automatically zips all outputs |

## Workflow

### Typical task: Generate a thumbnail from a video

1. **Prepare inputs**: Identify the video URL (must be publicly accessible HTTP/HTTPS). If using Google Drive, get a shareable link.

2. **Construct the request**:
   - Set `input_files` with key `in_1` pointing to the video URL
   - Set `output_files` with key `out_1` as the output filename (e.g., `thumbnail.jpg`)
   - Write the FFmpeg command using `{{in_1}}` and `{{out_1}}` placeholders
   - Set `max_command_run_seconds` to a safe value (default 300s is fine for thumbnails)

3. **Submit the command**:
   ```bash
   curl -X POST https://api.rendi.dev/v1/run-ffmpeg-command \
     -H "X-API-KEY: <your-key>" \
     -H "Content-Type: application/json" \
     -d '{
       "input_files": {"in_1": "https://example.com/video.mp4"},
       "output_files": {"out_1": "thumbnail.jpg"},
       "ffmpeg_command": "-i {{in_1}} -ss 00:00:17 -vframes 1 {{out_1}}"
     }'
   ```

4. **Poll for completion**:
   ```bash
   curl https://api.rendi.dev/v1/commands/<command_id> \
     -H "X-API-KEY: <your-key>"
   ```
   Check `status` field. Loop every 2 seconds until `SUCCESS` or `FAILED`.

5. **Retrieve output**: When status is `SUCCESS`, the response includes `output_files.out_1.storage_url`. Download or serve directly from Rendi's CDN.

6. **Clean up (optional)**: Delete files using `/commands/{command_id}/files` or `/files/{file_id}` if you don't need them stored.

### Typical task: Multi-step pipeline (trim → compress → watermark)

1. **Use chained commands** instead of three separate calls:
   ```json
   {
     "commands": [
       {
         "input_files": {"in_1": "https://example.com/video.mp4"},
         "output_files": {"out_1": "trimmed.mp4"},
         "ffmpeg_command": "-i {{in_1}} -ss 00:00:10 -to 00:00:30 -c copy {{out_1}}"
       },
       {
         "input_files": {"in_1": "{{PREVIOUS_COMMAND.out_1}}"},
         "output_files": {"out_1": "compressed.mp4"},
         "ffmpeg_command": "-i {{in_1}} -crf 28 -c:a aac {{out_1}}"
       },
       {
         "input_files": {"in_1": "{{PREVIOUS_COMMAND.out_1}}", "in_2": "https://example.com/logo.png"},
         "output_files": {"out_1": "final.mp4"},
         "ffmpeg_command": "-i {{in_1}} -i {{in_2}} -filter_complex overlay=10:10 {{out_1}}"
       }
     ]
   }
   ```

2. **Submit to `/run-chained-ffmpeg-commands`** and poll once. All three steps run in sequence; outputs from earlier steps feed later ones automatically.

## Common gotchas

- **Forgetting `in_` / `out_` prefixes**: Keys must start with these prefixes. `input_1` will fail; use `in_1`.

- **Curly bracket escaping in automation platforms**: If using Make, Zapier, or n8n, escape placeholders: `\\{\\{in_1\\}\\}` instead of `{{in_1}}`.

- **Input URLs must be publicly accessible**: Rendi can't fetch private files. Use signed URLs (S3, GCS) or public share links (Google Drive, Dropbox).

- **Not setting `max_command_run_seconds` for long jobs**: Default is 300s (5 minutes). For longer jobs, set it explicitly. Check your plan for the maximum allowed.

- **Polling too aggressively**: Poll every 2–5 seconds, not every 100ms. Use webhooks for jobs over ~30 seconds.

- **Forgetting to handle FAILED status**: Always check for `status: "FAILED"` and read `error_status` / `error_message` fields.

- **Using `input_compressed_folder` with `input_files` together**: Don't mix them. If using a ZIP, put all inputs in the ZIP and use only `input_compressed_folder`.

- **Assuming output files are deleted automatically**: Output files persist indefinitely. Delete them explicitly if you don't need them.

- **Not escaping special characters in FFmpeg filters**: Quotes and backslashes in filter strings need careful escaping in JSON. Test with cURL first.

- **Chained commands with wrong placeholder syntax**: Use `{{PREVIOUS_COMMAND.out_1}}` (not `{{out_1}}`) to reference outputs from earlier steps in a chain.

## Verification checklist

Before submitting a Rendi request:

- [ ] API key is set in `X-API-KEY` header and kept server-side (never in browser code)
- [ ] Input file URLs are publicly accessible (test in incognito browser)
- [ ] Input keys start with `in_` and output keys start with `out_`
- [ ] FFmpeg command uses `{{in_*}}` and `{{out_*}}` placeholders (double braces)
- [ ] Output file names contain only alphanumeric, underscores, and period for extension
- [ ] `max_command_run_seconds` is set appropriately for the expected runtime
- [ ] For chained commands, later steps reference earlier outputs with `{{PREVIOUS_COMMAND.out_*}}`
- [ ] Webhook URL (if used) is configured in dashboard and responds within 15 seconds
- [ ] Response status is checked for `SUCCESS` or `FAILED` before using output files
- [ ] Output files are deleted if no longer needed (to avoid storage costs)

## Resources

- **Comprehensive page index**: https://www.rendi.dev/docs/llms.txt
- **Full documentation**: https://rendi.dev/docs
- **OpenAPI specification** (canonical request/response schema): https://www.rendi.dev/docs/api-reference/openapi.json
- **FFmpeg cheatsheet** (canonical patterns for common operations): https://github.com/rendi-api/ffmpeg-cheatsheet
- **MCP server** (for Claude Code, Cursor, VS Code Copilot): https://www.rendi.dev/docs/mcp
- **System status**: https://status.rendi.dev

---

> For additional documentation and navigation, see: https://rendi.dev/docs/llms.txt