Skip to main content
This guide takes you from zero to a finished image in five steps: create a key, verify it, submit a generation, poll for the result, and download it. Every call targets the base URL:
https://api.samsa.ai/public/v1
The examples use a fake key (samsa_sk_example…) and placeholder ids. Replace them with your own. Store your key in an environment variable so it never lands in source control:
export SAMSA_API_KEY="samsa_sk_exampleXf9Lp2QyaBcDeFgHiJkLmNoPqRsTuVwx"

Create an API key

API keys are organization-owned and can only be created by an organization admin (OWNER or ADMIN).
1

Open your organization settings

In the Samsa app, go to your organization settings and open the API Keys tab.
2

Create a key

Give the key a name. By default it is granted all scopes (images.generate, images.edit, videos.generate, models.read, models.write, usage.read); narrow them if the integration needs less. You can also set an optional expiry.
3

Copy the key now

The full key (samsa_sk_…) is shown exactly once, at creation. Samsa stores only a hash and can never display it again. Copy it immediately and keep it somewhere safe — if you lose it, revoke the key and create a new one.
Keys act for their organization: credits are drawn from the organization’s pool, and any images or videos you generate appear in the app under the account of the admin who created the key.

Verify the key with GET /me

GET /me is the fastest way to confirm a key works. It returns the key’s organization, its safe metadata (prefix, scopes, expiry — never the secret), and the organization’s available credit balance.
curl https://api.samsa.ai/public/v1/me \
  -H "Authorization: Bearer $SAMSA_API_KEY"
import os
import requests

BASE_URL = "https://api.samsa.ai/public/v1"
API_KEY = os.environ["SAMSA_API_KEY"]
HEADERS = {"Authorization": f"Bearer {API_KEY}"}

resp = requests.get(f"{BASE_URL}/me", headers=HEADERS)
resp.raise_for_status()
print(resp.json())
const BASE_URL = "https://api.samsa.ai/public/v1";
const API_KEY = process.env.SAMSA_API_KEY!;
const headers = { Authorization: `Bearer ${API_KEY}` };

const resp = await fetch(`${BASE_URL}/me`, { headers });
if (!resp.ok) throw new Error(`GET /me failed: ${resp.status}`);
console.log(await resp.json());
Response
{
  "organization": {
    "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
    "name": "Acme Inc"
  },
  "api_key": {
    "id": "9c8d7e6f-5a4b-4c3d-2e1f-0a9b8c7d6e5f",
    "name": "Production key",
    "prefix": "samsa_sk_exam",
    "scopes": [
      "images.edit",
      "images.generate",
      "models.read",
      "models.write",
      "usage.read",
      "videos.generate"
    ],
    "expires_at": null
  },
  "credits": {
    "available": 1450
  }
}

Generate an image

Submit a prompt to POST /images/generations. Here we also compose one of the organization’s trained style models by passing its id or name as style_id — a name resolves to a model visible to you. You can combine object_ids, person_ids, setting_ids, and a color_palette_id the same way (the color palette is referenced by id only). The request returns 202 immediately with a job id; the image is produced asynchronously.
curl -X POST https://api.samsa.ai/public/v1/images/generations \
  -H "Authorization: Bearer $SAMSA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "A minimalist product shot of a ceramic mug on linen, soft daylight",
    "style_id": "2b9d1f7a-3c4e-4a5b-9c8d-0e1f2a3b4c5d",
    "aspect_ratio": "1:1",
    "resolution": "1K",
    "num_outputs": 1
  }'
payload = {
    "prompt": "A minimalist product shot of a ceramic mug on linen, soft daylight",
    "style_id": "2b9d1f7a-3c4e-4a5b-9c8d-0e1f2a3b4c5d",
    "aspect_ratio": "1:1",
    "resolution": "1K",
    "num_outputs": 1,
}

resp = requests.post(
    f"{BASE_URL}/images/generations",
    headers={**HEADERS, "Content-Type": "application/json"},
    json=payload,
)
resp.raise_for_status()
job = resp.json()
generation_id = job["id"]
print(job)
const payload = {
  prompt: "A minimalist product shot of a ceramic mug on linen, soft daylight",
  style_id: "2b9d1f7a-3c4e-4a5b-9c8d-0e1f2a3b4c5d",
  aspect_ratio: "1:1",
  resolution: "1K",
  num_outputs: 1,
};

const submit = await fetch(`${BASE_URL}/images/generations`, {
  method: "POST",
  headers: { ...headers, "Content-Type": "application/json" },
  body: JSON.stringify(payload),
});
if (!submit.ok) throw new Error(`generation failed: ${submit.status}`);
const job = await submit.json();
const generationId = job.id;
console.log(job);
Response — 202 Accepted
{
  "id": "7f9c0e2a-1b3d-4c5e-8f6a-9b0c1d2e3f40",
  "status": "pending",
  "estimated_credits": 5
}
The default engine is nano_banana_pro (pass engine to choose nano_banana_2). num_outputs defaults to 1; each output costs 5 credits at 1K, scaling with resolution (1K ×1, 2K ×2, 4K ×4). The style_id — an id or a name — must reference a completed model visible to you.

Poll for the result

Poll GET /images/generations/{id} until status is completed (or failed). Statuses are pending, processing, completed, failed, and cancelled.
curl https://api.samsa.ai/public/v1/images/generations/7f9c0e2a-1b3d-4c5e-8f6a-9b0c1d2e3f40 \
  -H "Authorization: Bearer $SAMSA_API_KEY"
import time

while True:
    resp = requests.get(
        f"{BASE_URL}/images/generations/{generation_id}",
        headers=HEADERS,
    )
    resp.raise_for_status()
    result = resp.json()
    if result["status"] in ("completed", "failed", "cancelled"):
        break
    time.sleep(2)

print(result)
async function poll(id: string) {
  while (true) {
    const resp = await fetch(`${BASE_URL}/images/generations/${id}`, { headers });
    if (!resp.ok) throw new Error(`poll failed: ${resp.status}`);
    const result = await resp.json();
    if (["completed", "failed", "cancelled"].includes(result.status)) {
      return result;
    }
    await new Promise((r) => setTimeout(r, 2000));
  }
}

const result = await poll(generationId);
console.log(result);
Response — completed
{
  "id": "7f9c0e2a-1b3d-4c5e-8f6a-9b0c1d2e3f40",
  "status": "completed",
  "created_at": "2026-07-02T12:00:00Z",
  "credits_used": 5,
  "images": [
    {
      "id": "d4c3b2a1-6f5e-4b3a-9d8c-1e0f2a3b4c5d",
      "url": "https://cdn.samsa.ai/user-.../7f9c0e2a.png?X-Amz-Signature=...",
      "thumbnail_url": "https://cdn.samsa.ai/user-.../7f9c0e2a-thumb.png?X-Amz-Signature=...",
      "width": 1024,
      "height": 1024,
      "seed": 128390
    }
  ],
  "error": null
}

Download the result

Each entry in images carries a presigned HTTPS url that is valid for 24 hours — download and store the asset before it expires.
curl -o mug.png \
  "https://cdn.samsa.ai/user-.../7f9c0e2a.png?X-Amz-Signature=..."
image_url = result["images"][0]["url"]
img = requests.get(image_url)
img.raise_for_status()
with open("mug.png", "wb") as f:
    f.write(img.content)
const imageUrl = result.images[0].url;
const img = await fetch(imageUrl);
const buffer = Buffer.from(await img.arrayBuffer());
await import("node:fs/promises").then((fs) => fs.writeFile("mug.png", buffer));

Next steps

API reference

The base URL, authentication, and the conventions every endpoint shares.

MCP server

Connect Samsa to Claude, ChatGPT, or any MCP client and generate media as tools — over OAuth or an API key.
Prefer push over polling? Pass a webhook_url on any generation request to receive a signed callback the moment the job reaches a terminal status.