---
title: "Get a version"
method: GET
path: "/v1/spaces/{spaceId}/versions/{versionId}"
tags: ["Versions"]
---

# Get a version

`GET /v1/spaces/{spaceId}/versions/{versionId}`

## Request

- Base URL: `https://api.spacefast.com`
- URL: `https://api.spacefast.com/v1/spaces/{spaceId}/versions/{versionId}`
- Auth: one of:
  - HTTP bearer
  - HTTP bearer

Returns one version with its status, number, permanent Version URL, and diagnostics. Anonymous claim tokens can poll this route to follow a publish.

## Path parameters

- `spaceId` string, required
- `versionId` string, required

## Response `200`

Response for status 200

- 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` object, required
    - `id` string, required
    - `ref` string, nullable, required: Human ref "v{number}"; null until the version reaches ready.
    - `number` integer, nullable, required
    - `spaceId` string, required
    - `source` object, nullable, required: Publish provenance: who/what produced this version.
      - `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
    - `publisher` object, nullable, required: The actor that published the version. The value is null for a legacy version with no attribution.
      - `type` 'user' | 'api_key' | 'partner_token' | 'oauth_client' | 'anonymous_claim' | 'system', required: The type of actor that published the version.
      - `displayName` string, required: The display name of the person, agent, or system that published the version.
      - `avatarUrl` string, nullable, required: The publisher's avatar URL. The value is null when no avatar exists.
      - `authorizedBy` object, nullable, required: The person who authorized the publisher. The value is null when the publisher is a person or has no known authorizing person.
        - `displayName` string, required: The person's display name.
        - `avatarUrl` string, nullable, required: The person's avatar URL. The value is null when no avatar exists.
    - `status` 'building' | 'prepared' | 'created' | 'uploading' | 'uploaded' | 'finalizing' | 'ready' | 'failed' | 'expired' | 'canceled', required
    - `failureCode` string, nullable, required
    - `failureMessage` string, nullable, required
    - `failedStage` string, nullable, required
    - `manifestHash` string, nullable, required
    - `buildId` string, nullable, required
    - `gitCommitSha` string, nullable, required: Commit the build for this version was made from; null for direct uploads.
    - `importedFromVersionId` string, nullable, required
    - `variables` unknown, required
    - `fileCount` integer, nullable, required
    - `totalBytes` integer, nullable, required
    - `filesAddedCount` integer, required: Paths this version added against the version it replaced.
    - `filesChangedCount` integer, required: Paths whose bytes changed against the version this one replaced.
    - `filesRemovedCount` integer, required: Paths this version removed against the version it replaced.
    - `pendingUploads` object[], required
      - `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.
      - `sourceUrl` string, uri: Optional HTTPS URL the runtime can fetch directly for this file instead of receiving bytes from the client.
    - `skippedPaths` string[], required
    - `immutableUrl` string, nullable, required: Permanent version URL ({label}--v{number}.space.fast form, under the space's own apex), computed once and stored at ready; survives slug changes, transfers, and channel repointing. Null before ready.
    - `immutableUrlStatus` 'pending' | 'ready', nullable, required: Whether the immutable version URL is ready. pending means the URL might not resolve yet.
    - `isCurrentProduction` boolean, required
    - `siteTitle` string, required
    - `config` object, nullable, required: SpaceConfig overlay snapshot the version was finalized with.
      - `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[]
              - …
          - `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', required
      - `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.
              - …
          - `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.
      - `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 }.
              - …
            - `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 }.
              - …
            - `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 }.
              - …
            - `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 }.
              - …
            - `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 }.
              - …
            - `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 }.
              - …
            - `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 }.
              - …
            - `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 }.
              - …
            - `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 }.
              - …
            - `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 }.
              - …
            - `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 }.
              - …
          - `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
              - …
            - object
              - …
      - `users` object
        - `enabled` boolean, required
        - `providers` object, required
          - `google` union, required
            - object
              - …
            - object
              - …
            - object
              - …
          - `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.
    - `operation` object, nullable, required
      - `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
    - `headersRuleCount` integer, required
    - `redirectsRuleCount` integer, required
    - `proxyRouteCount` integer, required
    - `crons` object[]: Cron declarations frozen at finalize, independent of worker presence. Included when inspecting a version; omitted from version lists.
      - `key` string, required: Stable identifier for this entry, derived from its path.
      - `path` string, required: Path on this space that gets requested.
      - `schedule` string, required: Schedule as declared, verbatim: named, an Nh/Nd/Nw interval, or a five-field crontab expression.
    - `runtimeCodeDetected` boolean, required
    - `buildLog` string, nullable, required
    - `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.
      - `id` string, required
      - `versionId` string, required
      - `createdAt` string, date-time, required
    - `createdAt` string, date-time, required
    - `readyAt` string, date-time, nullable, required
    - `updatedAt` string, date-time, required

## 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)
