Listing Reel Maker API
Documentation for POST /api/reels, GET /api/reels, and POST /api/reels/edit.
Base URL: https://www.listingreelmaker.com/api/reels
Overview
The Reels API lets you create a new video “reel” generation job from your listing assets and later check its status or download the rendered MP4. For reliability and speed, we recommend the JSON+URL workflow where you send asset URLs (or S3 keys) instead of uploading large files in the same request.
API Token & Access
API access is disabled by default. To enable it, email support@listingreelmaker.com. Once enabled, you will see a Get API token button in the app header.
Include your token with every request using the header X-API-Key: <YOUR_API_TOKEN>.
Endpoint Summary
POST /api/reels— Create a reel job with JSON asset URLs or a Zillow listing URL.GET /api/reels— List your jobs with status and URLs (when available).GET /api/reels?jobId=<id>— Fetch status for a single job and a preview/final URL if available.POST /api/reels/edit— Create an edited version from an existing reel.
Create a Reel (JSON mode)
Send Content-Type: application/json with public HTTP(S) URLs for your assets.
Request Body
{
"photos": [
"https://example.com/listing/1.jpg",
"https://example.com/listing/2.jpg",
"https://example.com/listing/3.jpg"
],
"logo": "https://example.com/brand/logo.png", // optional
"headshot": "https://example.com/agent.jpg", // optional
"headshotDetails": "Jane Doe — Broker | (555) 555-1212", // required if headshot is present
"details": "3 bed, 2 bath, renovated kitchen, fenced yard…", // optional
"displayText": "Open House Sat 2–4", // optional
"captionFadeOutSeconds": 5.0, // optional; ignored when textOverlays is present
"textOverlays": [], // optional advanced overlay payload
"headshotTextStyle": {}, // optional headshot badge style
"script": "Thirty to forty word voiceover text…", // optional; if present we generate TTS (+1 credit)
"musicType": "Modern", // required, same options as in the app, Upbeat, Luxury, Warm, Bright, Chill, Modern, Cinematic, Acoustic, normalized to lowercase
"musicKey": "tracks/custom.mp3", // optional specific track key
"voiceType": "kate", // required only if script present; "kate" | "steve"
"outputFormat": "portrait", // optional; "portrait" (default) | "landscape"
"enableLowResUpscale": false // optional; +1 credit
}Constraints & Validation
- photos: 3–15 required (max 15). Combined assets (photos + logo + headshot) ≤ 17 URLs.
- zillowUrl: can be sent instead of
photos. The API selects 3–15 photos automatically. - musicType: required for photo URL jobs. Zillow jobs default to
Modernif omitted. - details: optional.
- outputFormat: optional. Use
portraitfor 1080×1920 orlandscapefor 1920×1080. Edits keep the source reel format. - captionFadeOutSeconds: optional number. If provided, the caption will fade out starting at this time (in seconds). If omitted, the caption will remain visible for the entire video.
- headshot and headshotDetails must be provided together or omitted together.
- voiceType allowed values:
kate,steve(only ifscriptis provided).
Credits & Cost
Each job deducts credits before processing:
- Base:
number of photos(3–15) - +1 if headshot & headshotDetails are provided
- +1 if
scriptis provided (AI voiceover enabled) - +1 if
enableLowResUpscaleis true
If the job fails to start, we refund the credits automatically.
Successful Response
{
"jobId": "b2e8d1c4-53a0-468f-8bce-7d3a1a3fae9a",
"costCharged": 5
}Error Responses
// 400 Bad Request
{ "error": "musicType is required" }
// 400 Bad Request
{ "error": "3-15 photos required" }
// 400 Bad Request
{ "error": "Headshot requires both image and details, or neither." }
// 401 Unauthorized
{ "error": "Unauthorized" }
// 402 Payment Required (insufficient credits)
{ "error": "Insufficient credits", "required": 5, "have": 3 }
// 415 Unsupported Media Type
{ "error": "Unsupported Content-Type. Use application/json with URLs/keys." }cURL Example (JSON)
curl -X POST \
-H "Content-Type: application/json" \
-H "X-API-Key: $LRM_API_TOKEN" \
https://www.listingreelmaker.com/api/reels \
-d '{
"photos": [
"https://example.com/img/1.jpg",
"https://example.com/img/2.jpg",
"https://example.com/img/3.jpg"
],
"details": "3 bed, 2 bath…",
"displayText": "Open House Sat 2–4",
"captionFadeOutSeconds": 5.0,
"musicType": "Modern",
"script": "Thirty to forty word voiceover text…",
"voiceType": "kate"
}'JavaScript fetch Example
const res = await fetch("/api/reels", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": process.env.NEXT_PUBLIC_LRM_API_TOKEN!
},
body: JSON.stringify({
photos: ["https://example.com/1.jpg","https://example.com/2.jpg","https://example.com/3.jpg"],
details: "3 bed, 2 bath…",
displayText: "Open House Sat 2–4",
captionFadeOutSeconds: 5.0,
musicType: "Modern",
script: "Thirty to forty word voiceover text…",
voiceType: "steve"
})
});
const data = await res.json();
console.log(data.jobId);Python requests Example
import os, requests
BASE = "https://www.listingreelmaker.com/api/reels"
API_KEY = os.environ["LRM_API_TOKEN"]
payload = {
"photos": [
"https://example.com/1.jpg",
"https://example.com/2.jpg",
"https://example.com/3.jpg"
],
"details": "3 bed, 2 bath…",
"displayText": "Open House Sat 2–4",
"captionFadeOutSeconds": 5.0,
"musicType": "Modern",
"script": "Thirty to forty word voiceover text…",
"voiceType": "kate"
}
r = requests.post(BASE, json=payload, headers={"X-API-Key": API_KEY})
r.raise_for_status()
print(r.json())Create a Reel from a Zillow Link
Send a Zillow listing URL and the API will scrape listing details, pick the best photos, generate a short caption and voiceover script, ingest the images, and start the reel job.
{
"zillowUrl": "https://www.zillow.com/homedetails/123-Main-St_123456_zpid/",
"photoCount": 10, // optional max; 3-15, default 10
"strictPhotoCount": false, // optional; true forces exactly photoCount when enough photos exist
"musicType": "Modern", // optional for Zillow; defaults to Modern
"voiceType": "kate", // optional; "kate" | "steve"
"includeVoiceover": true, // optional; default true, +1 credit when script is generated
"autoDraft": true, // optional; default true
"objective": "luxury open house" // optional prompt hint
}You can still override any generated field by passing details, displayText, script, musicType, textOverlays, logo, or headshot fields in the same request.
cURL Example (Zillow)
curl -X POST \
-H "Content-Type: application/json" \
-H "X-API-Key: $LRM_API_TOKEN" \
https://www.listingreelmaker.com/api/reels \
-d '{
"zillowUrl": "https://www.zillow.com/homedetails/123-Main-St_123456_zpid/",
"photoCount": 10,
"musicType": "Modern",
"voiceType": "kate"
}'Successful response includes the job ID and source listing metadata:
{
"jobId": "b2e8d1c4-53a0-468f-8bce-7d3a1a3fae9a",
"costCharged": 11,
"sourceListing": {
"provider": "zillow",
"url": "https://www.zillow.com/homedetails/123-Main-St_123456_zpid/",
"address": "123 Main St, Austin, TX 78701",
"price": "$750,000",
"scrapedPhotoCount": 32,
"selectedPhotoCount": 10
}
}Status & Downloads
Poll a single job
Use GET /api/reels?jobId=<id> to retrieve status and URLs.
curl -H "X-API-Key: $LRM_API_TOKEN" \
"https://www.listingreelmaker.com/api/reels?jobId=$JOB_ID"Possible responses:
{ "status": "generating", "userId": "…", "motionUrls": ["https://…/motion1.mp4", "…"] }
{ "status": "failed", "userId": "…" }
{ "status": "ready", "url": "https://…/final.mp4?X-Amz-SignedHeaders=…", "userId": "…" }Note: When status is generating, the response may include a motionUrls array with preview videos that can be displayed while waiting for the final render.
List recent jobs
Use GET /api/reels to list your jobs. Supports pagination and status filtering.
# List all jobs (backward compatible array format)
curl -H "X-API-Key: $LRM_API_TOKEN" \
https://www.listingreelmaker.com/api/reels
# With pagination
curl -H "X-API-Key: $LRM_API_TOKEN" \
"https://www.listingreelmaker.com/api/reels?page=1&limit=20"
# Filter by status
curl -H "X-API-Key: $LRM_API_TOKEN" \
"https://www.listingreelmaker.com/api/reels?status=complete&page=1&limit=20"Response formats:
// Without pagination params (backward compatible)
[
{ "id": "…", "status": "generating", "url": null, "createdAt": "2024-01-01T00:00:00Z" },
{ "id": "…", "status": "complete", "url": "https://…/final.mp4?…", "createdAt": "2024-01-01T00:00:00Z", "title": "Open House Sat 2–4" }
]
// With pagination params
{
"reels": [
{ "id": "…", "status": "complete", "url": "https://…/final.mp4?…", "createdAt": "2024-01-01T00:00:00Z", "title": "Open House Sat 2–4" }
],
"pagination": {
"page": 1,
"limit": 20,
"total": 45,
"totalPages": 3,
"hasMore": true
}
}Query Parameters
jobId— Fetch a single job by ID (returns object, not array)page— Page number (default: 1)limit— Items per page (default: 50, max: 100)status— Filter by status:generating,complete, orfailed
Response Fields
id— Job IDstatus— One of:generating,complete,failedurl— Presigned download URL (null if not ready)createdAt— ISO 8601 timestamptitle— Optional title fromdisplayTextordetailsuserId— User ID (in single job responses)motionUrls— Array of preview video URLs (only when status isgenerating)
Edit an Existing Reel
Use POST /api/reels/edit to create a new version from a completed reel. Pass the source job ID plus any fields you want to change.
{
"sourceJobId": "existing-job-id",
"photos": ["https://example.com/new-1.jpg", "https://example.com/new-2.jpg", "https://example.com/new-3.jpg"],
"displayText": "New Open House",
"textOverlays": [],
"musicType": "Luxury",
"script": "Updated thirty to forty word narration...",
"voiceType": "kate",
"idempotencyKey": "client-generated-key"
}Edited versions are returned as normal jobs and can be polled with GET /api/reels?jobId=<id>.
Field Reference
photosrequiredzillowUrllistingUrlphotoCountstrictPhotoCountautoDraftincludeVoiceoverobjectivelogoheadshotheadshotDetailsheadshotTextStyledetailsdisplayTextcaptionFadeOutSecondstextOverlaysscriptvoiceTypemusicTyperequiredmusicKeyenableLowResUpscaleCommon Errors & Troubleshooting
- 401 Unauthorized: Missing/invalid API Token. Ensure the
X-API-Keyheader (or?api_key=when testing) is present and correct. - 402 Insufficient credits: Top up credits or reduce optional items (e.g., remove headshot or script).
- 400 musicType is required: Include a non-empty
musicTypefield. - 400 Asset ingest failed: A provided URL could not be fetched (4xx/5xx). Verify public reachability.
- 400 ZILLOW_SCRAPE_FAILED: Zillow listing data could not be loaded. Verify the URL is public and includes a Zillow property ID.
- 400 Too many assets: Combined assets (photos + logo + headshot) exceed the maximum of 17 URLs.
- 400 3-15 photos required: Photo count must be between 3 and 15 inclusive.