Loading…

Listing Reel Maker API

Documentation for POST /api/reels and GET /api/reels.

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. Supports JSON (preferred) and multipart/form-data (legacy).
  • 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.

Create a Reel (JSON mode — recommended)

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; seconds at which caption fades out
  "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
  "voiceType": "kate"                                      // required only if script present; "kate" | "steve"
}

Constraints & Validation

  • photos: 3–15 required (max 15). Combined assets (photos + logo + headshot) ≤ 17 URLs.
  • musicType: required (e.g., Modern, Chill, etc.).
  • details: optional.
  • 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 if script is provided).

Credits & Cost

Each job deducts credits before processing:

  • Base: number of photos (3–15)
  • +1 if headshot & headshotDetails are provided
  • +1 if script is provided (AI voiceover enabled)

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-5 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, or "multipart/form-data"." }

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 (multipart/form-data — legacy)

This mode uploads binary files in the same request. It is convenient but more likely to hit serverless limits on large payloads. If you see 413 errors, switch to JSON mode.

Note: The logo and headshot fields can be sent as either file uploads or as string URLs. If you send a URL string, the server will download it automatically.

Request Fields

  • photos: 3–15 required files (uploaded as binary)
  • logo: Optional file upload or HTTP(S) URL string
  • headshot: Optional file upload or HTTP(S) URL string (requires headshotDetails)
  • headshotDetails: Text string (required if headshot is provided)
  • details: Optional text string
  • displayText: Optional text string
  • captionFadeOutSeconds: Optional number (seconds at which caption fades out)
  • musicType: Required text string
  • script: Optional text string (triggers voiceover, +1 credit)
  • voiceType: Optional text string ("kate" | "steve", required if script present)

cURL Example (with file uploads)

curl -X POST \
  -H "X-API-Key: $LRM_API_TOKEN" \
  -F "photos=@/path/1.jpg" \
  -F "photos=@/path/2.jpg" \
  -F "photos=@/path/3.jpg" \
  -F "logo=@/path/logo.png" \
  -F "headshot=@/path/agent.jpg" \
  -F "headshotDetails=Jane Doe — Broker" \
  -F "details=3 bed, 2 bath…" \
  -F "displayText=Open House Sat 2–4" \
  -F "captionFadeOutSeconds=5.0" \
  -F "musicType=Modern" \
  -F "script=Thirty to forty word voiceover text…" \
  -F "voiceType=kate" \
  https://www.listingreelmaker.com/api/reels

cURL Example (with logo as URL string)

curl -X POST \
  -H "X-API-Key: $LRM_API_TOKEN" \
  -F "photos=@/path/1.jpg" \
  -F "photos=@/path/2.jpg" \
  -F "photos=@/path/3.jpg" \
  -F "logo=https://www.listingreelmaker.com/logo.png" \
  -F "details=3 bed, 2 bath…" \
  -F "displayText=Open House Sat 2–4" \
  -F "captionFadeOutSeconds=5.0" \
  -F "musicType=Modern" \
  https://www.listingreelmaker.com/api/reels

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, or failed

Response Fields

  • id — Job ID
  • status — One of: generating, complete, failed
  • url — Presigned download URL (null if not ready)
  • createdAt — ISO 8601 timestamp
  • title — Optional title from displayText or details
  • userId — User ID (in single job responses)
  • motionUrls — Array of preview video URLs (only when status is generating)

Field Reference

photosrequired
string[]
3–15 required; HTTP(S) URLs or our S3 keys.
logo
string
Optional; URL or S3 key.
headshot
string
Optional; requires headshotDetails if present.
headshotDetails
string
Optional; required if headshot present.
details
string
Optional text used for captions/visuals.
displayText
string
Optional on-video text (e.g., Open House).
captionFadeOutSeconds
number
Optional. Seconds at which the caption fades out. If omitted, caption remains visible for entire video.
script
string
Optional 30–40 word narration. Triggers AI voiceover and +1 credit.
voiceType
"kate" | "steve"
Required only if script present.
musicTyperequired
string
Required; free text; normalized (e.g., 'modern').

Common Errors & Troubleshooting

  • 401 Unauthorized: Missing/invalid API Token. Ensure the X-API-Key header (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).
  • 413 Payload too large: Use JSON mode and host images, or pre-upload to your S3.
  • 400 musicType is required: Include a non-empty musicType field.
  • 400 Asset ingest failed: A provided URL could not be fetched (4xx/5xx). Verify public reachability.
  • 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.