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

# Publish

> Publish and unpublish pages via frontmatter and read them at /p/{path}.

Publishing marks a page with `published: true` and `published_at` in frontmatter. Published pages are readable at `/p/{path}` without API authentication.

## Publish a page

```http theme={null}
POST /api/kiwi/publish
Content-Type: application/json
```

<ParamField body="path" type="string" required>
  File path to publish.
</ParamField>

```bash theme={null}
curl -X POST 'http://localhost:3333/api/kiwi/publish' \
  -H 'Content-Type: application/json' \
  -H 'X-Actor: agent:publisher' \
  -d '{"path":"concepts/auth.md"}'
```

```json Response theme={null}
{
  "path": "concepts/auth.md",
  "published": true,
  "published_at": "2026-05-02T14:30:00Z",
  "public_url": "/p/concepts/auth.md"
}
```

<Info>
  `published_at` is set only on first publish. Later republish calls preserve the original timestamp.
</Info>

## Bulk publish

Publish multiple pages in a single request.

```http theme={null}
POST /api/kiwi/publish/bulk
Content-Type: application/json
```

<ParamField body="paths" type="string[]" required>
  Array of file paths to publish.
</ParamField>

```bash theme={null}
curl -X POST 'http://localhost:3333/api/kiwi/publish/bulk' \
  -H 'Content-Type: application/json' \
  -H 'X-Actor: agent:publisher' \
  -d '{"paths":["concepts/auth.md","concepts/billing.md","concepts/users.md"]}'
```

```json Response theme={null}
{
  "published": 3,
  "results": [
    {"path": "concepts/auth.md", "published": true},
    {"path": "concepts/billing.md", "published": true},
    {"path": "concepts/users.md", "published": true}
  ]
}
```

## Unpublish

```http theme={null}
POST /api/kiwi/unpublish
Content-Type: application/json
```

<ParamField body="path" type="string" required>
  File path to unpublish.
</ParamField>

Sets `published: false` but keeps `published_at` for history.

## Bulk unpublish

```http theme={null}
POST /api/kiwi/unpublish/bulk
Content-Type: application/json
```

<ParamField body="paths" type="string[]" required>
  Array of file paths to unpublish.
</ParamField>

## List published pages

```http theme={null}
GET /api/kiwi/publish/list
```

Returns all currently published pages.

```json Response theme={null}
{
  "pages": [
    {"path": "concepts/auth.md", "published_at": "2026-05-02T14:30:00Z", "public_url": "/p/concepts/auth.md"},
    {"path": "guides/quickstart.md", "published_at": "2026-05-01T10:00:00Z", "public_url": "/p/guides/quickstart.md"}
  ]
}
```

## Publish status

```http theme={null}
GET /api/kiwi/publish/status?path=concepts/auth.md
```

<ParamField query="path" type="string" required>
  File path to check.
</ParamField>

```json Response theme={null}
{
  "path": "concepts/auth.md",
  "published": true,
  "published_at": "2026-05-02T14:30:00Z",
  "public_url": "/p/concepts/auth.md",
  "view_count": 42
}
```

<ResponseField name="view_count" type="integer">
  Included when publish metrics tracking is enabled on the server.
</ResponseField>

## Read published pages

No API key required:

```bash theme={null}
curl 'http://localhost:3333/p/concepts/auth.md'
```

## Public visibility (alternative model)

Separate from per-page publish flags, mark pages with `visibility: public` in frontmatter:

<CodeGroup>
  ```bash Read public file theme={null}
  curl 'http://localhost:3333/api/kiwi/public/file?path=concepts/open.md'
  ```

  ```bash Browse public tree theme={null}
  curl 'http://localhost:3333/api/kiwi/public/tree?path='
  ```
</CodeGroup>

<Note>
  Non-public pages return `404` to avoid leaking existence.
</Note>

## Related documentation

<CardGroup cols={2}>
  <Card title="Web UI" icon="window" href="/guides/web-ui#publishing">
    Publish toggle in the page header.
  </Card>

  <Card title="Utilities API" icon="screwdriver-wrench" href="/api/utilities">
    Share links and public routes.
  </Card>
</CardGroup>
