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

# Mint a token for a private preview port

> Activates token authentication for an already-published private port
and returns a credential scoped to exactly this sandbox, port, and
token generation. A machine client sends the response's `token` value
in a request header whose name is the response's `header` value.

For browser navigation, construct a signed URL by adding the URL-encoded
`token` under the query-parameter name returned in `query_param`. An
ordinary `GET` exchanges a valid query token for a secure host-only
cookie and returns a `302` redirect to the same-origin HTTPS URL with
the credential removed. The bootstrap response is `Cache-Control:
no-store` and `Referrer-Policy: no-referrer`. Non-`GET` requests and
complete WebSocket upgrade handshakes authenticate a valid query token
directly because they cannot round-trip that redirect. The edge strips
all preview-token header, query, and cookie carriers before forwarding
any request to sandbox code.

Public or unpublished ports cannot mint credentials. Minting requires
sandbox write access; an incapable or stale host is rejected rather
than activating a policy it cannot enforce.

The request body is optional. Omit it (or send `{}`) for a token that
remains valid until rotation, access-mode change, or unpublication.
An explicit expiry is also enforced for a cookie bootstrapped from that
token, even if the browser still stores the cookie.




## OpenAPI

````yaml https://raw.githubusercontent.com/superserve-ai/sandbox/refs/heads/main/api/openapi.yaml post /sandboxes/{sandbox_id}/preview-ports/{port}/token
openapi: 3.1.0
info:
  title: Superserve API
  version: 0.1.0
  description: >
    Superserve provides sandbox infrastructure to run AI agents in the cloud.
    Powered by Firecracker MicroVMs.


    ## Sandbox lifecycle


    ```

    active <--> paused --> deleted

    ```


    A sandbox is `active` when running and `paused` after being paused. Resuming

    a paused sandbox returns it to `active`. Deleting releases all resources.


    | Endpoint | What it does |

    |----------|-------------|

    | `POST /sandboxes` | Create a new sandbox (optionally `from_template`) |

    | `PATCH /sandboxes/:id` | Partially update a running sandbox (e.g. network
    rules) |

    | `POST /sandboxes/:id/pause` | Snapshot full state, suspend the VM |

    | `POST /sandboxes/:id/resume` | Restore from snapshot, continue where it
    left off |

    | `DELETE /sandboxes/:id` | Delete sandbox and all resources |


    ## Sandbox environment


    By default sandboxes boot from the curated `superserve/base` template
    (Ubuntu 24.04,

    1 vCPU, 1 GB RAM, 4 GB disk, with Python 3.12, Node.js 22, npm, git, curl,

    and build-essential pre-installed). Callers can override with any template

    name (e.g. `superserve/python-3.11`, `superserve/node-22`) or a team-owned
    template UUID

    via the `from_template` field on `POST /sandboxes`.


    ## Files and commands


    `/files`, `/exec`, and `/exec/stream` run against a single sandbox and use

    its `X-Access-Token` (returned by create, resume, and activate), not the

    team API key. Two host forms reach them:


    - `https://sandbox.superserve.ai/...` with `X-Superserve-Sandbox-Id:
    <sandbox_id>`.

    - `https://boxd-{sandbox_id}.sandbox.superserve.ai/...` — no routing header
    needed.
  contact:
    name: Superserve Team
  license:
    name: Proprietary
servers:
  - url: https://api.superserve.ai
    description: Production
security: []
paths:
  /sandboxes/{sandbox_id}/preview-ports/{port}/token:
    parameters:
      - $ref: '#/components/parameters/SandboxId'
      - $ref: '#/components/parameters/PreviewPort'
    post:
      tags:
        - Sandboxes
      summary: Mint a token for a private preview port
      description: |
        Activates token authentication for an already-published private port
        and returns a credential scoped to exactly this sandbox, port, and
        token generation. A machine client sends the response's `token` value
        in a request header whose name is the response's `header` value.

        For browser navigation, construct a signed URL by adding the URL-encoded
        `token` under the query-parameter name returned in `query_param`. An
        ordinary `GET` exchanges a valid query token for a secure host-only
        cookie and returns a `302` redirect to the same-origin HTTPS URL with
        the credential removed. The bootstrap response is `Cache-Control:
        no-store` and `Referrer-Policy: no-referrer`. Non-`GET` requests and
        complete WebSocket upgrade handshakes authenticate a valid query token
        directly because they cannot round-trip that redirect. The edge strips
        all preview-token header, query, and cookie carriers before forwarding
        any request to sandbox code.

        Public or unpublished ports cannot mint credentials. Minting requires
        sandbox write access; an incapable or stale host is rejected rather
        than activating a policy it cannot enforce.

        The request body is optional. Omit it (or send `{}`) for a token that
        remains valid until rotation, access-mode change, or unpublication.
        An explicit expiry is also enforced for a cookie bootstrapped from that
        token, even if the browser still stores the cookie.
      operationId: mintSandboxPreviewToken
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PreviewTokenRequest'
      responses:
        '200':
          description: Fresh header and signed-link credential; never cache this response
          headers:
            Cache-Control:
              schema:
                type: string
              description: Always `no-store`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PreviewTokenResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '500':
          $ref: '#/components/responses/InternalError'
      security:
        - apiKey: []
components:
  parameters:
    SandboxId:
      name: sandbox_id
      in: path
      required: true
      schema:
        $ref: '#/components/schemas/PublicSandboxId'
      description: The unique identifier of the sandbox.
    PreviewPort:
      name: port
      in: path
      required: true
      schema:
        type: integer
        minimum: 1024
        maximum: 65535
        not:
          enum:
            - 49983
      description: >-
        Published sandbox port. Port 49983 is reserved for Superserve's sandbox
        service.
  schemas:
    PreviewTokenRequest:
      type: object
      additionalProperties: false
      description: |
        Optional expiry for a preview token, independent of whether it is sent
        by header, used in a signed link, or stored by the edge in a browser
        cookie. Omit the body (or send `{}`) for a credential that remains valid
        until its generation changes.
      properties:
        expires_in_seconds:
          type: integer
          format: int64
          minimum: 1
          maximum: 604800
          description: Lifetime in whole seconds; omitted means no time expiry.
    PreviewTokenResponse:
      type: object
      description: >
        A single port-scoped credential with two explicit carriers. Machine

        clients normally send `token` in the request header named by `header`.

        For browser navigation, append the URL-encoded token under the parameter

        named by `query_param`, for example

        `https://{port}-{sandbox_id}.<sandbox-domain>/?{query_param}={token}`.


        For an ordinary `GET`, the edge validates the signed link, sets the

        host-only `__Host-superserve_preview_token` cookie with `Secure`,

        `HttpOnly`, `SameSite=None`, `Partitioned`, `Path=/`, and no `Domain`,

        then returns a `302` to a same-origin HTTPS URL with every reserved
        token

        parameter removed. Unrelated query data is preserved. The redirect is

        `Cache-Control: no-store` with `Referrer-Policy: no-referrer`.


        Non-`GET` requests and genuine WebSocket upgrade handshakes accept the

        query token directly without a redirect. In every case, the reserved

        header, query parameter, and cookie are removed before the upstream

        application receives the request. The edge revalidates cookie tokens on

        every request, so token expiry, generation rotation, access-mode change,

        or unpublication invalidates an existing browser session immediately;

        the browser may retain the now-unusable cookie value.
      required:
        - token
        - port
        - header
        - query_param
        - access
        - preview_access
        - token_version
      properties:
        token:
          type: string
          description: |
            Secret token scoped to this sandbox, port, and generation. Send it
            using the request header named by `header`, or URL-encode it under
            the signed-link query parameter named by `query_param`.
        port:
          type: integer
          minimum: 1024
          maximum: 65535
          not:
            enum:
              - 49983
        header:
          type: string
          example: X-Superserve-Preview-Token
          description: Request-header name to use when sending `token`.
        query_param:
          type: string
          example: superserve_preview_token
          description: Query-parameter name to use when constructing a signed link.
        access:
          type: string
          enum:
            - private
          description: The published port's access mode.
        preview_access:
          type: string
          enum:
            - legacy_public
            - public
            - private
          description: Sandbox default for newly published ports.
        token_version:
          type: integer
          format: int64
          minimum: 1
          description: Exact generation embedded in `token`.
        expires_at:
          type: string
          format: date-time
          description: |
            Present only when `expires_in_seconds` was supplied. After this
            instant the token is rejected in every carrier, including an
            already-established browser cookie.
    PublicSandboxId:
      type: string
      pattern: >-
        ^(sb-[a-z0-9]+-)?[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$
      description: >
        Public sandbox ID: a bare UUID, or the region-tagged form
        `sb-<region>-<uuid>` (e.g. `sb-use-1b4e28ba-…`). Treat as an opaque
        string; the tagged form routes the request to the sandbox's home region.
        Endpoints accept both forms interchangeably.
    Error:
      type: object
      description: |
        Error envelope. `error.code` is a stable, machine-readable identifier
        (e.g. `bad_request`, `not_found`, `conflict`, `rate_limited`,
        `too_many_builds`, `too_many_templates`, `too_many_sandboxes`,
        `image_pull_failed`, `step_failed`, `snapshot_failed`,
        `start_cmd_failed`, `ready_cmd_failed`, `build_failed`).
        `error.message` is human-readable and may change between releases;
        clients should branch on `code`, not `message`.
      properties:
        error:
          type: object
          properties:
            code:
              type: string
            message:
              type: string
  responses:
    BadRequest:
      description: Invalid request
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: Missing or invalid API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Forbidden:
      description: Caller is authenticated but not allowed to perform the action
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Conflict:
      description: Operation conflicts with the resource's current state
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    InternalError:
      description: Internal server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    apiKey:
      type: apiKey
      in: header
      name: X-API-Key

````