> ## Documentation Index
> Fetch the complete documentation index at: https://docs.viggle.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Generate Image

> Generate 1–6 PNG images from a text prompt, optionally guided by up to 8 reference images.

Send `multipart/form-data` with a `prompt` and, optionally, reference images. The request is asynchronous: it answers immediately with a `queued` [Image](/v1/api-reference/images/get) object whose ID starts with `img_`, and you poll [Get Image](/v1/api-reference/images/get) until `status` is `ready` or `failed`. Without reference images this is text-to-image; with at least one, the model is guided by them.

<Note>
  **Pricing** (1 credit = $0.01): **1 credit ($0.01) per image\*\* at `1K`, **2 credits (\$0.02) per image** at `2K`. A job costs `n` × the per-image price — for example, `2K` with `n=3` is 6 credits. The whole amount is reserved when the job is created and refunded in full if it fails. `aspect_ratio`, `seed`, and reference images don't affect price. See [Pricing and retention](/v1/pricing#viggle-image).
</Note>

## Request parameters

Send `multipart/form-data`.

| Parameter | Type | Required | Default | Description |
| - | - | :-: | - | - |
| `prompt` | string | Yes | — | Text description of the images. Up to 4000 characters, counted as Unicode code points (one CJK character counts as one). Must not be blank. |
| `model` | string | No | `qwen` | Image model. Only `qwen` is available. |
| `aspect_ratio` | string | No | `1:1` | `1:1`, `16:9`, `9:16`, `4:3`, `3:4`, `3:2`, or `2:3`. Together with `resolution`, selects the exact output size — see [Output sizes](#output-sizes). |
| `resolution` | string | No | `1K` | `1K` or `2K`, case-insensitive. Sets the output size tier and the per-image price: 1 credit at `1K`, 2 credits at `2K`. |
| `n` | integer | No | `1` | Number of images to generate, 1–6. |
| `seed` | integer | No | random | 0–2147483647. Image `i` (counting from 0) uses `(seed + i) mod 2147483648`. Omitted, the server picks a random seed. Every image reports the seed it actually used. |
| `reference_image` | file, repeatable | No | — | Reference image upload, up to 24 MiB each. Repeat the field to send more than one. |
| `reference_image_url` | string, repeatable | No | — | Publicly reachable `http(s)` image URL, under the same limits as `reference_image`. Repeat the field to send more than one. |

Up to **8 reference images** in total, as any mix of `reference_image` and `reference_image_url`. The model receives the uploaded files first, then the URLs, each in the order you sent them. Supplying any reference image moves `2K` to a smaller size — see the next section.

### Reference image limits

* Up to 24 MiB each, with a long-to-short side ratio of at most 8.
* JPEG, PNG, WebP, GIF, BMP, TIFF, or HEIC.
* An image with a long side of 3840 px or more, or a short side of 2160 px or more, is first downscaled, keeping its aspect ratio, to fit within 1920 × 1080 (1080 × 1920 for a portrait image).
* A `reference_image_url` must be publicly reachable; it is downloaded while the create request is being processed.

## Output sizes

`aspect_ratio` and `resolution` together select one of the model's fixed sizes — you get exactly the size listed. Width × height, in pixels:

| `aspect_ratio` | `1K` | `2K` (text only) | `2K` (with reference images) |
| - | - | - | - |
| `1:1` | 1024 × 1024 | 2048 × 2048 | 1536 × 1536 |
| `16:9` | 1376 × 768 | 2720 × 1536 | 2048 × 1152 |
| `9:16` | 768 × 1376 | 1536 × 2720 | 1152 × 2048 |
| `4:3` | 1184 × 896 | 2368 × 1760 | 1760 × 1344 |
| `3:4` | 896 × 1184 | 1760 × 2368 | 1344 × 1760 |
| `3:2` | 1248 × 832 | 2496 × 1664 | 1888 × 1248 |
| `2:3` | 832 × 1248 | 1664 × 2496 | 1248 × 1888 |

`1K` is the same with or without reference images. `2K` is about 2048² pixels of area for text-to-image and about 1536² with reference images; the price is the same either way. Each image's `width` and `height` in the response are its actual size.

## Response parameters

Returns `200 OK` with an Image object in `queued` state — the same shape [Get Image](/v1/api-reference/images/get) returns. `progress` is `0`, `images` is empty, and `completed_at` and `error` are `null`.

```json theme={null}
{
  "id": "img_b16a190d-2d44-41a0-8056-ef68183c3b9e",
  "status": "queued",
  "model": "qwen",
  "progress": 0,
  "images": [],
  "created_at": "2026-10-12T08:20:00Z",
  "completed_at": null,
  "error": null
}
```

## Common errors

| Error | Cause |
| - | - |
| `400 INVALID_REQUEST` | A parameter is invalid — `message` names which one — or the body isn't `multipart/form-data`. No job is created and no file is uploaded. |
| `401 UNAUTHENTICATED` | Missing or invalid API key. |
| `402 INSUFFICIENT_CREDITS` | The balance can't cover `n` × the per-image price; `message` gives the credits required. No generation starts. |
| `429 RATE_LIMITED` | Too many concurrent create requests on the same key. Retry later. |
| `500 INTERNAL_ERROR` | Internal server error. Retryable. |
| `503 SERVICE_BUSY` | Service temporarily unavailable. Retryable. |

HTTP errors use the standard envelope — `{"error": {"code", "message", "retryable", "request_id", "details", "remediation"}}`. See [Errors and recovery](/v1/production/errors). A job that is accepted and later fails reports its failure in the Image object's `error` field instead — see [Get Image](/v1/api-reference/images/get#status-and-errors).

<Note>
  Send your own `User-Agent` header. Python `urllib`'s default `User-Agent` has been observed to be blocked in front of `apis.viggle.ai`, which answers with a non-JSON error page instead of an API error.

  The body must be `multipart/form-data`, even without reference images — an `application/x-www-form-urlencoded` body gets `400`. With Python `requests`, pass the fields through `files=` (as below), not `data=` alone.
</Note>

## Examples

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://apis.viggle.ai/v1/images \
    -H "Authorization: Bearer $VIGGLE_API_KEY" \
    -F prompt="A watercolor fox reading a book under a maple tree" \
    -F aspect_ratio=16:9 \
    -F resolution=1K \
    -F n=2
  ```

  ```python Python theme={null}
  import os, requests
  fields = {"prompt": "A watercolor fox reading a book under a maple tree", "aspect_ratio": "16:9", "resolution": "1K", "n": "2"}
  response = requests.post(
      "https://apis.viggle.ai/v1/images",
      headers={"Authorization": f"Bearer {os.environ['VIGGLE_API_KEY']}"},
      files={name: (None, value) for name, value in fields.items()},  # forces multipart/form-data
  )
  response.raise_for_status()
  image = response.json()
  ```

  ```javascript JavaScript theme={null}
  const form = new FormData();
  form.append("prompt", "A watercolor fox reading a book under a maple tree");
  form.append("aspect_ratio", "16:9");
  form.append("resolution", "1K");
  form.append("n", "2");
  const response = await fetch("https://apis.viggle.ai/v1/images", {
    method: "POST",
    headers: { Authorization: `Bearer ${process.env.VIGGLE_API_KEY}` },
    body: form,
  });
  const image = await response.json();
  ```

  ```go Go theme={null}
  body := &bytes.Buffer{}; w := multipart.NewWriter(body)
  w.WriteField("prompt", "A watercolor fox reading a book under a maple tree"); w.WriteField("aspect_ratio", "16:9"); w.WriteField("resolution", "1K"); w.WriteField("n", "2"); w.Close()
  req, _ := http.NewRequest("POST", "https://apis.viggle.ai/v1/images", body)
  req.Header.Set("Authorization", "Bearer "+os.Getenv("VIGGLE_API_KEY")); req.Header.Set("Content-Type", w.FormDataContentType())
  resp, err := http.DefaultClient.Do(req); if err != nil { panic(err) }; defer resp.Body.Close()
  ```
</CodeGroup>

### With reference images

Uploads and URLs can be mixed, and both fields can be repeated:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://apis.viggle.ai/v1/images \
    -H "Authorization: Bearer $VIGGLE_API_KEY" \
    -F prompt="The same fox, now in winter, snow falling" \
    -F aspect_ratio=1:1 \
    -F resolution=2K \
    -F reference_image=@fox.png \
    -F reference_image_url=https://example.com/style.jpg
  ```

  ```python Python theme={null}
  import os, requests
  with open("fox.png", "rb") as fox:
      response = requests.post(
          "https://apis.viggle.ai/v1/images",
          headers={"Authorization": f"Bearer {os.environ['VIGGLE_API_KEY']}"},
          data={
              "prompt": "The same fox, now in winter, snow falling",
              "aspect_ratio": "1:1",
              "resolution": "2K",
              "reference_image_url": ["https://example.com/style.jpg"],
          },
          files=[("reference_image", ("fox.png", fox, "image/png"))],
      )
  response.raise_for_status()
  image = response.json()
  ```

  ```javascript JavaScript theme={null}
  import { openAsBlob } from "node:fs";

  const form = new FormData();
  form.append("prompt", "The same fox, now in winter, snow falling");
  form.append("aspect_ratio", "1:1");
  form.append("resolution", "2K");
  form.append("reference_image", await openAsBlob("fox.png"), "fox.png");
  form.append("reference_image_url", "https://example.com/style.jpg");
  const response = await fetch("https://apis.viggle.ai/v1/images", {
    method: "POST",
    headers: { Authorization: `Bearer ${process.env.VIGGLE_API_KEY}` },
    body: form,
  });
  const image = await response.json();
  ```
</CodeGroup>

### `@viggle/sdk`

Requires an `@viggle/sdk` version that includes the `images` resource.

```javascript theme={null}
import { Viggle } from "@viggle/sdk";

const viggle = new Viggle({ apiKey: process.env.VIGGLE_API_KEY! });
const image = await viggle.images.create({
  prompt: "A watercolor fox reading a book under a maple tree",
  aspectRatio: "16:9",
  resolution: "1K",
  n: 2,
});
// image.id, image.status ("queued"); poll with viggle.images.get(image.id)
```

## Next step

Use [Get Image](/v1/api-reference/images/get) with the returned `id` to poll for the result.

<CardGroup cols={2}>
  <Card title="Quick Start: Viggle Image" icon="rocket" href="/v1/guides/quickstart-image">
    Follow the complete create, poll, and download flow.
  </Card>

  <Card title="Get Image" icon="image" href="/v1/api-reference/images/get">
    Read the job's status, image URLs, sizes, and seeds.
  </Card>
</CardGroup>


## OpenAPI

````yaml openapi.yaml POST /v1/images
openapi: 3.0.3
info:
  title: Viggle API
  description: Generate AI-powered character animation videos
  version: 2.0.0
  contact:
    name: Viggle Support
    url: https://viggle.ai
servers:
  - url: https://apis.viggle.ai
    description: Production server
security:
  - bearerAuth: []
tags:
  - name: Renders
    description: Prepare inputs, create renders, observe progress, and retrieve results.
  - name: Credits
    description: Read the credit balance available to the calling principal.
  - name: Characters
    description: |
      Create, list, inspect, and delete reusable character assets. `type`
      selects whether creation also extracts a 3D vsplat; export its
      download URL separately once ready.
  - name: Motions
    description: |
      Create, list, inspect, and delete reusable motion assets, and import one
      from an official motion template. `type` selects whether creation also
      extracts or generates a 3D animation; export its download URL
      separately once ready.
  - name: Videos
    description: >
      Generate a MiniMax H3 video from text, frames, or references (`vid_`

      prefix) or a character-animation video from a character image and/or
      driving video

      (`anim_` prefix), and read the unified view over every video the

      caller owns — H3 generations, character-animation generations, and

      character+motion Renders (`render_` prefix) — merged into one

      resource.
  - name: Images
    description: |
      Viggle Image — generate 1–6 PNG images from a text prompt with the
      `qwen` model, optionally guided by up to 8 reference images
      (`img_` prefix), and retrieve them by ID.
paths:
  /v1/images:
    post:
      tags:
        - Images
      summary: Generate images
      description: |
        Starts an asynchronous generation of `n` PNG images (1–6) from
        `prompt` with the `qwen` model, optionally guided by up to 8
        reference images. `aspect_ratio` and `resolution` select the output
        size (see `CreateImageForm`). Answers `200` with the queued `Image`;
        poll `GET /v1/images/{image_id}` until it is `ready` or `failed`.

        Each image costs 1 credit at `1K` and 2 credits at `2K`. The whole
        job (`n` × the per-image price) is reserved when it is created —
        `402` when the balance cannot cover it — and refunded in full if
        the job fails. A `400` creates no job and uploads no file.
      operationId: createImage
      parameters:
        - $ref: '#/components/parameters/RequestId'
        - $ref: '#/components/parameters/SourceChannel'
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/CreateImageForm'
      responses:
        '200':
          description: Image generation accepted and queued.
          headers:
            X-Request-Id:
              $ref: '#/components/headers/RequestId'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Image'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/V1Unauthorized'
        '402':
          $ref: '#/components/responses/PaymentRequired'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
components:
  parameters:
    RequestId:
      name: X-Request-Id
      in: header
      required: false
      description: >-
        Optional caller-supplied correlation ID, up to 128 characters. The
        service returns the effective value in the response header for tracing
        and support.
      schema:
        type: string
        minLength: 1
        maxLength: 128
    SourceChannel:
      name: X-Viggle-Source
      in: header
      required: false
      description: >-
        Optional source-channel label, up to 128 characters, used to attribute
        traffic to an SDK, integration, product surface, or internal workflow.
      schema:
        type: string
        minLength: 1
        maxLength: 128
  schemas:
    CreateImageForm:
      description: |
        Body of `POST /v1/images`, `multipart/form-data` only. Text-to-image
        when no reference image is supplied, reference-guided generation when
        at least one is. `aspect_ratio` and `resolution` select one of the
        model's fixed output sizes (width × height, in pixels); with
        reference images, `2K` is a smaller size than without:

        | aspect_ratio | 1K | 2K | 2K with reference images |
        | --- | --- | --- | --- |
        | 1:1 | 1024×1024 | 2048×2048 | 1536×1536 |
        | 16:9 | 1376×768 | 2720×1536 | 2048×1152 |
        | 9:16 | 768×1376 | 1536×2720 | 1152×2048 |
        | 4:3 | 1184×896 | 2368×1760 | 1760×1344 |
        | 3:4 | 896×1184 | 1760×2368 | 1344×1760 |
        | 3:2 | 1248×832 | 2496×1664 | 1888×1248 |
        | 2:3 | 832×1248 | 1664×2496 | 1248×1888 |

        Up to 8 reference images in total, as any mix of `reference_image`
        uploads and `reference_image_url` URLs. The model receives the
        uploads first, then the URLs, each in the order sent.
      type: object
      required:
        - prompt
      properties:
        prompt:
          type: string
          minLength: 1
          maxLength: 4000
          description: >-
            Text description of the images. Up to 4000 characters, counted as
            Unicode code points (one CJK character counts as one). Must not be
            blank.
        model:
          type: string
          enum:
            - qwen
          default: qwen
          description: Image model. Only `qwen` is available.
        aspect_ratio:
          type: string
          enum:
            - '1:1'
            - '16:9'
            - '9:16'
            - '4:3'
            - '3:4'
            - '3:2'
            - '2:3'
          default: '1:1'
          description: >-
            Output aspect ratio. Together with `resolution`, it selects the
            exact output size.
        resolution:
          type: string
          enum:
            - 1K
            - 2K
          default: 1K
          description: >-
            Output size tier, case-insensitive, and the price of each image — 1
            credit at `1K`, 2 credits at `2K`. With any reference image, `2K` is
            about 1536² pixels instead of about 2048².
        'n':
          type: integer
          minimum: 1
          maximum: 6
          default: 1
          description: >-
            Number of images to generate. The job reserves `n` × the per-image
            price.
        seed:
          type: integer
          format: int64
          minimum: 0
          maximum: 2147483647
          description: |
            Image `i` (counting from 0) is generated with seed
            `(seed + i) mod 2147483648`. Omitted, the server picks a random
            seed; each image reports the seed it used.
        reference_image:
          type: array
          maxItems: 8
          items:
            type: string
            format: binary
          description: >-
            Reference image upload; repeat the field for more than one. Each up
            to 24 MiB, with a long-to-short side ratio of at most 8; JPEG, PNG,
            WebP, GIF, BMP, TIFF, or HEIC. Counts toward the 8-image total
            shared with `reference_image_url`.
        reference_image_url:
          type: array
          maxItems: 8
          items:
            type: string
            format: uri
          description: >-
            Publicly reachable http(s) reference image URL, downloaded while the
            create request is processed; repeat the field for more than one.
            Same limits as `reference_image`, and counts toward the same 8-image
            total.
    Image:
      description: |
        An image generation job (`img_` prefix), returned by both
        `POST /v1/images` and `GET /v1/images/{image_id}`. It only moves
        forward — `queued` → `processing` → `ready` or `failed` — and is
        never `cancelled`. `images` stays empty until the job is `ready`,
        then lists every generated image in request order. A job either
        produces all `n` images or fails; it never returns a partial set.
      type: object
      additionalProperties: false
      required:
        - id
        - status
        - model
        - progress
        - images
        - created_at
        - completed_at
        - error
      properties:
        id:
          type: string
          minLength: 1
          description: Public image job ID, `img_` prefix.
        status:
          type: string
          enum:
            - queued
            - processing
            - ready
            - failed
          description: Lifecycle state. `ready` and `failed` are terminal.
        model:
          type: string
          description: Model used for generation; currently always `qwen`.
        progress:
          type: integer
          nullable: true
          minimum: 0
          maximum: 100
          description: >-
            Share of the requested images generated so far — `0` while queued,
            0–99 while processing, `100` when ready, null when failed.
        images:
          type: array
          description: Empty until `ready`, then all `n` generated images in request order.
          items:
            $ref: '#/components/schemas/GeneratedImage'
        created_at:
          type: string
          format: date-time
          nullable: true
          description: Creation timestamp, RFC 3339.
        completed_at:
          type: string
          format: date-time
          nullable: true
          description: >-
            Terminal-state timestamp; set once the job is `ready` or `failed`,
            null before that.
        error:
          type: object
          nullable: true
          description: |
            Failure details, only when `status` is `failed`; otherwise null.
            `code` is `SERVICE_BUSY` (retryable — the generation service is
            busy or unavailable, or the job did not finish within 15
            minutes), `TASK_FAILED` (retryable — any other generation or
            upload failure), or `INVALID_REQUEST` (not retryable — the model
            rejected the request, for example an unusable reference image).
          allOf:
            - $ref: '#/components/schemas/ErrorBody'
    GeneratedImage:
      type: object
      additionalProperties: false
      required:
        - url
        - width
        - height
        - seed
      properties:
        url:
          type: string
          format: uri
          nullable: true
          description: >-
            Signed download URL of the PNG, valid for 1 hour; fetch the job
            again for a fresh one. Null once the file has been deleted, 24 hours
            after the job finished.
        width:
          type: integer
          minimum: 1
          description: Actual width in pixels.
        height:
          type: integer
          minimum: 1
          description: Actual height in pixels.
        seed:
          type: integer
          format: int64
          minimum: 0
          description: Seed actually used for this image.
    ErrorBody:
      type: object
      additionalProperties: false
      required:
        - code
        - message
        - retryable
        - request_id
        - details
        - remediation
      properties:
        code:
          description: Stable error category from the draft-based render error vocabulary.
          allOf:
            - $ref: '#/components/schemas/ErrorCode'
        message:
          type: string
          description: >-
            Human-readable explanation suitable for logs or presentation to a
            developer.
        retryable:
          type: boolean
          description: >-
            Whether retrying the operation without changing its semantic input
            may succeed.
        request_id:
          type: string
          description: >-
            Correlation identifier for tracing and support. Include it when
            reporting the failure.
        details:
          type: object
          description: Error-specific structured context; available keys depend on `code`.
          additionalProperties: true
        remediation:
          description: Suggested recovery action and optional retry delay.
          allOf:
            - $ref: '#/components/schemas/ErrorRemediation'
    ErrorResponse:
      type: object
      additionalProperties: false
      required:
        - error
      properties:
        error:
          description: >-
            Top-level draft-flow error payload containing the stable code,
            message, retry guidance, correlation ID, and error-specific details.
          allOf:
            - $ref: '#/components/schemas/ErrorBody'
    ErrorCode:
      description: |
        The failure vocabulary of the draft-based render flow. The resource
        operations project the same vocabulary onto the lower_snake_case codes
        described by `ResourceError`.
      type: string
      enum:
        - UNAUTHENTICATED
        - INVALID_CREDENTIAL
        - FORBIDDEN
        - INVALID_REQUEST
        - INVALID_CHARACTER
        - INVALID_MOTION
        - UNSUPPORTED_MEDIA
        - CONTENT_POLICY_VIOLATION
        - UPLOAD_REQUIRED
        - UPLOAD_MISMATCH
        - UPLOAD_EXPIRED
        - DRAFT_NOT_FOUND
        - DRAFT_ALREADY_CONSUMED
        - RENDER_NOT_FOUND
        - RENDER_NOT_CANCELLABLE
        - CHARACTER_NOT_FOUND
        - MOTION_NOT_FOUND
        - MOTION_NOT_READY
        - MOTION_TEMPLATE_NOT_FOUND
        - AVATAR_NOT_FOUND
        - ANIMATION_NOT_FOUND
        - EXTRACTION_UNAVAILABLE
        - EXTRACTION_FAILED
        - IDEMPOTENCY_KEY_REUSED
        - INSUFFICIENT_CREDITS
        - RATE_LIMITED
        - SERVICE_BUSY
        - INTERNAL_ERROR
        - NOT_FOUND
        - TASK_FAILED
    ErrorRemediation:
      type: object
      additionalProperties: false
      required:
        - action
        - retry_after_ms
      properties:
        action:
          type: string
          description: >-
            Suggested machine-readable or human-readable next action, such as
            retrying later, uploading media again, or correcting input.
        retry_after_ms:
          type: integer
          description: >-
            Recommended delay in milliseconds before retrying; null when no
            timed retry is advised.
          nullable: true
          format: int64
          minimum: 0
  headers:
    RequestId:
      description: Stable request identifier for support and tracing.
      schema:
        type: string
  responses:
    BadRequest:
      description: Invalid request.
      headers:
        X-Request-Id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    V1Unauthorized:
      description: Missing, invalid, or expired credential.
      headers:
        WWW-Authenticate:
          schema:
            type: string
        X-Request-Id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    PaymentRequired:
      description: Insufficient credits.
      headers:
        X-Request-Id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Forbidden:
      description: Credential does not grant access to this resource.
      headers:
        X-Request-Id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    RateLimited:
      description: Rate limit exceeded.
      headers:
        Retry-After:
          schema:
            type: integer
            minimum: 0
        X-Request-Id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    InternalServerError:
      description: Unexpected server error.
      headers:
        X-Request-Id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    ServiceUnavailable:
      description: Service temporarily unavailable.
      headers:
        Retry-After:
          schema:
            type: integer
            minimum: 0
        X-Request-Id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: API key or OAuth access token
      description: |
        Server-side SDK clients use a project API key. Remote MCP clients use
        an OAuth access token. Never expose a project API key in browser code.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.