openapi: 3.1.0
info:
  title: Mudbase Cells API
  description: >
    Mudbase Cells provides on-demand, isolated code execution environments (cells/sessions)
    accessible over a REST API. Each session runs a single language runtime in an isolated
    container with a fixed timeout and optional persistent storage.

    ## Features
    - Create and manage isolated execution sessions
    - Execute commands with streaming SSE output
    - Read and write files inside running sessions
    - Start named services and expose ports to the internet
    - Persistent named cells with durable workspace volumes
    - Checkpoint and restore sessions
  version: "1.0.0"
  contact:
    name: Mudbase Support
    url: https://cells.mudbase.dev

servers:
  - url: https://api.mudbase.dev/api/sandboxes
    description: Production

security:
  - ApiKeyAuth: []
  - BearerAuth: []

components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key
      description: Project API key issued from the Mudbase console.
    BearerAuth:
      type: http
      scheme: bearer
      description: User session bearer token.

  schemas:
    Session:
      type: object
      properties:
        sessionId:
          type: string
          description: Unique session identifier.
        language:
          type: string
          description: Runtime language (e.g. node, python, go, rust, php, java, ruby, csharp).
        languageVersion:
          type: string
          description: Language runtime version.
        status:
          type: string
          enum: [starting, running, suspended, ended, error]
        timeoutAt:
          type: string
          format: date-time
          description: ISO 8601 timestamp when the session will time out.
        publicUrl:
          type: string
          nullable: true
          description: Public HTTPS URL for the session (if a port is exposed).
        alwaysOn:
          type: boolean
          description: Whether the session persists past the timeout.
        cellName:
          type: string
          nullable: true
          description: Named cell identifier for persistent volume sessions.

    CreateSessionRequest:
      type: object
      required: []
      properties:
        language:
          type: string
          description: Language runtime. One of node, python, go, rust, php, java, ruby, csharp.
          example: "node"
        languageVersion:
          type: string
          description: Language version string matching the available versions.
          example: "22"
        languages:
          type: array
          items:
            type: string
          description: >
            Multi-language combo request (2 to 4 entries). Mutually exclusive with language/languageVersion.
          example: ["node", "python"]
        timeoutSeconds:
          type: integer
          description: Session timeout in seconds. Min 30, max 1800 (30 minutes). Default 300.
          minimum: 30
          maximum: 1800
          default: 300
        sizeId:
          type: string
          enum: [micro, small, standard, large, max]
          default: micro
          description: >
            Hardware size for the session machine. Defaults to micro.
            See the Sizes page for CPU/RAM per tier.
        cellName:
          type: string
          pattern: "^[a-zA-Z0-9_-]{1,63}$"
          description: >
            Stable name for a persistent cell. Sessions with the same cellName reattach to the
            same workspace volume. Concurrent sessions with different cellNames are supported.
        alwaysOn:
          type: boolean
          description: >
            If true, the session machine is not destroyed when the timeout expires; it is
            suspended instead and can be resumed. Requires a Growth or Scale plan.
        autoSuspendMinutes:
          type: integer
          minimum: 0
          description: >
            Auto-suspend the session after this many minutes of inactivity. 0 means use the
            plan default. alwaysOn sessions are not auto-suspended.
        initialExec:
          type: object
          description: >
            Command to execute immediately when the session agent connects (within 500ms of boot).
          properties:
            cmd:
              type: array
              items:
                type: string
              description: Command and arguments.
            timeoutMs:
              type: integer
              minimum: 1
              maximum: 120000
              description: Timeout for the initial exec in milliseconds.
        externalId:
          type: string
          maxLength: 128
          description: >
            Optional idempotency key. If a session with this externalId already exists and is
            active, that session is returned instead of creating a new one.

    CreateSessionResponse:
      type: object
      properties:
        success:
          type: boolean
        sessionId:
          type: string
        wsUrl:
          type: string
          description: WebSocket URL for the session gateway.
        token:
          type: string
          description: Short-lived JWT for authenticating gateway connections. Valid for 60 seconds.
        expiresAt:
          type: string
          format: date-time
          description: When the gateway token expires.
        language:
          type: string
        languageVersion:
          type: string
        timeoutAt:
          type: string
          format: date-time
        publicUrl:
          type: string
          nullable: true
        resumed:
          type: boolean
          description: Present and true when an existing session was returned (externalId match).
        usageWarning:
          type: object
          nullable: true
          description: Present when quota usage is between 80 and 99 percent.
          properties:
            percentUsed:
              type: integer

    ExecRequest:
      type: object
      required:
        - cmd
      properties:
        cmd:
          type: array
          items:
            type: string
          description: Command and arguments.
          example: ["node", "-e", "console.log('hello')"]
        timeoutMs:
          type: integer
          minimum: 1
          maximum: 300000
          default: 30000
          description: >
            Maximum execution time in milliseconds. Max is 300000 (300 seconds).
            Keepalive SSE comments are sent every 10 seconds to prevent proxy timeouts
            on long-running commands.
        env:
          type: object
          additionalProperties:
            type: string
          description: Extra environment variables to inject for this exec.
        workingDir:
          type: string
          description: Working directory for the command inside the session.

    WriteFilesRequest:
      type: object
      required:
        - files
      properties:
        files:
          type: array
          maxItems: 200
          description: Files to write. Max 200 files, about 9 MB of file content per write (either encoding); split larger files across multiple writes.
          items:
            type: object
            required:
              - path
              - content
            properties:
              path:
                type: string
                description: Relative path inside the session (no traversal).
              content:
                type: string
                description: File content. UTF-8 text by default; base64 when encoding is "base64".
              encoding:
                type: string
                enum: [utf8, base64]
                default: utf8

    ReadFileResponse:
      type: object
      properties:
        success:
          type: boolean
        path:
          type: string
        content:
          type: string
          description: File content. UTF-8 text by default; base64 when binary.
        encoding:
          type: string
          enum: [utf8, base64]
        sha256:
          type: string
        size:
          type: integer

    StartServiceRequest:
      type: object
      required:
        - name
        - cmd
      properties:
        name:
          type: string
          description: Human-readable service name (used to reference this service in other calls).
        cmd:
          type: string
          description: Executable path.
        args:
          type: array
          items:
            type: string
        cwd:
          type: string
          description: Working directory for the service.
        port:
          type: integer
          description: Port the service listens on. Used with waitForPort.
        env:
          type: object
          additionalProperties:
            type: string
        waitForPort:
          type: boolean
          description: Wait for the port to be reachable before returning.
        timeoutMs:
          type: integer
          description: Max wait time in milliseconds when waitForPort is true.

    ErrorResponse:
      type: object
      properties:
        success:
          type: boolean
          example: false
        error:
          type: string
        code:
          type: string

paths:
  /projects/{projectId}:
    post:
      operationId: createSession
      summary: Create a session
      description: >
        Create a new isolated code execution session. Returns a sessionId, a short-lived gateway
        token, and a WebSocket URL. If externalId is supplied and an active session already exists
        with that id, that session is returned instead (idempotent re-attach).
      tags:
        - Sessions
      parameters:
        - name: projectId
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateSessionRequest"
      responses:
        "201":
          description: Session created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreateSessionResponse"
        "200":
          description: Existing session returned (externalId match).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreateSessionResponse"
        "400":
          description: Invalid request parameters.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "402":
          description: Monthly Small-hours quota exhausted.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: Concurrent session limit reached.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "503":
          description: Session creation failed (infra error).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

    get:
      operationId: listSessions
      summary: List sessions
      description: Return all running sessions for the org that owns this project.
      tags:
        - Sessions
      parameters:
        - name: projectId
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Sessions listed.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  sessions:
                    type: array
                    items:
                      $ref: "#/components/schemas/Session"

  /projects/{projectId}/sessions/{sessionId}:
    get:
      operationId: getSession
      summary: Get a session
      description: Return the current status and metadata for a single session.
      tags:
        - Sessions
      parameters:
        - name: projectId
          in: path
          required: true
          schema:
            type: string
        - name: sessionId
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Session retrieved.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Session"
        "404":
          description: Session not found.

    delete:
      operationId: closeSession
      summary: Close a session
      description: Immediately terminate and destroy the session.
      tags:
        - Sessions
      parameters:
        - name: projectId
          in: path
          required: true
          schema:
            type: string
        - name: sessionId
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Session closed.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  sessionId:
                    type: string

    patch:
      operationId: patchSession
      summary: Update session metadata
      description: Update mutable session metadata (autoSuspendMinutes).
      tags:
        - Sessions
      parameters:
        - name: projectId
          in: path
          required: true
          schema:
            type: string
        - name: sessionId
          in: path
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                autoSuspendMinutes:
                  type: integer
                  minimum: 0
      responses:
        "200":
          description: Session updated.

  /projects/{projectId}/sessions/{sessionId}/exec:
    post:
      operationId: execSession
      summary: Run a command (streaming SSE)
      description: >
        Execute a command inside a running session. The response is a Server-Sent Events stream.
        Each event carries a line of stdout or stderr, or an exit code event when the command
        finishes. SSE comment lines (starting with `:`) are sent every 10 seconds as keepalives
        and should be ignored by the client.
      tags:
        - Execution
      parameters:
        - name: projectId
          in: path
          required: true
          schema:
            type: string
        - name: sessionId
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ExecRequest"
      responses:
        "200":
          description: SSE stream.
          content:
            text/event-stream:
              schema:
                type: string
                description: >
                  Newline-delimited SSE events.
                  Each data line is a JSON object:
                    { type: "stdout" | "stderr", data: string }
                  or on exit:
                    { type: "exit", exitCode: number }

  /projects/{projectId}/sessions/{sessionId}/connect-token:
    post:
      operationId: getConnectToken
      summary: Get a connect token
      description: >
        Issue a fresh 60-second gateway JWT for an existing session. Used by CLI tools to connect
        to sessions created more than 60 seconds ago (the original token TTL).
      tags:
        - Sessions
      parameters:
        - name: projectId
          in: path
          required: true
          schema:
            type: string
        - name: sessionId
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Token issued.

  /projects/{projectId}/sessions/{sessionId}/suspend:
    post:
      operationId: suspendSession
      summary: Suspend a session
      description: Suspend an always-on session to reduce resource usage.
      tags:
        - Sessions
      parameters:
        - name: projectId
          in: path
          required: true
          schema:
            type: string
        - name: sessionId
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Session suspended.

  /projects/{projectId}/sessions/{sessionId}/resume:
    post:
      operationId: resumeSession
      summary: Resume a session
      description: Resume a suspended always-on session.
      tags:
        - Sessions
      parameters:
        - name: projectId
          in: path
          required: true
          schema:
            type: string
        - name: sessionId
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Session resumed.

  /projects/{projectId}/sessions/{sessionId}/expose:
    post:
      operationId: exposePort
      summary: Expose a port
      description: Expose an additional port on the session so a running service is reachable from the internet.
      tags:
        - Sessions
      parameters:
        - name: projectId
          in: path
          required: true
          schema:
            type: string
        - name: sessionId
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - port
              properties:
                port:
                  type: integer
                  description: Port number to expose.
                access:
                  type: string
                  enum: [public, token-gated]
                  default: public
      responses:
        "200":
          description: Port exposed.

  /projects/{projectId}/sessions/{sessionId}/files:
    post:
      operationId: writeFiles
      summary: Write files
      description: >
        Batch-write up to 200 files into a running session.
        `encoding` controls how `content` is interpreted:
        `text` (default): `content` is a UTF-8 string. The server base64-encodes it before
        forwarding. The gate measures the base64 string size (12 MB limit), so UTF-8 content is
        capped at approximately 9 MB (its base64 form must fit within 12 MB).
        `base64`: `content` is standard-padded base64, up to 12 MB. The 12 MB base64 string
        represents approximately 9 MB of decoded data.
        Both modes cap file content at roughly 9 MB. Split larger files across multiple writes.
      tags:
        - Files
      parameters:
        - name: projectId
          in: path
          required: true
          schema:
            type: string
        - name: sessionId
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/WriteFilesRequest"
      responses:
        "200":
          description: Files written.

    get:
      operationId: readFile
      summary: Read a file
      description: Read a single file from a running session. Max 10 MB.
      tags:
        - Files
      parameters:
        - name: projectId
          in: path
          required: true
          schema:
            type: string
        - name: sessionId
          in: path
          required: true
          schema:
            type: string
        - name: path
          in: query
          required: true
          schema:
            type: string
          description: Relative file path inside the session (no traversal).
      responses:
        "200":
          description: File content.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ReadFileResponse"

  /projects/{projectId}/sessions/{sessionId}/services:
    get:
      operationId: listServices
      summary: List services
      description: List all named services currently running inside a session.
      tags:
        - Services
      parameters:
        - name: projectId
          in: path
          required: true
          schema:
            type: string
        - name: sessionId
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Services listed.

    post:
      operationId: startService
      summary: Start a service
      description: >
        Start a named service inside a session and optionally wait for its port to become reachable.
        Services keep running independently of exec calls.
      tags:
        - Services
      parameters:
        - name: projectId
          in: path
          required: true
          schema:
            type: string
        - name: sessionId
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/StartServiceRequest"
      responses:
        "200":
          description: Service started.

  /projects/{projectId}/sessions/{sessionId}/services/{name}:
    delete:
      operationId: stopService
      summary: Stop a service
      description: Stop a named service. No-op if the service is not running.
      tags:
        - Services
      parameters:
        - name: projectId
          in: path
          required: true
          schema:
            type: string
        - name: sessionId
          in: path
          required: true
          schema:
            type: string
        - name: name
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Service stopped.

  /projects/{projectId}/sessions/{sessionId}/services/{name}/logs:
    get:
      operationId: getServiceLogs
      summary: Get service logs (snapshot)
      description: Return the last N log lines from a named service (buffered snapshot).
      tags:
        - Services
      parameters:
        - name: projectId
          in: path
          required: true
          schema:
            type: string
        - name: sessionId
          in: path
          required: true
          schema:
            type: string
        - name: name
          in: path
          required: true
          schema:
            type: string
        - name: lines
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 5000
            default: 100
      responses:
        "200":
          description: Log snapshot.

  /projects/{projectId}/sessions/{sessionId}/services/{name}/logs/stream:
    get:
      operationId: streamServiceLogs
      summary: Stream service logs (SSE)
      description: >
        Open a live SSE tail of a named service's logs. Each event is a JSON SandboxLogLine.
        Uses a per-org concurrent connection cap (default 10) rather than a request-count limiter.
      tags:
        - Services
      parameters:
        - name: projectId
          in: path
          required: true
          schema:
            type: string
        - name: sessionId
          in: path
          required: true
          schema:
            type: string
        - name: name
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: SSE log stream.
          content:
            text/event-stream:
              schema:
                type: string

  /projects/{projectId}/sessions/{sessionId}/volume:
    delete:
      operationId: deleteSessionVolume
      summary: Delete a cell's persistent volume
      description: >
        Permanently destroy the persistent workspace volume for a named cell.
        Only valid for sessions with a cellName. Irreversible: all workspace data is lost.
      tags:
        - Sessions
      parameters:
        - name: projectId
          in: path
          required: true
          schema:
            type: string
        - name: sessionId
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Volume deleted.

  /projects/{projectId}/sessions/{sessionId}/checkpoint:
    post:
      operationId: checkpointSession
      summary: Create a checkpoint
      description: Capture a filesystem checkpoint of a running or suspended session.
      tags:
        - Checkpoints
      parameters:
        - name: projectId
          in: path
          required: true
          schema:
            type: string
        - name: sessionId
          in: path
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  description: Optional human-readable label.
      responses:
        "200":
          description: Checkpoint created.

  /projects/{projectId}/sessions/{sessionId}/checkpoints:
    get:
      operationId: listCheckpoints
      summary: List checkpoints
      description: List all stored checkpoints for a session, newest first.
      tags:
        - Checkpoints
      parameters:
        - name: projectId
          in: path
          required: true
          schema:
            type: string
        - name: sessionId
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Checkpoints listed.

  /projects/{projectId}/sessions/{sessionId}/restore:
    post:
      operationId: restoreFromCheckpoint
      summary: Restore from a checkpoint
      description: Restore a new session from a stored checkpoint (async).
      tags:
        - Checkpoints
      parameters:
        - name: projectId
          in: path
          required: true
          schema:
            type: string
        - name: sessionId
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - checkpointId
              properties:
                checkpointId:
                  type: string
      responses:
        "202":
          description: Restore job started.

  /projects/{projectId}/sessions/{sessionId}/restores/{restoreId}:
    get:
      operationId: getRestoreJob
      summary: Get restore job status
      description: Poll the status of an in-progress checkpoint restore job.
      tags:
        - Checkpoints
      parameters:
        - name: projectId
          in: path
          required: true
          schema:
            type: string
        - name: sessionId
          in: path
          required: true
          schema:
            type: string
        - name: restoreId
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Restore job status.

  /projects/{projectId}/sessions/{sessionId}/checkpoints/{checkpointId}:
    delete:
      operationId: deleteCheckpoint
      summary: Delete a checkpoint
      description: Delete a stored checkpoint.
      tags:
        - Checkpoints
      parameters:
        - name: projectId
          in: path
          required: true
          schema:
            type: string
        - name: sessionId
          in: path
          required: true
          schema:
            type: string
        - name: checkpointId
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Checkpoint deleted.

  /projects/{projectId}/billing/usage:
    get:
      operationId: getSandboxBillingUsage
      summary: Get billing usage
      description: Returns sandbox usage history for the org.
      tags:
        - Billing
      parameters:
        - name: projectId
          in: path
          required: true
          schema:
            type: string
        - name: months
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 12
            default: 4
      responses:
        "200":
          description: Usage history.
