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

# Publish files in one request

> Publishes a whole release in one body: a tar, gzip-compressed tar or zip archive, or one HTML page served as index.html. Archives may hold only regular files and directories; an entry whose mode has any execute bit is executable. Without computer, creates a computer that serves the files with no VM; with computer, makes them that computer's new live release. A cool.json at the release root configures serving: spa, and run with an optional port, a shortcut for starting a server by hand: the computer gets its VM if it has none, the files are written to /home/runtime/app and served from there, and run starts there as the managed service, answering every path no file matches; or functions, the path of one bundled .js or .mjs ES module of at most 1 MiB that answers every /api/ request, with secrets, the slug of an account secret set whose keys it gets as env (a key delivered by proxy only once the computer has its VM, as the placeholder runtime-proxy, its value set as Authorization by the computer's egress proxy on the https requests its rule matches); a release cannot declare both functions and run. The body is validated, cool.json included, before anything is created, and a computer this request created is deleted again if a later step fails. Limits: 20,000 files, 25 MiB per file and 1 GiB in total; a release that declares run holds at most 10,000 files and 512 MiB. Send an Idempotency-Key: a retry of the same request with the same key returns the original response or finishes that release, and never publishes again. Without any credential, it publishes without an account: files only (a release that declares run or functions answers 403 sign_in_required_for_servers), at most 1,000 files, 10 MiB per file and 100 MiB in total, and at most 20 such publishes per client IP per hour and 10 unclaimed computers per client IP, 50 per IPv6 /48, at once (429 anonymous_publish_rate_exceeded or unclaimed_computer_limit). The created computer is public and is deleted 24 hours later unless someone claims it; the response adds claim_key, returned only once, claim_url, whose fragment carries the computer ID and the key, and expires_at. To publish to that computer again before then, send ?computer=<computer ID> with Authorization: Claim <claim_key>; that does not extend expires_at. A signed-in user claims the computer with POST /api/computers/{id}/claim. A publish without an account takes no Idempotency-Key (400 idempotency_key_requires_account), because its response carries the claim key.



## OpenAPI

````yaml https://www.cool.computer/openapi.json post /api/publish
openapi: 3.1.0
info:
  title: Cool Computers API
  version: 1.0.0
  description: >-
    Create and operate reachable Linux computers. Each computer keeps a stable
    name.cool.computer address, persistent files, and agent-ready command
    execution. REST requests use UTC-aligned one-minute limits: 600 requests per
    account identified by a recognized valid account bearer credential, a
    separate 600-request budget per computer-scoped credential, or 60 requests
    per source IP otherwise. Read-only GETs answered from API state spend a
    separate read budget reported as account-read or computer-read, so status
    polling cannot exhaust the budget that protects work and mutations. To bound
    authentication-provider traffic, at most 60 first-seen bearer values are
    checked per source IP in a minute; recognized valid credentials use their
    account or computer policy. Successful bearer authentication is reused for
    at most five seconds; transient provider failures are not cached. Non-exempt
    API responses include the structured RateLimit and RateLimit-Policy fields;
    request admission 429 responses use code api_request_rate_exceeded and also
    include Retry-After. Health, OpenAPI, webhooks, callbacks, SSE, and
    WebSocket endpoints are exempt from the REST request budget. Authenticated
    SSE connection attempts remain subject to the authentication safeguards and
    can receive the same typed 429 response.
servers:
  - url: https://api.cool.computer
    description: Canonical API origin
security: []
tags:
  - name: Authentication
    description: Obtain and manage bearer credentials.
  - name: Billing
    description: Inspect and manage the account's no-card trial or Pro plan.
  - name: Computers
    description: Create, inspect, and delete resident computers.
  - name: Execution
    description: Run commands on a computer.
  - name: Files
    description: Read and change a computer's persistent files.
  - name: Publishing
    description: >-
      Publish files to a computer's URL as immutable releases, with no VM. To
      show something, publish the files; to run something, use the computer
      (exec, terminal, services), which gets Linux on first use.
  - name: Services
    description: >-
      Manage processes and select the HTTP port exposed at a computer's stable
      address.
  - name: Email
    description: Read and send mail through a computer's inbox.
  - name: Network
    description: Control a computer's public visibility and outbound network policy.
  - name: Sharing
    description: Invite people to use a computer without granting owner controls.
  - name: Public
    description: Unauthenticated discovery endpoints.
externalDocs:
  description: Cool Computers agent registration guide
  url: https://www.cool.computer/auth.md
paths:
  /api/publish:
    post:
      tags:
        - Publishing
      summary: Publish files in one request
      description: >-
        Publishes a whole release in one body: a tar, gzip-compressed tar or zip
        archive, or one HTML page served as index.html. Archives may hold only
        regular files and directories; an entry whose mode has any execute bit
        is executable. Without computer, creates a computer that serves the
        files with no VM; with computer, makes them that computer's new live
        release. A cool.json at the release root configures serving: spa, and
        run with an optional port, a shortcut for starting a server by hand: the
        computer gets its VM if it has none, the files are written to
        /home/runtime/app and served from there, and run starts there as the
        managed service, answering every path no file matches; or functions, the
        path of one bundled .js or .mjs ES module of at most 1 MiB that answers
        every /api/ request, with secrets, the slug of an account secret set
        whose keys it gets as env (a key delivered by proxy only once the
        computer has its VM, as the placeholder runtime-proxy, its value set as
        Authorization by the computer's egress proxy on the https requests its
        rule matches); a release cannot declare both functions and run. The body
        is validated, cool.json included, before anything is created, and a
        computer this request created is deleted again if a later step fails.
        Limits: 20,000 files, 25 MiB per file and 1 GiB in total; a release that
        declares run holds at most 10,000 files and 512 MiB. Send an
        Idempotency-Key: a retry of the same request with the same key returns
        the original response or finishes that release, and never publishes
        again. Without any credential, it publishes without an account: files
        only (a release that declares run or functions answers 403
        sign_in_required_for_servers), at most 1,000 files, 10 MiB per file and
        100 MiB in total, and at most 20 such publishes per client IP per hour
        and 10 unclaimed computers per client IP, 50 per IPv6 /48, at once (429
        anonymous_publish_rate_exceeded or unclaimed_computer_limit). The
        created computer is public and is deleted 24 hours later unless someone
        claims it; the response adds claim_key, returned only once, claim_url,
        whose fragment carries the computer ID and the key, and expires_at. To
        publish to that computer again before then, send ?computer=<computer ID>
        with Authorization: Claim <claim_key>; that does not extend expires_at.
        A signed-in user claims the computer with POST
        /api/computers/{id}/claim. A publish without an account takes no
        Idempotency-Key (400 idempotency_key_requires_account), because its
        response carries the claim key.
      operationId: publishRelease
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
        - name: computer
          in: query
          required: false
          description: >-
            Existing computer ID or slug to publish to. Omit it to create a
            computer. Without an account, only the unclaimed computer the Claim
            key belongs to.
          schema:
            type: string
            minLength: 1
        - name: name
          in: query
          required: false
          description: >-
            Slug for a created computer. Unless the release declares run, it
            must leave room for release hostnames up to r9999--<name>, so 56
            characters at most; slug_too_long_for_releases otherwise.
          schema:
            type: string
            pattern: ^[a-z0-9]{1,63}$
      requestBody:
        required: true
        content:
          application/x-tar:
            schema:
              type: string
              format: binary
          application/gzip:
            schema:
              type: string
              format: binary
          application/zip:
            schema:
              type: string
              format: binary
          text/html:
            schema:
              type: string
      responses:
        '201':
          headers:
            RateLimit:
              $ref: '#/components/headers/RateLimit'
            RateLimit-Policy:
              $ref: '#/components/headers/RateLimit-Policy'
          description: >-
            The computer and the receipt of its new live release. A publish
            without an account answers AnonymousPublishResult.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/PublishResult'
                  - $ref: '#/components/schemas/AnonymousPublishResult'
        '400':
          headers:
            RateLimit:
              $ref: '#/components/headers/RateLimit'
            RateLimit-Policy:
              $ref: '#/components/headers/RateLimit-Policy'
          description: >-
            Bad Request. `invalid_release` names the rejected path, limit or
            cool.json field. `idempotency_key_requires_account`: a publish
            without an account takes no Idempotency-Key. `invalid_request`: a
            Claim key needs ?computer=.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          headers:
            RateLimit:
              $ref: '#/components/headers/RateLimit'
            RateLimit-Policy:
              $ref: '#/components/headers/RateLimit-Policy'
          description: >-
            Unauthorized. ?computer= without an account credential needs
            Authorization: Claim <claim_key>.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '402':
          headers:
            RateLimit:
              $ref: '#/components/headers/RateLimit'
            RateLimit-Policy:
              $ref: '#/components/headers/RateLimit-Policy'
          description: >-
            Payment Required. A release that declares run needs a VM, and the
            trial expired or Pro is inactive; inspect the problem code and
            resolution.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '403':
          headers:
            RateLimit:
              $ref: '#/components/headers/RateLimit'
            RateLimit-Policy:
              $ref: '#/components/headers/RateLimit-Policy'
          description: >-
            Forbidden. `sign_in_required_for_servers`: a publish without an
            account cannot declare run or functions, because both run code.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '404':
          headers:
            RateLimit:
              $ref: '#/components/headers/RateLimit'
            RateLimit-Policy:
              $ref: '#/components/headers/RateLimit-Policy'
          description: >-
            Not Found. The computer does not exist or is not owned by this
            account, or the claim key is not this unclaimed computer's.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          headers:
            RateLimit:
              $ref: '#/components/headers/RateLimit'
            RateLimit-Policy:
              $ref: '#/components/headers/RateLimit-Policy'
          description: >-
            Conflict. `publish_in_progress`: another publish of the computer is
            running. `slug_taken`: pick another name. `idempotency_in_progress`:
            wait for Retry-After seconds, then retry the identical request with
            the same key. `idempotency_key_conflict`: the key was used for a
            different request. `claim_unavailable`: the unclaimed computer
            expired.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '413':
          headers:
            RateLimit:
              $ref: '#/components/headers/RateLimit'
            RateLimit-Policy:
              $ref: '#/components/headers/RateLimit-Policy'
          description: Payload Too Large. `release_too_large`.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '415':
          headers:
            RateLimit:
              $ref: '#/components/headers/RateLimit'
            RateLimit-Policy:
              $ref: '#/components/headers/RateLimit-Policy'
          description: >-
            Unsupported Media Type. `unsupported_publish_body`: send
            application/x-tar, application/gzip, application/zip or text/html.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          headers:
            RateLimit:
              $ref: '#/components/headers/RateLimit'
            RateLimit-Policy:
              $ref: '#/components/headers/RateLimit-Policy'
          description: >-
            Unprocessable Content. `slug_too_long_for_releases`,
            `content_size_conflict`, `functions_and_run`: cool.json declares
            both, `secret_set_not_found`: cool.json secrets names a set the
            account does not have, `secret_set_too_large`: functions on the edge
            get at most 64 env keys of at most 5,000 bytes, or
            `secret_file_in_public_release`: a release without run is served
            publicly and cannot include .env or .env.* files.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          headers:
            RateLimit:
              $ref: '#/components/headers/RateLimit'
            RateLimit-Policy:
              $ref: '#/components/headers/RateLimit-Policy'
            Retry-After:
              $ref: '#/components/headers/Retry-After'
          description: >-
            Too Many Requests. If the problem code is api_request_rate_exceeded,
            wait for Retry-After seconds; other problem codes describe a
            separate limit. computer_quota_exceeded means the account's artifact
            or VM quota is full. Without an account,
            anonymous_publish_rate_exceeded means this client IP published 20
            times in the last hour and unclaimed_computer_limit that it holds 10
            unclaimed computers, or its IPv6 /48 holds 50.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '500':
          headers:
            RateLimit:
              $ref: '#/components/headers/RateLimit'
            RateLimit-Policy:
              $ref: '#/components/headers/RateLimit-Policy'
          description: Internal Server Error.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '502':
          headers:
            RateLimit:
              $ref: '#/components/headers/RateLimit'
            RateLimit-Policy:
              $ref: '#/components/headers/RateLimit-Policy'
          description: >-
            Bad Gateway. `artifact_deploy_failed`: finalize again.
            `linux_create_failed`: giving the computer its VM failed and it
            stays a published site; `server_start_failed`: writing the files to
            the computer's VM, or starting or checking the server, failed;
            `context.step` names the failing step.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '503':
          headers:
            RateLimit:
              $ref: '#/components/headers/RateLimit'
            RateLimit-Policy:
              $ref: '#/components/headers/RateLimit-Policy'
          description: >-
            Service Unavailable. `artifacts_unavailable` means publishing is not
            configured on this server; `host_capacity_full` or
            `host_capacity_unavailable` means a release that declares run cannot
            get a VM now.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        default:
          headers:
            RateLimit:
              $ref: '#/components/headers/RateLimit'
            RateLimit-Policy:
              $ref: '#/components/headers/RateLimit-Policy'
          description: >-
            A machine-readable API error with a stable code and recovery
            instruction.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
      security:
        - bearerAuth: []
        - claimKeyAuth: []
        - {}
components:
  parameters:
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: false
      description: >-
        A caller-generated key for safely retrying this side effect. The server
        retains the key and response for 24 hours. Reusing it with the same
        request replays the original response; reusing it with different input
        returns 409.
      schema:
        type: string
        minLength: 1
        maxLength: 128
        pattern: ^[!-~]+$
        example: req_01J6M6Y9TF9Q9QF6M1ZP8K4R2A
  headers:
    RateLimit:
      description: >-
        The applied policy name, requests remaining after this request, and
        whole seconds until the current UTC-aligned window resets.
      schema:
        type: string
        pattern: >-
          ^"(account|account-read|computer|computer-read|source)";r=[0-9]+;t=([1-9]|[1-5][0-9]|60)$
        examples:
          - '"account";r=599;t=42'
          - '"computer-read";r=598;t=42'
    RateLimit-Policy:
      description: >-
        The selected policy name, quota, and window in seconds. Valid account
        credentials use account or account-read with q=600, computer credentials
        use computer or computer-read with q=600, and unauthenticated or
        unrecognized requests use source with q=60 for their source IP.
      schema:
        type: string
        pattern: >-
          ^("(account|account-read|computer|computer-read)";q=600|"source";q=60);w=60$
        examples:
          - '"account";q=600;w=60'
          - '"computer-read";q=600;w=60'
    Retry-After:
      description: >-
        Whole seconds to wait after an api_request_rate_exceeded response before
        retrying. Other 429 problem codes describe separate resource or provider
        limits and do not inherit this retry value.
      schema:
        type: integer
        minimum: 1
        maximum: 60
        examples:
          - 42
  schemas:
    PublishResult:
      type: object
      additionalProperties: false
      required:
        - computer
        - release
        - url
        - vm
        - next
      properties:
        computer:
          $ref: '#/components/schemas/Computer'
        release:
          $ref: '#/components/schemas/Release'
        url:
          type: string
          format: uri
          description: The computer's URL, which serves the live release.
        release_url:
          type: string
          format: uri
          description: >-
            This release's own hostname r<n>--<slug>. Absent once the computer's
            VM serves its URL.
        vm:
          type: boolean
          description: >-
            Whether the computer's VM serves its URL, because a server on it
            answered.
        next:
          $ref: '#/components/schemas/ReleaseNext'
    AnonymousPublishResult:
      type: object
      additionalProperties: false
      required:
        - computer
        - release
        - url
        - vm
        - next
        - expires_at
      properties:
        computer:
          $ref: '#/components/schemas/Computer'
        release:
          $ref: '#/components/schemas/Release'
        url:
          type: string
          format: uri
          description: The computer's URL, which serves the live release.
        release_url:
          type: string
          format: uri
          description: This release's own hostname r<n>--<slug>.
        vm:
          type: boolean
          description: 'Always false: a publish without an account serves files only.'
        next:
          $ref: '#/components/schemas/ReleaseNext'
        claim_key:
          type: string
          description: >-
            Authorizes publishing to this computer again (Authorization: Claim
            <claim_key>) and claiming it. Returned only by the publish that
            created the computer, and never again.
        claim_url:
          type: string
          format: uri
          description: >-
            https://www.<domain>/claim#<computer ID>.<claim_key>, for a
            signed-in user to claim the computer. Returned with claim_key.
        expires_at:
          type: string
          format: date-time
          description: >-
            When the computer is deleted unless someone claims it: 24 hours
            after it was created. Publishing again does not extend it.
    Problem:
      type: object
      additionalProperties: false
      required:
        - type
        - title
        - status
        - code
        - detail
        - resolution
      properties:
        type:
          type: string
          format: uri
        title:
          type: string
        status:
          type: integer
          minimum: 400
          maximum: 599
        code:
          type: string
          pattern: ^[a-z0-9_]+$
        detail:
          type: string
        resolution:
          type: string
        context:
          type: object
          additionalProperties: true
    Computer:
      type: object
      additionalProperties: false
      required:
        - id
        - hostname
        - slug
        - ip
        - status
        - visibility
        - access
        - site
        - network_policy
        - created_at
      properties:
        id:
          type: string
        hostname:
          type: string
        slug:
          type: string
        ip:
          type: string
        status:
          type: string
        public_url:
          type: string
          format: uri
        email_address:
          type: string
          format: email
        visibility:
          type: string
          enum:
            - private
            - public
        access:
          type: string
          enum:
            - owner
            - can_use
        site:
          type: boolean
          description: >-
            The URL serves the computer's published files: from the edge, or
            from its VM's built-in site server, which answers what no file
            matches with the program on the exposed port.
        network_policy:
          $ref: '#/components/schemas/NetworkPolicy'
        created_at:
          type: string
          format: date-time
        auto_delete_at:
          type:
            - string
            - 'null'
          format: date-time
        creation_mode:
          type: string
    Release:
      type: object
      additionalProperties: false
      required:
        - number
        - state
        - live
        - files
        - bytes
        - created_at
      properties:
        number:
          type: integer
          minimum: 1
        state:
          type: string
          enum:
            - uploading
            - ready
            - failed
        live:
          type: boolean
        files:
          type: integer
          minimum: 0
        bytes:
          type: integer
          format: int64
          minimum: 0
        created_at:
          type: string
          format: date-time
        ready_at:
          type: string
          format: date-time
    ReleaseNext:
      type: object
      additionalProperties: false
      required:
        - action
      description: 'What to do next: upload the missing hashes, finalize, or nothing (done).'
      properties:
        action:
          type: string
          enum:
            - upload
            - finalize
            - done
        upload:
          $ref: '#/components/schemas/ReleaseLink'
        finalize:
          $ref: '#/components/schemas/ReleaseLink'
    NetworkPolicy:
      type: object
      description: >-
        Outbound access policy. open allows public destinations, none blocks
        outbound access, and allowlist permits only the named public hosts.
        Private and reserved addresses remain blocked.
      additionalProperties: false
      required:
        - mode
      if:
        properties:
          mode:
            const: allowlist
        required:
          - mode
      then:
        required:
          - allowed_hosts
        properties:
          allowed_hosts:
            minItems: 1
      else:
        properties:
          allowed_hosts:
            maxItems: 0
      properties:
        mode:
          type: string
          enum:
            - open
            - none
            - allowlist
        allowed_hosts:
          type: array
          description: >-
            Required and non-empty only when mode is allowlist. Each value is a
            hostname, public IP, or leading wildcard such as *.example.com,
            without a scheme, port, path, or CIDR.
          maxItems: 100
          items:
            type: string
            example: api.example.com
    ReleaseLink:
      type: object
      additionalProperties: false
      required:
        - method
        - href
      properties:
        method:
          type: string
          enum:
            - PUT
            - POST
        href:
          type: string
          description: API path; {sha256} stands for each missing hash.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: WorkOS user or agent access token, or Cool Computers API key
      description: >-
        A Cool Computers API key, user access token, or claimed agent access
        token in the Authorization header. Follow
        https://www.cool.computer/auth.md for agent registration and
        https://www.cool.computer/authentication.md for direct user credentials.
    claimKeyAuth:
      type: apiKey
      in: header
      name: Authorization
      description: >-
        Claim <claim_key>: the claim key a publish without an account returned.
        It authorizes further publishes to that computer until the computer is
        claimed or expires, and nothing else.

````