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

트렌드

Nodaro 트렌드 카탈로그를 둘러보고, 트렌드의 슬롯을 내 사진으로 채우고, 무료로 견적을 받은 뒤 REST, SDK, CLI, MCP로 실행하세요.

Nodaro Cloud에서 사용할 수 있습니다

트렌드 API는 미리 만들어진 Cast Swap 레시피를 실행합니다. 트렌드는 슬롯이 있는 짧은 클립입니다. 슬롯은 교체할 수 있는 인물, 반려동물, 제품, 장소입니다. 슬롯을 내 사진으로 채우고 트렌드를 실행하면 그 사진이 들어간 클립을 받습니다.

트렌드는 Nodaro Cloud의 기능입니다. 셀프 호스팅 설치에서는 모든 라우트가 404로 응답합니다. 라우트는 Bearer 토큰을 받습니다. 인증을 참조하세요.

여기에는 게시된 트렌드만 있습니다. 초안, 게시되지 않은 슬러그, 알 수 없는 슬러그는 모든 라우트에서 404입니다.

엔드포인트

메서드경로하는 일
GET/v1/trends카탈로그 자체의 순서로 된 카탈로그입니다. { data: TrendCard[], next }. 쿼리: q(검색), tag, favorites=1(내 즐겨찾기만), locale, cursor, limit(1~60, 기본값 30).
GET/v1/trends/:slug트렌드 하나입니다. { data: TrendDetail }이며, 슬롯, 예시, 미리보기 길이, 해상도가 들어 있습니다. 쿼리: locale.
POST/v1/trends/:slug/estimate실행 견적을 받습니다. 무료입니다. { data: { expectedCredits, holdCredits, breakdown } }로 응답합니다.
POST/v1/trends/:slug/runs실행을 시작합니다. 202 { data: { jobId } }로 응답합니다. GET /v1/jobs/:id로 작업을 추적하세요.
GET/v1/trends/runs내 트렌드 실행을 최신순으로 반환합니다. { data: TrendRun[], next }. 쿼리: trend(슬러그), cursor, limit(1~60, 기본값 30).
PUT/v1/trends/:slug/favorite트렌드를 즐겨찾기에 추가합니다. 204로 응답합니다.
DELETE/v1/trends/:slug/favorite트렌드를 즐겨찾기에서 제거합니다. 204로 응답합니다.

이름, 설명, 슬롯 레이블, 힌트는 ?locale=이 플랫폼 언어이면 그 언어로 옵니다. 그렇지 않으면 내 프로필의 언어로, 그다음에는 영어로 옵니다.

트렌드가 새 버전으로 바뀌거나 게시가 취소된 뒤에도 실행은 GET /v1/trends/runs에서 계속 읽을 수 있습니다.

트렌드에 담긴 것

GET /v1/trends/:slug는 다음을 반환합니다.

  • slots: 각 슬롯의 key, label, kind(person, pet, product, location 중 하나), required, 선택 사항인 hint, 기본 칩.
  • examples: 각 예시의 결과 동영상과 각 슬롯이 쓴 사진.
  • previewSec: 트렌드가 4초 미리보기 실행을 제공하면 4, 아니면 null.
  • resolutions: 트렌드를 실행할 수 있는 해상도.

GET /v1/trends의 카탈로그 카드에는 슬러그, 이름, 태그, needs(종류별 슬롯 수), 길이(초), isFavorite가 담깁니다.

실행 본문

POST /v1/trends/:slug/estimate와 POST /v1/trends/:slug/runs는 같은 본문 { slots, example?, details?, preview?, resolution?, draft?, sessionId?, projectId? }를 받습니다.

필드하는 일
slots필수입니다. 슬롯 키 → { images?, …chips }이며, 슬롯마다 한 대상의 이미지 1~3장을 받습니다. 필수 슬롯에는 모두 이미지가 있어야 합니다.
example선택 사항입니다. 1부터 시작하는 예시 번호입니다. 비워 둔 선택 슬롯을 이 예시의 사진이 채웁니다. 기본값은 1입니다.
details선택 사항입니다. 내 문구로, 최대 1,000자입니다. 슬롯은 {slot:<key>}로 언급하세요.
preview선택 사항입니다. 트렌드의 previewSec가 4이면 true로 4초를 실행합니다.
resolution선택 사항입니다. 기본값인 "480p", "720p", "1080p" 중 하나입니다.
draft선택 사항입니다. 기본값은 true입니다. 초안은 480p에서만 쓸 수 있습니다.
sessionId선택 사항입니다. 받아서 확인하지만 아직 적용되지 않습니다. 트렌드 실행은 아직 세션에 보관되지 않습니다.
projectId선택 사항입니다. 받지만 현재 실행에는 쓰이지 않습니다.

칩은 슬롯 종류의 고유 특성입니다. 각 칩은 내 사진으로 만드는 "new", 또는 클립 그대로 유지하는 "original"입니다.

슬롯 종류칩
personbody, outfit, hair
petbody, coat
productshape, finish
location없음
{
  "slots": {
    "dancer": { "images": ["https://example.com/me.jpg"], "outfit": "original" }
  },
  "preview": true,
  "resolution": "480p"
}

견적

견적은 실행에 청구될 것으로 예상되는 expectedCredits와, 실행이 시작될 때 예약되는 holdCredits로 응답합니다. breakdown은 견적의 구성 항목을 나열합니다.

반복 요청

POST /v1/trends/:slug/runs는 8~200자의 Idempotency-Key 헤더를 받습니다. 같은 키로 반복된 요청은 첫 실행의 작업으로 응답합니다. 새로 시작되거나 청구되는 것은 없습니다.

권한

OAuth 앱에는 다음이 필요합니다.

  • 카탈로그, 트렌드, 내 실행을 읽으려면 jobs:read.
  • 실행 견적을 받거나 시작하려면 workflows:execute, sessionId를 보내려면 assets:write도.
  • 즐겨찾기에는 assets:write.

오류

거부의 본문은 { error: { code, message } }입니다. 슬롯 오류에는 슬롯의 키도 slot으로 담깁니다. 견적 라우트와 실행 라우트의 400 거부는 아무것도 청구되기 전에 일어납니다.

상태code발생 시점
400validation_error본문이나 쿼리가 유효하지 않거나, cursor가 이 목록이 준 값이 아니거나, Idempotency-Key가 8~200자가 아닙니다.
400missing_slot필수 슬롯에 이미지가 없거나, 선택 슬롯을 비워 두었는데 선택한 예시에 그 슬롯의 사진이 없습니다.
400unknown_slotslots가 트렌드에 없는 키를 지정합니다.
400invalid_choice슬롯의 종류가 받지 않는 칩입니다. 예를 들어 인물의 coat나, 장소에 붙은 칩입니다.
400example_out_of_rangeexample이 트렌드에 없는 예시를 지정하거나, 선택 슬롯을 비워 두었는데 트렌드에 그 슬롯을 채울 예시가 없습니다.
400preview_unavailable미리보기를 제공하지 않는 트렌드에 preview: true를 보냈습니다.
400invalid_slot_mentiondetails가 트렌드에 없는 키로 {slot:<key>}를 언급합니다.
400prompt_too_long이 트렌드에는 details가 너무 깁니다. 줄이세요.
401unauthorized인증된 사용자가 없습니다.
404not_found트렌드가 게시되지 않았거나, sessionId가 내가 쓸 수 없는 세션을 가리킵니다.
502engine_error동영상 엔진이 예상하지 못한 방식으로 응답했습니다.
503engine_unsupported이 플랫폼 버전에서는 아직 트렌드를 실행할 수 없습니다.
503trend_unavailable지금은 트렌드를 실행할 수 없습니다.
503not_available이 서버에는 아직 트렌드 카탈로그가 없습니다. GET /v1/trends/runs를 제외한 모든 라우트에 해당합니다.

동영상 엔진이 견적이나 실행을 거부하면, 트렌드 라우트는 자체 코드와 고정 메시지로 응답합니다.

상태code발생 시점
400trend_run_rejected엔진이 아래에 없는 이유로 이 입력을 거부했습니다.
400clip_out_of_range, preview_out_of_range, video_unreadable트렌드 자체의 클립을 있는 그대로 실행할 수 없습니다.
400unsafe_url사진이 공개 http 또는 https 주소가 아닙니다.
400raw_reference_tokendetails에 {image:, {video:, {audio:가 들어 있습니다.
402insufficient_credits내 크레딧으로 실행 비용을 감당할 수 없습니다. 워크스페이스에서는 거부한 한도에 따라 budget_exceeded, member_cap_exceeded, user_allowance_exceeded로 응답할 수도 있습니다.
413storage_limit_exceeded내 저장 공간이 가득 찼습니다.
422job_blocked배포 환경의 작업 정책이 실행을 막았습니다.
429rate_limited요청이 너무 많습니다. 잠시 후 다시 시도하세요.
503engine_unsupported, estimate_unavailable지금은 실행하거나 견적을 낼 수 없습니다. 잠시 후 다시 시도하세요.
502engine_error그 밖의 모든 경우입니다.

끝나지 않은 실행

GET /v1/trends/runs에서 끝나지 않은 실행에는 error: { code, message }가 있습니다. 메시지는 항상 같은 고정 문장이므로 코드로 분기하세요.

code의미
safety-block, policy-block작업이 차단되었습니다.
credits실행 도중 크레딧이 부족해졌습니다. 환불되었습니다. 크레딧을 충전한 뒤 다시 실행하세요.
cancelled실행이 취소되었습니다.
failed그 밖의 모든 실패입니다.

실패하지도 취소되지도 않은 실행은 error: null입니다. 완료된 실행에는 videoUrl, posterUrl, creditsCharged가 담깁니다. 실행의 각 슬롯은 그 사진이 예시에서 왔는지(fromExample) 알려 줍니다.

SDK에서 사용

client.trends는 이 라우트들을 감쌉니다. @nodaro/sdk/trends로도 가져올 수 있습니다.

list(params?: ListTrendsParams): Promise<TrendPage<TrendCard>>
get(slug: string, params?: { locale?: string }): Promise<TrendDetail>
estimate(slug: string, request: TrendRunRequest): Promise<TrendEstimate>
run(slug: string, request: TrendRunRequest, options?: { idempotencyKey?: string }): Promise<{ jobId: string }>
runs(params?: ListTrendRunsParams): Promise<TrendPage<TrendRun>>
favorite(slug: string): Promise<void>
unfavorite(slug: string): Promise<void>

list()와 runs()는 도착한 그대로의 페이지 { data, next }를 반환합니다. next를 cursor로 다시 넘기세요. 마지막 페이지에서는 null입니다. get(), estimate(), run()은 { data } 봉투 없이 페이로드를 반환합니다. "runs"는 슬러그가 될 수 없습니다. 슬러그를 받는 메서드는 요청을 보내기 전에 이 값에 대해 TypeError를 발생시킵니다.

import type { TrendRunRequest } from "@nodaro/sdk"

const { data: cards } = await client.trends.list({ q: "dance" })
const trend = await client.trends.get(cards[0].slug)

const request: TrendRunRequest = {
  // Every required slot needs 1–3 pictures; optional slots left out take the example's.
  slots: Object.fromEntries(
    trend.slots.filter((s) => s.required).map((s) => [s.key, { images: [myPhotoUrl] }]),
  ),
}
const quote = await client.trends.estimate(trend.slug, request)
console.log(`about ${quote.expectedCredits} credits, ${quote.holdCredits} held while it runs`)

const { jobId } = await client.trends.run(trend.slug, request, { idempotencyKey: crypto.randomUUID() })
const job = await client.jobs.get(jobId)

CLI에서 사용

nodaro trends list --search dance
nodaro trends get <slug>
nodaro trends estimate <slug> --slot dancer=https://example.com/me.jpg --choice dancer.outfit=original
nodaro trends run <slug> --slot dancer=https://example.com/me.jpg --idempotency-key <key>
nodaro trends runs --trend <slug>
nodaro trends favorite <slug>

--slot은 반복할 수 있으며, 슬롯마다 사진 1~3장을 받습니다. trends run은 크레딧을 쓰므로 먼저 trends estimate를 실행하세요. CLI 명령을 참조하세요.

MCP에서 사용

네 MCP 도구가 트렌드를 다룹니다. list_trends, get_trend, estimate_trend, run_trend입니다. MCP › 동영상을 참조하세요. confirm 없이 호출한 run_trend는 견적을 반환하고 아무것도 청구하지 않습니다. 사용자가 가격을 수락한 뒤 confirm: true로 호출하면 실행을 시작하고 작업 ID를 반환합니다.

자주 묻는 질문

Nodaro에서 트렌드란 무엇인가요?

트렌드는 미리 만들어진 Cast Swap 레시피입니다. 교체할 수 있는 인물, 반려동물, 제품, 장소를 위한 슬롯이 있는 짧은 클립입니다. 슬롯을 내 사진으로 채우면 그 사진이 들어간 클립을 받습니다.

트렌드 실행 비용은 어떻게 알 수 있나요?

실행할 때와 같은 본문으로 POST /v1/trends/:slug/estimate를 호출하세요. 무료입니다. 실행에 청구될 것으로 예상되는 expectedCredits와, 실행 중에 예약되는 holdCredits를 반환합니다.

모든 슬롯을 채워야 하나요?

아니요. 필수 슬롯에는 모두 사진 1~3장이 필요합니다. 비워 둔 선택 슬롯은 트렌드 예시의 사진을 쓰며, 기본값은 첫 번째 예시입니다.

트렌드 실행을 안전하게 재시도할 수 있나요?

네. 8~200자의 같은 Idempotency-Key 헤더를 보내세요. 같은 키로 반복된 요청은 첫 실행의 작업으로 응답하며, 새로 시작되거나 청구되는 것은 없습니다.

트렌드는 셀프 호스팅 설치에서도 작동하나요?

아니요. 트렌드는 Nodaro Cloud의 기능입니다. 셀프 호스팅 설치에서는 모든 트렌드 라우트가 404로 응답합니다.

최종 업데이트

목차