Ctrl K
ComunidadGuías…

spec/openapi.yml

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
openapi: 3.0.0
info:
  version: 0.1.0
  title: E2B API

servers:
  - url: https://api.e2b.app

components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
    # AuthProviderBearerAuth / AuthProviderTeamAuth: B before T in the name
    # so Bearer is validated before Team.
    AuthProviderBearerAuth:
      type: http
      scheme: bearer
      bearerFormat: access_token
    AuthProviderTeamAuth:
      type: apiKey
      in: header
      name: X-Team-ID
    # AdminApiKeyAuth / AdminTeamAuth: alphabetical names ensure token
    # validation runs before team context population.
    AdminApiKeyAuth:
      type: apiKey
      in: header
      name: X-Admin-Token
    AdminJWTAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
    AdminTeamAuth:
      type: apiKey
      in: header
      name: X-Team-ID

  parameters:
    clusterID:
      name: clusterID
      in: path
      required: true
      schema:
        type: string
        format: uuid
      description: Identifier of the cluster
    rigID:
      name: rigID
      in: path
      required: true
      schema:
        type: string
      description: Rig identifier (e.g. "default")
    templateID:
      name: templateID
      in: path
      required: true
      schema:
        type: string
    buildID:
      name: buildID
      in: path
      required: true
      schema:
        type: string
    sandboxID:
      name: sandboxID
      in: path
      required: true
      schema:
        type: string
    teamID:
      name: teamID
      in: path
      required: true
      description: Identifier of the team, as its UUID or its public project ID (prj_)
      schema:
        type: string
    nodeID:
      name: nodeID
      in: path
      required: true
      schema:
        type: string
    apiKeyID:
      name: apiKeyID
      in: path
      required: true
      schema:
        type: string
    aliasID:
      name: aliasID
      in: path
      required: true
      description: Identifier of the alias
      schema:
        type: string
        format: uuid
    snapshotID:
      name: snapshotID
      in: path
      required: true
      schema:
        type: string
        description: Identifier of the snapshot (template ID)
    tag:
      name: tag
      in: path
      required: true
      schema:
        type: string
        description: Tag name
    tagQuery:
      name: tag
      in: query
      required: true
      description: Template tag name to check.
      schema:
        type: string
        minLength: 1
    tagAssignmentLimit:
      name: assignmentLimit
      in: query
      required: false
      description: Maximum number of ready assignment rows to return per tag.
      schema:
        type: integer
        format: int32
        minimum: 1
        maximum: 25
        default: 6
    tagGroupsLimit:
      name: tagsLimit
      in: query
      required: false
      description: Maximum number of distinct tags to return per page.
      schema:
        type: integer
        format: int32
        minimum: 1
        maximum: 100
        default: 25
    tagGroupsCursor:
      name: tagsCursor
      in: query
      required: false
      description: Cursor returned by the previous list response in `{sort}|{latest_assigned_at}|{tag}` format (sort-tagged, RFC3339Nano).
      schema:
        type: string
    tagGroupsSearch:
      name: search
      in: query
      required: false
      description: Substring filter on tag name. Allowed characters are `a-z`, `0-9`, `.`, `_`, `-`.
      schema:
        type: string
        maxLength: 64
        pattern: "^[a-z0-9._-]*$"
    tagGroupsSort:
      name: sort
      in: query
      required: false
      description: Sort order for the returned tag groups.
      schema:
        type: string
        enum: [latest_desc, latest_asc, name_asc, name_desc]
        default: latest_desc
    tagAssignmentsLimit:
      name: limit
      in: query
      required: false
      description: Maximum number of assignment rows to return per page.
      schema:
        type: integer
        format: int32
        minimum: 1
        maximum: 100
        default: 50
    tagAssignmentsCursor:
      name: cursor
      in: query
      required: false
      description: Cursor returned by the previous list response in `assigned_at|assignment_id` format.
      schema:
        type: string
    paginationLimit:
      name: limit
      in: query
      description: Maximum number of items to return per page
      required: false
      schema:
        type: integer
        format: int32
        minimum: 1
        default: 100
        maximum: 100
    paginationNextToken:
      name: nextToken
      in: query
      description: Cursor to start the list from
      required: false
      schema:
        type: string
    templatesSearch:
      name: search
      in: query
      required: false
      description: Case-insensitive substring match on the template ID, its aliases and its names.
      schema:
        type: string
        maxLength: 256
    templatesSort:
      name: sort
      in: query
      required: false
      description: Sort column and direction.
      schema:
        type: string
        enum: [created_at_desc, created_at_asc, updated_at_desc, updated_at_asc]
        default: created_at_desc
    templatesPublic:
      name: public
      in: query
      required: false
      description: Only list public (true) or only non-public (false) templates.
      schema:
        type: boolean
    templatesCursor:
      name: cursor
      in: query
      required: false
      description: >
        Cursor returned by the previous page in `{sort}|{value}|{templateID}` format. Rejected if
        its sort does not match the request.
      schema:
        type: string
    templatesLimit:
      name: limit
      in: query
      required: false
      description: Maximum number of templates to return per page.
      schema:
        type: integer
        format: int32
        minimum: 1
        maximum: 100
        default: 50
    buildIDOrTemplate:
      name: build_id_or_template
      in: query
      required: false
      description: Optional filter by build identifier, template identifier, or template alias.
      schema:
        type: string
    buildStatuses:
      name: statuses
      in: query
      required: false
      description: Comma-separated list of build statuses to include.
      style: form
      explode: false
      schema:
        type: array
        items:
          $ref: "#/components/schemas/BuildStatus"
    buildsCursor:
      name: cursor
      in: query
      required: false
      description: Cursor returned by the previous list response in `created_at|build_id` format.
      schema:
        type: string
    buildsLimit:
      name: limit
      in: query
      required: false
      description: Maximum number of builds to return per page.
      schema:
        type: integer
        format: int32
        minimum: 1
        maximum: 100
        default: 50
    buildIDs:
      name: build_ids
      in: query
      required: true
      description: Comma-separated list of build IDs to get statuses for.
      style: form
      explode: false
      schema:
        type: array
        maxItems: 100
        items:
          type: string
          format: uuid
    volumeID:
      name: volumeID
      in: path
      required: true
      schema:
        type: string
    secretID:
      name: secretID
      in: path
      required: true
      schema:
        type: string
        description: >
          Identifier of the secret (sec_ prefixed), or its canonical
          lower-case name

    webhookID:
      name: webhookID
      in: path
      required: true
      schema:
        type: string
        format: uuid
  headers:
    ShouldRetry:
      description: |
        Whether the condition behind this error may clear, so that retrying the request could
        succeed. true marks a transient failure such as missing capacity, a rate limit, or a
        creation still in progress: retry after Retry-After when present, otherwise with
        exponential backoff. false marks a failure a retry cannot fix, such as a malformed request
        or a configuration fault, or an outcome that is unknown, where a retry could create a
        second sandbox. Successful responses and errors without an explicit classification omit
        the header. With idempotency enabled, retry sandbox creation with the same Idempotency-Key
        and request parameters. A retryable creation failure permits a fresh attempt; an
        idempotency_in_progress response only reports an existing attempt and never releases it.
      required: false
      schema:
        type: boolean
    XNextToken:
      description: Cursor to fetch the next page of results, if more exist
      schema:
        type: string
    XTotalRunning:
      description: >
        Number of running sandboxes matching the filters, before pagination is applied.
        Only present when running sandboxes were requested.
      schema:
        type: integer
        format: int32

  responses:
    "400":
      description: Bad request
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    "401":
      description: Authentication error
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    "403":
      description: Forbidden
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    "404":
      description: Not found
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    "409":
      description: Conflict
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    "429":
      description: Too many requests
      headers:
        Retry-After:
          description: When present, the number of seconds to wait before retrying the request.
          required: false
          schema:
            type: integer
            minimum: 0
          example: 30
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    "500":
      description: Server error
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    "501":
      description: Not implemented by this deployment
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    "502":
      description: Backend error
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    "503":
      description: Service unavailable
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    "504":
      description: Backend timeout
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"

  schemas:
    Rig:
      description: An orchestrator node pool backed by one cloud scaling group
      required:
        - id
        - provider
        - resourceID
        - capacityDesired
        - capacityCurrent
      properties:
        id:
          type: string
          description: Rig identifier (e.g. "default")
        provider:
          type: string
          description: Cloud provider backing the rig ("aws" or "gcp")
        resourceID:
          type: string
          description: Canonical cloud resource ID of the scaling group backing the rig (ARN on AWS, self-link on GCP)
        capacityDesired:
          type: integer
          format: int32
          description: Desired number of instances in the rig
        capacityMin:
          type: integer
          format: int32
          description: >
            Minimum capacity enforced on the rig's scaling group. Omitted when
            nothing enforces bounds (GCP MIG without an active autoscaler).
        capacityMax:
          type: integer
          format: int32
          description: >
            Maximum capacity enforced on the rig's scaling group. Omitted when
            nothing enforces bounds (GCP MIG without an active autoscaler).
        capacityCurrent:
          type: integer
          format: int32
          description: Number of instances currently attached to the rig

    RigCapacityChange:
      description: Desired capacity to set on the rig's scaling group
      required:
        - desired
      properties:
        desired:
          type: integer
          format: int32
          minimum: 0
          description: Absolute desired number of instances in the rig

    RigInstance:
      description: An instance attached to a rig's scaling group
      required:
        - id
        - transitioning
        - terminating
      properties:
        id:
          type: string
          description: Provider instance ID (EC2 instance ID on AWS, instance name on GCP), also the node ID the orchestrator reports
        createdAt:
          type: string
          format: date-time
          description: When the provider created the instance. Omitted while the instance is transitioning.
        transitioning:
          type: boolean
          description: The provider is creating, deleting, recreating or otherwise mutating the instance
        terminating:
          type: boolean
          description: The instance is on its way out of the group and can never become healthy again

    RigError:
      description: >
        Scaling error on the rig's scaling group, e.g. a failed instance
        creation due to resource exhaustion
      required:
        - timestamp
        - code
        - message
      properties:
        timestamp:
          type: string
          format: date-time
          description: When the error occurred
        code:
          type: string
          description: Provider-specific error code (e.g. ZONE_RESOURCE_POOL_EXHAUSTED, Failed)
        message:
          type: string
          description: Human-readable error message
        instance:
          type: string
          description: Instance the error relates to, if any
        action:
          type: string
          description: Action being performed when the error occurred (e.g. CREATING)

    Team:
      required:
        - teamID
        - name
        - apiKey
        - isDefault
      properties:
        teamID:
          type: string
          description: Identifier of the team
        name:
          type: string
          description: Name of the team
        apiKey:
          type: string
          description: API key for the team
        isDefault:
          type: boolean
          description: Whether the team is the default team

    TeamUser:
      required:
        - id
        - email
      properties:
        id:
          type: string
          format: uuid
          description: Identifier of the user
        email:
          type: string
          nullable: true
          deprecated: true
          default: null
          description: Email of the user

    TemplateUpdateRequest:
      properties:
        public:
          type: boolean
          description: Whether the template is public or only accessible by the team

    TemplateUpdateResponse:
      required:
        - names
      properties:
        names:
          type: array
          description: Names of the template (namespace/alias format when namespaced)
          items:
            type: string

    CPUCount:
      type: integer
      format: int32
      minimum: 1
      description: CPU cores for the sandbox

    MemoryMB:
      type: integer
      format: int32
      minimum: 128
      description: Memory for the sandbox in MiB

    DiskSizeMB:
      type: integer
      format: int32
      minimum: 0
      description: Disk size for the sandbox in MiB

    MinFreeDiskMb:
      type: integer
      format: int32
      minimum: 0
      description: >-
        Requested minimum free space after the template's build steps, in MiB.
        Omit to use the team's default. Set to 0 to request no minimum free-disk
        growth. The filesystem is never shrunk, including inherited or already-larger
        filesystems. Growth is best effort, so filesystem metadata can leave the
        available space slightly below the requested minimum.

    EnvdVersion:
      type: string
      description: Version of the envd running in the sandbox

    SandboxMetadata:
      additionalProperties:
        type: string
        description: Metadata of the sandbox

    SandboxState:
      type: string
      description: State of the sandbox
      enum:
        - running
        - paused

    OrderDirection:
      type: string
      description: Sort direction
      default: desc
      enum:
        - asc
        - desc

    SnapshotInfo:
      type: object
      required:
        - snapshotID
        - names
      properties:
        snapshotID:
          type: string
          description: Identifier of the snapshot template including the tag. Uses namespace/alias when a name was provided (e.g. team-slug/my-snapshot:default), otherwise falls back to the raw template ID (e.g. abc123:default).
        names:
          type: array
          items:
            type: string
          description: Full names of the snapshot template including team namespace and tag (e.g. team-slug/my-snapshot:v2)

    EnvVars:
      additionalProperties:
        type: string
        description: Environment variables for the sandbox

    Mcp:
      type: object
      description: MCP configuration for the sandbox
      additionalProperties: {}
      nullable: true

    SandboxNetworkConfig:
      type: object
      properties:
        allowPublicTraffic:
          type: boolean
          nullable: true
          description: >-
            Whether sandbox URLs accept traffic without the sandbox's traffic access token.
            When omitted or null on create, the project's default applies, which is true
            unless the project changed it.
        allowOut:
          type: array
          description: List of allowed destinations for egress traffic. Each entry can be a CIDR block (e.g. "8.8.8.8/32"), a bare IP address (e.g. "8.8.8.8"), or a domain name (e.g. "example.com", "*.example.com"). Allowed entries always take precedence over denied entries. When allowOut contains a domain, the servers in dnsServers (8.8.8.8 by default) are also allowed.
          items:
            type: string
        denyOut:
          type: array
          description: List of denied CIDR blocks or IP addresses for egress traffic. Domain names are not supported for deny rules.
          items:
            type: string
        dnsServers:
          type: array
          maxItems: 10
          description: DNS servers the sandbox can reach when allowOut contains a domain. Each entry must be an IPv4 address, and all traffic to it is allowed. Omit it to allow the default nameserver 8.8.8.8, or pass an empty list to allow none. This does not change the sandbox's /etc/resolv.conf.
          items:
            type: string
        egressProxy:
          $ref: "#/components/schemas/SandboxEgressProxyConfig"
        maskRequestHost:
          type: string
          description: Specify host mask which will be used for all sandbox requests
        httpsPorts:
          type: array
          description: Sandbox ports that serve HTTPS rather than plaintext HTTP. Affects how the proxy reaches the service inside the sandbox; the public URL is HTTPS either way. Certificates are not verified, so self-signed ones work. The envd port (49983) cannot be listed.
          maxItems: 128
          uniqueItems: true
          items:
            type: integer
            format: uint32
            minimum: 1
            maximum: 65535
        rules:
          type: object
          description: >
            Per-domain transform rules applied to matching outbound HTTPS requests.
            Keys may be exact DNS names (for example, "api.example.com") or a leading wildcard
            (for example, "*.example.com"), and are normalized to lowercase on write.
            Wildcards match subdomains at any depth but not the apex domain; a bare "*" is invalid.
            Exact rules take precedence, followed by the longest matching wildcard suffix, and
            matching rule sets are not merged. Broad wildcards such as "*.com" are allowed and may
            expose transformed credentials to every matching destination the sandbox contacts.
            Rules do not grant network access; configure allowOut separately to permit the destination.
          additionalProperties:
            type: array
            items:
              $ref: "#/components/schemas/SandboxNetworkRule"

    SandboxNetworkUpdateConfig:
      type: object
      description: Network configuration update for a running sandbox. Replaces the current egress rules with the provided configuration. Omitting a field clears it.
      properties:
        allowOut:
          type: array
          description: List of allowed destinations for egress traffic. Each entry can be a CIDR block (e.g. "8.8.8.8/32"), a bare IP address (e.g. "8.8.8.8"), or a domain name (e.g. "example.com", "*.example.com"). Allowed entries always take precedence over denied entries. When allowOut contains a domain, the servers in dnsServers (8.8.8.8 by default) are also allowed.
          items:
            type: string
        denyOut:
          type: array
          description: List of denied CIDR blocks or IP addresses for egress traffic. Domain names are not supported for deny rules.
          items:
            type: string
        dnsServers:
          type: array
          maxItems: 10
          description: DNS servers the sandbox can reach when allowOut contains a domain. Each entry must be an IPv4 address, and all traffic to it is allowed. Omit it to reset to the default nameserver 8.8.8.8, or pass an empty list to allow none. This does not change the sandbox's /etc/resolv.conf.
          items:
            type: string
        egressProxy:
          $ref: "#/components/schemas/SandboxEgressProxyConfig"
        rules:
          type: object
          description: >
            Per-domain transform rules applied to matching outbound HTTPS requests. Replaces all
            existing rules when provided. Keys may be exact DNS names or a single leading wildcard
            (for example, "*.example.com"), and are normalized to lowercase on write. Wildcards match
            subdomains at any depth but not the apex domain; a bare "*" is invalid. Exact rules take
            precedence, followed by the longest matching wildcard suffix, and matching rule sets are
            not merged. Broad wildcards such as "*.com" are allowed and may expose transformed
            credentials to every matching destination the sandbox contacts. Rules do not grant
            network access; configure allowOut separately to permit the destination.
          additionalProperties:
            type: array
            items:
              $ref: "#/components/schemas/SandboxNetworkRule"
        allow_internet_access:
          type: boolean
          description:
            Allow sandbox to access the internet. When set to false, it behaves the same as specifying denyOut
            to 0.0.0.0/0 in the network config.

    SandboxNetworkRule:
      type: object
      description: Transform rule applied to egress requests matching a domain pattern.
      properties:
        transform:
          $ref: "#/components/schemas/SandboxNetworkTransform"

    SandboxNetworkTransform:
      type: object
      description: Transformations applied to matching egress requests before forwarding.
      properties:
        headers:
          type: object
          description: >
            HTTP headers to inject or override in matching requests.
            An existing header with the same name is replaced. Values are plain strings;
            secret resolution happens client-side before sending to the API.
          additionalProperties:
            type: string

    SandboxEgressProxyConfig:
      type: object
      nullable: true
      description: >-
        SOCKS5 proxy for sandbox egress. Outbound TCP is tunneled through the
        proxy after allow/deny filtering; the sandbox is unaware. Domain-matched
        flows use remote DNS (ATYP=domain).
      required:
        - address
      properties:
        address:
          type: string
          description: >-
            SOCKS5 proxy address in host:port format (e.g. "proxy.example.com:1080").
        username:
          type: string
          maxLength: 255
          description: >-
            Optional SOCKS5 username (RFC 1929), max 255 bytes.
        password:
          type: string
          maxLength: 255
          description: >-
            Optional SOCKS5 password (RFC 1929), max 255 bytes.
        tls:
          $ref: "#/components/schemas/SandboxEgressProxyTLSConfig"

    SandboxEgressProxyTLSConfig:
      type: object
      nullable: true
      description: >-
        TLS for the connection to the SOCKS5 proxy. The SOCKS5 negotiation and
        the tunneled traffic both run inside the TLS session, so the proxy
        credentials are not sent in the clear. This secures only the hop to the
        proxy; what the proxy does onward is its own concern. A half-close from
        the sandbox reaches the proxy as a TLS close_notify, not a TCP FIN, and
        a proxy that treats close_notify as a full close cuts the reply short.
      required:
        - enabled
      properties:
        enabled:
          type: boolean
          description: >-
            Connect to the proxy over TLS. When false, no other field in this
            object may be set.
        serverName:
          type: string
          maxLength: 253
          description: >-
            Name to verify the proxy certificate against, and to send as SNI.
            Defaults to the host part of address. Set this only when the
            certificate does not match the address the proxy is reached at.
        caCert:
          type: string
          maxLength: 8192
          description: >-
            One or more PEM-encoded certificates to verify the proxy against,
            for a proxy fronted by a private CA. These replace the system trust
            store, which is what is used when this is omitted. The system trust
            store depends on the host the orchestrator runs on, so set this to
            get the same verification everywhere.

    SandboxAutoResumeEnabled:
      type: boolean
      description: Auto-resume enabled flag for paused sandboxes. Default false.
      default: false

    SandboxAutoResumeConfig:
      type: object
      description: Auto-resume configuration for paused sandboxes.
      required:
        - enabled
      properties:
        enabled:
          $ref: "#/components/schemas/SandboxAutoResumeEnabled"

    SandboxOnTimeout:
      type: string
      description: Action taken when the sandbox times out.
      enum:
        - kill
        - pause

    SandboxLifecycle:
      type: object
      description: Sandbox lifecycle policy returned by sandbox info.
      required:
        - autoResume
        - onTimeout
      properties:
        autoResume:
          type: boolean
          description: Whether the sandbox can auto-resume.
        onTimeout:
          $ref: "#/components/schemas/SandboxOnTimeout"

    EnvdUnresponsiveAtPause:
      type: boolean
      description: >-
        True when the snapshot a paused sandbox would resume from was taken
        while the sandbox guest agent was not responding. A plain resume of
        it is refused with 409 and error_code
        sandbox_snapshot_guest_agent_unresponsive, because restoring that
        memory would bring the unresponsive agent back; resume it without
        memory (`memory: false`), which cold-boots the sandbox from its disk.
        Omitted for a running sandbox and for a snapshot whose agent
        answered.

    SandboxPauseMode:
      type: string
      description: >-
        What the sandbox's latest pause saved. `full` saved the filesystem and
        the memory, and resuming restores the sandbox where it left off.
        `filesystem` saved only the filesystem, and resuming reboots the
        sandbox from disk. Returned for a paused sandbox once its pause has
        finished, and omitted while it is still pausing.
      enum:
        - full
        - filesystem

    SandboxLog:
      description: Log entry with timestamp and line
      required:
        - timestamp
        - line
      properties:
        timestamp:
          type: string
          format: date-time
          description: Timestamp of the log entry
        line:
          type: string
          description: Log line content

    SandboxLogEntry:
      required:
        - timestamp
        - level
        - message
        - fields
      properties:
        timestamp:
          type: string
          format: date-time
          description: Timestamp of the log entry
        message:
          type: string
          description: Log message content
        level:
          $ref: "#/components/schemas/LogLevel"
        fields:
          type: object
          additionalProperties:
            type: string

    SandboxLogs:
      required:
        - logs
        - logEntries
      properties:
        logs:
          description: Logs of the sandbox
          type: array
          items:
            $ref: "#/components/schemas/SandboxLog"
        logEntries:
          description: Structured logs of the sandbox
          type: array
          items:
            $ref: "#/components/schemas/SandboxLogEntry"

    SandboxLogsV2Response:
      required:
        - logs
      properties:
        logs:
          default: []
          description: Sandbox logs structured
          type: array
          items:
            $ref: "#/components/schemas/SandboxLogEntry"

    SandboxMetric:
      description: Metric entry with timestamp and line
      required:
        - timestamp
        - timestampUnix
        - cpuCount
        - cpuUsedPct
        - memUsed
        - memTotal
        - memCache
        - diskUsed
        - diskTotal
      properties:
        timestamp:
          type: string
          format: date-time
          deprecated: true
          description: Timestamp of the metric entry
        timestampUnix:
          type: integer
          format: int64
          description: Timestamp of the metric entry in Unix time (seconds since epoch)
        cpuCount:
          type: integer
          format: int32
          description: Number of CPU cores
        cpuUsedPct:
          type: number
          format: float
          description: CPU usage percentage
        memUsed:
          type: integer
          format: int64
          description: Memory used in bytes
        memTotal:
          type: integer
          format: int64
          description: Total memory in bytes
        memCache:
          type: integer
          format: int64
          description: Cached memory (page cache) in bytes
        diskUsed:
          type: integer
          format: int64
          description: Disk used in bytes
        diskTotal:
          type: integer
          format: int64
          description: Total disk space in bytes

    SandboxVolumeMount:
      type: object
      properties:
        name:
          type: string
          description: Name of the volume
        path:
          type: string
          description: Path of the volume
      required:
        - name
        - path

    Sandbox:
      required:
        - templateID
        - sandboxID
        - clientID
        - envdVersion
      properties:
        templateID:
          type: string
          description: Identifier of the template from which is the sandbox created
        sandboxID:
          type: string
          description: Identifier of the sandbox
        alias:
          type: string
          description: Alias of the template
        clientID:
          type: string
          deprecated: true
          description: Identifier of the client
        envdVersion:
          $ref: "#/components/schemas/EnvdVersion"
        envdAccessToken:
          type: string
          description: Access token used for envd communication
        trafficAccessToken:
          type: string
          nullable: true
          description: Token required for accessing sandbox via proxy.
        domain:
          type: string
          nullable: true
          description: Base domain where the sandbox traffic is accessible

    SandboxDetail:
      required:
        - templateID
        - sandboxID
        - clientID
        - startedAt
        - cpuCount
        - memoryMB
        - diskSizeMB
        - endAt
        - state
        - envdVersion
      properties:
        templateID:
          type: string
          description: Identifier of the template from which is the sandbox created
        alias:
          type: string
          description: Alias of the template
        sandboxID:
          type: string
          description: Identifier of the sandbox
        clientID:
          type: string
          deprecated: true
          description: Identifier of the client
        startedAt:
          type: string
          format: date-time
          description: Time when the sandbox was started
        endAt:
          type: string
          format: date-time
          description: Time when the sandbox will expire
        envdVersion:
          $ref: "#/components/schemas/EnvdVersion"
        envdUnresponsiveAtPause:
          $ref: "#/components/schemas/EnvdUnresponsiveAtPause"
        envdAccessToken:
          type: string
          description: Access token used for envd communication
        allowInternetAccess:
          type: boolean
          nullable: true
          description: Whether internet access was explicitly enabled or disabled for the sandbox. Null means it was not explicitly set.
        domain:
          type: string
          nullable: true
          description: Base domain where the sandbox traffic is accessible
        cpuCount:
          $ref: "#/components/schemas/CPUCount"
        memoryMB:
          $ref: "#/components/schemas/MemoryMB"
        diskSizeMB:
          $ref: "#/components/schemas/DiskSizeMB"
        metadata:
          $ref: "#/components/schemas/SandboxMetadata"
        state:
          $ref: "#/components/schemas/SandboxState"
        network:
          $ref: "#/components/schemas/SandboxNetworkConfig"
        lifecycle:
          $ref: "#/components/schemas/SandboxLifecycle"
        pauseMode:
          $ref: "#/components/schemas/SandboxPauseMode"
        volumeMounts:
          type: array
          items:
            $ref: "#/components/schemas/SandboxVolumeMount"

    ListedSandbox:
      required:
        - templateID
        - sandboxID
        - clientID
        - startedAt
        - cpuCount
        - memoryMB
        - diskSizeMB
        - endAt
        - state
        - envdVersion
      properties:
        templateID:
          type: string
          description: Identifier of the template from which is the sandbox created
        alias:
          type: string
          description: Alias of the template
        sandboxID:
          type: string
          description: Identifier of the sandbox
        clientID:
          type: string
          deprecated: true
          description: Identifier of the client
        startedAt:
          type: string
          format: date-time
          description: Time when the sandbox was started
        endAt:
          type: string
          format: date-time
          description: Time when the sandbox will expire
        cpuCount:
          $ref: "#/components/schemas/CPUCount"
        memoryMB:
          $ref: "#/components/schemas/MemoryMB"
        diskSizeMB:
          $ref: "#/components/schemas/DiskSizeMB"
        metadata:
          $ref: "#/components/schemas/SandboxMetadata"
        state:
          $ref: "#/components/schemas/SandboxState"
        envdVersion:
          $ref: "#/components/schemas/EnvdVersion"
        envdUnresponsiveAtPause:
          $ref: "#/components/schemas/EnvdUnresponsiveAtPause"
        volumeMounts:
          type: array
          items:
            $ref: "#/components/schemas/SandboxVolumeMount"

    SandboxesWithMetrics:
      required:
        - sandboxes
      properties:
        sandboxes:
          additionalProperties:
            $ref: "#/components/schemas/SandboxMetric"

    NewSandbox:
      required:
        - templateID
      properties:
        templateID:
          type: string
          description: Identifier of the required template
        timeout:
          type: integer
          format: int32
          minimum: 0
          default: 15
          description: Time to live for the sandbox in seconds.
        autoPause:
          type: boolean
          default: false
          description: Automatically pauses the sandbox after the timeout
        autoPauseMemory:
          type: boolean
          default: true
          description: >-
            Controls the snapshot kind taken when the sandbox auto-pauses on
            timeout (only relevant when autoPause is true). When false, the
            auto-pause drops the in-memory state and persists only the
            filesystem (a filesystem-only snapshot); resuming it cold-boots
            (reboots) the sandbox from disk. Such a snapshot cannot be
            auto-resumed by traffic and must be resumed explicitly, so it cannot
            be combined with autoResume. Defaults to true (full memory snapshot).
        autoResume:
          $ref: "#/components/schemas/SandboxAutoResumeConfig"
        secure:
          type: boolean
          deprecated: true
          description: "Ignored. All system communication with the sandbox is always secured; the template's envd version must support secured access."
        allow_internet_access:
          type: boolean
          description:
            Allow sandbox to access the internet. When set to false, it behaves the same as specifying denyOut
            to 0.0.0.0/0 in the network config.
        network:
          $ref: "#/components/schemas/SandboxNetworkConfig"
        metadata:
          $ref: "#/components/schemas/SandboxMetadata"
        envVars:
          $ref: "#/components/schemas/EnvVars"
        mcp:
          $ref: "#/components/schemas/Mcp"
        iam:
          $ref: "#/components/schemas/SandboxIam"
        volumeMounts:
          type: array
          items:
            $ref: "#/components/schemas/SandboxVolumeMount"

    NewSandboxV2:
      description: >-
        Sandbox creation request. All system communication with the sandbox is
        always secured; the template's envd version must support secured access.
      required:
        - templateID
      properties:
        templateID:
          type: string
          description: Identifier of the required template
        timeout:
          type: integer
          format: int32
          minimum: 1
          default: 300
          description: Time to live for the sandbox in seconds.
        autoPause:
          type: boolean
          default: false
          description: Automatically pauses the sandbox after the timeout
        autoPauseMemory:
          type: boolean
          default: true
          description: >-
            Controls the snapshot kind taken when the sandbox auto-pauses on
            timeout (only relevant when autoPause is true). When false, the
            auto-pause drops the in-memory state and persists only the
            filesystem (a filesystem-only snapshot); resuming it cold-boots
            (reboots) the sandbox from disk. Such a snapshot cannot be
            auto-resumed by traffic and must be resumed explicitly, so it cannot
            be combined with autoResume. Defaults to true (full memory snapshot).
        autoResume:
          $ref: "#/components/schemas/SandboxAutoResumeConfig"
        allow_internet_access:
          type: boolean
          description:
            Allow sandbox to access the internet. When set to false, it behaves the same as specifying denyOut
            to 0.0.0.0/0 in the network config.
        network:
          $ref: "#/components/schemas/SandboxNetworkConfig"
        metadata:
          $ref: "#/components/schemas/SandboxMetadata"
        envVars:
          $ref: "#/components/schemas/EnvVars"
        mcp:
          $ref: "#/components/schemas/Mcp"
        iam:
          $ref: "#/components/schemas/SandboxIam"
        volumeMounts:
          type: array
          items:
            $ref: "#/components/schemas/SandboxVolumeMount"

    SandboxIam:
      type: object
      description: >-
        Sandbox workload identity configuration. A non-empty, valid tokens map
        enables workload identity for the sandbox.
      properties:
        tokens:
          $ref: "#/components/schemas/SandboxIamTokens"

    SandboxIamTokens:
      type: object
      description: >-
        Named workload-token definitions, keyed by a caller-chosen token name.
      additionalProperties:
        $ref: "#/components/schemas/SandboxIamToken"

    SandboxIamToken:
      type: object
      required:
        - audience
        - tokenType
      properties:
        audience:
          type: string
          description: Audience of the workload token, stored exactly as provided.
        tokenType:
          type: string
          description: Workload token type.

    ResumedSandbox:
      properties:
        timeout:
          type: integer
          format: int32
          minimum: 0
          default: 15
          description: Time to live for the sandbox in seconds.
        autoPause:
          type: boolean
          deprecated: true
          description: Automatically pauses the sandbox after the timeout
        memory:
          type: boolean
          description: >-
            Defaults to true. When false, resume from disk state only: the sandbox cold-boots fresh and
            any memory in the snapshot is ignored, never modified or deleted. Disk
            state has crash-recovery semantics — writes not flushed before the pause
            may be lost. A no-op for snapshots that contain no memory. Rejected with
            an error in environments where this capability is not enabled, never
            silently downgraded to a memory restore. A snapshot taken while the
            sandbox guest agent was not responding (envdUnresponsiveAtPause) can
            only be resumed this way, and needs no enablement.

    ConnectSandbox:
      type: object
      required:
        - timeout
      properties:
        timeout:
          description: Timeout in seconds from the current time after which the sandbox should expire
          type: integer
          format: int32
          minimum: 0
        memory:
          type: boolean
          description: >-
            Defaults to true. When false and the sandbox is paused, resume from disk state only: the
            sandbox cold-boots fresh and any memory in the snapshot is ignored, never
            modified or deleted. Disk state has crash-recovery semantics — writes not
            flushed before the pause may be lost. A no-op for snapshots that contain
            no memory. Rejected with an error in environments where this capability
            is not enabled, never silently downgraded to a memory restore. A
            snapshot taken while the sandbox guest agent was not responding
            (envdUnresponsiveAtPause) can only be resumed this way, and needs no
            enablement.

    ConnectSandboxV2:
      type: object
      properties:
        timeout:
          description: Timeout in seconds from the current time after which the sandbox should expire
          type: integer
          format: int32
          minimum: 1
          default: 300
        memory:
          type: boolean
          description: >-
            Defaults to true. When false and the sandbox is paused, resume from disk state only: the
            sandbox cold-boots fresh and any memory in the snapshot is ignored, never
            modified or deleted. Disk state has crash-recovery semantics — writes not
            flushed before the pause may be lost. A no-op for snapshots that contain
            no memory. Rejected with an error in environments where this capability
            is not enabled, never silently downgraded to a memory restore. A
            snapshot taken while the sandbox guest agent was not responding
            (envdUnresponsiveAtPause) can only be resumed this way, and needs no
            enablement.

    SandboxTimeoutRequest:
      type: object
      required:
        - timeout
      properties:
        timeout:
          description: Timeout in seconds from the current time after which the sandbox should expire
          type: integer
          format: int32
          minimum: 0

    SandboxRefreshRequest:
      type: object
      properties:
        duration:
          description: Duration for which the sandbox should be kept alive in seconds
          type: integer
          maximum: 3600 # 1 hour
          minimum: 0

    SandboxSnapshotRequest:
      type: object
      properties:
        name:
          type: string
          description: Optional name for the snapshot template. If a snapshot template with this name already exists, a new build will be assigned to the existing template instead of creating a new one.
        memory:
          type: boolean
          description: >-
            Whether to capture a full memory snapshot. When false, only the
            filesystem is persisted: the snapshot is smaller and faster to take,
            and sandboxes created from it cold-boot (start fresh from disk)
            instead of restoring memory, so they begin without the source
            sandbox's running processes, in-memory state, and open connections.
            The source sandbox keeps running in both cases. Defaults to true.

    SandboxPauseRequest:
      type: object
      properties:
        memory:
          type: boolean
          default: true
          description: >-
            Whether to capture a full memory snapshot. When false, only the
            filesystem is persisted and resuming the sandbox cold-boots
            (reboots) it from disk, losing in-memory state, running processes,
            and open connections. Resume it with an explicit request (connect or
            resume); auto-resume, which can be triggered by arbitrary traffic,
            refuses such a sandbox. Defaults to true.
        requireHealthyGuest:
          type: boolean
          default: false
          description: >-
            The pause checks that the sandbox guest agent answers before it
            takes the snapshot. By default an unresponsive agent is recorded
            on the snapshot and the pause proceeds; the sandbox then shows
            `envdUnresponsiveAtPause` and a later resume must ask for
            `memory: false`, since restoring that memory would bring the
            unresponsive agent back. With this true, the pause is instead
            refused with 503 while the agent does not answer, and the sandbox
            keeps running. A filesystem-only pause (`memory: false`) is always
            refused while the agent does not answer, whatever this says.

    SandboxForkRequest:
      type: object
      properties:
        timeout:
          type: integer
          format: int32
          minimum: 0
          default: 15
          description: Time to live for the new forked sandboxes in seconds.
        count:
          type: integer
          format: int32
          minimum: 1
          maximum: 100
          default: 1
          description: >-
            Number of forked sandboxes to create. All forks boot from the same
            snapshot, so the snapshot is captured once regardless of count.
            Each fork succeeds or fails independently; the outcome of each is
            reported in its entry of the response list.

    SandboxForkResult:
      type: object
      description: >-
        Result of one requested fork. Exactly one of sandbox or error is set:
        sandbox when the fork started successfully, error when it failed to
        start.
      properties:
        sandbox:
          $ref: "#/components/schemas/Sandbox"
        error:
          $ref: "#/components/schemas/Error"

    TeamMetric:
      description: Team metric with timestamp
      required:
        - timestamp
        - timestampUnix
        - concurrentSandboxes
        - sandboxStartRate
      properties:
        timestamp:
          type: string
          format: date-time
          deprecated: true
          description: Timestamp of the metric entry
        timestampUnix:
          type: integer
          format: int64
          description: Timestamp of the metric entry in Unix time (seconds since epoch)
        concurrentSandboxes:
          type: integer
          format: int32
          description: The number of concurrent sandboxes for the team
        sandboxStartRate:
          type: number
          format: float
          description: Number of sandboxes started per second

    MaxTeamMetric:
      description: Team metric with timestamp
      required:
        - timestamp
        - timestampUnix
        - value
      properties:
        timestamp:
          type: string
          format: date-time
          deprecated: true
          description: Timestamp of the metric entry
        timestampUnix:
          type: integer
          format: int64
          description: Timestamp of the metric entry in Unix time (seconds since epoch)
        value:
          type: number
          description: The maximum value of the requested metric in the given interval

    TeamStatusResponse:
      required:
        - isBanned
        - isBlocked
        - blockedReason
      properties:
        isBanned:
          type: boolean
          description: Whether the team is banned
        isBlocked:
          type: boolean
          description: Whether the team is blocked
        blockedReason:
          type: string
          nullable: true
          description: Why the team is blocked, if a reason was recorded

    TeamLimits:
      description: The team's effective resource limits
      required:
        - maxLengthHours
        - concurrentSandboxes
        - concurrentTemplateBuilds
        - maxVcpu
        - maxRamMb
        - diskMb
        - eventsTtlDays
        - defaultFreeDiskSizeMb
        - maxFreeDiskSizeMb
        - apiTeamRpsList
        - apiTeamRpsDelete
        - maxSecrets
      properties:
        maxLengthHours:
          type: integer
          format: int64
          description: Maximum sandbox lifetime, in hours
        concurrentSandboxes:
          type: integer
          format: int64
          description: Maximum number of sandboxes running at once
        concurrentTemplateBuilds:
          type: integer
          format: int64
          description: Maximum number of template builds running at once
        maxVcpu:
          type: integer
          format: int64
          description: Maximum vCPUs per sandbox
        maxRamMb:
          type: integer
          format: int64
          description: Maximum memory per sandbox, in MiB
        diskMb:
          type: integer
          format: int64
          description: Disk size per sandbox, in MiB
        eventsTtlDays:
          type: integer
          format: int64
          description: Number of days sandbox events are kept
        defaultFreeDiskSizeMb:
          type: integer
          format: int64
          description: Free disk space a template build gets when it requests none, in MiB
        maxFreeDiskSizeMb:
          type: integer
          format: int64
          description: Maximum free disk space a template build may request, in MiB
        apiTeamRpsList:
          type: integer
          format: int64
          description: Requests per second the team may make to list endpoints
        apiTeamRpsDelete:
          type: integer
          format: int64
          description: Requests per second the team may make to delete endpoints
        maxSecrets:
          type: integer
          format: int64
          description: Maximum number of secrets the team may store

    TeamLimitsResponse:
      required:
        - limits
      properties:
        limits:
          $ref: "#/components/schemas/TeamLimits"

    ClusterDetail:
      type: object
      description: A cluster's configuration. The cluster's token is never returned.
      required:
        - id
        - name
        - endpoint
        - endpointTls
        - deletionProtection
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        endpoint:
          type: string
        endpointTls:
          type: boolean
        sandboxProxyDomain:
          type: string
          nullable: true
        authOrgId:
          type: string
          nullable: true
        deletionProtection:
          type: boolean
          description: While true, deleting the cluster is refused.

    ClusterDetailWithTeams:
      type: object
      required:
        - cluster
        - teams
        - teamCount
        - templateCount
      properties:
        cluster:
          $ref: "#/components/schemas/ClusterDetail"
        teams:
          $ref: "#/components/schemas/ClusterTeamListResponse"
        teamCount:
          type: integer
          format: int64
          description: Teams assigned to the cluster. Must be 0 before the cluster can be deleted.
        templateCount:
          type: integer
          format: int64
          description: Live templates on the cluster. Deleting the cluster deletes them.

    ClusterListItem:
      type: object
      required:
        - id
        - name
        - endpoint
        - teamCount
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        endpoint:
          type: string
        sandboxProxyDomain:
          type: string
          nullable: true
        teamCount:
          type: integer
          format: int64
          description: Number of teams assigned to the cluster.

    ClusterListResponse:
      type: object
      required:
        - items
        - total
      properties:
        items:
          type: array
          items:
            $ref: "#/components/schemas/ClusterListItem"
        total:
          type: integer
          format: int64
          description: Number of clusters matching the search, ignoring limit and offset

    ClusterTeamListItem:
      type: object
      required:
        - id
        - email
        - isBanned
        - createdAt
      properties:
        id:
          type: string
          format: uuid
        email:
          type: string
        name:
          type: string
          nullable: true
        slug:
          type: string
          nullable: true
        isBanned:
          type: boolean
        createdAt:
          type: string
          format: date-time

    ClusterTeamListResponse:
      type: object
      required:
        - items
        - total
      properties:
        items:
          type: array
          items:
            $ref: "#/components/schemas/ClusterTeamListItem"
        total:
          type: integer
          format: int64
          description: Number of teams assigned to the cluster, ignoring limit and offset

    AdminClusterCreateRequest:
      type: object
      required:
        - name
        - endpoint
        - endpoint_tls
        - token
      properties:
        cluster_id:
          type: string
          format: uuid
          description: Optional stable identifier for idempotent creation. Reuse succeeds only when the immutable configuration is identical.
        name:
          type: string
          minLength: 1
        endpoint:
          type: string
          minLength: 1
        endpoint_tls:
          type: boolean
        token:
          type: string
          minLength: 1
        sandbox_proxy_domain:
          type: string
          nullable: true
        auth_org_id:
          type: string
          nullable: true

    ClusterUpdateRequest:
      type: object
      description: >-
        Partial update; only the properties present are written. An explicit
        null or an empty string clears `sandboxProxyDomain` or `authOrgId`.
      properties:
        name:
          type: string
          minLength: 1
        endpoint:
          type: string
          minLength: 1
        endpointTls:
          type: boolean
        sandboxProxyDomain:
          type: string
          nullable: true
        authOrgId:
          type: string
          nullable: true
        deletionProtection:
          type: boolean

    ClusterTokenRotateRequest:
      type: object
      required:
        - token
      properties:
        token:
          type: string
          minLength: 1
          format: password
          description: New cluster access token. Write-only.

    AdminSandboxKillResult:
      required:
        - killedCount
        - failedCount
      properties:
        killedCount:
          type: integer
          description: Number of sandboxes successfully killed
        failedCount:
          type: integer
          description: Number of sandboxes that failed to kill

    AdminSandbox:
      type: object
      required:
        - sandboxID
        - teamID
        - state
      properties:
        sandboxID:
          type: string
          description: Identifier of the sandbox
        teamID:
          type: string
          format: uuid
          description: Identifier of the team that owns the sandbox
        state:
          $ref: "#/components/schemas/AdminSandboxState"

    AdminSandboxState:
      type: string
      description: State after the sandbox's latest create, resume, pause or kill event
      enum:
        - running
        - paused
        - killed
      x-enum-varnames:
        - AdminSandboxStateRunning
        - AdminSandboxStatePaused
        - AdminSandboxStateKilled

    AdminSandboxBuildStatusGroup:
      type: string
      description: |
        Coarse build state derived from the build status: pending (pending,
        waiting), in_progress (in_progress, building, snapshotting), ready
        (ready, uploaded, success) or failed (any other status)
      enum:
        - pending
        - in_progress
        - ready
        - failed
      x-enum-varnames:
        - AdminSandboxBuildStatusGroupPending
        - AdminSandboxBuildStatusGroupInProgress
        - AdminSandboxBuildStatusGroupReady
        - AdminSandboxBuildStatusGroupFailed

    AdminSandboxBuild:
      type: object
      description: A build assigned to a sandbox's snapshot template under a tag
      required:
        - buildID
        - templateID
        - tag
        - status
        - statusGroup
        - clusterNodeID
        - assignedAt
        - isCurrent
        - restorable
      properties:
        buildID:
          type: string
          format: uuid
          description: Identifier of the build
        templateID:
          type: string
          description: Identifier of the snapshot template the build is assigned to
        tag:
          type: string
          description: Tag the build is assigned under
        status:
          type: string
          description: Build status as stored, for example ready, snapshotting or waiting
        statusGroup:
          $ref: "#/components/schemas/AdminSandboxBuildStatusGroup"
        clusterNodeID:
          type: string
          nullable: true
          description: Node that produced the build, null when it was not recorded
        assignedAt:
          type: string
          format: date-time
          description: When the build was assigned to the template under this tag
        isCurrent:
          type: boolean
          description: |
            Whether this build is the template's newest ready assignment under
            the tag, the build a resume uses, regardless of the status filter
        restorable:
          type: boolean
          description: |
            Whether the restore route would accept this build: it is ready,
            assigned under the default tag, not the current build, and its
            snapshot template is not deleted

    AdminSandboxBuildList:
      type: object
      required:
        - items
        - total
        - snapshotTemplateID
      properties:
        items:
          type: array
          items:
            $ref: "#/components/schemas/AdminSandboxBuild"
        total:
          type: integer
          format: int64
          description: Number of assignments matching the tag and status filter, ignoring limit and offset
        snapshotTemplateID:
          type: string
          nullable: true
          description: |
            Identifier of the template that holds the sandbox's snapshot, null
            when the sandbox has no snapshot

    AdminSandboxBuildRestoreRequest:
      type: object
      required:
        - buildID
      properties:
        buildID:
          type: string
          format: uuid
          description: |
            Build to make current. It must be ready and already assigned to the
            sandbox's snapshot template under the default tag.

    AdminSandboxBuildRestoreResult:
      type: object
      required:
        - sandboxID
        - templateID
        - buildID
        - assignedAt
        - previousBuildID
      properties:
        sandboxID:
          type: string
          description: Identifier of the sandbox
        templateID:
          type: string
          description: Identifier of the snapshot template that received the assignment
        buildID:
          type: string
          format: uuid
          description: Build that is now the template's current default build
        assignedAt:
          type: string
          format: date-time
          description: When the new assignment was written
        previousBuildID:
          type: string
          format: uuid
          nullable: true
          description: Build that was current before the restore, null when there was none

    AdminTeamRunningSandboxCounts:
      type: object
      description: |
        Cached live sandbox index count keyed by team ID. Counts may briefly
        include sandboxes transitioning out of running; teams without indexed
        sandboxes are omitted.
      additionalProperties:
        type: integer
        format: int64
        minimum: 1

    AdminBuildCancelResult:
      required:
        - cancelledCount
        - failedCount
      properties:
        cancelledCount:
          type: integer
          description: Number of builds successfully cancelled
        failedCount:
          type: integer
          description: Number of builds that failed to cancel

    AdminTeamListRequest:
      type: object
      properties:
        projectIds:
          type: array
          description: Only list these teams. An empty list matches no team; omit it to list every team.
          items:
            type: string
            format: uuid
        search:
          type: string
          description: A team ID, as a UUID or public project ID, matches that team exactly. Any other text matches a substring of the email, name or slug, ignoring case.
        hideBanned:
          type: boolean
          default: false
          description: Leave out banned teams
        hideBlocked:
          type: boolean
          default: false
          description: Leave out blocked teams
        createdAfter:
          type: string
          format: date-time
          description: Only list teams created at or after this time
        createdBefore:
          type: string
          format: date-time
          description: Only list teams created at or before this time
        sortBy:
          $ref: "#/components/schemas/AdminTeamListSortField"
        sortOrder:
          allOf:
            - $ref: "#/components/schemas/OrderDirection"
          description: Ignored when `sortBy` is omitted.
        limit:
          type: integer
          format: int32
          minimum: 1
          maximum: 100
          default: 50
          description: Maximum number of teams to return
        offset:
          type: integer
          format: int32
          minimum: 0
          default: 0
          description: Number of matching teams to skip

    AdminTeamListSortField:
      type: string
      description: |
        Column to order by, with newer teams first among equal values. Omit it
        to list the newest teams first.
      enum:
        - name
        - email
        - createdAt
        - runningSandboxes
      x-enum-varnames:
        - AdminTeamListSortFieldName
        - AdminTeamListSortFieldEmail
        - AdminTeamListSortFieldCreatedAt
        - AdminTeamListSortFieldRunningSandboxes

    AdminTeamList:
      type: object
      required:
        - items
        - total
      properties:
        items:
          type: array
          items:
            $ref: "#/components/schemas/AdminTeamListItem"
        total:
          type: integer
          format: int64
          description: Number of teams matching the filters, ignoring limit and offset

    AdminTeamListItem:
      type: object
      required:
        - id
        - email
        - name
        - isBanned
        - isBlocked
        - createdAt
        - memberCount
      properties:
        id:
          type: string
          format: uuid
        email:
          type: string
        name:
          type: string
        isBanned:
          type: boolean
        isBlocked:
          type: boolean
        createdAt:
          type: string
          format: date-time
        memberCount:
          type: integer
          format: int64
          description: Number of users in the team
        runningSandboxCount:
          type: integer
          format: int64
          minimum: 0
          description: Running sandboxes from the same cached snapshot as `GET /admin/sandboxes/running-counts`. Present only when the list is sorted by `runningSandboxes`.

    AdminTeam:
      type: object
      required:
        - id
        - email
        - name
        - slug
        - createdAt
        - isBlocked
        - isBanned
        - sandboxSchedulingLabels
      properties:
        id:
          type: string
          format: uuid
        email:
          type: string
        name:
          type: string
        slug:
          type: string
        createdAt:
          type: string
          format: date-time
        isBlocked:
          type: boolean
        isBanned:
          type: boolean
        blockedReason:
          type: string
          nullable: true
        sandboxSchedulingLabels:
          type: array
          items:
            type: string
        clusterId:
          type: string
          format: uuid
          nullable: true
        clusterName:
          type: string
          nullable: true

    AdminTeamSchedulingLabels:
      type: object
      required:
        - labels
      properties:
        labels:
          type: array
          maxItems: 20
          description: The team's full set of labels. A request's labels replace the current ones.
          items:
            type: string
            minLength: 1
            maxLength: 63
            pattern: ^[a-z0-9]([a-z0-9-]*[a-z0-9])?$

    AdminTeamBanResult:
      type: object
      description: |
        The outcome of banning one team. The ban is stored before the team's
        sandboxes are killed and its builds cancelled, so it holds even when
        either step fails.
      required:
        - teamID
        - sandboxesKilled
        - sandboxesFailedToKill
        - buildsCancelled
        - buildsFailedToCancel
      properties:
        teamID:
          type: string
          format: uuid
        sandboxesKilled:
          type: integer
          description: Number of the team's sandboxes killed
        sandboxesFailedToKill:
          type: integer
          description: Number of the team's sandboxes that failed to kill
        sandboxKillError:
          type: string
          description: Set when the kill step failed or ran out of time; the counts cover what it did until then.
        buildsCancelled:
          type: integer
          description: Number of the team's builds cancelled
        buildsFailedToCancel:
          type: integer
          description: Number of the team's builds that failed to cancel
        buildCancelError:
          type: string
          description: Set when the cancel step failed or ran out of time; the counts cover what it did until then.

    AdminTeamsBanRequest:
      type: object
      required:
        - teamIDs
      properties:
        teamIDs:
          type: array
          minItems: 1
          maxItems: 100
          uniqueItems: true
          items:
            type: string
            format: uuid

    AdminTeamsBanResult:
      type: object
      required:
        - banned
        - notFound
        - failed
      properties:
        banned:
          type: array
          description: Teams whose ban is stored, with the outcome of killing their sandboxes and cancelling their builds
          items:
            $ref: "#/components/schemas/AdminTeamBanResult"
        notFound:
          type: array
          description: Requested teams that do not exist
          items:
            type: string
            format: uuid
        failed:
          type: array
          description: Teams whose ban could not be stored or put into force; retrying repeats every step
          items:
            $ref: "#/components/schemas/AdminTeamBanFailure"

    AdminTeamBanFailure:
      type: object
      required:
        - teamID
        - error
      properties:
        teamID:
          type: string
          format: uuid
        error:
          type: string

    AdminTemplateTeam:
      required:
        - id
        - name
        - email
      properties:
        id:
          type: string
          format: uuid
          description: Identifier of the team that owns the template
        name:
          type: string
          description: Name of the team
        email:
          type: string
          description: Contact email of the team

    AdminTemplateAlias:
      required:
        - id
        - templateID
        - alias
        - namespace
        - isRenamable
      properties:
        id:
          type: string
          format: uuid
          description: Identifier of the alias
        templateID:
          type: string
          description: Identifier of the template the alias resolves to
        alias:
          type: string
          description: The alias
        namespace:
          type: string
          nullable: true
          description: Namespace of the alias, or null for an alias that resolves for every team
        isRenamable:
          type: boolean
          description: Whether building the template under another name replaces the alias

    AdminTemplateAliases:
      required:
        - templateID
        - public
        - team
        - aliases
      properties:
        templateID:
          type: string
          description: Identifier of the template
        public:
          type: boolean
          description: Whether the template is public
        team:
          $ref: "#/components/schemas/AdminTemplateTeam"
        aliases:
          type: array
          description: All aliases of the template, those without a namespace first
          items:
            $ref: "#/components/schemas/AdminTemplateAlias"

    AdminTemplateAliasCreateRequest:
      required:
        - templateID
        - alias
      properties:
        templateID:
          type: string
          minLength: 1
          description: Identifier of the template the alias resolves to
        alias:
          type: string
          minLength: 1
          maxLength: 128
          description: The alias, without a namespace or tag

    AdminTemplateAliasDeleted:
      required:
        - aliasID
        - templateID
        - alias
      properties:
        aliasID:
          type: string
          format: uuid
          description: Identifier of the removed alias
        templateID:
          type: string
          description: Identifier of the template the alias resolved to
        alias:
          type: string
          description: The removed alias

    AdminDefaultTemplate:
      required:
        - templateID
        - description
      properties:
        templateID:
          type: string
          description: Identifier of the default template
        description:
          type: string
          nullable: true
          description: Description of the default template

    AdminDefaultTemplateCreateRequest:
      required:
        - templateID
      properties:
        templateID:
          type: string
          minLength: 1
          description: Identifier of the template to make a default template
        description:
          type: string
          nullable: true
          maxLength: 1000
          description: Description of the default template; blank is stored as none

    AdminDefaultTemplateUpdateRequest:
      required:
        - description
      properties:
        description:
          type: string
          nullable: true
          maxLength: 1000
          description: New description of the default template; null or blank clears it

    AdminTemplateLookup:
      required:
        - templateID
        - team
        - names
        - public
        - createdAt
        - lastSpawnedAt
        - spawnCount
        - isSnapshot
        - snapshotSandboxID
        - matchedBuildID
        - builds
      properties:
        templateID:
          type: string
          description: Identifier of the template
        team:
          $ref: "#/components/schemas/AdminTemplateTeam"
        names:
          type: array
          description: Names of the template (namespace/alias format when namespaced)
          items:
            type: string
        public:
          type: boolean
          description: Whether the template is public
        createdAt:
          type: string
          format: date-time
          description: Time when the template was created
        lastSpawnedAt:
          type: string
          format: date-time
          nullable: true
          description: Time when the template was last used
        spawnCount:
          type: integer
          format: int64
          description: Number of times the template was used
        isSnapshot:
          type: boolean
          description: Whether the template is a snapshot of a sandbox
        snapshotSandboxID:
          type: string
          nullable: true
          description: The sandbox a snapshot template was taken from
        matchedBuildID:
          type: string
          format: uuid
          nullable: true
          description: The build the query matched, when it was a build ID
        builds:
          type: array
          description: The template's newest builds of any tag and status, newest first, at most 100
          items:
            $ref: "#/components/schemas/TemplateBuild"

    VolumeToken:
      type: object
      properties:
        token:
          type: string
      required:
        - token

    Template:
      required:
        - templateID
        - buildID
        - cpuCount
        - memoryMB
        - diskSizeMB
        - public
        - createdAt
        - updatedAt
        - createdBy
        - lastSpawnedAt
        - spawnCount
        - buildCount
        - envdVersion
        - aliases
        - names
        - buildStatus
      properties:
        templateID:
          type: string
          description: Identifier of the template
        buildID:
          type: string
          description: Identifier of the last successful build for given template
        cpuCount:
          $ref: "#/components/schemas/CPUCount"
        memoryMB:
          $ref: "#/components/schemas/MemoryMB"
        diskSizeMB:
          $ref: "#/components/schemas/DiskSizeMB"
        public:
          type: boolean
          description: Whether the template is public or only accessible by the team
        aliases:
          type: array
          description: Aliases of the template
          deprecated: true
          items:
            type: string
        names:
          type: array
          description: Names of the template (namespace/alias format when namespaced)
          items:
            type: string
        createdAt:
          type: string
          format: date-time
          description: Time when the template was created
        updatedAt:
          type: string
          format: date-time
          description: Time when the template was last updated
        createdBy:
          allOf:
            - $ref: "#/components/schemas/TeamUser"
          nullable: true
        lastSpawnedAt:
          type: string
          nullable: true
          format: date-time
          description: Time when the template was last used
        spawnCount:
          type: integer
          format: int64
          description: Number of times the template was used
        buildCount:
          type: integer
          format: int32
          description: Number of times the template was built
        envdVersion:
          $ref: "#/components/schemas/EnvdVersion"
        buildStatus:
          $ref: "#/components/schemas/TemplateBuildStatus"
        isDefault:
          type: boolean
          description: >
            Whether the template is one of the platform's default templates. A default template
            owned by another team carries zero or null usage fields (`spawnCount`, `buildCount`,
            `lastSpawnedAt`, `createdBy`).
        description:
          type: string
          description: Description of the template

    TemplateSearchResponse:
      required:
        - data
        - nextCursor
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/Template"
        nextCursor:
          type: string
          nullable: true
          description: Cursor of the next page, or null on the last page

    BuildStatus:
      type: string
      description: Build status as the builds list reports it.
      enum:
        - building
        - failed
        - success

    ListedBuild:
      type: object
      required:
        - id
        - template
        - templateId
        - status
        - statusMessage
        - createdAt
        - finishedAt
        - cpuCount
        - memoryMB
        - diskSizeMB
        - envdVersion
      properties:
        id:
          type: string
          format: uuid
          description: Identifier of the build.
        template:
          type: string
          description: Template alias when present, otherwise template ID.
        templateId:
          type: string
          description: Identifier of the template.
        status:
          $ref: "#/components/schemas/BuildStatus"
        statusMessage:
          type: string
          nullable: true
          description: Failure message when status is `failed`, otherwise `null`.
        createdAt:
          type: string
          format: date-time
          description: Build creation timestamp in RFC3339 format.
        finishedAt:
          type: string
          format: date-time
          nullable: true
          description: Build completion timestamp in RFC3339 format, if finished.
        cpuCount:
          type: integer
          format: int64
          description: CPU cores configured for the build.
        memoryMB:
          type: integer
          format: int64
          description: Memory in MiB configured for the build.
        diskSizeMB:
          type: integer
          format: int64
          nullable: true
          description: Disk size in MiB configured for the build, if recorded.
        envdVersion:
          type: string
          nullable: true
          description: envd version the build was created with, if recorded.

    BuildsListResponse:
      type: object
      required:
        - data
        - nextCursor
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/ListedBuild"
        nextCursor:
          type: string
          nullable: true
          description: Cursor to pass to the next list request, or `null` if there is no next page.

    BuildStatusItem:
      type: object
      required:
        - id
        - status
        - finishedAt
        - statusMessage
      properties:
        id:
          type: string
          format: uuid
          description: Identifier of the build.
        status:
          $ref: "#/components/schemas/BuildStatus"
        finishedAt:
          type: string
          format: date-time
          nullable: true
          description: Build completion timestamp in RFC3339 format, if finished.
        statusMessage:
          type: string
          nullable: true
          description: Failure message when status is `failed`, otherwise `null`.

    BuildsStatusesResponse:
      type: object
      required:
        - buildStatuses
      properties:
        buildStatuses:
          type: array
          description: List of build statuses
          items:
            $ref: "#/components/schemas/BuildStatusItem"

    BuildInfo:
      type: object
      required:
        - createdAt
        - finishedAt
        - status
        - statusMessage
      properties:
        names:
          type: array
          items:
            type: string
          nullable: true
          description: Template names related to this build, if available.
        createdAt:
          type: string
          format: date-time
          description: Build creation timestamp in RFC3339 format.
        finishedAt:
          type: string
          format: date-time
          nullable: true
          description: Build completion timestamp in RFC3339 format, if finished.
        status:
          $ref: "#/components/schemas/BuildStatus"
        statusMessage:
          type: string
          nullable: true
          description: Failure message when status is `failed`, otherwise `null`.

    TemplateRequestResponseV3:
      required:
        - templateID
        - buildID
        - public
        - aliases
        - names
        - tags
      properties:
        templateID:
          type: string
          description: Identifier of the template
        buildID:
          type: string
          description: Identifier of the last successful build for given template
        public:
          type: boolean
          description: Whether the template is public or only accessible by the team
        names:
          type: array
          description: Names of the template
          items:
            type: string
        tags:
          type: array
          description: Tags assigned to the template build
          items:
            type: string
        aliases:
          type: array
          description: Aliases of the template
          deprecated: true
          items:
            type: string

    TemplateBuild:
      required:
        - buildID
        - status
        - createdAt
        - updatedAt
        - cpuCount
        - memoryMB
      properties:
        buildID:
          type: string
          format: uuid
          description: Identifier of the build
        status:
          $ref: "#/components/schemas/TemplateBuildStatus"
        createdAt:
          type: string
          format: date-time
          description: Time when the build was created
        updatedAt:
          type: string
          format: date-time
          description: Time when the build was last updated
        finishedAt:
          type: string
          format: date-time
          description: Time when the build was finished
        cpuCount:
          $ref: "#/components/schemas/CPUCount"
        memoryMB:
          $ref: "#/components/schemas/MemoryMB"
        diskSizeMB:
          $ref: "#/components/schemas/DiskSizeMB"
        envdVersion:
          $ref: "#/components/schemas/EnvdVersion"

    TemplateWithBuilds:
      allOf:
        - $ref: "#/components/schemas/Template"
        - type: object
          required:
            - builds
          properties:
            builds:
              type: array
              description: List of builds for the template
              items:
                $ref: "#/components/schemas/TemplateBuild"

    TemplateAliasResponse:
      required:
        - templateID
        - public
      properties:
        templateID:
          type: string
          description: Identifier of the template
        public:
          type: boolean
          description: Whether the template is public or only accessible by the team

    TemplateStep:
      description: Step in the template build process
      required:
        - type
      properties:
        type:
          type: string
          description: Type of the step
        args:
          default: []
          type: array
          description: Arguments for the step
          items:
            type: string
        filesHash:
          type: string
          pattern: "^[0-9a-f]{64}$"
          description: Hash of the files used in the step (lowercase hex SHA-256)
        force:
          default: false
          type: boolean
          description: Whether the step should be forced to run regardless of the cache

    TemplateBuildRequestV3:
      properties:
        name:
          description: Name of the template. Can include a tag with colon separator (e.g. "my-template" or "my-template:v1"). If tag is included, it will be treated as if the tag was provided in the tags array.
          type: string
          maxLength: 128
        tags:
          type: array
          description: Tags to assign to the template build
          items:
            type: string
        alias:
          description: Alias of the template. Deprecated, use name instead.
          type: string
          maxLength: 128
          deprecated: true
        teamID:
          deprecated: true
          type: string
          description: Identifier of the team, as its UUID or its public project ID (prj_)
        cpuCount:
          $ref: "#/components/schemas/CPUCount"
        memoryMB:
          $ref: "#/components/schemas/MemoryMB"
        minFreeDiskMb:
          $ref: "#/components/schemas/MinFreeDiskMb"

    FromImageRegistry:
      oneOf:
        - $ref: "#/components/schemas/AWSRegistry"
        - $ref: "#/components/schemas/GCPRegistry"
        - $ref: "#/components/schemas/GeneralRegistry"
      discriminator:
        propertyName: type
        mapping:
          aws: "#/components/schemas/AWSRegistry"
          gcp: "#/components/schemas/GCPRegistry"
          registry: "#/components/schemas/GeneralRegistry"

    AWSRegistry:
      type: object
      required:
        - type
        - awsAccessKeyId
        - awsSecretAccessKey
        - awsRegion
      properties:
        type:
          type: string
          enum: [aws]
          description: Type of registry authentication
        awsAccessKeyId:
          type: string
          description: AWS Access Key ID for ECR authentication
        awsSecretAccessKey:
          type: string
          description: AWS Secret Access Key for ECR authentication
        awsRegion:
          type: string
          description: AWS Region where the ECR registry is located

    GCPRegistry:
      type: object
      required:
        - type
        - serviceAccountJson
      properties:
        type:
          type: string
          enum: [gcp]
          description: Type of registry authentication
        serviceAccountJson:
          type: string
          description: Service Account JSON for GCP authentication

    GeneralRegistry:
      type: object
      required:
        - type
        - username
        - password
      properties:
        type:
          type: string
          enum: [registry]
          description: Type of registry authentication
        username:
          type: string
          description: Username to use for the registry
        password:
          type: string
          description: Password to use for the registry

    TemplateBuildStartV2:
      type: object
      description: Exactly one of fromImage or fromTemplate must be given and non-empty.
      properties:
        fromImage:
          type: string
          minLength: 1
          description: Image to use as a base for the template build
        fromTemplate:
          type: string
          minLength: 1
          description: Template to use as a base for the template build
        fromImageRegistry:
          $ref: "#/components/schemas/FromImageRegistry"
        force:
          default: false
          type: boolean
          description: Whether the whole build should be forced to run regardless of the cache
        steps:
          default: []
          description: List of steps to execute in the template build
          type: array
          items:
            $ref: "#/components/schemas/TemplateStep"
        startCmd:
          description: Start command to execute in the template after the build
          type: string
        readyCmd:
          description: Ready check command to execute in the template after the build
          type: string

    TemplateBuildFileUpload:
      required:
        - present
      properties:
        present:
          type: boolean
          description: Whether the file is already present in the cache
        url:
          description: Url where the file should be uploaded to
          type: string
        headers:
          description: Request headers that must be sent with the upload request
          type: object
          additionalProperties:
            type: string

    LogLevel:
      type: string
      description: State of the sandbox
      enum:
        - debug
        - info
        - warn
        - error

    BuildLogEntry:
      required:
        - timestamp
        - message
        - level
      properties:
        timestamp:
          type: string
          format: date-time
          description: Timestamp of the log entry
        message:
          type: string
          description: Log message content
        level:
          $ref: "#/components/schemas/LogLevel"
        step:
          type: string
          description: Step in the build process related to the log entry

    BuildStatusReason:
      required:
        - message
      properties:
        message:
          type: string
          description: Message with the status reason, currently reporting only for error status
        step:
          type: string
          description: Step that failed
        logEntries:
          default: []
          description: Log entries related to the status reason
          type: array
          items:
            $ref: "#/components/schemas/BuildLogEntry"

    TemplateBuildStatus:
      type: string
      description: Status of the template build
      enum:
        - building
        - waiting
        - ready
        - error

    TemplateBuildInfo:
      required:
        - templateID
        - buildID
        - status
        - logs
        - logEntries
      properties:
        logs:
          default: []
          deprecated: true
          description: Build logs (always empty since the V1 build path was removed, use logEntries)
          type: array
          items:
            type: string
        logEntries:
          default: []
          description: Build logs structured
          type: array
          items:
            $ref: "#/components/schemas/BuildLogEntry"
        templateID:
          type: string
          description: Identifier of the template
        buildID:
          type: string
          description: Identifier of the build
        status:
          $ref: "#/components/schemas/TemplateBuildStatus"
        reason:
          $ref: "#/components/schemas/BuildStatusReason"

    TemplateBuildLogsResponse:
      required:
        - logs
      properties:
        logs:
          default: []
          description: Build logs structured
          type: array
          items:
            $ref: "#/components/schemas/BuildLogEntry"

    LogsDirection:
      type: string
      description: Direction of the logs that should be returned
      enum:
        - forward
        - backward
      x-enum-varnames:
        - LogsDirectionForward
        - LogsDirectionBackward

    LogsSource:
      type: string
      description: Source of the logs that should be returned
      enum:
        - temporary
        - persistent
      x-enum-varnames:
        - LogsSourceTemporary
        - LogsSourcePersistent

    NodeStatus:
      type: string
      description: |
        Status of the node.
        - standby: the node is not actively used, but it can return to ready and continue serving traffic.
        - not_ready: the node is starting and cannot take new work yet. It becomes ready by itself and cannot be set through the API.
      enum:
        - ready
        - draining
        - connecting
        - unhealthy
        - standby
        - shutting_down
        - not_ready
      x-enum-varnames:
        - NodeStatusReady
        - NodeStatusDraining
        - NodeStatusConnecting
        - NodeStatusUnhealthy
        - NodeStatusStandby
        - NodeStatusShuttingDown
        - NodeStatusNotReady

    NodeStatusChange:
      required:
        - status
      properties:
        clusterID:
          type: string
          format: uuid
          description: Identifier of the cluster
        status:
          $ref: "#/components/schemas/NodeStatus"

    DiskMetrics:
      required:
        - mountPoint
        - device
        - filesystemType
        - usedBytes
        - totalBytes
      properties:
        mountPoint:
          type: string
          description: Mount point of the disk
        device:
          type: string
          description: Device name
        filesystemType:
          type: string
          description: Filesystem type (e.g., ext4, xfs)
        usedBytes:
          type: integer
          format: uint64
          description: Used space in bytes
        totalBytes:
          type: integer
          format: uint64
          description: Total space in bytes

    NodeMetrics:
      description: Node metrics
      required:
        - allocatedCPU
        - allocatedMemoryBytes
        - cpuPercent
        - memoryUsedBytes
        - cpuCount
        - memoryTotalBytes
        - disks
        - hugePagesTotal
        - hugePagesUsed
        - hugePagesReserved
        - hugePageSizeBytes
      properties:
        allocatedCPU:
          type: integer
          format: uint32
          description: Number of allocated CPU cores
        cpuPercent:
          type: integer
          format: uint32
          description: Node CPU usage percentage
        cpuCount:
          type: integer
          format: uint32
          description: Total number of CPU cores on the node
        allocatedMemoryBytes:
          type: integer
          format: uint64
          description: Amount of allocated memory in bytes
        memoryUsedBytes:
          type: integer
          format: uint64
          description: Node memory used in bytes
        memoryTotalBytes:
          type: integer
          format: uint64
          description: Total node memory in bytes
        hugePagesTotal:
          type: integer
          format: uint64
          description: Total number of preallocated hugepages on the node
        hugePagesUsed:
          type: integer
          format: uint64
          description: Number of hugepages in use (total - free)
        hugePagesReserved:
          type: integer
          format: uint64
          description: Number of reserved hugepages (committed but not yet faulted)
        hugePageSizeBytes:
          type: integer
          format: uint64
          description: Size of a single hugepage in bytes
        disks:
          type: array
          description: Detailed metrics for each disk/mount point
          items:
            $ref: "#/components/schemas/DiskMetrics"
    MachineInfo:
      required:
        - cpuFamily
        - cpuModel
        - cpuModelName
        - cpuArchitecture
      properties:
        cpuFamily:
          type: string
          description: CPU family of the node
        cpuModel:
          type: string
          description: CPU model of the node
        cpuModelName:
          type: string
          description: CPU model name of the node
        cpuArchitecture:
          type: string
          description: CPU architecture of the node

    Node:
      required:
        - id
        - serviceInstanceID
        - clusterID
        - status
        - statusChangedAt
        - sandboxCount
        - outstandingWork
        - maxSandboxes
        - metrics
        - createSuccesses
        - createFails
        - sandboxStartingCount
        - version
        - commit
        - machineInfo
      properties:
        version:
          type: string
          description: Version of the orchestrator
        commit:
          type: string
          description: Commit of the orchestrator
        id:
          type: string
          description: Identifier of the node
        serviceInstanceID:
          type: string
          description: Service instance identifier of the node
        clusterID:
          type: string
          description: Identifier of the cluster
        machineInfo:
          $ref: "#/components/schemas/MachineInfo"
        status:
          $ref: "#/components/schemas/NodeStatus"
        statusChangedAt:
          type: string
          format: date-time
          description: Time when the node status was last changed
        sandboxCount:
          type: integer
          format: uint32
          description: Number of sandboxes running on the node
        maxSandboxes:
          type: integer
          format: int64
          description: Cached node-scoped sandbox admission limit. Nonpositive values reject creation.
        outstandingWork:
          type: integer
          format: uint64
          minimum: 0
          description: Cached count of work holds on the node. Zero means idle or not yet reported; it does not by itself authorize deletion.
        metrics:
          $ref: "#/components/schemas/NodeMetrics"
        createSuccesses:
          type: integer
          format: uint64
          description: Number of sandbox create successes
        createFails:
          type: integer
          format: uint64
          description: Number of sandbox create fails
        sandboxStartingCount:
          type: integer
          format: int
          description: Number of starting Sandboxes

    NodeDetail:
      required:
        - id
        - serviceInstanceID
        - clusterID
        - status
        - statusChangedAt
        - sandboxCount
        - outstandingWork
        - maxSandboxes
        - createSuccesses
        - createFails
        - version
        - commit
        - metrics
        - machineInfo
      properties:
        clusterID:
          type: string
          description: Identifier of the cluster
        version:
          type: string
          description: Version of the orchestrator
        commit:
          type: string
          description: Commit of the orchestrator
        id:
          type: string
          description: Identifier of the node
        serviceInstanceID:
          type: string
          description: Service instance identifier of the node
        machineInfo:
          $ref: "#/components/schemas/MachineInfo"
        status:
          $ref: "#/components/schemas/NodeStatus"
        statusChangedAt:
          type: string
          format: date-time
          description: Time when the node status was last changed
        sandboxCount:
          type: integer
          format: uint32
          description: Number of sandboxes running on the node
        maxSandboxes:
          type: integer
          format: int64
          description: Cached node-scoped sandbox admission limit. Nonpositive values reject creation.
        outstandingWork:
          type: integer
          format: uint64
          minimum: 0
          description: Cached count of work holds on the node. Zero means idle or not yet reported; it does not by itself authorize deletion.
        metrics:
          $ref: "#/components/schemas/NodeMetrics"
        createSuccesses:
          type: integer
          format: uint64
          description: Number of sandbox create successes
        createFails:
          type: integer
          format: uint64
          description: Number of sandbox create fails

    TeamAPIKey:
      required:
        - id
        - name
        - mask
        - createdAt
      properties:
        id:
          type: string
          format: uuid
          description: Identifier of the API key
        name:
          type: string
          description: Name of the API key
        mask:
          $ref: "#/components/schemas/IdentifierMaskingDetails"
        createdAt:
          type: string
          format: date-time
          description: Timestamp of API key creation
        createdBy:
          allOf:
            - $ref: "#/components/schemas/TeamUser"
          nullable: true
        lastUsed:
          type: string
          format: date-time
          description: Last time this API key was used
          nullable: true

    CreatedTeamAPIKey:
      required:
        - id
        - key
        - mask
        - name
        - createdAt
      properties:
        id:
          type: string
          format: uuid
          description: Identifier of the API key
        key:
          type: string
          description: Raw value of the API key
        mask:
          $ref: "#/components/schemas/IdentifierMaskingDetails"
        name:
          type: string
          description: Name of the API key
        createdAt:
          type: string
          format: date-time
          description: Timestamp of API key creation
        createdBy:
          allOf:
            - $ref: "#/components/schemas/TeamUser"
          nullable: true
        lastUsed:
          type: string
          format: date-time
          description: Last time this API key was used
          nullable: true

    NewTeamAPIKey:
      required:
        - name
      properties:
        name:
          type: string
          description: Name of the API key

    UpdateTeamAPIKey:
      required:
        - name
      properties:
        name:
          type: string
          description: New name for the API key

    AssignedTemplateTags:
      required:
        - tags
        - buildID
      properties:
        tags:
          type: array
          items:
            type: string
          description: Assigned tags of the template
        buildID:
          type: string
          format: uuid
          description: Identifier of the build associated with these tags

    TemplateTag:
      required:
        - tag
        - buildID
        - createdAt
      properties:
        tag:
          type: string
          description: The tag name
        buildID:
          type: string
          format: uuid
          description: Identifier of the build associated with this tag
        createdAt:
          type: string
          format: date-time
          description: Time when the tag was assigned

    TemplateTagAssignment:
      type: object
      required:
        - assignmentId
        - buildId
        - assignedAt
        - buildCreatedAt
        - buildFinishedAt
      properties:
        assignmentId:
          type: string
          format: uuid
          description: Identifier of the tag assignment event.
        buildId:
          type: string
          format: uuid
          description: Identifier of the assigned build.
        assignedAt:
          type: string
          format: date-time
          description: Time when the tag was assigned to the build.
        buildCreatedAt:
          type: string
          format: date-time
          description: Time when the assigned build was created.
        buildFinishedAt:
          type: string
          format: date-time
          nullable: true
          description: Time when the assigned build finished.

    TemplateTagGroup:
      type: object
      required:
        - tag
        - assignments
        - hasMore
      properties:
        tag:
          type: string
          description: Template tag name.
        assignments:
          type: array
          description: Ready assignment events for this tag, sorted latest first.
          items:
            $ref: "#/components/schemas/TemplateTagAssignment"
        hasMore:
          type: boolean
          description: Whether more ready assignment events exist beyond the requested assignment limit.

    TemplateTagGroupsResponse:
      type: object
      required:
        - tags
        - nextCursor
      properties:
        tags:
          type: array
          items:
            $ref: "#/components/schemas/TemplateTagGroup"
        nextCursor:
          type: string
          nullable: true
          description: Cursor to pass as `tagsCursor` for the next page, or `null` if there is no next page.

    TemplateTagsCountResponse:
      type: object
      required:
        - total
      properties:
        total:
          type: integer
          format: int64
          description: Total distinct ready tags for the template.

    TemplateTagExistsResponse:
      type: object
      required:
        - exists
        - normalizedTag
      properties:
        exists:
          type: boolean
          description: Whether the template tag has at least one ready assignment.
        normalizedTag:
          type: string
          description: Normalized template tag name.

    TemplateTagAssignmentsResponse:
      type: object
      required:
        - data
        - nextCursor
      properties:
        data:
          type: array
          description: Ready assignment events for the tag, sorted latest first.
          items:
            $ref: "#/components/schemas/TemplateTagAssignment"
        nextCursor:
          type: string
          nullable: true
          description: Cursor to pass to the next list request, or `null` if there is no next page.

    AssignTemplateTagsRequest:
      required:
        - target
        - tags
      properties:
        target:
          type: string
          description: Target template in "name:tag" format
        tags:
          description: Tags to assign to the template
          type: array
          items:
            type: string

    DeleteTemplateTagsRequest:
      required:
        - name
        - tags
      properties:
        name:
          type: string
          description: Name of the template
        tags:
          description: Tags to delete
          type: array
          items:
            type: string

    Error:
      required:
        - code
        - message
      properties:
        code:
          type: integer
          format: int32
          description: Error code
        error_code:
          type: string
          description: >-
            Machine-readable semantic error code. Not a closed set; initial values:
            sandbox_capacity_unavailable, sandbox_placement_timeout,
            sandbox_no_compatible_node, sandbox_create_failed (a node could not
            create the sandbox this time; retry), sandbox_create_refused (a node
            refused the sandbox for a reason no retry changes, such as a vcpu
            count out of bounds in the stored build; a server error, since no
            request field reaches that check), internal_server_error,
            secret_limit_reached, idempotency_request_mismatch, idempotency_in_progress,
            idempotency_outcome_unknown, cluster_registration_invalid,
            cluster_registration_conflict, cluster_assignment_invalid,
            cluster_assignment_project_not_found, cluster_assignment_cluster_not_found,
            cluster_assignment_already_assigned, cluster_assignment_cluster_deleting,
            sandbox_snapshot_guest_agent_unresponsive (a plain resume of a
            snapshot taken while the sandbox guest agent was not responding;
            resume it with memory: false).
        message:
          type: string
          description: Error

    IdentifierMaskingDetails:
      required:
        - prefix
        - valueLength
        - maskedValuePrefix
        - maskedValueSuffix
      properties:
        prefix:
          type: string
          description: Prefix that identifies the token or key type
        valueLength:
          type: integer
          description: Length of the token or key
        maskedValuePrefix:
          type: string
          description: Prefix used in masked version of the token or key
        maskedValueSuffix:
          type: string
          description: Suffix used in masked version of the token or key

    Volume:
      type: object
      properties:
        volumeID:
          type: string
          description: ID of the volume
        name:
          type: string
          description: Name of the volume
      required:
        - volumeID
        - name

    VolumeAndToken:
      type: object
      properties:
        volumeID:
          type: string
          description: ID of the volume
        name:
          type: string
          description: Name of the volume
        token:
          type: string
          description: Auth token to use for interacting with volume content
        domain:
          type: string
          description: |
            Domain to use as the destination for volume content requests,
            replacing the default `api.<E2B_DOMAIN>`. Only returned when the
            team is connected to a custom (BYOC) cluster; absent otherwise, in
            which case the default domain is used.
      required:
        - volumeID
        - name
        - token

    NewVolume:
      type: object
      properties:
        name:
          type: string
          description: Name of the volume
          pattern: "^[a-zA-Z0-9_-]+$"
      required:
        - name

    SecretMetadata:
      type: object
      description: >
        Customer metadata of the secret. Always present, empty when unset.
        At most 32 entries; keys are limited to 128 bytes, values to 1024
        bytes, and a secret's metadata to 8192 bytes in total.
      maxProperties: 32
      additionalProperties:
        type: string
        maxLength: 1024

    Secret:
      type: object
      description: Metadata of a secret. It never carries the secret value.
      required:
        - secretID
        - name
        - currentVersion
        - metadata
        - createdAt
        - updatedAt
      properties:
        secretID:
          type: string
          description: Identifier of the secret
        name:
          type: string
          description: Name of the secret, unique within the project
        currentVersion:
          type: integer
          format: int64
          description: Version served to readers that do not name one
        metadata:
          $ref: "#/components/schemas/SecretMetadata"
        createdAt:
          type: string
          format: date-time
          description: Time when the secret was created
        updatedAt:
          type: string
          format: date-time
          description: Time when the secret was last updated

    NewSecret:
      type: object
      required:
        - name
        - value
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 128
          pattern: '^[a-zA-Z0-9_-]+$'
          description: >
            Name of the secret, unique within the project. Names are
            lower-cased before storage and returned in that canonical form;
            the sec_ prefix is reserved for secret identifiers.
        value:
          type: string
          description: Runtime marker stored as the secret's first version. The runtime resolves it to a value at sandbox egress.
        metadata:
          $ref: "#/components/schemas/SecretMetadata"

    SecretUpdate:
      type: object
      required:
        - value
      properties:
        value:
          type: string
          description: Runtime marker stored as the secret's new version. The runtime resolves it to a value at sandbox egress.
        metadata:
          $ref: "#/components/schemas/SecretMetadata"

    SandboxEvent:
      description: Sandbox event
      required:
        - id
        - version
        - type
        - timestamp
        - sandboxId
        - sandboxExecutionId
        - sandboxTemplateId
        - sandboxBuildId
        - sandboxTeamId
      properties:
        id:
          type: string
          format: uuid
          description: Event unique identifier
        version:
          type: string
          description: Event structure version
        type:
          type: string
          description: Event name
        eventCategory:
          type: string
          deprecated: true
          description: Category of the event (e.g., 'lifecycle', 'process', etc.)
        eventLabel:
          type: string
          deprecated: true
          description: Label for the specific event type (e.g., 'sandbox_started', 'process_oom', etc.)
        eventData:
          type: object
          nullable: true
          description: Optional JSON data associated with the event

        timestamp:
          type: string
          format: date-time
          description: Timestamp of the event
        sandboxId:
          type: string
          format: string
          description: Unique identifier for the sandbox
        sandboxExecutionId:
          type: string
          format: string
          description: Unique identifier for the sandbox execution
        sandboxTemplateId:
          type: string
          format: string
          description: Unique identifier for the sandbox template
        sandboxBuildId:
          type: string
          format: string
          description: Unique identifier for the sandbox build
        sandboxTeamId:
          type: string
          format: uuid
          description: Team identifier associated with the sandbox
    WebhookCreate:
      description: Configuration for registering new webhooks
      required:
        - name
        - url
        - events
        - signatureSecret
      properties:
        name:
          type: string
        url:
          type: string
          format: uri
        events:
          type: array
          items:
            type: string
        enabled:
          type: boolean
          default: true
        signatureSecret:
          type: string
          description: Secret used to sign the webhook payloads
    WebhookCreation:
      description: Webhook creation response
      required:
        - id
        - name
        - createdAt
        - teamId
        - url
        - enabled
        - events
      properties:
        id:
          type: string
          description: Webhook unique identifier
        name:
          type: string
          description: Webhook user friendly name
        createdAt:
          type: string
          format: date-time
          description: Time when the template was created
        teamId:
          type: string
          description: Unique identifier for the team
        url:
          type: string
          format: uri
        enabled:
          type: boolean
        events:
          type: array
          items:
            type: string
    WebhookDetail:
      description: Webhook detail response
      required:
        - id
        - teamId
        - name
        - createdAt
        - url
        - enabled
        - events
      properties:
        id:
          type: string
          description: Webhook unique identifier
        teamId:
          type: string
          description: Unique identifier for the team
        name:
          type: string
          description: Webhook user friendly name
        createdAt:
          type: string
          format: date-time
          description: Time when the template was created
        url:
          type: string
          format: uri
        enabled:
          type: boolean
        events:
          type: array
          items:
            type: string
    WebhookConfiguration:
      description: Configuration for updating existing webhooks
      properties:
        enabled:
          type: boolean
        name:
          type: string
          description: Webhook user friendly name
        url:
          type: string
          format: uri
        events:
          type: array
          items:
            type: string
        signatureSecret:
          type: string
          description: Secret used to sign the webhook payloads
    WebhookDelivery:
      description: Webhook delivery attempt
      required:
        - id
        - teamId
        - webhookId
        - eventId
        - sandboxId
        - eventType
        - status
        - durationMs
        - requestBody
        - requestHeaders
        - requestUrl
        - errorClass
        - timestamp
      properties:
        id:
          type: string
          format: uuid
          description: Delivery attempt identifier
        teamId:
          type: string
          format: uuid
          description: Team identifier
        webhookId:
          type: string
          format: uuid
          description: Webhook configuration identifier
        eventId:
          type: string
          format: uuid
          description: Sandbox event identifier
        sandboxId:
          type: string
          description: Sandbox identifier
        eventType:
          type: string
          description: Sandbox event type
        status:
          type: string
          enum: [success, failed]
          description: Delivery attempt status
        durationMs:
          type: integer
          format: int32
          description: Delivery request duration in milliseconds
        requestBody:
          type: string
          description: Serialized webhook request body
        requestHeaders:
          type: string
          description: JSON-encoded request headers with sensitive values redacted
        requestUrl:
          type: string
          format: uri
          description: URL attempted for this delivery
        responseBody:
          type: string
          nullable: true
          description: Truncated response body, if a response was received
        responseHeaders:
          type: string
          nullable: true
          description: JSON-encoded response headers, if a response was received
        responseHttpStatusCode:
          type: integer
          format: int32
          nullable: true
          description: HTTP response status code, if a response was received
        errorClass:
          type: string
          nullable: true
          enum:
            - http_error
            - dns_error
            - timeout
            - transport_error
            - request_error
            - signature_error
            - canceled
          description: Machine-readable non-HTTP or HTTP failure class
        errorMessage:
          type: string
          nullable: true
          description: Error message for failures without a useful response body
        timestamp:
          type: string
          format: date-time
          description: Time when the delivery attempt started
    WebhookDeliveryStats:
      description: Webhook delivery aggregate stats
      required:
        - buckets
        - total
        - failed
        - durationMs
      properties:
        buckets:
          type: array
          items:
            $ref: "#/components/schemas/WebhookDeliveryStatsBucket"
        total:
          type: integer
          format: int64
        failed:
          type: integer
          format: int64
        durationMs:
          $ref: "#/components/schemas/WebhookDeliveryDurationStats"
    WebhookDeliveryDurationStats:
      description: Webhook delivery duration statistics in milliseconds
      required:
        - minimum
        - average
        - maximum
      properties:
        minimum:
          type: number
          format: double
        average:
          type: number
          format: double
        maximum:
          type: number
          format: double
    WebhookDeliveryStatsBucket:
      description: Webhook delivery stats for a time bucket
      required:
        - timestamp
        - total
        - failed
        - durationMs
      properties:
        timestamp:
          type: string
          format: date-time
        total:
          type: integer
          format: int64
        failed:
          type: integer
          format: int64
        durationMs:
          $ref: "#/components/schemas/WebhookDeliveryDurationStats"
    WebhookDeliveryGroup:
      description: Webhook delivery attempts grouped by sandbox event
      required:
        - eventId
        - eventType
        - sandboxId
        - attempts
      properties:
        eventId:
          type: string
          format: uuid
        eventType:
          type: string
        sandboxId:
          type: string
        attempts:
          type: array
          items:
            $ref: "#/components/schemas/WebhookDelivery"
    WebhookDeliveriesListPayload:
      description: Paginated webhook delivery attempts grouped by event
      required:
        - data
        - nextCursor
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/WebhookDeliveryGroup"
        nextCursor:
          type: string
          nullable: true
          description: Cursor to pass to the next list request, or null when there is no next page.
    ManagementClusterRegistrationRequest:
      type: object
      required:
        - name
        - endpoint
        - endpoint_tls
        - token
      properties:
        name:
          type: string
          minLength: 1
        endpoint:
          type: string
          minLength: 1
        endpoint_tls:
          type: boolean
        token:
          type: string
          minLength: 1
        sandbox_proxy_domain:
          type: string
          nullable: true
        auth_org_id:
          type: string
          nullable: true

    ManagementClusterProjects:
      type: object
      required: [project_ids]
      properties:
        project_ids:
          type: array
          items:
            type: string
            format: uuid

    ManagementProjectSettingsRequest:
      type: object
      required: [revision, settings]
      properties:
        revision:
          type: integer
          format: int64
          minimum: 1
          description: >-
            Monotonic per-project revision. Older or duplicate revisions
            succeed without changing stored state.
        settings:
          $ref: "#/components/schemas/ProjectSettings"

    ProjectSettings:
      type: object
      description: The project's stored settings. PUT replaces the complete document.
      required: [sandboxSettings]
      properties:
        sandboxSettings:
          $ref: "#/components/schemas/SandboxSettings"

    SandboxSettings:
      type: object
      properties:
        defaultAllowPublicTraffic:
          type: boolean
          description: >-
            Whether new sandboxes without an explicit network.allowPublicTraffic
            accept traffic without a traffic access token. Omission uses the
            public default. Existing sandboxes, resumes and forks keep their settings.

    ManagementProjectUpsertRequest:
      type: object
      description: >-
        The properties of a project this side stores. Name, slug and email are
        synchronized on every push. The optional cluster assignment is preserved
        when omitted.


        A project's tier is not among them, and this side assigns none. Limits
        arrive separately and in full through managementUpsertProjectLimits.
      required: [name, slug, email]
      properties:
        cluster_id:
          type: string
          format: uuid
          description: Cluster assignment to synchronize. Omission preserves the existing assignment.
        name:
          type: string
          minLength: 1
          maxLength: 255
        slug:
          type: string
          minLength: 1
          maxLength: 63
          description: >-
            Changing it renames the project, and its template names follow:
            each name held under an earlier slug is also given under the new
            one, and the old names keep working. A name the new slug already
            holds is left as it is. A slug already held on this control plane
            is a 409, on a rename as much as on a create.
        email:
          type: string
          minLength: 1
          maxLength: 255
          description: Contact address recorded on the project.

    ManagementProject:
      allOf:
        - $ref: "#/components/schemas/ManagementProjectUpsertRequest"
        - type: object
          required: [id]
          properties:
            id:
              type: string
              format: uuid

    ManagementProjectMemberIdentity:
      type: object
      required: [issuer, subject]
      properties:
        issuer:
          type: string
          minLength: 1
          maxLength: 2048
        subject:
          type: string
          minLength: 1
          maxLength: 2048

    ManagementProjectMemberApplyRequest:
      type: object
      required: [revision, present]
      properties:
        revision:
          type: integer
          format: int64
          minimum: 1
        present:
          type: boolean
        is_default:
          type: boolean
          default: false
          description: Whether this membership is the user's default team. Omitted requests from older sources remain non-default.
        identities:
          type: array
          maxItems: 16
          items:
            $ref: "#/components/schemas/ManagementProjectMemberIdentity"

    ManagementProjectBlockRequest:
      type: object
      description: >-
        Desired project block state. A newer revision replaces the state,
        including any intervening manual block or unblock.
      required: [revision, blocked]
      properties:
        revision:
          type: integer
          format: int64
          minimum: 1
          description: >-
            Monotonic per-project revision. Older or duplicate revisions
            succeed without changing stored state.
        blocked:
          type: boolean
          description: Whether the project is refused billable work.
        reason:
          type: string
          description: >-
            Reason included in blocked-request errors. Cleared when blocked is false.
        decided_at:
          $ref: "#/components/schemas/ManagementDecidedAt"

    ManagementProjectBanRequest:
      type: object
      description: >-
        Desired project ban state. A newer revision replaces the state,
        including any intervening manual ban or unban.
      required: [revision, banned]
      properties:
        revision:
          type: integer
          format: int64
          minimum: 1
          description: >-
            Monotonic per-project revision. Older or duplicate revisions
            succeed without changing stored state.
        banned:
          type: boolean
          description: Whether the project is refused at authentication.
        decided_at:
          $ref: "#/components/schemas/ManagementDecidedAt"

    ManagementDecidedAt:
      type: string
      format: date-time
      description: >-
        When the caller decided this revision, in RFC 3339. Stored with the
        revision and used to measure how long the decision took to apply here.
        Omit it when the caller does not know; the delivery is then counted as
        origin unknown rather than as zero lag.

    ManagementProjectLimits:
      type: object
      description: >-
        A project's effective limits, already resolved by the caller. Every
        field is absolute: this side stores what it is given and performs no
        arithmetic of its own.


        The minimums below are the contract for what a limit may be, at least
        as strict as the CHECK constraints on default_limits. project_limits
        stores the same values under looser constraints on purpose — it is a
        push target, and a floor that only rejects the impossible keeps a
        future decision about what is allowed a change to this schema rather
        than a migration.


        `max_disk_size_mb` and `max_free_disk_size_mb` are one ceiling under two
        names, and either name alone carries it. A caller that sends both must
        send them equal; a caller that sends neither is refused. Sending both is
        what a caller does while receivers older than the second name are still
        running.
      required:
        - revision
        - concurrent_sandboxes
        - max_sandbox_length_hours
        - max_vcpu
        - max_ram_mb
        - disk_mb
        - concurrent_template_builds
        - events_ttl_days
        - default_free_disk_size_mb
        - api_team_rps_list
        - api_team_rps_delete
        - max_secrets
      anyOf:
        - required: [max_free_disk_size_mb]
        - required: [max_disk_size_mb]
      properties:
        revision:
          type: integer
          format: int64
          minimum: 1
          description: >-
            The caller's version of this answer, raised whenever the limits it
            resolved for the project change. Delivery is over a network, so two
            pushes can be in flight at once and arrive in either order: this
            side stores the revision it accepted and drops a delivery at or
            below it, which is what keeps a delayed retry from putting the
            project back on limits it has already left.


            Comparable only against earlier revisions for the same project.
        concurrent_sandboxes:
          type: integer
          format: int32
          minimum: 1
        max_sandbox_length_hours:
          type: integer
          format: int32
          minimum: 1
        max_vcpu:
          type: integer
          format: int32
          minimum: 1
        max_ram_mb:
          type: integer
          format: int64
          minimum: 1
        disk_mb:
          type: integer
          format: int64
          minimum: 1
        concurrent_template_builds:
          type: integer
          format: int32
          minimum: 1
        events_ttl_days:
          type: integer
          format: int32
          minimum: 1
        default_free_disk_size_mb:
          type: integer
          format: int64
          minimum: 0
          description: >-
            The default free-space growth target when a template build request
            omits one. May sit anywhere at or below the maximum free-space
            growth target, and usually sits well below it; a delivery whose
            default exceeds the maximum is rejected.
        max_free_disk_size_mb:
          type: integer
          format: int64
          minimum: 1
          description: >-
            The most a template build may request as its free-space growth
            target.
        max_disk_size_mb:
          type: integer
          format: int64
          minimum: 1
          description: >-
            The same ceiling as max_free_disk_size_mb, under the name it was
            first published with. Kept until every deployed sender and receiver
            speaks the other name.
        api_team_rps_list:
          type: integer
          format: int64
          minimum: 0
          description: >-
            Requests per second a project may make to each list endpoint. Zero
            disables the limit.
        api_team_rps_delete:
          type: integer
          format: int64
          minimum: 0
          description: >-
            Requests per second a project may make to each delete endpoint. Zero
            disables the limit.
        max_secrets:
          type: integer
          format: int32
          minimum: 1
          description: Live secrets the project may hold.
        decided_at:
          $ref: "#/components/schemas/ManagementDecidedAt"

tags:
  - name: templates
  - name: sandboxes
  - name: auth
  - name: api-keys
  - name: tags
  - name: volumes
  - name: secrets

paths:
  /health:
    get:
      summary: Health check
      description: Health check
      responses:
        "204":
          description: The service is healthy
        "401":
          $ref: "#/components/responses/401"
        "429":
          $ref: "#/components/responses/429"

  /teams:
    get:
      summary: List teams
      description: List all teams
      tags: [auth]
      security:
        - AuthProviderBearerAuth: []
      responses:
        "200":
          description: Successfully returned all teams
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Team"
        "401":
          $ref: "#/components/responses/401"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /teams/{teamID}/metrics:
    get:
      summary: Team metrics
      description: Get metrics for the team
      tags: [auth]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/teamID"
        - in: query
          name: start
          schema:
            type: integer
            format: int64
            minimum: 0
          description: Unix timestamp for the start of the interval, in seconds, for which the metrics
        - in: query
          name: end
          schema:
            type: integer
            format: int64
            minimum: 0
            description: Unix timestamp for the end of the interval, in seconds, for which the metrics
      responses:
        "200":
          description: Successfully returned the team metrics
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/TeamMetric"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "403":
          $ref: "#/components/responses/403"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /teams/{teamID}/metrics/max:
    get:
      summary: Maximum team metrics
      description: Get the maximum metrics for the team in the given interval
      tags: [auth]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/teamID"
        - in: query
          name: start
          schema:
            type: integer
            format: int64
            minimum: 0
          description: Unix timestamp for the start of the interval, in seconds, for which the metrics
        - in: query
          name: end
          schema:
            type: integer
            format: int64
            minimum: 0
            description: Unix timestamp for the end of the interval, in seconds, for which the metrics
        - in: query
          name: metric
          required: true
          schema:
            type: string
            enum: [concurrent_sandboxes, sandbox_start_rate]
          description: Metric to retrieve the maximum value for
      responses:
        "200":
          description: Successfully returned the team metrics
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MaxTeamMetric"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "403":
          $ref: "#/components/responses/403"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /unstable/teams/{teamID}/status:
    get:
      summary: Team access status
      description: Returns whether the team is banned or blocked, and why it is blocked. A team-authenticated request may read only its own team.
      tags: [auth]
      security:
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      parameters:
        - $ref: "#/components/parameters/teamID"
      responses:
        "200":
          description: Successfully returned the team access status
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TeamStatusResponse"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "403":
          $ref: "#/components/responses/403"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /unstable/teams/{teamID}/limits:
    get:
      summary: Team limits
      description: Returns the team's effective resource limits. A team-authenticated request may read only its own team.
      tags: [auth]
      security:
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      parameters:
        - $ref: "#/components/parameters/teamID"
      responses:
        "200":
          description: Successfully returned the team limits
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TeamLimitsResponse"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "403":
          $ref: "#/components/responses/403"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /sandboxes:
    get:
      summary: List running sandboxes
      x-api-group: list
      description: List all running sandboxes. Returns 400 when more than 5000 running sandboxes match; use GET /v2/sandboxes to page through them.
      deprecated: true
      tags: [sandboxes]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - name: metadata
          in: query
          description: Metadata query used to filter the sandboxes (e.g. "user=abc&app=prod"). Each key and values must be URL encoded.
          required: false
          schema:
            type: string
      responses:
        "200":
          description: Successfully returned all running sandboxes
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/ListedSandbox"
        "401":
          $ref: "#/components/responses/401"
        "400":
          $ref: "#/components/responses/400"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"
    post:
      summary: Create sandbox
      description: Create a sandbox from the template. All system communication with the sandbox is secured. Use POST /v2/sandboxes instead.
      deprecated: true
      tags: [sandboxes]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/NewSandbox"
      responses:
        "201":
          description: The sandbox was created successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Sandbox"
        "401":
          $ref: "#/components/responses/401"
        "400":
          $ref: "#/components/responses/400"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"
        "503":
          $ref: "#/components/responses/503"
        "504":
          $ref: "#/components/responses/504"

  /v2/sandboxes:
    post:
      summary: Create sandbox (v2)
      description: Create a sandbox from the template. All system communication with the sandbox is secured.
      parameters:
        - name: Idempotency-Key
          in: header
          required: false
          description: |
            Optional team-scoped key for retrying sandbox creation. Use 1 to 255 lowercase ASCII
            letters, digits, or hyphens (a-z, 0-9, -), such as a lowercase UUID. When idempotency is enabled,
            matching retries replay a completed status and body for the retention period. A creation
            failure explicitly classified as safe to retry (Should-Retry: true) permits a fresh
            attempt with the same key and parameters. Only one attempt can run at a time.
            Different request parameters return 409 with error_code idempotency_request_mismatch.
            An in-progress request returns 409 with error_code idempotency_in_progress; an unknown
            outcome returns 422 with error_code idempotency_outcome_unknown. These retries do not execute the request again.
            Retries do not extend retention. If a fresh attempt's request deadline plus response
            persistence budget would exceed the remaining retention, the previous error is replayed.
            After the key expires, it can start a new creation.
          schema:
            type: string
            minLength: 1
            maxLength: 255
            pattern: '^[a-z0-9-]+$'
      tags: [sandboxes]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/NewSandboxV2"
      responses:
        "201":
          description: The sandbox was created successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Sandbox"
        "401":
          $ref: "#/components/responses/401"
        "400":
          description: Bad request
          headers:
            Should-Retry:
              $ref: "#/components/headers/ShouldRetry"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "403":
          description: Forbidden
          headers:
            Should-Retry:
              $ref: "#/components/headers/ShouldRetry"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "404":
          description: Not found
          headers:
            Should-Retry:
              $ref: "#/components/headers/ShouldRetry"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "409":
          description: The Idempotency-Key conflicts with a different request (error_code idempotency_request_mismatch), or the matching original request has no recorded response yet and is within its expected response window (error_code idempotency_in_progress); this request was not executed again
          headers:
            Should-Retry:
              $ref: "#/components/headers/ShouldRetry"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "422":
          description: The matching original request has no recorded response and its expected response deadline has passed or is unknown (error_code idempotency_outcome_unknown); this request was not executed again
          headers:
            Should-Retry:
              $ref: "#/components/headers/ShouldRetry"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "429":
          description: Too many requests
          headers:
            Should-Retry:
              $ref: "#/components/headers/ShouldRetry"
            Retry-After:
              description: When present, the number of seconds to wait before retrying the request.
              required: false
              schema:
                type: integer
                minimum: 0
              example: 30
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "500":
          description: Server error
          headers:
            Should-Retry:
              $ref: "#/components/headers/ShouldRetry"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "503":
          description: Service unavailable
          headers:
            Should-Retry:
              $ref: "#/components/headers/ShouldRetry"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "504":
          description: Backend timeout
          headers:
            Should-Retry:
              $ref: "#/components/headers/ShouldRetry"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
    get:
      summary: List sandboxes (v2)
      x-api-group: list
      description: List all sandboxes
      tags: [sandboxes]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - name: metadata
          in: query
          description: Metadata query used to filter the sandboxes (e.g. "user=abc&app=prod"). Each key and values must be URL encoded.
          required: false
          schema:
            type: string
        - name: state
          in: query
          description: Filter sandboxes by one or more states
          required: false
          schema:
            type: array
            items:
              $ref: "#/components/schemas/SandboxState"
          style: form
          explode: false
        - name: order
          in: query
          description: Sort direction by sandbox start time. Defaults to desc (newest first).
          required: false
          schema:
            $ref: "#/components/schemas/OrderDirection"
        - name: startedAfter
          in: query
          description: Return sandboxes started at or after this timestamp.
          required: false
          schema:
            type: string
            format: date-time
        - name: template
          in: query
          description: Filter sandboxes by a template ID or alias.
          required: false
          schema:
            type: string
        - $ref: "#/components/parameters/paginationNextToken"
        - $ref: "#/components/parameters/paginationLimit"
      responses:
        "200":
          description: Successfully returned all running sandboxes
          headers:
            X-Next-Token:
              $ref: "#/components/headers/XNextToken"
            X-Total-Running:
              $ref: "#/components/headers/XTotalRunning"
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/ListedSandbox"
        "401":
          $ref: "#/components/responses/401"
        "400":
          $ref: "#/components/responses/400"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /sandboxes/metrics:
    get:
      summary: List sandbox metrics
      x-api-group: list
      description: List metrics for given sandboxes
      tags: [sandboxes]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - name: sandbox_ids
          in: query
          required: true
          description: Comma-separated list of sandbox IDs to get metrics for
          explode: false
          schema:
            type: array
            items:
              type: string
            maxItems: 100
            uniqueItems: true
      responses:
        "200":
          description: Successfully returned all running sandboxes with metrics
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SandboxesWithMetrics"
        "401":
          $ref: "#/components/responses/401"
        "400":
          $ref: "#/components/responses/400"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /sandboxes/{sandboxID}/logs:
    get:
      summary: Sandbox logs
      description: Get sandbox logs. Use /v2/sandboxes/{sandboxID}/logs instead.
      deprecated: true
      tags: [sandboxes]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/sandboxID"
        - in: query
          name: start
          schema:
            type: integer
            format: int64
            minimum: 0
          description: Starting timestamp of the logs that should be returned in milliseconds
        - in: query
          name: limit
          schema:
            default: 1000
            format: int32
            minimum: 0
            type: integer
          description: Maximum number of logs that should be returned
      responses:
        "200":
          description: Successfully returned the sandbox logs
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SandboxLogs"
        "404":
          $ref: "#/components/responses/404"
        "401":
          $ref: "#/components/responses/401"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /v2/sandboxes/{sandboxID}/logs:
    get:
      summary: Sandbox logs (v2)
      description: Get sandbox logs
      tags: [sandboxes]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/sandboxID"
        - in: query
          name: cursor
          schema:
            type: integer
            format: int64
            minimum: 0
          description: Starting timestamp of the logs that should be returned in milliseconds
        - in: query
          name: limit
          schema:
            default: 1000
            type: integer
            format: int32
            minimum: 0
            maximum: 1000
          description: Maximum number of logs that should be returned
        - in: query
          name: direction
          schema:
            $ref: "#/components/schemas/LogsDirection"
          description: Direction of the logs that should be returned
        - in: query
          name: level
          schema:
            $ref: "#/components/schemas/LogLevel"
          description: Minimum log level to return. Logs below this level are excluded
        - in: query
          name: search
          schema:
            type: string
            maxLength: 256
          description: Case-sensitive substring match on log message content
      responses:
        "200":
          description: Successfully returned the sandbox logs
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SandboxLogsV2Response"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /sandboxes/{sandboxID}:
    get:
      summary: Sandbox
      description: Get a sandbox by id
      tags: [sandboxes]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/sandboxID"
      responses:
        "200":
          description: Successfully returned the sandbox
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SandboxDetail"
        "404":
          $ref: "#/components/responses/404"
        "401":
          $ref: "#/components/responses/401"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

    delete:
      summary: Kill sandbox
      x-api-group: delete
      description: Kill a sandbox
      tags: [sandboxes]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/sandboxID"
      responses:
        "204":
          description: The sandbox was killed successfully
        "404":
          $ref: "#/components/responses/404"
        "401":
          $ref: "#/components/responses/401"
        "409":
          $ref: "#/components/responses/409"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /sandboxes/{sandboxID}/metrics:
    get:
      summary: Sandbox metrics
      description: Get sandbox metrics
      tags: [sandboxes]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/sandboxID"
        - in: query
          name: start
          schema:
            type: integer
            format: int64
            minimum: 0
          description: Unix timestamp for the start of the interval, in seconds, for which the metrics
        - in: query
          name: end
          schema:
            type: integer
            format: int64
            minimum: 0
            description: Unix timestamp for the end of the interval, in seconds, for which the metrics

      responses:
        "200":
          description: Successfully returned the sandbox metrics
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/SandboxMetric"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  # TODO: Pause and resume might be exposed as POST /sandboxes/{sandboxID}/snapshot and then POST /sandboxes with specified snapshotting setup
  /sandboxes/{sandboxID}/pause:
    post:
      summary: Pause sandbox
      description: >-
        Pause the sandbox. Answers 503 and leaves the sandbox running when it
        cannot be paused right now: its node is busy, it is being snapshotted,
        or `requireHealthyGuest` was set and the sandbox guest agent is not
        responding; retry later.
      tags: [sandboxes]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/sandboxID"
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SandboxPauseRequest"
      responses:
        "204":
          description: The sandbox was paused successfully and can be resumed
        "409":
          $ref: "#/components/responses/409"
        "404":
          $ref: "#/components/responses/404"
        "401":
          $ref: "#/components/responses/401"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"
        "503":
          $ref: "#/components/responses/503"

  /sandboxes/{sandboxID}/resume:
    post:
      summary: Resume sandbox
      deprecated: true
      description: >-
        Resume the sandbox. Answers 409 when the sandbox is already running,
        or when its snapshot was taken while the sandbox guest agent was not
        responding and a plain resume would restore that memory (error_code
        sandbox_snapshot_guest_agent_unresponsive); resume such a sandbox
        without memory (`memory: false`).
      tags: [sandboxes]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/sandboxID"
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ResumedSandbox"
      responses:
        "201":
          description: The sandbox was resumed successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Sandbox"
        "409":
          $ref: "#/components/responses/409"
        "404":
          $ref: "#/components/responses/404"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"
        "503":
          $ref: "#/components/responses/503"
        "504":
          $ref: "#/components/responses/504"

  /sandboxes/{sandboxID}/fork:
    post:
      summary: Fork sandbox
      description: >-
        Fork the sandbox: checkpoint the running sandbox in place (it is
        briefly paused, snapshotted with its full memory state, and resumed on
        its node, keeping its ID and expiration untouched) and create count
        new sandboxes from that snapshot. Returns one result per requested
        fork, each carrying either the created sandbox or the error that
        prevented it from starting. A non-201 status means the request failed
        before any fork was attempted.
      tags: [sandboxes]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/sandboxID"
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SandboxForkRequest"
      responses:
        "201":
          description: >-
            The sandbox was snapshotted and the forks were attempted; each
            entry reports one fork's outcome
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/SandboxForkResult"
        "409":
          $ref: "#/components/responses/409"
        "404":
          $ref: "#/components/responses/404"
        "401":
          $ref: "#/components/responses/401"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"
        "503":
          $ref: "#/components/responses/503"

  /sandboxes/{sandboxID}/connect:
    post:
      summary: Connect sandbox
      description: >-
        Returns sandbox details. If the sandbox is paused, it will be resumed.
        TTL is only extended. Use POST /v2/sandboxes/{sandboxID}/connect
        instead. Answers 409 with error_code
        sandbox_snapshot_guest_agent_unresponsive when the paused sandbox's
        snapshot was taken while its guest agent was not responding and the
        request did not ask for `memory: false`.
      deprecated: true
      tags: [sandboxes]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/sandboxID"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ConnectSandbox"
      responses:
        "200":
          description: The sandbox was already running
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Sandbox"
        "201":
          description: The sandbox was resumed successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Sandbox"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "409":
          $ref: "#/components/responses/409"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"
        "503":
          $ref: "#/components/responses/503"
        "504":
          $ref: "#/components/responses/504"

  /v2/sandboxes/{sandboxID}/connect:
    post:
      summary: Connect sandbox (v2)
      description: >-
        Returns sandbox details. If the sandbox is paused, it will be resumed.
        TTL is only extended. The request body is optional; an omitted timeout
        defaults to 300 seconds. Answers 409 with error_code
        sandbox_snapshot_guest_agent_unresponsive when the paused sandbox's
        snapshot was taken while its guest agent was not responding and the
        request did not ask for `memory: false`.
      tags: [sandboxes]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/sandboxID"
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ConnectSandboxV2"
      responses:
        "200":
          description: The sandbox was already running
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Sandbox"
        "201":
          description: The sandbox was resumed successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Sandbox"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "409":
          $ref: "#/components/responses/409"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"
        "503":
          $ref: "#/components/responses/503"
        "504":
          $ref: "#/components/responses/504"

  /sandboxes/{sandboxID}/timeout:
    post:
      summary: Set sandbox timeout
      description: Set the timeout for the sandbox. The sandbox will expire x seconds from the time of the request. Calling this method multiple times overwrites the TTL, each time using the current timestamp as the starting point to measure the timeout duration.
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      tags: [sandboxes]
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SandboxTimeoutRequest"
      parameters:
        - $ref: "#/components/parameters/sandboxID"
      responses:
        "204":
          description: Successfully set the sandbox timeout
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /sandboxes/{sandboxID}/network:
    put:
      summary: Update sandbox network
      description: Update the network configuration for a running sandbox. Replaces the current egress rules with the provided configuration. Omitting field clears it.
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      tags: [sandboxes]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SandboxNetworkUpdateConfig"
      parameters:
        - $ref: "#/components/parameters/sandboxID"
      responses:
        "204":
          description: Successfully updated the sandbox network configuration
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "409":
          $ref: "#/components/responses/409"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /sandboxes/{sandboxID}/refreshes:
    post:
      summary: Refresh sandbox
      description: Refresh the sandbox extending its time to live
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      tags: [sandboxes]
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SandboxRefreshRequest"
      parameters:
        - $ref: "#/components/parameters/sandboxID"
      responses:
        "204":
          description: Successfully refreshed the sandbox
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"

  /sandboxes/{sandboxID}/snapshots:
    post:
      summary: Create snapshot
      description: Create a persistent snapshot from the sandbox's current state. Snapshots can be used to create new sandboxes and persist beyond the original sandbox's lifetime.
      tags: [sandboxes]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/sandboxID"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SandboxSnapshotRequest"
      responses:
        "201":
          description: Snapshot created successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SnapshotInfo"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"
        "503":
          $ref: "#/components/responses/503"

  /snapshots:
    get:
      summary: List snapshots
      x-api-group: list
      description: List all snapshots for the team
      tags: [snapshots]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - name: sandboxID
          in: query
          required: false
          schema:
            type: string
            description: Filter snapshots by source sandbox ID
        - name: name
          in: query
          description: Filter snapshots by name or ID, optionally tag-qualified (e.g. "my-snapshot", "my-team/my-snapshot" or "my-snapshot:v1").
          required: false
          schema:
            type: string
        - $ref: "#/components/parameters/paginationLimit"
        - $ref: "#/components/parameters/paginationNextToken"
      responses:
        "200":
          description: Successfully returned snapshots
          headers:
            X-Next-Token:
              $ref: "#/components/headers/XNextToken"
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/SnapshotInfo"
        "401":
          $ref: "#/components/responses/401"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /v3/templates:
    post:
      summary: Create template (v3)
      description: Create a new template
      tags: [templates]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TemplateBuildRequestV3"

      responses:
        "202":
          description: The build was requested successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TemplateRequestResponseV3"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "403":
          $ref: "#/components/responses/403"
        "409":
          $ref: "#/components/responses/409"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /v2/templates:
    get:
      summary: List templates (v2)
      x-api-group: list
      description: List all templates
      tags: [templates]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - in: query
          required: false
          name: teamID
          schema:
            type: string
            description: Identifier of the team, as its UUID or its public project ID (prj_)
        - $ref: "#/components/parameters/paginationNextToken"
        - $ref: "#/components/parameters/paginationLimit"
      responses:
        "200":
          description: Successfully returned all templates
          headers:
            X-Next-Token:
              $ref: "#/components/headers/XNextToken"
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Template"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "403":
          $ref: "#/components/responses/403"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /templates/{templateID}/files/{hash}:
    get:
      summary: Template build file upload URL
      description: Get an upload link for a tar file containing build layer files
      tags: [templates]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/templateID"
        - in: path
          name: hash
          required: true
          schema:
            type: string
            pattern: "^[0-9a-f]{64}$"
            description: Hash of the files (lowercase hex SHA-256)

      responses:
        "201":
          description: The upload link where to upload the tar file
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TemplateBuildFileUpload"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /templates:
    get:
      summary: List templates
      x-api-group: list
      description: List all templates. Returns 400 when the team has more than 5000 templates; use /v2/templates to page through them.
      deprecated: true
      tags: [templates]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - in: query
          required: false
          name: teamID
          schema:
            type: string
            description: Identifier of the team, as its UUID or its public project ID (prj_)
      responses:
        "200":
          description: Successfully returned all templates
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Template"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /default-templates:
    get:
      summary: List default templates
      description: >
        Lists the platform's default templates, ordered by template ID. Deleted templates are left
        out. Templates that are not public are listed only to their own team and to admin callers.
        The build, resources and envd version are those of the newest ready build tagged
        `default`, the one a sandbox started from the template runs, and are zero or empty when
        there is none; `buildStatus` describes the newest build tagged `default` in any state.
        Usage fields (`spawnCount`, `buildCount`, `lastSpawnedAt`, `createdBy`) are
        reported only for the caller's own templates and to admin callers.
      tags: [templates]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      responses:
        "200":
          description: Successfully returned the default templates
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Template"
        "401":
          $ref: "#/components/responses/401"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /unstable/templates/search:
    get:
      summary: Search templates
      x-api-group: list
      description: >
        Lists the team's templates together with the platform's public default templates, which
        carry `isDefault: true`, with search, a visibility filter and sorts. Default templates are
        not listed to teams on a dedicated cluster, and those owned by another team carry zero or
        null usage fields. Results are newest first unless `sort` says otherwise; `nextCursor`
        continues the listing and is only valid with the same `sort`. For E2B's own clients: it
        may change or disappear without notice.
      tags: [unstable]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/templatesSearch"
        - $ref: "#/components/parameters/templatesSort"
        - $ref: "#/components/parameters/templatesPublic"
        - $ref: "#/components/parameters/templatesLimit"
        - $ref: "#/components/parameters/templatesCursor"
      responses:
        "200":
          description: Successfully returned the templates
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TemplateSearchResponse"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /unstable/builds:
    get:
      summary: List team builds
      description: >
        Lists the team's builds, newest first, with an optional filter by build ID, template ID or
        template alias and by status. `nextCursor` continues the listing. For E2B's own clients: it
        may change or disappear without notice.
      tags: [unstable]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/buildIDOrTemplate"
        - $ref: "#/components/parameters/buildStatuses"
        - $ref: "#/components/parameters/buildsLimit"
        - $ref: "#/components/parameters/buildsCursor"
      responses:
        "200":
          description: Successfully returned paginated builds.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BuildsListResponse"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "403":
          $ref: "#/components/responses/403"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /unstable/builds/statuses:
    get:
      summary: Build statuses
      description: >
        Returns the statuses of the team's builds with the given IDs; IDs of other teams' builds are
        left out. For E2B's own clients: it may change or disappear without notice.
      tags: [unstable]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/buildIDs"
      responses:
        "200":
          description: Successfully returned build statuses
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BuildsStatusesResponse"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "403":
          $ref: "#/components/responses/403"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /unstable/builds/{buildID}:
    get:
      summary: Build details
      description: >
        Returns a build of the team with the names of its template. For E2B's own clients: it may
        change or disappear without notice.
      tags: [unstable]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/buildID"
      responses:
        "200":
          description: Successfully returned build details.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BuildInfo"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "403":
          $ref: "#/components/responses/403"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /templates/{templateID}:
    get:
      summary: List template builds
      x-api-group: list
      description: List all builds for a template
      tags: [templates]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/templateID"
        - $ref: "#/components/parameters/paginationNextToken"
        - $ref: "#/components/parameters/paginationLimit"
      responses:
        "200":
          description: Successfully returned the template with its builds
          headers:
            X-Next-Token:
              $ref: "#/components/headers/XNextToken"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TemplateWithBuilds"
        "401":
          $ref: "#/components/responses/401"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"
    delete:
      summary: Delete template
      x-api-group: delete
      description: Delete a template
      tags: [templates]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/templateID"
      responses:
        "204":
          description: The template was deleted successfully
        "401":
          $ref: "#/components/responses/401"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"
    patch:
      summary: Update template
      description: Update template
      deprecated: true
      tags: [templates]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/templateID"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TemplateUpdateRequest"
      responses:
        "200":
          description: The template was updated successfully
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /v2/templates/{templateID}/builds/{buildID}:
    post:
      summary: Start template build (v2)
      description: Start the build
      tags: [templates]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/templateID"
        - $ref: "#/components/parameters/buildID"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TemplateBuildStartV2"
      responses:
        "202":
          description: The build has started
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /v2/templates/{templateID}:
    patch:
      summary: Update template (v2)
      description: Update template
      tags: [templates]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/templateID"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TemplateUpdateRequest"
      responses:
        "200":
          description: The template was updated successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TemplateUpdateResponse"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /templates/{templateID}/builds/{buildID}/status:
    get:
      summary: Template build status
      description: Get template build info
      tags: [templates]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/templateID"
        - $ref: "#/components/parameters/buildID"
        - in: query
          name: logsOffset
          schema:
            default: 0
            type: integer
            format: int32
            minimum: 0
          description: Index of the starting build log that should be returned with the template
        - in: query
          name: limit
          schema:
            default: 100
            type: integer
            format: int32
            minimum: 0
            maximum: 100
          description: Maximum number of logs that should be returned
        - in: query
          name: level
          schema:
            $ref: "#/components/schemas/LogLevel"
      responses:
        "200":
          description: Successfully returned the template
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TemplateBuildInfo"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /templates/{templateID}/builds/{buildID}/logs:
    get:
      summary: Template build logs
      description: Get template build logs
      tags: [templates]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/templateID"
        - $ref: "#/components/parameters/buildID"
        - in: query
          name: cursor
          schema:
            type: integer
            format: int64
            minimum: 0
          description: Starting timestamp of the logs that should be returned in milliseconds
        - in: query
          name: limit
          schema:
            default: 100
            type: integer
            format: int32
            minimum: 0
            maximum: 100
          description: Maximum number of logs that should be returned
        - in: query
          name: direction
          schema:
            $ref: "#/components/schemas/LogsDirection"
        - in: query
          name: level
          schema:
            $ref: "#/components/schemas/LogLevel"
        - in: query
          name: source
          schema:
            $ref: "#/components/schemas/LogsSource"
          description: Source of the logs that should be returned from
      responses:
        "200":
          description: Successfully returned the template build logs
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TemplateBuildLogsResponse"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /templates/tags:
    post:
      summary: Assign template tags
      description: Assign tag(s) to a template build
      tags: [tags]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AssignTemplateTagsRequest"
      responses:
        "201":
          description: Tag assigned successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AssignedTemplateTags"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"
    delete:
      summary: Delete template tags
      description: Delete multiple tags from templates
      tags: [tags]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DeleteTemplateTagsRequest"
      responses:
        "204":
          description: Tags deleted successfully
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /templates/{templateID}/tags:
    get:
      summary: List template tags
      x-api-group: list
      description: List all tags for a template
      tags: [tags]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/templateID"
      responses:
        "200":
          description: Successfully returned the template tags
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/TemplateTag"
        "401":
          $ref: "#/components/responses/401"
        "403":
          $ref: "#/components/responses/403"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /templates/{templateID}/tags/groups:
    get:
      summary: List template tag groups
      description: >
        Lists the template's tags that have at least one ready build, each with its most recent
        ready assignments, paginated over tags with a keyset cursor. Returns 404 when the template
        does not exist or belongs to another team.
      tags: [tags]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/templateID"
        - $ref: "#/components/parameters/tagAssignmentLimit"
        - $ref: "#/components/parameters/tagGroupsLimit"
        - $ref: "#/components/parameters/tagGroupsCursor"
        - $ref: "#/components/parameters/tagGroupsSearch"
        - $ref: "#/components/parameters/tagGroupsSort"
      responses:
        "200":
          description: Successfully returned template tag groups
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TemplateTagGroupsResponse"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "403":
          $ref: "#/components/responses/403"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /templates/{templateID}/tags/count:
    get:
      summary: Count template tags
      description: >
        Returns the number of distinct tags of the template that have at least one ready build.
        Returns 404 when the template does not exist or belongs to another team.
      tags: [tags]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/templateID"
      responses:
        "200":
          description: Successfully returned the tag count
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TemplateTagsCountResponse"
        "401":
          $ref: "#/components/responses/401"
        "403":
          $ref: "#/components/responses/403"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /templates/{templateID}/tags/exists:
    get:
      summary: Check template tag
      description: >
        Checks whether a tag of the template has at least one ready build. Returns 404 when the
        template does not exist or belongs to another team.
      tags: [tags]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/templateID"
        - $ref: "#/components/parameters/tagQuery"
      responses:
        "200":
          description: Successfully checked the tag
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TemplateTagExistsResponse"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "403":
          $ref: "#/components/responses/403"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /templates/{templateID}/tags/{tag}/assignments:
    get:
      summary: List template tag assignments
      description: >
        Lists the ready assignments of one tag of the template, newest first, with keyset cursor
        pagination. Returns 404 when the template does not exist or belongs to another team.
      tags: [tags]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/templateID"
        - $ref: "#/components/parameters/tag"
        - $ref: "#/components/parameters/tagAssignmentsCursor"
        - $ref: "#/components/parameters/tagAssignmentsLimit"
      responses:
        "200":
          description: Successfully returned the tag assignments
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TemplateTagAssignmentsResponse"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "403":
          $ref: "#/components/responses/403"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /templates/aliases/{alias}:
    get:
      summary: Check template alias
      description: Check if template with given alias exists
      tags: [templates]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - name: alias
          in: path
          required: true
          schema:
            type: string
            description: Template alias
      responses:
        "200":
          description: Successfully queried template by alias
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TemplateAliasResponse"
        "400":
          $ref: "#/components/responses/400"
        "403":
          $ref: "#/components/responses/403"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /nodes:
    get:
      summary: List nodes
      description: List all nodes
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      parameters:
        - in: query
          name: clusterID
          description: Identifier of the cluster
          required: false
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Successfully returned all nodes
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Node"
        "401":
          $ref: "#/components/responses/401"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /nodes/{nodeID}:
    get:
      summary: Node info
      description: Get node info
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      parameters:
        - $ref: "#/components/parameters/nodeID"
        - in: query
          name: clusterID
          description: Identifier of the cluster
          required: false
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Successfully returned the node
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NodeDetail"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"
    post:
      summary: Change node status
      description: Change status of a node
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      parameters:
        - $ref: "#/components/parameters/nodeID"
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/NodeStatusChange"
      responses:
        "204":
          description: The node status was changed successfully
        "409":
          $ref: "#/components/responses/409"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /admin/teams/{teamID}/sandboxes/kill:
    post:
      summary: Kill all sandboxes for a team
      description: Kills all sandboxes for the specified team
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      parameters:
        - name: teamID
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: Team ID
      responses:
        "200":
          description: Successfully killed sandboxes
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminSandboxKillResult"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /admin/sandboxes/running-counts:
    get:
      summary: Count running sandboxes by team
      description: |
        Returns a shared snapshot normally refreshed after five seconds. A
        sandbox transitioning out of running can remain counted until removal.
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      responses:
        "200":
          description: Running sandbox counts keyed by team ID
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminTeamRunningSandboxCounts"
        "401":
          $ref: "#/components/responses/401"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /admin/sandboxes/{sandboxID}:
    get:
      summary: Get a sandbox's team and state
      description: |
        Reads the team and state of a sandbox from its latest lifecycle event.
        The state lags the sandbox while that event is in flight. A sandbox
        whose events have expired is not found.
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      parameters:
        - $ref: "#/components/parameters/sandboxID"
      responses:
        "200":
          description: The sandbox, its team and its state
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminSandbox"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /unstable/admin/sandboxes/{sandboxID}/builds:
    get:
      summary: List the builds of a sandbox's snapshot template
      description: |
        Lists the build assignments of the template that holds the sandbox's
        snapshot under one tag. Assignments without a creation time are left
        out. A sandbox without a snapshot returns no items and a null
        `snapshotTemplateID`; this route does not report whether the sandbox
        exists.
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      parameters:
        - $ref: "#/components/parameters/sandboxID"
        - name: statusGroup
          in: query
          required: false
          description: Only list builds in these status groups, comma-separated. Omit to list every group.
          style: form
          explode: false
          schema:
            type: array
            items:
              $ref: "#/components/schemas/AdminSandboxBuildStatusGroup"
        - name: tag
          in: query
          required: false
          description: Tag whose assignments are listed
          schema:
            type: string
            minLength: 1
            default: default
        - name: order
          in: query
          required: false
          description: Direction of the assignment time order
          schema:
            $ref: "#/components/schemas/OrderDirection"
        - name: limit
          in: query
          required: false
          description: Maximum number of builds to return
          schema:
            type: integer
            format: int32
            minimum: 1
            maximum: 100
            default: 50
        - name: offset
          in: query
          required: false
          description: Number of matching builds to skip
          schema:
            type: integer
            format: int32
            minimum: 0
            default: 0
      responses:
        "200":
          description: A page of the snapshot template's build assignments
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminSandboxBuildList"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /unstable/admin/sandboxes/{sandboxID}/builds/restore:
    post:
      summary: Make a build the current build of a sandbox's snapshot
      description: |
        Assigns a ready build of the sandbox's snapshot template to the template
        again under the default tag, so the sandbox resumes from that build.
        The snapshot takes the restored build's kind, filesystem-only or
        memory.
        Answers 404 when the sandbox has no snapshot, its snapshot template is
        deleted, or the build is not assigned to that template under the
        default tag, and 409 when the build is not ready or is already the
        current build.
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      parameters:
        - $ref: "#/components/parameters/sandboxID"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AdminSandboxBuildRestoreRequest"
      responses:
        "200":
          description: The build is now the snapshot template's current default build
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminSandboxBuildRestoreResult"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "409":
          $ref: "#/components/responses/409"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /admin/teams/{teamID}/builds/cancel:
    post:
      summary: Cancel all builds for a team
      description: Cancels all in-progress and pending builds for the specified team
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      parameters:
        - name: teamID
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: Team ID
      responses:
        "200":
          description: Successfully cancelled builds
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminBuildCancelResult"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /admin/teams/{teamID}/api-keys:
    get:
      summary: List team API keys as admin
      description: Lists a team's API keys for internal service workflows. Unlike `GET /api-keys`, it does not resolve the team, so it also answers for a banned team.
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      parameters:
        - name: teamID
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: Team ID
      responses:
        "200":
          description: Successfully returned the team's API keys
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/TeamAPIKey"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "500":
          $ref: "#/components/responses/500"
    post:
      summary: Create team API key as admin
      description: Creates a team API key for internal service workflows.
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      parameters:
        - name: teamID
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: Team ID
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/NewTeamAPIKey"
      responses:
        "201":
          description: Team API key created successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreatedTeamAPIKey"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "403":
          $ref: "#/components/responses/403"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /admin/teams/{teamID}/api-keys/{apiKeyID}:
    delete:
      summary: Delete team API key as admin
      description: Deletes a team API key for internal service workflows.
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      parameters:
        - name: teamID
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: Team ID
        - $ref: "#/components/parameters/apiKeyID"
      responses:
        "204":
          description: Team API key deleted successfully
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /unstable/management/clusters/{clusterID}:
    parameters:
      - $ref: "#/components/parameters/clusterID"
    put:
      operationId: managementRegisterCluster
      summary: Register a cluster.
      description: A cluster registered here for the first time starts with deletion protection turned off. Registering an existing cluster again with the same name and auth organization updates its endpoint, TLS setting, sandbox proxy domain and token and keeps its stored deletion protection; a different name or auth organization returns a conflict with error_code cluster_registration_conflict. An invalid registration returns 400 with error_code cluster_registration_invalid.
      tags: [admin]
      security:
        - AdminJWTAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ManagementClusterRegistrationRequest"
      responses:
        "204":
          description: Cluster registration is present.
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "409":
          $ref: "#/components/responses/409"
        "500":
          $ref: "#/components/responses/500"
    delete:
      operationId: managementDeleteCluster
      summary: Delete a cluster and its environments.
      description: Deletes a cluster after all team assignments are detached. In the same transaction, soft-deletes every live template, snapshot template and paused sandbox snapshot on the cluster, releases their aliases, and releases all environment references while preserving environment and build history. A team assignment rejects the deletion and leaves the environments untouched, and so does deletion protection on the cluster. The local cluster's nil ID is rejected. Repeating a completed deletion succeeds.
      tags: [admin]
      security:
        - AdminJWTAuth: []
      responses:
        "204":
          description: Cluster is absent.
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "409":
          $ref: "#/components/responses/409"
        "500":
          $ref: "#/components/responses/500"

  /unstable/management/clusters/{clusterID}/projects:
    parameters:
      - $ref: "#/components/parameters/clusterID"
    get:
      operationId: managementListClusterProjects
      summary: List the projects assigned to a cluster.
      description: Returns the ID of every project whose team is assigned to the cluster, whichever way it was assigned. A deleted project is never assigned. An absent cluster has no projects.
      tags: [admin]
      security:
        - AdminJWTAuth: []
      responses:
        "200":
          description: The projects assigned to the cluster.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ManagementClusterProjects"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "500":
          $ref: "#/components/responses/500"

  /unstable/management/clusters/{clusterID}/deletion:
    parameters:
      - $ref: "#/components/parameters/clusterID"
    put:
      operationId: managementRequestClusterDeletion
      summary: Record that a cluster is being deleted.
      description: Records that the caller is deleting the cluster, for a caller that deletes the cluster's teams before the cluster itself. Refused while the cluster has deletion protection turned on; a protection change in flight commits before or after the check, never between. Once recorded, deletion protection cannot be turned on, so the cluster delete that follows is not refused for protection, and no team can be newly assigned to the cluster. An assignment either commits before the deletion is recorded, where the caller's next project listing finds it, or is refused with cluster_assignment_cluster_deleting. Succeeds when the cluster is absent. Repeating the request succeeds. The local cluster's nil ID is rejected.
      tags: [admin]
      security:
        - AdminJWTAuth: []
      responses:
        "204":
          description: The deletion is recorded, or the cluster is absent.
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "409":
          description: The cluster has deletion protection turned on.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "500":
          $ref: "#/components/responses/500"

  /unstable/management/clusters/{clusterID}/destroy-readiness:
    parameters:
      - $ref: "#/components/parameters/clusterID"
    get:
      operationId: managementClusterDestroyReadiness
      summary: Check cluster destroy readiness.
      description: Checks whether the cluster has deletion protection turned on, or more than one team uses this exact cluster, either as an assigned team or as the owner of active templates or snapshots on it. One team's own templates and snapshots do not block this check, because deleting the cluster soft-deletes them. Soft-deleted history does not count. Returns success if the cluster is absent. This read does not change resources or prevent later assignments or template creation.
      tags: [admin]
      security:
        - AdminJWTAuth: []
      responses:
        "204":
          description: At most one team uses the cluster.
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "409":
          description: The cluster has deletion protection turned on, or more than one team uses it and the other teams and their templates must move off it before destroying the cluster.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "500":
          $ref: "#/components/responses/500"

  /unstable/management/projects/{projectID}/cluster/{clusterID}:
    parameters:
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - $ref: "#/components/parameters/clusterID"
    put:
      operationId: managementAssignProjectCluster
      summary: Assign a cluster to a project.
      description: >-
        Assigns the cluster when the project has no cluster assigned. Replaying the identical
        assignment succeeds; replacing a different assigned cluster returns a conflict.
        Answers 404 when the project is missing or deleted.
      tags: [admin]
      security:
        - AdminJWTAuth: []
      responses:
        "204":
          description: Cluster is assigned to the project.
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "409":
          $ref: "#/components/responses/409"
        "500":
          $ref: "#/components/responses/500"
    delete:
      operationId: managementDetachProjectCluster
      summary: Detach a cluster assignment from a project.
      description: Answers 404 when the project is missing or deleted.
      tags: [admin]
      security:
        - AdminJWTAuth: []
      responses:
        "204":
          description: The matching assignment is absent.
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "409":
          $ref: "#/components/responses/409"
        "500":
          $ref: "#/components/responses/500"

  /unstable/management/projects/{projectID}:
    parameters:
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          format: uuid
    put:
      operationId: managementUpsertProject
      summary: Create or reconcile a project.
      tags: [admin]
      security:
        - AdminJWTAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ManagementProjectUpsertRequest"
      responses:
        "200":
          description: Existing project reconciled.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ManagementProject"
        "201":
          description: Project created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ManagementProject"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "409":
          $ref: "#/components/responses/409"
        "500":
          $ref: "#/components/responses/500"
    delete:
      operationId: managementDeleteProject
      summary: Soft-delete a project.
      description: >-
        Marks the project deleted and blocked, releases its cluster assignment,
        scrubs its name and email to DELETED and its slug to
        deleted-<project ID>, which releases the old slug for reuse, deletes
        its memberships and API keys, soft-deletes its templates and
        snapshots, and enqueues the teardown of its running sandboxes, all in
        one transaction. The project row remains. Afterwards the project
        answers 404 to other management writes. Repeating the call answers
        204 and repeats every step except the deletion time: it re-blocks and
        re-scrubs the project, clears a cluster assignment written since,
        deletes any memberships, keys, templates or snapshots created since,
        and enqueues the teardown again.
      tags: [admin]
      security:
        - AdminJWTAuth: []
      responses:
        "204":
          description: Project is deleted and its teardown is enqueued.
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "500":
          $ref: "#/components/responses/500"

  /unstable/management/projects/{projectID}/members/{userID}:
    parameters:
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - name: userID
        in: path
        required: true
        schema:
          type: string
          format: uuid
    put:
      operationId: managementApplyProjectMember
      summary: Apply one versioned project member projection.
      description: >-
        Applies the newest desired presence for one project member. An older
        or duplicate revision is accepted without changing target state.
      tags: [admin]
      security:
        - AdminJWTAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ManagementProjectMemberApplyRequest"
      responses:
        "204":
          description: Membership projection is applied or already superseded.
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "409":
          $ref: "#/components/responses/409"
        "500":
          $ref: "#/components/responses/500"

  /unstable/management/projects/{projectID}/limits:
    parameters:
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          format: uuid
    put:
      operationId: managementUpsertProjectLimits
      summary: Reconcile effective limits for a project.
      tags: [admin]
      security:
        - AdminJWTAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ManagementProjectLimits"
      responses:
        "204":
          description: Effective limits are synchronized.
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "500":
          $ref: "#/components/responses/500"

  /unstable/management/projects/{projectID}/settings:
    parameters:
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          format: uuid
    put:
      operationId: managementSetProjectSettings
      summary: Apply a project's settings revision.
      description: >-
        Replaces the complete project settings document when the revision is
        newer than the stored revision. Omitted settings are removed. Older
        and duplicate revisions leave the stored document unchanged. Every
        successful delivery invalidates the cached team. Answers 404 when the
        project is missing or deleted.
      tags: [admin]
      security:
        - AdminJWTAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ManagementProjectSettingsRequest"
      responses:
        "204":
          description: Project settings are applied or already superseded.
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "500":
          $ref: "#/components/responses/500"

  /unstable/management/projects/{projectID}/block:
    parameters:
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          format: uuid
    put:
      operationId: managementApplyProjectBlock
      summary: Apply a project's block state.
      description: >-
        Records whether the project is refused billable work, which the auth
        path reads before it lets a sandbox start. An older or duplicate
        revision is accepted without changing target state. Answers 404 when
        the project is missing or deleted.
      tags: [admin]
      security:
        - AdminJWTAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ManagementProjectBlockRequest"
      responses:
        "204":
          description: Block state is applied or already superseded.
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "500":
          $ref: "#/components/responses/500"

  /unstable/management/projects/{projectID}/ban:
    parameters:
      - name: projectID
        in: path
        required: true
        schema:
          type: string
          format: uuid
    put:
      operationId: managementApplyProjectBan
      summary: Apply a project's ban state.
      description: >-
        Records whether the project is banned. Authentication refuses a banned
        project's API keys and members. A revision that turns the ban on also
        kills the project's running sandboxes and cancels its builds in the
        background, and retries while the project stays banned and any of
        them remain. The newest revision wins: an older or duplicate revision is
        accepted without changing target state. Answers 404 when the project
        is missing or deleted.
      tags: [admin]
      security:
        - AdminJWTAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ManagementProjectBanRequest"
      responses:
        "204":
          description: Ban state is applied or already superseded.
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "500":
          $ref: "#/components/responses/500"

  /unstable/admin/teams/query:
    post:
      summary: List teams as admin
      description: |
        Lists teams matching the filters in the request body, with each team's
        member count, and its running sandbox count when sorted by running
        sandboxes. A read despite the POST: the body carries a project ID list
        too long for a query string.
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AdminTeamListRequest"
      responses:
        "200":
          description: The page of matching teams and the number of all matching teams
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminTeamList"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /unstable/admin/teams/bans:
    post:
      operationId: adminBanTeams
      summary: Ban teams
      description: |
        Bans up to 100 teams at once, as
        `PUT /unstable/admin/teams/{teamID}/ban` does, except that every
        team's ban is stored before any team's sandboxes are killed or builds
        cancelled, and the kills and cancellations of all teams share one time
        budget. One team's failure does not stop the others; the response sorts
        every requested team into banned, not found or failed. The work
        continues if the caller disconnects.
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AdminTeamsBanRequest"
      responses:
        "200":
          description: The outcome for every requested team
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminTeamsBanResult"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /unstable/admin/teams/{teamID}:
    get:
      summary: Team as admin
      description: Returns a team with its sandbox scheduling labels and cluster. It also answers for a banned or blocked team.
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      parameters:
        - name: teamID
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: Team ID
      responses:
        "200":
          description: The team
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminTeam"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /unstable/admin/teams/{teamID}/scheduling-labels:
    put:
      summary: Replace a team's sandbox scheduling labels
      description: |
        Replaces the labels that place the team's new sandboxes on matching
        nodes. Labels are deduplicated, keeping the first occurrence of each.
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      parameters:
        - name: teamID
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: Team ID
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AdminTeamSchedulingLabels"
      responses:
        "200":
          description: The labels as written
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminTeamSchedulingLabels"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /unstable/admin/teams/{teamID}/ban:
    parameters:
      - name: teamID
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: Team ID
    put:
      operationId: adminBanTeam
      summary: Ban a team
      description: |
        Marks the team as banned so its API keys stop authenticating, then
        kills its sandboxes and cancels its builds. The ban is stored first:
        a failure to kill or cancel is reported in the result and does not
        undo it. Killing and cancelling stop after a fixed time budget, and a
        step cut short is reported as failed. Banning an already banned team
        repeats the kill and cancel. The work continues if the caller
        disconnects.
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      responses:
        "200":
          description: The team is banned
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminTeamBanResult"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"
    delete:
      operationId: adminUnbanTeam
      summary: Unban a team
      description: Clears the team's ban. Idempotent.
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      responses:
        "204":
          description: The team is not banned
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /unstable/admin/clusters:
    get:
      operationId: adminListClusters
      summary: List clusters as admin
      description: Lists the registered clusters with the number of teams assigned to each. Never returns a cluster's token. The local cluster is not a registered cluster and is not listed.
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      parameters:
        - name: limit
          in: query
          required: false
          description: Maximum number of clusters to return
          schema:
            type: integer
            format: int32
            minimum: 1
            maximum: 100
            default: 50
        - name: offset
          in: query
          required: false
          description: Number of matching clusters to skip
          schema:
            type: integer
            format: int32
            minimum: 0
            default: 0
        - name: search
          in: query
          required: false
          description: Case-insensitive substring match on the cluster name or endpoint
          schema:
            type: string
        - name: sortBy
          in: query
          required: false
          description: Column to order by
          schema:
            type: string
            enum:
              - endpoint
              - name
              - teamCount
            default: endpoint
        - name: sortOrder
          in: query
          required: false
          schema:
            type: string
            enum:
              - asc
              - desc
            default: asc
            x-enum-varnames:
              - AdminListClustersSortOrderAsc
              - AdminListClustersSortOrderDesc
      responses:
        "200":
          description: The page of matching clusters and the number of all matching clusters
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ClusterListResponse"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "500":
          $ref: "#/components/responses/500"
    post:
      operationId: adminCreateCluster
      summary: Create a cluster as admin
      description: Creates a cluster whose configuration cannot be modified through this route. A new cluster starts with deletion protection turned on. Creating a cluster again with the same `cluster_id` and an identical configuration answers 201 with the stored cluster, whose deletionProtection is whatever is stored; a different configuration, or an auth organization another cluster uses, returns 409 with error_code cluster_registration_conflict. An invalid request returns 400 with error_code cluster_registration_invalid.
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AdminClusterCreateRequest"
      responses:
        "201":
          description: Cluster created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ClusterDetail"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "409":
          $ref: "#/components/responses/409"
        "500":
          $ref: "#/components/responses/500"

  /unstable/admin/clusters/{clusterID}:
    parameters:
      - $ref: "#/components/parameters/clusterID"
    get:
      operationId: adminGetCluster
      summary: Cluster as admin
      description: Returns a cluster with the first page of its assigned teams, the number of teams assigned to it and the number of live templates on it. Never returns the cluster's token.
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      parameters:
        - name: teamsLimit
          in: query
          required: false
          description: Page size for the embedded teams page
          schema:
            type: integer
            format: int32
            minimum: 1
            maximum: 100
            default: 50
        - name: teamsOffset
          in: query
          required: false
          description: Offset for the embedded teams page
          schema:
            type: integer
            format: int32
            minimum: 0
            default: 0
      responses:
        "200":
          description: The cluster
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ClusterDetailWithTeams"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "500":
          $ref: "#/components/responses/500"
    patch:
      operationId: adminUpdateCluster
      summary: Update a cluster as admin
      description: >-
        Writes only the properties present in the body. `endpoint` and
        `endpointTls` change where orchestration traffic for every team on the
        cluster goes, `sandboxProxyDomain` changes the public URL of every
        sandbox on it, and `authOrgId` changes how the cluster authenticates.
        A body with no property returns 400. Another cluster using the auth organization
        returns 409, and so does turning deletion protection on after the
        cluster's deletion is recorded. The token is rotated through
        `PUT /unstable/admin/clusters/{clusterID}/token`.
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ClusterUpdateRequest"
      responses:
        "200":
          description: The cluster as updated
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ClusterDetail"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "409":
          $ref: "#/components/responses/409"
        "500":
          $ref: "#/components/responses/500"
    delete:
      operationId: adminDeleteCluster
      summary: Delete a cluster and its environments as admin
      description: Deletes a cluster after all team assignments are detached. In the same transaction, soft-deletes every live template, snapshot template and paused sandbox snapshot on the cluster, releases their aliases, and releases all environment references while preserving environment and build history. A team assignment rejects the deletion and leaves the environments untouched, and so does deletion protection on the cluster. The local cluster's nil ID is rejected. Repeating a completed deletion succeeds.
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      responses:
        "204":
          description: Cluster deleted or already absent.
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "409":
          $ref: "#/components/responses/409"
        "500":
          $ref: "#/components/responses/500"

  /unstable/admin/clusters/{clusterID}/teams:
    parameters:
      - $ref: "#/components/parameters/clusterID"
    get:
      operationId: adminListClusterTeams
      summary: List a cluster's teams as admin
      description: Lists the teams assigned to the cluster.
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      parameters:
        - name: limit
          in: query
          required: false
          description: Maximum number of teams to return
          schema:
            type: integer
            format: int32
            minimum: 1
            maximum: 100
            default: 50
        - name: offset
          in: query
          required: false
          description: Number of teams to skip
          schema:
            type: integer
            format: int32
            minimum: 0
            default: 0
        - name: sortBy
          in: query
          required: false
          description: Column to order by
          schema:
            type: string
            enum:
              - createdAt
              - name
            default: createdAt
        - name: sortOrder
          in: query
          required: false
          schema:
            type: string
            enum:
              - asc
              - desc
            default: desc
            x-enum-varnames:
              - AdminListClusterTeamsSortOrderAsc
              - AdminListClusterTeamsSortOrderDesc
      responses:
        "200":
          description: The page of teams assigned to the cluster
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ClusterTeamListResponse"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "500":
          $ref: "#/components/responses/500"

  /unstable/admin/clusters/{clusterID}/token:
    parameters:
      - $ref: "#/components/parameters/clusterID"
    put:
      operationId: adminRotateClusterToken
      summary: Rotate a cluster's token as admin
      description: Replaces the token used to reach the cluster. The previous token stops working at once. No route returns a cluster's token.
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ClusterTokenRotateRequest"
      responses:
        "204":
          description: Token rotated.
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "500":
          $ref: "#/components/responses/500"

  /unstable/admin/templates/aliases:
    get:
      summary: Search template aliases as admin
      description: >
        Finds the templates whose ID equals `search`, or that own an alias equal to `search` in any
        namespace, with their owning team and all their aliases. Deleted templates are left out.
        Results are ordered by template ID; the next page's token is returned in `X-Next-Token`.
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      parameters:
        - name: search
          in: query
          required: true
          description: Exact template ID or alias
          schema:
            type: string
            minLength: 1
        - $ref: "#/components/parameters/paginationNextToken"
        - $ref: "#/components/parameters/paginationLimit"
      responses:
        "200":
          description: Successfully returned the matching templates
          headers:
            X-Next-Token:
              $ref: "#/components/headers/XNextToken"
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/AdminTemplateAliases"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "500":
          $ref: "#/components/responses/500"
    post:
      summary: Add a template alias without a namespace as admin
      description: >
        Adds an alias without a namespace to a template, so the template resolves by that name for
        every team. The alias follows the rules of template names (lowercase letters, digits, `-`
        and `_`) and cannot equal a template ID. Returns 404 when the template does not exist and
        409 when the alias is taken.
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AdminTemplateAliasCreateRequest"
      responses:
        "201":
          description: The alias was added
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminTemplateAlias"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "409":
          $ref: "#/components/responses/409"
        "500":
          $ref: "#/components/responses/500"

  /unstable/admin/templates/aliases/{aliasID}:
    delete:
      summary: Remove a template alias without a namespace as admin
      description: >
        Removes an alias without a namespace. A namespaced alias is not removed and answers 404.
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      parameters:
        - $ref: "#/components/parameters/aliasID"
      responses:
        "200":
          description: The alias was removed
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminTemplateAliasDeleted"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "500":
          $ref: "#/components/responses/500"

  /unstable/admin/templates/defaults:
    post:
      summary: Add a default template as admin
      description: >
        Makes a template one of the platform's default templates. Returns 404 when the template
        does not exist and 409 when it is already a default template.
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AdminDefaultTemplateCreateRequest"
      responses:
        "201":
          description: The template is now a default template
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminDefaultTemplate"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "409":
          $ref: "#/components/responses/409"
        "500":
          $ref: "#/components/responses/500"

  /unstable/admin/templates/defaults/{templateID}:
    patch:
      summary: Update a default template as admin
      description: Updates the description of a default template. Returns 404 when the template is not a default template.
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      parameters:
        - $ref: "#/components/parameters/templateID"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AdminDefaultTemplateUpdateRequest"
      responses:
        "200":
          description: The default template was updated
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminDefaultTemplate"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "500":
          $ref: "#/components/responses/500"
    delete:
      summary: Remove a default template as admin
      description: >
        Stops a template being one of the platform's default templates. The template itself is not
        changed. Returns 404 when the template is not a default template.
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      parameters:
        - $ref: "#/components/parameters/templateID"
      responses:
        "204":
          description: The template is no longer a default template
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "500":
          $ref: "#/components/responses/500"

  /unstable/admin/templates/lookup:
    get:
      summary: Look up a template as admin
      description: >
        Resolves `query` as, in order: a build ID (a UUID, matched to the template of the build's
        newest assignment, with no fallback), a template ID, or a template name (`namespace/alias`,
        or an alias without a namespace). Returns the template with its owning team and its newest
        builds. Deleted templates are not found.
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      parameters:
        - name: query
          in: query
          required: true
          description: Build ID, template ID, or template name
          schema:
            type: string
            minLength: 1
      responses:
        "200":
          description: Successfully resolved the template
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminTemplateLookup"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "500":
          $ref: "#/components/responses/500"

  /api-keys:
    get:
      summary: List team API keys
      x-api-group: list
      description: List all team API keys
      tags: [api-keys]
      security:
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      responses:
        "200":
          description: Successfully returned all team API keys
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/TeamAPIKey"
        "401":
          $ref: "#/components/responses/401"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"
    post:
      summary: Create team API key
      description: Create a new team API key
      tags: [api-keys]
      security:
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/NewTeamAPIKey"
      responses:
        "201":
          description: Team API key created successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreatedTeamAPIKey"
        "401":
          $ref: "#/components/responses/401"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /api-keys/{apiKeyID}:
    patch:
      summary: Update team API key
      description: Update a team API key
      tags: [api-keys]
      security:
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/apiKeyID"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateTeamAPIKey"
      responses:
        "200":
          description: Team API key updated successfully
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"
    delete:
      summary: Delete team API key
      description: Delete a team API key
      tags: [api-keys]
      security:
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/apiKeyID"
      responses:
        "204":
          description: Team API key deleted successfully
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /volumes:
    get:
      summary: List team volumes
      x-api-group: list
      description: List all team volumes
      tags: [volumes]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      responses:
        "200":
          description: Successfully listed all team volumes
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Volume"
        "401":
          $ref: "#/components/responses/401"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

    post:
      summary: Create team volume
      description: Create a new team volume
      tags: [volumes]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/NewVolume"
      responses:
        "201":
          description: Successfully created a new team volume
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/VolumeAndToken"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /volumes/{volumeID}:
    get:
      summary: Team volume
      description: Get team volume info
      tags: [volumes]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/volumeID"
      responses:
        "200":
          description: Successfully retrieved a team volume
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/VolumeAndToken"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

    delete:
      summary: Delete team volume
      description: Delete a team volume
      tags: [volumes]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/volumeID"
      responses:
        "204":
          description: Successfully deleted a team volume
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"

  /secrets:
    get:
      summary: List project secrets
      x-api-group: list
      description: List the project's secrets. No response carries a secret value.
      tags: [secrets]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/paginationNextToken"
        - $ref: "#/components/parameters/paginationLimit"
      responses:
        "200":
          description: Successfully listed the project's secrets
          headers:
            X-Next-Token:
              $ref: "#/components/headers/XNextToken"
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Secret"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "403":
          $ref: "#/components/responses/403"
        "404":
          $ref: "#/components/responses/404"
        "409":
          $ref: "#/components/responses/409"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"
        "502":
          $ref: "#/components/responses/502"
        "504":
          $ref: "#/components/responses/504"

    post:
      summary: Create a secret
      description: Create a secret by storing a runtime marker as its first version. The response carries metadata only.
      tags: [secrets]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/NewSecret"
      responses:
        "201":
          description: Successfully created the secret
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Secret"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "403":
          $ref: "#/components/responses/403"
        "404":
          $ref: "#/components/responses/404"
        "409":
          description: >-
            Secret name conflict or project live-secret limit reached. A quota
            response has error_code secret_limit_reached and, when reported by
            the backend, the effective cap in message.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                secretLimitReached:
                  value:
                    code: 409
                    message: Project has reached its limit of 50 live secrets
                    error_code: secret_limit_reached
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"
        "502":
          $ref: "#/components/responses/502"
        "504":
          $ref: "#/components/responses/504"

  /secrets/{secretID}:
    get:
      summary: Get a secret
      description: Get one secret's metadata, selected by identifier or name.
      tags: [secrets]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/secretID"
      responses:
        "200":
          description: Successfully retrieved the secret
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Secret"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "403":
          $ref: "#/components/responses/403"
        "404":
          $ref: "#/components/responses/404"
        "409":
          $ref: "#/components/responses/409"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"
        "502":
          $ref: "#/components/responses/502"
        "504":
          $ref: "#/components/responses/504"

    post:
      summary: Update a secret
      description: Replace the secret's stored marker by appending a new version. The response carries metadata only.
      tags: [secrets]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/secretID"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SecretUpdate"
      responses:
        "200":
          description: Successfully updated the secret
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Secret"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "403":
          $ref: "#/components/responses/403"
        "404":
          $ref: "#/components/responses/404"
        "409":
          $ref: "#/components/responses/409"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"
        "502":
          $ref: "#/components/responses/502"
        "504":
          $ref: "#/components/responses/504"

    delete:
      summary: Delete a secret
      description: Revoke the secret and schedule its versions for cleanup.
      tags: [secrets]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/secretID"
      responses:
        "204":
          description: Successfully deleted the secret
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "403":
          $ref: "#/components/responses/403"
        "404":
          $ref: "#/components/responses/404"
        "409":
          $ref: "#/components/responses/409"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"
        "502":
          $ref: "#/components/responses/502"
        "504":
          $ref: "#/components/responses/504"

  /clusters/{clusterID}/rigs:
    get:
      summary: List rigs of a cluster
      description: >
        List the orchestrator node pools ("rigs") of a cluster with a snapshot
        of their scaling groups. Forwarded to the cluster's edge service; a
        cluster with no rig management configured returns an empty list, and
        the local cluster answers 501.
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      parameters:
        - $ref: "#/components/parameters/clusterID"
      responses:
        "200":
          description: Successfully returned the rigs of the cluster
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Rig"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"
        "501":
          $ref: "#/components/responses/501"

  /clusters/{clusterID}/rigs/{rigID}/capacity:
    put:
      summary: Set the capacity of a rig
      description: >
        Set the desired instance count on the rig's scaling group. The value is
        passed to the cloud provider unchanged; violations of the group's bounds
        or conflicting concurrent operations surface as errors.
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      parameters:
        - $ref: "#/components/parameters/clusterID"
        - $ref: "#/components/parameters/rigID"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/RigCapacityChange"
      responses:
        "202":
          description: Capacity change accepted
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "409":
          $ref: "#/components/responses/409"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"
        "501":
          $ref: "#/components/responses/501"

  /clusters/{clusterID}/rigs/instances/{instanceID}:
    delete:
      summary: Terminate an instance of a rig
      description: >
        Terminate an instance in whichever rig's scaling group it belongs to.
        The caller chooses whether the rig shrinks or the instance is replaced.
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      parameters:
        - $ref: "#/components/parameters/clusterID"
        - name: instanceID
          in: path
          required: true
          schema:
            type: string
          description: Provider instance ID
        - name: decrementDesired
          in: query
          required: true
          schema:
            type: boolean
          description: >
            When true, desired capacity is decremented (rig shrinks);
            when false, the scaling group launches a replacement instance
      responses:
        "202":
          description: Instance termination accepted
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "409":
          $ref: "#/components/responses/409"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"
        "501":
          $ref: "#/components/responses/501"

  /clusters/{clusterID}/rigs/{rigID}/instances:
    get:
      summary: List the instances attached to a rig
      description: >
        List the instances attached to the rig's scaling group with their
        creation time and transition state, sorted by instance ID.
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      parameters:
        - $ref: "#/components/parameters/clusterID"
        - $ref: "#/components/parameters/rigID"
      responses:
        "200":
          description: Successfully returned the instances of the rig
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/RigInstance"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"
        "501":
          $ref: "#/components/responses/501"

  /clusters/{clusterID}/rigs/{rigID}/errors:
    get:
      summary: List recent scaling errors of a rig
      description: >
        List recent scaling errors on the rig's scaling group (e.g. failed
        instance creations due to resource exhaustion), newest first.
      tags: [admin]
      security:
        - AdminApiKeyAuth: []
        - AdminJWTAuth: []
      parameters:
        - $ref: "#/components/parameters/clusterID"
        - $ref: "#/components/parameters/rigID"
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            format: int32
            minimum: 1
            maximum: 50
            default: 20
          description: Maximum number of errors to return
      responses:
        "200":
          description: Successfully returned the scaling errors of the rig
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/RigError"
        "400":
          $ref: "#/components/responses/400"
        "401":
          $ref: "#/components/responses/401"
        "404":
          $ref: "#/components/responses/404"
        "429":
          $ref: "#/components/responses/429"
        "500":
          $ref: "#/components/responses/500"
        "501":
          $ref: "#/components/responses/501"

  /events/sandboxes/{sandboxID}:
    get:
      description: Get sandbox events
      tags: [events]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/sandboxID"
        - name: offset
          in: query
          required: false
          schema:
            type: integer
            format: int32
            minimum: 0
            default: 0
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            format: int32
            minimum: 1
            maximum: 100
            default: 10
        - name: orderAsc
          in: query
          required: false
          schema:
            type: boolean
            default: false
        - name: types
          in: query
          required: false
          style: form
          explode: true
          schema:
            type: array
            items:
              type: string
          description: Filter events to the provided event types
      responses:
        "200":
          description: Successfully returned the sandbox events
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/SandboxEvent"
        "400":
          $ref: "#/components/responses/400"
        "404":
          $ref: "#/components/responses/404"
        "401":
          $ref: "#/components/responses/401"
        "500":
          $ref: "#/components/responses/500"

  /events/sandboxes:
    get:
      description: Get all sandbox events for the team associated with the API key
      tags: [events]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - name: offset
          in: query
          required: false
          schema:
            type: integer
            format: int32
            minimum: 0
            default: 0
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            format: int32
            minimum: 1
            maximum: 100
            default: 10
        - name: orderAsc
          in: query
          required: false
          schema:
            type: boolean
            default: false
        - name: types
          in: query
          required: false
          style: form
          explode: true
          schema:
            type: array
            items:
              type: string
          description: Filter events to the provided event types
      responses:
        "200":
          description: Successfully returned the sandbox events
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/SandboxEvent"
        "400":
          $ref: "#/components/responses/400"
        "404":
          $ref: "#/components/responses/404"
        "401":
          $ref: "#/components/responses/401"
        "500":
          $ref: "#/components/responses/500"

  /events/webhooks:
    post:
      description: Register events webhook.
      tags: [webhooks]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/WebhookCreate"
      responses:
        "201":
          description: Successfully created webhook.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebhookCreation"
        "400":
          $ref: "#/components/responses/400"
        "404":
          $ref: "#/components/responses/404"
        "401":
          $ref: "#/components/responses/401"
        "500":
          $ref: "#/components/responses/500"
    get:
      description: List registered webhooks.
      tags: [webhooks]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      responses:
        "200":
          description: List of registered webhooks.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/WebhookDetail"
        "404":
          $ref: "#/components/responses/404"
        "401":
          $ref: "#/components/responses/401"
        "500":
          $ref: "#/components/responses/500"

  /events/webhooks/{webhookID}:
    get:
      description: Get a registered webhook.
      tags: [webhooks]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/webhookID"
      responses:
        "200":
          description: Successfully returned the webhook configuration.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebhookDetail"
        "404":
          $ref: "#/components/responses/404"
        "401":
          $ref: "#/components/responses/401"
        "500":
          $ref: "#/components/responses/500"

    patch:
      description: Update a registered webhook configuration.
      tags: [webhooks]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/webhookID"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/WebhookConfiguration"
      responses:
        "200":
          description: Successfully updated webhook.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebhookDetail"
        "400":
          $ref: "#/components/responses/400"
        "404":
          $ref: "#/components/responses/404"
        "401":
          $ref: "#/components/responses/401"
        "500":
          $ref: "#/components/responses/500"

    delete:
      description: Delete a registered webhook.
      tags: [webhooks]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/webhookID"
      responses:
        "200":
          description: Successfully deleted webhook.
        "404":
          $ref: "#/components/responses/404"
        "401":
          $ref: "#/components/responses/401"
        "500":
          $ref: "#/components/responses/500"

  /events/webhooks/{webhookID}/deliveries:
    get:
      description: List webhook delivery attempts.
      tags: [webhooks]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/webhookID"
        - name: cursor
          in: query
          required: false
          schema:
            type: string
          description: Opaque cursor from the previous response's nextCursor field.
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            format: int32
            minimum: 1
            maximum: 100
            default: 25
        - name: orderAsc
          in: query
          required: false
          schema:
            type: boolean
            default: false
        - name: start
          in: query
          required: false
          schema:
            type: string
            format: date-time
          description: Include deliveries at or after this timestamp.
        - name: end
          in: query
          required: false
          schema:
            type: string
            format: date-time
          description: Include deliveries before this timestamp.
        - name: deliveryStatus
          in: query
          required: false
          style: form
          explode: false
          schema:
            type: array
            items:
              type: string
              enum: [success, failed]
          description: Filter deliveries by delivery status
        - name: eventType
          in: query
          required: false
          style: form
          explode: false
          schema:
            type: array
            items:
              type: string
          description: Filter deliveries by event type
      responses:
        "200":
          description: List of webhook delivery attempts grouped by event.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebhookDeliveriesListPayload"
        "400":
          $ref: "#/components/responses/400"
        "404":
          $ref: "#/components/responses/404"
        "401":
          $ref: "#/components/responses/401"
        "500":
          $ref: "#/components/responses/500"

  /events/webhooks/{webhookID}/stats:
    get:
      description: Get webhook delivery aggregate stats.
      tags: [webhooks]
      security:
        - ApiKeyAuth: []
        - AuthProviderBearerAuth: []
          AuthProviderTeamAuth: []
        - AdminApiKeyAuth: []
          AdminTeamAuth: []
        - AdminJWTAuth: []
          AdminTeamAuth: []
      parameters:
        - $ref: "#/components/parameters/webhookID"
        - name: start
          in: query
          required: false
          schema:
            type: string
            format: date-time
          description: Inclusive stats range start. Defaults to 24 hours ago.
        - name: end
          in: query
          required: false
          schema:
            type: string
            format: date-time
          description: Exclusive stats range end. Defaults to now.
      responses:
        "200":
          description: Webhook delivery stats.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebhookDeliveryStats"
        "404":
          $ref: "#/components/responses/404"
        "401":
          $ref: "#/components/responses/401"
        "500":
          $ref: "#/components/responses/500"