Transcrição de áudio
Converta fala em texto: como enviar o áudio, o que a resposta traz, os limites e o custo por minuto.
Atualizado em 10 de ago. de 2026
O hinow/hivox transforma fala em texto. Você manda o arquivo — ou a URL dele — e recebe a transcrição e a duração do áudio.
Ele responde em POST https://api.hinow.ai/v1/audio/transcriptions, com a mesma chave e a mesma base URL do resto da API. O preço é por minuto de áudio: US$ 0,05 por minuto, independente do tamanho do arquivo ou do idioma falado.
O arquivo vai como file, em multipart/form-data — o mesmo formato que o SDK da OpenAI já envia:
curl https://api.hinow.ai/v1/audio/transcriptions \
-H "Authorization: Bearer $HINOW_API_KEY" \
-F "model=hinow/hivox" \
-F "file=@reuniao.mp3"import os, requests
with open("reuniao.mp3", "rb") as audio:
resposta = requests.post(
"https://api.hinow.ai/v1/audio/transcriptions",
headers={"Authorization": f"Bearer {os.environ['HINOW_API_KEY']}"},
files={"file": audio},
data={"model": "hinow/hivox"},
)
resposta.raise_for_status()
print(resposta.json()["text"])import { readFile } from "node:fs/promises";
const formulario = new FormData();
formulario.append("model", "hinow/hivox");
formulario.append(
"file",
new Blob([await readFile("reuniao.mp3")], { type: "audio/mpeg" }),
"reuniao.mp3",
);
const resposta = await fetch("https://api.hinow.ai/v1/audio/transcriptions", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.HINOW_API_KEY}` },
body: formulario,
});
const { text, duration } = await resposta.json();
console.log(duration, text);package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"mime/multipart"
"net/http"
"os"
)
func main() {
arquivo, err := os.Open("reuniao.mp3")
if err != nil {
panic(err)
}
defer arquivo.Close()
var corpo bytes.Buffer
formulario := multipart.NewWriter(&corpo)
formulario.WriteField("model", "hinow/hivox")
parte, err := formulario.CreateFormFile("file", "reuniao.mp3")
if err != nil {
panic(err)
}
if _, err := io.Copy(parte, arquivo); err != nil {
panic(err)
}
formulario.Close()
req, _ := http.NewRequest("POST", "https://api.hinow.ai/v1/audio/transcriptions", &corpo)
req.Header.Set("Authorization", "Bearer "+os.Getenv("HINOW_API_KEY"))
req.Header.Set("Content-Type", formulario.FormDataContentType())
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
var r struct {
Text string `json:"text"`
Duration float64 `json:"duration"`
}
if err := json.NewDecoder(res.Body).Decode(&r); err != nil {
panic(err)
}
fmt.Println(r.Duration, r.Text)
}A resposta de um diálogo de 8,5 segundos:
{
"duration": 8.5435,
"text": "Bom dia, Maria. Tudo bem? Tudo, obrigada. E você? Também estou bem. Obrigado. Tchau, João."
}São dois campos, e nada além deles:
text— a transcrição, com pontuação, em um parágrafo corrido.duration— a duração do áudio em segundos. É a base da cobrança.
O custo não vem na resposta
A conta sai do duration: US$ 0,05 por minuto, proporcional. Os 8,54 segundos acima custaram US$ 0,0071. Guarde o duration de cada chamada se você precisa reconciliar consumo.
As duas formas levam ao mesmo resultado. Mande o arquivo quando ele está na sua máquina ou no seu servidor; mande a URL quando o áudio já está publicado em algum lugar e você não quer trafegá-lo duas vezes.
curl https://api.hinow.ai/v1/audio/transcriptions \
-H "Authorization: Bearer $HINOW_API_KEY" \
-F "model=hinow/hivox" \
-F "file=@reuniao.mp3"curl https://api.hinow.ai/v1/audio/transcriptions \
-H "Authorization: Bearer $HINOW_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "hinow/hivox",
"parameters": { "audio": "https://exemplo.com/gravacoes/reuniao.mp3" }
}'A URL precisa ser pública de verdade
Quem baixa o arquivo é o serviço, não você: uma URL que exige sessão, cabeçalho ou assinatura falha — e falha como 502 de provedor, sem dizer que o problema foi o download. Em teste, um arquivo que transcrevia normalmente enviado como file deu 502 quando passado por URL, porque a origem recusou o download. Na dúvida, mande o arquivo.
| Formato | Resultado |
|---|---|
.mp3 | Transcreve |
.wav | Transcreve |
.ogg | Transcreve |
.m4a | **502** — converta antes de enviar |
Um ffmpeg -i entrada.m4a saida.mp3 resolve o caso do m4a, que é o formato que sai da maioria dos gravadores de celular — vale prever isso no seu fluxo de upload.
| Duração do áudio | Tempo da chamada |
|---|---|
| 8,6 s | 1,07 s |
| 60,5 s | 4,59 s |
Na ordem de treze vezes mais rápido que o tempo real: uma reunião de uma hora leva perto de cinco minutos. A chamada é síncrona e segura a conexão até o fim.
Áudio longo é trabalho de fila
Para arquivos de mais de alguns minutos, não transcreva dentro de uma requisição do seu usuário: coloque numa fila, transcreva em segundo plano e avise quando terminar. Timeout curto de cliente HTTP é a causa mais comum de "transcrição que falhou" e que na verdade rodou e foi cobrada.
US$ 0,05 por minuto de áudio, proporcional ao duration. Uma hora de gravação custa US$ 3,00; cem chamadas de atendimento de cinco minutos, US$ 25,00.
O preço não muda com o idioma, com o formato do arquivo nem com o tamanho em bytes — um wav de 50 MB e um mp3 de 500 KB com a mesma duração custam o mesmo. Comprimir antes de enviar economiza banda e tempo de upload, não dinheiro de API.
Vale saber antes de desenhar a sua tela:
- Sem marcação de tempo. Não há
segmentsnem timestamps por trecho — não dá para montar legenda sincronizada nem pular para o minuto em que uma palavra foi dita. - Sem separação de quem fala. O texto vem corrido, com as falas de todos misturadas. Diálogo de duas pessoas vira um parágrafo só.
- Sem o idioma detectado. A transcrição sai no idioma falado, mas a resposta não informa qual foi.
- Sem grau de confiança. Não há como saber, pela resposta, se um trecho foi bem entendido.
Parâmetros aceitos e ignorados
language e response_format são aceitos sem erro e não mudam nada: language=en num áudio em português devolveu a transcrição em português, e response_format=verbose_json devolveu o mesmo corpo de sempre. Não construa lógica em cima deles.
Os erros deste endpoint trazem um envelope próprio, com code legível, num_code estável e um details que costuma dizer exatamente o que fazer:
{
"success": false,
"error": {
"code": "MISSING_AUDIO",
"num_code": 4003,
"message": "Audio is required",
"details": "send the file as multipart 'file', or a URL in parameters.audio"
},
"request_id": "51d1bf35-5e04-44e1-818a-1b34cc6fb5c1"
}| Situação | code | HTTP |
|---|---|---|
Sem model no corpo | REQUEST_MISSING_FIELD (3002) | 400 |
| Modelo que não é de transcrição | INVALID_MODEL_CATEGORY (4001) | 400 |
Multipart sem a parte file | INVALID_AUDIO_UPLOAD (4002) | 400 |
| Nem arquivo nem URL | MISSING_AUDIO (4003) | 400 |
| Formato não suportado, ou URL que não baixou | PROVIDER_FAILED (5001) | 502 |
Guarde o request_id
Todo erro traz um request_id. É por ele que se rastreia uma chamada específica no suporte — grave-o no seu log junto do erro, não só a mensagem.
O envio em multipart é o mesmo: troque a baseURL para https://api.hinow.ai/v1, use a sua chave HINOW e o model para hinow/hivox.
import os
from openai import OpenAI
cliente = OpenAI(
base_url="https://api.hinow.ai/v1",
api_key=os.environ["HINOW_API_KEY"],
)
with open("reuniao.mp3", "rb") as audio:
transcricao = cliente.audio.transcriptions.create(model="hinow/hivox", file=audio)
print(transcricao.text)import OpenAI from "openai";
import { createReadStream } from "node:fs";
const cliente = new OpenAI({
baseURL: "https://api.hinow.ai/v1",
apiKey: process.env.HINOW_API_KEY,
});
const transcricao = await cliente.audio.transcriptions.create({
model: "hinow/hivox",
file: createReadStream("reuniao.mp3"),
});
console.log(transcricao.text);O SDK espera campos que não vêm
O objeto devolvido tem text e duration; os demais campos do tipo da OpenAI chegam vazios. Se o seu código lê language ou segments, trate a ausência.

