Nodaro 문서
문서노드 레퍼런스모델템플릿AI 에이전트(MCP)개발자셀프 호스팅리서치비교
REST API

보이스 및 미디어

보이스, 보이스 변경, 다중 화자 음색 변환, 더빙, 동영상 가져오기, 자막, 자르기, 오디오 도구, SNS 게시를 모두 Nodaro의 REST 엔드포인트로 사용하는 방법입니다.

보이스 및 미디어 엔드포인트는 Nodaro의 보이스와 미디어 도구를 일반 REST로 제공합니다. 보이스 카탈로그, 보이스 변경과 다중 화자 음색 변환, 더빙, 보이스 디자인, 동영상 가져오기, 자막, 자르기, 오디오 도구, 음성 텍스트 변환, SNS 게시를 다룹니다. 대부분은 작업입니다. POST가 바로 { jobId }를 반환하면, 상태가 completed가 될 때까지 GET /v1/jobs/:id/status를 폴링하고 output_data에서 결과를 읽으세요.

경로는 아래에 표시한 예외를 제외하고 모든 에디션에서 동작하며, Bearer 토큰을 받습니다. 인증을 참고하고, 여러 작업을 한 번에 폴링하는 방법은 작업을 참고하세요. 로컬 파일을 보내려면 먼저 업로드하세요. 업로드를 참고하세요.

보이스

메서드경로기능
GET/v1/voices기본 제공 보이스 카탈로그입니다. 이름, voice_id, 성별, 억양, 나이가 있습니다.
GET/v1/voices/librarysearch, gender, language, page, page_size 등으로 공유 보이스 라이브러리를 검색합니다.
GET/v1/voice-clones클로닝이 종료되기 전에 만든 보이스 클론입니다.
PATCH/v1/voice-clones/:id그 클론 중 하나의 이름을 바꾸거나 편집합니다.
DELETE/v1/voice-clones/:id그 클론 중 하나를 삭제합니다.
POST/v1/voice-clones, /v1/voice-clones/from-url종료되었습니다. 둘 다 410 voice_cloning_retired로 응답합니다.

보이스를 받는 경로에는 카탈로그 보이스의 voice_id, Rachel 같은 기본 제공 보이스의 이름, 또는 클론의 elevenlabsVoiceId를 전달하세요. 종료 전에 만든 클론은 어디서나 계속 동작합니다.

보이스 라이브러리 결과에는 recommendedProvider가 있을 수 있습니다. 그 보이스가 검증된 텍스트 음성 변환 모델입니다. 앱에 모델 선택기가 없다면 이 값을 텍스트 음성 변환에 provider로 보내세요. 그러면 보이스가 미리 듣기와 같은 소리를 냅니다. verifiedProviders는 그 보이스가 검증된 모든 모델을 나열합니다. 앱에 선택기가 있다면 사용자가 고른 모델이 이 목록에 없을 때만 선택을 덮어쓰세요. 응답의 hasMore로 “더 불러오기”를 구현합니다.

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 } : {}),
})

보이스 디자인 또는 설명한 보이스로 말하기

메서드경로본문결과
POST/v1/voice-design{ text, voiceDescription, model?, loudness?, guidanceScale?, seed?, quality?, shouldEnhance? }미리 듣기와 재사용할 수 있는 보이스 ID입니다.
POST/v1/voice-remix{ text, voiceDescription }클로닝 없이 설명한 보이스로 만든 음성입니다.

보이스 디자인에서 text는 1001,000자의 미리 듣기 문장이고, loudness는 -11, guidanceScale은 0100입니다. 보이스 리믹스에서 text는 15,000자입니다. 둘 다 작업을 반환합니다.

녹음의 보이스 바꾸기

POST /v1/voice-changer는 오디오 트랙이나 말하는 동영상 전체의 보이스를 대상 보이스 하나로 바꿉니다. audioUrl과 videoUrl 중 정확히 하나만 보내세요. 둘 다 보내면 동영상이 우선합니다. 동영상이면 Nodaro가 오디오를 꺼내 보이스를 바꾼 뒤 원래 화면에 다시 입히며, 작업의 output_data에는 videoUrl과 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
필드기능
voiceId필수. 대상 보이스입니다.
audioUrl 또는 videoUrl둘 중 하나는 필수. 바꿀 녹음입니다.
model음성 대 음성 변환 모델입니다.
stability, similarityBoost0~1. 전달이 얼마나 안정적인지, 대상 보이스에 얼마나 가까운지입니다.
style0~1, 기본값 0. 전달을 과장하며, 대신 속도와 안정성이 조금 떨어집니다.
useSpeakerBoost대상 보이스와의 유사도를 높이며, 조금 더 느려집니다.
seed출력을 재현할 수 있게 하는 정수입니다.
removeBackgroundNoisetrue이면 깨끗한 보이스만 반환하고, false이면 새 보이스 아래에 음악과 효과음을 유지합니다.

가격과 팁은 보이스 체인저를 참고하세요.

여러 화자의 음색 변환

보이스 체인저 Pro는 녹음에서 화자를 하나씩 감지하고, 말과 타이밍은 그대로 둔 채 화자마다 다른 보이스를 입힙니다. Nodaro Cloud에서 실행됩니다. Nodaro Cloud에 연결된 셀프 호스팅 설치는 그 연결을 통해 한 번에 끝나는 음색 변환을 실행할 수 있지만, 분석과 내보내기 단계에는 Nodaro Cloud 자체가 필요합니다. Nodaro Cloud에 연결을 참고하세요.

메서드경로기능
POST/v1/voice-changer-pro매핑된 모든 화자의 음색을 변환해 완성된 동영상이나 개별 스템으로 반환합니다.
POST/v1/voice-changer-pro/analyze음색 변환 없이 화자를 감지합니다. Nodaro Cloud 전용입니다.
POST/v1/voice-changer-pro/export스템을 직접 믹스한 결과로 완성된 동영상을 렌더링합니다. Nodaro Cloud 전용입니다.
POST/v1/voice-changer-pro/translate감지한 대본을 다른 언어로 번역해, 그 언어로 동영상을 다시 말하게 합니다. Nodaro Cloud 전용입니다.

화자에 보이스 매핑

orderedVoices는 감지 순서대로 화자를 매핑합니다. 화자 0은 항목 0을, 화자 1은 항목 1을 받는 식이며, 항목은 1~8개입니다. 목록 끝을 넘는 화자는 원래 보이스를 유지합니다. 각 항목은 다음 중 하나입니다.

  • 보이스 ID, 예: "Rachel".
  • null, 유지 슬롯입니다. 그 화자는 원래 보이스를 유지하고, 뒤의 화자는 계속 음색이 변환됩니다. 유지 슬롯은 비용이 들지 않지만, 항목 중 하나 이상은 보이스여야 합니다.
  • 화자별 설정을 담은 객체: { voiceId, engine?, stability?, similarityBoost?, style?, useSpeakerBoost?, seed?, volumeMode?, volume?, languageCode? }. engine은 sts(기본값, 음성 대 음성), v3 또는 v4입니다. v3는 대본을 바탕으로 ElevenLabs v3로 대사를 다시 연기하며, stability로 0, 0.5, 1만 받습니다. v4는 같은 일을 ElevenLabs v4로 하며, stability로 01 사이의 어떤 값이든 받고 similarityBoost를 적용합니다. languageCode는 번역한 대사를 말할 때 쓰며, 아래 설명처럼 v4에서만 받습니다. volumeMode는 match(기본값), normalize, manual 중 하나이며, manual에서는 volume을 0200%로 지정합니다.

음색을 변환하기 전에 Nodaro는 항상 보이스를 음악, 효과음과 분리합니다. 본문의 나머지 필드가 결과를 정합니다.

필드기능
audioUrl 또는 videoUrl둘 중 하나는 필수. 동영상이면 음색이 변환된 오디오를 원래 화면에 다시 입힙니다.
preserveBackground새 보이스 아래에 음악과 효과음을 다시 섞습니다. 기본값은 true입니다.
separationQualityfast(기본값, 보이스를 더 많이 보존) 또는 best(더 정밀한 분리)입니다.
removeBackgroundNoise결과의 노이즈도 제거합니다.
musicVolumeMode, musicVolume유지한 배경의 레벨입니다. match(기본값), normalize, 또는 0~200%를 지정하는 manual입니다.
voiceFx보이스에만 거는 리버브나 에코입니다: { preset, wetDryMix?, delayMs?, decay? }. room, hall, church 같은 리버브 프리셋은 wetDryMix를, echo와 custom은 delayMs와 decay를 사용합니다.
outputvideo(기본값, 완성된 결과) 또는 stems(직접 믹스할 수 있도록 효과와 레벨 조정이 없는 트랙)입니다.
analysis이전 분석 작업의 output_data입니다. 음색 변환은 화자를 다시 감지하지 않고 그 화자와 스템을 재사용합니다.

음색 변환은 매핑된 화자마다 요금이 부과되며, 분석과 내보내기는 고정 가격입니다. 가격은 보이스 체인저 Pro를 참고하세요.

다른 언어로 다시 말하기. POST /v1/voice-changer-pro/translate는 분석의 화자들을 구간별로 하나의 대상 언어로 번역합니다. 각 대사에는 길이 예산이 있어서, 다시 말한 대사가 원래 자리에 맞습니다. 본문은 { speakers, targetLanguage, sourceLanguage?, tier? }이며, speakers는 분석에서 가져오고 tier는 economy, standard, premium 중 하나입니다. 작업의 output_data.speakers는 모든 화자, 구간, 타이밍을 유지하며, 번역한 text, sourceText에 담긴 원문, 그리고 원래 언어로 남은 대사의 ID인 untranslated를 담습니다. 텍스트를 검토한 다음, 이 화자들을 음색 변환의 analysis.speakers로 보내고 다시 말할 각 보이스에 engine: "v4"와 대상 언어로 설정한 languageCode를 넣으세요. sts나 v3에 languageCode를 보내거나 모델이 제공하지 않는 언어를 보내면 400으로 응답합니다. 번역 가격은 텍스트 길이에 따라 정해지며, 최소 가격과 시작된 1,000자당 최대 가격은 등급에 따라 다릅니다. Nodaro Cloud가 아닌 곳에서는 네 개의 voice-changer-pro 라우트가 404로 응답합니다.

대화형 흐름: 분석, 스템으로 음색 변환, 내보내기

한 번에 끝나는 음색 변환은 호출 한 번으로 완성된 동영상을 렌더링합니다. 대화형 흐름에서는 음색 변환 비용을 내기 전에 화자를 확인하고, 렌더링하기 전에 결과를 믹스할 수 있습니다.

화자 감지

audioUrl 또는 videoUrl과, 선택적으로 separationQuality와 suggestTitle을 담아 POST /v1/voice-changer-pro/analyze를 호출하세요. 완료된 작업의 output_data에는 분리된 vocalsUrl과 backgroundUrl, 그리고 감지된 languageCode와 languageProbability가 들어 있습니다. speakers 목록은 각 화자의 id, segments, firstStartSec, wordCount, snippet을 알려 줍니다. 요청했다면 suggestedTitle도 있습니다. 박수처럼 사람이 아닌 “화자”가 있는지 살펴보세요.

스템으로 음색 변환

output: "stems"와 분석 output_data 전체를 analysis로 담아 POST /v1/voice-changer-pro를 호출하세요. 음색 변환이 감지 단계를 건너뛰므로, 감지 비용을 다시 내지 않고 다른 보이스로 다시 변환할 수 있습니다.

믹스와 내보내기

각 스템의 레벨은 내 인터페이스에서 직접 정하세요. 비용이 들지 않습니다. 그런 다음 원본 videoUrl과 최대 16개의 tracks를 담아 POST /v1/voice-changer-pro/export를 호출하세요. 각 트랙은 { url, gain, muted, kind? }입니다. gain은 0~200, kind는 voice 또는 background이며, 음소거되지 않은 트랙이 하나 이상 있어야 합니다. 선택 사항인 voiceFx는 보이스 트랙에만 적용됩니다. 동영상 스트림은 다시 인코딩하지 않고 그대로 복사하므로, 내보낸 결과가 미리 듣기와 일치합니다. 완료된 작업의 output_data.videoUrl이 결과입니다.

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

CLI에서 --voices의 keep이라는 단어는 유지 슬롯입니다.

다른 언어로 더빙

POST /v1/dubbing은 오디오 트랙이나 동영상 전체를 번역하고 다시 녹음하며, 각 화자의 보이스를 유지합니다. 원본은 정확히 하나만 보내세요. audioUrl, videoUrl, 또는 sourceUrl(YouTube나 TikTok 페이지처럼 더빙 모델이 직접 가져오는 공개 링크)입니다. 동영상은 더빙된 동영상으로 돌아옵니다. output_data.videoUrl과 함께, 더빙된 트랙만 따로 output_data.audioUrl에 들어 있습니다.

필드기능
targetLanguage필수. ISO 코드입니다. 예: es, pt-BR.
sourceLanguage말하는 언어입니다. 생략하면 감지합니다.
numSpeakers0(기본값)이면 화자 수를 감지합니다. 화자 수를 알면 1~20으로 지정해 분리 품질을 높일 수 있습니다.
startTime, endTime원본의 이 구간만 초 단위로 더빙합니다.
disableVoiceCloning, dropBackgroundAudio각 화자의 원래 보이스를 재현하지 않거나, 음악과 효과음을 뺍니다.
highestResolution동영상에서 원본 해상도를 유지합니다.
useProfanityFilter, targetAccent, watermark비속어 필터, 대상 언어의 억양, 동영상에 넣는 더빙 모델의 워터마크입니다.

더빙은 더빙하는 구간의 분 단위로 가격이 매겨지며, 최소 1분입니다. 구간은 최대 30분이며, 더 길면 413으로 응답하므로 startTime과 endTime으로 구간을 정해 더빙하세요. 더빙을 참고하세요.

POST /v1/download-video는 SNS 동영상(YouTube, TikTok, Instagram, X, Facebook)이나 동영상 파일 직접 링크를 내 저장 공간으로 가져옵니다. 작업 ID가 아니라 { downloadId }를 반환합니다. 완성된 파일은 내 라이브러리에 저장됩니다.

필드기능
url필수. 가져올 페이지나 파일입니다.
maxHeight해상도 상한입니다. 예: 720. 생략하면 가능한 최고 해상도입니다.
sectionStartSec, sectionEndSec해당 범위만 초 단위로 가져옵니다. 컷이 키프레임에 맞춰지기 때문에 앞뒤로 몇 초씩 더 포함됩니다. 둘 다 보내거나 둘 다 생략하고, 정확하게 자르려면 결과를 자르세요.
exactSectiontrue로 보내면 여유 없이 요청한 범위에서 정확히 자릅니다.
requireAudio소리가 없는 결과는 보통 품질이 떨어진 원본이라는 뜻이므로 기본적으로 실패합니다. 무음 클립을 받으려면 false를 보내세요.

다운로드는 서버 전송 이벤트 스트림인 GET /v1/download-video/progress/:downloadId로 추적하세요. 약 500ms마다 { phase, percent, videoUrl?, thumbnailUrl?, error? }를 보내며, 저장된 videoUrl과 함께 completed에서, 또는 error와 함께 failed에서 끝납니다. 진행률은 다운로드가 끝난 뒤 잠시만 보관되므로 가져오기가 시작되면 바로 수신을 시작하세요. 계정마다 다운로드는 동시에 최대 4개까지 실행되며, 다섯 번째는 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"

관련 경로 두 개는 바로 응답합니다.

  • { url }로 POST /v1/video-metadata를 호출하면 동영상을 다운로드하지 않고 길이, 크기, 제목, 라이브 여부를 읽습니다. 일부 구간만 가져올지 결정할 때 사용하세요.
  • { mediaUrl, filename?, mediaType? }로 POST /v1/save-to-storage를 호출하면 외부 미디어 URL을 서버에서 내 저장 공간으로 복사합니다. 작업을 반환합니다.

동영상 편집

메서드경로기능가격
POST/v1/trim-video동영상을 지정한 범위로 자릅니다.동영상 자르기
POST/v1/add-captions동영상에 자막을 입힙니다.자막 추가
POST/v1/still-to-video이미지 하나와 오디오 트랙 하나로 MP4를 만듭니다.0크레딧
POST/v1/slideshow이미지 2~100개와 선택 사항인 오디오 트랙으로 MP4를 만듭니다.0크레딧
POST/v1/video-overlay시간을 지정한 이미지 레이어 1~20개를 동영상 위에 배치합니다.22크레딧
POST/v1/media/process저장된 파일을 자르거나 크롭하고 바로 응답합니다.무료
POST/v1/edit-plan녹음의 대본으로 편집을 계획합니다. 군더더기를 줄이거나, 클립을 찾거나, 챕터를 표시하거나, 트레일러를 만듭니다. 결과는 미디어가 아니라 편집 결정 목록입니다.편집 계획
POST/v1/camera-switch편집의 각 컷을 말하는 사람의 카메라로 바꿉니다. 소리는 바뀌지 않습니다.카메라 전환
POST/v1/apply-edl편집 결정 목록을 동영상이나 오디오 파일 하나로 렌더링합니다. final 또는 proxy 미리 보기로 렌더링합니다.EDL 적용
POST/v1/tighten-episode팟캐스트나 인터뷰를 한 번의 호출로 다듬습니다. 녹음을 받아쓰고, 무음과 군더더기 말을 없애고, 에피소드를 렌더링하며, 원하면 자막과 배경 음악도 추가합니다.에피소드 다듬기
POST/v1/speaker-view편집을 화자가 화면에 나오도록 레이아웃에 배치해 렌더링하며, 화자가 바뀔 때마다 전환합니다. 출력 1분 단위로 가격이 매겨집니다.화자 뷰
POST/v1/split-media동영상, 오디오 파일 또는 둘 다를 최소 길이와 최대 길이 사이의 구간으로 자릅니다.실행당 22크레딧
POST/v1/video-mask텍스트로 설명한 대상을 추적해 흑백 마스크 동영상을 반환합니다. 클립 길이에 따라 가격이 매겨집니다.동영상 마스크
POST/v1/mask-composite마스크 동영상을 통해 전경 동영상을 배경 동영상 위에 배치합니다.시작된 5초마다 11크레딧
POST/v1/video-depth동영상을 가까운 곳은 밝고 먼 곳은 어두운 깊이 동영상으로 바꿉니다. 클립 길이에 따라 가격이 매겨집니다.동영상 깊이

편집 계획, 카메라 전환, 에피소드 다듬기의 계획 단계는 Nodaro Cloud에서 실행됩니다. 셀프 호스팅 설치는 Nodaro Cloud 연결을 통해 실행하며, 연결이 없으면 503 nodaro_connection_required로 응답합니다.

POST /v1/split-media는 videoUrl, audioUrl 또는 둘 다와 함께 chunkDuration(구간의 최대 길이, 1초 이상), minPartDuration(기본값 4, chunkDuration보다 클 수 없음), audioFormat(mp3, wav, aac)을 받습니다. 완료된 작업의 output_data에는 videoUrls, audioUrls, chunkCount, partDurationsSec가 있습니다. 구간을 자르는 방식은 구간 분할을 참고하세요.

GET /v1/edit-plan/capabilities는 이 서버가 계획할 수 있는 편집 계획 모드를 { modes, source, perMinute }로 나열합니다. tighten, clips, chapters는 항상 나열되고, trailer는 서버가 트레일러를 계획할 수 있을 때만 나열됩니다. perMinute는 편집 계획이 녹음의 시작된 1분마다 청구되면 true입니다. 서버가 나열하지 않은 모드는 POST /v1/edit-plan에서 아무것도 청구되기 전에 400 mode_not_available로 응답합니다.

에피소드 다듬기

POST /v1/tighten-episode는 녹음 하나에 에피소드 다듬기를 실행합니다. 본문은 { mediaUrls: [<recording URL>], musicUrl?, output?, framing?, captions?, captionStyle?, reviewBeforeRender?, planTier?, instructions?, styleGuide?, musicDuckAmount? }입니다. framing은 { aspect, layout } 또는 null입니다. 라우트는 { jobId, executionId }와 함께 202로 응답합니다.

  • 작업을 추적하세요. GET /v1/jobs/:id/status를 사용합니다. 작업의 output_data에는 에피소드(videoUrl, 오디오 에피소드라면 audioUrl), 편집(json), 대본(transcript), 그리고 quality가 담깁니다. quality는 검토 실행의 미리 보기라면 proxy, 그 밖에는 final입니다. 실패한 실행은 완료된 부분을 유지하고, 실패한 단계를 failedStep에 담습니다.
  • 안전하게 재시도하세요. Idempotency-Key 헤더가 있으면 같은 요청을 재시도했을 때 같은 jobId와 "deduped": true로 응답하고, 아무것도 시작하지 않습니다.
  • 먼저 가격을 확인하세요. POST /v1/tighten-episode/estimate는 같은 본문을 받아 아무것도 시작하지 않고 { data: { totalCredits, stepsCredits, feeCredits, durationSec } }로 응답합니다. 견적은 렌더링을 녹음 전체 길이로 계산하므로, 실제 실행은 대개 더 적게 듭니다.
  • 실행을 이어 가세요. { jobId, mode }와 함께 POST /v1/tighten-episode/continue를 보내면 내 실행 하나를 이어 갑니다. "mode": "from-failed"는 실패한 실행이 완료하지 못한 부분만 실행합니다. "mode": "render-final"은 계획을 내가 편집한 내용을 담은 선택 사항 editedEdl과 함께, 검토 실행의 최종본을 렌더링합니다.

미리 보기가 아니었던 실행의 최종 렌더링은 render_final_not_preview로 응답하고, 이미 렌더링된 편집의 최종 렌더링은 render_final_already_rendered로 응답합니다. 실패하지 않은 실행을 이어 가려고 하면 409 continuation_not_failed로 응답합니다.

워크플로 안에서 렌더링 전에 검토가 켜진 에피소드 다듬기 노드는 편집기나 앱 자체 페이지에서 사람이 검토해야 합니다. API, SDK, MCP의 run_workflow, 트리거로 시작한 워크플로 실행에서는 그 앞의 노드가 실행되고 청구된 다음, 이 노드가 preview_review_required로 실패하며 이 노드에는 아무것도 청구되지 않습니다. 이런 실행에서는 렌더링 전에 검토를 끄세요. 목록이 입력되는 검토 켜짐 노드는 실행이 하나라도 시작되기 전에 use_case_review_list_driven으로 거부됩니다. SDK는 client.edit.tightenEpisode, client.edit.estimateTightenEpisode, client.edit.continueUseCase로, CLI는 nodaro edit tighten-episode와 nodaro edit continue-use-case로 같은 라우트를 호출합니다. MCP에서는 tighten_episode와 continue_use_case를 사용하세요.

동영상 자르기

POST /v1/trim-video는 videoUrl과, 원하는 단위로 된 범위를 받습니다. 초 단위의 startTime과 endTime, trimStartFrames와 trimEndFrames, trimStartSeconds와 trimEndSeconds, 또는 keepFirstSeconds나 keepLastSeconds입니다.

자막 입히기

POST /v1/add-captions는 videoUrl을 받고, 다음 순서로 처음 찾은 소스에서 단어를 가져옵니다. captions(단어별 타이밍 항목), transcript, subtitle 스타일의 text, 마지막으로 음성 자동 변환입니다.

필드기능
stylesubtitle(고정 블록) 또는 키네틱 스타일인 word-highlight, karaoke, tiktok-words, word-pop, bouncy 중 하나입니다.
textsubtitle에서는 자막 자체이며, 동영상 전체에 고정 블록 하나로 입혀집니다. 키네틱 스타일에서는 음성 변환 결과가 없을 때만 쓰는 대체 텍스트입니다.
captions단어별 타이밍 항목 { text, startMs, endMs }이며, 키네틱 스타일에서는 단어마다 하나씩입니다. 음성 텍스트 변환의 words를 그대로 넣을 수 있습니다.
auto_transcribe, transcribe_provider다른 소스에서 단어를 얻지 못하면 음성을 텍스트로 변환합니다. 키네틱 스타일에는 단어 타이밍이 필요합니다: incredibly-fast-whisper(기본값) 또는 elevenlabs-stt.
lookoutline(키네틱 스타일의 기본값) 또는 clean(subtitle의 기본값)입니다.
maxWordsPerLine프레임 너비 제한과 별도로 줄당 1~20단어입니다. 1이나 2로 하면 리듬감 있게 읽힙니다.
highlightColor, animate키네틱 스타일 전용입니다. subtitle에서는 400으로 응답합니다.
position, positionY, fontSize, fontFamily, fontWeight, color, backgroundColor, strokeColor, strokeWidth, uppercase텍스트의 모양입니다.
segments동영상의 구간마다 스타일, 룩, 위치를 따로 지정합니다.

스타일을 지정하지 않은 일반 텍스트 subtitle은 저렴한 렌더링입니다. 키네틱 스타일, 스타일 필드, 타이밍이 있는 자막, 음성 자동 변환, segments 중 하나라도 쓰면 더 높은 가격으로 렌더링되며 원본 프레임 레이트를 유지합니다. 모든 옵션과 두 가격은 자막 추가를 참고하세요.

정지 이미지를 동영상으로

  • POST /v1/still-to-video는 { imageUrl, audioUrl, motion?, intensity?, resolution?, aspectRatio?, fps?, fit?, padColor? }를 받습니다. 동영상은 오디오 길이만큼 이어지며, 길이 필드는 없습니다. motion은 none(기본값), zoom-in, zoom-out, pan-left, pan-right, ken-burns 중 하나이며, intensity는 1~10입니다. 정지 이미지로 동영상 만들기를 참고하세요.
  • POST /v1/slideshow는 imageUrls(2~100개), 선택 사항인 audioUrl, imageDurations(이미지당 초, 자동이면 null) 또는 perImageDuration, transition, 그리고 같은 모양 필드를 받습니다. 오디오가 있으면 슬라이드쇼는 오디오 길이만큼 이어집니다. 고정한 길이의 합이 맞지 않으면 비율에 맞춰 조정되며, 작업 출력에 그 사실이 표시됩니다. 오디오가 없으면 이미지 수에 perImageDuration을 곱한 길이만큼 소리 없이 이어집니다. 슬라이드쇼를 참고하세요.

둘 다 AI 모델 없이 서버에서 렌더링되며 0크레딧입니다. resolution은 720p, 1080p, 4K 중 하나, fps는 24 또는 30이며, fit: "contain"은 자르는 대신 padColor로 레터박스를 넣습니다.

동영상에 이미지 오버레이

POST /v1/video-overlay는 렌더링 한 번으로 이미지 레이어 1~20개를 동영상 위에 배치하고, 원래 오디오는 건드리지 않습니다. 각 레이어는 { imageUrl, start, end?, preset?, corner?, anchor?, x?, y?, width?, height?, fit?, opacity?, animate?, zIndex? }입니다. start와 end는 초 단위이며, end가 없으면 레이어는 동영상이 끝날 때까지 이어집니다. preset은 card, corner-badge, full-frame 중 하나이며, 위치나 크기를 명시하면 프리셋보다 우선합니다. 둘 다 없는 레이어는 코너 배지가 되며, corner로 따로 정하지 않으면 오른쪽 아래에 놓입니다.

outputAspect(16:9, 9:16, 1:1, 4:5)는 baseFit, backgroundColor와 함께 프레임을 바꿉니다. 작업은 { videoUrl, thumbnailUrl, width, height, durationSec, warnings }를 반환합니다. 레이어 수와 관계없이 실행당 22크레딧이 들며, 사용자마다 분당 30개의 요청을 보낼 수 있습니다. 동영상 오버레이를 참고하세요.

저장된 파일을 바로 자르기 또는 크롭

POST /v1/media/process는 저장한 파일을 자르거나 크롭하고, 같은 요청 안에서 무료로 응답합니다. 본문은 { sourceUrl, type, trim?, crop?, format?, deleteSource? }입니다. type은 video 또는 audio, trim은 { startTime, endTime }, crop은 { x, y, width, height }이고, format은 mp4, webm, mp3, wav, m4a, aac 중 하나입니다. { data: { url, thumbnailUrl, assetId, sizeBytes, mimeType, metadata } }를 반환합니다. deleteSource: true는 원본이 내 것이고 다른 곳에서 쓰지 않을 때 작업 후 원본을 삭제합니다.

오디오 편집

각 경로는 작업을 반환합니다.

메서드경로본문기능
POST/v1/audio-separation{ audioUrl, mode?, quality? }트랙을 분리합니다. vocal_instrumental(기본값) 또는 전체 stems이며, 품질은 auto, fast, best입니다. 음원 분리를 참고하세요.
POST/v1/audio-isolation{ audioUrl }주 음성만 남기고 배경을 제거합니다. 음성 추출을 참고하세요.
POST/v1/audio-fx{ audioUrl, preset?, mix?, delayMs?, decay?, eqLow?, eqHigh? }리버브, 에코, 전화, 메가폰 효과입니다. 오디오 효과를 참고하세요.
POST/v1/mix-audio{ audioUrls, trackVolumes?, duck?, endAt? }트랙 220개를 각각 0200%로 겹칩니다. duck은 { under, amount?, thresholdDb?, ratio?, attackMs?, releaseMs? }이며, audioUrls[under]의 소리가 클 때 나머지 모든 트랙의 볼륨이 낮아집니다. 요금은 duck이 있든 없든 같습니다. endAt은 "longest"(기본값) 또는 "voice"이며, "voice"는 duck.under 트랙이 끝날 때 믹스를 끝내고 duck이 필요합니다. 오디오 믹스를 참고하세요.
POST/v1/adjust-volume{ audioUrl or videoUrl, volume?, normalize?, fadeIn?, fadeOut? }레벨을 바꾸거나, 노멀라이즈하거나, 페이드를 겁니다. 볼륨 조절을 참고하세요.
POST/v1/pitch-tempo{ audioUrl or videoUrl, semitones?, tempo?, preserveFormants? }피치를 -1212반음 옮기거나, 피치를 바꾸지 않고 템포를 0.52로 바꿉니다. 동영상은 화면을 그대로 유지하며 템포는 1로 고정됩니다. 입력의 시작된 1분마다 22크레딧이며, 최대 30분입니다. 피치 및 템포를 참고하세요.
POST/v1/combine-audio{ segments: [{ url, startTime?, endTime? }] }세그먼트를 끝과 끝으로 잇습니다. 오디오 합치기를 참고하세요.
POST/v1/trim-audio{ audioUrl or videoUrl, startTime?, endTime?, audioFormat? }오디오를 자르거나 동영상에서 오디오를 꺼내 mp3(기본값), wav, aac로 만듭니다. 오디오 자르기를 참고하세요.
POST/v1/silence-detect{ audioUrl, thresholdDb?, minSilenceMs?, padMs? }녹음에서 무음 구간을 찾습니다. 11크레딧입니다. 무음 감지를 참고하세요.
POST/v1/audio-sync{ sources: [{ id, url }], reference? }한 대화를 녹음한 2~6개 파일 사이의 오프셋을 측정합니다. 오디오 동기화를 참고하세요.

silence-detect의 기본값은 thresholdDb: -35, minSilenceMs: 700, padMs: 120이며, 오디오와 동영상을 모두 받습니다. output_data.json은 { version, ranges: [{ startMs, endMs }], durationMs }입니다.

audio-sync는 첫 번째 이후의 소스마다 11크레딧이 듭니다. 소스 2개는 11크레딧, 4개는 33크레딧, 6개는 55크레딧입니다. ID는 고유해야 하며, reference는 그중 하나여야 합니다(기본값은 첫 번째 소스). output_data.json은 { version, reference, offsets: [{ sourceId, offsetMs, confidence, driftMsPerHour }], notes }이며, 레퍼런스의 시간은 소스의 시간에 offsetMs를 더한 값과 같습니다. 드리프트는 측정해서 기록할 뿐, 보정하지 않습니다.

음성 텍스트 변환

POST /v1/transcribe는 음성을 텍스트로 바꾸고 작업을 반환합니다. 본문은 { audioUrl, provider?, language?, diarize?, tagAudioEvents?, wordTimestamps? }이며, audioUrl에는 동영상도 넣을 수 있습니다.

provider단어 타이밍참고
elevenlabs-stt항상diarize(각 단어를 누가 말했는지)와 tagAudioEvents(웃음, 박수)를 지원하는 유일한 엔진입니다.
incredibly-fast-whisperwordTimestamps: true일 때플래그가 없으면 작업은 성공하고 요금도 부과되지만, 구 단위로만 반환합니다.
whisper반환하지 않음구 단위로만 반환합니다. wordTimestamps: true를 보내면 크레딧이 쓰이기 전에 400 validation_error로 응답합니다.

provider를 생략하면 whisper가 실행되므로, 단어 타이밍이 필요할 때는 항상 엔진을 지정하세요. 완료된 작업의 output_data에는 text, language, words(단어마다 하나씩, 밀리초 단위의 { text, startMs, endMs, speaker? }), json(정규화된 대본, 역시 밀리초 단위), 그리고 이전 엔진에서만 초 단위의 segments가 들어 있습니다. words는 POST /v1/add-captions의 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

SNS에 게시

연결 흐름은 팝업 창을 열기 때문에 웹 앱에서 쓰도록 만들어졌습니다. 게시는 개인 API 토큰으로 할 수 있습니다. OAuth 앱 토큰으로는 연결을 관리할 수 없습니다.

메서드경로기능
GET/v1/social/providers지원하는 네트워크와, 각 네트워크를 이 배포 환경에서 사용할 수 있는지입니다.
GET/v1/social/connections연결된 내 계정입니다.
DELETE/v1/social/connections/:id계정 연결을 해제합니다.
POST/v1/social/telegram/connect봇 토큰으로 Telegram을 연결합니다: { botToken }.
POST/v1/social/connect/custom로그인 대신 필드를 쓰는 네트워크를 연결합니다: { platform, fields }.
POST/v1/social/publish지금 게시합니다. 작업을 반환합니다. 11크레딧입니다.
POST/v1/social/scheduled-posts게시물을 예약합니다. 11크레딧이며, 게시될 때 부과됩니다.
GET/v1/social/scheduled-posts예약된 내 게시물을 from, to, status로 필터링해 반환합니다.
PATCH/v1/social/scheduled-posts/:idqueued 또는 draft 상태인 동안 게시물을 편집합니다.
DELETE/v1/social/scheduled-posts/:id대기 중인 게시물을 취소합니다. 기록은 유지됩니다.

GET /v1/social/providers는 모든 네트워크를 { id, label, connectKind, editor, category, capabilities, available }로 나열합니다. category는 social(게시하는 피드) 또는 publishing(기사를 게시하는 사이트)입니다. 배포 환경에서 설정하지 않은 네트워크는 숨기지 않고 available: false로 나열합니다. 필드로 연결하는 네트워크(Bluesky, Dev.to, Hashnode, Medium, WordPress, Lemmy)는 customFields에 필드를 설명하며, Nodaro는 저장하기 전에 해당 네트워크에서 자격 증명을 확인합니다.

POST /v1/social/publish는 { platform, action, connectionId?, caption?, mediaUrl or mediaItems, … }를 받습니다. 두 가지 실패는 다르게 처리해야 합니다.

  • 503 publish_retryable: 아무것도 게시되지 않았습니다. 같은 요청을 다시 보내도 안전합니다.
  • 500 publish_failed: 결과를 알 수 없습니다. 다시 보내면 두 번 게시될 수 있으므로 먼저 네트워크를 확인하세요.

예약 게시물은 { connectionId, action, scheduledAt, caption?, media? }를 받으며, 각 미디어 항목은 { type, r2Key or url }입니다. 미디어는 이 배포 환경에 저장된 파일이어야 하며, Nodaro가 게시할 때 새 링크로 바꿉니다. 다른 사이트의 링크는 거부됩니다. 이미 게시 중인 게시물을 편집하면 409 not_editable로 응답합니다. SNS에 게시와 SNS 게시 가이드를 참고하세요.

SDK 및 CLI 대응

영역TypeScript SDKCLI
보이스와 보이스 변경client.voices.list, searchLibrary, listClones, deleteClone, change, recast, analyze, exportMix, design, remix, dubnodaro voice list, changer, recast, analyze, export, design, remix, dub, clones
미디어client.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
오디오client.audio.separate, isolate, applyFx, mix, adjustVolume, pitchTempo, combine, transcribenodaro audio separate, isolate, fx, mix, adjust-volume, pitch-tempo, combine, transcribe
편집 도우미client.edit.silenceDetect, audioSyncnodaro edit silence-detect, audio-sync

MCP에서는 같은 경로가 voice_changer, voice_changer_pro, voice_changer_pro_analyze, voice_changer_pro_export, dubbing, transcribe, add_captions, separate_audio 같은 도구로 제공됩니다. MCP 도구 레퍼런스를 참고하세요.

오류

상태코드의미
400validation_error필드가 없거나 잘못되었습니다. 예를 들어 whisper에 보낸 wordTimestamps, 키네틱 자막 스타일이 필요한 스타일 필드, 모든 트랙을 음소거한 내보내기가 있습니다.
400provider_not_configured배포 환경이 해당 SNS를 설정하지 않았습니다.
401unauthorized토큰이 없거나, 잘못되었거나, 폐기되었습니다.
402insufficient_creditsNodaro Cloud 전용입니다. 계정의 크레딧이 작업 비용에 못 미칩니다.
404not_found보이스 체인저 Pro를 제공하지 않는 배포 환경에서 그 경로를 호출했습니다.
409not_editable예약 게시물이 이미 게시 중입니다.
410voice_cloning_retired보이스 클로닝은 더 이상 제공되지 않습니다.
413—더빙하는 구간이 30분보다 깁니다.
429too_many_downloads내 계정에서 동영상 가져오기가 이미 4개 실행 중입니다.
500publish_failed게시물의 결과를 알 수 없습니다. 다시 보내기 전에 네트워크를 확인하세요.
503publish_retryable아무것도 게시되지 않았습니다. 같은 요청을 다시 보내도 안전합니다.

자주 묻는 질문

동영상 하나에서 여러 화자의 보이스를 바꾸려면 어떻게 하나요?

감지된 화자 순서대로 화자마다 항목을 하나씩 담은 orderedVoices와 함께 POST /v1/voice-changer-pro를 사용하세요. null 항목은 그 화자의 원래 보이스를 유지합니다. 화자를 먼저 확인하려면 분석 단계를 실행한 뒤 스템으로 음색을 변환하고 직접 믹스를 내보내세요.

API로 보이스를 복제할 수 있나요?

아니요. 보이스 클로닝은 종료되었으며, 클론 경로는 410 voice_cloning_retired로 응답합니다. 이전에 만든 클론은 보이스 ID로 계속 동작합니다. 대신 POST /v1/voice-design으로 설명에서 새 보이스를 디자인하세요.

단어 타이밍을 주는 음성 텍스트 변환 엔진은 무엇인가요?

elevenlabs-stt는 항상 단어 타이밍을 반환하고, incredibly-fast-whisper는 wordTimestamps를 true로 보낼 때 반환합니다. whisper는 구 단위로만 반환합니다. provider를 생략하면 whisper가 실행되므로, 단어 타이밍이 필요하면 엔진을 지정하세요.

더빙할 수 있는 클립의 길이는 얼마인가요?

더빙하는 구간은 최대 30분이며, 최소 1분으로 분 단위로 가격이 매겨집니다. 더 긴 원본은 startTime과 endTime으로 구간을 정해 더빙하세요.

어떤 미디어 도구가 무료인가요?

정지 이미지로 동영상 만들기, 슬라이드쇼, 동기식 자르기·크롭 경로인 POST /v1/media/process는 0크레딧입니다. 동영상 오버레이는 실행당 22크레딧, 무음 감지는 11크레딧입니다.

최종 업데이트

목차