Discount on all models + if you follow us on twitter and hit us on dm you will get free credit to your email hurry up 🔥🔥🔥 click here
Any issues any issue at all join our discord or use the feedback system and report it we will solve it faster than you think ̲𝖢̲𝗅̲𝗂̲𝖼̲𝗄̲ ̲𝗁̲𝖾̲𝗋̲𝖾̲ it will redirect to discord server.
API · ERRORS

Every error tells you what to do next.

Errors carry an error code, a human message, and a next field telling you the recommended remediation. Build your retries and fallbacks against error — never parse message for branching.

The error shape

HTTP 403
{
  "error":      "MODEL_NOT_ALLOWED",
  "message":    "This model isn't enabled for your account.",
  "next":       "Email sales@getvivix.com to request access — we typically respond within 24h.",
  "model":      "video-cinematic-4k",
  "request_id": "req_abc123xyz"
}

Always pass request_id when you write to support — it lets us pull up your exact log line in seconds instead of digging through traces. Every error has one.

Error codes

Auth · 401 / 403

CodeWhenWhat to do
401 UNAUTHORIZEDMissing or malformed Authorization header.Add Authorization: Bearer vvx_live_…. Make sure there's no quote/whitespace around the token.
401 KEY_INVALIDThe key doesn't exist in our records.Generate a new key in Settings → API. The old one was probably revoked or never existed.
401 KEY_REVOKEDThe key was revoked by the user (you, or your admin).Generate a new one. Revocation is permanent.
403 TIER_LOCKEDAPI access requires Pro or Ultimate. Your account is on Free or Standard.Upgrade your plan. Pro starts at $15.
403 MODEL_NOT_ALLOWEDYour account isn't enabled for this specific model.Email sales@getvivix.com to request access. Some models need a per-customer pricing arrangement.

Billing · 402

CodeWhenWhat to do
402 INSUFFICIENT_CREDITSYou don't have enough credits for this generation.Top up at /pricing, wait for your daily drop (free tier), or pick a cheaper config (lower res / shorter duration).

The error body includes balance (what you have) andneeded (what the call would have cost) so you can render a useful upsell to your end-users.

Validation · 422

CodeWhenWhat to do
422 INVALID_PARAMSA required param is missing or out of range.Check the field + reason in the body. Common: prompt over 2000 chars, duration outside the model's range, unknown aspect_ratio.
422 UNKNOWN_MODELThe <code>model</code> slug doesn&apos;t match any in your allowlist.Call GET /api/v1/models to see the exact slugs available to your key.

Rate · 429

CodeWhenWhat to do
429 RATE_LIMITYou&apos;re over your per-minute call limit (Pro 240, Ultimate 600).Back off. Read Retry-After header (in seconds) and retry after that. Long-term: batch where possible or upgrade tier.
429 CONCURRENCY_LIMITToo many in-flight jobs at once (Pro 5, Ultimate 20).Wait for one of your in-flight generations to finish, then retry.

Server · 5xx

CodeWhenWhat to do
500 INTERNAL_ERRORSomething went wrong on our side.Retry with exponential backoff (start at 1s, double each time, max 30s). Capture the request_id for support.
503 PROVIDER_DOWNThe underlying model provider is having an outage.Retry after 60s. We mirror most popular models across providers — falling back may take a few minutes if a major provider is down.

Recommended patterns

Idempotent retries. Generation requests are safe to retry — if the original succeeded, the retry creates a brand-new generation (and you pay twice). If you need true idempotency, dedupe on your side using a request hash before calling.
async function generateWithRetry(payload: any, attempt = 0): Promise<any> {
  const res = await fetch('https://vivix-atelier.vercel.app/api/v1/generate', {
    method: 'POST',
    headers: { Authorization: `Bearer ${process.env.VIVIX_KEY}`, 'Content-Type': 'application/json' },
    body: JSON.stringify(payload),
  })
  if (res.ok) return res.json()

  const body = await res.json()

  // Permanent failures — don't retry.
  if (res.status === 401 || res.status === 402 || res.status === 403 || res.status === 422) {
    throw new ApiError(body)
  }

  // Rate-limited — wait the server's recommended duration.
  if (res.status === 429) {
    const retryAfter = Number(res.headers.get('Retry-After') ?? '5')
    await sleep(retryAfter * 1000)
    return generateWithRetry(payload, attempt + 1)
  }

  // Server-side hiccup — exponential backoff up to 5 attempts.
  if (res.status >= 500 && attempt < 5) {
    await sleep(Math.min(30_000, 1000 * 2 ** attempt))
    return generateWithRetry(payload, attempt + 1)
  }

  throw new ApiError(body)
}

Where to next