Docs do Nodaro
DocumentaçãoReferência de nósModelosAgentes de IA (MCP)DesenvolvedoresSelf-hostingPesquisa
API REST

Voz e mídia

Vozes, troca de voz de um ou vários falantes, dublagem, importação de vídeo, legendas, cortes, ferramentas de áudio e publicação social via REST no Nodaro.

Os endpoints de voz e mídia expõem as ferramentas de voz e de mídia do Nodaro como REST simples. Eles cobrem catálogo de vozes, modificação de voz e troca de voz de vários falantes, dublagem, design de voz, importação de vídeo, legendas, cortes, ferramentas de áudio, transcrição e publicação em redes sociais. A maioria funciona como job: o POST retorna { jobId } na hora, você consulta periodicamente GET /v1/jobs/:id/status até o status ser completed e lê o resultado em output_data.

As rotas funcionam em todas as edições, com as exceções indicadas abaixo, e recebem um bearer token. Veja Autenticação e, para consultar periodicamente vários jobs de uma vez, Jobs. Para enviar arquivos locais, faça o upload deles primeiro; veja Envio de arquivos.

Vozes

MétodoCaminhoO que faz
GET/v1/voicesO catálogo de vozes prontas: nome, voice_id, gênero, sotaque e idade.
GET/v1/voices/libraryBusca na Biblioteca de vozes compartilhada, com search, gender, language, page, page_size e mais.
GET/v1/voice-clonesOs clones de voz que você fez antes de a clonagem ser descontinuada.
PATCH/v1/voice-clones/:idRenomeia ou edita um desses clones.
DELETE/v1/voice-clones/:idExclui um desses clones.
POST/v1/voice-clones, /v1/voice-clones/from-urlDescontinuadas. As duas retornam 410 voice_cloning_retired.

Sempre que uma rota aceita uma voz, passe o voice_id de uma voz do catálogo, o nome de uma voz pronta, como Rachel, ou o elevenlabsVoiceId de um clone. Os clones feitos antes da descontinuação continuam funcionando em todo lugar.

Um resultado da Biblioteca de vozes pode trazer recommendedProvider: o modelo de texto para fala em que a voz foi verificada. Quando o seu app não tem um seletor de modelo, envie esse valor como provider no Texto para fala (Text to Speech), para que a voz soe como na prévia. verifiedProviders lista todos os modelos em que a voz foi verificada; quando o seu app tem um seletor, substitua a escolha do usuário só quando ela não estiver nessa lista. hasMore, na resposta, controla o “carregar mais”.

import { createClient, StaticTokenAuth } from '@nodaro/sdk'

const client = createClient({
  baseUrl: 'https://app.nodaro.ai',
  auth: new StaticTokenAuth(process.env.NODARO_API_KEY!),
})

const { voices, hasMore } = await client.voices.searchLibrary({ search: 'deep', language: 'en' })
const voice = voices[0]
await client.nodes.run('text-to-speech', {
  text: 'Hello!',
  voice: voice.voice_id,
  voiceType: 'library',
  ...(voice.recommendedProvider ? { provider: voice.recommendedProvider } : {}),
})

Criar uma voz ou falar com uma voz descrita

MétodoCaminhoCorpoResultado
POST/v1/voice-design{ text, voiceDescription, model?, loudness?, guidanceScale?, seed?, quality?, shouldEnhance? }Uma prévia e um ID de voz reutilizável.
POST/v1/voice-remix{ text, voiceDescription }Fala na voz descrita, sem clonagem.

No Design de voz (Voice Design), text é uma frase de prévia de 100 a 1.000 caracteres, loudness vai de -1 a 1 e guidanceScale, de 0 a 100. No Remix de voz (Voice Remix), text tem de 1 a 5.000 caracteres. Os dois retornam um job.

Mudar a voz de uma gravação

POST /v1/voice-changer substitui a voz de uma faixa de áudio, ou de um vídeo inteiro com fala, por uma voz de destino. Envie exatamente um entre audioUrl e videoUrl; quando você envia os dois, o vídeo prevalece. Em um vídeo, o Nodaro extrai o áudio, muda a voz e coloca o áudio de volta na imagem original, e o output_data do job traz videoUrl e audioUrl.

curl -X POST https://app.nodaro.ai/v1/voice-changer \
  -H "Authorization: Bearer $NODARO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "videoUrl": "https://cdn.nodaro.ai/uploads/talking.mp4", "voiceId": "Aria", "removeBackgroundNoise": false }'
const { jobId } = await client.voices.change({
  videoUrl: 'https://cdn.nodaro.ai/uploads/talking.mp4',
  voiceId: 'Aria',
})
nodaro voice changer --voice Aria --video https://cdn.nodaro.ai/uploads/talking.mp4 --watch
CampoO que faz
voiceIdObrigatório. A voz de destino.
audioUrl ou videoUrlObrigatório, um dos dois. A gravação a modificar.
modelO modelo de fala para fala.
stability, similarityBoostDe 0 a 1. O quanto a interpretação é estável e o quanto a voz se aproxima da voz de destino.
styleDe 0 a 1, padrão 0. Exagera a interpretação, com algum custo em velocidade e estabilidade.
useSpeakerBoostAumenta a semelhança com a voz de destino, um pouco mais devagar.
seedUm inteiro que torna a saída repetível.
removeBackgroundNoisetrue retorna só a voz limpa; false mantém a música e os efeitos sob a nova voz.

Veja Modificador de voz (Voice Changer) para preços e dicas.

Trocar a voz de vários falantes

O Modificador de voz Pro (Voice Changer Pro) detecta cada falante de uma gravação e dá a cada um uma voz diferente, mantendo as palavras e o timing. Ele roda no Nodaro Cloud. Uma instalação self-hosted conectada ao Nodaro Cloud pode fazer a troca de voz em uma única chamada por meio dessa conexão; as etapas analyze e export exigem o próprio Nodaro Cloud. Veja Conectar ao Nodaro Cloud.

MétodoCaminhoO que faz
POST/v1/voice-changer-proTroca a voz de cada falante mapeado, como um vídeo pronto ou como stems separados.
POST/v1/voice-changer-pro/analyzeDetecta os falantes sem trocar as vozes. Só no Nodaro Cloud.
POST/v1/voice-changer-pro/exportRenderiza um vídeo pronto a partir da sua própria mixagem dos stems. Só no Nodaro Cloud.

Mapear vozes para os falantes

orderedVoices mapeia os falantes pela ordem de detecção: o falante 0 recebe a entrada 0, o falante 1 recebe a entrada 1, e assim por diante, com 1 a 8 entradas. Os falantes que passam do fim da lista mantêm a própria voz. Cada entrada é uma destas:

  • Um ID de voz, como "Rachel".
  • null, uma posição que mantém a voz original: esse falante mantém a própria voz, e os falantes seguintes ainda têm a voz trocada. Essas posições não custam nada, mas pelo menos uma entrada precisa ser uma voz.
  • Um objeto com configurações por falante: { voiceId, engine?, stability?, similarityBoost?, style?, useSpeakerBoost?, seed?, volumeMode?, volume? }. engine é sts (o padrão, fala para fala) ou v3, que interpreta a fala de novo a partir da transcrição com o ElevenLabs v3 e só aceita os valores 0; 0,5 e 1 em stability. volumeMode é match (o padrão), normalize ou manual, com volume de 0 a 200 por cento.

Antes de trocar as vozes, o Nodaro sempre separa as vozes da música e dos efeitos. O resto do corpo controla o resultado:

CampoO que faz
audioUrl ou videoUrlObrigatório, um dos dois. Em um vídeo, o áudio com as vozes trocadas volta para a imagem original.
preserveBackgroundMistura a música e os efeitos de volta sob as novas vozes. Padrão true.
separationQualityfast (o padrão, preserva mais da voz) ou best (uma separação mais fina).
removeBackgroundNoiseTambém remove o ruído do resultado.
musicVolumeMode, musicVolumeO nível do fundo mantido: match (o padrão), normalize ou manual, com 0 a 200 por cento.
voiceFxUma reverberação ou um eco só nas vozes: { preset, wetDryMix?, delayMs?, decay? }. As predefinições de reverberação, como room, hall ou church, usam wetDryMix; echo e custom usam delayMs e decay.
outputvideo (o padrão, o resultado pronto) ou stems (faixas secas, sem nivelamento, para a sua própria mixagem).
analysisO output_data de um job analyze anterior. A troca de voz reutiliza os falantes e os stems dessa análise, em vez de detectá-los de novo.

A troca de voz é cobrada por falante mapeado; analyze e export têm preços fixos. Veja os preços em Modificador de voz Pro.

O fluxo interativo: analyze, troca de voz em stems, export

A troca de voz em uma única chamada renderiza um vídeo pronto de uma vez. O fluxo interativo permite verificar os falantes antes de pagar pela troca de voz e mixar o resultado antes de renderizá-lo.

Detectar os falantes

POST /v1/voice-changer-pro/analyze com audioUrl ou videoUrl e, opcionalmente, separationQuality e suggestTitle. O output_data do job concluído traz vocalsUrl e backgroundUrl, já separados, e languageCode e languageProbability, detectados. A lista speakers dá, para cada falante, id, segments, firstStartSec, wordCount e um snippet. Ele também traz um suggestedTitle quando você pede um. Procure “falantes” que não são pessoas, como aplausos.

Trocar as vozes em stems

POST /v1/voice-changer-pro com output: "stems" e todo o output_data da análise como analysis. A troca de voz pula a detecção, então você pode trocar as vozes de novo, com outras vozes, sem pagar pela detecção outra vez.

Mixar e exportar

Defina o nível de cada stem na sua própria interface; isso não custa nada. Depois, envie POST /v1/voice-changer-pro/export com o videoUrl de origem e até 16 tracks, cada uma { url, gain, muted, kind? }. gain vai de 0 a 200, kind é voice ou background, e pelo menos uma faixa precisa estar com som. Um voiceFx opcional se aplica só às faixas de voz. O fluxo de vídeo é copiado, nunca codificado de novo, então a exportação corresponde à sua prévia. O output_data.videoUrl do job concluído é o resultado.

AUTH="Authorization: Bearer $NODARO_API_KEY"
VIDEO="https://cdn.nodaro.ai/uploads/panel.mp4"

# 1. Detect the speakers
JOB=$(curl -s -X POST https://app.nodaro.ai/v1/voice-changer-pro/analyze -H "$AUTH" \
  -H 'Content-Type: application/json' -d "{\"videoUrl\":\"$VIDEO\",\"suggestTitle\":true}" | jq -r .jobId)
# ...poll until completed, then keep the analysis
ANALYSIS=$(curl -s "https://app.nodaro.ai/v1/jobs/$JOB/status" -H "$AUTH" | jq .data.output_data)

# 2. Recast to stems: speaker 2 keeps their own voice
JOB=$(curl -s -X POST https://app.nodaro.ai/v1/voice-changer-pro -H "$AUTH" -H 'Content-Type: application/json' \
  -d "{\"videoUrl\":\"$VIDEO\",\"orderedVoices\":[\"Rachel\",null,\"Aria\"],\"output\":\"stems\",\"analysis\":$ANALYSIS}" | jq -r .jobId)

# 3. Export your mix
curl -s -X POST https://app.nodaro.ai/v1/voice-changer-pro/export -H "$AUTH" -H 'Content-Type: application/json' -d "{
  \"videoUrl\": \"$VIDEO\",
  \"tracks\": [
    { \"url\": \"<voice stem 0>\", \"gain\": 100, \"muted\": false },
    { \"url\": \"<voice stem 1>\", \"gain\": 90, \"muted\": false },
    { \"url\": \"<background stem>\", \"gain\": 70, \"muted\": false, \"kind\": \"background\" }
  ],
  \"voiceFx\": { \"preset\": \"hall\", \"wetDryMix\": 25 }
}"
const { jobId: analyzeJob } = await client.voices.analyze({ videoUrl, suggestTitle: true })
const analysis = (await client.jobs.get(analyzeJob)).output_data // once completed

const { jobId: recastJob } = await client.voices.recast({
  videoUrl,
  orderedVoices: ['Rachel', null, 'Aria'],
  output: 'stems',
  analysis,
})
const stems = (await client.jobs.get(recastJob)).output_data // once completed

await client.voices.exportMix({
  videoUrl,
  tracks: [
    { url: stems.tracks[0].url, gain: 100, muted: false },
    { url: stems.tracks[1].url, gain: 90, muted: false },
    { url: stems.backgroundUrl, gain: 70, muted: false, kind: 'background' },
  ],
  voiceFx: { preset: 'hall', wetDryMix: 25 },
})
nodaro voice analyze --video https://cdn.nodaro.ai/uploads/panel.mp4 --watch --json > analyze.json
jq .output_data analyze.json > analysis.json

nodaro voice recast --video https://cdn.nodaro.ai/uploads/panel.mp4 --voices Rachel,keep,Aria \
  --analysis-file analysis.json --output stems --watch

nodaro voice export --source https://cdn.nodaro.ai/uploads/panel.mp4 --tracks-file mix.json \
  --voice-fx hall --voice-fx-mix 25 --watch

Na CLI, a palavra keep em --voices cria uma posição que mantém a voz original.

Dublar para outro idioma

POST /v1/dubbing traduz e dubla uma faixa de áudio ou um vídeo inteiro, mantendo a voz de cada falante. Envie exatamente uma origem: audioUrl, videoUrl ou sourceUrl (um link público, como uma página do YouTube ou do TikTok, que o próprio modelo de dublagem busca). Um vídeo volta como vídeo dublado: output_data.videoUrl, mais a faixa dublada sozinha em output_data.audioUrl.

CampoO que faz
targetLanguageObrigatório. Um código ISO, por exemplo es ou pt-BR.
sourceLanguageO idioma falado. É detectado quando você o omite.
numSpeakers0 (o padrão) detecta os falantes; de 1 a 20 melhora a separação quando você sabe o número.
startTime, endTimeDubla só essa janela da origem, em segundos.
disableVoiceCloning, dropBackgroundAudioNão reproduz a voz própria de cada falante, ou descarta a música e os efeitos.
highestResolutionMantém a resolução de origem em um vídeo.
useProfanityFilter, targetAccent, watermarkUm filtro de palavrões, um sotaque para o idioma de destino e a marca-d’água do modelo de dublagem em um vídeo.

Uma dublagem é cobrada por minuto do trecho dublado, com mínimo de 1 minuto. O trecho pode ter até 30 minutos; um trecho mais longo retorna 413, então duble uma janela com startTime e endTime. Veja Dublagem (Dubbing).

POST /v1/download-video importa para o seu armazenamento um vídeo de rede social (YouTube, TikTok, Instagram, X ou Facebook) ou um link direto para um arquivo de vídeo. A rota retorna { downloadId }, não um ID de job. O arquivo pronto vai para a sua biblioteca.

CampoO que faz
urlObrigatório. A página ou o arquivo a importar.
maxHeightLimita a resolução, por exemplo 720. Omita para obter a melhor disponível.
sectionStartSec, sectionEndSecImporta só esse intervalo, em segundos, com cerca de 3 segundos a mais em cada ponta, porque o corte cai nos quadros-chave. Envie os dois ou nenhum, e corte o resultado para ter um corte exato.
requireAudioPor padrão, um resultado sem som falha, porque isso geralmente indica uma origem degradada. Envie false para aceitar um clipe sem som.

Acompanhe o download com GET /v1/download-video/progress/:downloadId, um fluxo de server-sent events. Mais ou menos a cada 500 ms, ele envia { phase, percent, videoUrl?, thumbnailUrl?, error? }, e termina em completed, com o videoUrl armazenado, ou em failed, com o error. Comece a ouvir assim que a importação começar, porque o progresso só fica guardado por pouco tempo depois que o download termina. No máximo 4 downloads ficam em andamento ao mesmo tempo por conta; um quinto retorna 429 too_many_downloads.

DL=$(curl -s -X POST https://app.nodaro.ai/v1/download-video \
  -H "Authorization: Bearer $NODARO_API_KEY" -H 'Content-Type: application/json' \
  -d '{ "url": "https://www.youtube.com/watch?v=VIDEO_ID", "maxHeight": 720 }' | jq -r .downloadId)

curl -sN https://app.nodaro.ai/v1/download-video/progress/$DL \
  -H "Authorization: Bearer $NODARO_API_KEY"
const { downloadId } = await client.media.downloadVideo({
  url: 'https://www.youtube.com/watch?v=VIDEO_ID',
  maxHeight: 720,
})
for await (const event of client.media.downloadVideoProgress(downloadId)) {
  console.log(`${event.phase} ${event.percent}%`)
  if (event.phase === 'completed') console.log('stored at', event.videoUrl)
}
nodaro media download "https://www.youtube.com/watch?v=VIDEO_ID" --max-height 720 --watch
nodaro media metadata "https://www.youtube.com/watch?v=VIDEO_ID"

Duas rotas relacionadas respondem na hora:

  • POST /v1/video-metadata com { url } lê a duração, o tamanho, o título e o status de transmissão ao vivo de um vídeo sem baixá-lo. Use essa rota para decidir se vale importar só um trecho.
  • POST /v1/save-to-storage com { mediaUrl, filename?, mediaType? } copia qualquer URL de mídia externa para o seu armazenamento, no servidor. A rota retorna um job.

Editar vídeo

MétodoCaminhoO que fazPreço
POST/v1/trim-videoCorta um vídeo em um intervalo.Cortar vídeo (Trim Video)
POST/v1/add-captionsEmbute legendas em um vídeo.Adicionar legendas (Add Captions)
POST/v1/still-to-videoUma imagem e uma faixa de áudio viram um MP4.0 créditos
POST/v1/slideshowDe 2 a 100 imagens e uma faixa de áudio opcional viram um MP4.0 créditos
POST/v1/video-overlayColoca de 1 a 20 camadas de imagem com tempo definido sobre um vídeo.22 créditos
POST/v1/media/processCorta ou recorta um arquivo armazenado e responde na hora.Grátis

Cortar um vídeo

POST /v1/trim-video recebe videoUrl e o intervalo na unidade que você preferir: startTime e endTime em segundos, trimStartFrames e trimEndFrames, trimStartSeconds e trimEndSeconds, ou keepFirstSeconds ou keepLastSeconds.

Embutir legendas

POST /v1/add-captions recebe videoUrl e as palavras da primeira fonte que encontra, nesta ordem: captions (entradas com tempo por palavra), transcript, text no estilo subtitle e, por fim, a transcrição automática da fala.

CampoO que faz
stylesubtitle (um bloco estático) ou um estilo cinético: word-highlight, karaoke, tiktok-words, word-pop ou bouncy.
textEm subtitle: a própria legenda, embutida como um bloco estático durante todo o vídeo. Em um estilo cinético: só o texto de reserva, usado quando a transcrição não encontra nada.
captionsEntradas com tempo por palavra, { text, startMs, endMs }, uma por palavra nos estilos cinéticos. As words de uma transcrição servem como estão.
auto_transcribe, transcribe_providerTranscreve a fala quando nada mais fornece as palavras. Um estilo cinético precisa de marcações de tempo por palavra: incredibly-fast-whisper (o padrão) ou elevenlabs-stt.
lookoutline (o padrão nos estilos cinéticos) ou clean (o padrão em subtitle).
maxWordsPerLineDe 1 a 20 palavras por linha, além do limite imposto pela largura do quadro. Com 1 ou 2, a leitura fica mais impactante.
highlightColor, animateSó nos estilos cinéticos; 400 em subtitle.
position, positionY, fontSize, fontFamily, fontWeight, color, backgroundColor, strokeColor, strokeWidth, uppercaseA aparência do texto.
segmentsDá a trechos do vídeo um estilo, um visual e uma posição próprios.

Uma subtitle de texto simples, sem estilização, é a renderização barata. Um estilo cinético, qualquer campo de estilização, legendas com tempo, a transcrição automática ou segments renderizam pelo preço mais alto e mantêm a taxa de quadros da origem. Veja todas as opções e os dois preços em Adicionar legendas.

Transformar imagens fixas em vídeo

  • POST /v1/still-to-video recebe { imageUrl, audioUrl, motion?, intensity?, resolution?, aspectRatio?, fps?, fit?, padColor? }. O vídeo dura o mesmo que o áudio; não existe campo de duração. motion é none (o padrão), zoom-in, zoom-out, pan-left, pan-right ou ken-burns, com intensity de 1 a 10. Veja Imagem fixa para vídeo (Still to Video).
  • POST /v1/slideshow recebe imageUrls (de 2 a 100), um audioUrl opcional, imageDurations (segundos por imagem, null para automático) ou perImageDuration, uma transition e os mesmos campos de aparência. Com áudio, a apresentação dura o mesmo que o áudio; as durações fixadas que não somam esse total são ajustadas proporcionalmente, e a saída do job avisa isso. Sem áudio, ela dura o número de imagens vezes perImageDuration, em silêncio. Veja Apresentação de slides (Slideshow).

As duas rotas renderizam no servidor, sem modelo de IA, e custam 0 créditos. resolution é 720p, 1080p ou 4K, fps é 24 ou 30, e fit: "contain" adiciona faixas com padColor em vez de cortar a imagem.

Sobrepor imagens a um vídeo

POST /v1/video-overlay coloca de 1 a 20 camadas de imagem sobre um vídeo em uma única renderização e mantém o áudio original intacto. Cada camada é { imageUrl, start, end?, preset?, corner?, anchor?, x?, y?, width?, height?, fit?, opacity?, animate?, zIndex? }. start e end são segundos; sem end, a camada dura até o fim do vídeo. preset é card, corner-badge ou full-frame, e uma posição ou um tamanho explícito o substitui. Uma camada sem nenhum dos dois é um selo de canto, no canto inferior direito, a menos que corner indique outro.

outputAspect (16:9, 9:16, 1:1 ou 4:5) muda o quadro, com baseFit e backgroundColor. O job retorna { videoUrl, thumbnailUrl, width, height, durationSec, warnings }. A rota custa 22 créditos por execução, qualquer que seja o número de camadas, e cada usuário pode enviar 30 requisições por minuto. Veja Sobreposição em vídeo (Video Overlay).

Cortar ou recortar um arquivo armazenado na hora

POST /v1/media/process corta ou recorta um arquivo que você armazenou e responde na mesma requisição, de graça. O corpo é { sourceUrl, type, trim?, crop?, format?, deleteSource? }: type é video ou audio, trim é { startTime, endTime }, crop é { x, y, width, height }, e format é mp4, webm, mp3, wav, m4a ou aac. A rota retorna { data: { url, thumbnailUrl, assetId, sizeBytes, mimeType, metadata } }. deleteSource: true exclui a origem depois, quando ela é sua e nada mais a usa.

Editar áudio

Cada rota retorna um job.

MétodoCaminhoCorpoO que faz
POST/v1/audio-separation{ audioUrl, mode?, quality? }Divide uma faixa: vocal_instrumental (o padrão) ou stems completos, com qualidade auto, fast ou best. Veja Separação de áudio (Audio Separation).
POST/v1/audio-isolation{ audioUrl }Mantém a voz principal e remove o fundo. Veja Extrator de voz (Voice Extractor).
POST/v1/audio-fx{ audioUrl, preset?, mix?, delayMs?, decay?, eqLow?, eqHigh? }Um efeito de reverberação, eco, telefone ou megafone. Veja Efeitos de áudio (Audio FX).
POST/v1/mix-audio{ audioUrls, trackVolumes? }Sobrepõe de 2 a 20 faixas, cada uma de 0 a 200 por cento. Veja Mixar áudio (Mix Audio).
POST/v1/adjust-volume{ audioUrl or videoUrl, volume?, normalize?, fadeIn?, fadeOut? }Muda o nível, normaliza ou aplica fade. Veja Ajustar volume (Adjust Volume).
POST/v1/combine-audio{ segments: [{ url, startTime?, endTime? }] }Junta segmentos um após o outro. Veja Combinar áudio (Combine Audio).
POST/v1/trim-audio{ audioUrl or videoUrl, startTime?, endTime?, audioFormat? }Corta áudio, ou extrai o áudio de um vídeo, como mp3 (o padrão), wav ou aac. Veja Cortar áudio (Trim Audio).
POST/v1/silence-detect{ audioUrl, thresholdDb?, minSilenceMs?, padMs? }Encontra os intervalos de silêncio de uma gravação. 11 créditos. Veja Detectar silêncio (Silence Detect).
POST/v1/audio-sync{ sources: [{ id, url }], reference? }Mede as defasagens entre as gravações (de 2 a 6) de uma mesma conversa. Veja Sincronizar áudio (Audio Sync).

silence-detect usa por padrão thresholdDb: -35, minSilenceMs: 700 e padMs: 120, e aceita áudio ou vídeo. O output_data.json dela é { version, ranges: [{ startMs, endMs }], durationMs }.

audio-sync custa 11 créditos por origem depois da primeira: 11 para 2 origens, 33 para 4, 55 para 6. Os IDs precisam ser únicos, e reference precisa ser um deles (por padrão, a primeira origem). O output_data.json dela é { version, reference, offsets: [{ sourceId, offsetMs, confidence, driftMsPerHour }], notes }, em que um tempo na referência é igual ao tempo na origem mais offsetMs. O desvio (drift) é medido e anotado, nunca corrigido.

Transcrever fala

POST /v1/transcribe transforma fala em texto e retorna um job. O corpo é { audioUrl, provider?, language?, diarize?, tagAudioEvents?, wordTimestamps? }, e audioUrl também pode ser um vídeo.

providerTempo por palavraObservações
elevenlabs-sttSempreO único mecanismo que respeita diarize (quem falou cada palavra) e tagAudioEvents (risos, aplausos).
incredibly-fast-whisperCom wordTimestamps: trueSem a flag, o job é bem-sucedido, é cobrado e retorna só frases.
whisperNuncaSó frases. wordTimestamps: true retorna 400 validation_error antes de qualquer crédito ser gasto.

Omitir provider executa whisper, então indique um mecanismo sempre que precisar de marcações de tempo por palavra. O output_data do job concluído guarda text, language, words (um { text, startMs, endMs, speaker? } por palavra, em milissegundos), json (a transcrição normalizada, também em milissegundos) e, só nos mecanismos mais antigos, segments em segundos. words entra direto em captions no POST /v1/add-captions.

curl -X POST https://app.nodaro.ai/v1/transcribe \
  -H "Authorization: Bearer $NODARO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "audioUrl": "https://cdn.nodaro.ai/uploads/talk.mp3", "provider": "elevenlabs-stt", "diarize": true }'
const { jobId } = await client.audio.transcribe({
  audioUrl: 'https://cdn.nodaro.ai/uploads/talk.mp3',
  provider: 'elevenlabs-stt',
})
// once completed, burn the words in as kinetic captions
const words = (await client.jobs.get(jobId)).output_data.words
await client.media.addCaptions({
  videoUrl: 'https://cdn.nodaro.ai/uploads/talk.mp4',
  captions: words,
  style: 'word-highlight',
  autoTranscribe: false,
})
nodaro audio transcribe --audio https://cdn.nodaro.ai/uploads/talk.mp3 --provider elevenlabs-stt --watch
nodaro jobs get <jobId> --json | jq '.output_data.words' > words.json
nodaro media add-captions https://cdn.nodaro.ai/uploads/talk.mp4 \
  --captions-file words.json --style word-highlight --no-auto-transcribe --watch

Publicar em redes sociais

Os fluxos de conexão abrem janelas pop-up e foram feitos para o app web. A publicação funciona com um token de API pessoal. Os tokens de app OAuth não podem gerenciar conexões.

MétodoCaminhoO que faz
GET/v1/social/providersAs redes aceitas e se cada uma está disponível nesta implantação.
GET/v1/social/connectionsAs suas contas conectadas.
DELETE/v1/social/connections/:idDesconecta uma conta.
POST/v1/social/telegram/connectConecta o Telegram com um token de bot: { botToken }.
POST/v1/social/connect/customConecta uma rede que usa campos em vez de login: { platform, fields }.
POST/v1/social/publishPublica agora. Retorna um job. 11 créditos.
POST/v1/social/scheduled-postsAgenda um post. 11 créditos, cobrados quando ele é publicado.
GET/v1/social/scheduled-postsOs seus posts agendados, filtrados por from, to e status.
PATCH/v1/social/scheduled-posts/:idEdita um post enquanto ele está queued ou draft.
DELETE/v1/social/scheduled-posts/:idCancela um post na fila. O histórico dele é mantido.

GET /v1/social/providers lista todas as redes com { id, label, connectKind, editor, category, capabilities, available }. category é social (um feed em que você posta) ou publishing (um site em que você publica artigos). Uma rede que a implantação não configurou aparece com available: false, nunca fica oculta. As redes que se conectam com campos (Bluesky, Dev.to, Hashnode, Medium, WordPress e Lemmy) descrevem os campos em customFields, e o Nodaro verifica a credencial com a rede antes de salvá-la.

POST /v1/social/publish recebe { platform, action, connectionId?, caption?, mediaUrl or mediaItems, … }. Duas falhas exigem tratamentos diferentes:

  • 503 publish_retryable: nada foi postado. Enviar a mesma requisição de novo é seguro.
  • 500 publish_failed: o resultado é desconhecido. Enviar de novo pode postar duas vezes, então verifique a rede primeiro.

Um post agendado recebe { connectionId, action, scheduledAt, caption?, media? }, em que cada item de mídia é { type, r2Key or url }. A mídia precisa ser de arquivos armazenados nesta implantação, que o Nodaro transforma em links novos quando o post sai; links para outros sites são recusados. Editar um post que já está sendo publicado retorna 409 not_editable. Veja Publicar nas redes (Publish to Social) e Publicar nas redes sociais.

Equivalentes no SDK e na CLI

ÁreaTypeScript SDKCLI
Vozes e modificação de vozclient.voices.list, searchLibrary, listClones, deleteClone, change, recast, analyze, exportMix, design, remix, dubnodaro voice list, changer, recast, analyze, export, design, remix, dub, clones
Mídiaclient.media.downloadVideo, downloadVideoProgress, videoMetadata, trimVideo, trimAudio, addCaptions, stillToVideo, slideshow, videoOverlay, saveToStorage, processnodaro media download, metadata, trim-video, trim-audio, add-captions, still-to-video, slideshow, video-overlay, save
Áudioclient.audio.separate, isolate, applyFx, mix, adjustVolume, combine, transcribenodaro audio separate, isolate, fx, mix, adjust-volume, combine, transcribe
Auxiliares de ediçãoclient.edit.silenceDetect, audioSyncnodaro edit silence-detect, audio-sync

Pelo MCP, as mesmas rotas são ferramentas como voice_changer, voice_changer_pro, voice_changer_pro_analyze, voice_changer_pro_export, dubbing, transcribe, add_captions e separate_audio. Veja a Referência das ferramentas MCP.

Erros

StatusCódigoSignificado
400validation_errorUm campo está ausente ou é inválido, por exemplo wordTimestamps no whisper, um campo de estilo que exige um estilo de legenda cinético ou uma exportação com todas as faixas sem som.
400provider_not_configuredA implantação não configurou essa rede social.
401unauthorizedO token está ausente, é inválido ou foi revogado.
402insufficient_creditsSó no Nodaro Cloud. A conta não tem créditos para cobrir o job.
404not_foundUma rota do Modificador de voz Pro foi chamada em uma implantação que não a oferece.
409not_editableO post agendado já está sendo publicado.
410voice_cloning_retiredA clonagem de voz não é mais oferecida.
413—O trecho dublado tem mais de 30 minutos.
429too_many_downloadsJá há 4 importações de vídeo em andamento na sua conta.
500publish_failedO resultado do post é desconhecido. Verifique a rede antes de enviar de novo.
503publish_retryableNada foi postado. É seguro enviar a mesma requisição de novo.

Perguntas frequentes

Última atualização

Nesta página