# Generate image, video and voice

> Choose a model, confirm the price, generate from text or images and use the result in the editor or in a post.

One route generates image, video or voice with models from several makers (Veo, Kling, Seedance, Wan, Nano Banana, GPT Image, ElevenLabs voices and others). You create the generation, poll until it is ready and use the result.

> Generating always charges, even on unlimited usage. Show the person the model and the price and wait for a yes before calling `POST /generations`. If it fails, the credits come back on their own.

### Choose the model

```bash
curl https://api.cut.pro/api/v1/generations/models \
  -H "X-Api-Key: $CUTPRO_API_KEY"
```

```json title="200 OK (abridged example)"
{
  "models": [
    {
      "id": "google/veo-3.1-lite",
      "name": "Veo 3.1 Lite",
      "kind": "video",
      "modes": ["text", "image", "frames"],
      "resolutions": ["720p", "1080p"],
      "seconds": [4, 6, 8],
      "aspect_ratios": ["16:9", "9:16"],
      "audio": "always",
      "max_images": 2,
      "typical_seconds": 74,
      "success_rate": 0.97,
      "prices": [{ "mode": "text", "resolution": "720p", "credits": 12, "silent_credits": null }]
    }
  ],
  "presets": { "video": [{ "id": "balanced", "model": "google/veo-3.1-lite", "resolution": "720p" }] },
  "prompt_max": 4000,
  "max_running": 4,
  "improve_credits": 1
}
```

Prices follow each model's cost and change without notice: read this route right before generating.

| Field | What it is for |
|---|---|
| `modes` | `text` (prompt only), `image` (animates an image), `frames` (from the first to the last frame), `references` (takes a person, product or style from the images, or edits them). |
| `prices[].credits` | Per second of video, per image or per 1,000 characters of voice. `silent_credits` is the price of the video without sound. |
| `audio` | `always` always has sound; `optional` accepts `audio: false`, usually cheaper; `null` is silent. |
| `refuses` | What the model refuses to show: `real_faces`, `minors`, `public_figures`. |
| `typical_seconds`, `success_rate` | Typical time and success rate over the last weeks. `null` until enough generations have run. |
| `presets` | The recommended model per type and tier (`fast`, `balanced`, `best`). Use it when the person does not choose. |
| `max_running` | How many generations the workspace runs at the same time. |

### Upload the images, if the mode requires them

```bash
curl -X POST https://api.cut.pro/api/v1/generations/images \
  -H "X-Api-Key: $CUTPRO_API_KEY" \
  -F "image=@produto.jpg"
```

```json title="201 Created"
{ "id": "7412960011002233" }
```

| `mode` | `image_ids` |
|---|---|
| `text` | none |
| `image` | one, the first frame |
| `frames` | two: first and last frame |
| `references` | up to the model's `max_images` |

An image generated by Cut.Pro does not need an upload: its `output.image_id` works just as well.

### Generate

```bash
curl -X POST https://api.cut.pro/api/v1/generations \
  -H "X-Api-Key: $CUTPRO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "kind": "video",
    "model": "google/veo-3.1-lite",
    "mode": "text",
    "resolution": "720p",
    "prompt": "a dog surfing at sunset",
    "seconds": 8,
    "aspect_ratio": "9:16",
    "credits": 96
  }'
```

```json title="201 Created"
{ "id": "7412960099887766", "status": "processing", "credits_charged": 96 }
```

`credits` is the total the person accepted: the price's `credits` times `seconds` on a video (12 × 8 = 96). If the price changed, nothing is charged and the response is `409 PRICE_CHANGED` with the new total in `extra.credits`. Show the new amount and ask for a yes again.

- **Video**: `seconds` is required and must be one of the model's `seconds`.
- **Image**: no `seconds`.
- **Voice** (`kind: "speech"`, `mode: "text"`): reads the `prompt` word for word in the `voice` chosen from the model's `voices`. No `aspect_ratio`. Outputs an MP3. Costs `credits` times the `prompt` characters divided by 1,000, rounded up.

### Follow along

```bash
curl https://api.cut.pro/api/v1/generations/7412960099887766 \
  -H "X-Api-Key: $CUTPRO_API_KEY"
```

Poll every 10 seconds while `status` is `processing`. `expected_seconds` says how long the model usually takes.

- `ready`: `output.url` is the preview (a 6-hour link, MP3 for a voice) and `output.thumbnail_url` is the thumbnail.
- `failed`: the reason is in `error_code` and the credits have already come back.

## Improve the prompt

`POST /generations/improve` rewrites a short request the way the chosen model understands best, in the language of the request. It generates nothing. It charges `improve_credits` and refunds if it fails. Show the new text to the person before generating with it.

```bash
curl -X POST https://api.cut.pro/api/v1/generations/improve \
  -H "X-Api-Key: $CUTPRO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "model": "google/veo-3.1-lite", "mode": "text", "prompt": "a dog surfing at sunset", "seconds": 8 }'
```

## Use the result

| Route | What it does |
|---|---|
| `GET /generations/{id}/download` | Link to the file in full quality, valid for 6 hours. After downloading, you can no longer ask for the credits back. |
| `POST /generations/{id}/edit` | Opens a finished video in the editor and returns the `edit_id`. Use it in [`POST /posts`](/en/publishing) or [`POST /renders`](/en/rendering). Calling again returns the same one. |
| `GET /generations` | Lists the generations, from newest to oldest. Filter with `kind`. |
| `DELETE /generations/{id}` | Removes it from the list and deletes the file from the library. Does not work for one in `processing`. |

## Rate or ask for the credits back

Rating is free and helps choose models:

```bash
curl -X POST https://api.cut.pro/api/v1/generations/7412960099887766/feedback \
  -H "X-Api-Key: $CUTPRO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "vote": "down", "reason": "bad_motion" }'
```

`vote` is `up`, `down` or `null` (clears). With `down`, `reason` is one of `prompt_ignored`, `defects`, `bad_motion`, `not_realistic`, `speech_wrong` (a word, name or number spoken wrong) or `other`. A `down` cancels the posts of that result that are still scheduled.

If the result is no good, ask for a refund with the same `reason` and a short `note`:

```bash
curl -X POST https://api.cut.pro/api/v1/generations/7412960099887766/refund \
  -H "X-Api-Key: $CUTPRO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "reason": "defects", "note": "The hands come out deformed in every shot." }'
```

The team reviews it. `refund_status` goes from `requested` to `approved` or `denied`.

> A refund is valid once per generation, only in `ready`, and never after downloading or posting: `409 REFUND_AFTER_DOWNLOAD` and `409 REFUND_AFTER_POST`.

## Errors

| Code | When |
|---|---|
| `INSUFFICIENT_CREDITS` | Insufficient balance. `extra.top_up_url` leads to the top-up; `extra.is_owner` says whether the caller can top up. |
| `PRICE_CHANGED` | The price changed. The new total is in `extra.credits`. |
| `TOO_MANY_RUNNING` | The workspace already has `max_running` generations running. Wait for one to finish. |
| `MODEL_UNAVAILABLE`, `MODE_UNSUPPORTED`, `RESOLUTION_INVALID`, `SECONDS_INVALID`, `RATIO_INVALID`, `IMAGES_INVALID`, `VOICE_INVALID` | The request does not match what the model accepts. Check `GET /generations/models`. |
| `IMAGE_NOT_FOUND` | An `image_ids` entry is not from this workspace. |

When the generation ends in `failed`, `error_code` says why: `SAFETY_BLOCKED`, `COPYRIGHT_BLOCKED` and `REAL_FACES_BLOCKED` are model refusals over the content (change the request or the model); `TIMEOUT` and `MEDIA_FAILED` are worth another attempt.
