---
title: "POST /voices/fishaudio/clones/{voiceClone}/retry — Retry Fish Audio Voice Clone"
url: https://lumean.app/de/developers/docs/api/post-voices-fishaudio-clones-voice-clone-retry
locale: de
description: "Retry Fish Audio Voice Clone"
generated: 2026-10-17
operationId: fishAudioVoice.retryClone
method: POST
path: "/voices/fishaudio/clones/{voiceClone}/retry"
scopes: [voices.write]
spec_version: 0.0.1
---

# POST /voices/fishaudio/clones/{voiceClone}/retry

**Retry Fish Audio Voice Clone**

A new attempt for a clone in `failed`, with the same sample. The clone goes back to
`pending` and takes a slot under the plan's cap again, so the checks are the same as
on creation (`404 service_not_found`, `402 no_subscription`,
`422 voice_clone_quota_exceeded`).

Only `failed` can be retried: a `ready` clone already has its voice and
`pending`/`cloning` are still running — those get `409 voice_clone_not_retryable`.

**Required key permission:** `voices.write`.

- Benötigtes Recht: `voices.write`

## Anfrage

```bash
curl -X POST 'https://api.lumean.app/api/public/voices/fishaudio/clones/{voiceClone}/retry' \
  -H 'Accept: application/json' \
  -H 'X-API-KEY: YOUR_API_KEY'
```

## Parameter

| Feld | In | Typ | Pflicht | Beschreibung |
| --- | --- | --- | --- | --- |
| `voiceClone` | path | `string` | Pflicht | Cartesia or Fish Audio voice clone UUID — 36 characters, not a number. Take it from the clone's `id` field: `POST /voices/cartesia/clones` (or `/voices/fishaudio/clones`) returns it on creation and the matching `GET …/clones` lists it. This is **not** the clone's `voice_id` (that one goes into a template). Someone else's clone returns `404` with `reason: voice_clone_not_found`. default: `0199b3a4-7c21-7d4e-9a8b-5f6e7d8c9b0a` |

## Request-Body

Kein Body.

## Antworten

### 200 — Success. The payload is in `data`.

**Antwortfelder**

| Feld | Typ | Pflicht | Beschreibung |
| --- | --- | --- | --- |
| `success` | `boolean` | Pflicht | Success flag. Branch on the HTTP status code instead: any 2xx response carries `true` here, while an error comes back in a different shape that need not contain this field at all. |
| `message` | `string` | Pflicht | A human-readable note in the account language. Fine to show to a user; do not parse it — the wording changes without notice and is not an error code. |
| `data` | `FishAudioVoiceClone` | Pflicht | The clone with a new attempt queued — back in `pending`. |
| `data.id` | `string` | Pflicht | Clone UUID. Use it in `/voices/fishaudio/clones/{voiceClone}/…` paths; it does NOT go into a template — `voice_id` does. |
| `data.provider` | `string` — `fishaudio` | Pflicht | Clone provider — always `fishaudio`. |
| `data.display_name` | `string` | Pflicht | Clone name given at creation. |
| `data.language` | `string` | Pflicht | Reference language label (ISO 639-1), or `null` if none was sent. It does not affect cloning. |
| `data.description` | `string` | Pflicht | Your description of the clone, or `null`. |
| `data.status` | `string` | Pflicht | Status: `pending` → `cloning` → `ready` or `failed`; `archived` — retired by the owner; `banned` — blocked by a moderator. Only `ready` can be used for narration. |
| `data.voice_id` | `string` | Pflicht | The Fish Audio voice id (a 32-character hex string, not a UUID) — the value for `tts_settings.voice_id` of a template with `service_key: fishaudio`. Present only for `ready`, otherwise `null`. |
| `data.attempts` | `integer` | Pflicht | Cloning attempt number: 1 on creation, +1 for every retry. |
| `data.error` | `object` — nullable | Pflicht | Why the last attempt failed; `null` while there has been no failure. |
| `data.error.reason` | `string` | Pflicht | Machine-readable failure code: `processing_error`, `max_retries`, `network`, `timeout`, `dispatch_failed`, `unbanned` (the clone was unbanned but had no voice). Retry with `POST /voices/fishaudio/clones/{voiceClone}/retry`; if `processing_error` keeps coming back, use a different sample. |
| `data.error.message` | `string` | Pflicht | Human-readable explanation of the failure, or `null`. Branch on `reason`, not on this text. |
| `data.created_at` | `string` | Pflicht | When the clone was created. |
| `data.completed_at` | `string` | Pflicht | When the clone became `ready`; `null` until then. |
| `data.failed_at` | `string` | Pflicht | When the last attempt failed; `null` if it has not. |
| `data.banned_at` | `string` | Pflicht | When a moderator banned the clone (`status = banned`); `null` if it is not banned. |
| `data.ban_reason` | `string` | Pflicht | Reason for the ban given by the moderator, or `null`. A banned clone can be neither used nor archived. |

**Beispiel**

```json
{
  "success": true,
  "message": "Success",
  "data": {
    "id": "01a10e08-2ee5-702c-b492-243c88fd9670",
    "provider": "fishaudio",
    "display_name": "Noisy sample",
    "language": "ru",
    "description": null,
    "status": "pending",
    "voice_id": null,
    "attempts": 2,
    "error": null,
    "created_at": "2026-10-14T07:40:02+00:00",
    "completed_at": null,
    "failed_at": null,
    "banned_at": null,
    "ban_reason": null
  }
}
```

### 401 — The key is missing, unknown, disabled or expired.

**Antwortfelder**

| Feld | Typ | Pflicht | Beschreibung |
| --- | --- | --- | --- |
| `success` | `boolean` | Pflicht | Always `false` in error responses. |
| `message` | `string` | Pflicht | Error text in the key's language (set through the `X-Locale` header). |
| `data` | `null` — nullable | Pflicht | Always `null` when the request is rejected before processing. |

**Beispiel**

```json
{
  "success": false,
  "message": "API key is missing. Provide it in the X-API-KEY header.",
  "data": null
}
```

### 402 — No live subscription that includes Fish Audio (`reason: no_subscription`). Returned only if the service is closed to paying from the balance.

**Antwortfelder**

| Feld | Typ | Pflicht | Beschreibung |
| --- | --- | --- | --- |
| `success` | `boolean` | Pflicht | Always `false` in error responses. |
| `message` | `string` | Pflicht | The reason for the rejection in words, in the account language. Meant for display; do not branch on it, the wording changes. |
| `reason` | `string` | Pflicht | Machine-readable reason of a business refusal (for example, `input_expired`, `insufficient_balance`). Branch on it, not on the `message` text. |
| `error_code` | `string` | Pflicht | The same machine-readable code as in `reason` — a second name for the field. The values always match. |

**Beispiel**

```json
{
  "success": false,
  "message": "An active subscription is required.",
  "reason": "no_subscription",
  "error_code": "no_subscription"
}
```

### 403 — The key lacks the `voices.write` permission.

**Antwortfelder**

| Feld | Typ | Pflicht | Beschreibung |
| --- | --- | --- | --- |
| `success` | `boolean` | Pflicht | Always `false` in error responses. |
| `message` | `string` | Pflicht | Error text in the key's language (set through the `X-Locale` header). |

**Beispiel**

```json
{
  "success": false,
  "message": "This API key does not have permission to perform this action."
}
```

### 404 — The clone does not exist or belongs to someone else (`reason: voice_clone_not_found`). A `voiceClone` that is not a UUID does not match the route: `reason: endpoint_not_found` (a hint with the docs address, llm.md §6.1). Also `reason: service_not_found` — the service is closed to the key owner.

**Antwortfelder**

| Feld | Typ | Pflicht | Beschreibung |
| --- | --- | --- | --- |
| `success` | `boolean` | Pflicht | Always `false` in error responses. |
| `message` | `string` | Pflicht | The reason for the rejection in words, in the account language. Meant for display; do not branch on it, the wording changes. |
| `reason` | `string` | Pflicht | Machine-readable reason of a business refusal (for example, `input_expired`, `insufficient_balance`). Branch on it, not on the `message` text. |
| `error_code` | `string` | Pflicht | The same machine-readable code as in `reason` — a second name for the field. The values always match. |

**Beispiel**

```json
{
  "success": false,
  "message": "Voice clone not found.",
  "reason": "voice_clone_not_found",
  "error_code": "voice_clone_not_found"
}
```

### 409 — The clone is not in `failed` (it is already `ready`, still `pending`/`cloning`, or `archived`), or its sample has already been deleted (`reason: voice_clone_not_retryable`). Create a new clone instead.

**Antwortfelder**

| Feld | Typ | Pflicht | Beschreibung |
| --- | --- | --- | --- |
| `success` | `boolean` | Pflicht | Always `false` in error responses. |
| `message` | `string` | Pflicht | The reason for the rejection in words, in the account language. Meant for display; do not branch on it, the wording changes. |
| `reason` | `string` | Pflicht | Machine-readable reason of a business refusal (for example, `input_expired`, `insufficient_balance`). Branch on it, not on the `message` text. |
| `error_code` | `string` | Pflicht | The same machine-readable code as in `reason` — a second name for the field. The values always match. |

**Beispiel**

```json
{
  "success": false,
  "message": "Only a clone that ended with an error can be retried.",
  "reason": "voice_clone_not_retryable",
  "error_code": "voice_clone_not_retryable"
}
```

### 422 — The clone cap of the plan is reached (`reason: voice_clone_quota_exceeded`, the cap is in `max`).

**Antwortfelder**

| Feld | Typ | Pflicht | Beschreibung |
| --- | --- | --- | --- |
| `success` | `boolean` | Pflicht | Always `false` in error responses. |
| `message` | `string` | Pflicht | The reason for the rejection in words, in the account language. Meant for display; do not branch on it, the wording changes. |
| `reason` | `string` | Pflicht | Machine-readable reason of a business refusal (for example, `input_expired`, `insufficient_balance`). Branch on it, not on the `message` text. |
| `error_code` | `string` | Pflicht | The same machine-readable code as in `reason` — a second name for the field. The values always match. |
| `max` | `integer` | Pflicht | The Fish Audio clone cap of your plan: how many clones in `pending`, `cloning` and `ready` you may hold at once (Cartesia clones do not count). Archive a clone you no longer need to free a slot. |

**Beispiel**

```json
{
  "success": false,
  "message": "Voice clone limit reached: no more than 3. Delete a clone you no longer need or wait for the current one to fail.",
  "reason": "voice_clone_quota_exceeded",
  "error_code": "voice_clone_quota_exceeded",
  "max": 3
}
```

### 429 — The clone rate limit is exceeded (`reason: rate_limit_exceeded`): by default 6 attempts per minute and 60 per day per user, shared with the web cabinet and LumVoice cloning. Every attempt counts, including one rejected by validation. Wait `retry_after` seconds (the `Retry-After` header).

**Antwortfelder**

| Feld | Typ | Pflicht | Beschreibung |
| --- | --- | --- | --- |
| `success` | `boolean` | Pflicht | Always `false` in error responses. |
| `message` | `string` | Pflicht | Error text in the key's language (set through the `X-Locale` header). |
| `reason` | `string` | Pflicht | Machine-readable failure reason — branch on this, not on the message text. |
| `error_code` | `string` | Pflicht | The same machine-readable code as in `reason` — a second name for the field. The values always match; branch on either. |
| `retry_after` | `integer` — nullable | — | How many seconds to wait before retrying (the same value is in the `Retry-After` header). |

**Beispiel**

```json
{
  "success": false,
  "message": "Too many attempts. Please wait a moment and try again.",
  "reason": "rate_limit_exceeded",
  "error_code": "rate_limit_exceeded",
  "retry_after": 30
}
```

---

- Diese Seite im Browser: https://lumean.app/de/developers/docs/api/post-voices-fishaudio-clones-voice-clone-retry
- Vollständige maschinenlesbare Referenz: https://api.lumean.app/docs/llm.md
