> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kymaapi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# JavaScript / Node.js

> Integrate Kyma API with JavaScript using the OpenAI SDK.

## Install

```bash theme={null}
npm install openai
```

## Setup

```javascript theme={null}
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://kymaapi.com/v1",
  apiKey: "ky-your-api-key",
});
```

## Basic chat

```javascript theme={null}
const response = await client.chat.completions.create({
  model: "qwen-3.6-plus",
  messages: [
    { role: "system", content: "You are a helpful assistant." },
    { role: "user", content: "What is machine learning?" },
  ],
});

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

## Streaming

```javascript theme={null}
const stream = await client.chat.completions.create({
  model: "llama-3.3-70b",
  messages: [{ role: "user", content: "Write a story" }],
  stream: true,
});

for await (const chunk of stream) {
  const content = chunk.choices[0]?.delta?.content;
  if (content) process.stdout.write(content);
}
```

## With fetch (no SDK)

```javascript theme={null}
const response = await fetch("https://kymaapi.com/v1/chat/completions", {
  method: "POST",
  headers: {
    "Authorization": "Bearer ky-your-api-key",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    model: "qwen-3.6-plus",
    messages: [{ role: "user", content: "Hello!" }],
  }),
});

const data = await response.json();
console.log(data.choices[0].message.content);
```

## Generating images and videos

Image and video models use a separate async endpoint. POST to `/v1/images/generations` or `/v1/videos/generations`, get a `job_id` back, poll `/v1/jobs/{id}` until status is `succeeded`. Use `fetch` directly - the OpenAI SDK does not cover these endpoints.

```javascript theme={null}
const API = "https://kymaapi.com/v1";
const headers = {
  Authorization: "Bearer ky-your-api-key",
  "Content-Type": "application/json",
};

const submit = await fetch(`${API}/videos/generations`, {
  method: "POST",
  headers,
  body: JSON.stringify({
    model: "kling-3-pro",
    prompt: "A drone shot over a misty mountain range at sunrise",
    duration: 5,
  }),
}).then((r) => r.json());

let job;
do {
  await new Promise((r) => setTimeout(r, 3000));
  job = await fetch(`${API}/jobs/${submit.id}`, { headers }).then((r) => r.json());
} while (!["succeeded", "failed", "expired", "refunded"].includes(job.status));

console.log(job.output.url);
```

Same pattern for `/v1/images/generations`: swap the model (`flux-1.1-ultra`, `ideogram-v3`, `recraft-v3`, `flux-kontext-pro`) and omit `duration`.
