# Transcribe audio and video

> Upload an audio or video file, transcribe with timing per sentence and, if you want, who is speaking. Download as JSON, SRT, VTT or text.

Transcription is independent of clipping: it works for a podcast, a class, an interview or any audio or video file. The result comes as sentences with start and end in seconds.

### Request the upload URL

```bash
curl -X POST https://api.cut.pro/api/v1/transcriptions/upload \
  -H "X-Api-Key: $CUTPRO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "file_name": "entrevista.mp3", "file_size": 48210000, "content_type": "audio/mpeg" }'
```

```json title="200 OK"
{ "media_id": "7412950033118822", "kind": "audio", "upload_url": "https://...", "expires_in": 3600 }
```

The extension of `file_name` decides whether it is audio or video. The ceiling is the lower of the plan's upload limit and the free space in storage.

### Send the file

```bash
curl -X PUT "$UPLOAD_URL" \
  -H "Content-Type: audio/mpeg" \
  --upload-file entrevista.mp3
```

The `Content-Type` must be the same as in the previous step.

### Transcribe

```bash
curl -X POST https://api.cut.pro/api/v1/transcriptions \
  -H "X-Api-Key: $CUTPRO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "media_id": "7412950033118822",
    "file_name": "entrevista.mp3",
    "file_size": 48210000,
    "source_language": "pt",
    "speaker_labels": true
  }'
```

```json title="202 Accepted"
{ "id": "7412950040021177", "status": "processing", "credits_charged": 42 }
```

| Field | Description |
|---|---|
| `media_id` | The one from the upload, or one that is already in your library. |
| `file_name`, `file_size` | Required for a newly uploaded file. |
| `source_language` | Spoken language, like `pt`. Without it, detection is automatic. Set it on short audio: detection confuses Portuguese with Spanish. |
| `speaker_labels` | Identifies who speaks in each sentence. Costs more. |

### Wait for it to be ready

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

Poll every 5 to 10 seconds while `status` is `processing`. It ends in `ready`, `no_speech` (the audio has no speech) or `failed`. The response carries `language`, `duration_seconds` and, with `speaker_labels`, `speaker_count`.

## Get the text

As JSON, to index or to draw your own interface:

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

```json title="200 OK"
{
  "language": "pt",
  "speaker_labels": true,
  "cues": [
    { "start": 0.48, "end": 3.12, "text": "Bem-vindo de volta ao programa.", "speaker": "A" },
    { "start": 3.40, "end": 5.95, "text": "Obrigado pelo convite.", "speaker": "B" }
  ]
}
```

As a caption file:

```bash
curl -o entrevista.srt "https://api.cut.pro/api/v1/transcriptions/7412950040021177/download?format=srt" \
  -H "X-Api-Key: $CUTPRO_API_KEY"
```

`format` accepts `srt` (default), `vtt` and `txt`. The body is the file, not JSON. On a transcription with `speaker_labels`, the speakers' names go into the file; `speakers=false` removes them.

Both routes respond `409 TRANSCRIPTION_NOT_READY` while the transcription is processing.

## Cost

| Situation | Charge |
|---|---|
| New transcription | Per measured minute of audio (`duration_seconds`), debited at the start. |
| With `speaker_labels` | Extra per minute. |
| The same file again | Free: responds `200 ready` right away, with `credits_charged: 0`. |
| Audio with no speech | Free: `200 no_speech`. |

To add speakers to a transcription that was made without them, ask again with the same `media_id` and `speaker_labels: true`. The audio is processed again and charged.

> `DELETE /transcriptions/{id}` removes the transcription from the lists, but the file stays in the library. Transcribing the same `media_id` later is free.

## Errors

| Code | When |
|---|---|
| `INVALID_FILE_TYPE` | File extension not accepted. `extra.allowed_extensions` carries the accepted ones. |
| `FILE_TOO_LARGE` | Exceeds the effective ceiling, in `extra.max_size`. |
| `STORAGE_LIMIT_EXCEEDED` | The plan's storage is full. |
| `MEDIA_METADATA_REQUIRED` | `file_name` or `file_size` missing for a newly uploaded file. |
| `MEDIA_TOO_LONG` | Duration above what is allowed. `extra.duration` and `extra.max_duration` say by how much. |
| `MEDIA_NOT_FOUND` | The `media_id` does not exist in this workspace. |
| `MEDIA_UNREADABLE` | The uploaded file is not readable audio or video. |
| `INSUFFICIENT_CREDITS` | Insufficient balance. `extra.credits_needed` says how much is missing. |
