SDK · jobs

rw.job()

Look up a generation job by id: status, output, cost and timing. Use it for image runs that answered before they finished, and for anything you started over REST. Wraps GET /api/v1/jobs/{id}.

Signature

TypeScript
rw.job(id: string): Promise<Job>

Parameters

idrequired
string
The job id, a UUID. Where it comes from is listed below.

Where job ids come from

  • Images: each entry of rw.image()'s data carries job_id at runtime (not in the 1.0.0 types, read it as (img as any).job_id).
  • Chat: the X-Railwail-Job-Id response header, or the part after chatcmpl- in the response id.
  • Video (REST): the job_id of the 202 answer from /api/v1/videos/generations.

Response

TypeScript
interface Job {
  id: string;
  object: "job";
  status: "queued" | "processing" | "completed" | "failed" | "cancelled";
  model: { name: string; slug: string; category: string; provider: string; provider_model_id: string };
  input: Record<string, unknown>;
  output: unknown;            // text, object or array, depending on the model
  output_url: string | null;  // file result (image, video, audio); may be a temporary provider URL
  cost: { credits: number; currency: "credits" };
  tokens: { input: number; output: number; total: number };
  timing: {
    created_at: number; queued_at: number | null; started_at: number | null; completed_at: number | null;
    latency_ms: number | null; duration_ms: number | null; duration_seconds: number | null;
  };
  source: string;
  provider_job_id: string | null;
  error: string | null;
}

The 1.0.0 type declares fewer fields; the ones above are what the API returns.

Polling until done

Stops on failed and cancelled as well as completed, and gives up after a deadline. Every poll counts toward your key's rate limit, so wait a few seconds between calls (5–10 s for video).

JavaScript
// poll.mjs: plain JavaScript, because railwail@1.0.0 does not type job_id on image
// results or error/output_url on jobs (in TypeScript, read them with a cast).
import railwail from "railwail";

const rw = railwail(process.env.RAILWAIL_API_KEY);

async function waitForJob(id, { intervalMs = 3000, timeoutMs = 10 * 60_000 } = {}) {
  const deadline = Date.now() + timeoutMs;
  while (Date.now() < deadline) {
    const job = await rw.job(id);
    if (job.status === "completed") return job;
    if (job.status === "failed" || job.status === "cancelled") {
      throw new Error(job.error ?? `Job ${job.status}`);
    }
    await new Promise((resolve) => setTimeout(resolve, intervalMs));
  }
  throw new Error(`Job ${id} not finished after ${timeoutMs / 1000} s`);
}

const res = await rw.image("flux-1-schnell", "A lighthouse at dusk");
const first = res.data[0];
const url = first.url ?? (await waitForJob(first.job_id)).output_url;
console.log(url);

Failed jobs are refunded

The credits held for a job come back automatically when it fails or is cancelled; the one exception is a run stopped at its GPU-time limit. cost.credits of a completed job is what was charged. See the Jobs API for statuses and errors.
rw.job() — Railwail Docs