---
title: "Read a version's build log"
description: "The build's output for one version, read from Vercel with the deployment the version's row holds, never an id the caller names."
api_method: GET
api_path: "/v1/workspaces/{workspaceId}/sites/{siteId}/versions/{versionId}/log"
canonical_url: https://wiblo.app/docs/developers/api/sites/get-site-version-log
last_updated: 2026-09-28T22:17:00+02:00
md_url: https://wiblo.app/docs/developers/api/sites/get-site-version-log.md
---

# Read a version's build log

`GET /v1/workspaces/{workspaceId}/sites/{siteId}/versions/{versionId}/log`

The build's output for one version, read from Vercel with the deployment the version's row holds, never an id the caller names. The body is `application/x-ndjson`: one `line` item per line the build wrote, oldest first, with the colour codes stripped, then exactly one `end` item that says the build's state, why the log closed, and the version's message when the build failed. A settled build's log arrives whole. A running build's log arrives as the build writes it and closes when the build settles, or four minutes after the request with the state still `building`: read again with `since` set to the last line's `at`. A build asked for a moment ago is waited for, up to a minute, until Vercel has started it. The source of `wiblo sites versions --log`, and how an agent reads why a build failed. Every active member may call it, and a run's workspace key is an expected bearer. Per-user rate-limited at 60/60s.

## Path parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `workspaceId` | `string` | Yes |  |
| `siteId` | `string` | Yes |  |
| `versionId` | `string` | Yes |  |

## Query parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `since` | `string` | No | Only lines written at or after this moment: the `at` of the last line already read. Lines written at that exact moment arrive again, so skip the ones already read. |

## Request

**curl**

```bash
curl https://api.wiblo.app/v1/workspaces/{workspaceId}/sites/{siteId}/versions/{versionId}/log \
  -H "Authorization: Bearer $WIBLO_TOKEN"
```

**TypeScript**

```ts
import { createSdk, getSiteVersionLog } from "@workspace/sdk"

const sdk = createSdk({ baseUrl: "https://api.wiblo.app" })

const { data, error } = await getSiteVersionLog({
  client: sdk,
  path: { workspaceId: "...", siteId: "...", versionId: "..." },
})
```

## Responses

**`200`** — The log as `application/x-ndjson`, one JSON object per line of the body: the `line` items, oldest first, then exactly one `end` item. Returns `SiteBuildLogItem`.

One of `SiteBuildLogLine` or `SiteBuildLogEnd`.

**`401`** — No valid session, `wbl_*` bearer, or run token was present. Returns `ApiErrorEnvelope`.

**`404`** — Workspace not visible to the caller (`WORKSPACE_NOT_FOUND`), no site with that id in it (`SITE_NOT_FOUND`), or no version with that id on the site (`VERSION_NOT_FOUND`). Returns `ApiErrorEnvelope`.

**`409`** — Vercel has not started a build for the version (`NO_BUILD_YET`): it is queued, it failed before the build was created, or a build asked for a moment ago still had no deployment after a minute's wait. The message carries the version's own reason when it failed. Returns `ApiErrorEnvelope`.

**`410`** — The version's deployment is gone from Vercel, and its log with it (`LOG_GONE`). Returns `ApiErrorEnvelope`.

**`422`** — Path param failed UUID validation, or `since` is not a timestamp (`INVALID_PARAMS`). Returns `ApiErrorEnvelope`.

**`429`** — Rate limit exceeded. The body's `error.code` is `RATE_LIMITED` and `error.details.retry_after` is the same number of seconds as the `Retry-After` header. Returns `ApiErrorEnvelope`.

**`502`** — Vercel did not answer (`PROVIDER_DOWN`), Vercel refused the read on the token or the plan, which no retry fixes (`PROVIDER_REJECTED`), or the deploy provider is not configured (`UPSTREAM_UNAVAILABLE`). Returns `ApiErrorEnvelope`.

**`503`** — Vercel is rate limited (`PROVIDER_BUSY`). `retry_after` is the wait in seconds, at most a minute. Returns `ApiErrorEnvelope`.

### The SiteBuildLogLine object

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `type` | `"line"` | Yes | Always `line` on a line of output. |
| `at` | `string` | Yes | When the build wrote the line. |
| `stream` | `"stdout" \| "stderr"` | Yes | The build's own stream for the line. For example, the "Module not found" line of a broken import is `stderr`. |
| `text` | `string` | Yes | The line as the build wrote it, with the colour codes stripped and any Vercel id replaced by `<id>`. Blank lines are left out. |

### The SiteBuildLogEnd object

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `type` | `"end"` | Yes | Always `end` on the last item of the log. |
| `state` | `"building" \| "ready" \| "error" \| "canceled"` | Yes | The build's state when the log closed: `ready`, `error`, or `canceled` once it finished, or `building` when the read stopped first. |
| `reason` | `"settled" \| "time_limit" \| "interrupted"` | Yes | Why the log closed. `settled`: the build finished, and `state` says how. `time_limit`: the build still ran when the read reached its limit, four minutes after the request. `interrupted`: the build still ran, and the live read from Vercel dropped and could not be opened again. After `time_limit` or `interrupted`, read again with `since` set to the last line's `at`. |
| `error` | `string \| null` | Yes | The version's `error` message when `state` is `error`. Null for every other state. |
