> ## 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.

# Deliver the kept episodes (THE billing gate)

> Export every episode whose FINAL verdict is accept (the machine verdict, flipped where a human overruled it) into the campaign's delivery archive, optionally publishing to a Hugging Face repo. Returns `202` immediately; poll the campaign's `delivery` object (status `exporting` → `exported` [→ `publishing` → `published`], or `failed`), then download GET …/export.tar.gz.

**You pay for what you take, this is the ONE billing gate.** 1 credit per kept episode entering THIS delivery that has never been billed on this campaign, debited atomically from your credits wallet BEFORE the export starts. The paid set persists on the campaign, so a re-deliver only charges episodes added since; concurrent delivers serialize; and a retried delivery finds its ledger receipt instead of paying twice. Only episodes whose render artifacts still exist are exported, and billed (artifacts pruned from disk are never charged for). On insufficient credits the call returns `402` with `detail` EXACTLY `insufficient_credits:need=N` (N = the unpaid episode count) and NOTHING is charged or exported. Signed-in identities without a configured wallet backend fail CLOSED (503, delivery disabled).

`target_repo` (optional) additionally publishes the export to a Hugging Face dataset repo; its namespace must be on the server's allowlist (403 otherwise; 400 when not `namespace/name`).




## OpenAPI

````yaml /forge-api-v1.yaml post /api/workbench/campaigns/{campaign_id}/deliver
openapi: 3.0.3
info:
  title: Alakazam Forge API
  version: '1.0'
  description: |
    The Forge Dataset Workbench API: upload or import robotics datasets,
    audit them, propose and run augmentation campaigns, review, and deliver.
    Served by the Forge workbench service at forge.alakazam.gg (not
    api.alakazam.gg).
servers:
  - url: https://forge.alakazam.gg
    description: Forge (Dataset Workbench)
security: []
tags:
  - name: Dataset Workbench
    description: |
      **Served at `https://forge.alakazam.gg`** (not the main API host). The
      Forge Dataset Workbench is the client surface of the robotics
      data-augmentation service: bring a LeRobot robot dataset, a public
      Hugging Face repo, a resumable chunked upload, or a one-click curated
      sample, and walk one owner-scoped **campaign** through the spine
      Source & Health → Sample → Transform → Run + Verify → Deliver, leaving
      with a verified augmented dataset. Every endpoint requires a **Supabase
      user access token** (`Authorization: Bearer …`, the `UserAuth` scheme);
      a missing or invalid token returns `401`, and another user's campaigns,
      runs, and uploads read as `404`. Errors use the platform envelope
      `{"detail": "…"}`. Nothing bills until **Deliver**, which charges 1
      credit per never-before-billed kept episode from your credits wallet.
  - name: Playground batches
    description: |
      The Forge playground's "describe a change" flow is not a REST surface on
      this host: a described change is submitted as a **scenario batch**
      through the platform (the Supabase RPC `create_scenario_batch`) and its
      progress/results stream back over Supabase realtime on the
      `scenario_batches` table. For the equivalent public REST surface, see
      **Scenario Studio** (`/v1/scenario-batches`).
paths:
  /api/workbench/campaigns/{campaign_id}/deliver:
    servers:
      - url: https://forge.alakazam.gg
        description: Forge (Dataset Workbench)
    post:
      tags:
        - Dataset Workbench
      summary: Deliver the kept episodes (THE billing gate)
      description: >
        Export every episode whose FINAL verdict is accept (the machine verdict,
        flipped where a human overruled it) into the campaign's delivery
        archive, optionally publishing to a Hugging Face repo. Returns `202`
        immediately; poll the campaign's `delivery` object (status `exporting` →
        `exported` [→ `publishing` → `published`], or `failed`), then download
        GET …/export.tar.gz.


        **You pay for what you take, this is the ONE billing gate.** 1 credit
        per kept episode entering THIS delivery that has never been billed on
        this campaign, debited atomically from your credits wallet BEFORE the
        export starts. The paid set persists on the campaign, so a re-deliver
        only charges episodes added since; concurrent delivers serialize; and a
        retried delivery finds its ledger receipt instead of paying twice. Only
        episodes whose render artifacts still exist are exported, and billed
        (artifacts pruned from disk are never charged for). On insufficient
        credits the call returns `402` with `detail` EXACTLY
        `insufficient_credits:need=N` (N = the unpaid episode count) and NOTHING
        is charged or exported. Signed-in identities without a configured wallet
        backend fail CLOSED (503, delivery disabled).


        `target_repo` (optional) additionally publishes the export to a Hugging
        Face dataset repo; its namespace must be on the server's allowlist (403
        otherwise; 400 when not `namespace/name`).
      parameters:
        - name: campaign_id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                target_repo:
                  type: string
                  nullable: true
                  example: your-org/augmented-dataset
                  description: >-
                    Optional Hugging Face repo (namespace/name) to publish to.
                    Omit (or send empty) to only export server-side for the
                    tar.gz download.
      responses:
        '202':
          description: >
            Delivery started (billing already settled). `billed_episodes` is how
            many episodes THIS call billed, 0 when everything entering the
            export was already paid for on an earlier delivery (or for the free
            local dev tenant).
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: exporting
                  target_repo:
                    type: string
                    nullable: true
                  billed_episodes:
                    type: integer
                    description: Episodes newly billed by this delivery (1 credit each).
        '400':
          description: >-
            No runs to deliver; no accepted+confirmed episodes; or target_repo
            is not namespace/name.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Authentication required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '402':
          description: >-
            Insufficient credits, `detail` starts with
            `insufficient_credits:need=N` (N = credits short) and appends
            machine-actionable pointers:
            `:checkout=/api/billing/credits/checkout:packs=/api/billing/credits/packs`.
            Nothing was charged and no export started.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Publishing to this namespace is not enabled on this server
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Campaign not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: >-
            The kept episodes' render artifacts are no longer on disk, re-run,
            then deliver.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '503':
          description: >-
            Billing backend not configured or unreachable (fail closed, no
            unledgered export).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - UserAuth: []
components:
  schemas:
    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:
    UserAuth:
      type: http
      scheme: bearer
      description: >
        Either a Supabase user access token (from a password login, or the
        passwordless magic-link flow) or a long-lived `forge_sk_…` API key. Both
        are sent as `Authorization: Bearer <value>` and resolve to the same
        owner, so every endpoint accepts either. Session tokens expire in ~1h;
        API keys do not expire and are the credential for MCP clients, CI, and
        partner integrations.

````