# Dateien hochladen

> Dateien bis 95 MB schickst du mit einem Request. Größere Dateien bis 2 GB lädst du in Chunks hoch und setzt den Upload bei Bedarf fort.

Canonical: https://transcript1.com/de/docs/uploads
Language: de
Last updated: 2026-10-14

Hochgeladene Audio- und Videodateien transkribiert transcript1 immer mit KI-Speech-to-Text. Für `source` sind deshalb nur `auto` und `stt` erlaubt. Wie du `language` und `diarize` setzt, steht unter [Quellen und Einstellungen](https://transcript1.com/de/docs/sources-and-options).

## Diese Dateien kannst du hochladen

Prüfe vor dem Upload die Dateiendung. Erlaubt sind `mp3`, `wav`, `m4a`, `flac`, `ogg`, `opus`, `mp4`, `mov`, `webm` und `mkv`. Bei anderen Endungen antwortet die API mit `422 unsupported_media`. Die Datei braucht außerdem eine Audiospur. Fehlt sie, endet die Transkription mit `unsupported_media`.

| Upload | Grenze |
|---|---|
| Ein Request mit `multipart/form-data` | 95 MB |
| Upload in Chunks | 2 GB (2.000.000.000 Bytes); je nach Tarif kann die Grenze niedriger sein. |
| Gleichzeitig offene Uploads in Chunks pro Team | 20 |

Ist die Datei zu groß, bekommst du `413 media_too_large`. Im Fehler steht unter `max_bytes`, wie viele Bytes du höchstens hochladen darfst.

## Bis 95 MB mit einem Request

Sende die Datei mit `POST /v1/transcriptions` als `multipart/form-data`. Bis 95 MB reicht dafür ein Request. Die Datei gehört ins Feld `file`. Optional kannst du die Formularfelder `language`, `diarize` mit `true` oder `false`, `source` mit `auto` oder `stt` sowie `webhook_url` mitschicken.

```bash
curl -X POST "https://api.transcript1.com/v1/transcriptions?wait=60" \
  -H "Authorization: Bearer $TRANSCRIPT1_API_KEY" \
  -F file=@interview.m4a \
  -F language=en \
  -F diarize=true
```

In der Antwort erhältst du das Transkriptionsobjekt; `source.platform` hat den Wert `upload`. Wie bei Video-Links steht `202` für eine laufende Verarbeitung und `200` für einen abschließenden Status. Ist die Datei leer, bekommst du `422 invalid_request`.

## Große Dateien in Chunks hochladen

Teile große Dateien für den Upload in Chunks auf. So musst du nach einem Verbindungsabbruch nicht von vorn anfangen. Der Ablauf hat vier Schritte.

### 1. Upload anlegen

Schicke zuerst Dateiname und Dateigröße als JSON. Wenn du möchtest, gib auch `mime_type` an. Mit einem `Idempotency-Key`-Header kannst du diesen Request später sicher wiederholen:

```bash
curl -X POST "https://api.transcript1.com/v1/transcriptions" \
  -H "Authorization: Bearer $TRANSCRIPT1_API_KEY" \
  -H "Idempotency-Key: interview-2026-10-13" \
  -H "Content-Type: application/json" \
  -d '{"upload":{"filename":"interview.m4a","size":48210334,"mime_type":"audio/mp4"},"language":"auto","diarize":true}'
```

Du bekommst `201` zurück. Die Transkription hat den Status `awaiting_upload`; im Block `upload` steht alles für den Upload:

```json
{
  "id": "tr_8fK2Lm0PqRsTuVwXyZaBcD",
  "object": "transcription",
  "status": "awaiting_upload",
  "upload": {
    "chunk_url_template": "https://api.transcript1.com/v1/transcriptions/tr_8fK2Lm0PqRsTuVwXyZaBcD/upload/chunks/{index}",
    "headers": { "X-Upload-Token": "t1u_..." },
    "expires_at": "2026-10-13T10:30:00.000Z",
    "chunks": [
      { "index": 0, "offset": 0, "size": 8388608 },
      { "index": 1, "offset": 8388608, "size": 8388608 }
    ]
  }
}
```

Der Server legt die Aufteilung fest. Unter `chunks` findest du die Liste der Chunks mit jeweils etwa 8 MiB (8.388.608 Bytes); im Beispiel ist sie gekürzt. Behandle das `X-Upload-Token` vertraulich. Es gilt nur für diesen Upload und läuft nach 1 Stunde ab. Den genauen Zeitpunkt findest du in `expires_at`.

### 2. Chunks einzeln senden

Baue für jeden Chunk die URL aus `chunk_url_template`: Ersetze `{index}` durch seinen `index`. Lies ab `offset` genau `size` Bytes aus der Datei und sende sie per `PUT` als `application/octet-stream`. Die Bytezahl muss exakt zum Plan passen.

Für diese Requests reicht der Header `X-Upload-Token`. Einen `Authorization`-Header brauchst du nicht.

```bash
curl -X PUT "https://api.transcript1.com/v1/transcriptions/tr_8fK2Lm0PqRsTuVwXyZaBcD/upload/chunks/0" \
  -H "X-Upload-Token: t1u_..." \
  -H "Content-Type: application/octet-stream" \
  --data-binary @chunk-0.bin
```

Nach jedem Chunk antwortet die API mit `{ "object": "upload_chunk", "index": 0, "size": 8388608 }`. Du kannst denselben Chunk erneut senden; er ersetzt dann die vorherige Version. Stimmen Größe oder Index nicht mit dem Plan überein, bekommst du `422 invalid_request`. Fehlt das Token oder ist es abgelaufen, bekommst du `401 unauthorized`.

### 3. Einen unterbrochenen Upload fortsetzen

Frage mit `GET /v1/transcriptions/:id/upload` ab, welche Chunks schon angekommen sind:

```json
{
  "object": "upload",
  "status": "awaiting_upload",
  "total_bytes": 48210334,
  "uploaded_bytes": 16777216,
  "received_chunks": [0, 1],
  "chunks": [ { "index": 0, "offset": 0, "size": 8388608 } ],
  "expires_at": "2026-10-13T10:30:00.000Z"
}
```

Lade anschließend nur die Chunks hoch, die noch nicht in `received_chunks` stehen. Ist das Token inzwischen abgelaufen, wiederhole den Request aus Schritt 1 mit identischem `Idempotency-Key` und denselben Parametern. Du bekommst dieselbe Transkription zurück, diesmal mit einem neuen Upload-Token.

### 4. Upload abschließen

```bash
curl -X POST "https://api.transcript1.com/v1/transcriptions/tr_8fK2Lm0PqRsTuVwXyZaBcD/upload/complete" \
  -H "Authorization: Bearer $TRANSCRIPT1_API_KEY"
```

Rufe `POST /v1/transcriptions/:id/upload/complete` auf, wenn du alle Chunks gesendet hast. Der Server prüft, ob sie vollständig und jeweils in der geplanten Größe vorliegen. Dann setzt er die Datei zusammen und reiht die Transkription zur Verarbeitung ein. Die Antwort ist `202` mit dem Transkriptionsobjekt.

Bei `409 upload_incomplete` fehlen noch Chunks. `missing_chunks` enthält die Indizes, die du erneut senden musst. Ist der Upload bereits abgeschlossen oder abgebrochen, bekommst du `409 invalid_state`. Nach erfolgreichem Abschluss fragst du den Status mit `GET /v1/transcriptions/:id?wait=60` ab oder wartest auf einen [Webhook](https://transcript1.com/de/docs/webhooks).

### Der gesamte Ablauf in Python

```python
import os
import requests

API = "https://api.transcript1.com"
auth = {"Authorization": f"Bearer {os.environ['TRANSCRIPT1_API_KEY']}"}
path = "interview.m4a"

created = requests.post(
    f"{API}/v1/transcriptions",
    headers={**auth, "Idempotency-Key": "interview-2026-10-13"},
    json={"upload": {"filename": os.path.basename(path), "size": os.path.getsize(path)}},
)
created.raise_for_status()
transcription = created.json()
upload = transcription["upload"]

with open(path, "rb") as file:
    for chunk in upload["chunks"]:
        file.seek(chunk["offset"])
        url = upload["chunk_url_template"].replace("{index}", str(chunk["index"]))
        response = requests.put(
            url,
            data=file.read(chunk["size"]),
            headers={**upload["headers"], "Content-Type": "application/octet-stream"},
        )
        response.raise_for_status()

done = requests.post(f"{API}/v1/transcriptions/{transcription['id']}/upload/complete", headers=auth)
done.raise_for_status()
print(done.json()["status"])
```

## Upload-Limits und Löschfristen

- Pro Team dürfen höchstens 20 Uploads gleichzeitig auf `awaiting_upload` stehen. Beim nächsten Versuch antwortet die API mit `429 too_many_active_jobs` und einem `Retry-After`-Header.
- Schließe einen Upload innerhalb von 24 Stunden nach dem Anlegen ab. Danach bricht transcript1 ihn ab und löscht die Chunks.
- Sobald die Transkription `completed`, `failed` oder `canceled` erreicht, beginnt die Löschfrist für die hochgeladene Datei. Nach 24 Stunden wird sie gelöscht. Das Transkript bleibt gespeichert, bis du es mit `DELETE /v1/transcriptions/:id` entfernst.
- Wenn eine Transkription fehlschlägt oder abgebrochen wird, berechnen wir nichts. Ansonsten rechnen wir jede angefangene Audiominute ab, sobald die Dauer der Datei feststeht. Details findest du unter [Abrechnung und Limits](https://transcript1.com/de/docs/billing-and-limits).
