Developers
Viralance API
Generate AI videos, images, voiceovers and 3D models from your own code over plain HTTPS and JSON. You use the same models, prices, moderation and credit wallet as viralance.com. There is no SDK to install and no MCP client needed.
- Base URL
https://viralance-mcp-70260648239.us-central1.run.app/v1- Auth
- Authorization: Bearer vrl_…
- Spec
- /v1/openapi.json
Quickstart
1. Create an API key on the API keys page and give it the scopes you need. 2. Start a job. 3. Poll the job or receive a webhook when it finishes. Video generation usually takes 1 to 3 minutes.
curl -X POST https://viralance-mcp-70260648239.us-central1.run.app/v1/videos \
-H "Authorization: Bearer $VIRALANCE_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 6f1c2d3e-order-1042" \
-d '{
"prompt": "A golden retriever surfing a turquoise wave, slow motion",
"model": "veo3.1-fast",
"duration": 8,
"resolution": "720p",
"aspectRatio": "9:16",
"callbackUrl": "https://example.com/webhooks/viralance"
}'HTTP/1.1 202 Accepted
X-Request-Id: req_4f0c...
{
"data": {
"videoId": "Xk3v9QpL2m",
"status": "processing",
"creditCost": 12,
"creditsRemaining": 188
},
"webhook": { "url": "https://example.com/webhooks/viralance", "registered": true },
"request_id": "req_4f0c..."
}curl https://viralance-mcp-70260648239.us-central1.run.app/v1/videos/Xk3v9QpL2m \
-H "Authorization: Bearer $VIRALANCE_API_KEY"
# {"data":{"id":"Xk3v9QpL2m","status":"completed",
# "videoUrl":"https://...mp4","thumbnailUrl":"https://..."}, "request_id":"req_..."}const BASE = 'https://viralance-mcp-70260648239.us-central1.run.app/v1';
const headers = {
Authorization: `Bearer ${process.env.VIRALANCE_API_KEY}`,
'Content-Type': 'application/json',
};
async function api(path, init = {}) {
const res = await fetch(BASE + path, { ...init, headers: { ...headers, ...init.headers } });
const body = await res.json();
if (!res.ok) {
const err = new Error(body.error?.message ?? res.statusText);
Object.assign(err, { status: res.status, code: body.error?.code, retryAfter: res.headers.get('Retry-After') });
throw err;
}
return body;
}
// 1. Start the job. Reuse the same Idempotency-Key when you retry.
const { data: job } = await api('/videos', {
method: 'POST',
headers: { 'Idempotency-Key': crypto.randomUUID() },
body: JSON.stringify({ prompt: 'Neon Tokyo street at night, rain, handheld', model: 'kling-3.0-pro', duration: 5 }),
});
// 2. Poll until it finishes (or use callbackUrl instead).
let video;
do {
await new Promise((r) => setTimeout(r, 10_000));
({ data: video } = await api(`/videos/${job.videoId}`));
} while (video.status === 'pending' || video.status === 'processing');
console.log(video.status, video.videoUrl);A video's status is pending, processing, completed or failed. Failed jobs are refunded automatically.
Authentication
Send your key in the Authorization header on every request: Authorization: Bearer vrl_…. Keys in query strings are not accepted, because URLs end up in logs. OAuth access tokens from the MCP sign-in flow work too.
Every key carries scopes. A request outside those scopes gets 403 with INSUFFICIENT_SCOPE before any credits are touched. Keys can also have an expiry date, an IP allowlist and a daily credit spend cap. Revoking a key takes effect on the next request.
| Scope | Allows |
|---|---|
| video:create | Generate, edit, analyze and compose videos |
| video:read | List videos and read their status |
| image:create | Images, try-on, product dimensions, voiceovers, 3D, saving products |
| image:read | List images and saved products |
| credits:read | Balance and credit history |
| prompt:use | Prompt enhancement, captions, hooks |
| trends:read | Read trends and unlock them |
| autopilot:use | Start, approve and read autopilot runs |
Keep keys on your server. Never ship them in a browser or mobile app.
Endpoints
Request bodies use the same field names as the MCP tools, for example prompt, model, duration, resolution, aspectRatio, mode, sourceImageUrl. The OpenAPI spec lists every field and allowed value.
Videos
| POST | /v1/videos | Generate a video. Returns 202 + videoId. Idempotent, supports callbackUrl. | video:create |
| GET | /v1/videos | List videos. limit, offset, status. | video:read |
| GET | /v1/videos/{id} | Status, progress, videoUrl, thumbnailUrl. | video:read |
| POST | /v1/edits | Reframe, upscale, subtitles, lip-sync, restyle and more. Supports callbackUrl. | video:create |
| POST | /v1/films | Stitch 2-20 clips (+ music) into one film. | video:create |
| POST | /v1/analyses | Virality score or content analysis. | video:create |
Images, audio and 3D
| POST | /v1/images | Generate an image (returns the URL). | image:create |
| GET | /v1/images | List images. limit, offset. | image:read |
| POST | /v1/images/edits | Background removal or outpaint. | image:create |
| POST | /v1/images/try-on | Virtual try-on (person + garment). | image:create |
| POST | /v1/images/product-dimensions | Marketplace dimension image. | image:create |
| POST | /v1/voiceovers | Text-to-speech voiceover. | image:create |
| POST | /v1/3d-models | Image to 3D model (GLB). | image:create |
Autopilot
| POST | /v1/autopilot/runs | Start a multi-asset run from one brief. Supports callbackUrl. | autopilot:use |
| GET | /v1/autopilot/runs/{id} | Status, items, activity log. | autopilot:use |
| POST | /v1/autopilot/runs/{id}/approve | Approve or reject a run awaiting approval. | autopilot:use |
Account, models and helpers
| GET | /v1/models | Every model with its exact credit cost per duration and resolution. | none |
| GET | /v1/balance | Current credit balance. | credits:read |
| GET | /v1/credits/history | Credit transactions, newest first. | credits:read |
| GET | /v1/products | Saved products. | image:read |
| POST | /v1/products | Create or update a saved product (free). | image:create |
| POST | /v1/prompts/enhance | Rewrite a prompt for a model. | prompt:use |
| POST | /v1/prompts/caption | Caption and hashtags. | prompt:use |
| POST | /v1/prompts/hooks | Opening hooks. | prompt:use |
| GET | /v1/trends | Latest trends (locked until unlocked). | trends:read |
| POST | /v1/trends/unlock | Unlock trends for 7 days (10 credits). | trends:read |
| GET | /v1/webhooks/secret | Webhook signing secret for this key. | any |
| POST | /v1/webhooks/secret/rotate | Rotate the signing secret. | any |
| GET | /v1/openapi.json | OpenAPI 3.1 spec. | public |
List endpoints take limit (1 to 100, default 20) and offset, and return a pagination object:
GET /v1/videos?limit=20&offset=0&status=completed
{
"data": [ { "id": "...", "status": "completed", "videoUrl": "..." } ],
"pagination": { "limit": 20, "offset": 0, "total": 57, "has_more": true, "next_offset": 20 },
"request_id": "req_..."
}Media inputs for edits, such as sourceVideoUrl, must be files hosted by Viralance or on fal.media. You can pass the URLs returned by this API directly.
Responses and errors
A success returns { "data": …, "request_id": "req_…" }. An error returns { "error": { "code", "message", "details?", "request_id" } }. Every response also carries an X-Request-Id header. Branch on error.code, not on the message text.
HTTP/1.1 402 Payment Required
{
"error": {
"code": "INSUFFICIENT_CREDITS",
"message": "Insufficient credits. Required: 12, Available: 3",
"details": { "required": 12, "available": 3, "shortfall": 9 },
"request_id": "req_91ab..."
}
}| 200 / 201 | Success. 201 means a finished resource was created (images, voiceovers, some edits). |
| 202 | Job accepted and queued (videos, most edits, autopilot). Poll it or wait for the webhook. |
| 400 | Invalid input, invalid JSON, invalid callbackUrl or a malformed Idempotency-Key. |
| 401 | Missing, invalid, revoked or expired key. |
| 402 | Not enough credits. details.required and details.available say how many. |
| 403 | The key lacks the required scope, the IP is not on the allowlist, or the account is disabled. |
| 404 | The resource does not exist or belongs to another account. |
| 409 | A request with the same Idempotency-Key is still running. Retry after Retry-After. |
| 422 | The Idempotency-Key was already used with a different request body. |
| 429 | Rate limit, daily per-key spend cap or concurrent-job limit. Always sends Retry-After. |
| 500 | Internal error. The message is generic. Quote request_id if you contact support. |
| 502 / 503 | The model provider failed (credits for that job are refunded automatically) or a dependency is down. |
Pricing
The API has no separate plan or markup. Each call spends the same credits as the same action on viralance.com, from the same balance. For example, an 8-second 720p VEO 3.1 Fast video costs 12 credits in the app and 12 credits over the API. Costs depend on model, duration and resolution. GET /v1/models returns the full price table, and every generation response includes creditCost and creditsRemaining.
Credits are charged when a job is accepted. If the model provider fails, they are refunded automatically. Top up on the credits page. Credits are one-time purchases, with no subscription; see pricing for every pack and the model catalog for per-clip costs.
Rate limits
- Requests: 30 per minute per key by default, with a burst limit of 10 in any 10 seconds. The API and MCP connections made with the same key share one budget. Each response includes
X-RateLimit-Limit,X-RateLimit-RemainingandX-RateLimit-Reset. - Daily spend cap: each key can spend up to 500 credits per UTC day by default, so a leaked key cannot drain your balance.
- Concurrency: up to 5 video jobs, 10 image jobs and 3 autopilot runs can be in progress at once.
Any of these returns 429 with a Retry-After header in seconds. Wait that long, then retry with the same Idempotency-Key.
Idempotency
Network errors happen. To retry a credit-spending POST safely, send an Idempotency-Key header: a unique value such as a UUID, 1 to 255 characters from A-Z a-z 0-9 _ - : .. Keys are stored per account for 24 hours.
- Same key and same body: you get the original response back, with an
Idempotent-Replayed: trueheader. The job is not run again and you are not charged again. - Same key, different body:
422 IDEMPOTENCY_KEY_MISMATCH. - Same key while the first request is still running:
409 IDEMPOTENCY_KEY_IN_USE. Retry after a few seconds. - If the first attempt was rejected before any charge (400, 402, 403, 404 or 429), the key is released. You can fix the cause, for example by topping up credits, and retry with the same key.
The header works on every generation endpoint: videos, edits, films, analyses, images, image edits, try-on, product dimensions, voiceovers, 3D models, trends unlock and autopilot. Other endpoints ignore it.
Webhooks
Instead of polling, add callbackUrl to POST /v1/videos, POST /v1/edits or POST /v1/autopilot/runs. When the job reaches a final state, Viralance sends one signed POST to that URL. Delivery usually comes within 1 to 2 minutes of the job finishing. Events are video.completed, video.failed, and autopilot_run.completed, .partial, .failed or .cancelled.
- The URL must be public
httpson port 443 with a DNS host name. IP addresses, localhost and private networks are rejected. Redirects are not followed. - Respond with any 2xx within 10 seconds. Other responses are retried after 1 minute, 5 minutes, 30 minutes, 2 hours and 6 hours, then the delivery is dropped. A delivery can arrive more than once, so de-duplicate on
id. - Webhooks are a convenience.
GET /v1/videos/{id}is always the source of truth.
POST https://example.com/webhooks/viralance
Content-Type: application/json
Viralance-Event-Id: evt_video_Xk3v9QpL2m
Viralance-Event-Type: video.completed
Viralance-Signature: t=1790000000,v1=5b8f...e21c
{
"id": "evt_video_Xk3v9QpL2m",
"type": "video.completed",
"created": "2026-09-26T12:03:11.000Z",
"data": {
"id": "Xk3v9QpL2m",
"status": "completed",
"model": "veo3.1-fast",
"duration": 8,
"videoUrl": "https://...mp4",
"thumbnailUrl": "https://...jpg",
"error": null,
"creditCost": 12
}
}Verify every delivery. Each API key has its own signing secret. Fetch it with GET /v1/webhooks/secret and rotate it with POST /v1/webhooks/secret/rotate. The Viralance-Signature header is t=<unix seconds>,v1=<hex>, where v1 = HMAC-SHA256(secret, t + "." + rawBody).
import crypto from 'node:crypto';
import express from 'express';
const app = express();
const SECRET = process.env.VIRALANCE_WEBHOOK_SECRET; // from GET /v1/webhooks/secret
// Verify against the RAW body. A re-serialized JSON object will not match.
app.post('/webhooks/viralance', express.raw({ type: 'application/json' }), (req, res) => {
const header = req.get('Viralance-Signature') ?? '';
const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')));
const t = Number(parts.t);
const expected = crypto.createHmac('sha256', SECRET).update(`${t}.${req.body}`).digest('hex');
const fresh = Math.abs(Date.now() / 1000 - t) < 300; // reject replays older than 5 min
const valid =
fresh &&
typeof parts.v1 === 'string' &&
parts.v1.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
if (!valid) return res.sendStatus(400);
const event = JSON.parse(req.body.toString());
// De-duplicate on event.id: a delivery can be retried.
console.log(event.type, event.data.videoUrl);
res.sendStatus(204);
});OpenAPI
The OpenAPI 3.1 spec at https://viralance-mcp-70260648239.us-central1.run.app/v1/openapi.json is generated from the live routes. Import it into Postman or Insomnia, or use it to generate a typed client.
MCP server for Claude and other AI agents
Viralance also runs a remote MCP (Model Context Protocol) server over streamable HTTP, so Claude Code, Claude Desktop and other MCP clients can generate videos, images and voiceovers from a chat. It uses the same models, moderation, credit wallet and prices as the REST API and the web app. Sign in through the browser (OAuth) or use an API key with the scopes above; per-key daily spend caps apply to both.
claude mcp add --transport http viralance https://mcp.viralance.com/mcpTools (26): generate_video, get_video_status, list_videos, edit_video, analyze_video, compose_film, generate_image, edit_image, list_images, virtual_tryon, product_dimensions, generate_3d, generate_voiceover, enhance_prompt, generate_caption, generate_hooks, get_trends, unlock_trends, autopilot_create, autopilot_execute, autopilot_status, list_products, save_product, get_balance, get_model_costs, get_credit_history. get_model_costs returns prices before anything is spent.
Copy-ready snippets for other clients are on the MCP setup page (sign-in required). Overview and examples: Claude MCP integration and the setup guide.
Frequently asked questions
Is there an API for AI video generation?
Yes. The Viralance REST API generates AI videos, images, voiceovers and 3D models over HTTPS and JSON at https://viralance-mcp-70260648239.us-central1.run.app/v1. Authenticate with a Bearer API key created in your dashboard; the OpenAPI 3.1 spec lists every endpoint.
How much does the Viralance API cost?
There is no separate API plan or markup. Each call spends the same credits as the same action on viralance.com, from one-time credit packs with no subscription. For example, an 8-second 720p VEO 3.1 Fast video costs 12 credits in the app and over the API. Failed jobs are refunded automatically.
Which AI video models can I use over the API?
The same models as the web app, including VEO 3.1, Kling, Seedance, Hailuo, PixVerse and Wan. GET /v1/models returns every model with its durations, resolutions and credit prices.
Does the API support webhooks?
Yes. Add callbackUrl to a video, edit or autopilot request and Viralance sends one signed POST when the job finishes. Verify the Viralance-Signature header (HMAC-SHA256) on every delivery.
Can Claude or other AI agents use Viralance?
Yes. Viralance runs a remote MCP server for Claude Code, Claude Desktop and other MCP clients, with the same models, prices and credit wallet as the API. Add it with: claude mcp add --transport http viralance https://mcp.viralance.com/mcp
What are the API rate limits?
30 requests per minute per key with a burst of 10 in any 10 seconds, a default daily spend cap of 500 credits per key, and up to 5 video jobs in progress at once. Limits return 429 with a Retry-After header.