Run nodes
Run any Nodaro node from TypeScript without a workflow. Discover node types, start runs, wait for results, and pass references and camera direction.
client.nodes lists the node types a Nodaro server supports and runs any one of them directly, without building a workflow. A run posts your parameters to the node's endpoint, POST /v1/<type>, and returns a job you can wait for. It is the same path the CLI uses for nodaro nodes run and the one Nodaro's MCP tools use. See Run a single node for the REST view.
Methods
| Method | What it does |
|---|---|
nodes.list() | List every node type, with its models and credit cost |
nodes.get(type) | Read one node type |
nodes.run(type, params?, options?) | Start a node and return its job id at once |
nodes.runAndWait(type, params?, opts?) | Start a node, poll its job, and return the output |
nodes.runMany(type, paramsList, opts?) | Start several runs of one node at once and wait for all of them |
client.nodes
list()
Lists every node type the server supports. The answer can be cached by the server for 5 minutes. The call costs nothing and needs no scopes.
list(): Promise<{ data: NodeDescriptor[] }>const { data: nodes } = await client.nodes.list()
const imageGenerators = nodes.filter((n) => n.category === "ai-image")
const takesReferences = nodes.filter((n) => n.capabilities?.includes("supports-reference-image"))Each NodeDescriptor has these fields:
| Field | Type | Description |
|---|---|---|
type | string | The API type, such as generate-image. Pass it to run(). |
label | string | The node's name in the editor. |
category | string | The category, such as ai-image, ai-video, ai-audio, ai-text, processing or parameter. |
description | string | A one-line description. |
outputType | string | text, image, video, audio, data or none. |
creditCost | number | string | The credit cost: a number when fixed, or a range such as "2-620" when it depends on the model. Nodaro Cloud only. |
providers | string[] | The model ids the node can run, for the provider parameter. |
capabilities | string[] | Flags such as supports-reference-image or supports-end-frame. |
inputSchema | { fields } | The input fields you can set, each with key, type, required and options. |
maxDurationSec | number | The longest duration the node accepts, where it has one. |
providerResolutions | Record<string, string[]> | The resolutions each model accepts, where they differ. |
Self-hosted Community and Business installs have no credit system, so their descriptors omit creditCost.
get(type)
Reads the descriptor of one node type.
get(type: string): Promise<{ data: NodeDescriptor }>Prop
Type
const { data: node } = await client.nodes.get("generate-video")
console.log(node.providers) // every video model id
console.log(node.creditCost) // Nodaro Cloud onlyTo show prices next to the models, pass node.providers to client.credits.modelCosts().
run(type, params?, options?)
Starts one node and returns at once. The body is sent to POST /v1/<type>, the route every generation node uses. Field names match the node's input fields.
run(type: string, params?: Record<string, unknown>, options?: { idempotencyKey?: string }): Promise<RunNodeResult>Prop
Type
const result = await client.nodes.run("generate-image", {
prompt: "A snow leopard in the mountains",
provider: "nano-banana-2",
})
if ("jobId" in result) {
const { data: job } = await client.jobs.getStatus(result.jobId)
console.log(job.status)
}What comes back. Most node types are asynchronous: the result carries a jobId, and a worker does the generation. Poll client.jobs.getStatus(jobId) until it ends, or use runAndWait(). A few inline node types, such as combine-text, return their full result at once, without a jobId. Branch on the presence of jobId.
Parameter corrections. On the image node types (generate-image, image-to-image and edit-image), the server may correct a value the chosen model does not accept. The run goes ahead with the corrected value, and the credits reserved match it. The result then carries adjustments, one entry per corrected field:
const result = await client.nodes.run("generate-image", {
prompt: "A snow leopard",
provider: "gpt-image-2",
aspectRatio: "3:2",
})
if ("adjustments" in result && result.adjustments?.length) {
for (const a of result.adjustments) {
console.warn(`${a.field}: ${a.from} -> ${a.to ?? "(dropped)"} (${a.reason})`)
}
}Each adjustment has field (aspectRatio, resolution, quality or duration), from, to and reason. adjustments is absent when nothing changed.
Throws InsufficientCreditsError when the account cannot pay, StorageExceededError when storage is full, and JobBlockedError when a content policy of the deployment refuses the request. See Errors.
runAndWait(type, params?, opts?)
Runs one asynchronous node to completion. It calls run(), takes the jobId, and polls client.jobs.getStatus() until the job ends. It resolves with the job's output when the status is completed.
runAndWait(type: string, params?: Record<string, unknown>, opts?: RunAndWaitOptions): Promise<NodeJobOutput>Prop
Type
const output = await client.nodes.runAndWait(
"generate-video",
{ prompt: "Rain falls on a neon street at night", provider: "seedance-2-fast", duration: 4 },
{ onProgress: (s) => console.log(`${s.progress ?? 0}%`) },
)
console.log(output.videoUrl, output.thumbnailUrl)The output is a NodeJobOutput: imageUrl for image nodes, videoUrl and thumbnailUrl for video nodes, audioUrl for audio nodes, plus any other fields the node writes. Audio Separation, for example, adds one URL per stem, such as vocalUrl and instrumentalUrl.
It throws these typed errors:
| Error | When |
|---|---|
InsufficientCreditsError, StorageExceededError, JobBlockedError | The run request was refused, before any polling. |
JobFailedError | The job ended as failed or cancelled. It carries jobId and the job's error message. |
JobTimeoutError | maxMs passed. The job is not cancelled. |
JobAbortedError | Your signal fired. The job is not cancelled. |
JobHeldError | The job is held for human review, on deployments with a content policy. |
Slow recoveries. Sometimes a model delivers its result after the worker gave up on it. The job then stays processing with recovering: true while the platform recovers it, which can take tens of minutes for slow models. If JobTimeoutError ends your wait, fetch the job later with client.jobs.get(jobId), or raise maxMs.
runMany(type, paramsList, opts?)
Starts several runs of one node type at the same time and waits for all of them, for example to generate a grid of candidates. Each entry runs through runAndWait().
runMany(type: string, paramsList: Record<string, unknown>[], opts?: RunAndWaitOptions): Promise<RunManyResult[]>Prop
Type
const results = await client.nodes.runMany("generate-image", [
{ prompt: "A snow leopard at sunrise" },
{ prompt: "A snow leopard at golden hour" },
{ prompt: "A snow leopard at blue hour" },
])
for (const { jobId, output } of results) console.log(jobId, output.imageUrl)It resolves when every run has finished, to one { jobId, output } per entry, in input order. It rejects as soon as any run fails, with the same errors as runAndWait(). To choose the best result afterwards, pass the URLs to client.reduce.run().
Typed parameters
Four node types have typed parameters, so your editor completes and checks their fields. Every other node type takes a plain object; its fields are the node's input fields, listed in inputSchema and on its page in the Node Reference. The 3D scene nodes also have typed parameters: see 3D scenes.
| Node type | Parameter type | Node page |
|---|---|---|
generate-image | GenerateImageParams | Generate Image |
generate-video | GenerateVideoParams | Generate Video |
text-to-video | TextToVideoParams | Generate Video |
assemble-narrated-video | AssembleNarratedVideoParams | Assemble Narrated Video |
Every typed parameter object also accepts other fields of the route. The server validates the full body.
GenerateImageParams
Prop
Type
GenerateVideoParams
The image-to-video lane: a start frame, an optional end frame, and references.
Prop
Type
TextToVideoParams
The prompt-only video lane, POST /v1/text-to-video. The prompt is required, and start and end frames belong to generate-video instead. A model without a text-to-video mode answers 400 image_required.
Prop
Type
AssembleNarratedVideoParams
Joins video blocks with narration into one video. The run costs 3 + ceil(blocks / 6) credits. See Assemble Narrated Video for how each block is fitted to its narration.
Prop
Type
References
generate-image, generate-video and text-to-video accept references the way the editor wires them. The server turns them into numbered directives such as @image_1 in the prompt, so you do not write "Image 1 is..." yourself.
connectedReferencesis a list ofConnectedReferenceentries, the editor's wired-reference shape, exported from the SDK. The server removes duplicates and keeps as many as the model accepts.referenceOrdersets their order by id.- Identity lock. An entry may carry
identityLock: { enabled: true, text? }. The server then adds a short line that tells the model to keep that reference's identity.textreplaces the built-in wording, and{ref}in it stands for the reference's name. It is off by default. describedReferencestakes up to 10{ name, description }entries for subjects you can name but have no picture of, such as a role in a script. Each becomes a lineName — description.in the prompt. Keep the name in your prompt text, so the model knows who it is.descriptionOverrideon a reference entry replaces its stored description for this run only.- Captions for video and audio references.
referenceVideoCaptionsandreferenceAudioCaptionsfollow the order ofreferenceVideoUrlsandreferenceAudioUrls. Each caption appears in the prompt as@video_1: caption.or@audio_1: caption.. - Mention an image reference in the prompt. On
generate-image, name a reference and mention it as@<name>:<index>or@<name>:<index>:<role>, for example@town:1:background. The mention renders that reference, or its role, at that point of the prompt.~lockand~nolockwork as on character mentions.
See Reference roles for the roles you can use and Consistent characters for identity work.
Direction
generate-image, generate-video and text-to-video accept a direction object of picker ids instead of words. Nodaro writes tested wording for each id into the prompt, so your code sends ids and the wording stays up to date.
await client.nodes.runAndWait("generate-image", {
prompt: "A detective waits under a street lamp",
direction: { shotSize: "wide-shot", timeOfDay: "golden-hour", mood: "suspicious" },
})- Keys are picker dimensions, such as
shotSize,lightingStyle,style,mood,photographerorera. The video routes add motion keys, such ascameraMotion,actionFx,transition,loopSubjectand thetemporalkeys. - Values are one id or an array of ids. A dimension that takes several values keeps at most its own limit and drops the rest. The request is refused only above 8 values per key or 100 characters per id.
- Unknown keys and ids are skipped, not refused. An empty
directionleaves your prompt unchanged. - One map serves images and video. A still-only key sent to a video run is accepted and adds nothing.
extend-videotakes nodirection, because its prompt continues an existing clip.
Read the valid ids from client.pickerCatalogs. See Picker catalogs for every dimension.
Language-model nodes
run(type, params) posts to /v1/<type>. For language-model nodes that route exists only for generate-script, image-critic, qa-check and describe-to-picker. The other language-model nodes use a longer path, so call them with client.request():
| Node type | Endpoint |
|---|---|
llm-chat | /v1/llm-chat/generate |
after-effects | /v1/after-effects/generate |
motion-graphics | /v1/motion-graphics/generate |
lottie-overlay | /v1/lottie-overlay/generate |
3d-title | /v1/3d-title/generate |
image-to-text | /v1/image-to-text/describe |
video-composer | /v1/scene-graph/generate |
await client.nodes.run("generate-script", {
prompt: "A 3-scene product launch script for a smart water bottle",
reasoningEffort: "high",
})reasoningEffortis"none","low","medium","high","xhigh"or"max", depending on the model. Omit it, or send a level the model does not support, for the model's default.xhighandmaxbill one credit tier higher. See Prompt for the models and their tiers.advancedMode: trueruns a Gemini model directly on its maker's API. Only there dotemperature,maxTokensand the full effort range take full effect. It bills one credit tier higher, on top of any effort increase. A model without that option answers400 advanced_mode_unsupported.- Streaming is not wrapped. The SDK does not read the streaming answer of the Prompt node. Use
fetchwith a readable stream for it.
Model-specific rules
Some video models accept values the others do not. Each model page lists the full options and prices.
- Seedance 2 accepts
resolution: "4k"andaspectRatio: "adaptive"or"21:9". Seedance 2 Fast and Seedance 2 Mini render at 480p or 720p only. - Seedance 2.5 renders at 480p, 720p or 1080p, runs up to 30 seconds in one call, and takes 30 image, 10 video and 10 audio references. With a start frame it uses that frame's aspect and refuses an explicit
aspectRatio. - MiniMax Hailuo 3 (
minimax-h3) takes 9 image, 3 video and 3 audio references atresolution: "2K"(the default) or"768P". Any other value renders and bills as 2K. - Wan 3.0 (
wan-3and the fasterwan-3-prime) takes 10 image, 5 video and 5 audio references. The reference lists cannot be combined withimageUrlorendFrameUrl.durationis a whole number from 2 to 30, andresolutionis480p,720por1080p. - Gemini Omni Flash takes the same request as Gemini Omni: durations of 4, 6, 8 or 10 seconds, 720p to 4K, and 16:9 or 9:16 only.
Text to Speech. When you omit provider, Text to Speech uses ElevenLabs v3 for text up to 3,000 characters. Longer text falls back to ElevenLabs Turbo v2.5, whose limit is 40,000 characters, so it is not cut short. A provider you name is always used.
Scrapers and other input nodes
Input nodes run the same way. A scraper, such as Web Scrape, answers at once: the result carries a jobId for your history and the data itself, so you can use it without polling. The request fields are the node's input fields, listed in inputSchema.
Frequently asked questions
Related
Jobs and executions
Models and credits
Nodes
Node reference
CLI
Last updated on
Jobs and executions
Poll, list, cancel and delete Nodaro runs from TypeScript. client.jobs tracks single generations, and client.executions tracks whole workflow runs.
Apps and templates
Browse and run published Nodaro apps from TypeScript, read their run history, clone workflow templates into a project, and list the tutorials.