# Create a cloned voice (/docs/api-reference/voice-cloning/createClonedVoice)

> Clone a voice from an audio sample. The sample must be Base64 encoded and 1 KB to 25 MB. MP3, WAV and WebM are accepted; a non-audio body is refused.

**POST** `/voices`

Clone a voice from an audio sample. The sample must be Base64 encoded and
1 KB to 25 MB. MP3, WAV and WebM are accepted; a non-audio body is
refused.

Creation is asynchronous. This call returns `202` at once with
`status: processing`. Poll `GET /voices/{voice_id}` until `status` is
`ready` or `failed`, then use the `voice_id` in an agent's `voice` config with
`voice.provider: cartesia`.

You must send `consent: true`: you confirm you have the right to clone
this voice. The attestation is recorded against the clone.

Limits apply per user: 5 clones an hour, 20 a day, and 200 stored
(processing plus ready). A request over a limit is refused with `429`.

```yaml
operationId: createClonedVoice
parameters:
  - in: header
    name: Idempotency-Key
    schema:
      type: string
    description: |
      Optional. Send a unique value per clone; a retry with the same key
      and body returns the first clone instead of creating a second. Every
      clone costs money at the provider, so this makes a retry safe. Up to
      255 printable characters.
requestBody:
  required: true
  content:
    application/json:
      schema:
        type: object
        required:
          - name
          - clip
          - consent
        properties:
          name:
            type: string
            description: A name for the cloned voice, 1 to 100 characters.
            example: Front desk
          clip:
            type: string
            description: Base64-encoded audio, 1 KB to 25 MB (MP3, WAV or WebM).
          filename:
            type: string
            description: Optional original filename, for your reference.
            example: sample.mp3
          description:
            type: string
            description: Optional description.
          language:
            type: string
            description: A short language code for the voice. Defaults to `en`.
            example: en
          gender:
            type: string
            enum:
              - male
              - female
            default: female
            description: The voice's gender. Defaults to `female`.
          consent:
            type: boolean
            description: |
              Required and must be `true`: you confirm you have the right
              to clone this voice.
            example: true
responses:
  '202':
    description: |
      The clone was accepted and is being created. Poll the status until it
      is `ready` or `failed`.
    content:
      application/json:
        schema:
          type: object
          properties:
            voice:
              type: object
              description: |
                A voice cloned from an audio sample. Created asynchronously: `status` is
                `processing` until the provider finishes, then `ready` or `failed`.
                `voice_id` is the provider id an agent uses, and is `null` until ready.
              properties:
                id:
                  type: integer
                  example: 412
                name:
                  type: string
                  example: Front desk
                description:
                  type: string
                  nullable: true
                language:
                  type: string
                  example: en
                gender:
                  type: string
                  enum:
                    - male
                    - female
                status:
                  type: string
                  enum:
                    - processing
                    - ready
                    - failed
                voice_id:
                  type: string
                  nullable: true
                  description: |
                    The provider voice id. Put it in an agent's `voice.voice_id` with
                    `voice.provider: cartesia`. `null` until `status` is `ready`.
                  example: 8a1c2f5e-3b7d-4c9a-9f21-2e6b0d4a7c88
                sample_url:
                  type: string
                  nullable: true
                  description: |
                    An mp3 preview of the cloned voice, when one exists. Fetching it
                    needs your API key in the `Authorization: Bearer` header, so a
                    browser `<audio>` tag cannot play it directly.
                error:
                  type: string
                  nullable: true
                  description: |
                    Present only when `status` is `failed`. Deliberately generic: no
                    provider name and no internal detail.
                created_at:
                  type: string
                  description: ISO 8601 time in UTC, with no offset.
                  nullable: true
                ready_at:
                  type: string
                  description: ISO 8601 time in UTC, with no offset.
                  nullable: true
        example:
          voice:
            id: 412
            name: Front desk
            description: null
            language: en
            gender: female
            status: processing
            voice_id: null
            sample_url: null
            error: null
            created_at: '2026-10-12T15:18:07.424509'
            ready_at: null
  '400':
    description: |
      The body is invalid: missing `name`, `clip` or `consent`, a `clip`
      that is not valid Base64, not audio, too small or too large, a bad
      language code, or a bad gender. Also `invalid_idempotency_key` when
      the `Idempotency-Key` header is longer than 255 characters or has
      unprintable characters.
    content:
      application/json:
        schema:
          type: object
          properties:
            error:
              type: string
              description: Machine-readable error code.
            error_description:
              type: string
              description: Human-readable explanation.
            code:
              type: string
              description: |
                Stable, specific reason. Present on the newer endpoints (Voice
                cloning, WhatsApp); older endpoints return only `error`.
            request_id:
              type: string
              description: |
                Correlates this response with the server log. Present alongside
                `code`. Also sent as the `X-Request-Id` header.
        example:
          error: invalid_request
          error_description: clip does not look like an audio file. Upload MP3, WAV or WebM.
          code: invalid_audio
          request_id: req_4a1e8c2d9f60
  '401':
    description: Missing or invalid API key.
    content:
      application/json:
        schema:
          type: object
          properties:
            error:
              type: string
              description: Machine-readable error code.
            error_description:
              type: string
              description: Human-readable explanation.
            code:
              type: string
              description: |
                Stable, specific reason. Present on the newer endpoints (Voice
                cloning, WhatsApp); older endpoints return only `error`.
            request_id:
              type: string
              description: |
                Correlates this response with the server log. Present alongside
                `code`. Also sent as the `X-Request-Id` header.
        example:
          error: unauthorized
          error_description: Missing or invalid API key
          code: invalid_api_key
          request_id: req_6e2b9d4f1a38
  '403':
    description: |
      Voice cloning is not enabled for this account. It must be included in
      your plan, and your API key's user needs write access to it.
    content:
      application/json:
        schema:
          type: object
          properties:
            error:
              type: string
              description: Machine-readable error code.
            error_description:
              type: string
              description: Human-readable explanation.
            code:
              type: string
              description: |
                Stable, specific reason. Present on the newer endpoints (Voice
                cloning, WhatsApp); older endpoints return only `error`.
            request_id:
              type: string
              description: |
                Correlates this response with the server log. Present alongside
                `code`. Also sent as the `X-Request-Id` header.
        example:
          error: forbidden
          error_description: You do not have permission to make changes to Voice Cloning.
          code: permission_denied
          request_id: req_7b3d5e1a0c94
  '409':
    description: |
      The `Idempotency-Key` was already used with a different body.
      `code` is `idempotency_key_reused`.
    content:
      application/json:
        schema:
          type: object
          properties:
            error:
              type: string
              description: Machine-readable error code.
            error_description:
              type: string
              description: Human-readable explanation.
            code:
              type: string
              description: |
                Stable, specific reason. Present on the newer endpoints (Voice
                cloning, WhatsApp); older endpoints return only `error`.
            request_id:
              type: string
              description: |
                Correlates this response with the server log. Present alongside
                `code`. Also sent as the `X-Request-Id` header.
        example:
          error: conflict
          error_description: >-
            This Idempotency-Key was already used with a different request. Use a new key for a new
            request.
          code: idempotency_key_reused
          request_id: req_8d1f4a7c2e59
  '429':
    description: |
      A per-user limit was hit. `code` is `rate_limited` (5 an hour or 20 a
      day) or `stored_limit` (200 stored voices). A `Retry-After` header is
      sent on `rate_limited`.
    content:
      application/json:
        schema:
          type: object
          properties:
            error:
              type: string
              description: Machine-readable error code.
            error_description:
              type: string
              description: Human-readable explanation.
            code:
              type: string
              description: |
                Stable, specific reason. Present on the newer endpoints (Voice
                cloning, WhatsApp); older endpoints return only `error`.
            request_id:
              type: string
              description: |
                Correlates this response with the server log. Present alongside
                `code`. Also sent as the `X-Request-Id` header.
        example:
          error: too_many_requests
          error_description: Too many voice clones were requested. Please wait and try again.
          code: rate_limited
          request_id: req_2c8f0d6b5a17
  '500':
    description: |
      The clone could not be started. Nothing was created; safe to retry.
    content:
      application/json:
        schema:
          type: object
          properties:
            error:
              type: string
              description: Machine-readable error code.
            error_description:
              type: string
              description: Human-readable explanation.
            code:
              type: string
              description: |
                Stable, specific reason. Present on the newer endpoints (Voice
                cloning, WhatsApp); older endpoints return only `error`.
            request_id:
              type: string
              description: |
                Correlates this response with the server log. Present alongside
                `code`. Also sent as the `X-Request-Id` header.
        example:
          error: server_error
          error_description: Could not start the voice clone. Please try again.
          code: clone_failed
          request_id: req_1e6b4a9c2d78
  '503':
    description: Voice cloning is temporarily unavailable. Try again shortly.
    content:
      application/json:
        schema:
          type: object
          properties:
            error:
              type: string
              description: Machine-readable error code.
            error_description:
              type: string
              description: Human-readable explanation.
            code:
              type: string
              description: |
                Stable, specific reason. Present on the newer endpoints (Voice
                cloning, WhatsApp); older endpoints return only `error`.
            request_id:
              type: string
              description: |
                Correlates this response with the server log. Present alongside
                `code`. Also sent as the `X-Request-Id` header.
        example:
          error: service_unavailable
          error_description: Voice cloning is temporarily unavailable.
          code: provider_unavailable
          request_id: req_3f7c0b5d8a21
```

**cURL**

```bash
# A real clip is too long for a command-line argument, so build the body in a file.
base64 < sample.mp3 | tr -d '\n' \
  | jq -Rs '{name:"Front desk", clip:., consent:true}' > body.json
curl -X POST "https://backend.omnidim.io/api/v1/voices" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d @body.json
```

**curl**

```bash
curl -X POST "https://omnidim.io/api/v1/voices" \
  -H "Authorization: Bearer $OMNIDIM_API_KEY"
```