Source: https://docs.sogni.ai/sogni-intelligence/billing-and-cost-control/

# 💳Billing & Cost Control

Sogni Intelligence bills both **LLM inference** (chat and planning tokens) and **creative media work** in two token types, and exposes per-request controls to **estimate**, **cap**, and **explicitly approve** media costs before any paid work runs. This page collects the rules and primitives that appear individually on the chat, durable-run, and workflow endpoints.

> Pass `token_type` to pick which balance pays. For workflows, use `max_estimated_capacity_units` as a hard cap and `confirm_cost: false` to get an estimate before starting. For chat runs, set `runtime_config.requireJobConfirmation: true` to pause before paid media work. These controls are not a total USD or account-wide budget: LLM inference bills separately as consumed. Watch `run_waiting_for_user` events for media-approval pauses.

* * *

## [#](https://docs.sogni.ai/sogni-intelligence/billing-and-cost-control/#token-types)Token types

| Token | What it pays for | How to get it |
| --- | --- | --- |
| **SOGNI** | Native Sogni Supernet inference — all Sogni-trained / Sogni-hosted models (Qwen LLMs, Z-Image, Chroma, Qwen Image Edit, FLUX, Wan video, Ace-Step 1.5 XL audio, etc.) | Earned from [running a worker node](https://docs.sogni.ai/run-a-worker/fast-worker/about-sogni-fast-worker/), staking, and seasonal [leaderboard](https://sogni.ai/leaderboard) airdrops; also available on the [open market](https://coinmarketcap.com/currencies/sogni-ai/#Markets) |
| **Premium Spark** | External-vendor models (OpenAI GPT Image 2 and GPT Image 2.5 Sunburst/Flare, [ByteDance Seedance 2.0](https://www.sogni.ai/models/seedance-2-0) / Fast / Mini and [Seedance 2.5](https://docs.sogni.ai/models/seedance-2-5/), [Alibaba HappyHorse 1.1](https://www.sogni.ai/models/happyhorse-1-1), [Wan 3](https://docs.sogni.ai/models/wan-3/), and [Wan 3 Uncensored](https://docs.sogni.ai/models/wan-3-uncensored/)) **and** can also pay for any native model | Purchased at [dashboard.sogni.ai](https://dashboard.sogni.ai/) with a credit card or with [USDC/USDT stablecoins](https://docs.sogni.ai/pricing/pay-with-crypto/) |
| **Free Spark** | Native Sogni Supernet models only; cannot pay for vendor/premium models. Accounts subject to free API restrictions use Krea 2 Turbo (`krea2_turbo_fp8_scaled`) as of September 2026. Eligibility can differ by account and subscription; a model listing alone is not approval to use free Spark. | Claim the [Monthly Boost](https://docs.sogni.ai/rewards/monthly-boost-reward/): 400 free Spark per UTC month, available when your free-Spark balance is under 800 |

> Learn more: [SOGNI token vs Spark Points](https://docs.sogni.ai/run-a-worker/supernet/sogni-token-vs-spark-points/).

### [#](https://docs.sogni.ai/sogni-intelligence/billing-and-cost-control/#selecting-which-token-pays)Selecting which token pays

Every paid endpoint accepts a `token_type` field:

| `token_type` | Behavior |
| --- | --- |
| `"sogni"` | Pay in SOGNI when supported. Falls back to Spark for vendor-only jobs (e.g. GPT Image 2). |
| `"spark"` | Pay in Spark for everything in the request. Required for vendor models. |
| `"auto"` | Default. Pays with Spark first and falls back to SOGNI; vendor models always use Spark. |

Send `token_type` in the JSON body. `/v1/chat/completions` also accepts an `X-Token-Type` header (the body wins); other endpoints read the body only. Tool execution inside a chat completion or chat run inherits the request's `token_type`; vendor-model tool calls are normalized to Spark even if the parent request asked for `sogni` / `auto`.

```
{
  "model": "qwen3.6-35b-a3b-gguf-iq4xs",
  "messages": [{"role": "user", "content": "Make a hero image"}],
  "token_type": "spark"
}
```

* * *

## [#](https://docs.sogni.ai/sogni-intelligence/billing-and-cost-control/#llm-token-spend)LLM token spend

LLM inference is billable, not just media generation. Every chat turn fires many small billable LLM calls — the assistant rounds plus auxiliary cognition (vision analysis, prompt refinement, transition planning). These are denominated in the request's `token_type` (Spark or SOGNI) and surfaced as a single per-turn line item in Billing history (category **Chat**, with input/output/total token counts), distinct from media (category **Media**).

In durable chat runs the authoritative per-round cost arrives on the [`llm_spend`](https://docs.sogni.ai/sogni-intelligence/durable-chat-runs/#event-types) SSE event (`costInToken`, `costInUSD`, `tokenType`, `modelName`, and token counts). Dedupe on `payload.eventId` when tallying.

LLM-token spend is **not** gated by `confirm_cost` — only worker / vendor / ffmpeg media work pauses for approval. The cost-control primitives below (`max_estimated_capacity_units`, `confirm_cost`, cost-approval pauses) govern media work; LLM tokens bill as they are consumed.

* * *

## [#](https://docs.sogni.ai/sogni-intelligence/billing-and-cost-control/#vendor-model-gating)Vendor-model gating

GPT Image 2 (`gpt-image-2`) and GPT Image 2.5 Sunburst/Flare (`gpt-image-2.5-sunburst`, `gpt-image-2.5-flare`), [Seedance 2.0](https://www.sogni.ai/models/seedance-2-0) (`seedance2`, `seedance2-mini`) and [Seedance 2.5](https://docs.sogni.ai/models/seedance-2-5/) (`seedance2-5`), [HappyHorse 1.1](https://www.sogni.ai/models/happyhorse-1-1) (`happyhorse-1.1-t2v`, `happyhorse-1.1-i2v`, `happyhorse-1.1-r2v`), [Wan 3](https://docs.sogni.ai/models/wan-3/) (`wan3.0-video`), and [Wan 3 Uncensored](https://docs.sogni.ai/models/wan-3-uncensored/) (`wan3.0-spicy-video`) are **external-vendor models**. The legacy `seedance2-fast` selector is still accepted but routes to the faster, lower-cost `seedance2-mini`. Two rules apply that don't apply to native models:

1.  **They require Premium Spark.** A request that asks for them with `token_type: "sogni"` is normalized to Spark for those tool calls; no automatic fallback to SOGNI tokens.
2.  **Hosted chat only uses them when the account can pay.** Name the vendor model explicitly to be sure you get it — ask for it in the user message so the LLM emits the right tool-call arguments, write the tool call yourself (`sogni_tool_execution: false`), or name it in a workflow step's `arguments.model` / `arguments.videoModel`. Hosted chat may also choose a GPT Image model for storyboard or character-sheet work; if the account is not eligible for Premium Spark, chat substitutes a Sogni-hosted model instead. Workflows never substitute: a workflow that names a vendor model on an ineligible account returns `402` with `details.vendorModels` before any step runs.

In chat completions, the simplest path is to name the vendor model in the user message so the LLM picks it up:

```
{
  "messages": [
    { "role": "user", "content": "Use GPT Image 2 to generate the product hero on wet asphalt with neon rim light." }
  ],
  "model": "qwen3.6-35b-a3b-gguf-iq4xs",
  "token_type": "spark",
  "sogni_tools": "creative-tools"
}
```

In durable workflows, name the vendor model directly inside the step's `arguments`:

```
{
  "input": {
    "title": "GPT Image 2 hero",
    "steps": [
      {
        "id": "hero",
        "toolName": "generate_image",
        "arguments": {
          "prompt": "Product hero on wet asphalt with neon rim light",
          "model": "gpt-image-2",
          "gptImageQuality": "high",
          "outputFormat": "png"
        }
      }
    ]
  },
  "token_type": "spark"
}
```

For the full vendor-model option matrix (quality flags, output formats, context-image limits, audio windows for Seedance), see [Chat Completions → External Media Models](https://docs.sogni.ai/sogni-intelligence/chat-completions/#external-media-models).

* * *

## [#](https://docs.sogni.ai/sogni-intelligence/billing-and-cost-control/#estimated-capacity-units)Estimated capacity units

Durable creative workflows return an **estimated capacity-units** value: a shared cross-model unit that the API uses to express "how much paid work is this going to do." Use it for hard caps and pre-flight approval — not as an exact billing total.

-   **`compose_workflow`** (planner) returns `estimated_capacity_units` alongside the plan and a `fits_budget` flag.
-   **`POST /v1/creative-agent/workflows`** rejects a request with `400` before persistence if the shared estimate exceeds `max_estimated_capacity_units`; `details.estimatedCapacity` carries the estimate.
-   The cost preview is best-effort. Final billing is reconciled against actual worker output (steps, resolution, duration, vendor-reported usage).

```
curl https://api.sogni.ai/v1/creative-agent/workflows \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "input": { "steps": [/* ... */] },
    "token_type": "spark",
    "max_estimated_capacity_units": 25
  }'
```

Pair `max_estimated_capacity_units` on the planner call **and** on the workflow start to hard-cap cost at both ends — the planner cap guards the LLM's plan; the start cap guards the final submission.

* * *

## [#](https://docs.sogni.ai/sogni-intelligence/billing-and-cost-control/#cost-approval-flow)Cost-approval flow

Chat runs and workflows approve paid media work differently.

### [#](https://docs.sogni.ai/sogni-intelligence/billing-and-cost-control/#in-durable-chat-runs)In durable chat runs

Start the run with `runtime_config.requireJobConfirmation: true`. When the model calls a paid media tool, the run holds every paid call from that round, emits `run_awaiting_cost_confirmation` for each one, then moves to `status: "waiting_for_user"` and emits `run_waiting_for_user` with the pending details. `confirm_cost` and `max_estimated_capacity_units` are recorded on chat runs but not enforced.

```
id: 5
event: run_awaiting_cost_confirmation
data: {"sequence":5,"type":"run_awaiting_cost_confirmation","at":"...","payload":{"toolCallId":"call_abc","toolName":"generate_video","estimatedCost":18,"tokenType":"spark"}}

id: 6
event: run_waiting_for_user
data: {"sequence":6,"type":"run_waiting_for_user","at":"...","payload":{"reason":"cost_approval_required","message":"Awaiting user approval before spending credits.","details":{"toolCallId":"call_abc","pendingToolCallIds":["call_abc"],"costApprovalPreview":{"totalEstimatedCapacityUnits":18,"tokenType":"spark","validityUntil":"2026-05-15T12:05:00.000Z"}}}}
```

To approve, call `POST /v1/chat/runs/:id/confirm-cost` with the pending tool call ID, `decision: "confirm"`, and `acceptedCostPreview` echoed from `details.costApprovalPreview` (required for `confirm`; a mismatched preview returns `409`, and the preview expires five minutes after the pause). This resumes the same run:

```
{
  "tool_call_id": "call_abc",
  "decision": "confirm",
  "acceptedCostPreview": {
    "totalEstimatedCapacityUnits": 18,
    "tokenType": "spark",
    "validityUntil": "2026-05-15T12:05:00.000Z"
  }
}
```

The confirm body may also carry an `overrides` object (allowlisted to `qualityTier`, `safeContentFilter`, and `prompt` / `prompts`) for prompt or quality edits the user made on the approval screen — see [Durable Chat Runs → Cost approval](https://docs.sogni.ai/sogni-intelligence/durable-chat-runs/#run-status). To reject the pending tool call, send `decision: "cancel"` to the same endpoint. To reject the full run, cancel it with `POST /v1/chat/runs/:id/cancel`.

Chat runs pause with `cost_approval_required` or `safety_review_required`. A cost pause whose `details.flavor` is `"insufficient_credits"` cannot be resolved by confirming; add credits and submit a new run, or send `decision: "cancel"`. Workflows report a wider set of `waitingReason` values; see [Creative Workflows](https://docs.sogni.ai/api-reference/workflows/#workflows-get).

### [#](https://docs.sogni.ai/sogni-intelligence/billing-and-cost-control/#in-durable-workflows)In durable workflows

An inline workflow (`input.steps`) starts immediately unless you ask for an estimate first. Submit with `confirm_cost: false`: a plan with a positive estimate returns `400` with `details.estimatedCapacity` and `details.confirmationRequired: true`, and nothing is saved. Show the estimate, then resubmit with `confirm_cost: true` (or without the field) to start. `max_estimated_capacity_units` applies either way.

A saved-template run (`workflow_id` + `inputs`) always returns `202` with `waitingForCostApproval: true` and a `preview`, and waits for `POST /v1/creative-agent/workflows/:id/confirm-cost` with `decision: "confirm"` and the echoed `acceptedCostPreview`.

* * *

## [#](https://docs.sogni.ai/sogni-intelligence/billing-and-cost-control/#per-tool-cost-metadata)Per-tool cost metadata

Durable chat runs write a `RunRecord` (schema v2 — see [Chat Completions → Replay Records](https://docs.sogni.ai/sogni-intelligence/chat-completions/#replay-records)). Each tool call inside a round carries optional `cost_class` and `risk_level` fields from a shared per-tool cost-metadata table, so UI clients can render cost/risk chips without re-deriving from raw arguments.

```
{
  "tool_calls": [
    {
      "id": "call_abc",
      "function": { "name": "generate_video" },
      "cost_class": "high",
      "risk_level": "medium"
    }
  ]
}
```

Sample classes: `free` (analysis/metadata), `low` (single image), `medium` (multi-image), `high` (video), `vendor` (external). The exact mapping is defined per tool and surfaced through the protocol package.

* * *

## [#](https://docs.sogni.ai/sogni-intelligence/billing-and-cost-control/#hard-limits-worth-knowing)Hard limits worth knowing

-   **Video safety limit.** Hosted tool execution blocks any single request that would generate more than 20 minutes of total video content across variations, long-video segments, or batch fan-out. Split larger jobs into multiple workflow runs.
-   **Vision input cap.** `/v1/chat/completions` accepts up to 20 vision images per request, each up to 10 MB and 1024 px on the longest side.
-   **Context-image limits per model.** GPT Image 2 edit accepts up to 16 context images; Qwen Image Edit 2511 accepts up to 3. The SDK and Sogni Socket enforce these before charging.
-   **Per-account daily ceilings.** Account-level rate and spend limits apply on top of any per-request controls; visible in the dashboard.

* * *

## [#](https://docs.sogni.ai/sogni-intelligence/billing-and-cost-control/#putting-it-together-a-safe-request-pattern)Putting it together: a safe request pattern

For a chat run that may invoke paid media tools, send an `Idempotency-Key` header and this body:

```
{
  "model": "qwen3.6-35b-a3b-gguf-iq4xs",
  "messages": [
    { "role": "user", "content": "Make a 5-shot product teaser, 9:16, 15s." }
  ],
  "token_type": "spark",
  "runtime_config": { "requireJobConfirmation": true }
}
```

This gets you:

-   Spark billing (works for native and vendor models).
-   An explicit user approval step before any paid media work runs.
-   Idempotent retries — a network hiccup on submit won't start a second run.

For a workflow your app already planned (no LLM in the loop):

```
{
  "input": { "steps": [/* ... */] },
  "token_type": "spark",
  "max_estimated_capacity_units": 25,
  "confirm_cost": true
}
```

Your app already chose every step, so no LLM can add surprise work, and the hard cap rejects the plan before anything is saved if the estimate exceeds 25 units. To show the user a price first, send the same body with `confirm_cost: false`, read `details.estimatedCapacity` from the `400`, then resubmit with `confirm_cost: true`.

* * *

## [#](https://docs.sogni.ai/sogni-intelligence/billing-and-cost-control/#where-each-control-lives)Where each control lives

| Concept | Where to read more |
| --- | --- |
| `token_type` request field, vendor-model gating | [Chat Completions → External Media Models](https://docs.sogni.ai/sogni-intelligence/chat-completions/#external-media-models) |
| Durable chat run cost-approval flow | [Durable Chat Runs](https://docs.sogni.ai/sogni-intelligence/durable-chat-runs/) |
| Workflow `max_estimated_capacity_units` / `confirm_cost` | [Creative-Agent Workflows](https://docs.sogni.ai/sogni-intelligence/creative-agent-workflows/) |
| Planner `estimated_capacity_units` / `fits_budget` | [Chat Completions → Workflow Planning](https://docs.sogni.ai/sogni-intelligence/chat-completions/#workflow-planning) |
| `cost_class` + `risk_level` on tool calls | [Chat Completions → Replay Records](https://docs.sogni.ai/sogni-intelligence/chat-completions/#replay-records) |
| Token-type enum + waiting-reason enum | [`@sogni-ai/sogni-protocol`](https://docs.sogni.ai/sogni-sdk/sogni-protocol/) |
