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

# Outfit / Fashion

> UGC Studio: the avatar wears your outfits, one look per clip

## Overview

The avatar wears your outfits, one look per clip. Send up to four outfit photos as `outfitImageKeys` (each one is dressed on the avatar and filmed), or your own outfit videos as `media`, which then replace them; photos in `media` alone answer `400`. Wrap the words for each look in `[look 1] … [/look]`, `[look 2] … [/look]` and so on. The outfit and the avatar share the frame as `adSettings` says.

This is one of the five [UGC Studio](/api-reference/ugc-studio/product-in-hand) formats; each one has its own endpoint and reads only its own fields. The avatar's voice, lip movement and gestures are generated with the picture.

***

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST "https://api.hooked.so/v1/project/create/ugc-studio/fashion" \
    -H "x-api-key: your_api_key_here" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Spring drop",
      "script": "Three looks for spring. [look 1]This linen set is my favourite.[/look] [look 2]And this one for the weekend.[/look]",
      "avatarId": "2",
      "outfitImageKeys": [
        "https://example.com/images/linen-set.png",
        "https://example.com/images/weekend.png"
      ],
      "language": "en",
      "webhook": "https://example.com/hooks/hooked?token=YOUR_SECRET"
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch("https://api.hooked.so/v1/project/create/ugc-studio/fashion", {
    method: "POST",
    headers: {
      "x-api-key": "your_api_key_here",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
        script: "Two outfits, one jacket. Here is how I style it.",
        avatarId: "2",
        outfitImageKeys: [
          "https://example.com/images/jacket-casual.png",
          "https://example.com/images/jacket-office.png"
        ],
        adSettings: {
          bRollType: "rounded-left"
        },
        webhook: "https://example.com/hooks/hooked?token=YOUR_SECRET"
      }),
  });

  const { data } = await response.json();
  console.log(data.projectId, data.status);
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      "https://api.hooked.so/v1/project/create/ugc-studio/fashion",
      headers={"x-api-key": "your_api_key_here"},
      json={
          "script": "My new favourite dress, styled two ways.",
          "avatarId": "2",
          "media": [
              "cm8w1r7d20002l708x9y8z7w7"
          ],
          "webhook": "https://example.com/hooks/hooked?token=YOUR_SECRET"
      },
  )
  data = response.json()["data"]
  print(data["projectId"], data["status"])
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "success": true,
    "data": {
      "projectId": "cm8x4f2qk0007l708a1b2c3d4",
      "status": "processing"
    },
    "message": "UGC ad successfully created"
  }
  ```

  ```json 400 theme={null}
  {
    "success": false,
    "message": "outfitImageKeys: Upload outfit photos (or your own outfit videos) for the fashion format"
  }
  ```

  ```json 401 theme={null}
  {
    "code": "not_authenticated",
    "message": "Not authenticated",
    "errorCode": "NOT_AUTHENTICATED",
    "details": { "x-api-key": "Header not provided or API Key invalid" }
  }
  ```

  ```json 402 missing keys theme={null}
  {
    "success": false,
    "code": "missing_credentials",
    "errorCode": "MISSING_CREDENTIALS",
    "missingProviders": [["bria"]],
    "message": "Your team uses its own provider keys (BYOK) and these are missing or invalid: Bria. Add them in Settings → AI keys."
  }
  ```

  ```json 402 subscription theme={null}
  {
    "success": false,
    "code": "subscription_required",
    "errorCode": "SUBSCRIPTION_REQUIRED",
    "message": "Your team generates with Hooked's keys, which are paid by your plan. Subscribe to keep generating."
  }
  ```

  ```json 402 credits theme={null}
  {
    "success": false,
    "errorCode": "INSUFFICIENT_CREDITS",
    "message": "Not enough credits for UGC ad creation. Estimated: 107, Available: 40",
    "creditsNeeded": 107,
    "creditsAvailable": 40
  }
  ```

  ```json 403 theme={null}
  {
    "code": "entitlement_required",
    "error": "entitlement_required",
    "message": "This endpoint requires the \"app\" product.",
    "product": "app"
  }
  ```
</ResponseExample>

***

## Errors

| Status | Body | When |
| - | - | - |
| 400 | `{ success: false, message }` | `Invalid JSON body`; `Subscription not found` (no plan record: contact support); a field fails validation (`script: Script must be at least 1 character`); no `outfitImageKeys` and no outfit video in `media` (`outfitImageKeys: Upload outfit photos (or your own outfit videos) for the fashion format`); a `media` ID not in your library; an unknown `avatarId` or `musicId`; an image key of another team; an invalid caption preset; `webhook: Must be a valid HTTPS URL` |
| 401 | `not_authenticated` | Missing or invalid `x-api-key` |
| 402 | `missing_credentials` | Your team uses its own keys (BYOK) and a key this request needs is missing. Nothing is created |
| 402 | `subscription_required` | Your team uses Hooked's keys and has no active subscription |
| 402 | `INSUFFICIENT_CREDITS` | The estimate is higher than your balance |
| 403 | `entitlement_required` | Your team does not have the product this endpoint belongs to |
| 500 | `{ success: false, message }` | `Internal server error` or `Failed to create UGC ad`. Credits charged are refunded |

<Warning>
  Send an [`Idempotency-Key`](/guides/idempotency) header to retry safely: if a request times out or answers 5xx, sending it again with the same key and body returns the first answer instead of creating (and charging) the project twice.
</Warning>

***

## Credits and your own keys

* **Teams on Hooked's keys (managed):** 7 credits plus 100 credits per started 15 seconds of script (estimated at about 2.5 words per second), plus the dressed image and the outfit video of each look made from a photo. Charged up front when the project is created; refunded if it fails.
* **Teams on their own keys (BYOK):** no credits are charged. The team needs OpenRouter, Google AI (Gemini) and Bria (Bria not when `adSettings.removeAvatarBackground` is `false` or `adSettings.avatarPresentation` is `cover`) in **Settings → AI keys**; without them the request answers `402 missing_credentials` and nothing is created.

***

## What happens next

The clips are generated, assembled and rendered automatically.

* Poll [Get Project](/api-reference/project/details) with the `projectId` until `data.video` is present and `data.video.status` is `COMPLETED`, then download `data.video.url`. The project's own `status` turns `completed` when the clips are assembled, a little before the render finishes; `failed` (or a `FAILED` video) means it will not finish.
* Or pass a `webhook` and get the result when the render finishes. See [Webhooks](/guides/webhooks).

## Related

<CardGroup cols={2}>
  <Card title="List Avatars" icon="users" href="/api-reference/avatar/list">
    Pick the presenter
  </Card>

  <Card title="Get Project" icon="info" href="/api-reference/project/details">
    Status of the project
  </Card>

  <Card title="Webhooks" icon="webhook" href="/guides/webhooks">
    Payloads and delivery
  </Card>
</CardGroup>


## OpenAPI

````yaml POST /v1/project/create/ugc-studio/fashion
openapi: 3.0.0
info:
  title: Hooked API
  version: 1.0.0
  description: AI Video Generation API
servers:
  - url: https://api.hooked.so
security:
  - ApiKeyAuth: []
tags:
  - name: Videos
    description: Create projects, follow them and render videos
  - name: Account Analysis
    description: Analyze TikTok and YouTube accounts
  - name: Channels
    description: Connected social accounts you publish to
  - name: Publish
    description: Schedule videos to your connected accounts
  - name: Images
    description: 'Image editing: background removal and expansion'
  - name: Media
    description: 'Your media library: list, import from a URL, upload a file'
  - name: Avatars
    description: Your team's own avatars (Actors) and their Hook + Demo reactions
paths:
  /v1/project/create/ugc-studio/fashion:
    post:
      tags:
        - Videos
      summary: 'UGC Studio: Outfit / Fashion'
      description: >-
        The avatar wears your outfits, one look per clip, from your reference
        photos (or your own outfit videos). Needs `outfitImageKeys` or outfit
        videos in `media`. BYOK: needs OpenRouter, Gemini and Bria (Bria not
        with `adSettings.removeAvatarBackground: false` or
        `adSettings.avatarPresentation: cover`).


        Create endpoints are not idempotent: do not retry a POST on a timeout or
        5xx without first checking your projects, or you may create (and pay
        for) the video twice.
      operationId: createUgcStudioFashion
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - script
                - avatarId
              properties:
                script:
                  type: string
                  minLength: 1
                  maxLength: 10000
                  description: >-
                    What the avatar says. Wrap the words for each look in `[look
                    1] … [/look]`, `[look 2] … [/look]` and so on. Marks are
                    never spoken; unmarked, the director decides.
                avatarId:
                  type: string
                  maxLength: 30
                  description: >-
                    Avatar ID from /v1/avatar/list (the library's or your team's
                    own). An unknown ID answers 400.
                name:
                  type: string
                  maxLength: 100
                  description: >-
                    Project name (max 100 characters). Generated from the script
                    when omitted. Outside the voiceover format it may be
                    replaced by the on-screen hook the director writes once the
                    clips are planned.
                outfitImageKeys:
                  type: array
                  maxItems: 4
                  items:
                    type: string
                    maxLength: 1000
                  description: >-
                    Up to 4 outfit photos, each a public `https` image URL or
                    the storage key of an image in your team's library (a key of
                    another team answers 400). Each one is dressed on the avatar
                    and filmed (priced per look). Needed unless you send outfit
                    videos in `media`, which then replace them.
                media:
                  type: array
                  maxItems: 50
                  items:
                    type: string
                    description: Media ID from your library
                  description: >-
                    Your own outfit VIDEOS: media IDs from your team's library
                    (max 50). Photos here are not read: send them as
                    `outfitImageKeys` (photos in `media` alone answer 400). A
                    media that is not `COMPLETED` yet (an import or upload in
                    progress) answers `400 media: Media "<id>" is not ready
                    (status PROCESSING)`.
                adSettings:
                  type: object
                  description: >-
                    How the content and the avatar share the frame. Also
                    accepted as `projectSettings.ad`.
                  properties:
                    bRollType:
                      type: string
                      enum:
                        - down
                        - up
                        - left
                        - right
                        - rounded-left
                        - rounded-right
                        - circle-left
                        - circle-right
                        - full-width
                      description: >-
                        Where the content and the avatar sit. up / down: split
                        screen, content on the top / bottom half. left / right:
                        split screen, content on that half. rounded-left /
                        rounded-right: content full frame, avatar in a rounded
                        card on that side. circle-left / circle-right: the same
                        in a circle. full-width: the content covers the whole
                        frame. Default: rounded-right.
                    removeAvatarBackground:
                      type: boolean
                      description: >-
                        Cut the avatar out of its background in the
                        picture-in-picture card (not with `avatarPresentation`
                        `cover`). BYOK: needs the Bria key.
                      default: true
                    avatarPresentation:
                      type: string
                      enum:
                        - pip
                        - cover
                      default: pip
                      description: >-
                        `pip` keeps the avatar on screen while the content
                        shows; `cover` lets the content cover it (only its voice
                        is heard).
                videoStyle:
                  type: object
                  description: >-
                    How the avatar is filmed and how it speaks. Every field is
                    optional.
                  properties:
                    cameras:
                      type: array
                      minItems: 1
                      items:
                        type: string
                        enum:
                          - most-used-still-camera-gestures
                          - static-shot
                          - slow-zoom-to-the-face
                          - fast-zoom-as-they-speak
                          - subtle-handheld
                          - subtle-push-in-podcast
                          - depth-of-field-bokeh
                      description: >-
                        Camera moves this video may use, at least one; the
                        director picks one per clip. Only the steady moves are
                        offered, so what the avatar holds or shows stays framed.
                        Default: `most-used-still-camera-gestures`,
                        `subtle-handheld`, `subtle-push-in-podcast`,
                        `slow-zoom-to-the-face`.
                    naturalGestures:
                      type: boolean
                      default: true
                      description: >-
                        Let the avatar move its hands and head while talking.
                        `false` turns off `gestures` and `pointsAtContent` too.
                    pointsAtContent:
                      type: boolean
                      default: true
                      description: >-
                        Only with `naturalGestures`: the avatar points to where
                        the content enters.
                    gestures:
                      type: array
                      maxItems: 20
                      items:
                        type: string
                        maxLength: 120
                      default: []
                      description: >-
                        Gestures to use, in alternate clips (never the first or
                        the last), word for word from this list: `adjusts their
                        cap`, `takes a sip of coffee and sets the cup down`,
                        `fixes their hair`, `waves hello`, `laughs`, `with a
                        surprised look on their face`, `and nods slowly,
                        smiling`, `points up`, `points up to the left`, `points
                        to the right`, `crosses their arms`, `shrugs`, `gives a
                        thumbs up`, `claps once`, `tilts their head curiously`,
                        `adjusts their glasses`, `tucks hair behind their ear`,
                        `taps their chin thoughtfully`, `snaps their fingers`,
                        `rolls their eyes playfully`. Anything else is ignored.
                        Empty: picked automatically. Needs `naturalGestures`.
                    voice:
                      type: string
                      enum:
                        - young-woman-25-30
                        - woman-mid-20s
                        - woman-mid-30s
                        - older-woman-50
                        - young-man-25-30
                        - man-mid-20s
                        - man-mid-30s
                        - older-man-50
                      description: >-
                        Voice card of the avatar, repeated in every clip. Picked
                        from the avatar's gender and age when omitted.
                        `voiceTone` wins over it.
                    accent:
                      type: string
                      enum:
                        - us-neutral-general-american
                        - us-southern
                        - us-new-york
                        - uk-london
                        - uk-northern-manchester
                        - australian-neutral
                        - irish-dublin
                        - spanish-neutral-latin-american
                        - spanish-spain-neutral-peninsular
                        - spanish-mexico
                        - spanish-colombia
                        - spanish-argentina-rioplatense
                        - spanish-caribbean
                      description: >-
                        Accent card. It applies only when it speaks the video's
                        `language` (the first seven are English, the rest
                        Spanish); otherwise the neutral accent of that language
                        is used. Languages other than English and Spanish get no
                        accent card.
                    voiceTone:
                      type: string
                      maxLength: 400
                      description: >-
                        Your own description of the voice (max 400 characters).
                        Wins over `voice`.
                aspectRatio:
                  type: string
                  enum:
                    - ratio_9_16
                    - ratio_16_9
                    - ratio_1_1
                  default: ratio_9_16
                  description: Shape of the video.
                language:
                  type: string
                  description: >-
                    Language the avatar speaks; detected from the script when
                    omitted. 2-letter ISO 639-1 code, e.g. `en`, `es`.
                caption:
                  type: object
                  description: Burned-in captions.
                  properties:
                    preset:
                      type: string
                      enum:
                        - default
                        - beast
                        - umi
                        - tiktok
                        - wrap1
                        - wrap2
                        - ariel
                        - hooked
                        - classic
                        - active
                        - bubble
                        - glass
                        - comic
                        - glow
                        - pastel
                        - neon
                        - retroTV
                        - red
                        - marker
                        - modern
                        - blue
                        - vivid
                      default: tiktok
                      description: Caption style. Any other value answers 400.
                    alignment:
                      type: string
                      enum:
                        - top
                        - middle
                        - bottom
                      default: bottom
                      description: Caption position
                    disabled:
                      type: boolean
                      default: false
                      description: true hides the captions
                content:
                  type: object
                  description: Branding.
                  properties:
                    brandingLogo:
                      type: object
                      description: >-
                        Your logo over the video. Drawn only with `enabled:
                        true` and a `url`.
                      properties:
                        enabled:
                          type: boolean
                          default: false
                        url:
                          type: string
                          description: Logo image URL (PNG with transparency works best)
                        position:
                          type: string
                          enum:
                            - top-left
                            - top-right
                            - bottom-left
                            - bottom-right
                          default: bottom-right
                        size:
                          type: number
                          minimum: 20
                          maximum: 200
                          default: 100
                          description: Logo size (20-200)
                musicId:
                  type: string
                  maxLength: 30
                  description: >-
                    Background music ID from /v1/music/list. An unknown ID
                    answers 400.
                webhook:
                  type: string
                  maxLength: 500
                  format: uri
                  description: >-
                    HTTPS URL on a public host, called when the video is ready
                    or the project fails (max 500 characters). Requests are
                    signed: verify the Hooked-Signature header (HMAC-SHA256 of
                    "<t>.<raw body>") with the signing secret from Settings →
                    Webhooks; Hooked-Event and Hooked-Delivery headers name the
                    event and the delivery. No redirects are followed; 10 s
                    timeout; 3 immediate attempts. See the Webhooks guide for
                    the payload.
                metadata:
                  type: object
                  additionalProperties: true
                  description: >-
                    Any JSON object of your own (max 5 KB). Sent back in the
                    webhook payload. The key `automationId` is reserved for
                    dashboard automations and is removed.
            example:
              name: Spring drop
              script: >-
                Three looks for spring. [look 1]This linen set is my
                favourite.[/look] [look 2]And this one for the weekend.[/look]
              avatarId: '1'
              outfitImageKeys:
                - https://example.com/images/linen-set.png
                - https://example.com/images/weekend.png
              language: en
              webhook: https://example.com/hooks/hooked?token=YOUR_SECRET
      responses:
        '200':
          description: >-
            Project created. Follow it with GET /v1/project/{projectId} or wait
            for the webhook.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProjectCreateResponse'
              example:
                success: true
                data:
                  projectId: clx9p2k4m0001abcd1234efgh
                  status: processing
                message: UGC ad successfully created
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '402':
          $ref: '#/components/responses/PaymentRequired'
        '403':
          $ref: '#/components/responses/EntitlementRequired'
        '409':
          $ref: '#/components/responses/IdempotencyInProgress'
        '422':
          $ref: '#/components/responses/IdempotencyMismatch'
        '429':
          $ref: '#/components/responses/RateLimited429'
        '500':
          $ref: '#/components/responses/InternalError'
      security:
        - ApiKeyAuth: []
components:
  parameters:
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: false
      description: >-
        Makes the request safe to retry. 1-255 printable ASCII characters, one
        per operation (your job id, or a UUID you store), reused on every retry.
        Within 24 hours the same key with the same body answers with the first
        response and the header `Idempotent-Replayed: true`, without running or
        charging again. Keys are scoped to your team and the endpoint. 5xx
        answers and refusals before anything ran (401, 402, 403, 409, 429) are
        not kept. See [Idempotency](/guides/idempotency).
      schema:
        type: string
        minLength: 1
        maxLength: 255
        pattern: ^[\x20-\x7E]+$
      example: order-1042-video
  schemas:
    ProjectCreateResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        data:
          type: object
          properties:
            projectId:
              type: string
              description: Follow it with GET /v1/project/{projectId}
            status:
              type: string
              enum:
                - draft
                - processing
                - completed
                - failed
              description: >-
                The project status right after creation, usually `draft` or
                `processing`. Follow it with GET /v1/project/{projectId}.
          required:
            - projectId
            - status
        message:
          type: string
      required:
        - success
        - data
        - message
    ValidationError400:
      type: object
      description: >-
        The request is invalid. `message` is `<field>: <reason>` when a field is
        to blame.
      properties:
        success:
          type: boolean
          enum:
            - false
        message:
          type: string
      required:
        - success
        - message
      example:
        success: false
        message: 'webhook: Must be a valid HTTPS URL'
    Error401:
      type: object
      description: Missing or invalid `x-api-key`.
      properties:
        code:
          type: string
          enum:
            - not_authenticated
        message:
          type: string
          example: Not authenticated
        errorCode:
          type: string
          enum:
            - NOT_AUTHENTICATED
        details:
          type: object
          additionalProperties:
            type: string
      example:
        code: not_authenticated
        message: Not authenticated
        errorCode: NOT_AUTHENTICATED
        details:
          x-api-key: Header not provided or API Key invalid
    MissingCredentials402:
      type: object
      description: >-
        BYOK team without the provider keys this request uses. Nothing was
        created or charged. Add the keys in Settings → AI keys.
      properties:
        success:
          type: boolean
          enum:
            - false
          description: Present when raised by the spend check
        code:
          type: string
          enum:
            - missing_credentials
        errorCode:
          type: string
          enum:
            - MISSING_CREDENTIALS
        missingProviders:
          type: array
          items:
            type: string
            enum:
              - openrouter
              - elevenlabs
              - gemini
              - bria
              - firecrawl
        message:
          type: string
        details:
          type: object
      required:
        - code
        - errorCode
        - missingProviders
        - message
      example:
        code: missing_credentials
        message: >-
          Your team uses its own provider keys (BYOK) and these are missing or
          invalid: OpenRouter, ElevenLabs. Add them in Settings → AI keys.
        errorCode: MISSING_CREDENTIALS
        missingProviders:
          - openrouter
          - elevenlabs
        details: {}
    SubscriptionRequired402:
      type: object
      description: Managed team (generates with Hooked's keys) without a live subscription.
      properties:
        success:
          type: boolean
          enum:
            - false
        code:
          type: string
          enum:
            - subscription_required
        errorCode:
          type: string
          enum:
            - SUBSCRIPTION_REQUIRED
        message:
          type: string
      required:
        - success
        - code
        - errorCode
        - message
      example:
        success: false
        code: subscription_required
        errorCode: SUBSCRIPTION_REQUIRED
        message: >-
          Your team generates with Hooked's keys, which are paid by your plan.
          Subscribe to keep generating.
    InsufficientCredits402:
      type: object
      description: >-
        Not enough credits for this request. `creditsNeeded` /
        `creditsAvailable` are included when the estimate is known.
      properties:
        success:
          type: boolean
          enum:
            - false
        errorCode:
          type: string
          enum:
            - INSUFFICIENT_CREDITS
        message:
          type: string
        creditsNeeded:
          type: number
        creditsAvailable:
          type: number
      required:
        - success
        - errorCode
        - message
      example:
        success: false
        errorCode: INSUFFICIENT_CREDITS
        message: Not enough credits to perform this action
        creditsNeeded: 40
        creditsAvailable: 12
    EntitlementRequired403:
      type: object
      description: >-
        Valid key, but the team does not have the product this endpoint belongs
        to.
      properties:
        code:
          type: string
          enum:
            - entitlement_required
        error:
          type: string
          enum:
            - entitlement_required
        message:
          type: string
        product:
          type: string
          example: app
      required:
        - code
        - error
        - message
        - product
      example:
        code: entitlement_required
        error: entitlement_required
        message: This endpoint requires the "app" product.
        product: app
    Error500:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - false
        message:
          type: string
        error:
          type: string
          description: Present on some endpoints
      example:
        success: false
        message: Internal server error
  responses:
    ValidationError:
      description: Validation error (also `Invalid JSON body`)
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ValidationError400'
    Unauthorized:
      description: Missing or invalid API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error401'
    PaymentRequired:
      description: >-
        Payment required: a BYOK team is missing provider keys (nothing was
        created or charged), a managed team has no live subscription, or there
        are not enough credits.
      content:
        application/json:
          schema:
            oneOf:
              - $ref: '#/components/schemas/MissingCredentials402'
              - $ref: '#/components/schemas/SubscriptionRequired402'
              - $ref: '#/components/schemas/InsufficientCredits402'
          examples:
            missingCredentials:
              value:
                code: missing_credentials
                message: >-
                  Your team uses its own provider keys (BYOK) and these are
                  missing or invalid: OpenRouter, ElevenLabs. Add them in
                  Settings → AI keys.
                errorCode: MISSING_CREDENTIALS
                missingProviders:
                  - openrouter
                  - elevenlabs
                details: {}
            subscriptionRequired:
              value:
                success: false
                code: subscription_required
                errorCode: SUBSCRIPTION_REQUIRED
                message: >-
                  Your team generates with Hooked's keys, which are paid by your
                  plan. Subscribe to keep generating.
            insufficientCredits:
              value:
                success: false
                errorCode: INSUFFICIENT_CREDITS
                message: Not enough credits to perform this action
                creditsNeeded: 40
                creditsAvailable: 12
    EntitlementRequired:
      description: The team does not have the product this endpoint needs
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/EntitlementRequired403'
    IdempotencyInProgress:
      description: >-
        A request with the same `Idempotency-Key` is still running. Retry in a
        few seconds.
      content:
        application/json:
          schema:
            type: object
            properties:
              success:
                type: boolean
                enum:
                  - false
              code:
                type: string
              message:
                type: string
              details:
                type: object
                additionalProperties: true
            required:
              - success
              - code
              - message
          example:
            success: false
            code: idempotency_conflict
            message: A request with this Idempotency-Key is still in progress
            details: {}
    IdempotencyMismatch:
      description: >-
        The `Idempotency-Key` was already used with a different body. Use a new
        key for a new request.
      content:
        application/json:
          schema:
            type: object
            properties:
              success:
                type: boolean
                enum:
                  - false
              code:
                type: string
              message:
                type: string
              details:
                type: object
                additionalProperties: true
            required:
              - success
              - code
              - message
          example:
            success: false
            code: idempotency_mismatch
            message: Idempotency-Key was used with a different request
            details: {}
    RateLimited429:
      description: >-
        Your team is over a rate limit: 30 POST requests per minute, 120 other
        requests per minute, or 3 downloads of your URLs running at once.
        Nothing ran and nothing was charged: wait `Retry-After` seconds and send
        the request again. See [Rate
        limits](/guides/error-handling#rate-limits-429).
      headers:
        Retry-After:
          description: Seconds to wait before sending again.
          schema:
            type: integer
        X-RateLimit-Limit:
          description: The limit of the bucket you hit (not sent for the download cap).
          schema:
            type: integer
        X-RateLimit-Remaining:
          description: 'Requests left in this window: 0 (not sent for the download cap).'
          schema:
            type: integer
        X-RateLimit-Reset:
          description: >-
            When the window ends, in Unix seconds (not sent for the download
            cap).
          schema:
            type: integer
      content:
        application/json:
          schema:
            type: object
            properties:
              success:
                type: boolean
                enum:
                  - false
              errorCode:
                type: string
                enum:
                  - RATE_LIMITED
              message:
                type: string
              retryAfterSeconds:
                type: integer
            required:
              - success
              - errorCode
              - message
              - retryAfterSeconds
          example:
            success: false
            errorCode: RATE_LIMITED
            message: >-
              Rate limit exceeded: 30 POST requests per minute per team. Retry
              after 12 s.
            retryAfterSeconds: 12
    InternalError:
      description: Internal server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error500'
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key

````

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