# Blogs and docs

Resolve a post by its folder path, preview drafts, and manage tags and authors.

Blogs and docs are the same implementation over two separate trees. Everything
here applies to both — swap `/api/blogs` for `/api/docs`.

Posts live in folders, and the natural way to read one is by the path a visitor
would use:

```bash
curl -G https://api.console.buildbase.app/api/blogs/path \
  -H "Authorization: $BUILDBASE_TOKEN" \
  --data-urlencode 'path=engineering/why-we-moved-off-cron'
```

> **Note:**
  Create folders and posts in the BuildBase console. Folder structure is
  editorial, so it is managed there rather than through the API.


## Reading

| Method | Path              | Purpose                                        |
| ------ | ----------------- | ---------------------------------------------- |
| `GET`  | `/api/blogs`      | List posts, paginated, with the usual `filter` |
| `GET`  | `/api/blogs/:id`  | One post by id                                 |
| `GET`  | `/api/blogs/path` | One post by folder path                        |
| `GET`  | `/api/blogs/tree` | The folder tree                                |

`/tree` is what renders a sidebar — it returns the folder structure rather than
the posts themselves, so you can build navigation without pulling every post
body.

## Paths

`path` is the folder path plus the post slug, joined with `/`:

```
engineering/why-we-moved-off-cron
└─ folder ─┘ └────── post slug ──────┘
```

The last segment is always the post; everything before it is folder structure.
A post at the root is just its slug.

## Previewing drafts

Unpublished posts are excluded by default. Add `draftPreview=true` to include
them:

```bash
curl -G https://api.console.buildbase.app/api/blogs/path \
  -H "Authorization: $BUILDBASE_TOKEN" \
  --data-urlencode 'path=engineering/upcoming-post' \
  --data-urlencode 'draftPreview=true'
```

Wire this to a preview route your editors can reach, and leave it off in the
path your public site renders. Since the endpoint needs a token either way,
"leaving it off" means your backend decides — a visitor cannot set it
themselves.

## Tags and authors

Both are managed with dedicated endpoints rather than through the post body, so
a retag does not rewrite the content:

| Method  | Path                     | Purpose                    |
| ------- | ------------------------ | -------------------------- |
| `PATCH` | `/api/blogs/:id/tags`    | Replace the post's tags    |
| `PATCH` | `/api/blogs/:id/authors` | Replace the post's authors |

Both **replace** rather than append. Read the current list, add to it, and send
the whole array back.

## Writing

| Method   | Path             | Purpose       |
| -------- | ---------------- | ------------- |
| `POST`   | `/api/blogs`     | Create a post |
| `PATCH`  | `/api/blogs/:id` | Update a post |
| `DELETE` | `/api/blogs/:id` | Delete a post |

The console is the expected authoring surface. The write endpoints are for
migrations and syncing from another system — importing an existing blog, for
instance.

## Rendering on a public site

These endpoints need a token, so the browser never calls them. Two workable
shapes:

- **Build time.** Fetch posts during your site build and render static pages.
  Fastest, and the token stays in CI.
- **Server-side.** Fetch in a server component or route handler, cache the
  result, and serve HTML. Use this when editors need changes live without a
  rebuild.

Either way the token stays server-side. See the
[admin API](/reference/admin-api) for token handling.

## Next Steps

- [Content overview](/content/overview) — the other content types.
- [Assets](/assets/overview) — images embedded in posts.
