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 a unas IPs
Cada clave 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 |
Los tres corren en paralelo sobre el mismo audio, así que pedir los tres
tarda casi lo mismo que pedir uno. Cada uno se cobra aparte, y
solo si se ejecuta: si un análisis falla, la transcripción llega igual y
la respuesta trae un array errors diciendo cuál faltó — y ese no se
factura.
sentiment necesita plan Developer o superior;
profile y diarize, cualquier plan con inteligencia de
audio. Un nombre que no sea uno de los tres devuelve 400 con la lista
válida, 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 — los mismos para transcribir y para analizar. webm
es lo que graba un navegador y m4a lo que graba un móvil, así que
ambos sirven tal cual.
Audio de salida (response_format de voz): wav,
mp3, opus, flac y pcm.
pcm es PCM crudo sin cabecera, así que por la webapp no se ofrece
—no lo reproduce un navegador— y 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 400 MB por petición y 3 horas de audio, con un tope de 100 MB de fichero en transcripción. Un WAV de 3 horas pesa unos 346 MB y no pasa ese tope: para audios largos, envíelo comprimido.
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
Voces estándar disponibles con model: tts-1:
alloy · echo · fable · nova ·
onyx · shimmer
El catálogo ampliado está en revisión; se publicará cuando esté cerrado.
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,032673 | 117,6 |
| Voz estándar | segundo de audio generado | 0,021004 | 75,6 |
| Voz clonada | segundo de audio generado | 0,406748 | 1.464,3 |
| 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,080000 | 288,0 |
| Resumen (LLM) | token de entrada | 0,001605 | — |
| Resumen (LLM) | token de salida | 0,080650 | — |
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 79,22 2.424,5 s x 0,032673
voz 43,18 2.055,8 s x 0,021004 (el inglés sale ~15 % más corto)
traducción 193,96 2.424,5 s x 0,080000
──────
316,36 créditos
Planes y límites
| Plan | €/mes | Créditos | Concurrencia | Voz alta calidad | Clonado | Resumir | SLA |
|---|---|---|---|---|---|---|---|
| Free | 0 | 500 | 1 | — | — | — | — |
| Startup | 19 | 7.500 | 3 | sí | sí | sí | — |
| Developer | 99 | 50.000 | 15 | sí | sí | sí | — |
| Professional | 299 | 200.000 | 50 | sí | sí | sí | 95,0 % |
| Business | 999 | 800.000 | 150 | sí | sí | sí | 99,0 % |
| Enterprise | a medida | a medida | a medida | 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.
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.
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 servidor mantiene la conexión hasta 7200 segundos, y 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.
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.
/health y el identificador de petición cubren lo
que de verdad se necesita para resolver un problema concreto.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 |
|---|---|---|
| Webhooks | Que te avisemos al terminar un trabajo largo, en vez de mantener la conexión abierta | Por decidir |
| Diccionario de pronunciación | Decirle al motor cómo se pronuncian nombres propios, marcas y siglas | Por decidir |
| Página pública de estado | Histórico de disponibilidad e incidencias | En camino |
| 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.