# Wysyłanie plików

> Plik do 95 MB wyślesz jednym requestem. Większe, do 2 GB, wrzucisz w częściach. Przerwany upload możesz wznowić.

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

Własny plik audio lub wideo możesz wysłać do transkrypcji AI. Pole `source` przyjmuje wtedy tylko `auto` lub `stt`. Jak ustawić `language` i `diarize`, sprawdzisz w [dokumentacji linków i ustawień](https://transcript1.com/pl/docs/sources-and-options).

## Jakie pliki możesz wysłać

Przyjmujemy pliki z rozszerzeniem `mp3`, `wav`, `m4a`, `flac`, `ogg`, `opus`, `mp4`, `mov`, `webm` lub `mkv` na końcu nazwy. Przy innym rozszerzeniu API zwróci `422 unsupported_media`. W pliku musi być ścieżka audio. Jeśli jej nie ma, transkrypcja zakończy się błędem `unsupported_media`.

| Co sprawdzamy | Limit |
|---|---|
| Upload jednym requestem (`multipart/form-data`) | 95 MB |
| Upload w częściach | 2 GB (2 000 000 000 bajtów). W twoim planie limit może być niższy. |
| Jednocześnie otwarte uploady w częściach na zespół | 20 |

Jeśli plik przekroczy limit, dostaniesz `413 media_too_large`. Pole `max_bytes` w błędzie poda dozwolony rozmiar.

## Upload jednym requestem

Plik do 95 MB wyślij na `POST /v1/transcriptions` jako `multipart/form-data`, w polu `file`. W tym samym formularzu możesz opcjonalnie dodać `language`, `diarize` (`true` lub `false`), `source` (`auto` lub `stt`) i `webhook_url`.

```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
```

W odpowiedzi dostaniesz obiekt transkrypcji, w którym `source.platform` ma wartość `upload`. Tak jak przy linku do nagrania, kod HTTP `202` oznacza, że transkrypcja trwa, a `200`, że już się zakończyła. Jeśli wyślesz pusty plik, API zwróci `422 invalid_request`.

## Większy plik wyślij w częściach

Duży plik podziel na części według planu z API. Jeśli upload się przerwie, doślesz tylko to, czego brakuje. Całość składa się z czterech kroków.

### 1. Zarezerwuj upload

Najpierw wyślij JSON z nazwą i rozmiarem pliku. Możesz też podać `mime_type`. Dodaj nagłówek `Idempotency-Key`, żeby w razie potrzeby bezpiecznie powtórzyć ten request:

```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}'
```

API odpowie kodem `201`. Transkrypcja będzie mieć status `awaiting_upload`, a w polu `upload` znajdziesz instrukcje wysyłania części:

```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 }
    ]
  }
}
```

Serwer dzieli plik na części po około 8 MiB (8 388 608 bajtów). Ich listę dostaniesz w `chunks`; powyżej pokazujemy tylko jej początek. Token `X-Upload-Token` jest poufny, działa tylko dla tego uploadu i wygasa po 1 godzinie. Dokładny termin znajdziesz w `expires_at`.

### 2. Wyślij części pliku

Dla każdej części wyślij request `PUT` pod adres z `chunk_url_template`. W miejsce `{index}` wpisz jej `index`. Odczytaj z pliku bajty od pozycji `offset`, dokładnie tyle, ile podaje `size`, i wyślij je jako `application/octet-stream`. Rozmiar body musi zgadzać się z planem. Do uwierzytelnienia wystarczy nagłówek `X-Upload-Token`; `Authorization` nie jest potrzebny.

```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
```

Po zapisaniu części API zwróci `{ "object": "upload_chunk", "index": 0, "size": 8388608 }`. Jeśli wyślesz ją ponownie, zastąpisz poprzednią wersję. Za rozmiar niezgodny z planem lub indeks spoza listy dostaniesz `422 invalid_request`. Bez tokenu lub po jego wygaśnięciu dostaniesz `401 unauthorized`.

### 3. Sprawdź, co dotarło, i wznów upload

Listę zapisanych części pobierzesz przez `GET /v1/transcriptions/:id/upload`:

```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"
}
```

Pomiń części wymienione w `received_chunks` i wyślij tylko brakujące. Jeśli token już wygasł, powtórz request z kroku 1. Użyj tego samego `Idempotency-Key` i tych samych parametrów. Dostaniesz tę samą transkrypcję z nowym tokenem uploadu.

### 4. Zakończ upload

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

Endpoint `POST /v1/transcriptions/:id/upload/complete` sprawdza, czy dotarły wszystkie części i czy mają właściwy rozmiar. Następnie łączy plik, dodaje transkrypcję do kolejki i zwraca `202` z jej obiektem.

Jeśli czegoś brakuje, dostaniesz `409 upload_incomplete`. Pole `missing_chunks` zawiera indeksy części, które trzeba dosłać. Dla zakończonego lub anulowanego uploadu API zwróci `409 invalid_state`.

Po zakończeniu uploadu sprawdzaj status przez `GET /v1/transcriptions/:id?wait=60` lub odbierz [webhook](https://transcript1.com/pl/docs/webhooks).

### Cały upload w Pythonie

```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"])
```

## Limity i usuwanie plików

- Zespół może mieć naraz do 20 uploadów ze statusem `awaiting_upload`. Przy próbie utworzenia kolejnego API zwróci `429 too_many_active_jobs` i nagłówek `Retry-After`.
- Jeśli nie zakończysz uploadu w ciągu 24 godzin od utworzenia, anulujemy go i usuniemy jego części.
- Plik źródłowy usuwamy 24 godziny po zakończeniu transkrypcji, niezależnie od tego, czy ma status `completed`, `failed` czy `canceled`. Transkrypcja zostaje, dopóki sam jej nie usuniesz przez `DELETE /v1/transcriptions/:id`.
- Minuty pobieramy, gdy znamy już długość nagrania. Czas zaokrąglamy w górę do pełnych minut. Jeśli transkrypcja się nie uda albo ją anulujesz, nic nie płacisz. Więcej o tym w [rozliczeniach i limitach](https://transcript1.com/pl/docs/billing-and-limits).
