Captioning API · v1

API de subtítulos de Picute

Envía la URL de un vídeo y recibe un MP4 con subtítulos incrustados, un SRT firmado y un JSON de transcripción. Toda la superficie de v1 está documentada abajo: inicio rápido, referencia interactiva y verificación de webhooks.

Inicio rápido

Elige tu lenguaje. Los fragmentos siguientes envían un trabajo de subtitulado con tu clave de API; reemplaza el marcador de posición antes de ejecutarlos.

curl -X POST https://picute.net/api/v1/captions \
  -H "Authorization: Bearer pk_live_<your_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "video_url": "https://cdn.example.com/clip.mp4",
    "language": "auto",
    "preset": "default",
    "callback_url": "https://api.your-app.com/webhooks/picute"
  }'

Referencia de la API

Todos los endpoints, esquemas de petición y códigos de error de v1. Haz clic en cualquier operación para desplegar los esquemas de petición y respuesta.

Webhooks

Picute hace POST de un webhook firmado a tu URL de retorno cuando un trabajo de subtítulos llega a un estado terminal. Verifica la cabecera X-Picute-Signature antes de confiar en el payload.

Eventos

  • caption.completedTrabajo de subtítulos completado correctamente. data es el recurso Caption completo con las URLs de salida pobladas.
  • caption.failedEl trabajo de subtítulos falló. data.error contiene el código de error y el mensaje.

Verificar la firma

Calcula HMAC-SHA256 sobre la cadena raw 'timestamp.body' con tu secreto de webhook y compárala en tiempo constante contra el digest hex contenido en el campo v1= de la cabecera.

import hmac, hashlib, time
from flask import Flask, request, abort

app = Flask(__name__)
SECRET = "<your_webhook_secret_from_dashboard>"
TOLERANCE_SECONDS = 5 * 60

def verify(req):
    header = req.headers.get("X-Picute-Signature", "")
    parts = dict(p.split("=", 1) for p in header.split(",") if "=" in p)
    timestamp = int(parts.get("t", "0"))
    received = parts.get("v1", "")
    if abs(time.time() - timestamp) > TOLERANCE_SECONDS:
        return False
    signed = f"{timestamp}.{req.get_data(as_text=True)}".encode("utf-8")
    expected = hmac.new(SECRET.encode("utf-8"), signed, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, received)

@app.post("/webhooks/picute")
def hook():
    if not verify(request):
        abort(401)
    payload = request.get_json()
    print(payload["event"], payload["data"]["id"])
    return "", 204