Autenticación
Cabecera Authorization: Bearer sk-echo-... en todas las peticiones. La clave
se muestra una sola vez al crearla: guárdala. Si la pierdes, revócala y crea otra.
Restringir una clave de API a unas IPs
Cada clave de API puede limitarse a las direcciones desde las que tiene sentido que se use. Si tu integración vive en un servidor con IP fija, una clave robada deja de servir de nada fuera de él.
Se configura en tu cuenta, en la columna IPs permitidas de cada clave. Se admiten direcciones sueltas y redes:
203.0.113.7, 198.51.100.0/24, 192.0.2.10
En blanco, la clave funciona desde cualquier sitio, que es el comportamiento por defecto.
Una petición desde una IP que no está en la lista recibe 403 con el código
ip_not_allowed y, en el cuerpo, la IP que hemos visto — que es justo lo que
necesitas para añadirla si te has dejado una:
{
"error": "ip_not_allowed",
"message": "This API key is restricted to a list of IP addresses and this request does not come from one of them",
"client_ip": "203.0.113.55"
}
403, no un 401. La clave es buena;
lo que no vale es el sitio desde el que llama. Distinguirlo importa: un
401 te haría rotar una clave que estaba perfectamente.La restricción cubre todos los endpoints autenticados, incluido
/v1/usage/last. Quien roba una clave no siempre quiere gastarla; a veces le
basta con ver cuánto gasta su dueño.
client_ip que te devuelve el
403, y añade esa.Análisis en la misma petición
Una transcripción puede traer análisis de voz sin subir el audio otra vez. Se piden en la cadena de consulta, separados por comas:
curl https://api.uttera.ai/v1/audio/transcriptions?extras=sentiment,profile,diarize \
-H "Authorization: Bearer $UTTERA_API_KEY" \
-F file=@grabacion.m4a \
-F model=whisper-1
| Extra | Devuelve | En la respuesta |
|---|---|---|
sentiment | tono emocional | sentiment |
profile | perfil del hablante (edad, género) | profile |
diarize | quién habla y cuándo | diarize |
entities | entidades del texto: personas, lugares, importes, identificadores… | entities |
redact | enmascara los datos personales del texto | reemplaza text |
Los tres primeros —sentiment, profile, diarize—
corren en paralelo sobre el mismo audio, así que pedir los tres tarda casi lo mismo
que pedir uno. entities y redact trabajan sobre el texto ya
transcrito, así que corren después, se cobran por carácter en vez de por segundo, y no
les afecta el formato del audio. Con redact, el campo text de la
respuesta llega ya enmascarado; están explicados en Entidades y
redacción. Cada análisis se cobra aparte y solo si se ejecuta: si uno falla, la
transcripción llega igual y la respuesta trae un array errors diciendo cuál
faltó — y ese no se factura.
sentiment y entities necesitan plan Developer o
superior; redact, Professional o superior; profile y
diarize, cualquier plan con inteligencia de audio. Un nombre que no sea uno de
los válidos devuelve 400 con la lista, no una transcripción silenciosamente sin
análisis.Para sentiment con nivel por segmentos o dimensional (valencia,
activación, dominancia), use el endpoint suelto
/v1/audio/sentiment: en extras va siempre el nivel
global.
Formatos e idiomas
Audio de entrada: wav, mp3, flac,
ogg, opus, aiff, m4a y
webm. webm es lo que graba un navegador y m4a
lo que graba un móvil, así que ambos sirven tal cual.
webm y m4a se
decodifican en el nodo igual que el resto, sin que tenga que convertirlos usted.Audio de salida (response_format de voz): wav,
mp3, opus, flac y pcm.
pcm es PCM crudo sin cabecera. En el Estudio se reproduce con un
reproductor dedicado (el botón ▶ Reproducir, no el normal); al usarlo por
API hay que decirle al decodificador los cuatro parámetros, porque el fichero no
los lleva:
| Voz | Frecuencia | Muestra | Canales | Orden |
|---|---|---|---|---|
| estándar | 24 000 Hz | 16 bits con signo | 1 (mono) | little-endian |
| HD | 48 000 Hz | 16 bits con signo | 1 (mono) | little-endian |
La frecuencia es la nativa de cada voz y no se remuestrea: la HD genera
a 48 kHz y se entrega tal cual. Lo único que cambia entre los dos es
la frecuencia; decodificarlo con la que no toca no suena peor, suena al doble o
a la mitad de velocidad. Con wav, flac u
opus esto no aplica: el fichero lo declara solo.
# voz estándar
ffmpeg -f s16le -ar 24000 -ac 1 -i voz.pcm voz.wav
# voz HD
ffmpeg -f s16le -ar 48000 -ac 1 -i voz.pcm voz.wav
Cualquier otro valor de response_format devuelve 422 con
la lista válida.
Tamaño: hasta 250 MB por petición y 4 horas de audio. Un WAV sin comprimir de 2 horas no cabe: para audios largos, envíelo comprimido. El detalle, en tamaños y duración.
Transcripción: detecta el idioma automáticamente y cubre los que soporta Whisper.
Voz: depende del motor, y la diferencia es grande. La voz estándar
(tts-1) habla los nueve de la tabla de abajo. La voz de alta calidad
(tts-1-hd) habla unos 30 —además de esos nueve, alemán, ruso, polaco,
neerlandés, los nórdicos, griego, turco, árabe, coreano y varios del sudeste asiático,
entre otros— y no hace falta declarar el idioma: se deduce del texto. Está explicado en
Tres voces, no dos.
Traducción: ~50 idiomas de texto. La cadena sintetiza con la voz estándar, así que con voz son estos nueve:
| Código | Idioma | Código | Idioma |
|---|---|---|---|
en | inglés | it | italiano |
en-gb | inglés británico | ja | japonés |
es | español | pt | portugués |
fr | francés | zh | chino |
hi | hindi |
Catálogo de voces
Las seis voces compatibles con OpenAI, disponibles con model: tts-1:
alloy · echo · fable · nova ·
onyx · shimmer
Pero el catálogo es bastante más largo, y se consulta por la API en vez de copiarlo aquí: así lo que lees es lo que hay servido en este momento.
GET /v1/audio/voices
curl https://api.uttera.ai/v1/audio/voices \
-H "Authorization: Bearer $UTTERA_API_KEY"
{
"voices": ["adam", "alex", "alex-pt", "alice", "alloy", …],
"catalog": [
{"name": "adam", "language": "en"},
{"name": "alex", "language": "es"},
{"name": "alex-pt", "language": "pt"},
…
]
}
voices son los nombres a secas, para rellenar un desplegable;
catalog añade el idioma de cada una. language puede venir
a null en las voces que no son de un idioma concreto. Una voz que no
esté en esta lista devuelve 422.
Créditos
Cada servicio cobra por lo que consume. Estos son los coeficientes vigentes:
| Servicio | Se cobra por | Créditos | Una hora de audio |
|---|---|---|---|
| Transcribir | segundo de audio de entrada | 0,025422 | 91,5 |
| Voz estándar | segundo de audio generado | 0,027626 | 99,5 |
| Voz clonada | segundo de audio generado | 0,385902 | 1.389,2 |
| Tono | segundo de audio | 0,005090 | 18,3 |
| Perfil del hablante | segundo de audio | 0,003464 | 12,5 |
| Interlocutores | segundo de audio | 0,020938 | 75,4 |
| Traducción | segundo de audio de entrada | 0,040000 | 144,0 |
| Resumen (LLM) | token de entrada | 0,001605 | — |
| Resumen (LLM) | token de salida | 0,080650 | — |
| Entidades y redacción | carácter de texto | 0,000500 | — |
Cómo se compone cada servicio
| Servicio | Fórmula |
|---|---|
| Transcribir | STT |
| Transcribir + tono | STT + tono |
| Voz | TTS sobre los segundos generados |
| Traducir | STT + TTS del audio generado + recargo de traducción |
| Resumir | STT + perfil + interlocutores + tokens del modelo |
Ejemplo real
Una grabación de 40 minutos (2.424 s) traducida al inglés con voz:
transcripción 61,64 2.424,5 s x 0,025422
voz 43,18 2.055,8 s x 0,021004 (el inglés sale ~15 % más corto)
traducción 96,98 2.424,5 s x 0,040000
──────
201,80 créditos
Planes y límites
| Plan | €/mes | Créditos | Concurrencia | Voz alta calidad | Clonado | Resumir | Entidades | Redacción | Capítulos | SLA |
|---|---|---|---|---|---|---|---|---|---|---|
| Free | 0 | 750 | 1 | — | — | — | — | — | — | — |
| Startup | 19 | 7.500 | 3 | sí | sí | sí | — | — | — | — |
| Developer | 99 | 50.000 | 15 | sí | sí | sí | sí | — | sí | — |
| Professional | 299 | 200.000 | 50 | sí | sí | sí | sí | sí | sí | 95,0 % |
| Business | 999 | 800.000 | 150 | sí | sí | sí | sí | sí | sí | 99,0 % |
| Enterprise | a medida | a medida | a medida | sí | sí | sí | sí | sí | sí | 99,9 % |
Los créditos se renuevan en la fecha de tu suscripción, no el día 1. Si cambias de plan a uno menor, conservas los créditos ya pagados hasta que venza el periodo.
Esta misma tabla se sirve en JSON y sin clave, para que un programa —o un agente que se esté configurando solo— pueda leer los límites antes de que nadie se registre:
curl https://api.uttera.ai/v1/plans
{"plans": {"free": {"price_eur_per_month": 0, "credits_per_month": 500,
"max_concurrent": 1, "rate_limits": {"stt": 1, "tts": 1, "sfx": 0,
"intelligence": 0}, "summary_allowed": false, "voice_clone_allowed": false, …}, …}}
Es la misma fuente que rellena la tabla de arriba: si algo cambia, cambian las dos a la vez.
Límites por segundo
| Plan | Voz | Transcripción | Análisis |
|---|---|---|---|
| Free | 1 | 1 | — |
| Startup | 5 | 20 | 5 |
| Developer | 100 | 400 | 50 |
| Professional | 250 | 1.000 | 200 |
| Business | 500 | 2.000 | 500 |
Cada respuesta lleva X-RateLimit-Remaining-Second y
X-Credits-Remaining-Monthly para que no tengas que adivinar.
Tamaños y duración máximos
| Qué | Límite |
|---|---|
| Tamaño del fichero que envías | 250 MB |
| Duración del audio | 4 horas |
| Pronunciar: tamaño de la muestra | 1 MB — es un alumno leyendo una frase, segundos de audio |
| Resumir: duración de la grabación | las mismas 4 horas — no tiene un límite propio más corto |
Texto a voz, voz estándar (tts-1) | 250.000 caracteres — del orden de cuatro a cinco horas de voz, según lo denso que sea el texto |
| Texto a voz, voz estándar en streaming | sin límite de longitud |
Texto a voz, voz de alta calidad y voz clonada (tts-1-hd) | 2.000 caracteres, unos dos minutos y medio |
Grabaciones largas: cómo las resume
Una grabación larga no cabe de una vez en el contexto del modelo. En vez de resumir un trozo, la partimos, resumimos cada pieza y luego fusionamos — y la fusión no es un resumen de resúmenes, que perdería información dos veces: se le pide que ordene y una las piezas, conservando todas las cifras, fechas y nombres.
Así que el resumen no tiene un límite propio más corto: lo que se puede transcribir se puede resumir. En una prueba interna, de punta a punta sobre una grabación de cuatro horas con tono, perfil y diarización: seis minutos, entero, con el principio y el final presentes.
Si alguna vez un resumen volviera cortado, la respuesta lo dice en truncated. No
es algo que debas ver, y preferimos decírtelo a darte un resumen recortado que se lee como uno
entero.
Cuatro horas tienen que caber en 250 MB
Los dos límites son independientes y hay que cumplir los dos. Para cuatro horas completas, eso significa no pasar de 145 kbps:
| Formato | Lo que cabe en 250 MB |
|---|---|
| mp3 a 64 kbps | 9 h 06 min |
| mp3 a 128 kbps | 4 h 33 min |
| mp3 a 160 kbps | 3 h 38 min |
| mp3 a 256 kbps | 2 h 17 min |
| wav 16 bits, mono, 16 kHz | 2 h 17 min |
| wav 16 bits, estéreo, 44,1 kHz | 24 min |
Para voz, un mp3 de 64 kbps no pierde nada que nos importe y te deja sitio de sobra. Si envías wav sin comprimir, cuenta con que cuatro horas no caben.
Texto a voz: el límite depende de la voz
No hay un límite único, porque las dos voces las genera maquinaria distinta:
Voz estándar (tts-1). Se puede pedir de dos formas:
- Respuesta completa (
/v1/audio/speech): devolvemos el audio entero cuando está terminado. Como tiene que existir todo a la vez, el tope son 250.000 caracteres —del orden de cuatro a cinco horas de voz—. El «del orden de» es a propósito: cuánto audio da un carácter depende mucho del texto, y medido sobre prosa real va de 12,6 a 17,5 caracteres por segundo. El tope es del texto, no de la duración. - Streaming (
/v1/audio/speech/stream): enviamos el audio según se genera. Aquí no hay límite de longitud, porque no se acumula nada.
Para una locución larga, el streaming sigue siendo mejor camino. Empiezas a oír el resultado en segundos en vez de esperar al final, y no hay que meter nada entero en una sola respuesta.
Voz de alta calidad y voz clonada (tts-1-hd). El tope es
2.000 caracteres por petición, unos dos minutos y medio de voz. Es bastante menos, y es
una limitación del modelo que da esa voz, no una decisión comercial. Para esta voz el
streaming no sirve para textos largos: úsala en fragmentos de un par de miles de caracteres
y encadénalos.
413 antes
de generar, en lugar de un audio incompleto. Trocea el texto en fragmentos más cortos y
encadénalos.Errores
| Código | Qué significa | Qué hacer |
|---|---|---|
400 | El fichero no se puede decodificar, o un parámetro no vale. | El motivo viene en detail. |
401 | Clave ausente, mal formada o revocada. | Revisa la cabecera Authorization. |
402 | Bolsa de créditos agotada. | Espera a la renovación o sube de plan. |
403 | Tu plan no incluye ese servicio. | El mensaje dice qué plan lo incluye. |
413 | Fichero demasiado grande. | Trocea o comprime el audio. |
422 | Petición válida pero imposible de servir. | Por ejemplo, audio en un idioma sin voz. No se cobra. |
429 | Demasiadas peticiones por segundo. | Respeta Retry-After. |
502 503 | Fallo temporal de un nodo. | Se reintenta solo una vez. Reintenta tú pasados unos segundos. |
Consultar el consumo
El cargo se calcula después de enviarte la respuesta, así que no viene dentro de ella. Para saber lo que te ha costado exactamente una petición:
GET /v1/usage/last
GET /v1/usage/last?endpoint=/v1/summarize
Devuelve los créditos cobrados y el desglose por tramo:
{
"endpoint": "/v1/summarize",
"credits": 108.978,
"breakdown": { "stt": 3.1255, "diarize": 2.0029,
"profile": 0.1946, "llm": 103.655 },
"audio_seconds": 95.66,
"input_tokens": 2776, "output_tokens": 1230
}
Guarda los diez últimos cargos durante una hora. Es para comprobar al momento, no un histórico de facturación.
Cuánto tarda cada cosa
Números medidos, no promesas. Varían con el nodo que atienda y con la carga del momento:
| Operación | Tiempo típico |
|---|---|
| Transcribir 100 minutos de audio | 10 a 35 s |
| Transcribir una grabación de 40 minutos | menos de 30 s |
| Voz estándar, una frase | décimas de segundo |
| Voz clonada | Bastante más: la muestra hay que procesarla |
| Acierto de caché | milisegundos |
| Resumen de una grabación larga | El más lento de sus tramos, no la suma: corren en paralelo |
Lo que de verdad hay que configurar bien es el tiempo de espera de tu cliente. El fallo más común al integrar es un cliente con 30 segundos por defecto que corta trabajos que iban perfectamente. Está explicado en Integración.
🔴 Máximo síncrono: 10 minutos. Una petición síncrona
(POST /v1/summarize sin async) está pensada para completarse en
10 minutos como mucho; configura el tiempo de espera de tu cliente en
600 segundos. Casi todo cabe de sobra: transcribir y resumir una grabación normal es
cuestión de segundos a minutos. Pero un informe de inteligencia
(?mode=intelligence, el grafo de evidencia) sobre una grabación larga y
densa —muchas afirmaciones que anclar— puede acercarse o pasar de esos 10 minutos, porque
su coste crece con lo que hay que extraer, no con la duración del audio. Para esos
trabajos, usa el modo asíncrono (?async=1): envías
el trabajo, recibes un job_id al instante y recoges el resultado con
GET /v1/jobs/<id> cuando esté, sin sostener una conexión que acabaría
cortándose. Si una petición síncrona supera los 10 minutos, el servidor la corta y
responde 504 con {"error":"report_timeout"} sin cobrarte
—detéctalo y reenvía el trabajo en asíncrono—. En el Estudio, el panel ya espera
hasta esos 10 minutos.
Versionado y cambios
Lo que integras hoy tiene que seguir funcionando mañana. Este es el compromiso:
Para que eso signifique algo, hace falta decir qué cuenta como romper y qué no:
| Rompe (seis meses de preaviso) | No rompe (puede pasar cualquier día) |
|---|---|
| Quitar un endpoint o un parámetro | Añadir un endpoint nuevo |
| Quitar o renombrar un campo de la respuesta | Añadir un campo a la respuesta |
| Cambiar el tipo o el significado de un campo | Añadir un parámetro opcional |
| Cambiar el valor por defecto de un parámetro | Añadir una voz o un idioma |
| Hacer obligatorio algo que era opcional | Añadir una cabecera de respuesta |
| Cambiar un código de error por otro distinto | Mejorar el texto de un mensaje de error |
De ahí sale la regla práctica para tu código: ignora los campos que no conozcas en vez de fallar al encontrarlos. Un cliente que revienta porque la respuesta trae una clave nueva se romperá solo, sin que nadie haya roto nada.
Los precios son caso aparte: no son la interfaz, pero sí tu factura. Una subida de coeficientes se anuncia con treinta días y no se aplica a un ciclo ya pagado. Una bajada se aplica en cuanto está.
Estado del servicio
Si algo va mal, lo primero es saber si es tuyo o nuestro.
GET https://api.uttera.ai/health responde sin necesidad de clave y dice si
la API está en pie. Es la comprobación que puedes automatizar.
curl -s https://api.uttera.ai/health
Cada respuesta lleva además una cabecera X-Request-Id. Guárdala cuando
algo falle: con ese identificador podemos decirte exactamente qué pasó con tu petición,
y sin él la conversación empieza por reconstruir cuál era.
Para cualquier incidencia, escríbenos con el X-Request-Id, la hora
aproximada y qué esperabas que pasara.
En estudio
Cosas que nos piden, que tienen sentido y que todavía no están. Las ponemos aquí porque enterarte de que algo no existe después de integrarlo es peor que saberlo ahora:
| Qué | Para qué | Estado |
|---|---|---|
| Diccionario de pronunciación | Decirle al motor cómo se pronuncian nombres propios, marcas y siglas | Por decidir |
| Cuentas de servicio y varios usuarios | Que una empresa tenga varias personas y claves separadas bajo una misma cuenta | Después de la beta |
Si alguna de ellas te bloquea, dínoslo: lo que nos piden los clientes es lo que decide el orden.