REST API Reference
Programmatic access to agent-media video generation. Create videos, manage actors, and monitor usage from any language.
Overview
Base URL
https://agent.media/api/v1Authentication
All requests require a Bearer token. API keys use the ma_ prefix.
Authorization: Bearer ma_your_api_key_hereRate Limiting
Rate limit headers are returned on responses:X-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-Reset. Exceeding the limit returns HTTP 429 with a Retry-After header.
Error Format
{
"error": {
"code": "missing_script",
"message": "Either script or prompt is required",
"type": "validation_error"
}
}Quickstart
1. Get an API key from the dashboard.
2. Create a video:
curl -X POST https://agent.media/api/v1/videos \
-H "Authorization: Bearer ma_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"script": "Ever wonder why top founders wake up at 5am? It is not about the alarm clock. It is about the mindset.",
"actor_slug": "emma",
"style": "hormozi"
}'3. Poll for completion (every 5 seconds):
curl https://agent.media/api/v1/videos/YOUR_JOB_ID \
-H "Authorization: Bearer ma_your_api_key"4. When status is completed, the output_url field contains the video URL.
/api/v1/videosCreate a video generation job. Credits are deducted immediately.
Core Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| script | string | Yes | - | Video script text (50-3000 chars). Required unless prompt is provided. |
| prompt | string | No | - | Text prompt to auto-generate script via GPT-4o. +5 credits. Required unless script is provided. |
| product_url | string | No | - | Product page URL for context when generating scripts. |
| actor_slug | string | No | - | Library actor slug for talking heads. Browse with GET /actors. |
| target_duration | number | No | auto | Target duration in seconds: 5, 10, or 15. Auto-estimated from script length if omitted. |
| style | string | No | hormozi | Subtitle style. See Subtitle Styles section. |
Advanced Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| tone | string | No | - | Video tone: energetic, calm, confident, dramatic |
| voice_speed | number | No | - | TTS speed multiplier (0.7 - 1.5) |
| music | string | No | - | Background music: chill, energetic, corporate, dramatic, upbeat |
| cta | string | No | - | End-screen call-to-action text (max 100 chars) |
| aspect_ratio | string | No | 9:16 | Aspect ratio: 9:16, 16:9, 1:1 |
| template | string | No | - | Template: monologue, testimonial, product-review, problem-solution, saas-review, before-after, listicle, product-demo |
| allow_broll | boolean | No | false | Enable AI-generated B-roll cutaways |
| broll_model | string | No | - | B-roll model: kling3, hailuo2, wan21 |
| broll_images | string[] | No | - | Image URLs for B-roll (max 10) |
| product_image_url | string | No | - | Product image URL for product-focused videos |
| dub_language | string | No | - | BCP-47 language code for dubbing (e.g. es, fr) |
| webhook_url | string | No | - | URL to receive webhook on completion |
Composition Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| composition_mode | string | No | - | Set to "pip" for picture-in-picture layout |
| pip_options | object | No | - | PIP config: { position, size, animation, frame_style } |
| pip_options.position | string | No | - | bottom-center, bottom-left, bottom-right |
| pip_options.size | string | No | - | small, medium, large |
| pip_options.animation | string | No | - | slide-up, slide-left, slide-right, fade, scale |
| pip_options.frame_style | string | No | - | none, rounded, shadow |
Scene Control
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| scenes | array | No | - | Manual scene definitions (max 30) |
| scenes[].type | string | No | - | talking_head or broll |
| scenes[].text | string | Yes | - | Narration text for the scene |
| scenes[].visual_prompt | string | No | - | Prompt for AI-generated visuals |
| scenes[].image | string | No | - | Image URL for the scene |
Validation Rules
- Request body must not exceed 1 MB.
- All fields are type-checked:
target_durationmust be 5, 10, or 15;tonemust be one of energetic, calm, confident, dramatic; etc. - Word count pacing: natural pace is 2.5 words/sec. Max words per duration: 5s = 12, 10s = 25, 15s = 37. Scripts exceeding 37 words are rejected.
- If a script is too long for the requested
target_duration, the duration is auto-upgraded to the next bucket (e.g. 13 words at 5s upgrades to 10s). Apacing_warningfield is included in the response when this happens.
Response (201)
{
"job_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "submitted",
"estimated_duration": 10,
"credits_deducted": 300,
"selected_voice": "cgSgspJ2msm6clMCkdW9",
"voice_auto_detected": false,
"word_count": 18,
"words_per_second": 1.8,
"max_words": 25
}When using prompt, the response also includes generated_script. When the duration is auto-upgraded, a pacing_warning string is included explaining the adjustment.
curl example
curl -X POST https://agent.media/api/v1/videos \
-H "Authorization: Bearer ma_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"script": "Ever wonder why top founders wake up at 5am? It is not about the alarm clock.",
"actor_slug": "emma",
"style": "hormozi",
"target_duration": 10,
"music": "chill"
}'/api/v1/videosList your video generation jobs with optional filtering and pagination.
Query Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| limit | number | No | 20 | Results per page (max 100) |
| offset | number | No | 0 | Results to skip for pagination |
| status | string | No | - | Filter: submitted, queued, processing, completed, failed, canceled |
| sort | string | No | newest | Sort order: newest or oldest |
Response (200)
{
"jobs": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"model_slug": "ugc-basic",
"operation": "ugc_video",
"status": "completed",
"credit_cost": 300,
"output_url": "https://pub-xxx.r2.dev/videos/a1b2c3d4.mp4",
"created_at": "2026-03-20T14:30:00.000Z",
"completed_at": "2026-03-20T14:32:15.000Z"
}
],
"total": 42
}curl "https://agent.media/api/v1/videos?limit=10&status=completed" \
-H "Authorization: Bearer ma_your_api_key"/api/v1/videos/:idGet the status and details of a single video job. Includes Retry-After header for in-progress jobs.
Path Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| id | string | Yes | - | Job ID (UUID) from video creation |
Response (200) -- completed
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "completed",
"output_url": "https://pub-xxx.r2.dev/videos/a1b2c3d4.mp4",
"credit_cost": 300,
"created_at": "2026-03-20T14:30:00.000Z",
"completed_at": "2026-03-20T14:32:15.000Z"
}Non-terminal statuses include a Retry-After: 5 header. Poll every 5 seconds.
curl https://agent.media/api/v1/videos/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
-H "Authorization: Bearer ma_your_api_key"/api/v1/videos/:idSoft-delete a video job. The video can be restored later.
Response (200)
{
"success": true,
"jobId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"deletedAt": "2026-03-20T15:00:00.000Z"
}curl -X DELETE https://agent.media/api/v1/videos/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
-H "Authorization: Bearer ma_your_api_key"/api/v1/videos/:id/cancelCancel an in-progress job. Only works for submitted, queued, or processing jobs. Credits are refunded.
Response (200)
{
"canceled": true,
"jobId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"credits_refunded": 300,
"refund_pending": false
}If the refund mechanism fails, refund_pending will be true and the refund will be retried automatically.
curl -X POST https://agent.media/api/v1/videos/a1b2c3d4-e5f6-7890-abcd-ef1234567890/cancel \
-H "Authorization: Bearer ma_your_api_key"/api/v1/actorsList available AI actors with optional filtering.
Query Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| gender | string | No | - | Filter by gender (e.g. female, male) |
| age_range | string | No | - | Filter by age range (e.g. 18-25, 26-35) |
| actor_type | string | No | - | Filter by type (e.g. Young Adult) |
| search | string | No | - | Search by name (case-insensitive) |
Response (200)
{
"actors": [
{
"id": "66ac63f6-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"name": "Emma",
"slug": "emma",
"gender": "female",
"age_range": "26-35",
"actor_type": "Young Adult",
"portrait_url": "https://pub-xxx.r2.dev/actors/emma/portrait.png",
"voice_id": "EXAVITQu4vr4xnSDxMaL",
"status": "active"
}
],
"total": 200
}# List all female actors
curl "https://agent.media/api/v1/actors?gender=female" \
-H "Authorization: Bearer ma_your_api_key"/api/v1/actors/:slugGet a single actor by slug. Returns similar slug suggestions on 404.
Response (200)
{
"actor": {
"id": "66ac63f6-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"name": "Emma",
"slug": "emma",
"gender": "female",
"age_range": "26-35",
"portrait_url": "https://pub-xxx.r2.dev/actors/emma/portrait.png",
"voice_id": "EXAVITQu4vr4xnSDxMaL",
"status": "active"
}
}curl https://agent.media/api/v1/actors/emma \
-H "Authorization: Bearer ma_your_api_key"/api/v1/accountGet account info including plan, credits, and feature limits.
Response (200)
{
"user_id": "user-uuid",
"plan": {
"tier": "starter",
"name": "Creator",
"status": "active",
"trial_active": false,
"trial_ends_at": null,
"current_period_end": "2026-04-20T00:00:00.000Z"
},
"credits": {
"monthly_remaining": 2400,
"monthly_allowance": 3900,
"purchased": 0,
"total": 2400
},
"limits": {
"max_concurrent_jobs": 3,
"max_video_duration": 10,
"models_available": ["ugc-basic"]
}
}Plan Tiers
| Tier | Name | Monthly Credits | Max Jobs | Max Duration |
|---|---|---|---|---|
| free | Free | 0 | 1 | 5s |
| payg | Pay As You Go | 0 | 2 | 15s |
| starter | Creator | 3,900 | 3 | 10s |
| creator | Pro | 6,900 | 5 | 15s |
| pro_plus | Pro Plus | 12,900 | 10 | 15s |
curl https://agent.media/api/v1/account \
-H "Authorization: Bearer ma_your_api_key"/api/v1/account/usageGet usage statistics for your account over a specified time period.
Query Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| period | string | No | 30d | Time period: 7d, 30d, or 90d |
Response (200)
{
"period": "30d",
"period_start": "2026-02-21T00:00:00.000Z",
"period_end": "2026-03-23T00:00:00.000Z",
"summary": {
"total_jobs": 45,
"completed_jobs": 40,
"failed_jobs": 3,
"credits_used": 12000
},
"by_model": [
{ "model_slug": "ugc-basic", "job_count": 45, "credits_used": 12000, "avg_duration_seconds": 85.2 }
],
"daily": [
{ "date": "2026-03-22", "job_count": 3, "credits_used": 900 }
],
"by_operation": [
{ "operation": "ugc_video", "job_count": 45 }
]
}curl "https://agent.media/api/v1/account/usage?period=7d" \
-H "Authorization: Bearer ma_your_api_key"/api/v1/account/keysCreate a new API key. The full key is returned only once -- store it securely.
Request Body
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| name | string | No | Default | Key name (max 100 characters) |
Response (201)
{
"key": "ma_a1b2c3d4e5f6789012345678901234ab",
"id": "key-uuid",
"key_prefix": "ma_a1b2c3d4",
"name": "Production Key",
"created_at": "2026-03-23T10:00:00.000Z"
}Maximum 25 active keys per account. The full key value is shown only at creation.
curl -X POST https://agent.media/api/v1/account/keys \
-H "Authorization: Bearer ma_your_api_key" \
-H "Content-Type: application/json" \
-d '{"name": "Production Key"}'/api/v1/account/keysList all active API keys. Returns metadata only -- the full key is never returned after creation.
Response (200)
{
"keys": [
{
"id": "key-uuid",
"key_prefix": "ma_a1b2c3d4",
"name": "Production Key",
"created_at": "2026-03-23T10:00:00.000Z",
"last_used_at": "2026-03-23T14:30:00.000Z"
}
]
}curl https://agent.media/api/v1/account/keys \
-H "Authorization: Bearer ma_your_api_key"/api/v1/account/keys/:keyIdRevoke an API key. The key can no longer be used for authentication.
Path Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| keyId | string | Yes | - | Key ID (UUID) from creation or listing |
Response (200)
{
"revoked": true,
"id": "key-uuid"
}curl -X DELETE https://agent.media/api/v1/account/keys/key-uuid-here \
-H "Authorization: Bearer ma_your_api_key"Subtitle Styles
The style parameter on video creation accepts these 17 values:
| Style | Description |
|---|---|
| hormozi | Yellow karaoke-style highlight (default) |
| minimal | Clean white text, minimal animation |
| bold | Neon cyan bold text |
| karaoke | Green pop karaoke highlighting |
| clean | White text on dark background |
| tiktok | TikTok-native subtitle style |
| neon | Neon glow effect |
| fire | Fire/flame animated text |
| glow | Soft glow effect |
| pop | Pop-in animation |
| aesthetic | Aesthetic/pastel style |
| impact | Impact font, bold white |
| pastel | Pastel color palette |
| electric | Electric/lightning effect |
| boxed | Text in colored boxes |
| gradient | Gradient-colored text |
| spotlight | Spotlight highlight effect |
Credit Costs
Videos are billed at 30 credits/second, rounded up to the nearest duration bucket.
| Duration | Credits | USD Equivalent |
|---|---|---|
| 5s | 150 | ~$1.50 |
| 10s | 300 | ~$3.00 |
| 15s | 450 | ~$4.50 |
AI script generation (using prompt) adds +5 credits. Credits are deducted immediately and refunded on failure or cancellation.
Errors
| HTTP Status | Error Type | Description |
|---|---|---|
| 400 | validation_error | Invalid or missing request parameters |
| 401 | authentication_error | Missing or invalid API key |
| 402 | insufficient_credits | Not enough credits for the operation |
| 403 | authentication_error | Forbidden (plan tier too low) |
| 404 | not_found | Resource not found |
| 429 | rate_limit_error | Too many requests -- check Retry-After header |
| 500 | server_error | Internal server error |
| 502 | server_error | Edge function unreachable |
Common Error Codes
| Code | When |
|---|---|
| missing_api_key | No Authorization header provided |
| invalid_json | Request body is not valid JSON |
| missing_script | Neither script nor prompt was provided |
| cta_too_long | CTA text exceeds 100 characters |
| job_not_found | Video job ID does not exist or belongs to another user |
| cannot_cancel | Job is already in a terminal state |
| plan_required | User plan tier too low for UGC videos |
| plan_limit | Requested duration exceeds plan limit |
| insufficient_credits | Not enough credits for the video |
| edge_function_unreachable | Backend service temporarily unavailable |
Important Notes
- Max video duration is 15 seconds. Valid values for target_duration are 5, 10, or 15.
- Videos are generated asynchronously. Use polling (GET /videos/:id every 5s) or provide a webhook_url.
- Credits are deducted immediately on job creation and refunded automatically on failure or cancellation.
- Voice is auto-selected based on the chosen actor. The voice, tts_provider, persona_slug, and face_photo_url parameters are not exposed via the REST API.
- Starter/Creator plans are limited to 10s. Pro and Pro Plus support the full 15s duration.
- API keys use the ma_ prefix and are hashed with SHA-256. The full key is only shown once at creation.