# SDKs & Client Libraries

Use the OpenAI, Anthropic, or Google SDK against Atlas Cloud, plus copy-paste clients for image, video, and audio generation in Python and Node.js.

Source: https://atlascloud.ai/docs/en/sdks

Atlas Cloud does not ship its own SDK, and for language models you do not need one — the API speaks the formats existing SDKs already use. For media generation, this page has a small client you can copy into your project.

| What you're calling | How |
| --- | --- |
| Language models | Point the OpenAI, Anthropic, or Google SDK at Atlas Cloud |
| Image, video, audio, 3D | Plain HTTP against the asynchronous endpoints — client below |
| From a terminal or CI | The [CLI](/cli) |
| From an AI-assisted IDE | The [MCP Server](/mcp-server) |

## Language models

Change the base URL and the API key. Everything else stays the same.

<Tabs groupId="llm-sdk" items={['OpenAI Python', 'OpenAI Node.js', 'Anthropic', 'Google']}>
<Tab value="OpenAI Python">

```bash
pip install openai
```

```python
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["ATLASCLOUD_API_KEY"],
    base_url="https://api.atlascloud.ai/v1",
)

response = client.chat.completions.create(
    model="deepseek-ai/deepseek-v3.2",
    messages=[{"role": "user", "content": "Explain HTTP vs HTTPS"}],
)
print(response.choices[0].message.content)
```

</Tab>
<Tab value="OpenAI Node.js">

```bash
npm install openai
```

```javascript
import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.ATLASCLOUD_API_KEY,
  baseURL: "https://api.atlascloud.ai/v1",
});

const response = await client.chat.completions.create({
  model: "deepseek-ai/deepseek-v3.2",
  messages: [{ role: "user", content: "Explain HTTP vs HTTPS" }],
});
console.log(response.choices[0].message.content);
```

</Tab>
<Tab value="Anthropic">

```bash
pip install anthropic
```

```python
import os
from anthropic import Anthropic

client = Anthropic(
    api_key=os.environ["ATLASCLOUD_API_KEY"],
    base_url="https://api.atlascloud.ai",
)

message = client.messages.create(
    model="MODEL_ID",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Hello"}],
)
print(message.content[0].text)
```

</Tab>
<Tab value="Google">

```bash
pip install google-genai
```

```python
import os
from google import genai

client = genai.Client(
    api_key=os.environ["ATLASCLOUD_API_KEY"],
    http_options={"base_url": "https://api.atlascloud.ai"},
)

response = client.models.generate_content(
    model="MODEL_ID",
    contents="Hello",
)
print(response.text)
```

</Tab>
</Tabs>

<Callout type="warn">
Models differ in which protocol they accept — some only work with Messages, others only with Responses. Check the model's API reference before assuming Chat Completions works. See [LLM API Protocols](/llm-protocols).
</Callout>

## Media generation client

Image, video, audio, and 3D generation are asynchronous: submit, then poll. Here is a complete minimal client.

<Tabs groupId="lang" items={['Python', 'Node.js']}>
<Tab value="Python">

```python
import os
import time
import requests

API_KEY = os.environ["ATLASCLOUD_API_KEY"]
BASE = "https://api.atlascloud.ai/api/v1"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}

# The endpoint is chosen by output type: 3D uses image; speech, music and transcription all use audio
ENDPOINTS = {
    "image": f"{BASE}/model/generateImage",
    "video": f"{BASE}/model/generateVideo",
    "audio": f"{BASE}/model/generateAudio",
}
TERMINAL = {"completed", "succeeded", "failed", "timeout"}


def submit(kind: str, model: str, **params) -> str:
    """Submit a job and return its prediction ID. Parameters go at the top level, not inside an `input` object."""
    response = requests.post(
        ENDPOINTS[kind],
        headers=HEADERS,
        json={"model": model, **params},
        timeout=60,
    )
    response.raise_for_status()
    return response.json()["data"]["id"]


def wait(prediction_id: str, timeout: int = 600) -> dict:
    """Poll until the job reaches a terminal state, backing off as it goes."""
    deadline = time.time() + timeout
    delay = 2.0

    while time.time() < deadline:
        response = requests.get(
            f"{BASE}/model/prediction/{prediction_id}",
            headers=HEADERS,
            timeout=30,
        )
        response.raise_for_status()
        data = response.json()["data"]

        if data.get("status") in TERMINAL:
            if data["status"] in ("failed", "timeout"):
                raise RuntimeError(f"Generation failed: {data.get('error') or data['status']}")
            return data

        time.sleep(delay)
        delay = min(delay * 1.5, 10.0)

    raise TimeoutError(f"Job {prediction_id} did not finish within {timeout}s")


def upload(path: str) -> str:
    """Upload a local file and return a URL usable in a generation request."""
    with open(path, "rb") as f:
        response = requests.post(
            f"{BASE}/model/uploadMedia", headers=HEADERS, files={"file": f}, timeout=600
        )
    response.raise_for_status()
    data = response.json()["data"]
    return data.get("download_url") or data.get("url")


if __name__ == "__main__":
    pid = submit("image", "MODEL_ID", prompt="a ceramic mug on a linen backdrop")
    result = wait(pid)
    print(result["outputs"][0])
```

</Tab>
<Tab value="Node.js">

```javascript
const API_KEY = process.env.ATLASCLOUD_API_KEY;
const BASE = "https://api.atlascloud.ai/api/v1";
const HEADERS = { Authorization: `Bearer ${API_KEY}` };

// The endpoint is chosen by output type: 3D uses image; speech, music and transcription all use audio
const ENDPOINTS = {
  image: `${BASE}/model/generateImage`,
  video: `${BASE}/model/generateVideo`,
  audio: `${BASE}/model/generateAudio`,
};
const TERMINAL = new Set(["completed", "succeeded", "failed", "timeout"]);

/** Submit a job and return its prediction ID. Parameters go at the top level, not inside an `input` object. */
async function submit(kind, model, params = {}) {
  const response = await fetch(ENDPOINTS[kind], {
    method: "POST",
    headers: { ...HEADERS, "Content-Type": "application/json" },
    body: JSON.stringify({ model, ...params }),
  });
  if (!response.ok) throw new Error(`Submit failed: ${response.status}`);
  const { data } = await response.json();
  return data.id;
}

/** Poll until the job reaches a terminal state, backing off as it goes. */
async function wait(predictionId, timeoutMs = 600_000) {
  const deadline = Date.now() + timeoutMs;
  let delay = 2000;

  while (Date.now() < deadline) {
    const response = await fetch(`${BASE}/model/prediction/${predictionId}`, {
      headers: HEADERS,
    });
    if (!response.ok) throw new Error(`Status check failed: ${response.status}`);
    const { data } = await response.json();

    if (TERMINAL.has(data.status)) {
      if (data.status === "failed" || data.status === "timeout") {
        throw new Error(`Generation failed: ${data.error ?? data.status}`);
      }
      return data;
    }

    await new Promise((r) => setTimeout(r, delay));
    delay = Math.min(delay * 1.5, 10_000);
  }

  throw new Error(`Job ${predictionId} timed out`);
}

const pid = await submit("image", "MODEL_ID", {
  prompt: "a ceramic mug on a linen backdrop",
});
const result = await wait(pid);
console.log(result.outputs[0]);
```

</Tab>
</Tabs>

<Callout type="warn">
Two things this client gets right that are easy to get wrong:

1. **Parameters go at the top level**, next to `model` — not wrapped in an `input` object.
2. **For transcription and lyric models, `outputs[0]` is text, not a URL.** Do not blindly download it. See [Audio Models](/models/audio).
</Callout>

## Production notes

- **Prefer webhooks over polling** for video, which can take minutes. See [Webhooks](/webhooks).
- **Retry on `429`, `500`, `503`, `504`** with exponential backoff. Do not retry `400`, `401`, `402`, `403`. See [Errors & Rate Limits](/errors).
- **Be careful retrying submissions.** A timed-out submit may still have been accepted, and a blind retry creates a second billable job. Submit asynchronously and poll instead.
- **Log `X-Request-ID`** from every response — it is what support needs to trace a call.

## Community libraries

Community-maintained wrappers are listed in [awesome-atlas-cloud-integrations](https://github.com/AtlasCloudAI/awesome-atlas-cloud-integrations). They are maintained independently — verify what a wrapper does before using it in production.

## Related

<Cards>
  <Card title="LLM API Protocols" href="/llm-protocols" description="Which protocol each model accepts." />
  <Card title="Predictions" href="/predictions" description="Job lifecycle and status values." />
  <Card title="Errors & Rate Limits" href="/errors" description="Status codes and retry strategy." />
  <Card title="Integrations" href="/integrations" description="CLI, MCP, ComfyUI, n8n." />
</Cards>
