Introduction
The ProperVid API lets you programmatically create professional property marketing videos from images. Upload your property photos, provide a description, and the API generates a polished video with AI voiceover, background music, and captions.
Base URL
https://www.propervid.io/api/v1Version
v1Content Type
application/jsonAll requests and responses use JSON. Provide an Authorization header with your API key on every request.
Video generation is asynchronous — you submit a job and poll for completion, or configure a webhook to be notified when your video is ready.
Use the dashboard to create reusable templates, design brand kit end frames, and connect social media accounts for automatic posting — then reference them in your API calls.
Authentication
All API requests require a Bearer token in the Authorization header. API keys are generated from your dashboard under Settings.
Authorization: Bearer vg_live_your_api_key_hereExample Request
curl https://www.propervid.io/api/v1/health \
-H "Authorization: Bearer vg_live_abc123..."Response
{
"status": "ok",
"timestamp": "2025-02-07T12:00:00.000Z",
"version": "1.0.0",
"database": "configured"
}Warning
Quick Start
Create your first property video in 3 steps. Provide your listing photos and a description, and ProperVid generates a professional marketing video with AI voiceover and music.
Step 1: Create a Property Video
Submit your property images and listing description. ProperVid generates the voiceover, sequences the images, and starts video processing.
curl -X POST https://www.propervid.io/api/v1/properties \
-H "Authorization: Bearer vg_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"images": [
{ "url": "https://example.com/front.jpg" },
{ "url": "https://example.com/living.jpg" },
{ "url": "https://example.com/kitchen.jpg" },
{ "url": "https://example.com/bedroom.jpg" },
{ "url": "https://example.com/garden.jpg" }
],
"productDescription": "Stunning 4-bedroom family home at 12 Oak Avenue. Open-plan kitchen and living area, landscaped garden, two bathrooms, double garage.",
"voiceId": "eldrin"
}'Returns a jobId immediately (HTTP 202). Video processing continues in the background (~2-8 minutes).
Tip
front-exterior.jpg) and labels improve matching accuracy, but the AI will work with unlabelled images too.Step 2: Poll for Completion
Poll the job status endpoint. The response includes retryAfter to tell you how long to wait before the next poll.
curl https://www.propervid.io/api/v1/properties/YOUR_JOB_ID \
-H "Authorization: Bearer vg_live_your_key"Response (processing)
{
"id": "708a3c36-...",
"status": "processing",
"progress": 45,
"retryAfter": 30,
"estimatedCompletionAt": "2025-02-07T19:44:00.000Z"
}Step 3: Download Your Video
When status is "completed", the response includes download URLs for each output format.
{
"id": "708a3c36-...",
"status": "completed",
"progress": 100,
"outputs": {
"landscape": {
"url": "https://blob.vercel-storage.com/videos/708a3c36-.../landscape.mp4",
"size": 10969861
},
"srt": {
"url": "https://blob.vercel-storage.com/videos/708a3c36-.../captions.srt"
}
},
"createdAt": "2025-02-07T19:36:14.124Z",
"completedAt": "2025-02-07T19:38:28.343Z"
}Polling Example
async function waitForVideo(jobId, apiKey) {
const headers = { Authorization: `Bearer ${apiKey}` };
while (true) {
const res = await fetch(
`https://www.propervid.io/api/v1/properties/${jobId}`,
{ headers }
);
const job = await res.json();
if (job.status === "completed") return job.outputs;
if (job.status === "failed") throw new Error(job.error.message);
// Wait the recommended interval
const wait = (job.retryAfter || 30) * 1000;
await new Promise(r => setTimeout(r, wait));
}
}Tip
Optional: Save a Template
Save your preferred voice, music, and output settings as a reusable template. Pass the template ID as presetId when creating videos to apply your saved configuration automatically.
curl -X POST https://www.propervid.io/api/v1/templates \
-H "Authorization: Bearer vg_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"name": "Luxury Property Tour",
"config": {
"voiceId": "eldrin",
"voiceEmotion": "warm",
"backgroundMusic": { "trackId": "apricity", "volume": 20 },
"captions": { "enabled": true },
"outputs": {
"landscape": { "enabled": true, "resolution": "1080p" }
}
}
}'Then use the template: "presetId": "YOUR_TEMPLATE_ID" in your video creation requests. See Templates for full details.
Property Videos
Submit your listing photos and a description, and ProperVid handles the rest — AI vision analyses each image, generates a professional voiceover script, sequences your images, and produces a polished video.
Endpoints
/api/v1/properties/api/v1/properties/api/v1/properties/:jobId/api/v1/properties/:jobId/api/v1/properties
Create a property video with AI-generated voiceover, background music, and professional timing.
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
images | array | Required | Property images (1-40) |
images[].url | string | Required | Image URL |
images[].label | string | Optional | Short description of the image. If omitted, ProperVid uses AI vision to identify image contents automatically. |
imageOrder | number[] | Optional | Display order as array of image indices. Defaults to the order provided. |
productDescription | string | Required | Property listing description (max 50000 chars) |
contentType | enum | Optional | Content type (see categories below) |
scriptStyle | enum | Optional | punchy (short, snappy), flowery (eloquent), factual (direct) |
language | enum | Optional | en, fr, es, or ro |
voiceId | string | Optional | Voice ID (see Voices reference). Required unless provided by preset. |
voiceEmotion | enum | Optional | neutral, warm, energetic, calm, cheerful |
backgroundMusicUrl | string | Optional | Background music URL or relative path |
backgroundMusicVolume | number | Optional | Music volume (0-100) |
outputs | object | Optional | At least one output format (landscape, square, portrait). Defaults to landscape 1080p if not provided by request or preset. |
scalingMode | enum | Optional | cover or blur-fill |
captions | object | Optional | { enabled: boolean, textColor: '#FFFFFF', highlightColor: '#FFD700' } |
endFrame | object | Optional | { brandKitId: 'uuid' } — Reference a brand kit created in the dashboard, or pass { enabled: true, logoUrl, website, phone } to generate on the fly |
motionEffect | enum | Optional | Motion applied to images: zoom (slow zoom in), zoomOut (slow zoom out), kenBurns (cinematic zoom & pan) |
webhookUrl | string | Optional | Webhook URL for completion notification |
presetId | uuid | Optional | Template ID — merges saved config (per-call values override) |
externalId | string | Optional | Your reference ID (max 255 chars) |
customerMetadata | object | Optional | Custom key-value data |
Categories
real_estateholiday_rentalhotel_roomvenueboatcarmotorhomejewellerywatchart_antiqueproductgeneralResponse (202 Accepted)
{
"success": true,
"jobId": "708a3c36-1965-44ab-82fc-9c79a2ac8d37",
"status": "pending",
"script": "Presenting this stunning four-bedroom family home...",
"estimatedDuration": 36.5
}Info
jobId to poll for the video output via GET /api/v1/properties/:jobId, or configure a webhook to be notified on completion./api/v1/properties
List recent video jobs for the authenticated user.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
limit | number | Optional | Max results to return (1-100) |
offset | number | Optional | Number of results to skip (for pagination) |
externalId | string | Optional | Filter by your external reference ID |
Response (200 OK)
{
"jobs": [
{
"id": "708a3c36-1965-44ab-82fc-9c79a2ac8d37",
"status": "completed",
"progress": 100,
"landscapeUrl": "https://blob.vercel-storage.com/videos/.../landscape.mp4",
"createdAt": "2025-02-07T19:36:14.124Z",
"completedAt": "2025-02-07T19:38:28.343Z"
}
],
"limit": 20,
"offset": 0
}/api/v1/properties/:jobId
Get the status and outputs of a single video job.
Response (200 OK — processing)
{
"id": "708a3c36-...",
"status": "processing",
"progress": 45,
"retryAfter": 30,
"estimatedCompletionAt": "2025-02-07T19:44:00.000Z"
}Response (200 OK — completed)
{
"id": "708a3c36-...",
"status": "completed",
"progress": 100,
"outputs": {
"landscape": {
"url": "https://blob.vercel-storage.com/videos/.../landscape.mp4",
"size": 10969861
},
"srt": {
"url": "https://blob.vercel-storage.com/videos/.../captions.srt"
}
},
"createdAt": "2025-02-07T19:36:14.124Z",
"completedAt": "2025-02-07T19:38:28.343Z"
}Tip
retryAfter field to know how long to wait before your next poll. See Smart Polling for details./api/v1/properties/:jobId
Permanently delete a video job and its outputs.
Response (200 OK)
{ "deleted": true }Templates
Tip
Templates save reusable video configurations. Your oldest template is automatically applied as the default for all video creation requests. Pass a specific presetId to use a different template, or override individual settings in the request body. Per-call values always take precedence.
Endpoints
/api/v1/templates/api/v1/templates/api/v1/templates/:templateId/api/v1/templates/:templateId/api/v1/templates/:templateId/api/v1/templates
Create a new video template.
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Required | Template name (1-200 chars) |
config.language | enum | Optional | en, fr, es, or ro |
config.scriptStyle | enum | Optional | punchy, flowery, or factual |
config.voiceId | string | Optional | Voice ID |
config.voiceEmotion | enum | Optional | neutral, warm, energetic, calm, cheerful |
config.backgroundMusic | object | Optional | { url?, trackId?, volume? } |
config.captions | object | Optional | { enabled?, textColor?, highlightColor? } |
config.endFrame | object | Optional | { brandKitId? } |
config.outputs | object | Optional | { landscape?, square?, portrait? } |
config.scalingMode | enum | Optional | cover or blur-fill |
config.effects | object | Optional | { motionEffect? } — zoom, zoomOut, or kenBurns |
Example Request
curl -X POST https://www.propervid.io/api/v1/templates \
-H "Authorization: Bearer vg_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"name": "Premium Property Tour",
"config": {
"language": "en",
"scriptStyle": "flowery",
"voiceId": "eldrin",
"voiceEmotion": "warm",
"backgroundMusic": {
"trackId": "apricity",
"volume": 20
},
"captions": { "enabled": true },
"outputs": {
"landscape": { "enabled": true, "resolution": "1080p" },
"portrait": { "enabled": true, "resolution": "1080p" }
},
"effects": {
"motionEffect": "zoom"
}
}
}'Response (201 Created)
{
"id": "d21220d9-9ff9-4e49-a7a6-19b3a6e7634b",
"name": "Premium Property Tour",
"config": { ... },
"createdAt": "2025-02-07T19:20:00.000Z",
"updatedAt": "2025-02-07T19:20:00.000Z"
}Tip
presetId to use a different template, or override individual settings in the request body./api/v1/templates
List all templates for the authenticated user.
Response (200 OK)
{
"templates": [
{
"id": "d21220d9-9ff9-4e49-a7a6-19b3a6e7634b",
"name": "Premium Property Tour",
"config": {
"voiceId": "eldrin",
"voiceEmotion": "warm",
"backgroundMusic": { "trackId": "apricity", "volume": 20 },
"captions": { "enabled": true },
"outputs": { "landscape": { "enabled": true, "resolution": "1080p" } }
},
"createdAt": "2025-02-07T19:20:00.000Z",
"updatedAt": "2025-02-07T19:20:00.000Z"
}
]
}/api/v1/templates/:templateId
Get a single template by ID.
Response (200 OK)
{
"id": "d21220d9-9ff9-4e49-a7a6-19b3a6e7634b",
"name": "Premium Property Tour",
"config": {
"language": "en",
"scriptStyle": "flowery",
"voiceId": "eldrin",
"voiceEmotion": "warm",
"backgroundMusic": { "trackId": "apricity", "volume": 20 },
"captions": { "enabled": true },
"outputs": {
"landscape": { "enabled": true, "resolution": "1080p" },
"portrait": { "enabled": true, "resolution": "1080p" }
},
"effects": { "motionEffect": "kenBurns", "transitionEffect": "fade" }
},
"createdAt": "2025-02-07T19:20:00.000Z",
"updatedAt": "2025-02-07T19:20:00.000Z"
}/api/v1/templates/:templateId
Update a template. All fields are optional — only provided fields are changed.
Request Body
{
"name": "Updated Template Name",
"config": {
"voiceId": "alicia",
"backgroundMusic": { "trackId": "paragliding", "volume": 30 }
}
}Response (200 OK)
{
"id": "d21220d9-9ff9-4e49-a7a6-19b3a6e7634b",
"name": "Updated Template Name",
"config": { ... },
"createdAt": "2025-02-07T19:20:00.000Z",
"updatedAt": "2025-02-07T20:15:00.000Z"
}/api/v1/templates/:templateId
Permanently delete a template.
Response (200 OK)
{ "deleted": true }Brand Kits
Tip
Brand kits add a professional end frame to your property videos with your logo, website, and contact details.
How Brand Kits Work
- Create a brand kit in the dashboard under Settings > Brand Kit
- Upload your logo, enter your website and phone number, and customise text styling
- Use the returned
brandKitIdin your API requests via theendFrameparameter - You can also save a brand kit reference inside a template for automatic use
Using a Brand Kit in Video Creation
// In POST /api/v1/properties:
{
"endFrame": {
"brandKitId": "d21220d9-9ff9-4e49-a7a6-19b3a6e7634b"
}
}The brand kit includes pre-rendered end frame images for all three formats (landscape, portrait, square) along with your logo, website, phone number, and custom text styling.
Using a Brand Kit in a Template
// In POST /api/v1/templates:
{
"name": "Branded Property Tour",
"config": {
"endFrame": {
"brandKitId": "d21220d9-9ff9-4e49-a7a6-19b3a6e7634b"
},
"captions": {
"enabled": true
}
}
}Once saved in a template, the brand kit is automatically applied to all videos that use that template.
Inline End Frame (without Brand Kit)
If you don't have a brand kit, you can provide end frame details inline:
{
"endFrame": {
"enabled": true,
"duration": 4,
"logoUrl": "https://example.com/logo.png",
"website": "www.example.com",
"phone": "+1 (555) 123-4567"
}
}Tip
Upload
Upload listing images for your property videos. Most users rely on ProperVid's AI voices and royalty-free music library for audio — but if you need to, you can also upload your own pre-recorded voiceover or custom background music track.
/api/v1/upload
Upload a listing image or audio file for use in property video generation. Supports multipart form data or JSON with base64.
Multipart Upload
curl -X POST https://www.propervid.io/api/v1/upload \
-H "Authorization: Bearer vg_live_your_key" \
-F "file=@/path/to/property-photo.jpg"Base64 Upload
curl -X POST https://www.propervid.io/api/v1/upload \
-H "Authorization: Bearer vg_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"data": "iVBORw0KGgoAAAANS...",
"contentType": "image/jpeg"
}'Supported File Types
Images (max 10 MB)
image/jpeg (JPEG)image/png (PNG)image/webp (WebP)Audio (max 50 MB)
audio/mpeg (MP3)audio/mp3 (MP3)audio/wav (WAV)audio/ogg (OGG)audio/aac (AAC)audio/m4a (M4A)Info
backgroundMusic.url for your own music track, or as audio.voiceover.url for a pre-recorded narration. Audio levels are automatically normalised during video processing.Uploading Multiple Images
The upload endpoint accepts one file at a time. To upload multiple listing photos, call it once per image and collect the returned URLs.
const fs = require("fs");
const photos = ["front.jpg", "living.jpg", "kitchen.jpg", "bedroom.jpg"];
const urls = await Promise.all(photos.map(async (photo) => {
const formData = new FormData();
formData.append("file", fs.createReadStream(photo));
const res = await fetch("https://www.propervid.io/api/v1/upload", {
method: "POST",
headers: { Authorization: "Bearer vg_live_your_key" },
body: formData,
});
const { url } = await res.json();
return { url, label: photo.replace(/\.[^.]+$/, "").replace(/-/g, " ") };
}));
// urls is now ready to pass as the "images" array to /api/v1/propertiesResponse (200 OK)
{
"url": "https://blob.vercel-storage.com/uploads/abc123.jpg",
"filename": "property-photo.jpg",
"size": 1024000,
"contentType": "image/jpeg"
}Webhooks
Instead of polling, configure a webhook URL to receive a POST request when your video completes or fails. Webhooks are signed with HMAC-SHA256 so you can verify they came from ProperVid.
How Webhooks Work
- Include a
webhookUrlwhen creating a video - When the video completes (or fails), ProperVid sends a POST request to your URL
- The request includes an HMAC-SHA256 signature for verification
- If your endpoint is unavailable, we retry up to 3 times with exponential backoff
Webhook Events
video.completed
{
"event": "video.completed",
"jobId": "708a3c36-1965-44ab-82fc-9c79a2ac8d37",
"externalId": "OAK-AVE-12",
"customerMetadata": { "agent": "Jane Doe" },
"timestamp": "2025-02-07T19:38:28.000Z",
"data": {
"landscapeUrl": "https://blob.vercel-storage.com/videos/.../landscape.mp4",
"landscapeSize": 10969861,
"squareUrl": null,
"portraitUrl": null,
"srtUrl": "https://blob.vercel-storage.com/videos/.../captions.srt"
}
}video.failed
{
"event": "video.failed",
"jobId": "708a3c36-1965-44ab-82fc-9c79a2ac8d37",
"externalId": "OAK-AVE-12",
"timestamp": "2025-02-07T19:35:00.000Z",
"error": {
"code": "PROCESSING_ERROR",
"message": "Failed to download image 0: 404 Not Found"
}
}Webhook Headers
| Header | Description |
|---|---|
X-ProperVid-Signature | HMAC-SHA256 hex digest of the request body |
X-ProperVid-Event | Event type: video.completed or video.failed |
X-ProperVid-Delivery | Unique delivery ID (UUID) |
Signature Verification
Your webhook signing secret is provided when you generate your API key. Use it to verify that webhook requests are genuinely from ProperVid.
const crypto = require("crypto");
function verifyWebhookSignature(body, signature, signingSecret) {
const expected = crypto
.createHmac("sha256", signingSecret)
.update(JSON.stringify(body))
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// In your webhook handler:
app.post("/webhooks/propervid", (req, res) => {
const signature = req.headers["x-propervid-signature"];
if (!verifyWebhookSignature(req.body, signature, SIGNING_SECRET)) {
return res.status(401).send("Invalid signature");
}
const { event, jobId, data } = req.body;
if (event === "video.completed") {
console.log("Video ready:", data.landscapeUrl);
}
res.status(200).send("OK");
});Retry Policy
If your webhook endpoint returns a non-2xx status code or times out (10s), we retry with exponential backoff:
| Attempt | Delay |
|---|---|
| 1st retry | 30 seconds |
| 2nd retry | 5 minutes |
| 3rd retry (final) | 30 minutes |
Warning
Smart Polling
When polling for job status, the API returns hints to help you poll efficiently without wasting requests or missing completion.
Polling Fields
| Field | Description |
|---|---|
retryAfter | Recommended seconds to wait before next poll |
estimatedCompletionAt | ISO 8601 estimated completion timestamp |
Retry-After | HTTP header with same value as retryAfter |
Recommended Intervals
| Job Status | retryAfter | Reason |
|---|---|---|
pending | 60 seconds | Waiting for worker pickup |
processing (<80%) | 30 seconds | Actively rendering |
processing (≥80%) | 10 seconds | Nearly complete |
completed / failed | — | Terminal state, no more polling needed |
Average processing time is ~2-8 minutes depending on video length and output formats.
Polling Example
async function pollUntilDone(jobId, apiKey) {
const url = `https://www.propervid.io/api/v1/properties/${jobId}`;
const headers = { Authorization: `Bearer ${apiKey}` };
while (true) {
const res = await fetch(url, { headers });
const job = await res.json();
console.log(`Status: ${job.status} | Progress: ${job.progress}%`);
if (job.status === 'completed') {
return job.outputs;
}
if (job.status === 'failed') {
throw new Error(`Video failed: ${job.error.message}`);
}
// Use the server-recommended wait time
const waitMs = (job.retryAfter || 30) * 1000;
await new Promise(resolve => setTimeout(resolve, waitMs));
}
}Tip
retryAfter intervals keeps you well within limits for typical usage.Rate Limiting
API requests are rate limited per API key on a daily basis. Your rate limit is set and agreed during account creation. Rate limit information is included in response headers on every request.
Response Headers
Every API response includes these rate limit headers:
| Header | Example | Description |
|---|---|---|
X-RateLimit-Limit | 1000 | Your daily request limit |
X-RateLimit-Remaining | 987 | Requests remaining today |
X-RateLimit-Reset | 2025-02-08T00:00:00.000Z | When the limit resets (next UTC midnight) |
Rate Limit Exceeded (429)
When you exceed your limit, the API returns a 429 status code:
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded. Try again later."
}
}Info
X-RateLimit-Reset header to know exactly when your limit refreshes.Voices
ProperVid supports multiple AI voices across different languages and accents. All voices are included with your account. You can preview every voice in the dashboard before using them in your API calls.
British English
en-GB — 4 voices
| Voice ID | Name | Gender | Description |
|---|---|---|---|
eldrin | Eldrin | Male | Crisp British baritone |
alicia | Alicia | Female | Polished global anchor |
finley | Finley | Male | Articulate, authoritative anchor |
florence | Florence | Male | Atmospheric British storyteller |
American English
en-US — 8 voices
| Voice ID | Name | Gender | Description |
|---|---|---|---|
darian | Darian | Male | Warm, grounded storyteller |
talia | Talia | Female | Warm, soft guide |
adam | Adam | Male | Deep, authoritative |
caleb | Caleb | Male | Trusted guide |
lawrence | Lawrence | Male | Bright and informative |
elara | Elara | Female | Crisp professional narrator |
jade | Jade | Female | Upbeat and natural |
maisie | Maisie | Female | Friendly, casual neighbor |
Australian English
en-AU — 1 voices
| Voice ID | Name | Gender | Description |
|---|---|---|---|
baxter | Baxter | Male | Dry, calm Aussie |
French
fr-FR — 4 voices
| Voice ID | Name | Gender | Description |
|---|---|---|---|
paul-k | Paul K | Male | Warm, engaging narrator |
dore | Dore | Female | Captivating, soft |
mathieu | Mathieu | Male | Serious, calm |
lea | Lea | Female | Calm, educational |
Spanish
es-ES — 4 voices
| Voice ID | Name | Gender | Description |
|---|---|---|---|
el-javier | Javier | Male | Warm, middle-aged narrator |
el-elena | Elena | Female | Soothing, professional |
el-dante | Dante | Male | Dynamic, energetic |
el-gabriela | Gabriela | Female | Warm, engaging (Mexican Spanish) |
Romanian
ro-RO — 4 voices
| Voice ID | Name | Gender | Description |
|---|---|---|---|
el-andrei | Andrei | Male | Warm, sophisticated |
el-antonia | Antonia | Female | Young, warm, smooth |
el-alex-max | Alex | Male | Mature, rich, inviting tone |
el-cristina | Cristina | Female | Warm, expressive storytelling |
Voice Emotions
All voices support an optional voiceEmotion parameter that adjusts the delivery tone:
neutralProfessional, straightforward
warmFriendly, approachable
energeticUpbeat, enthusiastic
calmRelaxed, reassuring
cheerfulPositive, bright
Background Music
Choose from 29 royalty-free tracks included with your account. You can preview every track in the dashboard before using them. Use the trackId in your background music configuration, or upload your own audio and use the URL directly.
Available Tracks
29 royalty-free tracks
| Track ID | Name | Mood |
|---|---|---|
a-special-morning | A Special Morning | Uplifting & Warm |
apricity | Apricity | Warm & Reflective |
at-dawn | At Dawn | Peaceful & Fresh |
battleborn-symphony | Battleborn Symphony | Epic & Powerful |
calling-my-flight | Calling My Flight | Adventurous & Free |
carried-by-light | Carried By Light | Uplifting & Ethereal |
clean-exit | Clean Exit | Smooth & Modern |
dubwise-connection | Dubwise Connection | Groovy & Relaxed |
everything-in-motion | Everything in Motion | Dynamic & Flowing |
feel-the-beat | Feel the Beat | Energetic & Dynamic |
flycatcher | Flycatcher | Light & Playful |
hand-covers-bruise | Hand Covers Bruise | Emotional & Cinematic |
i-found-paradise | I Found Paradise | Blissful & Dreamy |
in-motion | In Motion | Driving & Energetic |
iron-pulse | Iron Pulse | Industrial & Bold |
la-lune-et-la-mouette | La Lune et la Mouette | Romantic & French |
make-me-smile | Make Me Smile | Happy & Cheerful |
meltspace | Meltspace | Ambient & Spacey |
movie-time | Movie Time | Cinematic & Fun |
one-story-and-many-toys | One Story and Many Toys | Whimsical & Playful |
opus | Opus | Grand & Classical |
oxygen-lsv | Oxygen LSV | Airy & Electronic |
paragliding | Paragliding | Soaring & Uplifting |
tears-in-the-rain | Tears in the Rain | Melancholic & Beautiful |
the-chosen-one | The Chosen One | Heroic & Inspiring |
the-leaves-that-fall | The Leaves That Fall | Gentle & Autumnal |
vostoc | Vostoc | Electronic & Cosmic |
windows-of-silence | Windows of Silence | Calm & Meditative |
you-are-hero | You Are Hero | Triumphant & Bold |
Output Resolutions
Property videos can be rendered in three aspect ratios at up to 1440p. Request one or more output formats when creating a video.
Landscape (16:9)
720p1280 x 720
1080p1920 x 1080
1440p2560 x 1440
Square (1:1)
720p720 x 720
1080p1080 x 1080
1440p1440 x 1440
Portrait (9:16)
720p720 x 1280
1080p1080 x 1920
1440p1440 x 2560
Motion Effects
Motion effects animate each image during its display duration. Set via motionEffect on the Property Videos or Videos endpoints.
zoomZoom In
Slowly zooms into the image over its duration. The default for property videos.
zoomOutZoom Out
Starts zoomed in, then slowly pulls back to reveal the full image.
kenBurnsKen Burns
Cinematic combination of slow zoom and horizontal pan, inspired by the classic documentary technique.
Error Codes
Error Response Format
All errors follow a consistent JSON structure:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Human-readable description of what went wrong"
}
}All Error Codes
| Code | HTTP | Description |
|---|---|---|
MISSING_AUTH | 401 | No Authorization header provided |
INVALID_AUTH_FORMAT | 401 | Authorization header not in Bearer format |
MISSING_API_KEY | 401 | API key value is empty |
INVALID_API_KEY | 401 | API key not found or inactive |
UNAUTHORIZED | 401 | No valid authentication (API key or session) |
USER_REQUIRED | 403 | Operation requires a linked user account |
AI_ACCESS_DENIED | 403 | Account does not have access to this AI feature |
VALIDATION_ERROR | 400 | Request body failed validation |
INVALID_VOICE | 400 | Voice ID not found |
INVALID_MUSIC | 400 | Music track ID not found |
INVALID_BRAND_KIT | 400 | Brand kit UUID not found for this user |
JOB_NOT_FOUND | 404 | Video job not found or not owned by API key |
TEMPLATE_NOT_FOUND | 404 | Template not found or not owned by user |
NO_FILE | 400 | No file provided for upload |
INVALID_FILE_TYPE | 400 | File type not supported |
FILE_TOO_LARGE | 400 | File exceeds size limit |
RATE_LIMIT_EXCEEDED | 429 | Daily request limit exceeded |
SUBSCRIPTION_REQUIRED | 403 | Feature not available on your current account |
PROCESSING_ERROR | — | Video processing failed (returned on job, not HTTP) |
WORKER_ERROR | 503 | Failed to connect to video processor |
CONFIG_ERROR | 503 | Video processing not configured on server |
INTERNAL_ERROR | 500 | Unexpected server error |
ProperVid API Documentation — v1.0.0
Questions? Contact us