Docs API reference
Markdown Get an API key

API referenceGetting started

Getting Started

Everything on this page applies to every endpoint in the reference: where the API lives, how you authenticate, how errors and rate limits behave, and how spend is billed. Read it once, then go build.

#Introduction

The Sogni REST API lives at https://api.sogni.ai. One surface covers an OpenAI-compatible chat endpoint, synchronous creative tools, a durable agent runtime, a creative-workflow engine, project status, account balances, worker analytics, and model discovery. Hosted chat and workflows stream over Server-Sent Events; everything else is an ordinary JSON read or write.

#What's here

#Quick start

The shortest path to a result: a chat completion that runs Sogni creative tools server-side.

curl https://api.sogni.ai/v1/chat/completions \
  -H "Authorization: Bearer $SOGNI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [
      {"role": "user", "content": "Generate a cinematic image of a neon alley in Tokyo during rain."}
    ]
  }'
Want the bigger picture? The Sogni Intelligence guides explain how chat, tools, and workflows fit together.

#Authentication

Authenticated endpoints accept a bearer token in the Authorization header. Create API keys in the Sogni account dashboard. Public endpoints, including aggregate worker analytics and generation-model discovery, do not require a key.

Authorization: Bearer YOUR_API_KEY

#Two credential types

  • API keys are long-lived UUIDs scoped to a wallet, intended for backend and SDK use. They are required for durable chat runs and creative workflow execution. Generate or rotate yours at dashboard.sogni.ai/api-key.
  • Session tokens are short-lived browser JWTs issued by the Sogni auth flow. Most read endpoints accept either credential type.

The legacy api-key header is still accepted, but new integrations should use Authorization: Bearer.

Treat API keys like passwords. They authorize spend on your behalf. Keep them on your server, never in a browser bundle. Rotate from the dashboard if a key is exposed; revoked keys stop authenticating immediately.

#Versioning

Each endpoint has its own versioned path. Most use /v1/*; newer-shape replacements include owner-scoped project status at /v2/projects/:id and account balances at /v4/account/balance. Use the exact path shown for each endpoint. Do not change the version prefix across your whole integration.

#Errors

The API uses standard HTTP status codes. Successful responses return 200, 201, or 202; failures return 4xx for caller mistakes and 5xx for server-side problems. Error bodies are JSON.

200OK. Synchronous success.
201Created. A workflow (inline start or reseed), a workflow template (create or fork), or a replay record was saved.
202Accepted. A durable chat run or a personal LoRA import was accepted, a workflow template run is waiting for cost approval, or a workflow resume was scheduled.
304Not modified. A cached public read matched your If-None-Match tag; reuse your cached body.
400Validation error. A body or query parameter failed validation.
401Authentication missing or invalid.
402Insufficient balance. The selected token can't cover the request, or a vendor-model step needs Premium Spark.
403Forbidden. The credential or account isn't allowed to perform the action, such as a subscriber-only feature without an active plan or publishing a public workflow template.
404Resource not found, or hidden from the caller.
409Conflict. The run or workflow is in the wrong state for the action (for example not awaiting cost approval, a stale or expired cost preview, or already finished), an idempotency key was reused with a different confirm-cost body, too many workflows are active, or a resource already exists.
413Payload too large. A replay record exceeds 1 MB, or a workflow template exceeds its size limit.
422Unprocessable entity. A workflow template failed schema validation or could not compile.
429Rate limited. Wait for the Retry-After header or the retryAfter body field (seconds) when present; otherwise back off with jitter.
500Internal error. Retry after backoff; report persistent failures.
502Upstream model error, such as a failed model stream or a malformed tool call. Retry.
503Temporarily unavailable. Retry with exponential backoff and jitter; do not treat it as data loss.
504Upstream timeout. Retry with backoff.

#Error envelopes

LLM routes (/v1/chat/completions, /v1/models) emit the OpenAI-compatible error shape:

{
  "error": {
    "message": "'messages' is required and must be a non-empty array",
    "type": "invalid_request_error",
    "param": null,
    "code": "invalid_request_error"
  }
}

All other endpoints emit the Sogni envelope:

{
  "status": "error",
  "errorCode": 102,
  "message": "Creative workflow requires input.steps"
}

Sogni envelopes may also include details (structured context, such as why a 409 happened) and retryAfter in seconds. OpenAI-shaped errors may include details. Some 429 bodies are a plain { "error": "Too Many Requests" }, and workflow template validation failures return { "status": "error", "data": { "validation": { "issues": [ … ] } } }. Branch on the HTTP status first.

#Rate limits

When a request is rate-limited, the API returns 429 Too Many Requests. Honor the Retry-After header when present. Otherwise, retry with exponential backoff and jitter. Reduce concurrency instead of immediately repeating failed requests.

Active-workflow cap. If a workflow start returns 409 because too many workflows are active, cancel or finish an existing run before submitting another, or batch work into a single multi-step workflow. Check the error message: other conflicts also use 409. The active-workflow 409 carries details.activeWorkflowCount and details.activeWorkflowLimit, and it does not use up your start allowance. A 429 on a workflow start means starts arrived too quickly or overall workflow capacity is full. A start-rate refusal carries the wait in the Retry-After header and, in seconds, in the body's retryAfter; a start sent before then is refused again. Retry with the same Idempotency-Key.

Default limits for workflows, render concurrency, and SDK connections, and how to design around them, are in Production Integrations.

#Idempotency

Write endpoints that can produce side effects accept an idempotency key. Reusing the same key for the same caller returns the original result instead of starting a duplicate run. Use it to make retries safe across network failures and double-clicks.

#Headers

Idempotency-Key: 7c9e6f7c-23a1-4f06-9d33-2dd5d6c8f5fb

X-Idempotency-Key is accepted as an alias.

#Supported endpoints

Scope. The key is scoped to the calling wallet, so the same key from a different wallet does not collide. Chat-run keys longer than 200 characters are ignored, and workflow keys longer than 192 characters are truncated; a UUID is ideal for both.

#Billing and tokens

Spend is denominated in two token types. Pick one explicitly with token_type on a request, or let the API choose.

TokenHow acquiredUsed for
sogniNative. Earned through Supernet participation or staking.Pays for Sogni-native models (such as Krea, Qwen, LTX, WAN, MiniMax H3, and ACE-Step) when selected, or as the fallback for auto.
sparkPurchased with cash, or earned.Paid first under auto. Premium Spark is required for external vendor models: gpt-image-2, gpt-image-2.5-sunburst, gpt-image-2.5-flare, seedance2, seedance2-mini, seedance2-5, happyhorse-1.1-*, wan3.0-video, and wan3.0-spicy-video.

#Selecting a token

Accepted values are auto (default), sogni, and spark. When tokens are billed, auto pays with Spark first and falls back to SOGNI.

{ "token_type": "auto" }

/v1/chat/completions also accepts an X-Token-Type header (the body field wins); other endpoints read token_type from the body only. Vendor-model jobs are normalized to spark automatically, regardless of preference.

#Plan or tokens

token_type only picks which token pays. Whether an active Unlimited plan or your token balance pays is a separate field, billing_mode, accepted by chat completions, tool execution, chat runs, and workflows (start, resume, and reseed).

billing_modeBehavior
autoDefault. An active Unlimited plan covers the work it can, and no tokens are spent on that work. Everything else bills your token balance according to token_type.
subscriptionBill eligible work against the plan only. Work the plan can't cover fails instead of billing tokens.
tokensAlways bill your token balance, even when a plan is active.

With an active plan, changing token_type between spark and auto does not move a job off the plan. To spend Premium Spark you hold, which gets fastest-priority queue access ahead of plan-covered jobs, send billing_mode: "tokens". Vendor models are never plan-covered and always bill Premium Spark. A request that asks to pay in SOGNI (token_type: "sogni") is not plan-covered either.

{ "token_type": "spark", "billing_mode": "tokens" }

#Vendor model gating

Models from external vendors (OpenAI GPT Image 2 and GPT Image 2.5 Sunburst / Flare, ByteDance Seedance 2.0 / Mini, Seedance 2.5, Alibaba HappyHorse 1.1, Wan 3, and Wan 3 Uncensored) bill Premium Spark. Hosted chat may choose a GPT Image model for storyboard or character-sheet work; if the account is not eligible for Premium Spark, chat uses a Sogni-hosted model instead. Workflows never substitute: a workflow that names a vendor model returns 402 with details.vendorModels before any step runs, including a confirm_cost: false estimate.

#Cost approval

  • Creative workflows use a two-step confirmation. Submit with confirm_cost: false to get a 400 whose details.estimatedCapacity holds the estimate, then resubmit with confirm_cost: true. max_estimated_capacity_units is a hard cap: plans over it are rejected with 400 before anything is saved. Template runs (workflow_id) always return 202 with a preview and wait for POST /v1/creative-agent/workflows/:id/confirm-cost.
  • Chat runs opt in with runtime_config.requireJobConfirmation: true. When the model calls a paid media tool, the run pauses in waiting_for_user with reason cost_approval_required, holds every paid call from that round, and emits run_awaiting_cost_confirmation for each held call. Resume or decline with POST /v1/chat/runs/:id/confirm-cost, echoing waiting.details.costApprovalPreview. confirm_cost and max_estimated_capacity_units are recorded on chat runs but not enforced.