KolWrite KolWrite Developers

KolWrite API for AI agents

How to let an AI agent (Claude Code, Codex, Cursor, or a script of your own) turn recordings into transcripts, SRT subtitles and word timings with the KolWrite platform API at https://api.kolwrite.com. A person creates a token once; the agent reads it from an environment variable and calls plain HTTPS. No SDK is needed.

This is the platform API with kol_ tokens. The credits API at https://app.kolwrite.com (header x-api-key) is a different API, described at https://console.kolwrite.com/llms.txt.

1. Give the agent a token

TaskScopes
Transcribe and exportfiles:write, jobs:write, jobs:read, transcripts:read
Also check the credit balanceadd billing:read
OpenAI-compatible endpointsai:use (spends credits; not part of the app's Automation preset)
Create share linksadd shares:write

Paste this into AGENTS.md, CLAUDE.md or .cursorrules:

## KolWrite platform API
- Base URL https://api.kolwrite.com. The token is in the environment variable KOLWRITE_TOKEN: send it as "Authorization: Bearer $KOLWRITE_TOKEN" and never print it.
- Flow: POST /api/v1/media/upload-session, PUT the bytes to data.upload_url, POST /api/v1/media/complete, POST /api/v1/jobs, poll GET /api/v1/jobs/{job_id} until status is succeeded, then GET /api/v1/jobs/{job_id}/export?format=json
- Spec: https://kolwrite-docs.pages.dev/openapi.json. Guide: https://kolwrite-docs.pages.dev/agents.md

2. When to use which call

You wantCall
A transcript of a file, with word timings and speakersupload session, then POST /api/v1/jobs (type: transcription), then GET /api/v1/jobs/{job_id}/export?format=json
SRT or VTT subtitlesGET /api/v1/jobs/{job_id}/export?format=srt or format=vtt (Plus plan or higher)
Subtitles in another languageoptions.target_language on the job, then export
Plain textexport?format=text
Text for a short voice clip, no jobPOST /api/v1/ai/openai/audio/transcriptions
Chat, responses, embeddings/api/v1/ai/openai/* (OpenAI-compatible endpoints)
The saved, versioned transcriptGET /api/v1/jobs/{job_id}/artifacts
The credit balanceGET /api/v1/billing/balance
A public link to a transcriptPOST /api/v1/shares
Which model profiles existGET /api/v1/models

3. Transcribe a file in Python

import json, mimetypes, os, time
import requests

BASE = "https://api.kolwrite.com"
TOKEN = os.environ["KOLWRITE_TOKEN"]


def call(method, path, **kw):
    headers = {"Authorization": f"Bearer {TOKEN}", **kw.pop("headers", {})}
    r = requests.request(method, BASE + path, headers=headers, timeout=120, **kw)
    r.raise_for_status()
    return r


def transcribe(path, profile="oracle", language="auto"):
    name, size = os.path.basename(path), os.path.getsize(path)
    ctype = mimetypes.guess_type(name)[0] or "application/octet-stream"
    session = call("POST", "/api/v1/media/upload-session",
                   json={"filename": name, "file_size_bytes": size,
                         "content_type": ctype}).json()["data"]
    with open(path, "rb") as f:
        requests.put(session["upload_url"], data=f, headers=session["headers"],
                     timeout=3600).raise_for_status()
    media = call("POST", "/api/v1/media/complete",
                 json={"finalize_token": session["finalize_token"]}).json()["data"]
    job = call("POST", "/api/v1/jobs",
               headers={"Idempotency-Key": f"{name}-{size}-{profile}-{language}"},
               json={"type": "transcription",
                     "input": {"type": "media_ref", "media_id": media["media_id"]},
                     "profile": profile,
                     "options": {"language": language,
                                 "diarization": {"mode": "regular"}}}).json()["data"]
    while True:
        status = call("GET", f"/api/v1/jobs/{job['job_id']}").json()["data"]["status"]
        if status in ("succeeded", "failed", "cancelled"):
            break
        time.sleep(5)
    if status != "succeeded":
        raise RuntimeError(f"job {job['job_id']} {status}")
    export = call("GET", f"/api/v1/jobs/{job['job_id']}/export",
                  params={"format": "json"}).json()
    return job["job_id"], json.loads(export["data"])  # data is a JSON string


job_id, transcript = transcribe("interview.wav")
for seg in transcript["segments"]:
    print(f"{seg['start']:.2f}-{seg['end']:.2f} {seg.get('speaker', '')} {seg['text']}")

Large files are uploaded in parts: the session then returns data.upload_url as null and a URL for each part in data.multipart_part_urls (see the quickstart).

4. Use the timings

The JSON export has segments, each with start and end in seconds, text, a speaker when diarization ran, and words (text, start, end). Let the agent choose segments by index and read the times from the transcript; never let a model type timestamps.

import subprocess

keep = [s for s in transcript["segments"] if "pricing" in s["text"].lower()]
for i, seg in enumerate(keep):
    subprocess.run(["ffmpeg", "-y", "-i", "talk.mp4", "-ss", str(seg["start"]),
                    "-to", str(seg["end"]), f"clip{i}.mp4"], check=True)

Subtitles come straight from the API. include_speakers=false leaves the speaker names out, and max_chars_per_entry sets the length of each subtitle entry:

curl -H "Authorization: Bearer $KOLWRITE_TOKEN" -o talk.srt \
  "https://api.kolwrite.com/api/v1/jobs/JOB_ID/export?format=srt&include_speakers=false&max_chars_per_entry=42"

SRT and VTT downloads need a Plus plan or higher. Other plans get HTTP 403 with the code subtitle_export_requires_plus; JSON and text exports are not affected.

5. Rules for agents

Questions

How do I make SRT subtitles from a video with an AI agent?

Upload the file, create a transcription job, wait for succeeded, then call the export endpoint with format=srt. Subtitles need a Plus plan or higher.

Can Claude Code or Codex call the KolWrite API?

Yes. They call it over HTTPS with a personal access token from an environment variable. There is no SDK or MCP server to install.

How does an agent get word timestamps?

Export the job as JSON. Each segment carries words with start and end in seconds.

Markdown version of this page