Video transcription and notes API
Send an audio or video file from your server and get back a timestamped transcript, AI notes and ready-made downloads. The API uses the same processing as the website and the Chrome extension.
- Base URL
https://api.video-to-notes.com- Authentication
- API key as a bearer token
- Format
- JSON over HTTPS; files go straight to storage through signed URLs
- Access
- Included in active Basic and Plus plans; uses your plan hours
Quickstart
These steps take a file from your disk to a transcript and notes. You need an active Basic or Plus plan, a terminal and, for the example client, Python 3.12 or later.
1. Create an API key
Sign in on the website (for example on the pricing page), open API keys in the account bar, name the key and, if you like, set an expiry date. Copy the secret when it appears: it is shown only once. Up to three keys can be active at a time.
2. Store the key in an environment variable
Keep the key out of source code, command-line arguments and logs. The examples read the key from VTN_API_KEY and the base URL from VTN_API_BASE.
export VTN_API_BASE="https://api.video-to-notes.com"
read -rs VTN_API_KEY && export VTN_API_KEY # paste the key, press Enter$env:VTN_API_BASE = "https://api.video-to-notes.com"
$env:VTN_API_KEY = Read-Host "API key" -MaskInput3. Check your account
This call confirms that the key works and returns your plan, your remaining plan seconds, the supported formats and the current limits.
# 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 - "$@"
}
vtn "$VTN_API_BASE/api/v1/account"$headers = @{ Authorization = "Bearer $env:VTN_API_KEY" }
Invoke-RestMethod "$env:VTN_API_BASE/api/v1/account" -Headers $headers |
ConvertTo-Json -Depth 54. Transcribe a file
Download the Python example client. It needs only the standard library. It uploads the file in parts, starts the job, waits for it and saves every result page.
python client.py run meeting.mp4 --state meeting.state.json \
--output meeting.jsonl --download meeting-filesTo process only part of a recording, add --start and --end in seconds from the start of the file. --audio-language gives a language hint and --notes-language chooses the language of the notes. Without these options the whole file is processed and the languages are detected automatically.
python client.py run lecture.webm --state lecture.state.json \
--start 30 --end 3630 --audio-language ru --notes-language enThe state file stores the upload ID and the request identity, never the key. If the command stops, run it again with the same state file: it recovers the same job and you are not charged twice. Use a new state file for each new job.
5. Read the results
meeting.jsonl holds one JSON result page per line: transcript text with timings, notes in Markdown, gaps and warnings. meeting-files holds the downloads, such as the transcript as TXT and the notes as Markdown, HTML and PDF. The client has these other commands:
python client.py account
python client.py status JOB_ID
python client.py result JOB_ID --output results.jsonl --download files
python client.py cancel JOB_ID
python client.py resume JOB_IDPrefer curl? The Bash quickstart runs the same upload, job and result steps with curl and jq.
bash quickstart.sh meeting.mp4How a job works
Every integration follows the same six steps. The API reference shows each call with a request and a response example.
- Check the account.
GET /api/v1/accountreturns your plan, remaining seconds, supported formats and limits. - Create an upload.
POST /api/v1/uploadswith the file size in bytes and the file extension. The response gives the part size and the number of parts. - Upload the parts. Get signed URLs from
POST /api/v1/uploads/{upload_id}/parts, send each part with an HTTPPUTstraight to storage, keep eachETag, then callPOST /api/v1/uploads/{upload_id}/complete. - Start the job.
POST /api/v1/jobswith the upload ID and anIdempotency-Keyheader. The server checks the real file, plans the work and reserves the time from your plan. - Poll the status.
GET /api/v1/jobs/{job_id}until the state is final, waiting at leastpoll_after_secondsbetween calls. - Read the result.
GET /api/v1/jobs/{job_id}/resultand follownext_cursoruntil it is null. Download the files listed inartifactsbefore their links expire.
A job ends as completed, completed_with_gaps, interrupted, cancelled, failed or expired. charged_seconds shows how much of your plan the job used.
Best practices
These habits keep your keys safe, prevent double charges and make long jobs reliable.
Keep keys secret
- Call the API only from a server or a script you control. Never put a key in browser code, a mobile app, a URL or source control.
- Load the key from an environment variable or a secret manager, and keep it out of logs, error reports and command-line arguments.
- Use one key per integration and give it an expiry date, so you can rotate or revoke one key without touching the others.
- To rotate a key, create the new key, deploy it, then revoke the old one. Jobs that already started keep running.
- If a key may have leaked, for example in a chat, a ticket or a commit, revoke it right away in the API keys panel.
Make job creation safe to retry
- Generate a random
Idempotency-Key, such as a UUID, for each new job and save it with the upload ID before you send the request. - If the response is lost, send the same request with the same key again. You get the original job back and you are not charged twice.
- Never reuse a key for another file or other options: the API answers with 409
IDEMPOTENCY_CONFLICT.
Poll politely and handle limits
- Wait at least five seconds between status calls, and longer when
poll_after_secondsasks for it. - On 429 or 503, wait for the
Retry-Afterheader orerror.retry_after_seconds, then retry with a little random jitter. - Retry a request unchanged only when
error.retryableis true. Otherwise fix the request first. - An account runs one upload and one job at a time. Queue your files and send the next one when the current job is finished.
Control how many hours you use
- Check
remaining_secondsbefore you upload. A job that needs more time than you have fails withINSUFFICIENT_BALANCE; the API never shortens your selection to make it fit. - Send a
rangewhen you need only part of a recording. Only the selected audio is charged. - Cancel jobs you no longer need. Finished parts stay available and reserved time that was not used is returned.
- Abort uploads you will not use, so that the next upload can start.
Collect complete results
- Follow
next_cursoruntil it is null. A page holds at most 32 items. - Treat
gapitems as audio that could not be processed, not as silence, and check thewarnings. - Download the files in
artifactswhile their links are valid (up to ten minutes); request the page again for fresh links. - Save what you need: result files are kept for about 24 hours and transcript recovery for about 48 hours.
- Read the fields you need and ignore the rest.
Frequently asked questions
Who can use the API?
Anyone with an active Basic or Plus plan. API access is included in both plans and has no separate price. Without an active plan, new jobs are refused with PLAN_REQUIRED. See the plans and pricing.
How is API usage counted?
API jobs use the same plan hours as the website and the Chrome extension. The server measures the real length of the selected audio; charged_seconds in the job status and in each result page shows the exact amount. For a job with gaps that cannot be recovered, the terms explain how the missing audio is charged.
Which file formats and sizes are supported?
Video: MP4, M4V, MOV, WebM, MKV, OGV, AVI, WMV, ASF, FLV, MPG, MPEG, VOB, TS, MTS, M2TS, 3GP, 3G2 and MXF. Audio: MP3, M4A, AAC, WAV, FLAC, OGG, OGA, OPUS, WMA, AMR, AIFF, AIF, CAF and AC3. A file can be up to 8 GiB. It must contain an audio track that can be decoded; copy-protected files cannot be read.
Which languages can I use?
Automatic detection is the default. You can also give a hint for the audio language or choose the notes language with one of more than 60 language codes, for example en, de, es, fr, ja or zh. The account call lists every value accepted right now.
How long does a job take?
It depends on the length of the selected audio and on the current load. Jobs run in the background, so you can upload a long recording and check back later. completed_units and total_units in the job status show the progress.
Can I call the API from a browser or a mobile app?
No. An API key gives access to your plan hours, so it must stay on a server you control. For a web or mobile app, send the files to your own backend and call the API from there.
Can I send a YouTube link or another URL?
No. The API processes files that you upload; it does not download URLs or YouTube videos.
Are there webhooks or email notifications?
No. Poll the job status and respect poll_after_seconds. API jobs do not send email.
What happens if my connection drops?
If a part fails to upload, request a fresh signed URL for that part and send it again before the upload expires. If the response to job creation is lost, repeat the request with the same Idempotency-Key and you get the same job back. A running job does not depend on your connection.
How long are results kept?
Result pages and download files are kept for about 24 hours after the job finishes, and the transcript can be recovered for about 48 hours. Each response gives the exact expires_at time, so save what you need before then.
What happens when I revoke a key or my plan ends?
Revoking a key does not stop jobs that already started; use another key to read their results. When your plan ends, a valid key can still read status and results and cancel jobs until the content expires, but new uploads, new jobs and resume need an active plan.
What happens to my uploaded files?
We aim to delete uploaded source files within 24 hours of upload. Deletion may take longer. The privacy policy explains what is stored and for how long.
Is there an SDK or an OpenAPI file?
There is no SDK package. Use the OpenAPI 3.1 file to generate a client or to import the API into a tool such as Postman or Insomnia, or start from the Python and curl examples.
What are the rate limits?
An account runs one upload and one job at a time, can start up to 10 uploads with 20 GiB in total per UTC day, can create 12 jobs per minute and can send 60 other requests per minute across all of its keys. The account call returns the values that apply to you.
Files and examples
The examples and contract files are published with the site and match the live API.
- client.py: Python 3.12+ example client, standard library only
- quickstart.sh: Bash example with curl and jq
- openapi.json: OpenAPI 3.1 description of every endpoint, with examples
- paid-api.schema.json: JSON Schema of every request and response
Help
Something unclear or not working? Contact us and include the request_id from the error response, the time and the endpoint. Never send us your API key.