📡 Webhook API — Integration Guide

Base URL: http://127.0.0.1:8765 (localhost only) · Auth: API Key via X-API-Key header · License: MAX

ℹ️Full per-endpoint parameters are in the Webhook API section (User Guide). The API is asynchronous: submit → poll /api/status → download files. Up to 10 tasks run concurrently; tasks live in memory (lost on app restart).
📄Detailed reference to hand to an AI for fast integration: WEBHOOK_INTEGRATION.en.md · WEBHOOK_INTEGRATION.vi.md

🔑 Authentication

All endpoints (except /api/health and /api/files/*) require an API key header:

text
X-API-Key: YOUR_API_KEY

The API key (32-byte URL-safe token) is auto-generated in Settings → Webhook. You can regenerate it anytime.

json
{
  "error": "Invalid or missing API key"
}

📡 Endpoints

MethodEndpointAuthDescription
GET/api/healthServer health
POST/api/image/generateGenerate image (Flow — Nano Banana)
POST/api/video/generateGenerate video (Veo)
POST/api/grok/generateGenerate Grok image/video (T2I/I2I/T2V/I2V) NEW
POST/api/meta/generateGenerate Meta AI image/video (T2I/I2I/T2V/I2V) NEW
GET/api/status/{task_id}Check status
GET/api/result/{task_id}Get result
GET/api/tasksList 50 most recent tasks
GET/api/files/{filename}Download binary file

1. Image — POST /api/image/generate

FieldTypeDefaultDescription
promptstring— (required)Image description
modelstringnano_banana_2nano_banana_2, nano_banana_pro or nano_banana_2_lite (unknown → nano_banana_2)
aspect_ratiostring1:11:1, 3:4, 4:3, 9:16, 16:9
reference_imagesarray[]Up to 10 base64 images or objects
upscalearray[]["2K"], ["4K"] (4K requires an Ultra account)

2. Video — POST /api/video/generate

FieldTypeDefaultDescription
promptstring— (required)Motion description
modelstringveo_31_fastveo_31_fast, veo_31_lite, veo_31_quality, veo_31_lite_relaxed (Ultra), omni_flash
modestringtext_to_videotext_to_video, start_image, start_end_image, components
aspect_ratiostring16:916:9, 9:16
resolutionarray["720p"]720p, 1080p, 4K (only 4K requires Ultra)
reference_imagesarray[]Required when mode ≠ text. Max 3 (Veo), 7 (Omni Flash)
voicestring""Voice name — components mode only
video_lengthint8Seconds. Veo: 4/6/8 (4/6 require Ultra). Omni Flash: 4/6/8/10
⚠️veo_31_fast_relaxed is no longer valid (falls back to veo_31_fast). Omni Flash does not support start_end_image.

3. Grok — POST /api/grok/generate NEW

FieldTypeDefaultDescription
promptstring— (required)Content description
modestringt2vt2i, i2i, t2v, i2v (invalid mode → failed)
aspect_ratiostring9:169:16, 16:9, 1:1, 2:3, 3:2
reference_imagesarray[]Up to 5; required for i2i & i2v
video_lengthint66 or 10 (video modes only)
resolutionstring480p480p or 720p (video modes only; images always 1K)

4. Meta AI — POST /api/meta/generate NEW

FieldTypeDefaultDescription
promptstring— (required)Content description
modestringt2it2i, i2i, t2v, i2v (invalid mode → failed)
aspect_ratiostring9:169:16, 16:9, 1:1
resolutionstring720p480p or 720p (video modes only; images always 1K)
countint11–4 outputs per prompt
character_image / scene_image / style_imagestringbase64 — components for i2i mode (≥1 required)
start_image / end_imagestringbase64 — start frame (required) / end frame (optional) for i2v mode
ℹ️Meta AI needs a separate Meta account (the vibes.ai meta_session cookie). The Meta AI page in the app is PLUS/MAX only; reference images are passed as named slots, not the reference_images array.

Reference images & @tag

json
"reference_images": [
  "data:image/png;base64,...",
  {"data": "base64...", "category": "subject", "name": "red_car.png"}
]

category (subject/scene/style) is ignored for Flow models. When an image has a name, point at it in the prompt with @tag (substring of filename) — works for image & video (Veo) only, Grok & Meta AI do not support it.

5–8: Status, Result, Tasks, Files

text
GET /api/status/{task_id}    — Check task status
GET /api/result/{task_id}    — Get result
GET /api/tasks               — List tasks (max 50)
GET /api/files/{filename}    — Download binary file

Status values: pendingrunningcompleted / failed

🔄 Polling Pattern

Since generation takes time, poll (suggested every 3–5 seconds):

python
import requests, time

BASE = "http://127.0.0.1:8765"
HEADERS = {"X-API-Key": "YOUR_API_KEY", "Content-Type": "application/json"}

resp = requests.post(f"{BASE}/api/image/generate", headers=HEADERS, json={
    "prompt": "a futuristic city at sunset",
    "model": "nano_banana_2",
    "aspect_ratio": "16:9"
})
task_id = resp.json()["task_id"]

while True:
    s = requests.get(f"{BASE}/api/status/{task_id}", headers=HEADERS).json()
    if s["status"] == "completed":
        for url in s["results"]:
            data = requests.get(url).content   # /api/files needs no key
            open(url.split("/")[-1], "wb").write(data)
        break
    if s["status"] == "failed":
        print(s["error_code"], s["error"])
        break
    time.sleep(4)

🔗 Integration Examples

JavaScript / Node.js

javascript
const BASE = "http://127.0.0.1:8765";
const H = { "X-API-Key": "YOUR_API_KEY", "Content-Type": "application/json" };

const res = await fetch(`${BASE}/api/image/generate`, {
  method: "POST", headers: H,
  body: JSON.stringify({ prompt: "a cat in space", model: "nano_banana_2", aspect_ratio: "1:1" })
});
const { task_id } = await res.json();

const poll = setInterval(async () => {
  const s = await fetch(`${BASE}/api/status/${task_id}`, { headers: H }).then(r => r.json());
  if (s.status === "completed") { clearInterval(poll); console.log(s.results); }
  if (s.status === "failed") { clearInterval(poll); console.error(s.error); }
}, 5000);

cURL Quick Test

bash
curl http://127.0.0.1:8765/api/health

curl -X POST http://127.0.0.1:8765/api/grok/generate \
  -H "X-API-Key: YOUR_KEY" -H "Content-Type: application/json" \
  -d '{"prompt": "a girl swimming", "mode": "t2i", "aspect_ratio": "16:9"}'

curl -X POST http://127.0.0.1:8765/api/meta/generate \
  -H "X-API-Key: YOUR_KEY" -H "Content-Type: application/json" \
  -d '{"prompt": "a girl swimming", "mode": "t2i", "aspect_ratio": "16:9"}'

curl -H "X-API-Key: YOUR_KEY" http://127.0.0.1:8765/api/status/TASK_ID

⚠️ Error Codes

HTTP CodeMeaning
202Task accepted (queued)
400Empty body / invalid JSON
401Invalid or missing API key
404Task/file/endpoint not found
500File read error

When a task is failed, the status response carries an error_code:

error_codeMeaning
429Quota / rate limit → back off, rotate accounts, retry
403PERMISSION_DENIED / session issue
400Invalid request / prompt policy violation
500Upstream Google/xAI/Meta error
0Validation error (missing prompt, no accounts, invalid Grok/Meta mode, timeout...)