Nodaro Docs
DocumentationNode ReferenceModelsAI Agents (MCP)DevelopersSelf-hostingResearch
TypeScript SDK

Jobs and executions

Poll, list, cancel and delete Nodaro runs from TypeScript. client.jobs tracks single generations, and client.executions tracks whole workflow runs.

A job is one generation in Nodaro, such as one image, one video render or one voiceover, and an execution is one run of a whole workflow. client.jobs reads, lists, cancels and deletes jobs, and client.executions reads, lists and cancels workflow runs. client.videoPro stops or continues a long Generate Video Pro run. The methods call the same endpoints as the Jobs and Executions REST APIs.

Methods

MethodWhat it does
executions.get(id)Read a workflow run, with the state of every node
executions.listForWorkflow(workflowId, params?)List the runs of a workflow
executions.cancel(id, params?)Stop a workflow run
jobs.get(id)Read a job with its input and output
jobs.list(params?)List your jobs, newest first
jobs.getStatus(id)Read the status of a job, for polling
jobs.cancel(id)Stop a job and refund its reserved credits
jobs.delete(id)Delete a job and the media it produced
videoPro.stop(jobId)Stop a Generate Video Pro run and keep what is done
videoPro.continueRun(jobId, opts?)Continue a Generate Video Pro run as a new job

Statuses

A job moves through these statuses:

Job statusMeaning
pending, queuedWaiting for a worker.
processingRunning. progress goes from 0 to 100 when the model reports it.
pending_reviewHeld for human review by a content policy of this deployment. Not an end state.
completedDone. output_data holds the result.
failedFailed. error_message explains why, and error_hint may classify it.
cancelledStopped by a cancel.

An execution has its own statuses: pending, running, completed, failed, cancelled, stopping, timed_out and discarded. Each node inside it is pending, running, completed, failed or skipped.

client.executions

An execution is one run of a workflow. It groups one job per AI node and the state of every node.

executions.get(id)

Reads a workflow run, including a map of every node's state. When the id belongs to a single-node job instead of a workflow run, the server answers with the same shape for that one node.

get(id: string): Promise<{ data: WorkflowExecution }>

Prop

Type

const { data } = await client.executions.get(executionId)
console.log(data.status, `${data.completedNodes}/${data.totalNodes}`, data.totalCreditsUsed)

A WorkflowExecution has id, workflowId, status, triggerType (manual, webhook, schedule, app_run or single-node), nodeStates, totalNodes, completedNodes, failedNodes, totalCreditsUsed, errorMessage, startedAt, completedAt, createdAt and updatedAt.

Reading a node's output. nodeStates[nodeId].output is present when the node completed. It can also be present when the node failed but the run kept a usable result, as the 3D scene nodes do. Check the field, not the status, and never treat a present output as success:

import { nodeStateMayCarryOutput } from "@nodaro/sdk"

const node = data.nodeStates["scene-1"]
if (node.status === "failed") {
  console.error(node.error) // the failure stands
  if (node.output?.plan) {
    // the draft the run kept is still here, and it was billed
  }
}
nodeStateMayCarryOutput(node.status) // true for "completed" and "failed"

OUTPUT_BEARING_NODE_STATUSES, the set of those two statuses, is exported too.

executions.listForWorkflow(workflowId, params?)

Lists the runs of one workflow, newest first, a page at a time. The list includes single-node runs started on that workflow.

listForWorkflow(workflowId: string, params?: ListExecutionsForWorkflowParams): Promise<{
  data: WorkflowExecutionSummary[]
  nextCursor?: string
}>

Prop

Type

const { data: runs, nextCursor } = await client.executions.listForWorkflow(workflowId, {
  limit: 20,
  status: "completed",
})

executions.cancel(id, params?)

Stops a workflow run. There are three ways to stop it:

  • Immediately (the default): running jobs are cancelled, their reserved credits are refunded, and the status becomes cancelled.
  • mode: "after_current": the status becomes stopping. Running nodes finish and land on the canvas and in your library, then the run stops.
  • mode: "discard": no new nodes start, but running jobs are not cancelled, because an external model call cannot be stopped halfway. They finish and are saved to your library, but their results do not return to the canvas. The status becomes discarded, and there is no refund, because the jobs completed.
cancel(id: string, params?: { mode?: "after_current" | "discard" }): Promise<{ success: true }>

Prop

Type

await client.executions.cancel(executionId, { mode: "after_current" })

client.jobs

A job is one generation: one image, one video render, one voiceover. A workflow run creates one job per AI node, and every single-node run creates one job. Job fields use snake_case, as the API sends them.

jobs.get(id)

Reads a job, including its input and output.

get(id: string): Promise<{ data: Job }>

Prop

Type

const { data: job } = await client.jobs.get(jobId)
if (job.status === "completed") console.log(job.output_data)

A Job has these fields:

FieldDescription
id, status, progressThe job id, its status and its progress from 0 to 100.
input_data, output_dataThe request and the result. Server-only values are removed from both.
error_messageWhy the job failed, or null.
error_hintA structured reason for some failures. See below.
creditsThe credits reserved for the job, or null.
credit_statusreserved, committed or refunded: where the credits stand. null for a job without a charge.
job_typeThe kind of job.
created_at, started_at, completed_atTimestamps.
user_idThe owner.
source, source_detailWhere the job came from: sdk, cli, mcp, app, web, api and more, with a detail such as sdk/2.17.0.
recoveringtrue while the platform recovers a job whose worker stopped after the model delivered.

error_hint has two kinds. Narrow on kind before you read the rest:

  • safety-block: the model's own safety filter refused the output. class is copyright, likeness or safety. retried says whether Nodaro already retried once, and suggestedProvider, when present, names a model you can retry the same request on. See When a model blocks the prompt.
  • policy-block: a content policy of this deployment rejected the request or the result. reason is written for users, so show it as it is.

jobs.list(params?)

Lists your jobs, newest first, a page at a time (GET /v1/jobs).

list(params?: { type?: string; origin?: string; limit?: number; cursor?: string }): Promise<{
  data: Job[]
  next: string | null
}>

Prop

Type

let cursor: string | undefined
do {
  const page = await client.jobs.list({ type: "llm-structured", origin: "my-app", cursor })
  for (const job of page.data) console.log(job.id, job.status)
  cursor = page.next ?? undefined
} while (cursor)

A page can hold fewer rows than limit, even none, and still have a next. Page on next, never on the number of rows.

jobs.getStatus(id)

Reads only the status of a job: id, status, progress, output_data, error_message, error_hint and credit_status (GET /v1/jobs/:id/status). It skips the request data and the cost fields, so it is much lighter than get(). Use it in polling loops.

getStatus(id: string): Promise<{ data: JobStatusResult }>

Prop

Type

async function waitForJob(jobId: string) {
  for (;;) {
    const { data } = await client.jobs.getStatus(jobId)
    if (data.status === "completed") return data.output_data
    if (data.status === "failed" || data.status === "cancelled") {
      throw new Error(data.error_message ?? data.status)
    }
    await new Promise((resolve) => setTimeout(resolve, 2_000))
  }
}

client.nodes.runAndWait() runs this loop for you, with progress, cancellation and typed errors.

jobs.cancel(id)

Cancels a job and refunds the credits it had reserved. A job held for review can be cancelled too.

cancel(id: string): Promise<{ success: true; cancelled: number }>

Prop

Type

const { cancelled } = await client.jobs.cancel(jobId)

jobs.delete(id)

Deletes a job and the private media it produced (DELETE /v1/jobs/:id). Only the job's owner may delete it. A running job is deleted as it is, so cancel it first when its worker should stop.

delete(id: string): Promise<{ success: true }>

Prop

Type

await client.jobs.cancel(jobId)
await client.jobs.delete(jobId)

client.videoPro

Run control for Generate Video Pro, the node that renders long videos in segments. It works on Nodaro Cloud. Start the run like any node run, then use these methods on its job.

videoPro.stop(jobId)

Stops a running Generate Video Pro job gracefully. The segment in progress is abandoned and still billed, and the remaining segments are skipped. The finished segments are joined into the job's final video, and the unused reserve is refunded. A job that has not started yet is cancelled with a full refund.

stop(jobId: string): Promise<StopVideoProResult>

Prop

Type

await client.videoPro.stop(jobId)
const { data } = await client.jobs.getStatus(jobId) // becomes completed, with the partial video

Keep polling the job. It completes with output_data.pro.stopped set to true.

videoPro.continueRun(jobId, opts?)

Continues a stopped, failed or completed run as a new job. Segments before fromSegment are reused, and every segment from it on is generated again. You pay only for the regenerated segments plus the flat Pro fee.

continueRun(jobId: string, opts?: { fromSegment?: number }): Promise<ContinueVideoProResult>

Prop

Type

const { jobId: newJobId, fromSegment } = await client.videoPro.continueRun(jobId, { fromSegment: 4 })

The result carries the new jobId to poll, and may carry continuedFromJobId, fromSegment, segmentCount and deduped.

Frequently asked questions

Last updated on

On this page