# Fouten afhandelen

> Herken fouten aan hun code, lees het foutobject en bepaal wanneer je een request opnieuw kunt sturen.

Canonical: https://transcript1.com/nl/docs/errors
Language: nl
Last updated: 2026-11-05

Een request kan meteen worden geweigerd. Een transcriptie kan ook pas later mislukken, nadat de API die al heeft geaccepteerd. In dat geval staat `status` op `failed`. Houd deze twee situaties uit elkaar bij het afhandelen van fouten.

## Zo ziet een foutresponse eruit

Als een `/v1`-request mislukt, krijg je dit vaste formaat:

```json
{
  "error": {
    "code": "insufficient_minutes",
    "message": "Not enough minutes",
    "retryable": false,
    "action_url": "https://transcript1.com/dashboard/billing",
    "minutes_needed": 20,
    "minutes_remaining": 3
  }
}
```

Laat je code reageren op `code`, niet op de tekst van `message`. Die tekst is voor de gebruiker en kan veranderen. Staat `retryable` op `true`, dan kan hetzelfde request later wel slagen.

Afhankelijk van de fout krijg je naast `retryable` extra velden:

| Veld | Foutcode | Wat staat erin? |
|---|---|---|
| `action_url` | `insufficient_minutes`, `no_active_plan`, `topup_needs_user` | De link om een abonnement te nemen of minuten bij te kopen. |
| `minutes_needed`, `minutes_remaining` | `insufficient_minutes` | Het aantal benodigde minuten en je huidige saldo. Het benodigde aantal is `null` zolang de duur nog onbekend is. |
| `reason`, `packs` | `topup_needs_user` | Waarom de kaart niet is belast, en het aantal gevraagde pakketten. |
| `supported_platforms` | `unsupported_platform` | De toegestane platforms: `["youtube", "x", "tiktok", "instagram", "facebook", "bluesky", "twitch", "dailymotion", "pinterest", "linkedin", "snapchat"]`. |
| `missing_chunks` | `upload_incomplete` | De indexen van de chunks die de server nog mist. |
| `max_bytes` | `media_too_large` | Jouw maximale bestandsgrootte in bytes. |
| `params` | `invalid_request` | Bij ongeldige body- of queryvelden een object dat per veld uitlegt wat je moet aanpassen. |

## Wanneer de API je request weigert

| HTTP-status | `code` | Opnieuw proberen? | Oorzaak |
|---|---|---|---|
| 400, 422 | `invalid_request` | Nee | Een parameter of bodyveld ontbreekt of is ongeldig. Dit geldt ook voor ongeldige JSON en combinaties zoals `diarize` met `source: "captions"` of `reuse_recent` met `webhook_url`. |
| 422 | `invalid_url` | Nee | De link is niet geldig of komt niet overeen met `platform`. Gebruik YouTube, X, TikTok, Instagram, Facebook, Bluesky of een ander platform uit [Bronnen en instellingen](https://transcript1.com/nl/docs/sources-and-options). |
| 422 | `unsupported_platform` | Nee | De opgegeven waarde voor `platform` is niet toegestaan. |
| 422 | `unsupported_media` | Nee | De bestandsextensie wordt niet ondersteund. |
| 401 | `unauthorized` | Nee | Je API-sleutel of token ontbreekt, is ongeldig, verlopen of ingetrokken. Ook een ongeldig of verlopen uploadtoken geeft deze fout. |
| 403 | `insufficient_scope` | Nee | Het OAuth-token heeft geen `transcriptions:read` of `transcriptions:write` waar die scope nodig is. |
| 403 | `email_not_verified` | Nee | Je moet eerst je e-mailadres bevestigen om transcripties of live sessies te kunnen starten. |
| 402 | `insufficient_minutes` | Nee | Je beschikbare saldo is 0 of je hebt te weinig minuten voor deze transcriptie, of voor een live sessie minder dan één gestarte minuut. Staat [automatisch opwaarderen](https://transcript1.com/nl/docs/billing-and-limits#auto-top-up) aan, dan probeert transcript1 eerst op te waarderen. Koop minuten via `action_url`, of laat een agent ze kopen met `POST /v1/topups` of de MCP-tool `top_up`. |
| 402 | `no_active_plan` | Nee | Je wilt minuten bijkopen, maar hebt geen actief betaald abonnement. Alleen `POST /v1/topups` en de billing-endpoints van het dashboard geven deze fout, niet de transcriptie-endpoints. |
| 402 | `topup_needs_user` | Alleen bij `pending` en `in_progress` | `POST /v1/topups` heeft de kaart niet belast. `reason` geeft de reden: `not_allowed` (de inloggegevens mogen geen opwaarderingen kopen, of de gebruiker is geen teamadmin), `cap_reached` (de maandlimiet voor agents heeft geen ruimte meer), `card_declined`, `authentication_required` of `no_card`. De gebruiker kan de pakketten kopen via `action_url`. Bij `pending` (de betaling is nog niet bevestigd) en `in_progress` (er loopt al een andere opwaardering) kan de betaling nog doorgaan: probeer het later opnieuw met dezelfde `Idempotency-Key` in plaats van de gebruiker naar de aankooppagina te sturen. |
| 404 | `not_found` | Nee | De transcriptie bestaat niet of is van een ander team. |
| 409 | `upload_incomplete` | Nee | De server mist nog chunks. Verstuur die en rond de upload daarna opnieuw af. |
| 409 | `invalid_state` | Nee | De transcriptie wacht niet meer op een upload. Je kunt geen chunks meer sturen en de upload niet meer afronden. |
| 409 | `session_ended` | Nee | Een live sessie is afgelopen, dus `POST /v1/live/sessions/:id/token` kan geen token meer uitgeven. Wordt ook verstuurd als `error`-event op de WebSocket. |
| 422 | `unsupported_language` | Nee | De `language` van een live sessie wordt niet ondersteund. |
| 422 | `unsupported_translation` | Nee | De `translate_to`-taal van een live sessie wordt niet ondersteund, of live vertalen is niet beschikbaar. |
| 409 | `idempotency_conflict` | Nee | Je hebt deze `Idempotency-Key` eerder met andere parameters gebruikt. |
| 413 | `media_too_large` | Nee | Het bestand overschrijdt je uploadlimiet. Bekijk [Bestanden uploaden](https://transcript1.com/nl/docs/uploads). |
| 413 | `invalid_request` | Nee | De JSON-body is groter dan 1 MB. Bij te grote bestanden krijg je `media_too_large`. |
| 429 | `rate_limited` | Ja | Je stuurt te veel requests per minuut. Wacht het aantal seconden uit `Retry-After`. |
| 429 | `too_many_active_jobs` | Ja | Er lopen te veel transcripties of er staan te veel uploads open. Wacht het aantal seconden uit `Retry-After`. |
| 429 | `too_many_live_sessions` | Ja | De gelijktijdige live sessies van je abonnement zijn in gebruik. Wacht `Retry-After` seconden (30). |
| 500 | `internal_error` | Ja | Er gaat iets mis bij transcript1. Probeer het na een korte pauze opnieuw. |
| 503 | `service_unavailable` | Ja | transcript1 is even niet beschikbaar. Probeer het na een korte pauze opnieuw. |
| 503 | `live_capacity` | Ja | Alle live capaciteit is in gebruik. Wacht `Retry-After` seconden (30) en maak de sessie opnieuw aan. |
| 503 | `live_unavailable` | Nee | Live transcriptie is op dit moment niet beschikbaar. |

Bij browserrequests met een inlogcookie controleren we ook vanaf welke site het request komt. Een andere site krijgt `403 forbidden_origin`. Voor API-requests met een bearer-token in de `Authorization`-header geldt die controle niet.

In elke `429`-response staat `Retry-After`: het aantal seconden dat je moet wachten. De limieten zelf vind je bij [Minuten, abonnementen en limieten](https://transcript1.com/nl/docs/billing-and-limits).

## Wanneer stuur je een request opnieuw?

- Herhaal alleen requests met `retryable` op `true`: `rate_limited`, `too_many_active_jobs`, `too_many_live_sessions`, `live_capacity`, `internal_error`, `service_unavailable` en `topup_needs_user` met `reason` `pending` of `in_progress`. Houd de wachttijd uit `Retry-After` aan. Ontbreekt die header, wacht dan bij elke poging langer.
- Herhaal je `POST /v1/transcriptions` of `POST /v1/topups`, gebruik dan dezelfde `Idempotency-Key`-header. Zo betaal je niet dubbel als het eerste request toch is gelukt.
- Pas bij alle andere codes eerst je request aan voordat je het nog eens verstuurt.

## Live transcriptie

`POST /v1/live/sessions` en de andere live endpoints gebruiken dezelfde foutenvelop. `invalid_request`, `unsupported_language`, `insufficient_minutes` en `email_not_verified` gelden er ook voor, samen met de live codes in de tabel hierboven. Een sessie aanmaken is niet idempotent: een nieuwe poging na `too_many_live_sessions` of `live_capacity` maakt dus een nieuwe sessie aan.

Zodra de sessie bestaat, komen problemen binnen op de WebSocket als `error`-events en sluitcodes, niet als HTTP-fouten. Zie [Live transcriptie](https://transcript1.com/nl/docs/live#websocket-protocol) voor elk event.

| Sluitcode | Betekenis |
|---|---|
| `1000` | Normale sluiting, na `session.ended`. |
| `1011` | Onverwachte serverfout. Hervat met een nieuw token. |
| `1012` | Serverherstart, na `reconnect`. Hervat met een nieuw token. |
| `4001` | Ongeldig, verlopen of al gebruikt token. |
| `4004` | Sessie niet gevonden of al afgelopen. |
| `4008` | Protocolschending: een audioframe met oneven lengte of dat te groot is. |
| `4010` | Vervangen door een nieuwere verbinding met dezelfde sessie. |

Een live sessie die eindigt om een reden als `balance_exhausted` of `idle_timeout` is geen fout: hij stuurt `session.ended` met een eindreden en wordt opgeslagen. Zie [Eindredenen](https://transcript1.com/nl/docs/live#end-reasons).

## Als een transcriptie later mislukt

Ook na een geslaagd request kan de transcriptie nog mislukken. Dan krijg je `status` op `failed` en `error: { "code", "message" }` in het object. Controleer `error` dus ook tijdens het pollen of bij een [webhook](https://transcript1.com/nl/docs/webhooks) van het type `transcription.failed`. Mislukt een vertaling, dan wordt de webhook `transcription.translation.failed` verstuurd en mislukt het transcript daardoor nooit.

| `error.code` | Wat is er mis? | Wat kun je doen? |
|---|---|---|
| `media_unavailable` | De video bestaat niet of is niet meer beschikbaar. | Niet opnieuw proberen. Controleer de URL. |
| `media_private` | De video is afgeschermd. | Gebruik een openbare post of een openbare of verborgen YouTube-video. Hetzelfde request herhalen helpt niet. |
| `login_required` | Je moet op het platform ingelogd zijn om de video te bekijken. | Niet opnieuw proberen. Deze fout is definitief; we proberen het niet automatisch opnieuw. |
| `no_audio` | Er zit geen audiospoor in de video. | Niet opnieuw proberen. Deze fout is definitief; we proberen het niet automatisch opnieuw. |
| `age_restricted` | De video heeft een leeftijdsbeperking. | Hetzelfde request herhalen helpt niet. Upload het bestand. |
| `live_stream` | De uitzending loopt nog of is nog niet begonnen. | Probeer het na afloop van de uitzending. |
| `no_captions` | Je zette `source` op `captions`, maar er is geen bruikbaar ondertitelspoor. | Kies `source: "auto"` of `"stt"`. |
| `media_too_long` | De opname duurt langer dan de 5 uur die speech-to-text aankan. | Splits het bestand. Hetzelfde request herhalen helpt niet. |
| `unsupported_media` | Het bestand is niet leesbaar of heeft geen audiospoor. | Stuur een ondersteund bestand; herhaal niet hetzelfde request. |
| `no_speech` | Geen spraak gedetecteerd. | Niet opnieuw proberen. |
| `unsupported_language` | We ondersteunen de taal van deze opname niet. | Kies voor `language` een ondersteunde code of `"auto"`; probeer niet opnieuw met dezelfde instelling. |
| `insufficient_minutes` | Je saldo was op voordat we de minuten konden afschrijven, en automatisch opwaarderen kon, als het aanstond, geen minuten toevoegen. | Na een opwaardering. |
| `fetch_failed` | Ook na meerdere pogingen konden we de opname niet ophalen. | Probeer het later opnieuw. |
| `transcription_failed` | Ook na meerdere pogingen lukte speech-to-text niet. | Probeer het later opnieuw. |

Mislukt een transcriptie of annuleer je die, dan betaal je niets. Hadden we al minuten afgeschreven, dan krijg je die terug.
