Errores
Los 28 códigos estables de la API, qué hacer con cada uno y cuáles no se emiten nunca.
Toda respuesta de error tiene la misma forma:
{
"error": {
"type": "invalid_request_error",
"code": "invalid_parameter",
"message": "…",
"param": "understanding.sentiment_analysis.scope",
"doc_url": "https://docs.callsist.com/referencia/errores#invalid_parameter",
"request_id": "req_9xKp2mQvRt4L"
}
}Programa contra code, nunca contra message. Los códigos son estables para
siempre: añadir uno es libre, renombrar o reutilizar uno es un cambio rompedor. Los
mensajes cambian sin aviso y están en castellano.
Guarda request_id. Es el mismo que viaja en la cabecera Callsist-Request-Id de
toda respuesta y el que aparece en app.callsist.com/logs.
Pegarlo ahí es la diferencia entre depurar en un minuto y abrir un ticket.
Qué reintentar
| Códigos | Qué hacer | |
|---|---|---|
| Reintentables | 429, 500, 503 | Espera exponencial con jitter, respetando Retry-After si viene |
| No reintentables | 400, 401, 403, 404, 409, 413, 415, 422 | Reintentar gasta cuota y no cambia el resultado |
| Caso aparte | 402 | Para el lote entero, avisa y recarga. Seguir mandando solo llena los logs |
Trece códigos están publicados y no se emiten jamás. Es deliberado: la taxonomía
cubre casos que el pipeline todavía no distingue. Los que se sabe que no llegan están
marcados abajo con «no se emite». Maneja los errores por familia de type y no des por
hecho que verás cada código de esta lista.
400 · invalid_request_error
La petición está mal. No reintentar sin cambiarla.
invalid_parameter
Un campo tiene un valor que no se admite. param dice cuál, con notación de punto para
los anidados: understanding.sentiment_analysis.scope.
missing_parameter
Falta un campo obligatorio. El caso más frecuente es subir un fichero sin el campo de
formulario file en POST /v1/files: el nombre no es negociable.
invalid_audio_source
Hay que indicar exactamente uno de audio_url o file_id en POST /v1/transcripts.
Mandar los dos, o ninguno, cae aquí.
audio_duration_exceeded
Más de 10 horas de audio. Trocéalo antes de enviarlo.
unsupported_language
El código de idioma no está en el catálogo. language admite "auto" o un ISO-639-1 de
dos letras.
sentiment_scope_not_permitted
understanding.sentiment_analysis.scope solo admite "customer". Mandar "agent" cae
aquí, y no es un bug pendiente de arreglar: el Reglamento de IA (art. 5.1.f) prohíbe
inferir emociones de trabajadores en su entorno laboral, y vincula también al proveedor
del sistema.
Esto no impide evaluar la calidad del trabajo de un agente contra una plantilla — eso es evaluación de desempeño sobre hechos observables. Lo que no se puede es preguntar «¿cómo se sentía el agente?».
invalid_model
El identificador de modelo no existe. Consulta
GET /v1/models, que es público y sin autenticación. La respuesta
no repite el ID que mandaste.
invalid_webhook_url
Solo https en POST /v1/webhooks.
También cae aquí mandar webhook_url, webhook_auth_header o webhook_include_result
dentro de POST /v1/transcripts: no existe el webhook por petición. Hasta hace poco
se aceptaban en silencio, devolvían 202 y no los leía nadie. Ver
Webhooks.
401 · authentication_error
missing_api_key
Falta la cabecera Authorization.
invalid_api_key
La clave no tiene la forma esperada o no existe. Empiezan por sk_live_ seguido de 32
caracteres alfanuméricos; una clave sk_test_ se rechaza por forma, porque el modo de
prueba se retiró.
revoked_api_key
La clave se revocó. Ojo con el margen: una clave revocada sigue funcionando hasta 30 segundos, que es lo que dura la caché de autenticación.
expired_api_key
Declarado, no se emite: hoy las claves no caducan solas.
402 · insufficient_credit
insufficient_credit
No hay saldo. POST /v1/transcripts estima el coste y devuelve esto antes de
procesar, así que no se gasta nada.
Para el lote y recarga. Reintentar no arregla nada. Configura el aviso de saldo bajo en app.callsist.com/billing: se manda una sola vez al cruzar el umbral hacia abajo, así que un lote de cuatrocientas llamadas por debajo del umbral produce un correo, no cuatrocientos.
spend_cap_reached
Declarado, no se emite todavía.
403 · permission_error
missing_scope
La clave no tiene el permiso que la ruta exige. param dice cuál falta.
También es lo que sale si tu IP está fuera de la lista blanca de la clave, con
param: "ip_allowlist". Es el error más desconcertante de la API: si una clave que
funcionaba deja de funcionar desde una máquina nueva, mira la lista blanca antes que los
scopes.
ip_not_allowed
Declarado, no se emite nunca. El caso que describe sale como missing_scope con
param: "ip_allowlist".
404 · not_found_error
resource_not_found
El recurso o el modelo no existen. Vale también para una transcripción de otra organización: no se distingue «no existe» de «no es tuya», a propósito.
409 · conflict_error
idempotency_key_reused
Misma Idempotency-Key, cuerpo distinto, dentro de la ventana de 24 h. Con la misma
clave y el mismo cuerpo se devuelve la respuesta original y la cabecera
Idempotency-Replayed: true, sin cobrar de nuevo.
413 · payload_too_large
file_too_large
Más de 2 GB. Se rechaza por Content-Length antes de leer el cuerpo.
415 · unsupported_media_type
unsupported_audio_format
Formatos admitidos: wav, mp3, flac, mpga, oga, ogg, m4a, mp4.
422 · unprocessable_audio
Los tres están declarados y ninguno se emite hoy: un audio inservible acaba en una
transcripción con status: "failed" o con el aviso asr_no_segments, no en un 422.
Están documentados porque el código puede empezar a emitirlos sin ser un cambio
rompedor.
audio_corrupt
El fichero no se puede decodificar. No reintentar.
audio_silent
No hay voz en el audio.
audio_too_short
Demasiado corto para transcribir.
429 · rate_limit_error
rate_limit_exceeded
Más de 300 peticiones por minuto y por clave. Espera los segundos de Retry-After.
El cubo es por clave, no por organización: dos claves distintas son dos cubos. Y el sondeo de estado consume del mismo cubo que las llamadas de negocio si van con la misma clave. Ver Lotes y límites.
concurrency_limit_exceeded
Más de 32 transcripciones en vuelo por organización — todo lo que esté en queued o
processing. Viene con Retry-After: 30.
500 · api_error
internal_error
Fallo nuestro. Reintentar con espera creciente. No se factura.
503 · service_unavailable
upstream_unavailable
Una dependencia no responde. Reintentar con espera creciente. No se factura.
queue_saturated
Declarado, no se emite. La saturación se manifiesta como espera en la cola, no como error.