Video Generation API
Create Veo 3.1 text-to-video and image-to-video tasks with your API key, then poll the same /api/status endpoint you use for images.
Authentication
Send your API key as a Bearer token on every request. Use the same key to create a task and to check its status. You can create keys on the API keys page of your dashboard.
Authorization: Bearer YOUR_API_KEYModels and credits
Set the model field to one of the values below. Any other value is rejected with HTTP 400 and nothing is charged.
| model value | Model | Text to video (credits) | Image to video (credits) |
|---|---|---|---|
veo3_fast | Veo 3.1 Fast (default) | 25 | 35 |
veo3 | Veo 3.1 Quality | 180 | 180 |
veo3-fast is accepted as an alias of veo3_fast. If you omit model, veo3_fast is used. Image-to-video pricing applies when image_urls contains at least one URL.
Create a video task
Validates the request, charges credits and returns a task_id. The video is generated asynchronously: poll /api/status or set callback_url to receive the result.
Text description of the video to generate.
veo3_fast (alias veo3-fast) or veo3. Any other value returns HTTP 400. Defaults to veo3_fast.
Public image URLs for image-to-video. With 1 image, the video is built around that image. With 2 images, they become the first and the last frame. imageUrls (camelCase) is accepted as an alias. If both are sent, image_urls is used.
16:9, 9:16 or Auto. Auto crops the video to match the uploaded image. Defaults to 16:9.
When true, the prompt is translated into English before generation. Defaults to true.
Watermark text to add to the video.
Public URL that receives a POST request with the final result when the task finishes.
Fields that are not supported
duration, resolution and image_url (singular) are not part of this API and are ignored. The model decides the video length. Send images as an image_urls array.
curl -X POST "https://nanobnana.com/api/video/generate" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "The camera slowly pushes in as the city lights turn on at dusk",
"model": "veo3_fast",
"image_urls": ["https://example.com/first-frame.jpg"],
"aspect_ratio": "16:9"
}'{
"code": 200,
"message": "success",
"data": {
"task_id": "veo24223f74e4f445ec9c4403b532cc328fbksv"
}
}Check task status
Video task IDs start with veo and end with bksv. /api/status detects them automatically and returns the video URL when the task is completed.
The task_id returned by POST /api/video/generate.
Set to veo3 to force video routing for a task_id that does not follow the veo…bksv format.
curl "https://nanobnana.com/api/status?task_id=veo24223f74e4f445ec9c4403b532cc328fbksv" \
-H "Authorization: Bearer YOUR_API_KEY"{
"code": 200,
"message": "success",
"data": {
"task_id": "veo24223f74e4f445ec9c4403b532cc328fbksv",
"request": {
"prompt": "The camera slowly pushes in as the city lights turn on at dusk",
"model": "veo3_fast",
"image_urls": [
"https://example.com/first-frame.jpg"
],
"aspect_ratio": "16:9"
},
"response": null,
"status": "IN_PROGRESS",
"status_code": 3,
"status_text": "IN_PROGRESS",
"consumed_credits": 35,
"created_at": "2026-10-04 17:05:12",
"model": "veo3"
},
"model": "veo3"
}Status values
IN_PROGRESS·status_code: 3— the video is still being generated. Keep polling.COMPLETED·status_code: 1— the video is ready. response contains the video URL.FAILED·status_code: 2— generation failed. error_message explains why, and the credits are refunded automatically.
Billing and refunds
- Credits are charged when the task is created, before generation starts.
- If the create request does not return HTTP 200, no task exists and the charged credits are refunded immediately. The response states how many credits were refunded.
- If a created task later ends as FAILED, its credits are refunded automatically and consumed_credits in the status response becomes 0.
Polling example
Video generation usually takes a few minutes. Poll every 10 seconds while status_code is 3, and stop when it is 1 or 2.
async function waitForVideo(taskId) {
while (true) {
const res = await fetch(`https://nanobnana.com/api/status?task_id=${taskId}`, {
headers: { Authorization: 'Bearer YOUR_API_KEY' }
});
const payload = await res.json();
if (!res.ok) throw new Error(payload.message);
const task = payload.data;
if (task.status_code === 1) return task.response[0];
if (task.status_code === 2) throw new Error(task.error_message || 'Video generation failed');
await new Promise((resolve) => setTimeout(resolve, 10000));
}
}Callback
If you set callback_url, we send a POST request with this JSON body when the task completes or fails. The URL must be reachable from the public internet.
{
"code": 200,
"message": "success",
"data": {
"request": {
"prompt": "The camera slowly pushes in as the city lights turn on at dusk",
"model": "veo3_fast",
"image_urls": [
"https://example.com/first-frame.jpg"
],
"aspect_ratio": "16:9"
},
"response": [
"https://example.com/generated-video.mp4"
],
"status": "COMPLETED",
"created_at": "2026-10-04 17:05:12"
}
}Common errors
{
"code": 400,
"message": "prompt is required",
"data": null
}