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

# Create a campaign (multi-chapter book → game)

> Turn a whole **book** (`text`) into **N linked chapter-worlds** — one story spine and one playable world per chapter — through the same book pipeline that `POST /v1/worlds {text}` runs for a single chapter, extended to segment the book, build a shared story bible + spine, and author each act in order.

**Always asynchronous** → `202 { jobId, campaignId }`. The campaign container is created immediately; chapters are authored by a background job. Poll `GET /v1/jobs/{jobId}` for progress (`actsDone`/`actsTotal`) and `GET /v1/campaigns/{id}` for the chapters authored so far.

**Metering: one `generation` per chapter**, reserved fail-closed right before each chapter is authored (not a flat per-request charge). If a mid-campaign chapter hits the daily quota the job stops with the chapters authored so far intact (partial campaign) and no half-charge; already-authored chapters are never re-charged on a retry.

**Character carry.** One canonical character reference is carried into EVERY chapter's seed so the protagonist stays visually identical across the whole book — same face, build, hair and clothing. Provide it as `subject_ref` (a hosted `image_url`, or `image_b64` which is hosted first); if you omit it the server paints one protagonist reference from the book bible and carries THAT into every chapter. The chosen reference is stamped on each chapter world's `subjectRef`, so you can keep generating more scenes for any chapter with `POST /v1/worlds/{id}/scenes`.

A **test**-mode key returns a deterministic mock campaign (a canned `campaignId` + one mock chapter, `jobId: "test_mock"`) with no quota spend and no generation.




## OpenAPI

````yaml /alakazam-v1.yaml post /v1/campaigns
openapi: 3.0.3
info:
  title: 'Alakazam: Programmable Worlds API'
  version: '1.0'
  description: >
    **Alakazam is the programmable worlds API.** Generate playable, AI-rendered
    worlds from a prompt or an image, program their logic, and embed them in
    your own products and games.


    A world is *programmable*: a live graph of states and events you generate,
    then read, edit, fork, drive, and react to through the API. Two surfaces: a
    **Creation API** (generate, read, manage, fork worlds) and a **Runtime/Embed
    API** (mint short-lived session tokens your end-users' browsers use to boot
    an embedded world).


    **Authentication.** Two schemes. Management endpoints (`/v1/apps*`) use your
    Supabase user session. Data endpoints use an **API key** issued per app:
    `pk_…` (publishable, browser-safe, read-only) and `sk_…` (secret,
    server-only — create/edit worlds and mint session tokens). Embedding a world
    in a browser uses a short-lived **session token** minted server-side with a
    secret key (not a publishable key directly). Never ship a secret key to a
    browser.


    **Test vs live.** Keys come in `test` and `live` modes — the prefix tells
    you which (`sk_test_…`/`pk_test_…` vs `sk_live_…`/`pk_live_…`). A **test**
    key runs against a sandbox: every generative endpoint returns a
    deterministic mock marked `"mock": true`, with no GPU or vendor spend; test
    worlds/characters are isolated from live data (forced `private`, never
    slugged or discoverable); and test usage is **never** billed. See the
    Testing guide.


    **Usage, quota & billing.** Every operation is counted against a per-app
    daily quota, reserved before any GPU spend. Exceeding it returns `402`. The
    quota is a free abuse guard, not a charge. Billing, when enabled, is
    **runtime-only**: you pay for `session_seconds` (live play time). Creating
    worlds and every other operation are free. Test-mode usage is never billed,
    even after billing is enabled. The API is in developer preview. See Pricing.


    **Building with an AI coding agent?** Install the skill (`npx skills add -g
    https://docs.alakazam.gg/skill.md`) and the MCP server (`npx
    @alakazamworld/mcp`) so your agent knows this API and can call it live. See
    the Agent quickstart.
servers:
  - url: https://api.alakazam.gg
    description: Production (placeholder, set to your conjure-service host)
security: []
tags:
  - name: Apps & Keys
    description: >-
      Create apps (tenants) and manage API keys. Authenticated with your user
      session.
  - name: Worlds
    description: >-
      Create, read, manage, and fork SMWorld games. Authenticated with an API
      key.
  - name: Graph editing
    description: >
      Read and program a world's graph of states (nodes), events (edges), and
      the entrance, using deterministic CRUD, a batch op vocabulary, a
      natural-language kernel-agent edit, and the kernel validate/lint gate.
      Every write is validated fail-closed before it persists. Authenticated
      with an API key.
  - name: Versions
    description: >
      Snapshot, branch, check out, and diff a world's graph. Versions form a
      branching tree of full snapshots; a HEAD pointer tracks the working graph.
      Authenticated with an API key.
  - name: Characters
    description: >
      Create, manage, and talk to characters: a SMWorld subtype that pairs a
      stance-graph with a "brain" (persona, lore, voice). CRUD is authenticated
      with an API key. The live talk turn (/say) and voice (/tts) are called
      from the browser with a short-lived session token.
  - name: Scenario Studio
    description: >
      Author variation/counterfactual plans over an episode or scenario, submit
      them as durable batches (N verified clips), poll them, and accept/reject
      each result. Nothing bills at submit — a clip is charged only when
      accepted; rejected and failed clips never touch the ledger. Authenticated
      with an API key.
  - name: Sessions
    description: Mint short-lived runtime tokens for embedding a world.
  - name: Usage
    description: Per-app usage and quota.
  - name: Webhooks
    description: >-
      Register HTTPS endpoints to receive signed server-side event
      notifications. Managed with your user session.
  - name: Simulation & Data
    description: >
      **Beta — self-hosted runner.** Drive a world headlessly as a training
      environment (gym) and stream the SNN-controller observation contract: two
      virtual proximity sensors, collision spikes, object labels, and an
      optional square RGB camera. The same schema is emitted offline by the
      dataset exporter (JSONL episodes + train-ready NPZ), so controllers
      trained on recorded data plug straight into the live loop.
paths:
  /v1/campaigns:
    post:
      tags:
        - Worlds
      summary: Create a campaign (multi-chapter book → game)
      description: >
        Turn a whole **book** (`text`) into **N linked chapter-worlds** — one
        story spine and one playable world per chapter — through the same book
        pipeline that `POST /v1/worlds {text}` runs for a single chapter,
        extended to segment the book, build a shared story bible + spine, and
        author each act in order.


        **Always asynchronous** → `202 { jobId, campaignId }`. The campaign
        container is created immediately; chapters are authored by a background
        job. Poll `GET /v1/jobs/{jobId}` for progress (`actsDone`/`actsTotal`)
        and `GET /v1/campaigns/{id}` for the chapters authored so far.


        **Metering: one `generation` per chapter**, reserved fail-closed right
        before each chapter is authored (not a flat per-request charge). If a
        mid-campaign chapter hits the daily quota the job stops with the
        chapters authored so far intact (partial campaign) and no half-charge;
        already-authored chapters are never re-charged on a retry.


        **Character carry.** One canonical character reference is carried into
        EVERY chapter's seed so the protagonist stays visually identical across
        the whole book — same face, build, hair and clothing. Provide it as
        `subject_ref` (a hosted `image_url`, or `image_b64` which is hosted
        first); if you omit it the server paints one protagonist reference from
        the book bible and carries THAT into every chapter. The chosen reference
        is stamped on each chapter world's `subjectRef`, so you can keep
        generating more scenes for any chapter with `POST
        /v1/worlds/{id}/scenes`.


        A **test**-mode key returns a deterministic mock campaign (a canned
        `campaignId` + one mock chapter, `jobId: "test_mock"`) with no quota
        spend and no generation.
      parameters:
        - name: Idempotency-Key
          in: header
          required: false
          schema:
            type: string
          description: >
            A retried request with the same key returns the original `{ jobId,
            campaignId }` without starting a second campaign. Keyed per (app,
            mode, key value) in its own `campaign:` namespace.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - text
              properties:
                text:
                  type: string
                  maxLength: 200000
                  description: >
                    The book (or a long excerpt) to adapt, as plain text.
                    Required, must be a non-empty string, capped at 200000
                    characters. A non-string, empty/whitespace-only, or over-cap
                    value → `400`.
                name:
                  type: string
                  description: >-
                    Optional campaign title; defaults to a title distilled from
                    the book bible.
                fidelity:
                  type: string
                  enum:
                    - faithful
                    - spirit
                  default: faithful
                  description: >
                    How closely the chapters track the source text — `faithful`
                    (hew to the book's events and settings) or `spirit` (keep
                    the tone/premise, invent freely). Defaults to `faithful`.
                target_acts:
                  type: integer
                  minimum: 2
                  maximum: 12
                  description: >
                    Optional TARGET for how many chapters to author — the story
                    planner aims for it but may author more or fewer (within
                    2..12) to fit the book's natural act breaks, so treat it as
                    guidance, not a guarantee. If present it must be an integer
                    in 2..12 (else `400`); omitted, the spine picks a count.
                    Chapter count is hard-capped at 12 to bound cost.
                subject_ref:
                  type: object
                  description: >
                    Optional canonical-character reference carried into EVERY
                    chapter's seed (the PIXEL subject lock, applied book-wide).
                    Omit it and the server auto-paints one protagonist reference
                    from the bible and carries that instead. Normalized before
                    anything is persisted: an `image_b64` is hosted to a durable
                    URL; a `data:` URI passed as `image_url` is rejected (`400`)
                    — host it first or send it as `image_b64`.
                  properties:
                    image_b64:
                      type: string
                      description: >-
                        Base64 reference image (raw base64 or a data: URL
                        accepted here). Hosted to a durable URL, then discarded.
                    image_url:
                      type: string
                      description: >-
                        URL of an ALREADY-hosted reference image (used
                        verbatim). Must NOT be a data: URI — that is rejected
                        with 400.
                    descriptor:
                      type: string
                      description: >-
                        Optional prose descriptor of the character, appended to
                        seed prompts as a confirmation.
      responses:
        '202':
          description: >-
            Campaign created; chapters authoring asynchronously. Poll the job
            for progress and the campaign for chapters. (No quota is reserved
            here — each chapter reserves one `generation` as the worker authors
            it, so a daily-quota `402` surfaces on the JOB, not on this call.)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateCampaignResponse'
        '400':
          description: >-
            Invalid body: `text` missing / not a string / empty / over 200000
            chars; `name` not a string; `fidelity` not `faithful`/`spirit`;
            `target_acts` present but not an integer in 2..12; or an invalid
            `subject_ref` (a data: URI in image_url — host it first, or pass the
            bytes as image_b64).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Authentication required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: >-
            API key is missing the required scope (worlds:write) — e.g. a
            publishable (pk_) key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '502':
          description: >-
            subject_ref hosting failed — a supplied `subject_ref.image_b64`
            could not be hosted to a durable URL. FAIL CLOSED: no campaign is
            created (the paid character reference would otherwise be silently
            dropped). Safe to retry.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - ApiKeyAuth: []
components:
  schemas:
    CreateCampaignResponse:
      type: object
      description: >
        Returned by POST /v1/campaigns (always `202`). Generation is
        asynchronous: the campaign container exists immediately; its chapters
        are authored by a background job. Poll GET /v1/jobs/{jobId} for progress
        (`actsDone`/`actsTotal`) and GET /v1/campaigns/{id} for the chapters
        authored so far.
      required:
        - jobId
        - campaignId
      properties:
        jobId:
          type: string
          description: >-
            The durable book→game job to poll (GET /v1/jobs/{jobId}). A
            test-mode key returns the sentinel `test_mock` (no real job).
        campaignId:
          type: string
          format: uuid
          description: The new campaign's id (GET /v1/campaigns/{id}).
        schemaVersion:
          type: string
          example: '1.0'
    Error:
      type: object
      properties:
        detail:
          type: string
          description: Human-readable error message.
        errors:
          type: array
          items:
            type: string
          description: Field-level validation errors (e.g. on 422 from POST /v1/worlds).
        schemaVersion:
          type: string
      required:
        - detail
  securitySchemes:
    ApiKeyAuth:
      type: http
      scheme: bearer
      description: >-
        An app API key, e.g. `Authorization: Bearer sk_live_…`. Secret (`sk_`)
        for writes/sessions; publishable (`pk_`) is read-only (browser-safe).

````