API Documentation
Programmatic access to FaceDub video generation. Create, monitor, and retrieve AI-generated UGC videos via REST API.
Authentication
API access requires an Agency plan. Generate API keys from your Dashboard under the API Keys tab.
All API keys start with fdb_ and are shown only once at creation. Store them securely.
Include your API key in the Authorization header:
Authorization: Bearer fdb_your_api_key_hereBase URL
https://api.facedub.ioAll endpoints are relative to this base URL.
Endpoints
/jobsCreate a new video generation job
Request Body (multipart/form-data)
| Field | Type | Description |
|---|---|---|
| character_photo | file | Photo of the character (JPG, PNG, WebP) |
| reference_video | file | Reference video with motion to replicate |
| duration | int | Video duration in seconds (1-30, default 5) |
Response
{
"job_id": "abc123def456",
"status": "queued",
"credits_charged": 2,
"is_overage": false
}/jobsList your recent jobs (up to 50)
[
{
"id": "abc123def456",
"status": "completed",
"stage": "done",
"output_url": "https://cdn.facedub.io/...",
"created_at": 1709337600,
"error": null,
"duration_seconds": 10,
"credits_charged": 2
}
]/jobs/{job_id}Get status of a specific job
{
"id": "abc123def456",
"status": "processing",
"stage": "generating_views",
"output_url": null,
"created_at": 1709337600,
"error": null,
"duration_seconds": 10,
"credits_charged": 2
}/jobs/{job_id}/stream?token=YOUR_JWTSSE stream of real-time job status updates
Note: SSE streaming requires a JWT token (not API key). Pass it as a token query parameter since EventSource cannot set headers.
/usageGet your current credit usage
{
"plan": "agency",
"credits_used": 42,
"credits_limit": 150,
"bonus_credits": 0,
"credits_remaining": 108
}/api-keysCreate a new API key (max 5 active)
{
"name": "Production Key"
}{
"id": "key_abc123",
"name": "Production Key",
"key": "fdb_a1b2c3d4e5f6...",
"prefix": "fdb_a1b2c3d4",
"created_at": 1709337600
}The full key is returned only once at creation. Store it securely.
/api-keysList your API keys (prefix only)
/api-keys/{key_id}Revoke an API key
Job Statuses
queuedJob is waiting in the processing queue
processingAI pipeline is actively generating the video
completedVideo is ready — output_url is populated
failedGeneration failed — check the error field
Rate Limits
Requests are rate-limited per user on a sliding 1-minute window. Exceeding the limit returns 429 Too Many Requests with a Retry-After header.
| Endpoint | Limit |
|---|---|
| POST /jobs | 10/min |
| GET /jobs/* | 60/min |
| All other endpoints | 120/min |
Concurrency
API access allows up to 2 concurrent jobs per user. Submitting a 3rd job while 2 are still processing returns 429. Wait for a job to complete before submitting more.
Code Examples
cURL
curl -X POST https://api.facedub.io/jobs \
-H "Authorization: Bearer fdb_your_key_here" \
-F "[email protected]" \
-F "[email protected]" \
-F "duration=10"Python
import requests
import time
API_KEY = "fdb_your_key_here"
BASE = "https://api.facedub.io"
headers = {"Authorization": f"Bearer {API_KEY}"}
# Create job
with open("photo.jpg", "rb") as photo, open("video.mp4", "rb") as video:
res = requests.post(
f"{BASE}/jobs",
headers=headers,
files={
"character_photo": photo,
"reference_video": video,
},
data={"duration": 10},
)
job = res.json()
print(f"Job created: {job['job_id']}")
# Poll for completion
while True:
status = requests.get(
f"{BASE}/jobs/{job['job_id']}",
headers=headers,
).json()
print(f"Status: {status['status']} — {status['stage']}")
if status["status"] in ("completed", "failed"):
break
time.sleep(5)
if status["status"] == "completed":
print(f"Download: {status['output_url']}")Node.js
const fs = require("fs");
const API_KEY = "fdb_your_key_here";
const BASE = "https://api.facedub.io";
async function createVideo() {
const form = new FormData();
form.append("character_photo", fs.createReadStream("photo.jpg"));
form.append("reference_video", fs.createReadStream("video.mp4"));
form.append("duration", "10");
const res = await fetch(`${BASE}/jobs`, {
method: "POST",
headers: { Authorization: `Bearer ${API_KEY}` },
body: form,
});
const job = await res.json();
console.log("Job created:", job.job_id);
// Poll for completion
while (true) {
const status = await fetch(`${BASE}/jobs/${job.job_id}`, {
headers: { Authorization: `Bearer ${API_KEY}` },
}).then((r) => r.json());
console.log(`Status: ${status.status} — ${status.stage}`);
if (["completed", "failed"].includes(status.status)) {
if (status.status === "completed") {
console.log("Download:", status.output_url);
}
break;
}
await new Promise((r) => setTimeout(r, 5000));
}
}
createVideo();Error Codes
| Code | Meaning |
|---|---|
| 400 | Bad request — invalid parameters |
| 401 | Unauthorized — missing or invalid API key |
| 403 | Forbidden — not on Agency plan, or account suspended |
| 404 | Not found — job doesn't exist or isn't yours |
| 429 | Too many requests — rate or concurrency limit exceeded |
| 500 | Internal server error — try again or contact support |
Need Help?
Agency plan includes priority support. Reach out at [email protected]