curl --request POST \
--url https://api.aurous-labs.com/v1/videos/estimate \
--header 'Content-Type: application/json' \
--header 'X-Api-Key: <api-key>' \
--data '
{
"prompt": "A golden sunset over the ocean with gentle waves",
"video_lora_id": "action_01HXMQ7Z3K8Y2VNABCDEFGHJKM",
"character_id": "char_01HXMQ7Z3K8Y2VNABCDEFGHJKM",
"reference_image_urls": [
"file_01HXMQ7Z3K8Y2NABCDEFGHJKMN",
"https://example.com/ref2.jpg"
],
"subjects": [
{
"type": "character",
"character_id": "char_01HXMQ7Z3K8Y2VNABCDEFGHJKM",
"image_urls": [
"file_01HXMQ7Z3K8Y2NABCDEFGHJKMN"
]
}
],
"first_frame_url": "file_01HXMQ7Z3K8Y2NABCDEFGHJKMN",
"last_frame_url": "https://example.com/last.jpg",
"duration": 5,
"generate_audio": true,
"watermark": true,
"enhance_prompt": true,
"reference_video_url": "https://cdn.example.com/clips/dance-loop.mp4",
"reference_audio_url": "https://cdn.example.com/audio/voiceover.mp3",
"video_task": "reference",
"extend_direction": "forward"
}
'import requests
url = "https://api.aurous-labs.com/v1/videos/estimate"
payload = {
"prompt": "A golden sunset over the ocean with gentle waves",
"video_lora_id": "action_01HXMQ7Z3K8Y2VNABCDEFGHJKM",
"character_id": "char_01HXMQ7Z3K8Y2VNABCDEFGHJKM",
"reference_image_urls": ["file_01HXMQ7Z3K8Y2NABCDEFGHJKMN", "https://example.com/ref2.jpg"],
"subjects": [
{
"type": "character",
"character_id": "char_01HXMQ7Z3K8Y2VNABCDEFGHJKM",
"image_urls": ["file_01HXMQ7Z3K8Y2NABCDEFGHJKMN"]
}
],
"first_frame_url": "file_01HXMQ7Z3K8Y2NABCDEFGHJKMN",
"last_frame_url": "https://example.com/last.jpg",
"duration": 5,
"generate_audio": True,
"watermark": True,
"enhance_prompt": True,
"reference_video_url": "https://cdn.example.com/clips/dance-loop.mp4",
"reference_audio_url": "https://cdn.example.com/audio/voiceover.mp3",
"video_task": "reference",
"extend_direction": "forward"
}
headers = {
"X-Api-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-Api-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
prompt: 'A golden sunset over the ocean with gentle waves',
video_lora_id: 'action_01HXMQ7Z3K8Y2VNABCDEFGHJKM',
character_id: 'char_01HXMQ7Z3K8Y2VNABCDEFGHJKM',
reference_image_urls: ['file_01HXMQ7Z3K8Y2NABCDEFGHJKMN', 'https://example.com/ref2.jpg'],
subjects: [
{
type: 'character',
character_id: 'char_01HXMQ7Z3K8Y2VNABCDEFGHJKM',
image_urls: ['file_01HXMQ7Z3K8Y2NABCDEFGHJKMN']
}
],
first_frame_url: 'file_01HXMQ7Z3K8Y2NABCDEFGHJKMN',
last_frame_url: 'https://example.com/last.jpg',
duration: 5,
generate_audio: true,
watermark: true,
enhance_prompt: true,
reference_video_url: 'https://cdn.example.com/clips/dance-loop.mp4',
reference_audio_url: 'https://cdn.example.com/audio/voiceover.mp3',
video_task: 'reference',
extend_direction: 'forward'
})
};
fetch('https://api.aurous-labs.com/v1/videos/estimate', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.aurous-labs.com/v1/videos/estimate",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'prompt' => 'A golden sunset over the ocean with gentle waves',
'video_lora_id' => 'action_01HXMQ7Z3K8Y2VNABCDEFGHJKM',
'character_id' => 'char_01HXMQ7Z3K8Y2VNABCDEFGHJKM',
'reference_image_urls' => [
'file_01HXMQ7Z3K8Y2NABCDEFGHJKMN',
'https://example.com/ref2.jpg'
],
'subjects' => [
[
'type' => 'character',
'character_id' => 'char_01HXMQ7Z3K8Y2VNABCDEFGHJKM',
'image_urls' => [
'file_01HXMQ7Z3K8Y2NABCDEFGHJKMN'
]
]
],
'first_frame_url' => 'file_01HXMQ7Z3K8Y2NABCDEFGHJKMN',
'last_frame_url' => 'https://example.com/last.jpg',
'duration' => 5,
'generate_audio' => true,
'watermark' => true,
'enhance_prompt' => true,
'reference_video_url' => 'https://cdn.example.com/clips/dance-loop.mp4',
'reference_audio_url' => 'https://cdn.example.com/audio/voiceover.mp3',
'video_task' => 'reference',
'extend_direction' => 'forward'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-Api-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.aurous-labs.com/v1/videos/estimate"
payload := strings.NewReader("{\n \"prompt\": \"A golden sunset over the ocean with gentle waves\",\n \"video_lora_id\": \"action_01HXMQ7Z3K8Y2VNABCDEFGHJKM\",\n \"character_id\": \"char_01HXMQ7Z3K8Y2VNABCDEFGHJKM\",\n \"reference_image_urls\": [\n \"file_01HXMQ7Z3K8Y2NABCDEFGHJKMN\",\n \"https://example.com/ref2.jpg\"\n ],\n \"subjects\": [\n {\n \"type\": \"character\",\n \"character_id\": \"char_01HXMQ7Z3K8Y2VNABCDEFGHJKM\",\n \"image_urls\": [\n \"file_01HXMQ7Z3K8Y2NABCDEFGHJKMN\"\n ]\n }\n ],\n \"first_frame_url\": \"file_01HXMQ7Z3K8Y2NABCDEFGHJKMN\",\n \"last_frame_url\": \"https://example.com/last.jpg\",\n \"duration\": 5,\n \"generate_audio\": true,\n \"watermark\": true,\n \"enhance_prompt\": true,\n \"reference_video_url\": \"https://cdn.example.com/clips/dance-loop.mp4\",\n \"reference_audio_url\": \"https://cdn.example.com/audio/voiceover.mp3\",\n \"video_task\": \"reference\",\n \"extend_direction\": \"forward\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Api-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.aurous-labs.com/v1/videos/estimate")
.header("X-Api-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"prompt\": \"A golden sunset over the ocean with gentle waves\",\n \"video_lora_id\": \"action_01HXMQ7Z3K8Y2VNABCDEFGHJKM\",\n \"character_id\": \"char_01HXMQ7Z3K8Y2VNABCDEFGHJKM\",\n \"reference_image_urls\": [\n \"file_01HXMQ7Z3K8Y2NABCDEFGHJKMN\",\n \"https://example.com/ref2.jpg\"\n ],\n \"subjects\": [\n {\n \"type\": \"character\",\n \"character_id\": \"char_01HXMQ7Z3K8Y2VNABCDEFGHJKM\",\n \"image_urls\": [\n \"file_01HXMQ7Z3K8Y2NABCDEFGHJKMN\"\n ]\n }\n ],\n \"first_frame_url\": \"file_01HXMQ7Z3K8Y2NABCDEFGHJKMN\",\n \"last_frame_url\": \"https://example.com/last.jpg\",\n \"duration\": 5,\n \"generate_audio\": true,\n \"watermark\": true,\n \"enhance_prompt\": true,\n \"reference_video_url\": \"https://cdn.example.com/clips/dance-loop.mp4\",\n \"reference_audio_url\": \"https://cdn.example.com/audio/voiceover.mp3\",\n \"video_task\": \"reference\",\n \"extend_direction\": \"forward\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.aurous-labs.com/v1/videos/estimate")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Api-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"prompt\": \"A golden sunset over the ocean with gentle waves\",\n \"video_lora_id\": \"action_01HXMQ7Z3K8Y2VNABCDEFGHJKM\",\n \"character_id\": \"char_01HXMQ7Z3K8Y2VNABCDEFGHJKM\",\n \"reference_image_urls\": [\n \"file_01HXMQ7Z3K8Y2NABCDEFGHJKMN\",\n \"https://example.com/ref2.jpg\"\n ],\n \"subjects\": [\n {\n \"type\": \"character\",\n \"character_id\": \"char_01HXMQ7Z3K8Y2VNABCDEFGHJKM\",\n \"image_urls\": [\n \"file_01HXMQ7Z3K8Y2NABCDEFGHJKMN\"\n ]\n }\n ],\n \"first_frame_url\": \"file_01HXMQ7Z3K8Y2NABCDEFGHJKMN\",\n \"last_frame_url\": \"https://example.com/last.jpg\",\n \"duration\": 5,\n \"generate_audio\": true,\n \"watermark\": true,\n \"enhance_prompt\": true,\n \"reference_video_url\": \"https://cdn.example.com/clips/dance-loop.mp4\",\n \"reference_audio_url\": \"https://cdn.example.com/audio/voiceover.mp3\",\n \"video_task\": \"reference\",\n \"extend_direction\": \"forward\"\n}"
response = http.request(request)
puts response.read_body{
"object": "estimate",
"estimated_cost": {
"amount": 2,
"breakdown": {
"base": 6.5,
"size_tier": "standard"
},
"adaptive": false,
"amount_min": 10,
"amount_max": 37.5
},
"currency": "credit",
"warnings": [
{
"code": "parameter_ignored",
"param": "seed",
"message": "`seed` has no effect on this generation and was ignored."
}
]
}{
"error": {
"type": "invalid_request",
"code": "balance_too_low",
"message": "Team available balance is 1.5 credits, generation requires 2.0.",
"doc_url": "https://docs.aurous-labs.com/errors#balance_too_low",
"request_id": "req_01HXMQ7Z3K8Y2VNABCDEFGHJKM",
"param": "prompt",
"reason": "wrong_view",
"detected_view": "full_left"
}
}{
"error": {
"type": "invalid_request",
"code": "balance_too_low",
"message": "Team available balance is 1.5 credits, generation requires 2.0.",
"doc_url": "https://docs.aurous-labs.com/errors#balance_too_low",
"request_id": "req_01HXMQ7Z3K8Y2VNABCDEFGHJKM",
"param": "prompt",
"reason": "wrong_view",
"detected_view": "full_left"
}
}{
"error": {
"type": "invalid_request",
"code": "balance_too_low",
"message": "Team available balance is 1.5 credits, generation requires 2.0.",
"doc_url": "https://docs.aurous-labs.com/errors#balance_too_low",
"request_id": "req_01HXMQ7Z3K8Y2VNABCDEFGHJKM",
"param": "prompt",
"reason": "wrong_view",
"detected_view": "full_left"
}
}{
"error": {
"type": "invalid_request",
"code": "balance_too_low",
"message": "Team available balance is 1.5 credits, generation requires 2.0.",
"doc_url": "https://docs.aurous-labs.com/errors#balance_too_low",
"request_id": "req_01HXMQ7Z3K8Y2VNABCDEFGHJKM",
"param": "prompt",
"reason": "wrong_view",
"detected_view": "full_left"
}
}{
"error": {
"type": "invalid_request",
"code": "balance_too_low",
"message": "Team available balance is 1.5 credits, generation requires 2.0.",
"doc_url": "https://docs.aurous-labs.com/errors#balance_too_low",
"request_id": "req_01HXMQ7Z3K8Y2VNABCDEFGHJKM",
"param": "prompt",
"reason": "wrong_view",
"detected_view": "full_left"
}
}{
"error": {
"type": "invalid_request",
"code": "balance_too_low",
"message": "Team available balance is 1.5 credits, generation requires 2.0.",
"doc_url": "https://docs.aurous-labs.com/errors#balance_too_low",
"request_id": "req_01HXMQ7Z3K8Y2VNABCDEFGHJKM",
"param": "prompt",
"reason": "wrong_view",
"detected_view": "full_left"
}
}Estimate the credit cost of a video generation
For a fixed duration, estimated_cost.amount is the exact charge. For adaptive (duration: -1, the default), estimated_cost.adaptive is true and the price is a range: amount_min–amount_max, where amount equals amount_max (the credits held up front). You are charged for the delivered length and refunded the difference. Same validation as POST /v1/videos, but without side effects — no character synthesis, no reference materialization. A cast (subjects[]) is validated identically to POST /v1/videos — cast characters are existence/readiness-checked — and does not change the price.
reference_video_url/reference_audio_url (a file_<ulid> from POST /v1/files or an HTTPS URL) are validated for shape and parameter-combination compatibility, identically to POST /v1/videos. A file_<ulid> additionally gets the same read-only checks the create call performs — it must exist, belong to your team (404 otherwise), and have been uploaded with the matching purpose (400 reference_media_invalid otherwise). The media bytes are never fetched at estimate time — the estimate never touches the network — so byte-level validation (format, duration, resolution) and HTTPS-URL fetching only happen on the actual create call. A reference-to-video request is never charged for enhance_prompt, even when enhance_prompt: true — the system composes the prompt around the reference and never invokes the enhancer, so the flat enhance adder never applies.
Because the reference clip is never fetched, its real duration is unknown at estimate time, so a reference (video_task: reference) or extend request is priced at the 15-second input ceiling — an upper bound. The actual charge is typically lower: the create hold prices against the real clip length. As with the image estimate, this is a deliberate, conservative divergence on that path — a BYO-reference request is never charged more than this estimate.
Auto-matching is not run here, and the quote can miss in EITHER direction. This endpoint prices exactly the request body you sent. Every structural validation rule is identical to POST /v1/videos, but model MATCHING is a create-time decision: if you omit video_lora_id and a video model then matches at create (from your prompt, or — when a first_frame_url is attached — from the image), the generation dispatches as a video-input generation and is priced accordingly. Which way the charge moves depends on what YOU pinned, because a matched model supplies default_duration, default_resolution AND default_ratio for whatever you left out, and all three are priced:
- You omitted
duration/resolution(the usual shape for a barefirst_frame_urlrequest): with no model, this endpoint has to price adaptive duration (the 15-second ceiling) at 1080p, and the matched model then brings a shorter, smaller default. The quote is an upper bound that can substantially OVER-state — measured on the first-frame path:amount827.26 against an actual settled charge of 279.91. On these (adaptive) requests,amount_min/amount_maxis the honest range to plan against;amountis only the ceiling that gets held. - You sent
durationandresolutionexplicitly: your values win over the model defaults, so a match can only ADD the motion-reference input leg to the price. On that shape the charge genuinely exceeds this quote.
Pin video_lora_id whenever you need the quote to be exact — that is the only value that removes matching from the create path entirely. video_lora_id: null opts out of IMAGE-based matching only, so on a request without a first_frame_url it does NOT make this quote exact; and on a request WITH one it also declines the model defaults, so an otherwise-bare request prices (and charges) the adaptive-15s/1080p fallback. This is inherent to auto-matching and is not specific to first frames.
Video and image rates are both DB-driven. Video is priced from the live per-model rate table — see GET /v1/models for the current per-model credit rates — NOT frozen in the Aurous-Version rate card. Image pricing works the same way: the pixel-tiered rate card behind POST /v1/images/estimate is also read live from the registry and MAY change without an Aurous-Version bump — the same pricing asymmetry the LLM chat/embeddings surfaces use (spec §6.4). Pin an Aurous-Version for stable request/response shapes; call the matching estimate endpoint for an authoritative current-price quote immediately before you generate.
curl --request POST \
--url https://api.aurous-labs.com/v1/videos/estimate \
--header 'Content-Type: application/json' \
--header 'X-Api-Key: <api-key>' \
--data '
{
"prompt": "A golden sunset over the ocean with gentle waves",
"video_lora_id": "action_01HXMQ7Z3K8Y2VNABCDEFGHJKM",
"character_id": "char_01HXMQ7Z3K8Y2VNABCDEFGHJKM",
"reference_image_urls": [
"file_01HXMQ7Z3K8Y2NABCDEFGHJKMN",
"https://example.com/ref2.jpg"
],
"subjects": [
{
"type": "character",
"character_id": "char_01HXMQ7Z3K8Y2VNABCDEFGHJKM",
"image_urls": [
"file_01HXMQ7Z3K8Y2NABCDEFGHJKMN"
]
}
],
"first_frame_url": "file_01HXMQ7Z3K8Y2NABCDEFGHJKMN",
"last_frame_url": "https://example.com/last.jpg",
"duration": 5,
"generate_audio": true,
"watermark": true,
"enhance_prompt": true,
"reference_video_url": "https://cdn.example.com/clips/dance-loop.mp4",
"reference_audio_url": "https://cdn.example.com/audio/voiceover.mp3",
"video_task": "reference",
"extend_direction": "forward"
}
'import requests
url = "https://api.aurous-labs.com/v1/videos/estimate"
payload = {
"prompt": "A golden sunset over the ocean with gentle waves",
"video_lora_id": "action_01HXMQ7Z3K8Y2VNABCDEFGHJKM",
"character_id": "char_01HXMQ7Z3K8Y2VNABCDEFGHJKM",
"reference_image_urls": ["file_01HXMQ7Z3K8Y2NABCDEFGHJKMN", "https://example.com/ref2.jpg"],
"subjects": [
{
"type": "character",
"character_id": "char_01HXMQ7Z3K8Y2VNABCDEFGHJKM",
"image_urls": ["file_01HXMQ7Z3K8Y2NABCDEFGHJKMN"]
}
],
"first_frame_url": "file_01HXMQ7Z3K8Y2NABCDEFGHJKMN",
"last_frame_url": "https://example.com/last.jpg",
"duration": 5,
"generate_audio": True,
"watermark": True,
"enhance_prompt": True,
"reference_video_url": "https://cdn.example.com/clips/dance-loop.mp4",
"reference_audio_url": "https://cdn.example.com/audio/voiceover.mp3",
"video_task": "reference",
"extend_direction": "forward"
}
headers = {
"X-Api-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-Api-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
prompt: 'A golden sunset over the ocean with gentle waves',
video_lora_id: 'action_01HXMQ7Z3K8Y2VNABCDEFGHJKM',
character_id: 'char_01HXMQ7Z3K8Y2VNABCDEFGHJKM',
reference_image_urls: ['file_01HXMQ7Z3K8Y2NABCDEFGHJKMN', 'https://example.com/ref2.jpg'],
subjects: [
{
type: 'character',
character_id: 'char_01HXMQ7Z3K8Y2VNABCDEFGHJKM',
image_urls: ['file_01HXMQ7Z3K8Y2NABCDEFGHJKMN']
}
],
first_frame_url: 'file_01HXMQ7Z3K8Y2NABCDEFGHJKMN',
last_frame_url: 'https://example.com/last.jpg',
duration: 5,
generate_audio: true,
watermark: true,
enhance_prompt: true,
reference_video_url: 'https://cdn.example.com/clips/dance-loop.mp4',
reference_audio_url: 'https://cdn.example.com/audio/voiceover.mp3',
video_task: 'reference',
extend_direction: 'forward'
})
};
fetch('https://api.aurous-labs.com/v1/videos/estimate', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.aurous-labs.com/v1/videos/estimate",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'prompt' => 'A golden sunset over the ocean with gentle waves',
'video_lora_id' => 'action_01HXMQ7Z3K8Y2VNABCDEFGHJKM',
'character_id' => 'char_01HXMQ7Z3K8Y2VNABCDEFGHJKM',
'reference_image_urls' => [
'file_01HXMQ7Z3K8Y2NABCDEFGHJKMN',
'https://example.com/ref2.jpg'
],
'subjects' => [
[
'type' => 'character',
'character_id' => 'char_01HXMQ7Z3K8Y2VNABCDEFGHJKM',
'image_urls' => [
'file_01HXMQ7Z3K8Y2NABCDEFGHJKMN'
]
]
],
'first_frame_url' => 'file_01HXMQ7Z3K8Y2NABCDEFGHJKMN',
'last_frame_url' => 'https://example.com/last.jpg',
'duration' => 5,
'generate_audio' => true,
'watermark' => true,
'enhance_prompt' => true,
'reference_video_url' => 'https://cdn.example.com/clips/dance-loop.mp4',
'reference_audio_url' => 'https://cdn.example.com/audio/voiceover.mp3',
'video_task' => 'reference',
'extend_direction' => 'forward'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-Api-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.aurous-labs.com/v1/videos/estimate"
payload := strings.NewReader("{\n \"prompt\": \"A golden sunset over the ocean with gentle waves\",\n \"video_lora_id\": \"action_01HXMQ7Z3K8Y2VNABCDEFGHJKM\",\n \"character_id\": \"char_01HXMQ7Z3K8Y2VNABCDEFGHJKM\",\n \"reference_image_urls\": [\n \"file_01HXMQ7Z3K8Y2NABCDEFGHJKMN\",\n \"https://example.com/ref2.jpg\"\n ],\n \"subjects\": [\n {\n \"type\": \"character\",\n \"character_id\": \"char_01HXMQ7Z3K8Y2VNABCDEFGHJKM\",\n \"image_urls\": [\n \"file_01HXMQ7Z3K8Y2NABCDEFGHJKMN\"\n ]\n }\n ],\n \"first_frame_url\": \"file_01HXMQ7Z3K8Y2NABCDEFGHJKMN\",\n \"last_frame_url\": \"https://example.com/last.jpg\",\n \"duration\": 5,\n \"generate_audio\": true,\n \"watermark\": true,\n \"enhance_prompt\": true,\n \"reference_video_url\": \"https://cdn.example.com/clips/dance-loop.mp4\",\n \"reference_audio_url\": \"https://cdn.example.com/audio/voiceover.mp3\",\n \"video_task\": \"reference\",\n \"extend_direction\": \"forward\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Api-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.aurous-labs.com/v1/videos/estimate")
.header("X-Api-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"prompt\": \"A golden sunset over the ocean with gentle waves\",\n \"video_lora_id\": \"action_01HXMQ7Z3K8Y2VNABCDEFGHJKM\",\n \"character_id\": \"char_01HXMQ7Z3K8Y2VNABCDEFGHJKM\",\n \"reference_image_urls\": [\n \"file_01HXMQ7Z3K8Y2NABCDEFGHJKMN\",\n \"https://example.com/ref2.jpg\"\n ],\n \"subjects\": [\n {\n \"type\": \"character\",\n \"character_id\": \"char_01HXMQ7Z3K8Y2VNABCDEFGHJKM\",\n \"image_urls\": [\n \"file_01HXMQ7Z3K8Y2NABCDEFGHJKMN\"\n ]\n }\n ],\n \"first_frame_url\": \"file_01HXMQ7Z3K8Y2NABCDEFGHJKMN\",\n \"last_frame_url\": \"https://example.com/last.jpg\",\n \"duration\": 5,\n \"generate_audio\": true,\n \"watermark\": true,\n \"enhance_prompt\": true,\n \"reference_video_url\": \"https://cdn.example.com/clips/dance-loop.mp4\",\n \"reference_audio_url\": \"https://cdn.example.com/audio/voiceover.mp3\",\n \"video_task\": \"reference\",\n \"extend_direction\": \"forward\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.aurous-labs.com/v1/videos/estimate")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Api-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"prompt\": \"A golden sunset over the ocean with gentle waves\",\n \"video_lora_id\": \"action_01HXMQ7Z3K8Y2VNABCDEFGHJKM\",\n \"character_id\": \"char_01HXMQ7Z3K8Y2VNABCDEFGHJKM\",\n \"reference_image_urls\": [\n \"file_01HXMQ7Z3K8Y2NABCDEFGHJKMN\",\n \"https://example.com/ref2.jpg\"\n ],\n \"subjects\": [\n {\n \"type\": \"character\",\n \"character_id\": \"char_01HXMQ7Z3K8Y2VNABCDEFGHJKM\",\n \"image_urls\": [\n \"file_01HXMQ7Z3K8Y2NABCDEFGHJKMN\"\n ]\n }\n ],\n \"first_frame_url\": \"file_01HXMQ7Z3K8Y2NABCDEFGHJKMN\",\n \"last_frame_url\": \"https://example.com/last.jpg\",\n \"duration\": 5,\n \"generate_audio\": true,\n \"watermark\": true,\n \"enhance_prompt\": true,\n \"reference_video_url\": \"https://cdn.example.com/clips/dance-loop.mp4\",\n \"reference_audio_url\": \"https://cdn.example.com/audio/voiceover.mp3\",\n \"video_task\": \"reference\",\n \"extend_direction\": \"forward\"\n}"
response = http.request(request)
puts response.read_body{
"object": "estimate",
"estimated_cost": {
"amount": 2,
"breakdown": {
"base": 6.5,
"size_tier": "standard"
},
"adaptive": false,
"amount_min": 10,
"amount_max": 37.5
},
"currency": "credit",
"warnings": [
{
"code": "parameter_ignored",
"param": "seed",
"message": "`seed` has no effect on this generation and was ignored."
}
]
}{
"error": {
"type": "invalid_request",
"code": "balance_too_low",
"message": "Team available balance is 1.5 credits, generation requires 2.0.",
"doc_url": "https://docs.aurous-labs.com/errors#balance_too_low",
"request_id": "req_01HXMQ7Z3K8Y2VNABCDEFGHJKM",
"param": "prompt",
"reason": "wrong_view",
"detected_view": "full_left"
}
}{
"error": {
"type": "invalid_request",
"code": "balance_too_low",
"message": "Team available balance is 1.5 credits, generation requires 2.0.",
"doc_url": "https://docs.aurous-labs.com/errors#balance_too_low",
"request_id": "req_01HXMQ7Z3K8Y2VNABCDEFGHJKM",
"param": "prompt",
"reason": "wrong_view",
"detected_view": "full_left"
}
}{
"error": {
"type": "invalid_request",
"code": "balance_too_low",
"message": "Team available balance is 1.5 credits, generation requires 2.0.",
"doc_url": "https://docs.aurous-labs.com/errors#balance_too_low",
"request_id": "req_01HXMQ7Z3K8Y2VNABCDEFGHJKM",
"param": "prompt",
"reason": "wrong_view",
"detected_view": "full_left"
}
}{
"error": {
"type": "invalid_request",
"code": "balance_too_low",
"message": "Team available balance is 1.5 credits, generation requires 2.0.",
"doc_url": "https://docs.aurous-labs.com/errors#balance_too_low",
"request_id": "req_01HXMQ7Z3K8Y2VNABCDEFGHJKM",
"param": "prompt",
"reason": "wrong_view",
"detected_view": "full_left"
}
}{
"error": {
"type": "invalid_request",
"code": "balance_too_low",
"message": "Team available balance is 1.5 credits, generation requires 2.0.",
"doc_url": "https://docs.aurous-labs.com/errors#balance_too_low",
"request_id": "req_01HXMQ7Z3K8Y2VNABCDEFGHJKM",
"param": "prompt",
"reason": "wrong_view",
"detected_view": "full_left"
}
}{
"error": {
"type": "invalid_request",
"code": "balance_too_low",
"message": "Team available balance is 1.5 credits, generation requires 2.0.",
"doc_url": "https://docs.aurous-labs.com/errors#balance_too_low",
"request_id": "req_01HXMQ7Z3K8Y2VNABCDEFGHJKM",
"param": "prompt",
"reason": "wrong_view",
"detected_view": "full_left"
}
}Authorizations
Your team API key (starts with al_live_).
Headers
Optional API version pin (YYYY-MM-DD). Omit the header to receive the platform default, currently 2026-08-26.
^\d{4}-\d{2}-\d{2}$"2026-08-26"
Body
Text prompt describing the video. Optional when the request carries another content source: a first_frame_url (image-to-video), a reference_video_url (reference-to-video), or a pinned video_lora_id (the video model supplies the motion and, when nothing else is sent, generates its own subject). Subject-driven generation (subjects[], character_id, or reference_image_urls) still requires a prompt describing the action unless a video model is pinned or a reference video is attached. A request with none of the four sources returns 400 missing_field.
"A golden sunset over the ocean with gentle waves"
Optional, and TRI-STATE. An id (or slug, where one is set) from GET /v1/video_loras pins a specific video model. A pinned model is also a complete request on its own: send just video_lora_id — no prompt — and the model generates its own subject and motion; add subjects[] (or the legacy character_id/reference_image_urls) to cast specific people, still with no prompt required. Only a pinned id substitutes for a prompt — null never does, and an empty string is treated as omitted. A pin cannot combine with reference_video_url (400 parameter_invalid_combination): both supply the motion. If OMITTED, the platform picks a suitable model for you: matching reads your prompt, or — when first_frame_url is attached — what the IMAGE shows. If none matches, your request is generated as plain video, plain image-to-video, or (with a subject attached) a subject-driven video; matching never fails the request. Send NULL to opt out of IMAGE-based matching — meaningful only when first_frame_url is attached, where it guarantees plain image-to-video. WITHOUT a first frame, null behaves exactly like omitting the field and your prompt is still auto-matched; pin an id if you need a specific model. A first frame plus a pinned or matched model reports inference_type: "r2v" and starts NEAR your image rather than exactly on it. PRICING: a pinned or matched model also supplies default_resolution and default_ratio alongside default_duration for whatever you left out (anything you send explicitly wins), and all three are priced — so null on an otherwise-bare first-frame request falls back to adaptive duration at 1080p and costs ~2.8x the same still with a model pinned. Send duration and resolution alongside null if you want the exact-frame guarantee at a predictable price.
"action_01HXMQ7Z3K8Y2VNABCDEFGHJKM"
Drive the video from a saved character (reference-to-video). Must be status: ready — otherwise 400 character_not_ready. Cross-team ids 404 (existence never leaked). Mutually exclusive with reference_image_urls (→ 400 mutually_exclusive_input) and with first_frame_url/last_frame_url (→ 400 parameter_invalid_combination). Omit both a subject and a frame for plain text-to-video. Superseded by subjects[] (which also supports multi-person casts); fully supported — successful responses carry an advisory Deprecation: true header when this field is used.
"char_01HXMQ7Z3K8Y2VNABCDEFGHJKM"
Up to 6 subject reference images — each a file_<ulid> (POST /v1/files) or an https:// URL (SSRF-pinned server-side fetch). Image files only: a file_<ulid> uploaded with purpose reference_video/reference_audio is rejected (400 invalid_format). The subject is anchored across the video. Mutually exclusive with character_id and with first_frame_url/last_frame_url. Superseded by subjects[] (which also supports multi-person casts); fully supported — successful responses carry an advisory Deprecation: true header when this field is used.
6[
"file_01HXMQ7Z3K8Y2NABCDEFGHJKMN",
"https://example.com/ref2.jpg"
]
Ordered cast for a multi-person video. Up to 2 subjects per generation (current engine limit — may increase; exceeding it returns 400 parameter_invalid_combination). Each subject is a saved character or its own group of 1–4 reference images; character and reference subjects can be mixed. Supersedes the single-subject character_id/reference_image_urls fields — sending both shapes returns 400 mutually_exclusive_input. A cast may accompany reference_video_url (the clip supplies motion, the cast supplies identity) but not video_task: "extend" and not first_frame_url/last_frame_url. Duplicate characters or a reference image reused across subjects return 400. Empty array is treated as omitted.
2Show child attributes
Show child attributes
First frame for image-to-video / first+last frame interpolation. Either an opaque file_<ulid> ID returned by POST /v1/files, or an https:// URL pointing at a public host (max 2048 chars). Image files only — a file_<ulid> uploaded with purpose reference_video/reference_audio is rejected (400 invalid_format). URLs are server-side fetched through an SSRF-pinned client (rejects private IPs / cloud metadata). MINIMUM SIZE — when a video model is pinned or left to auto-match, this frame is upscaled into a short seed clip, so it must be at least 64 px on its shortest side AND at least 6,400 px in total (80x80 is the smallest square accepted; at a 64 px short side the long side needs 100). A file_<ulid> below that returns 400 first_frame_too_small before any credit hold (dimensions were measured at upload); an https:// URL is accepted and settles at status: failed with error_code: "first_frame_too_small" and a full refund, because validation never fetches the bytes. The check runs on the POSSIBILITY of a model, not on one actually being used — an un-pinned frame is rejected even if no model would have matched your image. No minimum applies with video_lora_id: null, nor when a last_frame_url rides alongside — a first+last pair never auto-matches and builds no seed clip either, so no first_frame_too_small ever fires on an interpolation request.
2048"file_01HXMQ7Z3K8Y2NABCDEFGHJKMN"
Last frame for first+last frame interpolation. Same rules as first_frame_url. Requires first_frame_url — sending last_frame_url alone returns 400 with code parameter_invalid_combination.
2048"https://example.com/last.jpg"
Output video resolution
480p, 720p, 1080p Output video aspect ratio
16:9, 4:3, 1:1, 3:4, 9:16, 21:9, adaptive Video length in seconds. Pass -1 for ADAPTIVE (default): the model selects the optimal whole-second length within its supported range (currently 4–15 s) and you are billed for the delivered length — a VARIABLE price. Call POST /v1/videos/estimate to see the min–max range before submitting. Pass a whole number 4–15 to pin a fixed length (fixed price). Omitting uses the video model's default length when your request pins or is matched to one; otherwise adaptive (-1). Adaptive holds the 15 s ceiling from your balance until it settles.
-1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 5
Whether the generated video includes synchronized audio. Defaults to the selected video model's audio setting (currently true for all models unless noted on the model).
Whether to add watermark
Whether to enhance the prompt with AI. A no-op on requests without a prompt (model-driven and reference-driven bodies): nothing to enhance, nothing charged.
Your reference video — the motion source for a reference-mode generation, or the clip to continue when video_task is extend. Either an opaque file_<ulid> returned by POST /v1/files (uploaded with purpose: reference_video — format/duration/resolution were already validated at upload), or an HTTPS URL. Requirements: MP4 or MOV (H.264/H.265), 2–15 seconds, up to 50 MB, frame area between 409,600 px (≈640×640) and 2,073,600 px (1920×1080, ≈1080p). URLs must be publicly fetchable or pre-signed, serve HTTPS directly (redirects are refused — pass the final URL), and respond within the fetch budget. Cannot be combined with first_frame_url/last_frame_url. While the reference is prepared the generation stays in processing — see the endpoint description for timing.
2048"https://cdn.example.com/clips/dance-loop.mp4"
An audio reference (voice, music, or ambience) to guide the generated soundtrack — either a file_<ulid> from POST /v1/files (purpose: reference_audio) or an HTTPS URL. WAV or MP3, 2–15 seconds, up to 15 MB. Needs a companion — a reference video, a subject (subjects[] or the legacy fields), or a pinned video_lora_id — and requires audio output (generate_audio must not be false). Same URL rules as reference_video_url (public or signed HTTPS, no redirects).
2048"https://cdn.example.com/audio/voiceover.mp3"
What to do with reference_video_url. reference (default): generate a new scene that borrows the clip's motion. extend: continue the clip itself in extend_direction; extend takes the clip as-is, so it cannot be combined with video_lora_id. Only valid when reference_video_url is present.
reference, extend Direction to continue the clip when video_task is extend. Defaults to forward. Only valid with video_task: "extend".
forward, backward Response
Cost estimate
Discriminator
estimate "estimate"
Cost breakdown for this would-be generation.
Show child attributes
Show child attributes
Currency unit. All amounts in this response are in credit.
credit "credit"
Non-fatal request adjustments the real create would also report (e.g. a retired style pin that generates without a style, or a parameter with no effect on this generation path). Same shape and codes as the warnings on the POST /v1/images 201 body — the estimate warns exactly when the create would. Omitted when empty. Codes are an OPEN set: ignore unknown codes.
Show child attributes
Show child attributes
[
{
"code": "parameter_ignored",
"param": "seed",
"message": "`seed` has no effect on this generation and was ignored."
}
]

