API-referentie
Elke aanroep hieronder heeft een voorbeeldverzoek en een voorbeeldantwoord; daarna volgen de taakstatussen, foutcodes, limieten en bewaartermijnen. Nieuw hier? Begin met de ontwikkelaarsgids.
Overzicht
- Basis-URL:
https://api.video-to-notes.com. Elk pad begint met/api/v1. - Verzoeken en antwoorden zijn JSON via HTTPS. Stuur
Content-Type: application/jsonmee met elke verzoekbody. - Tijden zijn Unix-tijdstempels in seconden (UTC). Posities in een opname zijn seconden vanaf het begin van het bestand.
- ID’s en cursors zijn ondoorzichtige tekenreeksen. Bewaar ze precies zoals je ze ontvangt.
- Elk foutantwoord bevat een
request_id. Vermeld die als je contact opneemt met support. - Antwoorden worden verstuurd met
Cache-Control: no-store; sla ze niet op in gedeelde caches. - Het machineleesbare contract staat in openapi.json (OpenAPI 3.1) en paid-api.schema.json (JSON Schema).
Authenticatie
Stuur je API-sleutel als bearer-token mee met elk API-verzoek. Sleutels beginnen met vtn_prod_. Je maakt en trekt sleutels in terwijl je bent aangemeld op de website; een API-sleutel kan geen sleutels, betalingen of het account beheren.
Authorization: Bearer vtn_prod_...Een ontbrekende, onjuiste, verlopen of ingetrokken sleutel geeft 401 UNAUTHORIZED. Stuur de sleutel nooit naar de ondertekende opslag-URL’s: die hebben hun eigen autorisatie. De curl-voorbeelden op deze pagina gebruiken deze kleine hulpfunctie, die de sleutel via standaardinvoer aan curl doorgeeft:
# Sends the key through stdin, so it never appears in the process list.
vtn() {
printf 'header = "Authorization: Bearer %s"\n' "$VTN_API_KEY" |
curl -s --config - "$@"
}Account
GET /api/v1/account
Geeft het abonnement, de resterende abonnementsseconden, het einde van het huidige tegoed en de functies en limieten die nu voor het account gelden. Lees dit voordat je uploadt: als eligible of capabilities.api_admission_enabled false is, worden nieuwe taken geweigerd.
vtn "$VTN_API_BASE/api/v1/account"{
"plan": "basic",
"eligible": true,
"remaining_seconds": 64800,
"allowance_expires_at": 1792886400,
"capabilities": {
"api_admission_enabled": true,
"key_creation_enabled": true,
"server_upload_enabled": true,
"long_jobs": true,
"formats": [
"mp4", "m4v", "mov", "webm", "mkv", "ogv", "avi", "wmv", "asf",
"flv", "mpg", "mpeg", "vob", "ts", "mts", "m2ts", "3gp", "3g2",
"mxf", "mp3", "m4a", "aac", "wav", "flac", "ogg", "oga", "opus",
"wma", "amr", "aiff", "aif", "caf", "ac3"
],
"audio_languages": [
"auto", "af", "am", "ar", "hy", "az", "be", "bn", "bs", "bg", "my",
"ca", "zh", "hr", "cs", "da", "nl", "en", "et", "tl", "fi", "fr",
"gl", "ka", "de", "el", "gu", "ha", "he", "hi", "hu", "is", "id",
"it", "ja", "kn", "kk", "km", "ko", "lv", "lt", "mk", "ms", "ml",
"mt", "mr", "mn", "ne", "no", "fa", "pl", "pt", "pa", "ro", "ru",
"sr", "sk", "sl", "es", "sw", "sv", "ta", "te", "th", "tr", "uk",
"uz", "vi"
],
"notes_languages": [
"auto", "af", "am", "ar", "hy", "az", "be", "bn", "bs", "bg", "my",
"ca", "zh", "hr", "cs", "da", "nl", "en", "et", "tl", "fi", "fr",
"gl", "ka", "de", "el", "gu", "ha", "he", "hi", "hu", "is", "id",
"it", "ja", "kn", "kk", "km", "ko", "lv", "lt", "mk", "ms", "ml",
"mt", "mr", "mn", "ne", "no", "fa", "pl", "pt", "pa", "ro", "ru",
"sr", "sk", "sl", "es", "sw", "sv", "ta", "te", "th", "tr", "uk",
"uz", "vi"
],
"download_formats": ["transcript_txt", "notes_md", "notes_html", "notes_pdf"],
"email_opt_in": false,
"limits": {
"max_upload_bytes": 8589934592,
"max_selection_seconds": null,
"active_jobs": 1,
"active_uploads": 1,
"daily_uploads": 10,
"daily_upload_bytes": 21474836480,
"new_requests_per_minute": 12,
"read_requests_per_minute": 60,
"poll_after_seconds": 5,
"result_page_bytes": 1000000,
"result_page_items": 32,
"upload_url_seconds": 900,
"download_url_seconds": 600,
"result_retention_seconds": 86400,
"recovery_retention_seconds": 172800,
"idempotency_retention_seconds": 34560000
}
}
}Uploads
Bestanden worden in delen via ondertekende URL’s rechtstreeks naar de opslag geüpload. Een account kan één actieve upload tegelijk hebben.
POST /api/v1/uploads
Start een upload. Stuur de exacte bestandsgrootte in bytes en de bestandsextensie. Het antwoord geeft part_size en part_count: deel het bestand op in stukken van part_size bytes; het laatste deel mag kleiner zijn.
vtn -X POST "$VTN_API_BASE/api/v1/uploads" \
-H "Content-Type: application/json" \
-d '{
"byte_size": 1048576,
"extension": "mp4"
}'{
"upload_id": "upload-1",
"state": "created",
"expires_at": 1792807200,
"part_size": 16777216,
"part_count": 1,
"error": null
}POST /api/v1/uploads/{upload_id}/parts
Geeft ondertekende upload-URL’s voor 1 tot 100 deelnummers. Elke URL is tot 15 minuten geldig; vraag een nieuwe aan als hij verloopt of als een deel opnieuw moet worden verstuurd.
vtn -X POST "$VTN_API_BASE/api/v1/uploads/upload-1/parts" \
-H "Content-Type: application/json" \
-d '{
"part_numbers": [1]
}'{
"upload_id": "upload-1",
"targets": [
{
"part_number": 1,
"url": "https://example.invalid/signed",
"expires_at": 1792800900
}
]
}PUT {signed part URL}
Stuur elk deel als ruwe bytes van een HTTP-PUT naar de bijbehorende ondertekende URL, zonder Authorization-header. Bewaar de antwoordheader ETag precies zoals hij terugkomt, inclusief de aanhalingstekens. Elke URL accepteert alleen de exacte grootte van zijn deel: part_size voor elk deel behalve het laatste, dat de resterende bytes bevat. Een body met een andere lengte wordt geweigerd met HTTP 403.
# PART_URL comes from the parts response; send no Authorization header.
curl -s --upload-file part-0001.bin --dump-header - --output /dev/null \
"$PART_URL" | grep -i '^etag:'POST /api/v1/uploads/{upload_id}/complete
Rondt de upload af. Stuur elk deelnummer met zijn ETag. Het afronden van een upload start de verwerking niet; maak daarna een taak aan.
vtn -X POST "$VTN_API_BASE/api/v1/uploads/upload-1/complete" \
-H "Content-Type: application/json" \
-d '{
"parts": [
{
"part_number": 1,
"etag": "opaque-etag"
}
]
}'{
"upload_id": "upload-1",
"state": "uploaded",
"expires_at": 1792807200,
"part_size": 16777216,
"part_count": 1,
"error": null
}GET /api/v1/uploads/{upload_id}
Geeft de status van een upload: created, uploading, uploaded, probing, probed, failed, aborted of expired.
vtn "$VTN_API_BASE/api/v1/uploads/upload-1"{
"upload_id": "upload-1",
"state": "uploaded",
"expires_at": 1792807200,
"part_size": 16777216,
"part_count": 1,
"error": null
}POST /api/v1/uploads/{upload_id}/abort
Breekt een upload af die je niet gaat gebruiken en maakt de uploadplek van het account vrij. Opnieuw aanroepen kan geen kwaad.
vtn -X POST "$VTN_API_BASE/api/v1/uploads/upload-1/abort" \
-H "Content-Type: application/json" \
-d '{}'Taken
Een taak verwerkt één geüpload bestand tot een transcriptie en notities. Een account kan één taak tegelijk uitvoeren.
POST /api/v1/jobs
Start de verwerking van een geüpload bestand. De header Idempotency-Key is verplicht: 1 tot 128 afdrukbare ASCII-tekens zonder spaties, nieuw voor elke taak. Optionele velden zijn range (start_seconds en end_seconds, allebei verplicht als het veld wordt meegestuurd), audio_language en notes_language. Geeft 202 met de taak in status preparing. Dezelfde sleutel met dezelfde body geeft dezelfde taak; dezelfde sleutel met een andere body geeft 409.
vtn -X POST "$VTN_API_BASE/api/v1/jobs" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $IDEMPOTENCY_KEY" \
-d '{
"upload_id": "upload-1",
"range": {
"start_seconds": 5,
"end_seconds": 60
},
"audio_language": null,
"notes_language": "en"
}'{
"job_id": "job-1",
"state": "preparing",
"stage": "probe",
"created_at": 1792800000,
"expires_at": 1792807200,
"result_expires_at": null,
"idempotency_expires_at": 1827360000,
"poll_after_seconds": 5,
"status_url": "/api/v1/jobs/job-1",
"result_url": "/api/v1/jobs/job-1/result",
"completed_units": 0,
"total_units": null,
"charged_seconds": 0,
"result_available": false,
"can_resume": false,
"warnings": [],
"error": null
}GET /api/v1/jobs/{job_id}
Geeft de status, de huidige fase, de voortgang (completed_units van total_units), charged_seconds, waarschuwingen en een eventuele fout. Ook een mislukte taak geeft 200; lees dan zijn error.
vtn "$VTN_API_BASE/api/v1/jobs/job-1"{
"job_id": "job-1",
"state": "completed",
"stage": "terminal",
"created_at": 1792800000,
"expires_at": 1792807200,
"result_expires_at": 1792886400,
"idempotency_expires_at": 1827360000,
"poll_after_seconds": 5,
"status_url": "/api/v1/jobs/job-1",
"result_url": "/api/v1/jobs/job-1/result",
"completed_units": 8,
"total_units": 8,
"charged_seconds": 1140,
"result_available": true,
"can_resume": false,
"warnings": [],
"error": null
}POST /api/v1/jobs/{job_id}/cancel
Stopt een taak. Voltooide delen blijven beschikbaar en gereserveerde tijd die niet is gebruikt, krijg je terug. Opnieuw aanroepen kan geen kwaad.
vtn -X POST "$VTN_API_BASE/api/v1/jobs/job-1/cancel" \
-H "Content-Type: application/json" \
-d '{}'POST /api/v1/jobs/{job_id}/resume
Hervat een onderbroken taak als de status can_resume: true meldt. Dit vereist een actief abonnement en controleert je resterende tijd opnieuw. Delen die al verwerkt zijn, worden niet opnieuw gerekend.
vtn -X POST "$VTN_API_BASE/api/v1/jobs/job-1/resume" \
-H "Content-Type: application/json" \
-d '{}'Resultaten
GET /api/v1/jobs/{job_id}/result
Geeft één resultaatpagina met maximaal 32 items en 1 MB. De items zijn geordend en hebben een kind: transcript (tekst met getimede segmenten), notes (Markdown), gap (audio die niet verwerkt kon worden) of warning. Geef next_cursor mee als queryparameter cursor om de volgende pagina op te halen, tot die null is. Elke pagina kan in artifacts tot vier downloadlinks bevatten, tot 10 minuten geldig. Wordt de taak hervat terwijl je leest, dan antwoordt de API met 409 JOB_CONFLICT; begin dan opnieuw bij de eerste pagina.
vtn --get "$VTN_API_BASE/api/v1/jobs/job-1/result" \
--data-urlencode "cursor=$NEXT_CURSOR" # omit for the first page{
"job_id": "job-1",
"snapshot": "generation-1",
"items": [
{
"index": 0,
"kind": "transcript",
"text": "Welcome to the weekly planning meeting.",
"segments": [
{
"text": "Welcome to the weekly planning meeting.",
"start_seconds": 0,
"end_seconds": 4.2,
"timing_quality": "approximate",
"timing_method": "provider_segment"
}
]
},
{
"index": 0,
"kind": "notes",
"text": "## Summary\n\nThe team agreed on the launch plan.\n\n## Key points\n\n- Launch moves to Monday."
}
],
"next_cursor": "opaque-account-bound-cursor",
"artifacts": [
{
"format": "notes_md",
"url": "https://example.invalid/signed-notes",
"expires_at": 1792800600
}
],
"charged_seconds": 1140,
"partial": false,
"expires_at": 1792886400
}Elk transcriptiesegment meldt zijn timing_quality: aligned, approximate of unavailable. Bij benadering bepaalde tijden liggen dicht bij de spraak, maar zijn niet tot op het woord nauwkeurig.
De downloadformaten zijn transcript_txt (TXT), notes_md (Markdown), notes_html (HTML) en notes_pdf (PDF). Lange notities kunnen over meerdere bestanden verdeeld zijn; download ze op volgorde. De accountaanroep toont de formaten die nu beschikbaar zijn.
Taakstatussen
| Status | Betekenis |
|---|---|
preparing | De server controleert het bestand en plant het werk. |
queued | De taak wacht op de start. |
processing | De audio wordt geëxtraheerd, getranscribeerd en tot notities verwerkt. |
completed | Klaar. De volledige transcriptie en de notities zijn beschikbaar. |
completed_with_gaps | Klaar, maar een deel van de audio kon niet worden verwerkt. Zie de gap-items. |
interrupted | Voor het einde gestopt. Controleer can_resume. |
cancelled | Op jouw verzoek gestopt. Voltooide delen blijven beschikbaar. |
failed | De taak kon niet worden verwerkt. Zie error. |
expired | De inhoud wordt niet meer bewaard. |
stage toont de stap die bezig is: probe, planning, admission, extraction, transcription, notes, publication en ten slotte terminal.
Fouten
Elke fout heeft dezelfde JSON-body. retryable vertelt of hetzelfde verzoek later kan slagen, en retry_after_seconds hoe lang je moet wachten.
{
"error": {
"code": "RATE_LIMITED",
"message": "Request refused.",
"retryable": true,
"retry_after_seconds": 5
},
"request_id": "request-1"
}| Code | HTTP | Betekenis | Wat te doen |
|---|---|---|---|
UNAUTHORIZED | 401 | De sleutel ontbreekt, is onjuist, verlopen, ingetrokken of hoort bij een andere omgeving. | Controleer de sleutel of maak een nieuwe. |
FORBIDDEN | 403 | De sleutel kan niet voor dit verzoek worden gebruikt. | Beheer sleutels en betalingen op de website. |
NOT_FOUND | 404 | De upload of taak bestaat niet of hoort bij een ander account. | Controleer de ID. |
VALIDATION_ERROR | 400 | De body, een header of een queryparameter is ongeldig. | Pas het verzoek aan; herhaal het niet ongewijzigd. |
PLAN_REQUIRED | 403 | Het account heeft geen actief Basic- of Plus-abonnement. | Kies een abonnement en probeer het opnieuw. |
INSUFFICIENT_BALANCE | 403 | De resterende abonnementstijd dekt de geselecteerde audio niet. | Kies een korter bereik of wacht tot je uren worden vernieuwd. |
CAPABILITY_DISABLED | 503 | Nieuwe taken zijn gepauzeerd of een functie staat uit. | Probeer het later opnieuw; de accountaanroep toont de huidige stand. |
UNSUPPORTED_MEDIA | 400 | Het formaat wordt niet ondersteund, of de geüploade grootte wijkt af van de opgegeven grootte. | Upload een ondersteund bestand met de exacte grootte. |
MEDIA_TOO_LARGE | 413 | Het bestand is groter dan de limiet. | Upload een bestand van maximaal 8 GiB. |
PROBE_FAILED | 400 | Het bestand heeft geen decodeerbaar audiospoor, of het bereik valt buiten het bestand. | Controleer het bestand en het bereik. Er wordt geen tijd gerekend. |
IDEMPOTENCY_CONFLICT | 409 | De Idempotency-Key is al gebruikt met andere invoer. | Gebruik een nieuwe sleutel voor een nieuwe taak. |
IDEMPOTENCY_EXPIRED | 410 | De oorspronkelijke taak voor deze sleutel is verlopen. | Herhaal hem niet; start een nieuwe taak met een nieuwe sleutel. |
JOB_CONFLICT | 409 | Er is een andere upload of taak actief, de status staat deze actie niet toe, of het resultaat is veranderd tijdens het bladeren. | Wacht op de huidige taak of begin het bladeren opnieuw bij de eerste pagina. |
RESULT_EXPIRED | 410 | Het resultaat wordt niet meer bewaard. | Bewaar resultaten voordat ze verlopen. |
RATE_LIMITED | 429 | Te veel verzoeken, of de dagelijkse uploadlimiet is bereikt. | Wacht op Retry-After en probeer het dan opnieuw. |
UNAVAILABLE | 503 | Een dienst is tijdelijk niet beschikbaar. | Probeer het opnieuw met steeds langere pauzes. |
Limieten
Dit zijn de standaardwaarden. De accountaanroep geeft de waarden die voor jouw account gelden; ga daarvan uit.
| Limiet | Standaard | Veld in capabilities.limits |
|---|---|---|
| Bestandsgrootte | 8 GiB | max_upload_bytes |
| Geselecteerde audio per taak | Je resterende abonnementstijd (null betekent geen andere bovengrens) | max_selection_seconds |
| Actieve uploads en taken | Eén van elk per account | active_uploads, active_jobs |
| Uploads per UTC-dag | 10 uploads, samen 20 GiB | daily_uploads, daily_upload_bytes |
| Nieuwe taken en hervattingen | 12 per minuut | new_requests_per_minute |
| Andere verzoeken | 60 per minuut over alle sleutels | read_requests_per_minute |
| Status opvragen | Niet vaker dan om de 5 seconden | poll_after_seconds |
| Resultaatpagina | 32 items en 1 MB | result_page_items, result_page_bytes |
| Ondertekende upload-URL | Tot 15 minuten geldig | upload_url_seconds |
| Downloadlink | Tot 10 minuten geldig | download_url_seconds |
| Mislukte authenticatie | 30 per minuut per IP-adres; daarna krijgt elk verzoek vanaf dat adres 429, ook met een geldige sleutel, tot de minuut voorbij is | — |
Bewaartermijnen
| Gegevens | Bewaard gedurende |
|---|---|
| Upload zonder taak | Ongeveer 2 uur |
| Resultaatpagina’s en downloadbestanden | Ongeveer 24 uur na afloop van de taak |
| Herstel van de transcriptie | Ongeveer 48 uur |
| Idempotentierecord, zonder inhoud | 400 dagen |
De waarden in expires_at van elk antwoord zijn leidend; gebruik die in plaats van deze standaardwaarden.
Wijzigingslog
De API-versie maakt deel uit van het pad. Wijzigingen aan v1 staan hier met hun datum.
- 2026-10-24: API v1 beschikbaar voor de abonnementen Basic en Plus.