Authentication
API Key Authentication
API access is available on the Enterprise plan ($199/mo). Create and manage keys in your dashboard.
1. Generate an API Key
Navigate to Dashboard > API Keys and click "Create Key". Give it a descriptive name. The key value (sk_live_...) is shown once — copy it immediately. You can revoke and rotate keys at any time.
2. Include Bearer Token
Include your API key in the Authorization header on every request. All requests must use HTTPS.
Authorization: Bearer sk_live_your_api_key_here3. Security Best Practices
- Never expose API keys in client-side code or public repositories
- Use environment variables to store keys
- Rotate keys periodically and revoke unused ones
- Each key can be independently revoked without affecting others
Endpoints
Complete API Reference
All endpoints accept and return JSON. Generated files are delivered as signed R2 URLs. Credits are deducted before processing and refunded on failure.
Generation
/api/generate/image Auth 10 creditsGenerate Image
Generate an image from a text prompt. Supports multiple AI models per plan tier.
Required Parameters
promptstring— Text prompt (1-2,000 chars)Optional Parameters
widthnumber— Image width 256-2048 (default 1024)heightnumber— Image height 256-2048 (default 1024)stepsnumber— Inference steps 1-50 (default 4)seednumber— Reproducibility seedstylestring— photorealistic | illustration | 3d | flatmodelstring— grok-imagine | flux-2-dev | flux-2-pro | ideogram-v3 | flux-kontext-maxnegativePromptstring— What to avoid in the imageResponse
{ "data": { "jobId": "uuid", "status": "queued", "message": "..." } }/api/generate/video Auth 250 creditsGenerate Video
Generate a video from a script. Optionally attach an avatar face image.
Required Parameters
scriptstring— Video script (1-5,000 chars)Optional Parameters
avatarImagestring— HTTPS URL of face image for avatarvoiceIdstring— Cloned voice IDdurationnumber— Max seconds 3-60resolutionstring— 720p | 1080p (default 720p)stylestring— professional | casual | energeticmodelstring— wan-2.6 | kling-2.6-pro | kling-3.0-pro | veo-3.1Response
{ "data": { "jobId": "uuid", "status": "queued", "message": "..." } }/api/generate/voice Auth 80 creditsGenerate Voice (TTS)
Convert text to speech using AI voices. Supports multiple TTS providers.
Required Parameters
textstring— Text to speak (1-10,000 chars)Optional Parameters
voiceIdstring— Custom voice ID (or default)speednumber— Playback speed 0.5-2.0 (default 1.0)languagestring— ISO language code (default en)modelstring— kokoro | elevenlabs-v3 | fish-audio-s1Response
{ "data": { "jobId": "uuid", "status": "queued", "estimatedMinutes": 1, "message": "..." } }/api/generate/voice-clone Auth 80 creditsClone Voice
Create a custom voice clone from an audio sample. Requires Creator plan or higher.
Required Parameters
namestring— Voice name (1-100 chars)sampleAudioUrlstring— HTTPS URL to 15-30s audio sampleResponse
{ "voiceId": "string", "message": "Voice cloned successfully" }/api/generate/avatar Auth 750 creditsGenerate Avatar Video
Create a talking-head video from a photo and script or audio.
Required Parameters
imagestring— HTTPS URL of spokesperson photoresolutionstring— 480p | 720p | 1080pmodelstring— veed-fabric | creatify-aurora | kling-avatar-v2 | omnihuman-1.5Optional Parameters
audiostring— Pre-recorded audio URLtextstring— Text to speak (if no audio)voiceIdstring— Voice ID for TTSResponse
{ "data": { "jobId": "uuid", "status": "queued", "message": "..." } }/api/generate/clip Auth 30 creditsAuto-Clip Video
Extract the best clips from a long video using AI viral scoring.
Required Parameters
sourceVideoUrlstring— HTTPS URL of source videoOptional Parameters
maxClipsnumber— Maximum clips to extract 1-20minDurationnumber— Min clip duration (seconds)maxDurationnumber— Max clip duration (seconds)addCaptionsboolean— Add auto-captionsaspectRatiostring— 9:16 | 1:1 | 16:9viralScoreThresholdnumber— Minimum score 1-10Response
{ "data": { "jobId": "uuid", "status": "queued", "message": "..." } }/api/generate/b-roll Auth 150 creditsGenerate B-Roll
Generate cinematic B-roll footage from a text description.
Required Parameters
promptstring— Scene descriptionOptional Parameters
durationnumber— Duration 3-6 secondsresolutionstring— 480p | 720pmodelstring— wan-2.6 | kling-2.6-proResponse
{ "data": { "jobId": "uuid", "status": "queued", "message": "..." } }/api/generate/text2video Auth 250 creditsText to Video
Generate a video directly from a text script.
Required Parameters
scriptstring— Video scriptOptional Parameters
durationnumber— Duration in secondsresolutionstring— 720p | 1080pstylestring— cinematic | documentary | animation | aerialmodelstring— wan-2.6 | kling-2.6-pro | kling-3.0-pro | veo-3.1Response
{ "data": { "jobId": "uuid", "status": "queued", "message": "..." } }/api/generate/commercial Auth 3000 creditsGenerate Commercial
AI-generated commercial with script, voiceover, visuals, and composition.
Required Parameters
productstring— Product name/descriptionplatformstring— tiktok | youtube | instagram | tvdurationnumber— 15 | 30 | 60 secondstonestring— professional | energetic | casual | luxury | funnyOptional Parameters
targetAudiencestring— Target audience descriptionspokespersonImagestring— URL for AI spokespersonproductImagesstring[]— Array of product image URLsvoiceIdstring— Custom voice IDvoiceModelstring— TTS model to usemusicMoodstring— Background music moodvideoModelstring— Video generation modelResponse
{ "data": { "jobId": "uuid", "status": "queued", "message": "..." } }/api/generate/translate Auth 1800 creditsTranslate Video
Translate a video to another language with lip-sync.
Required Parameters
videoUrlstring— HTTPS URL of source videooutputLanguagestring— Target language ISO codeOptional Parameters
preserveOriginalVoiceboolean— Keep original voice timbreResponse
{ "data": { "jobId": "uuid", "status": "queued", "message": "..." } }/api/generate/instant-ad Auth 500-1,250 creditsInstant Ad from URL
Scrape a website URL and auto-generate ad creatives.
Required Parameters
websiteUrlstring— Product/landing page URLplatformstring— tiktok | youtube | instagram | facebook | linkedincountnumber— Number of variations 1-4stylestring— modern | bold | minimal | luxury | playfulOptional Parameters
outputFormatstring— image | video | bothbrandProfileIdstring— Saved brand profile IDResponse
{ "data": { "jobId": "uuid", "status": "queued", "message": "..." } }/api/generate/photoshoot Auth 30 creditsAI Product Photoshoot
Generate professional product photos with AI backgrounds and lighting.
Required Parameters
productImagestring— Uploaded product photo URLbackgroundstring— studio-white | lifestyle | outdoor | flat-lay | customanglestring— front | hero | 45-degree | top-down | lifestylelightingstring— studio | natural | dramatic | soft | golden-hourcountnumber— Number of photos 1-4Optional Parameters
customBackgroundstring— Description if background=custommodelstring— Image model IDResponse
{ "data": { "jobId": "uuid", "status": "queued", "message": "..." } }Voice Agent
/api/voice-agent/calls/outbound Auth 10/min creditsStart Outbound Call
Initiate an AI phone call to a target number using a configured agent.
Required Parameters
agentIdstring— Voice agent IDphoneNumberstring— Target phone number (E.164)Response
{ "data": { "callId": "uuid", "status": "active" } }/api/voice-agent/calls AuthList Calls
List all voice agent calls for the current user.
Response
{ "data": [...calls] }/api/voice-agent/agents AuthCreate Agent
Create a new voice agent with system prompt, greeting, and voice configuration.
Required Parameters
namestring— Agent display namesystemPromptstring— System prompt for the LLMgreetingstring— Opening greeting textttsModelstring— kokoro | elevenlabs-v3 | fish-audio-s1llmModelstring— LLM model for conversationResponse
{ "data": { "id": "uuid", "name": "...", ... } }Management
/api/jobs AuthList Jobs
List generation jobs for the current user. Returns status, output URLs, and metadata.
Response
{ "data": [...jobs] }/api/usage AuthGet Usage
Retrieve current credit balance, usage counts, and billing cycle info.
Response
{ "data": { "credits": 4500, "used": { "images": 12, ... }, "plan": "enterprise" } }/api/keys AuthList API Keys
List all API keys for the current user. Enterprise only.
Response
{ "data": [...keys] }/api/keys AuthCreate API Key
Generate a new API key. Enterprise only. Key value is shown once on creation.
Required Parameters
namestring— Key display nameResponse
{ "data": { "id": "uuid", "key": "sk_live_...", "name": "..." } }Webhooks
/api/settings AuthConfigure Webhook URL
Set or update the webhook URL for job completion notifications. URL is validated against SSRF.
Required Parameters
webhookUrlstring— HTTPS URL to receive webhook eventsResponse
{ "data": { "webhookUrl": "https://..." } }Code Examples
Quick Start
Copy-paste examples for common operations. Replace YOUR_API_KEY with your Enterprise API key.
curl -X POST https://useapexstudio.com/api/generate/image \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "A futuristic city skyline at sunset, photorealistic",
"width": 1024,
"height": 1024,
"model": "flux-2-pro"
}'
# Response:
# {
# "data": {
# "jobId": "abc123-...",
# "status": "queued",
# "message": "Image generation job queued"
# }
# }import requests
import time
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://useapexstudio.com"
HEADERS = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
}
# 1. Submit generation job
resp = requests.post(f"{BASE_URL}/api/generate/image", headers=HEADERS, json={
"prompt": "A futuristic city skyline at sunset, photorealistic",
"width": 1024,
"height": 1024,
"model": "flux-2-pro",
})
resp.raise_for_status()
job_id = resp.json()["data"]["jobId"]
# 2. Check rate limit headers
print(f"Remaining requests: {resp.headers.get('X-RateLimit-Remaining')}")
# 3. Poll for completion (or use webhooks)
while True:
status = requests.get(f"{BASE_URL}/api/jobs?id={job_id}", headers=HEADERS)
job = status.json()["data"]
if job["status"] in ("completed", "failed"):
break
time.sleep(2)
print(f"Output: {job.get('outputUrl')}")const API_KEY = "YOUR_API_KEY";
const BASE_URL = "https://useapexstudio.com";
// 1. Submit generation job
const response = await fetch(`${BASE_URL}/api/generate/image`, {
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
prompt: "A futuristic city skyline at sunset, photorealistic",
width: 1024,
height: 1024,
model: "flux-2-pro",
}),
});
const { data } = await response.json();
console.log("Job ID:", data.jobId);
// 2. Check rate limit headers
console.log("Remaining:", response.headers.get("X-RateLimit-Remaining"));
console.log("Reset at:", new Date(Number(response.headers.get("X-RateLimit-Reset")) * 1000));
// 3. Poll for completion (or use webhooks)
let job;
do {
await new Promise((r) => setTimeout(r, 2000));
const res = await fetch(`${BASE_URL}/api/jobs?id=${data.jobId}`, {
headers: { Authorization: `Bearer ${API_KEY}` },
});
job = (await res.json()).data;
} while (job.status !== "completed" && job.status !== "failed");
console.log("Output URL:", job.outputUrl);Rate Limiting
Request Limits
Current Limits
| Endpoint Type | Rate | Window |
|---|---|---|
| Generation endpoints (POST /api/generate/*) | 5 requests | 10 seconds |
| Read endpoints (GET /api/jobs, /api/usage, etc.) | 20 requests | 10 seconds |
| File uploads (/api/upload/*) | 10 requests | 60 seconds |
| Destructive operations (DELETE) | 10 requests | 60 seconds |
| Outbound calls (Enterprise) | 200 calls | 1 hour |
Rate Limit Headers
Every response includes rate limit headers so you can track your usage in real-time:
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests allowed in the current window |
X-RateLimit-Remaining | Number of requests remaining in the current window |
X-RateLimit-Reset | Unix timestamp (seconds) when the current window resets |
Retry-After | Seconds to wait before retrying (only on 429 responses) |
When You Hit a 429
When rate limited, the API returns HTTP 429 with a JSON body:
{
"error": "Too many requests",
"code": "RATE_LIMITED"
}Read the Retry-After header to know how many seconds to wait before retrying. Implement exponential backoff in your client for best results.
Webhooks
Real-Time Job Notifications
Instead of polling, configure a webhook URL to receive notifications when generation jobs complete or fail.
Setup
Configure your webhook URL in Dashboard > Settings. The URL must be a public HTTPS endpoint. All webhook URLs are validated against SSRF protections (private IPs, internal hostnames, and cloud metadata endpoints are blocked).
Webhook Payload (Job Completed)
When a job finishes, we POST the following JSON to your webhook URL:
{
"event": "job.completed",
"timestamp": "2026-03-16T12:00:00Z",
"data": {
"jobId": "550e8400-e29b-41d4-a716-446655440000",
"type": "image",
"status": "completed",
"outputUrl": "https://cdn.useapexstudio.com/outputs/550e.../output.png",
"outputType": "image/png",
"metadata": {
"model": "flux-2-pro",
"width": 1024,
"height": 1024,
"durationMs": 8200
},
"createdAt": "2026-03-16T11:59:50Z",
"completedAt": "2026-03-16T12:00:00Z"
}
}Webhook Payload (Job Failed)
{
"event": "job.failed",
"timestamp": "2026-03-16T12:00:00Z",
"data": {
"jobId": "550e8400-e29b-41d4-a716-446655440000",
"type": "video",
"status": "failed",
"error": "Generation failed",
"creditsRefunded": 250,
"createdAt": "2026-03-16T11:59:50Z",
"failedAt": "2026-03-16T12:00:00Z"
}
}Credits are automatically refunded on job failure. The errorfield contains a generic message — internal details are never exposed.
Example Payloads by Job Type
| Job Type | outputType | Extra Metadata |
|---|---|---|
| image | image/png | model, width, height |
| video | video/mp4 | model, durationSeconds, resolution |
| voice | audio/wav | model, durationSeconds, language |
| avatar | video/mp4 | model, durationSeconds, resolution |
| clip | video/mp4 | clipCount, viralScores[] |
| commercial | video/mp4 | sceneClips[], platform, duration |
| translate | video/mp4 | outputLanguage, durationSeconds |
| instant-ad | image/png or video/mp4 | variationCount, platform, format |
| photoshoot | image/png | photoCount, background, lighting |
Retry Behavior
- Failed webhook deliveries are retried up to 3 times
- Retries use exponential backoff: 10s, 60s, 300s
- Your endpoint must return a 2xx status code within 10 seconds
- After all retries are exhausted, the webhook is marked as failed (check job status via API)
Error Handling
Error Responses
All errors follow a consistent JSON shape. Internal details are never exposed.
Error Response Shape
{
"error": "Human-readable error message",
"code": "MACHINE_READABLE_CODE"
}Error Codes
| HTTP Status | Code | Description |
|---|---|---|
| 400 | BAD_REQUEST | Invalid input parameters. Check the error message for specifics. |
| 401 | UNAUTHORIZED | Missing or invalid API key. |
| 402 | PAYMENT_REQUIRED | Insufficient credits. Purchase more at Dashboard > Billing. |
| 403 | FORBIDDEN | Model or feature not available on your plan. Upgrade required. |
| 429 | RATE_LIMITED | Too many requests. Check Retry-After header. |
| 500 | INTERNAL_ERROR | Server error. Credits are auto-refunded. Retry after a short delay. |
| 503 | SERVICE_UNAVAILABLE | Temporary outage. Retry with exponential backoff. |
Platform Features
Enterprise-Grade Infrastructure
Low Latency
Images in under 10 seconds. Voice in 5-15 seconds. Avatar videos in 30-90 seconds. All on dedicated GPU infrastructure.
Webhooks
Real-time notifications when jobs complete or fail. Retries with exponential backoff. Configurable in dashboard.
Enterprise Security
Rate limiting, SSRF protection, input validation with Zod, webhook URL validation, and CSP headers.
Global CDN
Generated assets served via Cloudflare R2 with global edge caching. Signed URLs valid for 24 hours.
99.9% Uptime SLA
Enterprise plan includes a 99.9% uptime SLA. Dedicated GPU pools ensure consistent generation times.
Data Privacy
All data encrypted at rest and in transit. Voice samples and generated content are never used for training. GDPR compliant.
FAQ
Frequently Asked Questions
How do I get API access?
API access is available on the Enterprise plan ($199/mo). Sign up, navigate to Dashboard > API Keys, and generate your first API key. You can also contact our team for a custom Enterprise agreement with higher rate limits.
What authentication method does the API use?
The API uses Bearer token authentication. Include your API key in the Authorization header: 'Authorization: Bearer your_api_key'. API keys can be rotated and revoked from your dashboard at any time.
Is there a rate limit?
Enterprise plan includes 5 generation requests per 10 seconds (strict limit) and 20 read requests per 10 seconds (standard limit). Rate limit information is returned in response headers (X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset). Contact us for higher limits.
How do webhooks work?
Register a webhook URL in Dashboard > Settings. When a job completes or fails, we POST a JSON payload to your URL. Webhooks retry up to 3 times with exponential backoff. All webhook URLs are validated against SSRF protections.
What response format does the API use?
All API responses are JSON. Success responses use { data: ... } and errors use { error: string, code: string }. Generated files (video, audio, images) are returned as signed R2 URLs valid for 24 hours.
What happens when a job fails?
Credits are automatically refunded on failure. The job status updates to 'failed' and a webhook notification fires if configured. You can check job status via GET /api/jobs.