mrkeyoor.com_
Wed 05 Aug 05:05 UTC
npmAI / MLupdated 05 Aug 2026

openai

The official TypeScript and JavaScript client for the OpenAI REST API, generated from OpenAI's published OpenAPI spec. It covers the Responses API (now the primary interface), Chat Completions, files, fine-tuning, webhooks, and the Realtime API over WebSocket, with typed requests and responses, automatic retries with backoff, server-sent-event streaming, auto-pagination, and dedicated support for Azure OpenAI and Amazon Bedrock's OpenAI-compatible endpoint.

Verdict

If you call the OpenAI API from JavaScript, use this client; it is official, typed, and updated in step with the API. Add a provider-abstraction layer on top only when you genuinely expect to swap models.

API stability3/5The README states that backwards-incompatible type-level and low-impact changes may ship in minor releases, and the primary interface migrated from Chat Completions to Responses; Chat Completions stays supported indefinitely.
Docs4/5A long, example-dense README plus api.md and a runnable examples directory; conceptual guides live on platform.openai.com rather than in the repo, so you bounce between the two.
Maintenance5/5Official OpenAI project regenerated against the live API spec; the repo shows pushes on 2026-08-05, the day of this review.
Ecosystem4/5The de facto JS entry point to OpenAI at 33M weekly downloads; most higher-level tooling either wraps this client or mirrors its request shapes.

Use it if

  • You call OpenAI models from Node.js 22+, Deno, Bun, Cloudflare Workers, or the Vercel Edge Runtime
  • You want typed request and response objects, built-in retries, and SSE streaming without writing fetch plumbing yourself
  • You need Azure OpenAI or Bedrock's OpenAI-compatible API through the same client with the same call shapes
  • You receive OpenAI webhooks and want signature verification handled by client.webhooks.unwrap
Skip it if

Setup reality

npm install openai plus an OPENAI_API_KEY env var and you are making calls in minutes; the client reads the key by default. The friction is elsewhere: OpenAI moved its primary interface from Chat Completions to the Responses API, so examples online mix two styles, and multi-turn Responses conversations fail confusingly if you filter reasoning or tool-call items out of the history you send back. SemVer is also loose here: type-level and low-impact breaking changes are allowed in minor releases, so pin and read changelogs.

Patterns

Generate text with the Responses APIgenerate-text

import OpenAI from 'openai';

const client = new OpenAI(); // reads OPENAI_API_KEY

const response = await client.responses.create({
  model: 'gpt-5.5',
  instructions: 'You are a concise assistant',
  input: 'Are semicolons optional in JavaScript?',
});

console.log(response.output_text);

Responses is the primary API now; output_text is the convenience accessor for the generated text.

Chat Completions (legacy but supported)chat-completion

const completion = await client.chat.completions.create({
  model: 'gpt-5.5',
  messages: [
    { role: 'developer', content: 'Talk like a pirate.' },
    { role: 'user', content: 'Are semicolons optional in JavaScript?' },
  ],
});

console.log(completion.choices[0].message.content);

Chat Completions is supported indefinitely; note the developer role where older examples show system.

Stream a response with SSEstream-response

const stream = await client.responses.create({
  model: 'gpt-5.5',
  input: 'Write a haiku about build tools',
  stream: true,
});

for await (const event of stream) {
  if (event.type === 'response.output_text.delta') {
    process.stdout.write(event.delta);
  }
}

You iterate typed events, not raw text chunks; filter on event.type to get just the text deltas.

Continue a conversation across turnsmulti-turn-conversation

const first = await client.responses.create({
  model: 'gpt-5.5',
  input: 'My name is Sam.',
});

const second = await client.responses.create({
  model: 'gpt-5.5',
  previous_response_id: first.id,
  input: 'What is my name?',
});

If you manage history manually instead, keep all output items in order; filtering to just messages drops reasoning and tool-call items and breaks the next request. The toResponseInputItems() helper normalizes them.

Ask about an imagevision-image-input

const response = await client.responses.create({
  model: 'gpt-5.5',
  input: [
    {
      role: 'user',
      content: [
        { type: 'input_text', text: 'What is in this image?' },
        { type: 'input_image', image_url: 'https://example.com/photo.jpg' },
      ],
    },
  ],
});

Content is an array mixing input_text and input_image blocks; a bare string only works for text-only input.

Upload a fileupload-file

import fs from 'fs';
import OpenAI, { toFile } from 'openai';

const client = new OpenAI();

await client.files.create({
  file: fs.createReadStream('input.jsonl'),
  purpose: 'fine-tune',
});

// from raw bytes
await client.files.create({
  file: await toFile(Buffer.from('my bytes'), 'input.jsonl'),
  purpose: 'fine-tune',
});

toFile() buffers whole streams in memory; use toStreamingFile() for large streams you want sent without buffering.

Handle API errors by typehandle-errors

import OpenAI from 'openai';

try {
  await client.responses.create({ model: 'gpt-5.5', input: 'hi' });
} catch (err) {
  if (err instanceof OpenAI.APIError) {
    console.log(err.status);      // e.g. 429
    console.log(err.name);        // e.g. RateLimitError
    console.log(err.request_id);  // for OpenAI support
  } else {
    throw err;
  }
}

Connection errors, 408, 409, 429, and 5xx are already retried twice by default before you ever see them.

Configure automatic retriesconfigure-retries

// default for all requests
const client = new OpenAI({ maxRetries: 0 }); // default is 2

// or per request
await client.responses.create(
  { model: 'gpt-5.5', input: 'hello' },
  { maxRetries: 5 },
);

Retries use short exponential backoff; set maxRetries: 0 when your caller already has its own retry loop.

Set request timeoutsconfigure-timeout

const client = new OpenAI({
  timeout: 20 * 1000, // 20 seconds, default is 10 minutes
});

await client.responses.create(
  { model: 'gpt-5.5', input: 'hello' },
  { timeout: 5 * 1000 },
);

The default is a generous 10 minutes, and requests that time out are still retried twice by default.

Iterate a paginated listauto-pagination

const jobs = [];
for await (const job of client.fineTuning.jobs.list({ limit: 20 })) {
  jobs.push(job); // fetches more pages automatically
}

// or page by page
let page = await client.fineTuning.jobs.list({ limit: 20 });
while (page.hasNextPage()) {
  page = await page.getNextPage();
}

for await crosses page boundaries silently; on huge lists that means many hidden API calls.

Verify and parse a webhookverify-webhook

const client = new OpenAI({
  webhookSecret: process.env.OPENAI_WEBHOOK_SECRET,
});

export async function webhook(request: Request) {
  const body = await request.text();
  try {
    const event = client.webhooks.unwrap(body, request.headers);
    if (event.type === 'response.completed') {
      console.log('done:', event.data);
    }
    return Response.json({ message: 'ok' });
  } catch {
    return new Response('Invalid signature', { status: 400 });
  }
}

Pass the raw body string to unwrap(); parsing the JSON first breaks signature verification.

Use Azure OpenAIazure-openai

import { AzureOpenAI } from 'openai';
import { getBearerTokenProvider, DefaultAzureCredential } from '@azure/identity';

const credential = new DefaultAzureCredential();
const azureADTokenProvider = getBearerTokenProvider(
  credential,
  'https://cognitiveservices.azure.com/.default',
);

const openai = new AzureOpenAI({
  azureADTokenProvider,
  apiVersion: '2024-10-01-preview',
});

The Azure API shape differs slightly from the core API, so the static types will not always match what Azure returns.

Alternatives

PackageRegistryPick it when
@anthropic-ai/sdknpmThe equivalent official client if you are on Claude models
ainpmVercel AI SDK when you want provider-agnostic calls and UI streaming hooks
@google/genainpmThe official SDK if you are on Gemini models