How to Build a Real Estate Video App with the PhotoAIVideo API
You do not need to train a model, rent GPUs, or build a render farm to ship a real estate video product. Eight REST endpoints — two of which cost anything — cover the entire pipeline from listing photo to finished branded reel. Here is how to wire them into a real application.
Why Build on a Video API Instead of From Scratch
The naive version of "add video to my real estate product" involves an image-to-video model, a GPU pool that can absorb bursty demand, an FFmpeg pipeline for concatenation and audio, storage and CDN delivery for the outputs, a job queue with retries, and someone on call when a render wedges at 2am. That is a multi-quarter infrastructure project before you write a single line of product code.
The API version is a different shape of problem entirely. You are writing an orchestration layer: move bytes to storage, create jobs, track their state, and present the results. There is no model to evaluate, no capacity to plan, and no render infrastructure to operate. The unit economics are also legible from day one — one credit per generated clip, one credit per reel merge, and nothing for uploads, status polls, job listings, or balance checks.
That legibility matters more than it sounds. Because only two endpoints cost anything, you can calculate the exact cost of any customer action before you build it. A ten-photo listing rendered into a merged reel is eleven credits — ten clips plus one merge — every single time, regardless of how many times you poll or how long the render takes.
The two-endpoint mental model
Everything in this API reduces to two paid calls and six free ones. POST /api/v1/videos turns one photo into one clip. POST /api/v1/reels turns many clips into one reel. Uploads, status checks, job lists, and credit balances are free, so you can poll as aggressively as your UX requires without touching your cost model.
The Five-Stage Pipeline
Every application built on this API — a standalone app, a feature inside an existing CRM, a bulk processing job for a brokerage — moves through the same five stages. The differences between products are in the orchestration around these stages, not the stages themselves.
Authenticate with an API key
Activate a plan in the API dashboard, generate a key, and send it on every request as an Authorization: Bearer header or an x-api-key header. Keys are scoped to your account and all keys share the same credit pool, so you can issue one key per environment — staging, production, internal tooling — without splitting your balance. Revoking a key returns 401 immediately, which makes rotation safe.
Reserve presigned upload URLs
Input images must live on our storage. External image URLs are rejected, so your app cannot simply hand us a link to an MLS photo — it has to move the bytes. Call the presigned URL endpoint with a count between 1 and 20 and you get back a path, a token, a presignedUrl to upload to, and the publicUrl you will reference later. This endpoint is free.
Create video jobs
POST a prompt and the publicUrl of an uploaded image. Optionally add an endImageUrl to control the final frame, an array of camera effects, and a duration of 4, 5, or 6 seconds. This is where the credit is charged. The response is immediate and contains a jobId with a pending status — no video yet.
Poll until each clip is ready
Both generation endpoints are asynchronous. Poll the job status every few seconds until it flips to completed or failed. A completed job returns video_url for inline playback and download_url for a forced download. A failed job refunds the credit automatically, so your billing logic does not have to compensate for broken renders.
Merge clips into a branded reel
Pass 2 to 20 completed job IDs in playback order along with orientation, background music, a text overlay, an ending card, and a logo watermark. This costs one more credit and returns a jobId you poll exactly like a video job. The output is a single finished MP4 your app can host, download, or push to social.
Stage One: Authentication
Activate a plan in the API dashboard and generate a key from the API Keys tab. The API accepts the key two ways, so use whichever fits your HTTP client better:
Authorization: Bearer <API_KEY>
# or
x-api-key: <API_KEY>Because credits are pooled across every key on the account, treat keys as environment labels rather than billing boundaries. One key for production, one for staging, one for the internal admin tool. If a key leaks, revoke it and the rest keep working — and a revoked key starts returning 401 immediately rather than degrading quietly.
Stage Two: Getting Photos Into Storage
This is the stage most developers underestimate. Input images have to live on our storage — you cannot pass an arbitrary external URL — so your app is responsible for moving the bytes. Start by reserving upload slots for the whole listing in one call:
GET /api/v1/presigned-urls?count=1
{
"bucket": "api-uploads",
"uploads": [
{
"path": "<keyId>/<uuid>",
"token": "...",
"presignedUrl": "https://...",
"publicUrl": "https://..."
}
]
}Set count to the number of photos in the listing, up to 20, and you get an array back in one round trip. Then PUT the raw bytes to each presignedUrl with the correct content type:
curl -X PUT "<presignedUrl>" \
-H "Content-Type: image/jpeg" \
--data-binary @photo.jpgKeep the matching publicUrl for each upload. That is the value you pass as imageUrl in the next stage, and it is the one piece of state you genuinely cannot regenerate — so persist it rather than holding it in a local variable.
Stage Three: Creating Video Jobs
Now the paid call. POST a prompt describing the motion you want plus the uploaded image URL. Effects and duration are optional but worth setting deliberately:
POST /api/v1/videos
{
"prompt": "smooth cinematic reveal of a modern living room",
"imageUrl": "<publicUrl>",
"effects": ["push_in", "pan_left"],
"duration": 5
}
{ "jobId": "uuid", "status": "pending", "creditsCharged": 1 }Notice what comes back: a job ID and a pending status, not a video. The credit is already charged at this point. This is the moment to write the job to your database — associate the jobId with the listing, the photo, the user, and the credit spent. If your process dies before you persist it, you have paid for a render you can no longer find.
Prompt authoring is where product design enters. You can generate prompts from listing metadata you already have — room type, style, feature tags — which keeps the experience zero-effort for the user. Or expose a text field for power users. Most successful implementations do both: a sensible generated default with an optional override, so the common path requires no input at all.
Stage Four: Polling Without Blocking
Generation is asynchronous, which is a feature rather than a limitation — it means a long render never times out on an open HTTP connection. Poll the job until it reaches a terminal state:
GET /api/v1/videos/:jobId
{
"job": {
"status": "completed",
"video_url": "https://...",
"download_url": "https://...?download",
"credit_cost": 1
}
}Status polling is free, so the constraint on polling frequency is politeness and your own compute, not cost. Every few seconds is reasonable. The important architectural rule is that polling belongs in a background worker, not in the request the user is waiting on. If you poll inside a serverless function while the browser hangs, you will hit function timeouts on exactly the longest renders.
Handle failed as an ordinary outcome. The credit is refunded automatically, so a retry costs you the same as the original attempt and your billing ledger stays consistent without any compensating logic.
Stage Five: Merging Into a Branded Reel
Individual clips are useful, but the shareable asset is a reel. Pass completed job IDs in the order you want them to play, then layer on branding:
POST /api/v1/reels
{
"videoJobIds": ["uuid-1", "uuid-2"],
"orientation": "portrait",
"musicType": "lofi",
"textOverlay": { "text": "123 Main Street, Miami", "fontSize": 56 },
"ending": { "text": "Contact us today!", "duration": 3 },
"logo": { "url": "<logoPublicUrl>", "scale": 15 }
}The clip order is entirely yours to decide, which is a genuine product lever. A reel that opens with the exterior, moves through the main living space, and closes on the primary suite tells a better story than MLS photo order. If you have room-type metadata, you can sequence intelligently without asking the user to drag anything. The logo field is also where a white-label story lives — populate it with your customer's logo and the output carries their brand, not yours.
Production Architecture: What Separates a Demo From a Product
A working prototype takes an afternoon. The gap between that and something you can charge for is almost entirely in state management and failure handling. These five decisions account for most of it.
Job state persistence
Store every jobId in your own database the moment you receive it, along with the listing it belongs to and the credit you were charged.
Holding jobIds only in memory or in a browser tab, so a refresh or a deploy orphans in-flight renders you already paid for.
Polling strategy
A background worker or queue that polls on an interval with backoff, decoupled from any user's HTTP request.
Polling inside the request that the user is waiting on, which ties up a serverless function and times out on longer renders.
Credit accounting
Read the credits endpoint on a schedule, store the remaining balance, and refuse new jobs below a safety threshold you control.
Discovering you are out of credits when a customer's batch fails halfway through a twenty-photo listing.
Failure handling
Treat failed as a normal terminal state with a retry path, and surface a clear message plus an automatic retry to the user.
Treating any non-completed status as a fatal error and leaving the listing stuck with no clip and no explanation.
Upload concurrency
Request presigned URLs in one batched call for the whole listing, then upload in parallel with a sane concurrency cap.
Requesting one presigned URL per photo in a serial loop, which turns a twenty-photo listing into a slow crawl.
The through-line is that your database, not the API, is the source of truth for what your application believes about a render. The API will happily tell you the state of any job you ask about — but only if you kept the ID.
Product Decisions to Make Before You Write Code
The API is deliberately unopinionated, which means these questions land on you. Answering them up front saves a refactor later, because several of them change your data model.
- 1Which listing photos become clips — all of them, the first six, or a set the user picks by hand?
- 2Who writes the prompt: your app from listing metadata, or the end user in a text box?
- 3Do you expose camera effects to users, or pick sensible defaults and hide the complexity?
- 4Is a reel generated automatically when clips finish, or is merging a separate user action?
- 5Where do finished MP4s live long term — our URLs, or copied into your own storage?
- 6How do you meter usage to your customers: per video, per listing, per month, or bundled into an existing plan?
- 7What happens when a customer exhausts their allotment mid-listing?
- 8Do you brand reels with your own logo, your customer's logo, or let the customer upload one?
The metering question deserves the most thought. Because your cost is exactly one credit per clip and one per merge, you can price per listing with confidence — a fixed photo count means a fixed cost. Products that let users generate unlimited clips at a flat monthly rate are the ones that end up with margin surprises.
A Realistic First Milestone
Do not start with the full product. Start with a single script that takes a folder of photos and produces one reel. It exercises every endpoint, forces you to handle the async pattern, and produces something you can show a stakeholder. From there, the work is wrapping it in your own auth, storage, and UI.
Once that script works end to end, the remaining build is conventional web application work — no video expertise required. The full endpoint reference, request schemas, and error codes are in the API documentation, and the plan tiers and credit allotments are on the developer API page.
Start building today
Activate an API plan, generate a key, and have your first listing photo rendered into a cinematic clip within an hour.
Related Articles
API Keys, Authentication and Credits: A Complete Guide
Key rotation, the pooled credit model, and how to never run a batch dry mid-listing.
Async Jobs and Polling: Production Video Pipelines
Queue design, backoff, terminal states, and why polling belongs in a worker.
PhotoAIVideo Developer API
Endpoint reference, camera effects, credit costs, and plan tiers.