{"openapi":"3.1.0","info":{"title":"cheapaiapi","description":"Image, text, and video generation API for production workloads. CheapAIAPI implements the fields and behaviors documented here; it is not a drop-in implementation of every parameter offered by official model APIs. Use this documentation and the generated OpenAPI schema as the compatibility contract.\n\n**Compare current prices.** CheapAIAPI is a prepaid, usage-based API with no monthly or annual subscription. The public catalog contains real starting prices for new customers in [Markdown](https://cheapaiapi.org/pricing.md) and [JSON](https://cheapaiapi.org/pricing.json). See dated, like-for-like comparisons at [cheapaiapi.org/models](https://cheapaiapi.org/models/).\n\n**Get access or a volume discount.** API keys are issued after account approval. Customers with existing production volume may qualify for lower account-specific rates. Use [cheapaiapi.org/contact](https://cheapaiapi.org/contact) to send the exact model, current monthly usage, and average and peak RPS.\n\n**Authenticate.** Click **Authorize** and paste your `sk_cheap_...` key. The docs will attach it as `Authorization: Bearer <key>` for Try it out requests.\n\n**Recommended production flow.**\n1. Call `GET /v1/models` to see your enabled SKUs and prices.\n2. Submit `POST /v1/images/generations?async=true` with `webhook_url`.\n3. Store the returned `id`.\n4. Handle the signed webhook as the primary image completion path; recover with `GET /v1/jobs/{id}` if no callback arrives.\n\n**Video generation.** When video is enabled for your account, submit `POST /v1/videos`, poll `GET /v1/videos/{id}`, and stream the completed MP4 through the authenticated `GET /v1/videos/{id}/content` endpoint. Use `GET /v1/models` as the source of truth for available video SKUs and prices. `image_url` is the first frame, `last_frame_image_url` is the last frame, and `reference_image_urls` are style/identity images not frames. Standard `seedance-2.0` supports text-to-video plus `image_url`, `last_frame_image_url`, `reference_image_urls`, and `seed`. Standard `seedance-2.5` and entitled `seedance-2.5-nsfw` accept the same media fields; NSFW only changes moderation. Defaults are five seconds, 720p, 16:9, audio on. Callers may set `duration` (1-15), `resolution`, `aspect_ratio`, and `generate_audio`; price equals the account's per-output-second rate for the selected model and resolution multiplied by duration. `GET /v1/models` returns the current resolution rate card. NSFW mode is disabled by default. Contact our team for account-level enablement and custom pricing; additional pricing applies, and acceptance is not guaranteed.\n\n**Text completions.** Call `POST /v1/chat/completions` with required `messages`; `model`, `stream`, and `conversation_id` are optional. The endpoint schema is authoritative: text, the `image_url` request shape, function tools, a non-stream JSON completion envelope, and buffered OpenAI-compatible SSE form the integration core. Additional compatibility fields such as `response_format`, `reasoning_effort`, sampling controls, and unrecognized top-level fields may be best-effort passthrough and are not guaranteed across every model. For accounts with token-priced text enabled, default prices per 1M input/output tokens are `gemini-3.5-flash` ($1.05/$6.30), `gemini-3.1-flash-lite` ($0.175/$1.05), `gemini-3.1-pro` ($1.40/$8.40). The authenticated `GET /v1/models` response is authoritative for the caller's enabled SKUs and prices; accounts not yet cut over retain the pricing unit returned there. Only enabled account SKUs appear in `GET /v1/models`. The response is either one JSON completion or an SSE sequence ending in `[DONE]`.\n\n**Long text and files.** The API does not promise one shared context window, file-count limit, or attachment-size limit across all text models. The OpenAI-compatible `image_url` content part accepts a public URL or base64 `data:` URL. Context and media support depend on the selected model.\n\n**Integration rules for coding agents.** `queued` and `running` are pending states, not failures. Result data is available only after `status` is `done`. Use a stable `Idempotency-Key` per client-side job and reuse the same key when retrying after a timeout. Do not send concurrent duplicate create requests for the same client-side job.\n\n\n## Webhook integration\n\nEvery image account can use webhooks. Pass `webhook_url` in the normal\nasynchronous generation request to receive an HTTPS `POST` when the Job reaches\n`done` or `failed`. `custom_data` is an optional JSON object of at most 4096\nserialized bytes; it is stored and echoed unchanged in create, polling, and\ncallback responses, and can also be used without a webhook. Do not put secrets\nin `custom_data`. Chat Completions and video do not accept `webhook_url`.\n\nThe full guide is at https://cheapaiapi.org/docs/webhooks.md.\n\n```json\n{\n  \"model\": \"nano-banana-pro-2k\",\n  \"prompt\": \"Place the product on a clean studio background.\",\n  \"response_format\": \"url\",\n  \"webhook_url\": \"https://api.example.com/webhooks/cheapaiapi\",\n  \"custom_data\": {\"customer_request_id\": \"customer-job-123\"}\n}\n```\n\nSubmit this body to `POST /v1/images/generations?async=true`, store the returned\nJob `id`, and keep `GET /v1/jobs/{id}` as the recovery path. Webhook URLs must be\npublicly reachable HTTPS endpoints. Callback Jobs require\n`response_format: \"url\"` so callback bodies contain durable result URLs rather\nthan large inline image bytes.\n\n### Callback body\n\nThe callback is the frozen terminal projection of the public Job response, with\nan additional stable `event_id`. A successful callback looks like this:\n\n```json\n{\n  \"event_id\": \"0bd05147-b6a0-45fa-b176-9cfe008bb350\",\n  \"id\": \"3e7487ca-a942-4ef0-bc47-4cb8171a2ca8\",\n  \"status\": \"done\",\n  \"model\": \"nano-banana-pro-2k\",\n  \"created_at\": \"2026-07-14T12:20:00+00:00\",\n  \"finished_at\": \"2026-07-14T12:20:14+00:00\",\n  \"custom_data\": {\"customer_request_id\": \"customer-job-123\"},\n  \"data\": [{\"url\": \"https://cheapaiapi.org/v1/jobs/3e7487ca-a942-4ef0-bc47-4cb8171a2ca8/results/0?sig=...\"}],\n  \"error\": null\n}\n```\n\nFor a failed Job, `status` is `failed`, `data` is empty, and `error` contains\nthe same sanitized public error shape returned by polling. The submitted\n`webhook_url` and prompt are not echoed.\n\n### Signing secret and verification\n\nRead `webhook_secret` from `GET /v1/balance` and store it on your backend.\nThe first `GET /v1/balance` or `webhook_url` create creates the secret if the\naccount has none. Do not put it in browser or mobile code.\n\nEvery callback has one signing header:\n\n```text\nX-CheapAIAPI-Signature: t=<unix_timestamp>,v1=<hex_hmac_sha256>\n```\n\nThe signed bytes are `<unix_timestamp>.<exact raw request body>`. Read the raw\nbody before JSON parsing, reject timestamps more than five minutes from your\nclock, and compare digests in constant time.\n\n```python\nimport hashlib\nimport hmac\nimport json\nimport time\n\nfrom fastapi import FastAPI, HTTPException, Request, Response\n\napp = FastAPI()\nWEBHOOK_SECRET = \"<from GET /v1/balance webhook_secret>\"\n\n\ndef verify_signature(header: str, raw_body: bytes) -> bool:\n    try:\n        parts = dict(part.split(\"=\", 1) for part in header.split(\",\"))\n        timestamp = int(parts[\"t\"])\n        supplied = parts[\"v1\"]\n    except (KeyError, TypeError, ValueError):\n        return False\n    if abs(int(time.time()) - timestamp) > 300:\n        return False\n    signed = f\"{timestamp}.\".encode() + raw_body\n    expected = hmac.new(\n        WEBHOOK_SECRET.encode(), signed, hashlib.sha256\n    ).hexdigest()\n    return hmac.compare_digest(expected, supplied)\n\n\n@app.post(\"/webhooks/cheapaiapi\")\nasync def receive_webhook(request: Request) -> Response:\n    raw_body = await request.body()\n    signature = request.headers.get(\"X-CheapAIAPI-Signature\", \"\")\n    if not verify_signature(signature, raw_body):\n        raise HTTPException(status_code=400, detail=\"invalid signature\")\n    event = json.loads(raw_body)\n    # Insert event[\"event_id\"] into an inbox table with a UNIQUE constraint,\n    # and apply your business effect in the same database transaction.\n    return Response(status_code=204)\n```\n\nReturn any `2xx` quickly to acknowledge delivery. Transient delivery failures\nare retried automatically, so the same signed `event_id` may arrive more than\nonce. Deduplicate by `event_id`; on a duplicate, skip the business effect and\nreturn `2xx`. If no callback arrives, recover with `GET /v1/jobs/{id}`.\n\nUse webhooks as the primary completion signal for production image volume and\npolling only as a recovery path. For workloads above 1,000 generation Jobs per day\nthis is especially important: it removes polling traffic and polling-interval\ndelay; it does not reduce generation time. The full guide is\nhttps://cheapaiapi.org/docs/webhooks.md.\n\n\n**Image inputs.** `image` accepts public `https://` URLs or `data:image/<mime>;base64,...` URIs. Empty `image` means text-to-image.\n\n**Responses.** Every generation response includes a job `id`, even if the request later finishes asynchronously. Result URLs are served from cheapaiapi result endpoints. Generation and job responses may include `usage.cost_usd` and `usage.balance_remaining_usd`; these are customer-facing amounts only. `balance_remaining_usd` is the available balance at response time, so parallel requests can make responses arrive out of balance order.\n\n**Errors.** Customer-facing errors use a small stable taxonomy: `RateLimited`, `UpstreamDown`, `NoFunds`, `InvalidPrompt`, `Unauthorized`.","version":"0.1.0.2"},"servers":[{"url":"https://cheapaiapi.org","description":"Production"}],"paths":{"/v1/balance":{"get":{"tags":["Account"],"summary":"Get account balance","description":"Return the authenticated account's available USD balance and the image webhook HMAC secret. Pass `webhook_url` on `POST /v1/images/generations?async=true`. Store `webhook_secret` on your backend to verify `X-CheapAIAPI-Signature`.","operationId":"get_balance_v1_balance_get","responses":{"200":{"description":"Available account balance.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BalanceResponse"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"},"example":{"error":{"message":"Missing or invalid API key.","type":"authentication_error","code":"invalid_api_key"}}}}},"422":{"description":"Request validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"},"example":{"error":{"message":"Request validation failed.","type":"invalid_request_error","param":"prompt","code":"invalid_parameter"}}}}},"429":{"description":"Rate limit exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"},"example":{"error":{"message":"Too many requests. Please retry later.","type":"rate_limit_exceeded","code":"rate_limit_exceeded"}}}}},"500":{"description":"Temporary service error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"},"example":{"error":{"message":"An internal server error occurred. Please retry; if the issue persists, contact support.","type":"server_error","code":"server_error"}}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/usage":{"get":{"tags":["Account"],"summary":"Get usage","description":"Return aggregate job counts and spend for the authenticated account.","operationId":"get_usage_v1_usage_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"from","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"ISO-8601 lower bound (inclusive). Defaults to 30 days ago.","title":"From"},"description":"ISO-8601 lower bound (inclusive). Defaults to 30 days ago."},{"name":"to","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"ISO-8601 upper bound (exclusive). Defaults to now.","title":"To"},"description":"ISO-8601 upper bound (exclusive). Defaults to now."}],"responses":{"200":{"description":"Usage totals for the selected time range.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageResponse"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"example":{"error":{"message":"Missing or invalid API key.","type":"authentication_error","code":"invalid_api_key"}},"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Request validation failed.","content":{"application/json":{"example":{"error":{"message":"Request validation failed.","type":"invalid_request_error","param":"prompt","code":"invalid_parameter"}},"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"429":{"description":"Rate limit exceeded.","content":{"application/json":{"example":{"error":{"message":"Too many requests. Please retry later.","type":"rate_limit_exceeded","code":"rate_limit_exceeded"}},"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Temporary service error.","content":{"application/json":{"example":{"error":{"message":"An internal server error occurred. Please retry; if the issue persists, contact support.","type":"server_error","code":"server_error"}},"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"400":{"description":"Invalid usage time range.","content":{"application/json":{"example":{"error":{"message":"`from` must be earlier than `to`.","type":"invalid_request_error","param":"from","code":"invalid_range"}},"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/jobs":{"get":{"tags":["Jobs"],"summary":"List jobs","description":"Return the authenticated Customer Account's Jobs newest first across all of its API keys. Pages use an opaque cursor and contain durable request metadata plus Customer Ledger charges only. Prompts, input/output media, result URLs, provider attempts, provider identities, internal costs, and raw diagnostic payloads are never included. Job and billing metadata is retained independently from the shorter media-retention policy.","operationId":"list_jobs_v1_jobs_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Limit"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string","minLength":1,"maxLength":512},{"type":"null"}],"title":"Cursor"}}],"responses":{"200":{"description":"Account-wide customer-safe Job history.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerJobHistoryResponse"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"example":{"error":{"message":"Missing or invalid API key.","type":"authentication_error","code":"invalid_api_key"}},"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Request validation failed.","content":{"application/json":{"example":{"error":{"message":"Request validation failed.","type":"invalid_request_error","param":"prompt","code":"invalid_parameter"}},"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"429":{"description":"Rate limit exceeded.","content":{"application/json":{"example":{"error":{"message":"Too many requests. Please retry later.","type":"rate_limit_exceeded","code":"rate_limit_exceeded"}},"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Temporary service error.","content":{"application/json":{"example":{"error":{"message":"An internal server error occurred. Please retry; if the issue persists, contact support.","type":"server_error","code":"server_error"}},"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"400":{"description":"The pagination cursor is invalid."}}}},"/v1/transactions":{"get":{"tags":["Account"],"summary":"List transactions","description":"Return balance-changing Customer Ledger events newest first across the authenticated Customer Account. The signed amount is positive for credits and negative for usage debits. Zero-value internal audit events and private operator notes are not exposed. Pages use an opaque cursor.","operationId":"list_transactions_v1_transactions_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Limit"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string","minLength":1,"maxLength":512},{"type":"null"}],"title":"Cursor"}}],"responses":{"200":{"description":"Account-wide Customer Ledger transaction history.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerTransactionHistoryResponse"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"example":{"error":{"message":"Missing or invalid API key.","type":"authentication_error","code":"invalid_api_key"}},"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Request validation failed.","content":{"application/json":{"example":{"error":{"message":"Request validation failed.","type":"invalid_request_error","param":"prompt","code":"invalid_parameter"}},"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"429":{"description":"Rate limit exceeded.","content":{"application/json":{"example":{"error":{"message":"Too many requests. Please retry later.","type":"rate_limit_exceeded","code":"rate_limit_exceeded"}},"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Temporary service error.","content":{"application/json":{"example":{"error":{"message":"An internal server error occurred. Please retry; if the issue persists, contact support.","type":"server_error","code":"server_error"}},"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"400":{"description":"The pagination cursor is invalid."}}}},"/v1/jobs/{job_id}":{"get":{"tags":["Jobs"],"summary":"Get job","description":"Return the customer-safe state for one image, video, or chat job. For a chat completion, strip the `chatcmpl-` prefix from the completion `id` and poll this path until `status` is `done` or `failed`. `queued` and `running` are pending states. Image results are in `data` only when `status` is `done`. A completed chat job includes the persisted public completion in `response`. When the create request included `webhook_url`, the same terminal state is also sent as a signed callback. Prefer that callback; this GET is the recovery path.","operationId":"get_job_v1_jobs__job_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Job Id"}}],"responses":{"200":{"description":"Public job state.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobLookupResponse"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"example":{"error":{"message":"Missing or invalid API key.","type":"authentication_error","code":"invalid_api_key"}},"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Request validation failed.","content":{"application/json":{"example":{"error":{"message":"Request validation failed.","type":"invalid_request_error","param":"prompt","code":"invalid_parameter"}},"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"429":{"description":"Rate limit exceeded.","content":{"application/json":{"example":{"error":{"message":"Too many requests. Please retry later.","type":"rate_limit_exceeded","code":"rate_limit_exceeded"}},"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Temporary service error.","content":{"application/json":{"example":{"error":{"message":"An internal server error occurred. Please retry; if the issue persists, contact support.","type":"server_error","code":"server_error"}},"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"No job exists for the supplied id.","content":{"application/json":{"example":{"error":{"message":"No job with that id.","type":"invalid_request_error","code":"job_not_found"}},"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/models":{"get":{"tags":["Models"],"summary":"List enabled models","description":"Return model SKUs enabled for the account, including mutually exclusive per-call, per-output-second video, or input/output token pricing in USD.","operationId":"list_models_v1_models_get","responses":{"200":{"description":"Models enabled for the authenticated Customer Account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelListResponse"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"},"example":{"error":{"message":"Missing or invalid API key.","type":"authentication_error","code":"invalid_api_key"}}}}},"422":{"description":"Request validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"},"example":{"error":{"message":"Request validation failed.","type":"invalid_request_error","param":"prompt","code":"invalid_parameter"}}}}},"429":{"description":"Rate limit exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"},"example":{"error":{"message":"Too many requests. Please retry later.","type":"rate_limit_exceeded","code":"rate_limit_exceeded"}}}}},"500":{"description":"Temporary service error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"},"example":{"error":{"message":"An internal server error occurred. Please retry; if the issue persists, contact support.","type":"server_error","code":"server_error"}}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/chat/completions":{"post":{"tags":["Chat"],"summary":"Create chat completion","description":"Create an OpenAI-compatible text completion. The guaranteed integration contract covers required messages, optional model and stream, text and the image_url request shape, one completion, function tools, a non-stream JSON completion envelope, and buffered OpenAI-compatible SSE. A standard assistant function tool_calls message followed by role=tool is accepted unchanged. Only function-type tools are accepted; tool_choice supports auto, required, none, or a named function. image_url accepts a public HTTPS URL or base64 data URI. Additional compatibility fields such as response_format, reasoning, sampling, and unrecognized top-level fields may be best-effort passthrough; behavior can vary by model. webhook_url and custom_data are not accepted for Chat Completions. n may be omitted or set to integer 1; multiplying fields are unsupported; use only one of max_tokens and max_completion_tokens, up to 65,536. Context and media support depend on the selected model. Successful responses always include terminal prompt, completion, and total token counts used for customer billing.","operationId":"create_chat_completion_v1_chat_completions_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","minLength":1,"maxLength":255},{"type":"null"}],"title":"Idempotency-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatCompletionRequest"}}}},"responses":{"200":{"description":"With stream=false, returns one OpenAI-compatible JSON completion. With stream=true, returns text/event-stream; its final JSON event contains usage and is followed by data: [DONE].","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatCompletionResponse"}},"text/event-stream":{"schema":{"type":"string"},"example":"data: {\"id\":\"chatcmpl-018f5f1c-7b19-7e4a-a5c1-0d44fe93aa10\",\"object\":\"chat.completion.chunk\",\"model\":\"gemini-3.5-flash\",\"choices\":[{\"index\":0,\"delta\":{\"role\":\"assistant\",\"content\":\"Hello!\"},\"finish_reason\":\"stop\"}]}\n\ndata: {\"id\":\"chatcmpl-018f5f1c-7b19-7e4a-a5c1-0d44fe93aa10\",\"object\":\"chat.completion.chunk\",\"model\":\"gemini-3.5-flash\",\"choices\":[],\"usage\":{\"prompt_tokens\":12,\"completion_tokens\":8,\"total_tokens\":20}}\n\ndata: [DONE]\n\n"}},"headers":{"X-Chat-Completion-Id":{"description":"Recoverable chatcmpl-<Job UUID> for SSE responses.","schema":{"type":"string"}},"X-Conversation-Id":{"description":"Conversation identifier when one is returned.","schema":{"type":"string"}}}},"408":{"description":"The non-stream delivery deadline elapsed while the Job continued in the background. Strip the `chatcmpl-` prefix from `X-Chat-Completion-Id` and poll `GET /v1/jobs/{uuid}`.","headers":{"X-Chat-Completion-Id":{"description":"Exact recoverable chatcmpl-<Job UUID> identifier.","schema":{"type":"string"}},"X-Should-Retry":{"description":"Always false; recover the existing Job instead of replaying POST.","schema":{"type":"string","enum":["false"]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/images/generations":{"post":{"tags":["Images"],"summary":"Create image generation","description":"Create an image generation job. Use `?async=true` for production workloads, pass `webhook_url`, and store the returned `id`. Read `webhook_secret` from `GET /v1/balance`. Recover with `GET /v1/jobs/{id}` if no callback arrives. Treat `queued` and `running` as pending states, not errors; `data` is empty until `done`. Use a stable `Idempotency-Key` when retrying after a timeout. Do not send concurrent duplicate create requests for the same client-side job. Image output is URL-only: omit `response_format` or set it to `url`, then download the image from `data[].url`.","operationId":"generate_v1_images_generations_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"async","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Async"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","minLength":1,"maxLength":255},{"type":"null"}],"title":"Idempotency-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageGenerationRequest"}}}},"responses":{"200":{"description":"Image generation job state.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageGenerationResponse"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"example":{"error":{"message":"Missing or invalid API key.","type":"authentication_error","code":"invalid_api_key"}},"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Invalid request body or unsupported image output format. Use `response_format=url` or omit the field.","content":{"application/json":{"examples":{"invalid_parameter":{"value":{"error":{"message":"Request validation failed.","type":"invalid_request_error","param":"prompt","code":"invalid_parameter"}}},"unsupported_response_format":{"value":{"error":{"message":"`b64_json` output is not supported. Use `response_format=\"url\"` (or omit `response_format`) and download the generated image from `data[].url`. Integration docs: https://cheapaiapi.org/docs","type":"invalid_request_error","param":"response_format","code":"unsupported_response_format"}}}},"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"429":{"description":"Rate limit exceeded.","content":{"application/json":{"example":{"error":{"message":"Too many requests. Please retry later.","type":"rate_limit_exceeded","code":"rate_limit_exceeded"}},"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Temporary service error.","content":{"application/json":{"example":{"error":{"message":"An internal server error occurred. Please retry; if the issue persists, contact support.","type":"server_error","code":"server_error"}},"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"400":{"description":"Invalid image generation request.","content":{"application/json":{"example":{"error":{"message":"Request validation failed.","type":"invalid_request_error","param":"prompt","code":"invalid_parameter"}},"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"402":{"description":"Account balance is too low for this request.","content":{"application/json":{"example":{"error":{"message":"Insufficient balance for this request.","type":"insufficient_quota","code":"insufficient_balance"}},"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"503":{"description":"Webhook intake is temporarily unavailable.","content":{"application/json":{"example":{"error":{"message":"Webhook callbacks and custom correlation data are temporarily unavailable. Try again later.","type":"server_error","param":"webhook_url","code":"webhook_temporarily_unavailable"}},"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"202":{"description":"The job was queued for asynchronous processing. Handle the signed webhook, or recover with `GET /v1/jobs/{id}`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageGenerationResponse"}}}}}}},"/v1/videos":{"post":{"tags":["Videos"],"summary":"Create video","description":"Create one asynchronous video using the supported official Seedance generation fields: content, duration, resolution, ratio, and generate_audio. Seedance 2.0 accepts 4-15 seconds (default 5); Seedance 2.5 requires an explicit duration of 4-30 seconds. Defaults are 720p, ratio=adaptive, and audio on. Price is the account's USD-per-second rate for the requested model and resolution, multiplied by duration. Poll `GET /v1/videos/{id}` until the status is `completed` or `failed`, then download completed output from `GET /v1/videos/{id}/content`.","operationId":"create_video_v1_videos_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","minLength":1,"maxLength":255},{"type":"null"}],"title":"Idempotency-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VideoCreateRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VideoResource"}}}},"400":{"description":"Unknown, unavailable, or unpriced video model."},"401":{"description":"Missing or invalid API key."},"402":{"description":"Insufficient balance."},"404":{"description":"Video resource not found."},"409":{"description":"Idempotency key reused with a different request body."},"422":{"description":"Request validation failed."},"429":{"description":"Too many active jobs."},"500":{"description":"Unexpected server error."},"503":{"description":"Video generation is temporarily unavailable."}}}},"/v1/videos/{video_id}":{"get":{"tags":["Videos"],"summary":"Get video","description":"Return the customer-safe state of one video. A completed video's content is available for up to 24 hours at `GET /v1/videos/{id}/content`.","operationId":"get_video_v1_videos__video_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"video_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Video Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VideoResource"}}}},"400":{"description":"Unknown, unavailable, or unpriced video model."},"401":{"description":"Missing or invalid API key."},"402":{"description":"Insufficient balance."},"404":{"description":"Video resource not found."},"409":{"description":"Idempotency key reused with a different request body."},"422":{"description":"Request validation failed."},"429":{"description":"Too many active jobs."},"500":{"description":"Unexpected server error."},"503":{"description":"Video generation is temporarily unavailable."}}}},"/v1/videos/{video_id}/content":{"get":{"tags":["Videos"],"summary":"Download video content","description":"Stream completed MP4 content through the API domain. A single HTTP byte Range is supported. Content is retained for up to 24 hours.","operationId":"get_video_content_v1_videos__video_id__content_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"video_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Video Id"}},{"name":"Range","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Range"}}],"responses":{"200":{"description":"Successful Response"},"401":{"description":"Missing or invalid API key."},"404":{"description":"Video resource not found."},"409":{"description":"Video generation has not completed."},"410":{"description":"Generated video content has expired."},"416":{"description":"Invalid or unsatisfiable byte range."},"502":{"description":"Video content could not be fetched safely."},"503":{"description":"Video streaming capacity is temporarily exhausted."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"ApiErrorResponse":{"properties":{"error":{"$ref":"#/components/schemas/ErrorEnvelope","description":"Stable error envelope for client handling."}},"additionalProperties":false,"type":"object","required":["error"],"title":"ApiErrorResponse","description":"OpenAI-compatible customer-facing error response.","example":{"error":{"code":"invalid_model","message":"The request could not be processed.","param":"model","type":"invalid_request_error"}}},"AspectRatio":{"type":"string","enum":["auto","4:3","3:4","16:9","9:16","2:3","3:2","1:1","4:5","5:4","21:9"],"title":"AspectRatio","description":"Supported image aspect ratios."},"BalanceResponse":{"properties":{"balance_usd":{"type":"string","title":"Balance Usd","description":"Available account balance as a decimal string."},"currency":{"type":"string","const":"USD","title":"Currency","description":"Balance currency.","default":"USD"},"webhook_secret":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhook Secret","description":"HMAC secret for image Job webhooks. Present on API-key `GET /v1/balance` only. Store it on your backend. Created on first API-key read or first `webhook_url` Job if missing."}},"additionalProperties":false,"type":"object","required":["balance_usd"],"title":"BalanceResponse","description":"``GET /v1/balance`` response.","example":{"balance_usd":"25.50","currency":"USD","webhook_secret":"whsec_example"}},"ChatCompletionChoice":{"properties":{"index":{"type":"integer","minimum":0.0,"title":"Index"},"message":{"$ref":"#/components/schemas/ChatCompletionMessage"},"finish_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Finish Reason"},"logprobs":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Logprobs"}},"additionalProperties":false,"type":"object","required":["index","message"],"title":"ChatCompletionChoice","description":"One non-streaming chat completion choice."},"ChatCompletionMessage":{"properties":{"role":{"type":"string","const":"assistant","title":"Role","default":"assistant"},"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content"},"reasoning_content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reasoning Content","description":"Optional model reasoning content when the selected SKU returns it."},"refusal":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Refusal"},"function_call":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Function Call"},"tool_calls":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Tool Calls"},"annotations":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Annotations"},"audio":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Audio"}},"additionalProperties":false,"type":"object","title":"ChatCompletionMessage","description":"Assistant message in a non-streaming chat completion choice."},"ChatCompletionRequest":{"properties":{"model":{"type":"string","enum":["gemini-3.5-flash","gemini-3.1-flash-lite","gemini-3.1-pro"],"title":"Model","default":"gemini-3.5-flash"},"messages":{"items":{"$ref":"#/components/schemas/ChatMessage"},"type":"array","minItems":1,"title":"Messages"},"stream":{"type":"boolean","title":"Stream","default":false},"conversation_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Conversation Id"},"temperature":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Temperature"},"top_p":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Top P"},"n":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"N"},"stop":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Stop"},"max_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Tokens"},"max_completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Completion Tokens"},"presence_penalty":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Presence Penalty"},"frequency_penalty":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Frequency Penalty"},"logit_bias":{"anyOf":[{"additionalProperties":{"type":"integer"},"type":"object"},{"type":"null"}],"title":"Logit Bias"},"user":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User"},"seed":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Seed"},"response_format":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Response Format"},"tools":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Tools"},"tool_choice":{"anyOf":[{"type":"string"},{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Tool Choice"},"parallel_tool_calls":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Parallel Tool Calls"},"reasoning_effort":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reasoning Effort"},"stream_options":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Stream Options"},"logprobs":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Logprobs"},"top_logprobs":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Top Logprobs"},"service_tier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Service Tier"},"store":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Store"},"metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Metadata"},"moderation":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Moderation"},"modalities":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Modalities"},"prediction":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Prediction"},"audio":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Audio"},"web_search_options":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Web Search Options"},"verbosity":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Verbosity"},"prompt_cache_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Prompt Cache Key"},"prompt_cache_options":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Prompt Cache Options"},"prompt_cache_retention":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Prompt Cache Retention"},"safety_identifier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Safety Identifier"},"extra_body":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Extra Body"},"function_call":{"anyOf":[{"type":"string"},{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Function Call"},"functions":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Functions"},"best_of":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Best Of"},"candidate_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Candidate Count"},"num_return_sequences":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Num Return Sequences"}},"additionalProperties":true,"type":"object","required":["messages"],"title":"ChatCompletionRequest","description":"Public chat request with forward-compatible parameter passthrough."},"ChatCompletionResponse":{"properties":{"id":{"type":"string","title":"Id","description":"Recoverable chatcmpl-<Job UUID> identifier."},"object":{"type":"string","const":"chat.completion","title":"Object","default":"chat.completion"},"created":{"type":"integer","title":"Created","description":"Unix timestamp supplied with the completion."},"model":{"type":"string","title":"Model","description":"The requested public cheapaiapi model SKU."},"choices":{"items":{"$ref":"#/components/schemas/ChatCompletionChoice"},"type":"array","title":"Choices"},"usage":{"$ref":"#/components/schemas/ChatCompletionUsage","description":"Terminal token usage. Present in the JSON response and in the final JSON event before [DONE] when stream=true."},"conversation_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Conversation Id"}},"additionalProperties":false,"type":"object","required":["id","created","model","choices","usage"],"title":"ChatCompletionResponse","description":"OpenAI-compatible non-streaming text completion response.","example":{"choices":[{"finish_reason":"stop","index":0,"message":{"content":"Hello! How can I help?","role":"assistant"}}],"created":1784589000,"id":"chatcmpl-018f5f1c-7b19-7e4a-a5c1-0d44fe93aa10","model":"gemini-3.5-flash","object":"chat.completion","usage":{"completion_tokens":8,"prompt_tokens":12,"total_tokens":20}}},"ChatCompletionTokenDetails":{"properties":{"reasoning_tokens":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Reasoning Tokens"},"audio_tokens":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Audio Tokens"},"accepted_prediction_tokens":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Accepted Prediction Tokens"},"rejected_prediction_tokens":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Rejected Prediction Tokens"}},"additionalProperties":false,"type":"object","title":"ChatCompletionTokenDetails","description":"Optional completion-token breakdown returned by the text model."},"ChatCompletionUsage":{"properties":{"prompt_tokens":{"type":"integer","minimum":0.0,"title":"Prompt Tokens","description":"Input tokens billed at the model's input-token rate."},"completion_tokens":{"type":"integer","minimum":0.0,"title":"Completion Tokens","description":"Output tokens billed at the model's output-token rate, including reasoning tokens when the model reports them."},"total_tokens":{"type":"integer","minimum":0.0,"title":"Total Tokens","description":"Sum of prompt_tokens and completion_tokens."},"prompt_tokens_details":{"anyOf":[{"$ref":"#/components/schemas/ChatPromptTokenDetails"},{"type":"null"}]},"completion_tokens_details":{"anyOf":[{"$ref":"#/components/schemas/ChatCompletionTokenDetails"},{"type":"null"}]}},"additionalProperties":false,"type":"object","required":["prompt_tokens","completion_tokens","total_tokens"],"title":"ChatCompletionUsage","description":"Authoritative token counts used for this completion's Customer Charge."},"ChatImagePart":{"properties":{"type":{"type":"string","const":"image_url","title":"Type"},"image_url":{"$ref":"#/components/schemas/ChatImageURL"},"prompt_cache_breakpoint":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Prompt Cache Breakpoint"}},"type":"object","required":["type","image_url"],"title":"ChatImagePart","description":"Image or file passed using the OpenAI-compatible wire shape."},"ChatImageURL":{"properties":{"url":{"type":"string","title":"Url"},"detail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Detail"}},"type":"object","required":["url"],"title":"ChatImageURL","description":"URL or data URI carried by an ``image_url`` content part."},"ChatMessage":{"properties":{"role":{"type":"string","enum":["system","developer","user","assistant","tool","function"],"title":"Role"},"content":{"anyOf":[{"type":"string"},{"items":{"anyOf":[{"$ref":"#/components/schemas/ChatTextPart"},{"$ref":"#/components/schemas/ChatImagePart"},{"additionalProperties":true,"type":"object"}]},"type":"array"},{"type":"null"}],"title":"Content"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"tool_calls":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Tool Calls"},"tool_call_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tool Call Id"},"function_call":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Function Call"},"refusal":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Refusal"},"audio":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Audio"},"annotations":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Annotations"}},"type":"object","required":["role"],"title":"ChatMessage","description":"One lossless OpenAI-compatible chat-history message.\n\nTool loops replay provider-authored assistant messages. Some upstreams\nembed a mandatory opaque signature inside ``tool_calls`` and require that\nexact object in the next request, so nested compatibility fields must never\nbe projected away here."},"ChatPromptTokenDetails":{"properties":{"cached_tokens":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Cached Tokens"},"audio_tokens":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Audio Tokens"}},"additionalProperties":false,"type":"object","title":"ChatPromptTokenDetails","description":"Optional prompt-token breakdown returned by the text model."},"ChatTextPart":{"properties":{"type":{"type":"string","const":"text","title":"Type"},"text":{"type":"string","title":"Text"},"prompt_cache_breakpoint":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Prompt Cache Breakpoint"}},"type":"object","required":["type","text"],"title":"ChatTextPart","description":"One OpenAI-compatible text content part."},"CustomerJobHistoryItem":{"properties":{"id":{"type":"string","title":"Id","description":"CheapAIAPI Job UUID."},"model":{"type":"string","title":"Model","description":"Customer-facing model SKU."},"kind":{"type":"string","title":"Kind","description":"Product kind such as image, chat, or video."},"status":{"type":"string","enum":["queued","running","done","failed"],"title":"Status"},"created_at":{"type":"string","title":"Created At"},"finished_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Finished At"},"duration_ms":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Duration Ms","description":"Request-to-terminal duration when the Job is terminal."},"billing_status":{"type":"string","enum":["pending","not_charged","charged","partially_refunded","refunded"],"title":"Billing Status"},"charged_usd":{"type":"string","title":"Charged Usd","description":"Ledger debit linked to this Job."},"refunded_usd":{"type":"string","title":"Refunded Usd","description":"Customer Ledger refunds linked to this Job."},"net_spent_usd":{"type":"string","title":"Net Spent Usd","description":"Charge minus linked refunds."},"currency":{"type":"string","const":"USD","title":"Currency","default":"USD"},"error":{"anyOf":[{"$ref":"#/components/schemas/ErrorEnvelope"},{"type":"null"}]}},"additionalProperties":false,"type":"object","required":["id","model","kind","status","created_at","billing_status","charged_usd","refunded_usd","net_spent_usd"],"title":"CustomerJobHistoryItem","description":"One durable customer-visible Job record without request or provider data."},"CustomerJobHistoryResponse":{"properties":{"data":{"items":{"$ref":"#/components/schemas/CustomerJobHistoryItem"},"type":"array","title":"Data"},"has_more":{"type":"boolean","title":"Has More"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"}},"additionalProperties":false,"type":"object","required":["data","has_more"],"title":"CustomerJobHistoryResponse","description":"Cursor page of account-wide durable Job records.","example":{"data":[{"billing_status":"charged","charged_usd":"0.06","created_at":"2026-08-28T12:00:00+00:00","currency":"USD","duration_ms":12000,"finished_at":"2026-08-28T12:00:12+00:00","id":"00000000-0000-4000-8000-000000000000","kind":"image","model":"nano-banana-pro-2k","net_spent_usd":"0.06","refunded_usd":"0","status":"done"}],"has_more":true,"next_cursor":"eyJ2IjoxLCIuLi4iOiIuLi4ifQ"}},"CustomerTransactionHistoryItem":{"properties":{"id":{"type":"string","title":"Id","description":"Stable Customer Ledger transaction UUID."},"type":{"type":"string","enum":["topup","debit","refund","adjustment"],"title":"Type"},"amount_usd":{"type":"string","title":"Amount Usd","description":"Signed balance delta. Credits are positive and debits are negative."},"currency":{"type":"string","const":"USD","title":"Currency","default":"USD"},"created_at":{"type":"string","title":"Created At"},"job_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Job Id","description":"Related Job UUID for a usage debit or refund, when present."}},"additionalProperties":false,"type":"object","required":["id","type","amount_usd","created_at"],"title":"CustomerTransactionHistoryItem","description":"One balance-changing Customer Ledger event."},"CustomerTransactionHistoryResponse":{"properties":{"data":{"items":{"$ref":"#/components/schemas/CustomerTransactionHistoryItem"},"type":"array","title":"Data"},"has_more":{"type":"boolean","title":"Has More"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"}},"additionalProperties":false,"type":"object","required":["data","has_more"],"title":"CustomerTransactionHistoryResponse","description":"Cursor page of account-wide balance-changing transactions.","example":{"data":[{"amount_usd":"-0.06","created_at":"2026-08-28T12:00:12+00:00","currency":"USD","id":"aaaaaaaa-0000-4000-8000-000000000000","job_id":"00000000-0000-4000-8000-000000000000","type":"debit"}],"has_more":false}},"ErrorEnvelope":{"properties":{"type":{"type":"string","title":"Type"},"code":{"type":"string","title":"Code"},"message":{"type":"string","title":"Message","description":"Human-readable public error text. For moderated content-policy refusals, this may contain a localized user-facing explanation of why generation was rejected; other failures use stable generic text."},"param":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Param"}},"additionalProperties":false,"type":"object","required":["type","code","message"],"title":"ErrorEnvelope","description":"Error details for failed jobs."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ImageDataItem":{"properties":{"url":{"type":"string","title":"Url"},"revised_prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Revised Prompt"}},"additionalProperties":false,"type":"object","required":["url"],"title":"ImageDataItem","description":"One element in the ``data`` array of a successful response."},"ImageGenerationRequest":{"properties":{"model":{"type":"string","maxLength":128,"minLength":1,"title":"Model","description":"SKU from `GET /v1/models`, e.g. `nano-banana-pro-1k`."},"prompt":{"type":"string","maxLength":262144,"minLength":1,"title":"Prompt","description":"Generation or edit instruction."},"response_format":{"type":"string","const":"url","title":"Response Format","description":"Image output format. Only `url` is supported. Omit this field or set it to `url`, then download the image from `data[].url`.","default":"url"},"aspect_ratio":{"anyOf":[{"$ref":"#/components/schemas/AspectRatio"},{"type":"null"}],"description":"Optional aspect ratio. Use `auto` to let the model decide; otherwise must be one of the closed enum."},"prompt_optimization":{"type":"boolean","title":"Prompt Optimization","description":"Defaults to false, disabling provider-side prompt rewriting. Set to true to request safe-prompt rewriting when the selected route supports it.","default":false},"image":{"items":{"type":"string"},"type":"array","maxItems":14,"title":"Image","description":"Reference images for img2img / multi-ref edit. Each entry is either a public `https://` URL OR a `data:image/<mime>;base64,...` URI. Empty list = pure text-to-image. `nano-banana-2-*` SKUs allow 14; `nano-banana-pro-*` SKUs allow 14; the base `nano-banana` family allows 4; `gpt-image-*` allows 10; every other image SKU allows at most 10. In the model-limit map the longest matching selector wins.","x-cheapaiapi-model-max-items":{"default":10,"gpt-image-*":10,"nano-banana":4,"nano-banana-*":4,"nano-banana-2":14,"nano-banana-2-*":14,"nano-banana-pro":14,"nano-banana-pro-*":14}},"extra":{"additionalProperties":true,"type":"object","title":"Extra","description":"Optional model- and route-specific advanced generation options. Existing keys remain accepted for compatibility; unsupported keys may be ignored. Do not rely on an option unless support has been confirmed for the selected account and SKU."},"_meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"Optional caller metadata for your own support/debugging context. Not used for model routing."},"webhook_url":{"anyOf":[{"type":"string","maxLength":2048},{"type":"null"}],"title":"Webhook Url","description":"Optional HTTPS endpoint called once the job reaches `done` or `failed`. Callbacks are signed with the account webhook secret and may be retried."},"custom_data":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Custom Data","description":"Optional JSON object echoed unchanged in generation responses, job polling, and callbacks when a callback is requested. Compact UTF-8 serialization must be at most 4096 bytes."}},"additionalProperties":false,"type":"object","required":["model","prompt"],"title":"ImageGenerationRequest","description":"``POST /v1/images/generations`` body.\n\nUse ``model`` from ``GET /v1/models`` and a required non-empty ``prompt``.\n``image`` is optional for image-to-image or multi-reference edits; omit it\nfor text-to-image.\n\nProduction clients should prefer ``?async=true``, pass ``webhook_url``,\nand store the returned job ``id``. Recover with ``GET /v1/jobs/{id}`` if\nno callback arrives. Send a stable ``Idempotency-Key`` per client-side\njob and reuse it when retrying after a timeout.","example":{"_meta":{"request_id":"catalog-shot-001"},"aspect_ratio":"1:1","custom_data":{"request_id":"catalog-shot-001"},"extra":{},"image":["https://example.com/input.png"],"model":"nano-banana-pro-2k","prompt":"Place the product on a clean studio background.","prompt_optimization":false,"response_format":"url","webhook_url":"https://example.com/webhooks/cheapaiapi"}},"ImageGenerationResponse":{"properties":{"id":{"type":"string","title":"Id"},"created":{"type":"integer","title":"Created"},"status":{"type":"string","enum":["queued","running","done","failed"],"title":"Status"},"data":{"items":{"$ref":"#/components/schemas/ImageDataItem"},"type":"array","title":"Data"},"error":{"anyOf":[{"$ref":"#/components/schemas/ErrorEnvelope"},{"type":"null"}]},"usage":{"anyOf":[{"$ref":"#/components/schemas/ResponseUsage"},{"type":"null"}]},"custom_data":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Custom Data","description":"Optional caller correlation data echoed unchanged."}},"additionalProperties":false,"type":"object","required":["id","created","status"],"title":"ImageGenerationResponse","description":"``POST /v1/images/generations`` body, both happy + ``running`` paths.\n\nOn ``status=\"done\"``: ``data`` is populated, ``error`` is null.\nOn ``status=\"running\"``: ``data=[]``; recover with ``GET /v1/jobs/{id}``\nif no webhook arrives.\nOn ``status=\"queued\"``: same as running but for ``?async=true`` returns.\nOn ``status=\"failed\"``: ``data=[]``, ``error`` populated.","examples":[{"created":1770000000,"data":[],"id":"00000000-0000-4000-8000-000000000000","status":"queued","usage":{"balance_remaining_usd":42.5,"cost_usd":0.06}},{"created":1770000000,"data":[],"id":"00000000-0000-4000-8000-000000000000","status":"running","usage":{"balance_remaining_usd":42.44,"cost_usd":0.06}},{"created":1770000000,"data":[{"url":"https://cheapaiapi.org/v1/jobs/00000000-0000-4000-8000-000000000000/results/0?sig=example"}],"id":"00000000-0000-4000-8000-000000000000","status":"done","usage":{"balance_remaining_usd":42.44,"cost_usd":0.06}}],"example":{"created":1770000000,"data":[{"url":"https://cheapaiapi.org/v1/jobs/00000000-0000-4000-8000-000000000000/results/0?sig=example"}],"id":"00000000-0000-4000-8000-000000000000","status":"done","usage":{"balance_remaining_usd":42.44,"cost_usd":0.06}}},"ImageInputCapabilities":{"properties":{"max_items":{"type":"integer","minimum":1.0,"title":"Max Items","description":"Hard maximum number of items accepted in the request `image` array."},"accepted_formats":{"items":{"type":"string","enum":["https_url","data_image_base64_uri"]},"type":"array","title":"Accepted Formats","description":"Provider-neutral forms accepted for every `image` item."}},"additionalProperties":false,"type":"object","required":["max_items","accepted_formats"],"title":"ImageInputCapabilities","description":"Reference-image inputs accepted by one image SKU."},"JobLookupResponse":{"properties":{"id":{"type":"string","title":"Id"},"created_at":{"type":"string","title":"Created At"},"status":{"type":"string","enum":["queued","running","done","failed"],"title":"Status"},"model":{"type":"string","title":"Model"},"finished_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Finished At"},"data":{"items":{"$ref":"#/components/schemas/ImageDataItem"},"type":"array","title":"Data"},"error":{"anyOf":[{"$ref":"#/components/schemas/ErrorEnvelope"},{"type":"null"}]},"usage":{"anyOf":[{"$ref":"#/components/schemas/ResponseUsage"},{"type":"null"}]},"custom_data":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Custom Data","description":"Optional caller correlation data echoed unchanged."},"response":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Response","description":"Persisted response for a completed chat job. Image jobs use data instead."}},"additionalProperties":false,"type":"object","required":["id","created_at","status","model"],"title":"JobLookupResponse","description":"``GET /v1/jobs/{id}``. Superset of ``ImageGenerationResponse`` for poll-recovery.","examples":[{"created_at":"2026-06-29T12:00:00+00:00","id":"00000000-0000-4000-8000-000000000000","model":"nano-banana-pro-2k","status":"running","usage":{"balance_remaining_usd":42.44,"cost_usd":0.06}},{"created_at":"2026-06-29T12:00:00+00:00","data":[{"url":"https://cheapaiapi.org/v1/jobs/00000000-0000-4000-8000-000000000000/results/0?sig=example"}],"finished_at":"2026-06-29T12:00:12+00:00","id":"00000000-0000-4000-8000-000000000000","model":"nano-banana-pro-2k","status":"done","usage":{"balance_remaining_usd":42.44,"cost_usd":0.06}},{"created_at":"2026-06-29T12:00:00+00:00","error":{"code":"UpstreamDown","message":"The generation could not be completed right now. Please retry the request.","type":"server_error"},"finished_at":"2026-06-29T12:00:12+00:00","id":"00000000-0000-4000-8000-000000000000","model":"nano-banana-pro-2k","status":"failed","usage":{"balance_remaining_usd":42.44,"cost_usd":0.06}}],"example":{"created_at":"2026-06-29T12:00:00+00:00","data":[{"url":"https://cheapaiapi.org/v1/jobs/00000000-0000-4000-8000-000000000000/results/0?sig=example"}],"finished_at":"2026-06-29T12:00:12+00:00","id":"00000000-0000-4000-8000-000000000000","model":"nano-banana-pro-2k","status":"done","usage":{"balance_remaining_usd":42.44,"cost_usd":0.06}}},"LegacyVideoCreateRequest":{"properties":{"model":{"type":"string","enum":["seedance-2.0","seedance-2.5","seedance-2.5-nsfw"],"title":"Model","description":"The fixed public video model SKU."},"prompt":{"type":"string","maxLength":10000,"minLength":1,"title":"Prompt","description":"Text instruction for the generated video."},"duration":{"type":"integer","maximum":15.0,"minimum":1.0,"title":"Duration","description":"Generated length in seconds. Integer from 1 to 15. Default 5.","default":5},"resolution":{"type":"string","enum":["480p","720p","1080p","4k"],"title":"Resolution","description":"Output resolution. seedance-2.0 accepts 480p, 720p, 1080p, and 4k. seedance-2.5 accepts 480p and 720p.","default":"720p"},"aspect_ratio":{"type":"string","enum":["16:9","9:16","1:1","4:3","3:4","21:9","adaptive"],"title":"Aspect Ratio","description":"Output aspect ratio. Default 16:9.","default":"16:9"},"generate_audio":{"type":"boolean","title":"Generate Audio","description":"Whether to generate audio with the clip. Default true.","default":true},"image_url":{"anyOf":[{"type":"string","minLength":1,"format":"uri"},{"type":"null"}],"title":"Image Url","description":"Optional HTTPS first-frame image. This becomes the first frame of the clip, not a style reference. Use image_url; input_image is not accepted. The URL must return image bytes directly without authentication or cookies and remain publicly downloadable until generation finishes. A browser preview or sharing-page URL is not an image URL."},"seed":{"anyOf":[{"type":"integer","maximum":4294967295.0,"minimum":-1.0},{"type":"null"}],"title":"Seed","description":"Optional deterministic seed. Use -1 or omit to let the model pick."},"last_frame_image_url":{"anyOf":[{"type":"string","minLength":1,"format":"uri"},{"type":"null"}],"title":"Last Frame Image Url","description":"Optional HTTPS last-frame image. This is the final frame of the clip, not a style reference and not the first frame. The URL must return image bytes directly without authentication or cookies and remain publicly downloadable until generation finishes."},"reference_image_urls":{"items":{"type":"string","minLength":1,"format":"uri"},"type":"array","maxItems":30,"title":"Reference Image Urls","description":"Optional HTTPS reference images (style or identity). Not a first or last frame. Entries are numbered from 1 in array order, so the prompt may refer to the first URL as `@Image1`, the second as `@Image2`, and so on. First/last-frame images are not part of this numbering. The total of first frame, last frame, and reference images may not exceed 9 for seedance-2.0 or 30 for Seedance 2.5 models. Every URL must return image bytes directly without authentication or cookies and remain publicly downloadable until generation finishes."},"reference_audio_urls":{"items":{"type":"string","minLength":1,"format":"uri"},"type":"array","maxItems":10,"title":"Reference Audio Urls","description":"Optional HTTPS audio references for Seedance 2.5 models only. At most 10 tracks with no more than 30 seconds combined. They guide the whole generation (for example rhythm or synchronization); prompt tags cannot select an individual track. Audio references do not change the generation price."}},"additionalProperties":false,"type":"object","required":["model","prompt"],"title":"LegacyVideoCreateRequest","description":"Retained flat request vocabulary for existing integrations and retries.","example":{"aspect_ratio":"16:9","duration":5,"image_url":"https://example.com/first-frame.jpg","model":"seedance-2.0","prompt":"A paper boat crossing a rainy street.","resolution":"720p"}},"ModelCapabilities":{"properties":{"image_input":{"$ref":"#/components/schemas/ImageInputCapabilities"}},"additionalProperties":false,"type":"object","required":["image_input"],"title":"ModelCapabilities","description":"Typed request capabilities attached to an authenticated model row."},"ModelInfo":{"properties":{"id":{"type":"string","title":"Id","description":"Public model SKU to pass in generation requests."},"pricing_unit":{"type":"string","enum":["per_call","per_output_second_by_resolution","per_million_tokens"],"title":"Pricing Unit","description":"How this model is billed. Other price fields are omitted."},"price_per_call_usd":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Price Per Call Usd","description":"Current per-call price as a decimal string."},"input_price_per_million_tokens_usd":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Input Price Per Million Tokens Usd","description":"Current input-token price per one million tokens."},"output_price_per_million_tokens_usd":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Output Price Per Million Tokens Usd","description":"Current output-token price per one million tokens."},"price_per_output_second_usd_by_resolution":{"anyOf":[{"additionalProperties":{"type":"string"},"propertyNames":{"enum":["480p","720p","1080p","4k"]},"type":"object"},{"type":"null"}],"title":"Price Per Output Second Usd By Resolution","description":"Current video price per output second for each supported resolution."},"currency":{"type":"string","const":"USD","title":"Currency","description":"Pricing currency.","default":"USD"},"capabilities":{"anyOf":[{"$ref":"#/components/schemas/ModelCapabilities"},{"type":"null"}],"description":"Provider-neutral request capabilities for this enabled SKU."}},"additionalProperties":false,"type":"object","required":["id","pricing_unit"],"title":"ModelInfo","description":"One public model row from ``GET /v1/models``."},"ModelListResponse":{"properties":{"data":{"items":{"$ref":"#/components/schemas/ModelInfo"},"type":"array","title":"Data","description":"Public image, video, and text generation models enabled for the account."}},"additionalProperties":false,"type":"object","required":["data"],"title":"ModelListResponse","description":"``GET /v1/models`` response.","example":{"data":[{"capabilities":{"image_input":{"accepted_formats":["https_url","data_image_base64_uri"],"max_items":14}},"currency":"USD","id":"nano-banana-pro-2k","price_per_call_usd":"0.0950","pricing_unit":"per_call"},{"currency":"USD","id":"seedance-2.0","price_per_output_second_usd_by_resolution":{"1080p":"0.8550","480p":"0.1900","4k":"1.7860","720p":"0.3420"},"pricing_unit":"per_output_second_by_resolution"},{"currency":"USD","id":"gemini-3.5-flash","input_price_per_million_tokens_usd":"1.0500","output_price_per_million_tokens_usd":"6.3000","pricing_unit":"per_million_tokens"}]}},"ResponseUsage":{"properties":{"cost_usd":{"type":"number","title":"Cost Usd","description":"Amount charged or reserved for this request."},"balance_remaining_usd":{"type":"number","title":"Balance Remaining Usd","description":"Available account balance at response time after this request is accounted for."}},"additionalProperties":false,"type":"object","required":["cost_usd","balance_remaining_usd"],"title":"ResponseUsage","description":"Customer-facing money usage for one response."},"Seedance20CreateRequest":{"properties":{"model":{"type":"string","const":"seedance-2.0","title":"Model"},"content":{"items":{"oneOf":[{"$ref":"#/components/schemas/SeedanceTextContent"},{"$ref":"#/components/schemas/SeedanceImageContent"}],"discriminator":{"propertyName":"type","mapping":{"image_url":"#/components/schemas/SeedanceImageContent","text":"#/components/schemas/SeedanceTextContent"}}},"type":"array","maxItems":10,"minItems":1,"title":"Content","description":"Exactly one non-empty text item, with optional frame images or up to nine ordered reference images. First/last-frame images cannot be combined with reference images."},"duration":{"type":"integer","maximum":15.0,"minimum":4.0,"title":"Duration","default":5},"resolution":{"type":"string","enum":["480p","720p","1080p","4k"],"title":"Resolution","default":"720p"},"ratio":{"type":"string","enum":["16:9","9:16","1:1","4:3","3:4","21:9","adaptive"],"title":"Ratio","default":"adaptive"},"generate_audio":{"type":"boolean","title":"Generate Audio","default":true}},"additionalProperties":false,"type":"object","required":["model","content"],"title":"Seedance20CreateRequest","description":"Seedance 2.0: text, frame inputs, or up to nine image references."},"Seedance25CreateRequest":{"properties":{"model":{"type":"string","enum":["seedance-2.5","seedance-2.5-nsfw"],"title":"Model"},"content":{"items":{"oneOf":[{"$ref":"#/components/schemas/SeedanceTextContent"},{"$ref":"#/components/schemas/SeedanceImageContent"},{"$ref":"#/components/schemas/SeedanceAudioContent"}],"discriminator":{"propertyName":"type","mapping":{"audio_url":"#/components/schemas/SeedanceAudioContent","image_url":"#/components/schemas/SeedanceImageContent","text":"#/components/schemas/SeedanceTextContent"}}},"type":"array","maxItems":41,"minItems":1,"title":"Content","description":"Exactly one non-empty text item, with optional frame images or up to 30 ordered reference images and 10 audio references. Audio references must total no more than 30 seconds; media duration is validated during generation. Frame inputs require ratio=adaptive and cannot be combined with reference media."},"duration":{"type":"integer","maximum":30.0,"minimum":4.0,"title":"Duration","description":"Required output length in seconds, from 4 to 30. Automatic duration (-1) is unsupported: specify a positive duration so the price can be reserved before generation."},"resolution":{"type":"string","enum":["480p","720p"],"title":"Resolution","description":"Supported output resolutions are 480p and 720p.","default":"720p"},"ratio":{"type":"string","enum":["16:9","9:16","1:1","4:3","3:4","21:9","adaptive"],"title":"Ratio","default":"adaptive"},"generate_audio":{"type":"boolean","title":"Generate Audio","default":true}},"additionalProperties":false,"type":"object","required":["model","content","duration"],"title":"Seedance25CreateRequest","description":"Seedance 2.5: frame inputs or up to 30 images and 10 audio references."},"SeedanceAudioContent":{"properties":{"type":{"type":"string","const":"audio_url","title":"Type"},"audio_url":{"$ref":"#/components/schemas/SeedanceMediaURL"},"role":{"type":"string","const":"reference_audio","title":"Role"}},"additionalProperties":false,"type":"object","required":["type","audio_url","role"],"title":"SeedanceAudioContent","description":"A whole-generation audio reference supported for Seedance 2.5."},"SeedanceImageContent":{"properties":{"type":{"type":"string","const":"image_url","title":"Type"},"image_url":{"$ref":"#/components/schemas/SeedanceMediaURL"},"role":{"type":"string","enum":["first_frame","last_frame","reference_image"],"title":"Role","description":"Image role. Omitting role selects first_frame. Frame inputs cannot be combined with reference media. Reference images retain their array order.","default":"first_frame"}},"additionalProperties":false,"type":"object","required":["type","image_url"],"title":"SeedanceImageContent","description":"An image with its official first-frame, last-frame, or reference role."},"SeedanceMediaURL":{"properties":{"url":{"type":"string","minLength":1,"format":"uri","title":"Url","description":"Direct public HTTPS media URL. It must return media bytes without authentication or cookies and remain downloadable until generation finishes. Sharing pages, base64 data, and asset identifiers are unsupported."}},"additionalProperties":false,"type":"object","required":["url"],"title":"SeedanceMediaURL","description":"A direct public HTTPS media file that remains available until completion."},"SeedanceTextContent":{"properties":{"type":{"type":"string","const":"text","title":"Type"},"text":{"type":"string","maxLength":10000,"minLength":1,"title":"Text"}},"additionalProperties":false,"type":"object","required":["type","text"],"title":"SeedanceTextContent","description":"The single required text instruction in content."},"UsageByModelItem":{"properties":{"model":{"type":"string","title":"Model","description":"Public model SKU."},"total_calls":{"type":"integer","title":"Total Calls","description":"Total jobs created in the selected time window."},"successful_calls":{"type":"integer","title":"Successful Calls","description":"Jobs that completed successfully."},"failed_calls":{"type":"integer","title":"Failed Calls","description":"Jobs that failed."},"total_spent_usd":{"type":"string","title":"Total Spent Usd","description":"Total debited amount as a decimal string."}},"additionalProperties":false,"type":"object","required":["model","total_calls","successful_calls","failed_calls","total_spent_usd"],"title":"UsageByModelItem","description":"Usage aggregates for one public model SKU."},"UsageResponse":{"properties":{"from":{"type":"string","title":"From","description":"Inclusive start of the usage window."},"to":{"type":"string","title":"To","description":"Exclusive end of the usage window."},"total_calls":{"type":"integer","title":"Total Calls","description":"Total jobs created in the selected time window."},"successful_calls":{"type":"integer","title":"Successful Calls","description":"Jobs that completed successfully."},"failed_calls":{"type":"integer","title":"Failed Calls","description":"Jobs that failed."},"total_spent_usd":{"type":"string","title":"Total Spent Usd","description":"Total debited amount as a decimal string."},"currency":{"type":"string","const":"USD","title":"Currency","description":"Usage currency.","default":"USD"},"by_model":{"items":{"$ref":"#/components/schemas/UsageByModelItem"},"type":"array","title":"By Model","description":"Usage grouped by public model SKU."}},"additionalProperties":false,"type":"object","required":["from","to","total_calls","successful_calls","failed_calls","total_spent_usd","by_model"],"title":"UsageResponse","description":"``GET /v1/usage`` response.","example":{"by_model":[{"failed_calls":2,"model":"nano-banana-pro-2k","successful_calls":40,"total_calls":42,"total_spent_usd":"1.26"}],"currency":"USD","failed_calls":2,"from":"2026-06-01T00:00:00+00:00","successful_calls":40,"to":"2026-06-29T00:00:00+00:00","total_calls":42,"total_spent_usd":"1.26"}},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"VideoCreateRequest":{"oneOf":[{"$ref":"#/components/schemas/Seedance20CreateRequest"},{"$ref":"#/components/schemas/Seedance25CreateRequest"}],"title":"VideoCreateRequest","description":"Create a video using the supported official Seedance content contract.","discriminator":{"propertyName":"model","mapping":{"seedance-2.0":"#/components/schemas/Seedance20CreateRequest","seedance-2.5":"#/components/schemas/Seedance25CreateRequest","seedance-2.5-nsfw":"#/components/schemas/Seedance25CreateRequest"}}},"VideoResource":{"properties":{"id":{"type":"string","title":"Id"},"object":{"type":"string","const":"video","title":"Object","default":"video"},"created_at":{"type":"integer","title":"Created At","description":"Unix timestamp in UTC."},"status":{"type":"string","enum":["queued","in_progress","completed","failed"],"title":"Status"},"model":{"type":"string","enum":["seedance-2.0","seedance-2.5","seedance-2.5-nsfw"],"title":"Model"},"completed_at":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Completed At","description":"Unix timestamp in UTC, present only after terminal completion."},"error":{"anyOf":[{"$ref":"#/components/schemas/ErrorEnvelope"},{"type":"null"}]}},"additionalProperties":false,"type":"object","required":["id","created_at","status","model"],"title":"VideoResource","description":"Recoverable state returned by both create and poll endpoints."}},"securitySchemes":{"HTTPBearer":{"type":"http","description":"Paste your `sk_cheap_...` API key. Need access? Request a quote at https://cheapaiapi.org/contact.","scheme":"bearer","bearerFormat":"API key (sk_cheap_...)"}}},"tags":[{"name":"Chat","description":"Create non-streaming or SSE-streaming text completions."},{"name":"Images","description":"Create image generation jobs and retrieve completed image data."},{"name":"Videos","description":"Create video jobs, poll their status, and stream completed media."},{"name":"Jobs","description":"Poll durable image generation jobs after async submission or disconnects."},{"name":"Models","description":"List public model SKUs and account-specific pricing units and rates."},{"name":"Account","description":"Inspect balance and usage for the authenticated account."}]}