---
title: "Publish files or capture a website and get a live URL"
method: POST
path: "/v1/publish"
tags: ["Publishing"]
---

# Publish files or capture a website and get a live URL

`POST /v1/publish`

## Request

- Base URL: `https://api.spacefast.com`
- URL: `https://api.spacefast.com/v1/publish`
- Auth: one of:
  - none
  - HTTP bearer
  - HTTP bearer
  - OAuth 2 (authorization code, authorization URL `https://api.spacefast.com/v1/auth/oauth2/authorize`, token URL `https://api.spacefast.com/v1/auth/oauth2/token`; client credentials, token URL `https://api.spacefast.com/v1/auth/oauth2/token`, scopes: `spaces:publish`)
  - OAuth 2 (authorization code, authorization URL `https://api.spacefast.com/v1/auth/oauth2/authorize`, token URL `https://api.spacefast.com/v1/auth/oauth2/token`; client credentials, token URL `https://api.spacefast.com/v1/auth/oauth2/token`, scopes: `publish:write`)

Publish files, a zip/tar archive, or a public HTTPS website and get a Spacefast URL. Pass sourceUrl to capture and publish a website; URL publishing must be enabled for the caller and is mutually exclusive with files, deletions, and archive uploads. URL publishes and archives that need a build return a durable Build receipt with next.action=poll; follow links.status until publication completes. The Build's capture field reports URL capture progress and quality evidence; an unmeasured visual comparison is not a passing comparison. Use a stable Idempotency-Key when retrying the same request. Already-built files and static website archives publish directly and wait for finalization by default; pass async=1 to return an operation link to poll instead. For buildable source on a Spacefast-managed Space, the receipt's git block provides the repository remote and the Build's input.commit identifies the source commit; later git pushes continue that repository history. The Open link provides reusable access; anonymous Spaces also receive a Claim link for ownership transfer. New Spaces are Private by default. Pass spaceId to update an existing Space; otherwise a new Space is created.

## Query parameters

- `async` '1' | 'true' | '0' | 'false'

## Headers

- `Idempotency-Key` string
- `X-Spacefast-Idempotency-Principal` string

## Request body

- object
  - `spaceId` string
  - `teamId` string, nullable
  - `principal` object
    - `type` 'team' | 'external', required: Owning principal kind.
    - `id` string, required: Tenant-local principal id: a team id or an integrator external customer id.
  - `sourceUrl` string, uri: Capture a public HTTPS website as portable HTML; mutually exclusive with files.
  - `files` object[]: Desired file manifest for a declared publish session. `sha256` is optional: omitted local bytes receive path-addressed upload targets and are hashed by the runtime; declared hashes receive content-addressed targets and can reuse existing bytes. Clients upload returned targets, then finalize.
    - `path` string, required: Version-relative POSIX path. Canonicalized at intake to UTF-8 NFC, percent-decoded exactly once; max 1,024 bytes in canonical form.
    - `size` integer, required: File size in bytes.
    - `sha256` string: Optional SHA-256 content digest, 64 lowercase hex characters without the `sha256:` prefix. Omit it to let the runtime hash uploaded bytes; include it to upload by content address, with the digest verified as the bytes land.
    - `contentType` string: Optional content type for serving metadata.
    - `sourceUrl` string, uri: Optional HTTPS URL the runtime can fetch directly for this file instead of receiving bytes from the client.
  - `deletePaths` string[]: Explicit paths to remove when `publishMode` is additive. Omitted paths are retained. Only listed paths are deleted.
  - `immutableAssetPrefixes` string[]: Publisher-owned directory prefixes whose declared files are immutable generation assets. Snapshot publishes retain the matching files from the current generation for exactly one subsequent generation.
  - `source` object: Publish provenance recorded on the version; defaults to {kind: "direct_upload"}.
    - `kind` 'direct_upload' | 'cli' | 'dashboard' | 'api' | 'git' | 'import' | 'agent' | 'build' | 'variable_update' | 'config_update', required: How this version was produced.
    - `client` string: Publishing client attribution, for example `spacefast-cli/1.2.3`.
    - `branch` string: Git branch the publish came from.
    - `commit` string: Git commit SHA the publish came from.
    - `message` string: Plain-language description of the publish (the version changelog entry, commit message, or release note). This is THE spelling for the publish description; the version files-diff API is the fallback when none is given.
    - `dirty` boolean: Whether the working tree had uncommitted changes at publish time.
    - `metadata` object: Additional provenance (repository, CI run URL, workflow, actor, ...).
    - `git` object
      - `repository` string, nullable
      - `repositoryFullName` string, nullable
      - `repositoryUrl` string, nullable
      - `ref` string, nullable
      - `branch` string, nullable
      - `branchAliasUrl` string, nullable
      - `commit` string, nullable
      - `commitSha` string, nullable
      - `pullRequestNumber` number, nullable
  - `sourceMetadata` object: Additional control-plane-only provenance for build/deploy read models.
  - `buildLog` string: Bounded build transcript for deploys that ran a local build before publishing.
  - `publishMode` 'additive' | 'snapshot': How to interpret omitted paths in `files`: `additive` retains existing paths unless explicitly replaced; `snapshot` treats `files` as the complete desired manifest.
  - `email` string, email: Optional expiry-reminder address for anonymous publishes. The server stores it only until the space is claimed or expires, then deletes it. It is never logged.
  - `channel` 'live' | 'production', nullable: Omit for live publish, use production as an alias for live, or pass null to create a ready version without promotion.
  - `space` object
    - `slug` string
    - `title` string
    - `dataLocation` string: Data location for a new Space; "auto" lets placement decide.
  - `config` object: SpaceConfig overlay to store on the space.
    - `index` union: Directory index file; false disables index resolution.
      - string
      - false
    - `fallback` union: Fallback document. "/index.html" means SPA. Defaults to the nearest 404.html.
      - string
      - object
        - `path` string, required: Committed file served when no exact route matches.
        - `status` integer, required: Response status for the fallback.
    - `cleanUrls` boolean: Serve flat `<name>.html` files at their extensionless URL (`/about` serves `about.html`). Defaults to on, unless a 200-status SPA fallback is configured.
    - `listing` boolean: Enable automatic directory listings.
    - `meta` object: Listing, viewer, sharing, and browser icon metadata.
      - `title` string
      - `description` string
      - `image` string
      - `favicon` string
    - `superpowers` object: Platform-managed built-ins and custom JavaScript snippets.
      - `enabled` boolean: Master switch for platform-managed injections.
      - `disable_all_injection` boolean: When true, suppresses every platform-managed script/tag injection.
      - `googleAnalytics` object
        - `enabled` boolean
        - `measurementId` string
      - `googleTagManager` object
        - `enabled` boolean
        - `containerId` string
      - `javascriptTags` object[]
        - `id` string
        - `name` string
        - `enabled` boolean
        - `code` string, required
      - `tags` object
        - `inheritance` object
          - `inherited` boolean
          - `overrides` object[]
            - `tagId` string, required
            - `disabled` boolean
            - `reason` string, nullable
        - `requireReview` boolean: When true, integration changes must go through review before release.
    - `templates` string[]: Files that receive {{ vars.NAME }} substitution at finalize.
    - `theme` object: Visual tokens for every Spacefast-authored page.
      - `accent` string: Accent color for Spacefast-authored pages.
      - `background` string: Background color for Spacefast-authored pages.
      - `logo` string: Logo image (https URL or root-relative path) shown in the brand row.
      - `name` string: Display name shown in the brand row of Pages defaults.
      - `font` string: Font-family stack applied to Spacefast-authored pages.
      - `hideSpacefastBranding` boolean: Remove the Spacefast badge from default pages when the plan permits it.
    - `collab` object: Comments overlay delivery. `default` injects Spacefast's UI; `custom` injects only /__spacefast/collab.css for a self-built UI. Turning comments off lives in the Space's Comments settings, not here.
      - `ui` 'default' | 'custom'
    - `build` object: Default settings for remote repository builds.
      - `rootDirectory` string, nullable
      - `installDirectory` string, nullable
      - `installCommand` string, nullable
      - `buildCommand` string, nullable
      - `outputDirectory` string, nullable
      - `ignoredBuildCommand` string, nullable
      - `frameworkPreset` string, nullable
      - `platformPreset` string, nullable
      - `allowUnsupportedPlatformFeatures` boolean
      - `timeoutSeconds` integer
    - `placement` object: Placement controls for this space.
      - `burstable` boolean
      - `edge` boolean: Run the redirects and headers the edge can answer at the edge, ahead of the space. Takes effect at the next publish. Off by default; the rules the edge cannot answer faithfully stay with the space either way.
    - `markdownNegotiation` boolean: Accepted serving flag; runtime enforcement ships separately.
    - `firewall` object[]: Requests to block or challenge before they reach the space.
      - `name` string: Name for this rule: lowercase letters, digits, `-` and `_`, up to 61 characters. Names the rule in the CLI and the API.
      - `description` string: What this rule is for.
      - `action` 'block' | 'challenge', required: `block` answers without reaching the space; `challenge` asks for proof of a human.
      - `status` integer: Status a blocked request gets. Defaults to 403. Blocks only.
      - `match` TrafficRuleMatch, required: Request attributes the rule looks at. At least one.
        - `path` union: What the field has to match. A string with a `*` in it matches as a wildcard, any other string matches exactly, and a list matches any of its values. An `ip` value with a `/` in it matches a CIDR range. Everything else is an explicit clause: { "op": "exists" }, { "op": "contains", "value": "bot" }, { "op": "in", "values": ["RU"], "not": true }.
          - string
          - string[]
          - TrafficRuleClause: An explicit comparison, for the operators the shorthands cannot express.
            - `op` 'eq' | 'neq' | 'in' | 'inCidr' | 'contains' | 'startsWith' | 'endsWith' | 'wildcard' | 'exists', required: How the request attribute is compared to the value.
            - `value` string: Single value to compare against.
            - `values` string[]: Values to compare against, for `in` and `inCidr`.
            - `not` boolean: Match when the comparison does not hold.
        - `host` union: What the field has to match. A string with a `*` in it matches as a wildcard, any other string matches exactly, and a list matches any of its values. An `ip` value with a `/` in it matches a CIDR range. Everything else is an explicit clause: { "op": "exists" }, { "op": "contains", "value": "bot" }, { "op": "in", "values": ["RU"], "not": true }.
          - string
          - string[]
          - TrafficRuleClause: An explicit comparison, for the operators the shorthands cannot express.
            - `op` 'eq' | 'neq' | 'in' | 'inCidr' | 'contains' | 'startsWith' | 'endsWith' | 'wildcard' | 'exists', required: How the request attribute is compared to the value.
            - `value` string: Single value to compare against.
            - `values` string[]: Values to compare against, for `in` and `inCidr`.
            - `not` boolean: Match when the comparison does not hold.
        - `method` union: What the field has to match. A string with a `*` in it matches as a wildcard, any other string matches exactly, and a list matches any of its values. An `ip` value with a `/` in it matches a CIDR range. Everything else is an explicit clause: { "op": "exists" }, { "op": "contains", "value": "bot" }, { "op": "in", "values": ["RU"], "not": true }.
          - string
          - string[]
          - TrafficRuleClause: An explicit comparison, for the operators the shorthands cannot express.
            - `op` 'eq' | 'neq' | 'in' | 'inCidr' | 'contains' | 'startsWith' | 'endsWith' | 'wildcard' | 'exists', required: How the request attribute is compared to the value.
            - `value` string: Single value to compare against.
            - `values` string[]: Values to compare against, for `in` and `inCidr`.
            - `not` boolean: Match when the comparison does not hold.
        - `ip` union: What the field has to match. A string with a `*` in it matches as a wildcard, any other string matches exactly, and a list matches any of its values. An `ip` value with a `/` in it matches a CIDR range. Everything else is an explicit clause: { "op": "exists" }, { "op": "contains", "value": "bot" }, { "op": "in", "values": ["RU"], "not": true }.
          - string
          - string[]
          - TrafficRuleClause: An explicit comparison, for the operators the shorthands cannot express.
            - `op` 'eq' | 'neq' | 'in' | 'inCidr' | 'contains' | 'startsWith' | 'endsWith' | 'wildcard' | 'exists', required: How the request attribute is compared to the value.
            - `value` string: Single value to compare against.
            - `values` string[]: Values to compare against, for `in` and `inCidr`.
            - `not` boolean: Match when the comparison does not hold.
        - `country` union: What the field has to match. A string with a `*` in it matches as a wildcard, any other string matches exactly, and a list matches any of its values. An `ip` value with a `/` in it matches a CIDR range. Everything else is an explicit clause: { "op": "exists" }, { "op": "contains", "value": "bot" }, { "op": "in", "values": ["RU"], "not": true }.
          - string
          - string[]
          - TrafficRuleClause: An explicit comparison, for the operators the shorthands cannot express.
            - `op` 'eq' | 'neq' | 'in' | 'inCidr' | 'contains' | 'startsWith' | 'endsWith' | 'wildcard' | 'exists', required: How the request attribute is compared to the value.
            - `value` string: Single value to compare against.
            - `values` string[]: Values to compare against, for `in` and `inCidr`.
            - `not` boolean: Match when the comparison does not hold.
        - `asn` union: What the field has to match. A string with a `*` in it matches as a wildcard, any other string matches exactly, and a list matches any of its values. An `ip` value with a `/` in it matches a CIDR range. Everything else is an explicit clause: { "op": "exists" }, { "op": "contains", "value": "bot" }, { "op": "in", "values": ["RU"], "not": true }.
          - string
          - string[]
          - TrafficRuleClause: An explicit comparison, for the operators the shorthands cannot express.
            - `op` 'eq' | 'neq' | 'in' | 'inCidr' | 'contains' | 'startsWith' | 'endsWith' | 'wildcard' | 'exists', required: How the request attribute is compared to the value.
            - `value` string: Single value to compare against.
            - `values` string[]: Values to compare against, for `in` and `inCidr`.
            - `not` boolean: Match when the comparison does not hold.
        - `userAgent` union: What the field has to match. A string with a `*` in it matches as a wildcard, any other string matches exactly, and a list matches any of its values. An `ip` value with a `/` in it matches a CIDR range. Everything else is an explicit clause: { "op": "exists" }, { "op": "contains", "value": "bot" }, { "op": "in", "values": ["RU"], "not": true }.
          - string
          - string[]
          - TrafficRuleClause: An explicit comparison, for the operators the shorthands cannot express.
            - `op` 'eq' | 'neq' | 'in' | 'inCidr' | 'contains' | 'startsWith' | 'endsWith' | 'wildcard' | 'exists', required: How the request attribute is compared to the value.
            - `value` string: Single value to compare against.
            - `values` string[]: Values to compare against, for `in` and `inCidr`.
            - `not` boolean: Match when the comparison does not hold.
        - `referer` union: What the field has to match. A string with a `*` in it matches as a wildcard, any other string matches exactly, and a list matches any of its values. An `ip` value with a `/` in it matches a CIDR range. Everything else is an explicit clause: { "op": "exists" }, { "op": "contains", "value": "bot" }, { "op": "in", "values": ["RU"], "not": true }.
          - string
          - string[]
          - TrafficRuleClause: An explicit comparison, for the operators the shorthands cannot express.
            - `op` 'eq' | 'neq' | 'in' | 'inCidr' | 'contains' | 'startsWith' | 'endsWith' | 'wildcard' | 'exists', required: How the request attribute is compared to the value.
            - `value` string: Single value to compare against.
            - `values` string[]: Values to compare against, for `in` and `inCidr`.
            - `not` boolean: Match when the comparison does not hold.
        - `header` object: Per-name conditions: { "x-api-client": { "op": "exists" } }.
        - `cookie` object: Per-name conditions: { "x-api-client": { "op": "exists" } }.
        - `query` object: Per-name conditions: { "x-api-client": { "op": "exists" } }.
        - `extension` union: What the field has to match. A string with a `*` in it matches as a wildcard, any other string matches exactly, and a list matches any of its values. An `ip` value with a `/` in it matches a CIDR range. Everything else is an explicit clause: { "op": "exists" }, { "op": "contains", "value": "bot" }, { "op": "in", "values": ["RU"], "not": true }.
          - string
          - string[]
          - TrafficRuleClause: An explicit comparison, for the operators the shorthands cannot express.
            - `op` 'eq' | 'neq' | 'in' | 'inCidr' | 'contains' | 'startsWith' | 'endsWith' | 'wildcard' | 'exists', required: How the request attribute is compared to the value.
            - `value` string: Single value to compare against.
            - `values` string[]: Values to compare against, for `in` and `inCidr`.
            - `not` boolean: Match when the comparison does not hold.
        - `ja3` union: What the field has to match. A string with a `*` in it matches as a wildcard, any other string matches exactly, and a list matches any of its values. An `ip` value with a `/` in it matches a CIDR range. Everything else is an explicit clause: { "op": "exists" }, { "op": "contains", "value": "bot" }, { "op": "in", "values": ["RU"], "not": true }.
          - string
          - string[]
          - TrafficRuleClause: An explicit comparison, for the operators the shorthands cannot express.
            - `op` 'eq' | 'neq' | 'in' | 'inCidr' | 'contains' | 'startsWith' | 'endsWith' | 'wildcard' | 'exists', required: How the request attribute is compared to the value.
            - `value` string: Single value to compare against.
            - `values` string[]: Values to compare against, for `in` and `inCidr`.
            - `not` boolean: Match when the comparison does not hold.
        - `ja4` union: What the field has to match. A string with a `*` in it matches as a wildcard, any other string matches exactly, and a list matches any of its values. An `ip` value with a `/` in it matches a CIDR range. Everything else is an explicit clause: { "op": "exists" }, { "op": "contains", "value": "bot" }, { "op": "in", "values": ["RU"], "not": true }.
          - string
          - string[]
          - TrafficRuleClause: An explicit comparison, for the operators the shorthands cannot express.
            - `op` 'eq' | 'neq' | 'in' | 'inCidr' | 'contains' | 'startsWith' | 'endsWith' | 'wildcard' | 'exists', required: How the request attribute is compared to the value.
            - `value` string: Single value to compare against.
            - `values` string[]: Values to compare against, for `in` and `inCidr`.
            - `not` boolean: Match when the comparison does not hold.
      - `any` boolean: Fire when any match field holds. Defaults to false: all of them have to.
    - `cache` object: Cache behavior, including which requests skip it.
      - `bypass` object[]: Requests that skip the cache, in order. At most 50.
        - `name` string: Name for this rule: lowercase letters, digits, `-` and `_`, up to 61 characters. Names the rule in the CLI and the API.
        - `description` string: What this rule is for.
        - `match` TrafficRuleMatch, required: Request attributes the rule looks at. At least one.
          - `path` union: What the field has to match. A string with a `*` in it matches as a wildcard, any other string matches exactly, and a list matches any of its values. An `ip` value with a `/` in it matches a CIDR range. Everything else is an explicit clause: { "op": "exists" }, { "op": "contains", "value": "bot" }, { "op": "in", "values": ["RU"], "not": true }.
            - string
            - string[]
            - TrafficRuleClause: An explicit comparison, for the operators the shorthands cannot express.
              - …
          - `host` union: What the field has to match. A string with a `*` in it matches as a wildcard, any other string matches exactly, and a list matches any of its values. An `ip` value with a `/` in it matches a CIDR range. Everything else is an explicit clause: { "op": "exists" }, { "op": "contains", "value": "bot" }, { "op": "in", "values": ["RU"], "not": true }.
            - string
            - string[]
            - TrafficRuleClause: An explicit comparison, for the operators the shorthands cannot express.
              - …
          - `method` union: What the field has to match. A string with a `*` in it matches as a wildcard, any other string matches exactly, and a list matches any of its values. An `ip` value with a `/` in it matches a CIDR range. Everything else is an explicit clause: { "op": "exists" }, { "op": "contains", "value": "bot" }, { "op": "in", "values": ["RU"], "not": true }.
            - string
            - string[]
            - TrafficRuleClause: An explicit comparison, for the operators the shorthands cannot express.
              - …
          - `ip` union: What the field has to match. A string with a `*` in it matches as a wildcard, any other string matches exactly, and a list matches any of its values. An `ip` value with a `/` in it matches a CIDR range. Everything else is an explicit clause: { "op": "exists" }, { "op": "contains", "value": "bot" }, { "op": "in", "values": ["RU"], "not": true }.
            - string
            - string[]
            - TrafficRuleClause: An explicit comparison, for the operators the shorthands cannot express.
              - …
          - `country` union: What the field has to match. A string with a `*` in it matches as a wildcard, any other string matches exactly, and a list matches any of its values. An `ip` value with a `/` in it matches a CIDR range. Everything else is an explicit clause: { "op": "exists" }, { "op": "contains", "value": "bot" }, { "op": "in", "values": ["RU"], "not": true }.
            - string
            - string[]
            - TrafficRuleClause: An explicit comparison, for the operators the shorthands cannot express.
              - …
          - `asn` union: What the field has to match. A string with a `*` in it matches as a wildcard, any other string matches exactly, and a list matches any of its values. An `ip` value with a `/` in it matches a CIDR range. Everything else is an explicit clause: { "op": "exists" }, { "op": "contains", "value": "bot" }, { "op": "in", "values": ["RU"], "not": true }.
            - string
            - string[]
            - TrafficRuleClause: An explicit comparison, for the operators the shorthands cannot express.
              - …
          - `userAgent` union: What the field has to match. A string with a `*` in it matches as a wildcard, any other string matches exactly, and a list matches any of its values. An `ip` value with a `/` in it matches a CIDR range. Everything else is an explicit clause: { "op": "exists" }, { "op": "contains", "value": "bot" }, { "op": "in", "values": ["RU"], "not": true }.
            - string
            - string[]
            - TrafficRuleClause: An explicit comparison, for the operators the shorthands cannot express.
              - …
          - `referer` union: What the field has to match. A string with a `*` in it matches as a wildcard, any other string matches exactly, and a list matches any of its values. An `ip` value with a `/` in it matches a CIDR range. Everything else is an explicit clause: { "op": "exists" }, { "op": "contains", "value": "bot" }, { "op": "in", "values": ["RU"], "not": true }.
            - string
            - string[]
            - TrafficRuleClause: An explicit comparison, for the operators the shorthands cannot express.
              - …
          - `header` object: Per-name conditions: { "x-api-client": { "op": "exists" } }.
          - `cookie` object: Per-name conditions: { "x-api-client": { "op": "exists" } }.
          - `query` object: Per-name conditions: { "x-api-client": { "op": "exists" } }.
          - `extension` union: What the field has to match. A string with a `*` in it matches as a wildcard, any other string matches exactly, and a list matches any of its values. An `ip` value with a `/` in it matches a CIDR range. Everything else is an explicit clause: { "op": "exists" }, { "op": "contains", "value": "bot" }, { "op": "in", "values": ["RU"], "not": true }.
            - string
            - string[]
            - TrafficRuleClause: An explicit comparison, for the operators the shorthands cannot express.
              - …
          - `ja3` union: What the field has to match. A string with a `*` in it matches as a wildcard, any other string matches exactly, and a list matches any of its values. An `ip` value with a `/` in it matches a CIDR range. Everything else is an explicit clause: { "op": "exists" }, { "op": "contains", "value": "bot" }, { "op": "in", "values": ["RU"], "not": true }.
            - string
            - string[]
            - TrafficRuleClause: An explicit comparison, for the operators the shorthands cannot express.
              - …
          - `ja4` union: What the field has to match. A string with a `*` in it matches as a wildcard, any other string matches exactly, and a list matches any of its values. An `ip` value with a `/` in it matches a CIDR range. Everything else is an explicit clause: { "op": "exists" }, { "op": "contains", "value": "bot" }, { "op": "in", "values": ["RU"], "not": true }.
            - string
            - string[]
            - TrafficRuleClause: An explicit comparison, for the operators the shorthands cannot express.
              - …
        - `any` boolean: Fire when any match field holds. Defaults to false: all of them have to.
    - `redirects` object[]: Browser redirect rules. Same matcher grammar as _redirects, and _redirects rules match first.
      - `source` string, required: Request path to match. * is a splat, :name captures a segment.
      - `destination` string, required: Path or absolute URL. :splat and :name from the source are substituted.
      - `status` 301 | 302 | 303 | 307 | 308: Redirect status, 302 when omitted. To serve other content under this URL, use rewrites.
      - `force` boolean: Answer even when the request path resolves to a committed file, the ! of a _redirects rule.
      - `query` object: Query parameters the request must carry, as parameter name to capture name: { "id": "id" } is the name=:capture token id=:id.
    - `rewrites` object[]: Rewrite and proxy rules: the URL stays, the content comes from the destination. _redirects rules match first, then redirects.
      - `source` string, required: Request path to match. * is a splat, :name captures a segment.
      - `destination` string, required: Path to serve under this URL, or an absolute URL to proxy. :splat and :name from the source are substituted.
      - `cache` 'shared': Let shared caches store the proxy response. Absolute-URL destinations only.
      - `force` boolean: Answer even when the request path resolves to a committed file, the ! of a _redirects rule.
      - `query` object: Query parameters the request must carry, as parameter name to capture name: { "id": "id" } is the name=:capture token id=:id.
      - `notFound` boolean: Serve the destination with status 404, the 404 of a _redirects rule. The destination must be a path.
    - `headers` object[]: Response headers to set or remove on matching requests. A _headers rule wins on the same header name.
      - `source` string, required: Request path to match.
      - `headers` union[], required
        - union
          - object
            - `key` string, required
            - `value` string, required
          - object
            - `key` string, required
            - `remove` true, required: Remove this header instead of setting it, the !Name line of a _headers block.
    - `users` object
      - `enabled` boolean, required
      - `providers` object, required
        - `google` union, required
          - object
            - `mode` 'disabled', required
          - object
            - `mode` 'managed', required
          - object
            - `mode` 'direct', required
            - `clientId` string, required
        - `gravatar` object, required
          - `enabled` boolean, required
        - `spacefast` object, required
          - `enabled` boolean, required
    - `dataSources` object: Named public WordPress sources exposed to repository builds; at most 32 entries.
  - `access` 'private' | 'team' | 'public': Set the initial root access for this new team-owned Space. Omit this field to use the team's default. Do not set this field with spaceId.

## Response `201`

Response for status 201

- object
  - `$schema` string, uri: Canonical JSON Schema URL for this response body. The server also sends it in the `Link: rel="describedby"` response header.
  - `data` union, required
    - object
      - `space` object, required
        - `id` string, required
        - `slug` string, required
        - `title` string, required
        - `publicName` string, required
        - `defaultHostname` string
        - `liveUrl` string, nullable, required
      - `build` object, required
        - `capture` object: URL capture progress and advisory evidence; absent for other inputs.
          - `state` string, required
          - `previewSummary` object
          - `progress` object
          - `archiveHash` string
        - `id` string, required: Build id (`bld_`); opaque and never derived from a version id.
        - `spaceId` string, required: Space (`spc_`) the build produces a version for.
        - `status` 'waiting_for_source' | 'uploading_source' | 'queued' | 'running' | 'succeeded' | 'failed' | 'canceled' | 'skipped', required: Build lifecycle status.
        - `input` union, required: Public build input. Internal clone URLs and provider source references are hidden.
          - object
            - `kind` 'url', required
            - `sourceUrl` string, uri, required
          - object
            - `kind` 'archive', required: Build from an uploaded source archive.
          - object
            - `kind` 'repository', required: Build from repository source where clone credentials are not exposed.
            - `ref` string, required: Branch, tag, or ref to build.
            - `commit` string: Exact commit built, once resolved.
            - `branch` string: Branch name when available.
            - `pullRequestNumber` integer
        - `source` object, nullable, required: Publish provenance as declared at build start (client, git ref data, publish message). Present on failed and running builds too; the produced version's `source` is the authoritative copy once one exists. Null when nothing was declared.
          - `kind` 'direct_upload' | 'cli' | 'dashboard' | 'api' | 'git' | 'import' | 'agent' | 'build' | 'variable_update' | 'config_update', required: How this version was produced.
          - `client` string: Publishing client attribution, for example `spacefast-cli/1.2.3`.
          - `branch` string: Git branch the publish came from.
          - `commit` string: Git commit SHA the publish came from.
          - `message` string: Plain-language description of the publish (the version changelog entry, commit message, or release note). This is THE spelling for the publish description; the version files-diff API is the fallback when none is given.
          - `dirty` boolean: Whether the working tree had uncommitted changes at publish time.
          - `metadata` object: Additional provenance (repository, CI run URL, workflow, actor, ...).
          - `git` object
            - `repository` string, nullable
            - `repositoryFullName` string, nullable
            - `repositoryUrl` string, nullable
            - `ref` string, nullable
            - `branch` string, nullable
            - `branchAliasUrl` string, nullable
            - `commit` string, nullable
            - `commitSha` string, nullable
            - `pullRequestNumber` number, nullable
        - `settingsSnapshot` object, required: Resolved build settings. Builds persist this as an immutable `settingsSnapshot`.
          - `rootDirectory` string, nullable, required
          - `installDirectory` string, nullable, required
          - `installCommand` string, nullable, required
          - `buildCommand` string, nullable, required
          - `outputDirectory` string, nullable, required
          - `ignoredBuildCommand` string, nullable, required
          - `frameworkPreset` string, nullable, required
          - `platformPreset` string, nullable, required
          - `allowUnsupportedPlatformFeatures` boolean, required
          - `timeoutSeconds` integer, required
        - `target` object, required: Where a successful build should publish or run in preview mode.
          - `channel` string, nullable, required: Channel to promote when the build succeeds. production is an alias for live; null means no automatic promotion.
          - `preview` boolean, required: Whether the build targets preview behavior.
        - `retryOfBuildId` string, nullable, required: Original build retried by this build.
        - `producedVersionId` string, nullable, required: Version (`ver_`) minted by a successful build; null otherwise.
        - `reusedVersionId` string, nullable, required: Existing version reused by a successful no-change build; null otherwise.
        - `diagnostics` object[], required
          - `code` string, required: Stable snake_case diagnostic code naming the public contract that produced it.
          - `severity` 'info' | 'warning' | 'error', required: How actionable the diagnostic is.
          - `message` string, required: Human-readable explanation with enough detail to act on.
          - `path` string, nullable: Artifact path the diagnostic points at, for example "_headers:12", when one exists.
          - `provider` 'infra' | 'dns' | 'registrar' | 'runtime', nullable: Upstream system the diagnostic originated from, when not Spacefast itself.
          - `details` object, nullable: Machine-readable context for the diagnostic code.
          - `fix` string, nullable: Concrete, agent-actionable remediation hint, when one can be derived.
          - `retryable` boolean, nullable: Whether retrying the same operation can resolve this diagnostic without the caller changing anything.
        - `createdAt` string, date-time, required
        - `startedAt` string, date-time, nullable, required: When the runner picked the build up.
        - `finishedAt` string, date-time, nullable, required: When the build reached a terminal state.
      - `version` object
        - `id` string, required
        - `status` 'building' | 'prepared' | 'created' | 'uploading' | 'uploaded' | 'finalizing' | 'ready' | 'failed' | 'expired' | 'canceled', required
        - `immutableUrl` string, nullable, required: Permanent version URL, or null while the version is still being finalized.
        - `ref` string, nullable
        - `number` integer, nullable
        - `manifestHash` string, nullable, required
      - `activation` object
        - `channel` 'live', nullable, required: Channel this publish targeted; null means a ready version without promotion.
        - `outcome` 'activated' | 'unpromoted' | 'superseded' | 'pending', required: activated: the live pointer moved to this version. unpromoted: ready without promotion — either the caller passed channel null, or the live channel's promotion policy held it; `reason` says which. superseded: ready, but a newer publish holds the live pointer. pending: not settled yet.
        - `currentLiveVersionId` string, nullable, required: The version currently serving live traffic, or null when the space has none.
        - `reason` 'channel_promotion_manual': Why the outcome is not what the caller asked for. channel_promotion_manual: the live channel's promotion policy is manual, so this publish finalized ready but unpromoted; POST promote to move the pointer.
      - `next` object, required
        - `action` 'done' | 'upload' | 'finalize' | 'poll', required: What the caller does next: `done` (stop; this request intent is settled), `upload` (PUT upload targets, then follow the finalize link), `finalize` (all bytes are present, POST `url` to commit), or `poll` (server-side work is in flight, GET `url` after `retryAfter` seconds).
        - `url` string: The endpoint the action applies to.
        - `retryAfter` integer: Polling cadence in seconds; present only when action is poll.
        - `hint` string, required: One plain sentence for an agent in the middle of a loop.
      - `git` object
        - `managedBy` 'spacefast' | 'github' | 'connected', required: Who owns the Git history. `spacefast`: push to publish. `github` or `connected`: deploys from an upstream repository; direct pushes are refused.
        - `remoteUrl` string, nullable, required: Credential-free git remote to push to, or null for an upstream-managed repository. Authenticate as HTTP Basic user `t` with a space key or API key as the password.
        - `repository` string, nullable, required: Name of the connected upstream repository this Space deploys from, else null.
        - `defaultBranch` string, nullable, required: Branch that publishes to the live channel when pushed.
        - `provisioned` boolean, required: Whether the repository behind this block exists yet. Always true for a GitHub binding; for a hosted remote, true once it was minted or first pushed to, and false while there is nothing to browse.
      - `access` object
        - `url` string, uri, required
        - `token` string, required
        - `expiresAt` string, date-time, nullable, required
      - `claim` object
        - `key` string, required: The space key (sfc_…): the one credential for this unclaimed space. Bearer auth for publish, update, status, sharing, rotation, and the one-time continuation exchange. Returned only at creation and rotation; save it immediately.
        - `url` string, uri, required: The site door: the live URL with the space key in /__/<key> form. Opening it exchanges the key for a private view session and lands on the site. It is the same key in URL form, so share it as carefully as the key.
        - `claimUrl` string, uri, required: Claim page link in /claim#<key> form. The fragment is the key; browsers never send it to a server and the claim page strips it before analytics. Works until expiresAt and can be opened more than once.
        - `expiresAt` string, date-time, required
      - `diagnostics` object[]
        - `code` string, required: Stable snake_case diagnostic code naming the public contract that produced it.
        - `severity` 'info' | 'warning' | 'error', required: How actionable the diagnostic is.
        - `message` string, required: Human-readable explanation with enough detail to act on.
        - `path` string, nullable: Artifact path the diagnostic points at, for example "_headers:12", when one exists.
        - `provider` 'infra' | 'dns' | 'registrar' | 'runtime', nullable: Upstream system the diagnostic originated from, when not Spacefast itself.
        - `details` object, nullable: Machine-readable context for the diagnostic code.
        - `fix` string, nullable: Concrete, agent-actionable remediation hint, when one can be derived.
        - `retryable` boolean, nullable: Whether retrying the same operation can resolve this diagnostic without the caller changing anything.
      - `links` object, required
        - `inspect` string, required
        - `build` string, required
        - `status` string, required
        - `version` string
    - object
      - `space` object, required
        - `id` string, required
        - `slug` string, required
        - `title` string, required
        - `publicName` string, required
        - `defaultHostname` string
        - `liveUrl` string, nullable, required
      - `access` object: Reusable Open link for owned (team/external) publishes. Anonymous publishes get no separate access object: the space key in `claim` is the credential, and `claim.url` is the door.
        - `url` string, uri, required
        - `token` string, required
        - `expiresAt` string, date-time, nullable, required
      - `version` object, required
        - `id` string, required
        - `status` 'building' | 'prepared' | 'created' | 'uploading' | 'uploaded' | 'finalizing' | 'ready' | 'failed' | 'expired' | 'canceled', required
        - `immutableUrl` string, nullable, required: Permanent version URL, or null while the version is still being finalized.
        - `ref` string, nullable
        - `number` integer, nullable
        - `manifestHash` string, nullable, required
      - `activation` object, required
        - `channel` 'live', nullable, required: Channel this publish targeted; null means a ready version without promotion.
        - `outcome` 'activated' | 'unpromoted' | 'superseded' | 'pending', required: activated: the live pointer moved to this version. unpromoted: ready without promotion — either the caller passed channel null, or the live channel's promotion policy held it; `reason` says which. superseded: ready, but a newer publish holds the live pointer. pending: not settled yet.
        - `currentLiveVersionId` string, nullable, required: The version currently serving live traffic, or null when the space has none.
        - `reason` 'channel_promotion_manual': Why the outcome is not what the caller asked for. channel_promotion_manual: the live channel's promotion policy is manual, so this publish finalized ready but unpromoted; POST promote to move the pointer.
      - `next` object, required
        - `action` 'done' | 'upload' | 'finalize' | 'poll', required: What the caller does next: `done` (stop; this request intent is settled), `upload` (PUT upload targets, then follow the finalize link), `finalize` (all bytes are present, POST `url` to commit), or `poll` (server-side work is in flight, GET `url` after `retryAfter` seconds).
        - `url` string: The endpoint the action applies to.
        - `retryAfter` integer: Polling cadence in seconds; present only when action is poll.
        - `hint` string, required: One plain sentence for an agent in the middle of a loop.
      - `git` object: Git remote for this space. `managedBy: "spacefast"` carries a `remoteUrl` you can push to; `managedBy: "github"` means the space deploys from GitHub and direct pushes are refused.
        - `managedBy` 'spacefast' | 'github' | 'connected', required: Who owns the Git history. `spacefast`: push to publish. `github` or `connected`: deploys from an upstream repository; direct pushes are refused.
        - `remoteUrl` string, nullable, required: Credential-free git remote to push to, or null for an upstream-managed repository. Authenticate as HTTP Basic user `t` with a space key or API key as the password.
        - `repository` string, nullable, required: Name of the connected upstream repository this Space deploys from, else null.
        - `defaultBranch` string, nullable, required: Branch that publishes to the live channel when pushed.
        - `provisioned` boolean, required: Whether the repository behind this block exists yet. Always true for a GitHub binding; for a hosted remote, true once it was minted or first pushed to, and false while there is nothing to browse.
      - `authMode` 'anonymous' | 'authenticated': anonymous: authorized by a space key. authenticated: authorized by an account.
      - `persistence` 'temporary' | 'managed': temporary: the space expires unless claimed. managed: the space belongs to a team and persists.
      - `operation` object: Background finalize operation when publish work continues asynchronously.
        - `id` string, required
        - `kind` string, required
        - `status` 'queued' | 'running' | 'succeeded' | 'failed' | 'canceled', required
        - `resources` object[], required
          - `type` string, required
          - `id` string, required
        - `progress` object
          - `total` integer, required
          - `completed` integer, required
          - `failed` integer, required
        - `diagnostics` object[]
          - `code` string, required: Stable snake_case diagnostic code naming the public contract that produced it.
          - `severity` 'info' | 'warning' | 'error', required: How actionable the diagnostic is.
          - `message` string, required: Human-readable explanation with enough detail to act on.
          - `path` string, nullable: Artifact path the diagnostic points at, for example "_headers:12", when one exists.
          - `provider` 'infra' | 'dns' | 'registrar' | 'runtime', nullable: Upstream system the diagnostic originated from, when not Spacefast itself.
          - `details` object, nullable: Machine-readable context for the diagnostic code.
          - `fix` string, nullable: Concrete, agent-actionable remediation hint, when one can be derived.
          - `retryable` boolean, nullable: Whether retrying the same operation can resolve this diagnostic without the caller changing anything.
        - `createdAt` string, date-time, required
        - `finishedAt` string, date-time
      - `upload` object
        - `id` string, required: Upload session id (upl_…) minted by the runtime.
        - `mode` 'dist' | 'source', required: `dist` bytes are publishable output. `source` bytes must be transformed, unpacked, or built before publish.
        - `expiresAt` string, date-time, required: Instant when the session token expires. This rotates only the token, never the version lifecycle boundary. Resume always mints a fresh token.
        - `summary` object, required: Counts for the whole manifest, independent of target paging.
          - `upload` integer, required: Files that still need uploading.
          - `reused` integer, required: Files satisfied by hash reuse.
          - `ignored` integer: Deprecated; current servers return zero.
        - `targets` object[], required: Opaque upload targets, bounded by the instruction payload budget. Upload these, then call `links.refresh` for the remainder.
          - `path` string, required: Caller-local path/key identifying the bytes this target accepts.
          - `method` 'PUT' | 'POST', required: HTTP method to use for this target.
          - `url` union, required: Absolute or API-relative upload URL issued by the control plane.
            - string, uri
            - string
          - `headers` object, required: Exact headers to send with the upload request.
          - `body` object: Optional body recipe. Omitted means the client uploads the local bytes for `path`; `url` means POST the URL for server-side fetch.
            - `kind` 'url', required
            - `url` string, uri, required
          - `size` integer: Expected byte size when known.
          - `maxBytes` integer: Maximum accepted byte size when the server can advertise it.
          - `sha256` string
          - `contentType` string
        - `bulk` object: Optional direct runtime transport for this page's content-addressed targets. Clients that do not support it continue with targets.
          - `kind` 'zip-cas-v1', required
          - `method` 'PUT', required
          - `url` union, required: Upload-auth runtime URL that accepts a ZIP of SHA-named CAS blobs.
            - string, uri
            - string
          - `headers` object, required: Exact headers to send with the bulk upload request.
          - `maxCompressedBytes` integer, required
          - `maxExpandedBytes` integer, required
          - `maxBlobs` integer, required
        - `links` object, required
          - `refresh` string, required
          - `resume` string
          - `finalize` string, required
        - `details` object
          - `reused` object[]
            - `path` string, required
            - `reason` string, required
          - `diagnostics` object[]
            - `code` string, required: Stable snake_case diagnostic code naming the public contract that produced it.
            - `severity` 'info' | 'warning' | 'error', required: How actionable the diagnostic is.
            - `message` string, required: Human-readable explanation with enough detail to act on.
            - `path` string, nullable: Artifact path the diagnostic points at, for example "_headers:12", when one exists.
            - `provider` 'infra' | 'dns' | 'registrar' | 'runtime', nullable: Upstream system the diagnostic originated from, when not Spacefast itself.
            - `details` object, nullable: Machine-readable context for the diagnostic code.
            - `fix` string, nullable: Concrete, agent-actionable remediation hint, when one can be derived.
            - `retryable` boolean, nullable: Whether retrying the same operation can resolve this diagnostic without the caller changing anything.
      - `claim` object
        - `key` string, required
        - `url` string, required
        - `claimUrl` string, required
        - `expiresAt` string, date-time, required
      - `diagnostics` object[]: Publish diagnostics. `noop_publish` means the content did not change. `hostname_attach_pending` means the first live version can serve before the space hostname serves. The live URL can take a few minutes to start serving. Other codes report manifest warnings or serving configuration.
        - `code` string, required: Stable snake_case diagnostic code naming the public contract that produced it.
        - `severity` 'info' | 'warning' | 'error', required: How actionable the diagnostic is.
        - `message` string, required: Human-readable explanation with enough detail to act on.
        - `path` string, nullable: Artifact path the diagnostic points at, for example "_headers:12", when one exists.
        - `provider` 'infra' | 'dns' | 'registrar' | 'runtime', nullable: Upstream system the diagnostic originated from, when not Spacefast itself.
        - `details` object, nullable: Machine-readable context for the diagnostic code.
        - `fix` string, nullable: Concrete, agent-actionable remediation hint, when one can be derived.
        - `retryable` boolean, nullable: Whether retrying the same operation can resolve this diagnostic without the caller changing anything.
      - `links` object: Follow-up links so agents can act on the receipt without knowing the full API.
        - `refresh` string: Upload-instruction refresh endpoint; present while bytes still need uploading.
        - `resume` string: Deprecated alias for `refresh`; carries the identical URL.
        - `finalize` string: Finalize endpoint; present while bytes still need uploading.
        - `promote` string: Promote endpoint; followable once the version reaches status "ready".
        - `operation` string: Operation polling endpoint when publish queued.
        - `inspect` string: Space resource URL for follow-up reads.
        - `version` string: Version resource URL for structured clients.
        - `status` string: Space-key-authenticated anonymous publish status endpoint.

## Other responses

- `default`: Problem details (RFC 9457). Any 4xx/5xx response is one `application/problem+json` document.

---

[API](https://skmtc.dev/spacefast/apis/spacefast-api.md) · [All operations](https://skmtc.dev/spacefast/apis/spacefast-api/llms.txt) · [OpenAPI document](https://skmtc.dev/spacefast/apis/spacefast-api/revisions/bd165bc7c983?raw)
