API de KolWrite para agentes de IA
Cómo dejar que un agente de IA (Claude Code, Codex, Cursor o un script tuyo) convierta grabaciones en transcripciones, subtítulos SRT y tiempos por palabra con la API de plataforma de KolWrite en https://api.kolwrite.com. Una persona crea un token una sola vez; el agente lo lee de una variable de entorno y llama a HTTPS sin más. No hace falta ningún SDK.
Esta es la API de plataforma con tokens kol_. La API de créditos de https://app.kolwrite.com (cabecera x-api-key) es otra API distinta, descrita (en inglés) en https://console.kolwrite.com/llms.txt para quien la busque.
1. Dale un token al agente
- El acceso a la API se activa por cuenta; sin él, crear o usar un token se rechaza.
- Una persona crea el token en la app de KolWrite (Ajustes → Cuenta → Acceso a la API → Crear token) y elige el conjunto más pequeño de ámbitos. El secreto (
kol_...) se muestra una sola vez. - Guárdalo en una variable de entorno, lejos de prompts, registros y git.
| Tarea | Ámbitos |
|---|---|
| Transcribir y exportar | files:write, jobs:write, jobs:read, transcripts:read |
| Consultar también el saldo de créditos | añade billing:read |
| Endpoints compatibles con OpenAI | ai:use (gasta créditos; no forma parte del ajuste Automation de la app) |
| Crear enlaces para compartir | añade shares:write |
Pega esto en AGENTS.md, CLAUDE.md o .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. Qué llamada usar
| Quieres | Llamada |
|---|---|
| La transcripción de un archivo, con tiempos por palabra y hablantes | sesión de subida, luego POST /api/v1/jobs (type: transcription), luego GET /api/v1/jobs/{job_id}/export?format=json |
| Subtítulos SRT o VTT | GET /api/v1/jobs/{job_id}/export?format=srt o format=vtt (plan Plus o superior) |
| Subtítulos en otro idioma | options.target_language en el trabajo y luego exportar |
| Texto sin formato | export?format=text |
| El texto de un clip de voz corto, sin trabajo | POST /api/v1/ai/openai/audio/transcriptions |
| Chat, respuestas, embeddings | /api/v1/ai/openai/* (endpoints compatibles con OpenAI) |
| La transcripción guardada, con versiones | GET /api/v1/jobs/{job_id}/artifacts |
| El saldo de créditos | GET /api/v1/billing/balance |
| Un enlace público a una transcripción | POST /api/v1/shares |
| Qué perfiles de modelo existen | GET /api/v1/models |
3. Transcribir un archivo en 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']}")
Los archivos grandes se suben por partes: la sesión devuelve entonces data.upload_url como null y una URL por parte en data.multipart_part_urls (consulta el inicio rápido).
4. Usar los tiempos
La exportación JSON trae segments, cada uno con start y end en segundos, text, un speaker cuando se ejecutó la diarización y words (text, start, end). Deja que el agente elija segmentos por índice y lea los tiempos de la transcripción; nunca dejes que un modelo escriba marcas de tiempo.
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)
Los subtítulos salen directamente de la API. include_speakers=false omite los nombres de los hablantes y max_chars_per_entry fija la longitud de cada entrada de subtítulo:
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"
Las descargas de SRT y VTT requieren el plan Plus o superior. Los demás planes reciben HTTP 403 con el código subtitle_export_requires_plus; las exportaciones JSON y de texto no se ven afectadas.
5. Reglas para agentes
- Envía un
Idempotency-Keyal crear un trabajo, para que un reintento no inicie un segundo trabajo. - Reintenta tras
429,502,503y504con espera exponencial; ante un429esperaRetry-After. No reintentes tras401,403ni errores de validación. Consulta errores. - Lee
detail.code, no el texto del mensaje. - Un trabajo reserva créditos al crearse y los liquida al terminar; consulta
GET /api/v1/billing/balanceantes de un lote grande. - El archivo OpenAPI es el contrato: cada operación indica su ámbito requerido en
x-required-scope.
Preguntas
¿Cómo hago subtítulos SRT de un vídeo con un agente de IA?
Sube el archivo, crea un trabajo de transcripción, espera a succeeded y llama al endpoint de exportación con format=srt. Los subtítulos requieren el plan Plus o superior.
¿Pueden Claude Code o Codex llamar a la API de KolWrite?
Sí. La llaman por HTTPS con un token de acceso personal tomado de una variable de entorno. No hay SDK ni servidor MCP que instalar.
¿Cómo obtiene un agente las marcas de tiempo por palabra?
Exporta el trabajo como JSON. Cada segmento incluye words con start y end en segundos.