Already using the Anthropic or OpenAI SDK? Ship your agent to production in one call.

See the quickstart

Node.js SDK

The official Jettson SDK for Node.js. Native fetch, zero runtime deps, full type coverage.

Three lines, one agent. The Node SDK is the fastest path from npm install to a running agent.

Install

bash
npm install @jettson/sdk

Requires Node 18 or later. Uses native fetch — no runtime dependencies.

Quickstart

ts
import { Jettson } from "@jettson/sdk";

const jettson = new Jettson({ apiKey: process.env.JETTSON_API_KEY! });

const agent = await jettson.agents.spawn({
  task: "Browse https://news.ycombinator.com and return the top story title.",
});

const result = await jettson.agents.wait(agent.agent_id);
console.log(result.final_result);

Get an API key at /console/api-keys.

Constructor

ts
new Jettson({
  apiKey: string,              // required
  baseUrl?: string,            // default: "https://jettson.dev/api/v1"
  maxRetries?: number,         // default: 3
})

| Option | Default | Notes | | --- | --- | --- | | apiKey (required) | — | Bearer token. Read it from env. | | baseUrl | https://jettson.dev/api/v1 | Override for testing. | | maxRetries | 3 | Retries on 429 + 5xx. Set to 0 for first-failure semantics. |

Agents

agents.spawn(input)

ts
const agent = await jettson.agents.spawn({
  task: "Research linear.app",
  name: "research-run-001",        // optional
  region: "lhr",                   // optional — "iad" | "lhr" | "syd"
  idempotencyKey: "spawn:abc:1",   // optional — dedupe accidental retries
});

Returns immediately with status: "spawning".

agents.wait(agentId, options?)

ts
const result = await jettson.agents.wait(agent.agent_id, {
  timeoutMs: 5 * 60 * 1000,    // default
  pollIntervalMs: 1000,        // initial
  maxPollIntervalMs: 5000,     // ceiling (exponential backoff)
});

Polls until status is completed / error / stopped. Throws AgentTimeoutError if the deadline lapses.

agents.get(agentId)

ts
const agent = await jettson.agents.get("ag_…");

agents.list(options?)

ts
let cursor: string | undefined;
do {
  const page = await jettson.agents.list({ limit: 50, cursor });
  for (const a of page.data) console.log(a.agent_id, a.status);
  cursor = page.next_cursor ?? undefined;
} while (cursor);

agents.cancel(agentId)

ts
await jettson.agents.cancel("ag_…");

Idempotent. Terminal agents return 200 unchanged.

Memory

memory.put(input)

ts
await jettson.memory.put({
  key: "brand_color",
  value: "Brand primary color is #FF5733",
  namespace: "user_profile",
  importance: 8,
  tags: ["brand"],
  expiresInDays: 90,   // optional
});

memory.get(key, options?)

ts
const m = await jettson.memory.get("brand_color", { namespace: "user_profile" });
if (m) console.log(m.value);

Returns null (not an error) if no memory matches.

memory.search(input)

ts
const results = await jettson.memory.search({
  query: "what color is the brand?",
  namespace: "user_profile",
  mode: "hybrid",           // "hybrid" | "semantic" | "keyword"
  limit: 10,
  minScore: 0.4,
});

Returns an array of MemorySearchResult with score and breakdown per row.

memory.list(options?) / memory.delete(key, options?) / memory.dedupe(options?) / memory.consolidate(options?) / memory.namespaces() / memory.export() / memory.import(memories)

All ten public-API memory endpoints are covered. Signatures mirror the Memory API reference.

Error handling

Every HTTP failure surfaces as a typed error. Catch the base class to handle anything, or narrow:

ts
import {
  JettsonAuthError,
  JettsonRateLimitError,
  JettsonQuotaExceededError,
  JettsonValidationError,
  JettsonNotFoundError,
  JettsonServerError,
  JettsonNetworkError,
  AgentTimeoutError,
} from "@jettson/sdk";

try {
  await jettson.agents.spawn({ task: "…" });
} catch (err) {
  if (err instanceof JettsonRateLimitError) {
    console.log(`Backing off ${err.retryAfterSeconds}s`);
  } else if (err instanceof JettsonQuotaExceededError) {
    console.log(`Hit quota: ${err.used}/${err.limit} on ${err.plan}`);
  } else {
    throw err;
  }
}

Idempotent spawns

If your code might retry a spawn because of a network blip on the way to Jettson, pass an idempotency key:

ts
await jettson.agents.spawn({
  task: "…",
  idempotencyKey: `spawn:${userId}:${requestId}`,
});

The server returns the same agent for repeat calls inside a short window.

Regions

Multi-region warm pool is live in iad / lhr / syd. Pin a region per spawn:

ts
await jettson.agents.spawn({ task: "…", region: "lhr" });

If you don't specify one, the server tries iad first then falls back to other regions before cold-spawning.

Retries

Automatic retries on:

  • 429 — honors Retry-After header (3 attempts)
  • 5xx — exponential backoff 1s → 2s → 4s (3 attempts)
  • Network failure — one retry after the initial backoff
ts
// Disable retries
new Jettson({ apiKey, maxRetries: 0 });

TypeScript types

Everything is exported:

ts
import type {
  Agent,
  AgentListResponse,
  AgentStatus,
  Memory,
  MemorySearchResult,
  MemorySearchMode,
  NamespaceInfo,
  Region,
  // …and all error classes
} from "@jettson/sdk";

Source

github.com/jettsondev/jettson-sdk-node — MIT, ~1k LOC + tests. Read it.