curl --request POST \
--url https://public.reap.video/api/v1/automation/create-reframe \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"sourceUrl": "<string>",
"uploadId": "<string>",
"genre": "talking",
"orientation": "portrait",
"exportResolution": 1080,
"selectedStart": 123,
"selectedEnd": 123,
"disableAutoSplit": false
}
'import requests
url = "https://public.reap.video/api/v1/automation/create-reframe"
payload = {
"sourceUrl": "<string>",
"uploadId": "<string>",
"genre": "talking",
"orientation": "portrait",
"exportResolution": 1080,
"selectedStart": 123,
"selectedEnd": 123,
"disableAutoSplit": False
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
sourceUrl: '<string>',
uploadId: '<string>',
genre: 'talking',
orientation: 'portrait',
exportResolution: 1080,
selectedStart: 123,
selectedEnd: 123,
disableAutoSplit: false
})
};
fetch('https://public.reap.video/api/v1/automation/create-reframe', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://public.reap.video/api/v1/automation/create-reframe",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'sourceUrl' => '<string>',
'uploadId' => '<string>',
'genre' => 'talking',
'orientation' => 'portrait',
'exportResolution' => 1080,
'selectedStart' => 123,
'selectedEnd' => 123,
'disableAutoSplit' => false
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://public.reap.video/api/v1/automation/create-reframe"
payload := strings.NewReader("{\n \"sourceUrl\": \"<string>\",\n \"uploadId\": \"<string>\",\n \"genre\": \"talking\",\n \"orientation\": \"portrait\",\n \"exportResolution\": 1080,\n \"selectedStart\": 123,\n \"selectedEnd\": 123,\n \"disableAutoSplit\": false\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://public.reap.video/api/v1/automation/create-reframe")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"sourceUrl\": \"<string>\",\n \"uploadId\": \"<string>\",\n \"genre\": \"talking\",\n \"orientation\": \"portrait\",\n \"exportResolution\": 1080,\n \"selectedStart\": 123,\n \"selectedEnd\": 123,\n \"disableAutoSplit\": false\n}")
.asString();{
"id": "<string>",
"title": "<string>",
"thumbnail": "<string>",
"billedDuration": 123,
"status": "queued",
"projectType": "clipping",
"source": "Upload",
"genre": "talking",
"topics": [
"<string>"
],
"clipDurations": [
[
123
]
],
"selectedStart": 123,
"selectedEnd": 123,
"exportResolution": 123,
"exportOrientation": "landscape",
"captionsPreset": "<string>",
"enableCaptions": true,
"enableEmojis": true,
"enableHighlights": true,
"language": "<string>",
"dubbingLanguage": "<string>",
"translateTranscription": true,
"translationLanguages": [
"<string>"
],
"transcriptionScript": "native",
"metadata": {
"width": 123,
"height": 123,
"aspectRatio": "<string>",
"size": 123,
"bitrate": 123,
"fps": 123,
"duration": 123,
"rotation": 123,
"resolution": 123,
"codec": "<string>",
"codecFullName": "<string>",
"codecTag": "<string>",
"format": "<string>",
"formatFullName": "<string>"
},
"urls": {
"videoFile": "<string>",
"audioFile": "<string>",
"transcription": "<string>",
"transcription_srt": "<string>",
"transcription_vtt": "<string>",
"transcription_csv": "<string>",
"transcription_txt": "<string>"
},
"createdAt": 123,
"updatedAt": 123
}Create Reframe
Automatically reframe videos for different aspect ratios
curl --request POST \
--url https://public.reap.video/api/v1/automation/create-reframe \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"sourceUrl": "<string>",
"uploadId": "<string>",
"genre": "talking",
"orientation": "portrait",
"exportResolution": 1080,
"selectedStart": 123,
"selectedEnd": 123,
"disableAutoSplit": false
}
'import requests
url = "https://public.reap.video/api/v1/automation/create-reframe"
payload = {
"sourceUrl": "<string>",
"uploadId": "<string>",
"genre": "talking",
"orientation": "portrait",
"exportResolution": 1080,
"selectedStart": 123,
"selectedEnd": 123,
"disableAutoSplit": False
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
sourceUrl: '<string>',
uploadId: '<string>',
genre: 'talking',
orientation: 'portrait',
exportResolution: 1080,
selectedStart: 123,
selectedEnd: 123,
disableAutoSplit: false
})
};
fetch('https://public.reap.video/api/v1/automation/create-reframe', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://public.reap.video/api/v1/automation/create-reframe",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'sourceUrl' => '<string>',
'uploadId' => '<string>',
'genre' => 'talking',
'orientation' => 'portrait',
'exportResolution' => 1080,
'selectedStart' => 123,
'selectedEnd' => 123,
'disableAutoSplit' => false
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://public.reap.video/api/v1/automation/create-reframe"
payload := strings.NewReader("{\n \"sourceUrl\": \"<string>\",\n \"uploadId\": \"<string>\",\n \"genre\": \"talking\",\n \"orientation\": \"portrait\",\n \"exportResolution\": 1080,\n \"selectedStart\": 123,\n \"selectedEnd\": 123,\n \"disableAutoSplit\": false\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://public.reap.video/api/v1/automation/create-reframe")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"sourceUrl\": \"<string>\",\n \"uploadId\": \"<string>\",\n \"genre\": \"talking\",\n \"orientation\": \"portrait\",\n \"exportResolution\": 1080,\n \"selectedStart\": 123,\n \"selectedEnd\": 123,\n \"disableAutoSplit\": false\n}")
.asString();{
"id": "<string>",
"title": "<string>",
"thumbnail": "<string>",
"billedDuration": 123,
"status": "queued",
"projectType": "clipping",
"source": "Upload",
"genre": "talking",
"topics": [
"<string>"
],
"clipDurations": [
[
123
]
],
"selectedStart": 123,
"selectedEnd": 123,
"exportResolution": 123,
"exportOrientation": "landscape",
"captionsPreset": "<string>",
"enableCaptions": true,
"enableEmojis": true,
"enableHighlights": true,
"language": "<string>",
"dubbingLanguage": "<string>",
"translateTranscription": true,
"translationLanguages": [
"<string>"
],
"transcriptionScript": "native",
"metadata": {
"width": 123,
"height": 123,
"aspectRatio": "<string>",
"size": 123,
"bitrate": 123,
"fps": 123,
"duration": 123,
"rotation": 123,
"resolution": 123,
"codec": "<string>",
"codecFullName": "<string>",
"codecTag": "<string>",
"format": "<string>",
"formatFullName": "<string>"
},
"urls": {
"videoFile": "<string>",
"audioFile": "<string>",
"transcription": "<string>",
"transcription_srt": "<string>",
"transcription_vtt": "<string>",
"transcription_csv": "<string>",
"transcription_txt": "<string>"
},
"createdAt": 123,
"updatedAt": 123
}
For AI agents: a documentation index is at /llms.txt. Every page is also available as markdown, just append .md to the URL.
Overview
Automatically reframe videos from landscape to portrait or square formats using AI. Perfect for adapting content for TikTok, Instagram Stories, and other vertical video platforms. You must provide eithersourceUrl (a web video URL, e.g. YouTube) or uploadId (a previously uploaded file), but not both. Use selectedStart / selectedEnd to reframe just a window of a longer video — only the selected window is billed.
Rate Limiting
This endpoint is rate limited to 10 requests per minute per API key.Video Requirements
Selection Window
Maximum: 10 minutes
The source video itself can be longer — select a window with
selectedStart / selectedEnd.File Size
Format
Source Format
Plan Limits
| Plan | Concurrent Projects | Max Resolution |
|---|---|---|
| Creator | 3 | 1080p |
| Studio | 10 | 4K (2160p) |
Response
processing- Video is being analyzed and reframedcompleted- Reframing completed successfullyfailed- Processing failed due to an error
Example Request
curl -X POST "https://public.reap.video/api/v1/automation/create-reframe" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"uploadId": "65f1a2b3c4d5e6f7a8b9c0d1",
"genre": "talking",
"orientation": "portrait",
"disableAutoSplit": false
}'
const response = await fetch('https://public.reap.video/api/v1/automation/create-reframe', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
uploadId: '65f1a2b3c4d5e6f7a8b9c0d1',
genre: 'talking',
orientation: 'portrait',
disableAutoSplit: false
})
});
const project = await response.json();
console.log('Reframe project created:', project.id);
import requests
headers = {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
}
data = {
'uploadId': '65f1a2b3c4d5e6f7a8b9c0d1',
'genre': 'talking',
'orientation': 'square',
'disableAutoSplit': False
}
response = requests.post(
'https://public.reap.video/api/v1/automation/create-reframe',
headers=headers,
json=data
)
project = response.json()
print(f'Reframe project created: {project["id"]}')
<?php
$data = [
'uploadId' => '65f1a2b3c4d5e6f7a8b9c0d1',
'genre' => 'talking',
'orientation' => 'portrait',
'disableAutoSplit' => false
];
$ch = curl_init('https://public.reap.video/api/v1/automation/create-reframe');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer YOUR_API_KEY',
'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$project = json_decode($response, true);
echo 'Reframe project created: ' . $project['id'] . "\n";
?>
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
func main() {
url := "https://public.reap.video/api/v1/automation/create-reframe"
data := map[string]interface{}{
"uploadId": "65f1a2b3c4d5e6f7a8b9c0d1",
"genre": "talking",
"orientation": "portrait",
"disableAutoSplit": false,
}
payload, _ := json.Marshal(data)
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(payload))
req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println(string(body))
}
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
public class CreateReframeExample {
public static void main(String[] args) throws Exception {
URL url = new URL("https://public.reap.video/api/v1/automation/create-reframe");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Authorization", "Bearer YOUR_API_KEY");
conn.setRequestProperty("Content-Type", "application/json");
conn.setDoOutput(true);
String jsonInputString = "{\"uploadId\":\"65f1a2b3c4d5e6f7a8b9c0d1\",\"genre\":\"talking\",\"orientation\":\"portrait\",\"disableAutoSplit\":false}";
try (OutputStream os = conn.getOutputStream()) {
os.write(jsonInputString.getBytes("utf-8"));
}
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
StringBuilder response = new StringBuilder();
String responseLine;
while ((responseLine = br.readLine()) != null) {
response.append(responseLine.trim());
}
System.out.println("Reframe project created: " + response.toString());
}
}
Example Response
Processing Workflow
- Upload Analysis - Video is analyzed for speakers, objects, and key visual elements
- Smart Cropping - AI automatically crops and reframes to keep important content in view
- Motion Tracking - Follows speakers and maintains optimal framing throughout the video
- Segmentation - Optionally splits longer videos into optimal segments (unless disabled)
- Output Generation - Creates reframed video in the target aspect ratio
Reframing Features
- Speaker Tracking: Automatically follows speakers and keeps them centered
- Object Recognition: Identifies and tracks important visual elements
- Smart Cropping: Maintains optimal composition throughout the video
- Smooth Transitions: Ensures natural camera movements between focus points
- Auto-Segmentation: Intelligently splits content into engaging segments
Use Cases
Multi-Platform Distribution
Content Management Systems
Video Hosting Platforms
Marketing Automation
Best Practices
- Source Quality: Use high-resolution landscape videos for best results
- Speaker Positioning: Videos with centered speakers reframe more effectively
- Content Type: Works best with talking head videos and presentations
- Duration: Shorter videos (under 5 minutes) process faster and more accurately
Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Body
Video URL to process, e.g. a YouTube link (alternative to uploadId)
Upload ID from a previously uploaded file (alternative to sourceUrl)
Video genre for better AI analysis
talking, screenshare, gaming Target orientation
portrait, square Output resolution for the reframed video. Resolutions above 1080 require a Studio plan. Capped at the source's actual resolution.
720, 1080, 1440, 2160 Start time in seconds of the window to reframe (defaults to the start of the video)
End time in seconds of the window to reframe (defaults to the end of the video). The selected window must be between 3 seconds and 10 minutes; only the window is billed.
Whether to disable automatic splitting into segments
Response
Successful response
queued, prepped, draft, processing, finalizing, completed, invalid, expired, failed, error clipping, captions, reframe, dubbing, transcription Upload, Youtube, Vimeo, TwitchVod, Twitter, RumbleEmbed, Generic talking, screenshare, gaming landscape, portrait, square native, roman Show child attributes
Show child attributes
Presigned URLs for the project's assets. URLs expire — always use the most recent API response. The transcription_* subtitle/text exports are only present on transcription projects.
Show child attributes
Show child attributes
Was this page helpful?