SegmindSegmind / Docs

JavaScript SDK

Run any Segmind model from Node.js and TypeScript. Async-by-default run(), a blocking runSync(), submit/wait jobs for long renders, a normalized LLM chat(), presigned file uploads, request history, webhooks and PixelFlow workflows — with retries that never bill twice.

The Segmind JavaScript SDK is a typed client over the AI Gateway for Node.js 22+ and TypeScript. It mirrors the Python SDK: run() submits to the v2 async API, waits for the result and returns it, and runSync() makes one blocking v1 call.

Version 0.2. This page covers models, LLM chat, file uploads, request history, webhooks, PixelFlow workflows, the catalog and your account. Realtime sessions arrive in 0.3. Until 1.0, a breaking change ships in a new minor version, so pin segmind@~0.2 if you need the API to hold still.

Install

npm install segmind

The package ships ESM and CommonJS builds with TypeScript types, and has no dependencies. It needs Node.js 22 or later, which provides the global fetch it uses.

Set your API key once via the environment:

export SEGMIND_API_KEY="YOUR_API_KEY"

The SDK reads SEGMIND_API_KEY automatically. Grab a key from the API Keys page.

Quick start

import { Segmind } from 'segmind';

const segmind = new Segmind(); // reads SEGMIND_API_KEY

// Submit to v2, wait until COMPLETED, return the result body.
const result = await segmind.run('seedream-4.5', { prompt: 'a red rose on a wooden table' });
console.log(result.output); // URL to the generated image
import { writeFile } from 'node:fs/promises';
import { Segmind } from 'segmind';

const segmind = new Segmind();

// One blocking v1 call. Returns the fetch Response.
const response = await segmind.runSync('seedream-4.5', { prompt: 'a red rose on a wooden table' });
await writeFile('rose.jpg', Buffer.from(await response.arrayBuffer()));

Prefer plain functions? The module-level exports use a shared client built from SEGMIND_API_KEY:

import * as segmind from 'segmind';

const result = await segmind.run('seedream-4.5', { prompt: 'a cyberpunk city at night' });

Model inputs and call options

Every call takes the model inputs as its second argument, exactly as the model page lists them, and call options as an optional third:

await segmind.run(
  'seedream-4.5',
  { prompt: 'a lighthouse in a storm', aspect_ratio: '16:9' }, // model inputs
  { timeout: 120_000, signal: controller.signal },               // call options
);

Keeping them apart means a model input that happens to be called timeout still reaches the model. Times are in milliseconds.

API

segmind.run(slug, params?, options?)

Submits to POST /v2/{slug}, polls until the request reaches COMPLETED, and resolves with the result body. Polls every 1 s and gives up after 10 minutes unless you pass timeout and interval.

OptionDefaultDescription
timeout600000Give up waiting after this many ms (the request keeps running server-side).
interval1000Milliseconds between status checks.
signal—An AbortSignal that cancels the call.
requestIdgeneratedIdempotency key. See Retries that never bill twice.
const result = await segmind.run('seedream-4.5', { prompt: 'a sunset over the ocean' });
console.log(result.output);

segmind.runSync(slug, params?, options?)

One blocking call to POST /v1/{slug}. Resolves with the standard fetch Response: read .arrayBuffer() for binary output (images, audio) or .json() for JSON. Fine for fast models; v1 is in maintenance mode.

runSync is never retried, because every v1 call bills.

segmind.submit(slug, params?, options?)

Submits a v2 request and resolves with a Job immediately, without waiting for the result. Use it for long renders, to keep the requestId, or to start many requests in parallel.

const job = await segmind.submit('seedance-2.0', { prompt: 'a sunset timelapse' });
console.log(job.requestId); // e.g. "2c7f59ea-13f1-402c-9353-915a2b5a2124"

const result = await job.wait({ timeout: 15 * 60_000, interval: 5_000 });

Job

MemberReturnsDescription
.requestIdstringUnique id for the request.
.statusUrlstringLightweight status endpoint (no payload).
.responseUrlstringFull result endpoint.
.status()Promise<JobStatus>Current status without waiting. status is one of QUEUED, PROCESSING, COMPLETED, FAILED.
.result()Promise<RunResult>The finished result. Throws InferenceFailed if the request failed, and a SegmindError if it hasn't finished yet.
.wait({ timeout, interval, signal })Promise<RunResult>Wait for a terminal state and return the result. Throws InferenceFailed / InferenceTimeout.

Retries that never bill twice

Every v2 submit carries an X-Request-ID. If the connection drops or the gateway answers 429, 502 or 504, the SDK sends the submit again with the same id, and the gateway returns the request it already started instead of starting (and billing) a second one.

To make a submit idempotent across process restarts, pass your own id (8–128 characters of A-Z, a-z, 0-9, _, -):

const job = await segmind.submit('seedream-4.5', { prompt: 'a red rose' }, { requestId: `order-${orderId}` });

Status checks and reads retry connection errors and 408, 429, 502, 503 and 504 (honouring Retry-After), up to maxRetries times.

LLM chat

For text and LLM models, chat() returns a ChatResponse with a provider-agnostic .text. It is async-by-default like run(), with chatSync() and submitChat() counterparts.

const reply = await segmind.chat('gpt-5.5', { prompt: 'Write a haiku about the sea' });
console.log(reply.text);

Pass either prompt or the model's own messages: an array for OpenAI- and Anthropic-style models, or Gemini's { system_instruction, contents } object for Gemini models, sent unchanged. Images go in a message with the imageUrl() helper, which accepts a URL, a data URI, a file path (Node) or bytes:

import { imageUrl } from 'segmind';

const described = await segmind.chat('gpt-5.5', {
  messages: [
    {
      role: 'user',
      content: [{ type: 'text', text: "What's in this image?" }, await imageUrl('cat.png')],
    },
  ],
});
MemberDescription
.textThe assistant's text, whichever model family answered.
.json().text parsed as JSON, for structured output (response_format).
.usageToken usage as the model reported it.
.finishReasonWhy generation stopped, as the model reported it.
.toolCallsTool calls requested by the model, or [].
.rawThe model's full response body.

Streaming is not supported by the gateway, and stream: true is refused. See the v2 async reference for the underlying response shape.

Catalog and account

const catalog = (await segmind.models.list())['Inference Model Information List'];
console.log(catalog.length, catalog[0].slug, catalog[0].type);

const account = await segmind.accounts.current();

Each catalog entry carries slug, title, type (imageToVideo, textToImage, …), description, parameters_schema, and flags such as is_new and is_depreciated.

Files

files.upload() hosts a file so you can pass its URL as a model input. It accepts a path (Node), a Blob or File, or bytes, and sends the file straight to storage on a presigned URL, so large videos never travel as base64 JSON.

const { url } = await segmind.files.upload('portrait.jpg');
const result = await segmind.run('some-image-to-image-model', { image: url });

// Several at once, in order
const uploaded = await segmind.files.upload([firstBytes, secondBlob]);

Each call returns { url, filename, size }. Bytes without a name need { filename: 'clip.mp4' } unless their type can be read from the first bytes (PNG, JPEG, GIF, WebP, MP4, MP3, WAV and PDF can).

These URLs are public and temporary: uploads are kept for at least two days, long enough for a model to fetch them. The Python SDK's files.upload returns persistent Segmind Storage URLs instead; use that API when you need a file to stay.

Request history

// Generated outputs, newest first
const page = await segmind.generations.list({ modelName: 'flux-schnell' });
console.log(page.total_records, page.data[0]?.generation_url);

// Every request with its cost and outcome, failures included
const failed = await segmind.generations.history({ status: 'FAILED', perPage: 50 });

// One request by id, of any age; the newest few for one model
const one = await segmind.generations.get(requestId);
const latest = await segmind.generations.recent('flux-schnell');
CallReturns
list({ page, modelName, startDate, endDate, userId })Generated outputs, with status, credits_deduction (USD), latency_ms, prompt and the input parameters.
history({ page, perPage, fromDate, toDate, modelName, status, sortBy, sortOrder, userId, userEmail })Requests, failed and in-flight ones included, with request_body and error. The window defaults to the last 7 days and spans at most 31.
get(requestId)One of your own requests. A teammate's id is not found.
recent(modelName)The newest generations for one model.

Dates are YYYY-MM-DD. Both pages carry total_records, total_pages, current_page, per_page, has_next, has_previous and data. history lists a request once per output, each row with the request's full cost: de-duplicate on request_id before summing credits_deduction.

Webhooks

Manage webhook registrations without opening the console:

const hook = await segmind.webhooks.add('https://example.com/hooks/segmind', ['PIXELFLOW']);

const hooks = await segmind.webhooks.get(); // each carries its signing_secret
await segmind.webhooks.update(hook.id, 'https://example.com/hooks/v2', ['PIXELFLOW']);
await segmind.webhooks.logs(hook.id);   // delivery history
await segmind.webhooks.delete(hook.id); // deactivates it

Event types are subscription types: PIXELFLOW for PixelFlow runs. One active registration is allowed per set of types, so a second add for the same types is refused with a 409. See Webhooks for what each delivery contains.

PixelFlow workflows

Run a published workflow by its API slug, which you can copy from the workflow's API tab. Inputs are keyed by each input's keyname.

const result = await segmind.pixelflows.run('your-workflow-slug', {
  Text_Prompt: 'An infographic about green tea',
});
console.log(result.outputs); // { image_out: 'https://images.segmind.com/...' }

run() submits, polls and returns { status, outputs, raw }. outputs maps each output keyname to its URL or value; raw is the engine's own body. For long workflows, submit and wait with your own deadline:

const job = await segmind.pixelflows.submit('your-workflow-slug', { Text_Prompt: '...' });
console.log(job.requestId);
const done = await job.wait({ timeout: 20 * 60_000, interval: 5_000 });

// Later, from another process:
const state = await segmind.pixelflows.getStatus(job.requestId);
const finished = await segmind.pixelflows.poll(job.requestId);

Runs use the current workflow engine (/workflows/v2/{slug}, see the Workflow API Reference); pass { engine: 'v1' } for the legacy one. A submit is never retried, because a run bills. A failed run throws InferenceFailed whose detail names the node that failed, and a run past its timeout throws InferenceTimeout.

Error handling

ErrorThrown whenProperties
SegmindErrorBase class for every SDK error, including HTTP errors (401, 404, 5xx)..status, .detail, .requestId, .body
APIConnectionErrorNo response arrived: a network failure or the per-request timeout.—
InferenceFailedA request or PixelFlow run reached FAILED..detail (the reason; for a workflow, the failing node), .requestId, .statusBody
InferenceTimeoutwait() passed its timeout first. The request may still finish — call job.wait() again..requestId, .elapsedMs
import { InferenceFailed, InferenceTimeout, Segmind } from 'segmind';

const segmind = new Segmind();
try {
  const result = await segmind.run('seedream-4.5', { prompt: 'a red rose' });
  console.log(result.output);
} catch (err) {
  if (err instanceof InferenceFailed) console.error(`Model failed: ${err.detail}`);
  else if (err instanceof InferenceTimeout) console.error(`Still running: ${err.requestId}`);
  else throw err;
}

Client options

const segmind = new Segmind({
  apiKey: process.env.SEGMIND_API_KEY, // the default
  timeout: 600_000,                     // ms per HTTP request
  maxRetries: 2,                        // for retryable reads and submits
  fetch: customFetch,                   // any fetch implementation
  defaultHeaders: { 'x-my-header': 'value' },
});

SEGMIND_BASE_URL overrides the gateway host, for example to point at a proxy.

Browsers and React Native

Keep your API key on a server. Anyone using a web or mobile app can read a key shipped inside it. The constructor refuses an API key in a browser or React Native app, so call Segmind from your backend and give the app your own endpoint. Pass dangerouslyAllowBrowser: true only for internal tools where exposing the key is acceptable.

Worked example: slow video model

Video generation can take several minutes, longer than run()'s default 10-minute wait for some models. Submit, keep the id, and wait with your own deadline:

import { InferenceFailed, InferenceTimeout, Segmind } from 'segmind';

const segmind = new Segmind();
const job = await segmind.submit('seedance-2.0', { prompt: 'a sunset timelapse over the ocean' });
console.log(`Submitted ${job.requestId}`);

try {
  const result = await job.wait({ timeout: 15 * 60_000, interval: 5_000 });
  console.log(result.output); // URL to the generated video
} catch (err) {
  if (err instanceof InferenceTimeout) console.log(`Not done yet; poll ${job.statusUrl} later`);
  else if (err instanceof InferenceFailed) console.log(`Failed: ${err.detail}`);
  else throw err;
}

For truly long-running or fire-and-forget jobs, register a webhook instead of polling.

See also

On this page