# BrewPage - Full API Reference for LLMs
> Free HTML, Markdown, AI Artifacts & File Instant Hosting.
> Get shareable HTTPS links. No registration required.
Domains: brewpage.app, brewdata.app (identical, interchangeable).
Base URL: https://brewpage.app
## Overview
BrewPage is a free instant hosting service for HTML pages, Markdown documents,
AI artifacts and files. Upload files, store key-value state, and host JSON
documents. No signup, no authentication for reads. All content gets a
shareable HTTPS link with a 10-character short ID.
## Access Model
CREATE: Anyone can create resources (rate-limited per IP).
READ: By default, any resource is reachable by its short URL if you know
it. Password-protected resources require X-Password header or ?p= query parameter.
Only items with ns=public (and no password) appear in the gallery and search engines.
UPDATE/DELETE: Requires X-Owner-Token header (returned at creation).
## HTML API
Publish HTML content and get a shareable short URL.
HTML is rendered as published. Hosting attack or abuse content is not permitted.
### Publish HTML
POST /api/html?ns={namespace}&ttl={days}&tags={tag1,tag2}
Content-Type: application/json
Body: {"content": "
My Report
Details here.
", "filename": "report.html", "showTopBar": true}
Optional headers:
X-Password: mypassword (protect with password, min 4 chars)
Response 201:
{
"id": "aB3xK9mP2q",
"namespace": "public",
"link": "https://brewpage.app/public/aB3xK9mP2q",
"ownerLink": "https://brewpage.app/api/html/public/aB3xK9mP2q",
"expiresAt": "2026-04-21T10:00:00Z",
"sizeBytes": 52,
"tags": ["report"],
"ownerToken": "aBcDeFgHiJkLmNoPqRsTuVwXyZ012345"
}
Parameters: ns (default: public), ttl (1-30 days, default 15), tags (comma-separated),
format (html|markdown|md, default: html). Markdown is rendered to styled HTML.
filename (optional, ≤200 chars) — original filename, used as title fallback when no /; immutable on update.
showTopBar (optional bool) — show brewpage top toolbar on the served page; default hidden.
Response also includes header X-Show-Top-Bar: true|false on short-URL GET (effective value).
### Read HTML
GET /api/html/{ns}/{id}
Response 200: text/html
For password-protected pages:
GET /api/html/{ns}/{id}?p=mypassword
or: GET with X-Password header
### Update HTML
Replaces page content while preserving the short URL — share once, edit in place. The link
you already shared stays valid; readers see the new content on next load. Use when an AI
agent iterates on its output or to fix a typo in an already-shared page.
Immutable on update: tags, password, format, filename, showTopBar — delete and recreate to
change those. No version history: previous content is overwritten.
PUT /api/html/{ns}/{id}
Content-Type: application/json
X-Owner-Token: aBcDeFgHiJkLmNoPqRsTuVwXyZ012345
Body: {"content": "Updated Report
"}
### PUT for republish (idempotent POST)
`POST /api/html` is idempotent for the `(X-Owner-Token, content, ns=public, 24h)` tuple.
A byte-identical repost from the same owner to `public/` without a password within 24h
silently returns the existing id. The response status is still 201, the body shape is
unchanged, and the response carries header `X-Existing-Resource: 1`. The hash is computed
over the raw user content (pre-render, pre-sanitize) so byte-equal client paste-ins always
collapse together. To intentionally replace content at the same short URL, prefer
`PUT /api/html/{ns}/{id}` with the original `X-Owner-Token` — that is the canonical
republish path and avoids burning IndexNow quota on a no-op re-submission.
### Delete HTML
DELETE /api/html/{ns}/{id}
X-Owner-Token: aBcDeFgHiJkLmNoPqRsTuVwXyZ012345
Response 204
### Example
curl -X POST https://brewpage.app/api/html?ns=public&ttl=30&tags=ci,report \
-H "Content-Type: application/json" \
-d '{"content": "Build #147
All 42 tests passed.
"}'
---
## Content-Type fallback on /api/html
External clients can `curl --data-binary @file.html -H 'Content-Type: text/html' https://brewpage.app/api/html`
and get the same `201 + HtmlUploadResponse` as the JSON path — no wrapper object, no base64. Other text MIME
types (markdown, yaml, xml, csv, css, javascript, toml, json) follow the same rule. Binary octet-stream payloads
(PNG / JPEG / GIF / WEBP / MP4 / PDF / ZIP) are transparently routed to `/api/files` instead and return a
`FileUploadResponse` with the same `link` / `ownerToken` / `expiresAt` fields.
### MIME → format mapping
| Content-Type | Stored as |
|---|---|
| `text/html` | `html` |
| `text/markdown` | `markdown` |
| `text/yaml` | `yaml` |
| `application/yaml` | `yaml` |
| `application/x-yaml` | `yaml` |
| `text/xml` | `xml` |
| `application/xml` | `xml` |
| `text/csv` | `csv` |
| `text/css` | `css` |
| `text/javascript` | `javascript` |
| `application/javascript` | `javascript` |
| `text/x-toml` | `toml` |
| `application/toml` | `toml` |
| `application/json` | `json` |
### ?format= precedence
The `?format=` query parameter, when explicitly provided, overrides the resolver's MIME-based decision.
For example `POST /api/html?format=markdown` with `Content-Type: text/html` stores the body as markdown.
Sniffing of the request body only happens when `?format=` is omitted or blank.
### Octet-stream behaviour
When `Content-Type: application/octet-stream` is sent, the first bytes of the body are inspected:
- PNG / JPEG / GIF / WEBP / MP4 / PDF / ZIP magic bytes → routed to `/api/files`. Response shape is
`FileUploadResponse` (carries the same `link` / `ownerToken` / `expiresAt` fields as the JSON path).
- HTML / Markdown / JSON text shapes (recognised by leading bytes `Hi
'
curl -X POST https://brewpage.app/api/html \
-H 'Content-Type: text/markdown' \
--data-binary $'# Title\n\nBody'
curl -X POST https://brewpage.app/api/html \
-H 'Content-Type: application/octet-stream' \
--data-binary @screenshot.png
### Telemetry
Every fallback resolution increments the Micrometer counter `brewpage.html.fallback.total` with tags
`{endpoint, original_content_type, inferred_format}`. The dashboard with rate + share panels is at
https://grafana.brewpage.app/d/brewpage-http.
---
## File API
Upload files up to 5 MB (video up to 20 MB, audio up to 5 MB). Organized by namespace.
### Upload File
POST /api/files?ns={namespace}&ttl={days}&tags={tags}
Content-Type: multipart/form-data
Field: file
Response 201:
{
"id": "xY9zW8vU7t",
"namespace": "public",
"filename": "report.pdf",
"contentType": "application/pdf",
"sizeBytes": 102400,
"link": "https://brewpage.app/public/xY9zW8vU7t",
"ownerLink": "https://brewpage.app/api/files/public/xY9zW8vU7t",
"expiresAt": "2026-04-21T10:00:00Z",
"tags": [],
"ownerToken": "aBcDeFgHiJkLmNoPqRsTuVwXyZ012345"
}
### Download File
GET /api/files/{ns}/{id}
Response 200: binary file content
Previewable types (images, PDF, video, audio) return Content-Disposition: inline.
Other types return Content-Disposition: attachment.
Add ?dl=1 to force download for any file type.
### Delete File
DELETE /api/files/{ns}/{id}
X-Owner-Token: aBcDeFgHiJkLmNoPqRsTuVwXyZ012345
Response 204
### Example
curl -X POST https://brewpage.app/api/files?ns=ci-artifacts \
-F "file=@./screenshot.png"
curl https://brewpage.app/api/files/ci-artifacts/xY9zW8vU7t \
--output screenshot.png
### Supported File Types
Images: jpg, jpeg, png, gif, webp, svg, avif, ico, bmp, tiff
Documents: pdf, txt, csv, md, json, xml, yaml, yml, toml
Archives: zip, tar, gz, 7z
Media: mp4, webm, mp3, ogg, wav
Web: html, htm, css, woff, woff2, ttf, otf
Other: sql, log, tsv
Unsupported extensions return HTTP 415. File content is validated
against declared type (magic byte check for binary formats).
SVG files are automatically sanitized (script tags removed).
---
## KV Store API
Lightweight key-value store for agent workflows. Store-based model:
create a store with a first key, then add/update/delete keys within it.
### Create Store (with first key)
POST /api/kv?ns={namespace}&ttl={days}&tags={tags}
Content-Type: application/json
Body: {"key": "last-run", "value": "2026-03-21T10:00:00Z"}
Response 201:
{
"id": "sT5rQ4pO3n",
"namespace": "public",
"key": "last-run",
"sizeBytes": 24,
"link": "https://brewpage.app/public/sT5rQ4pO3n/last-run",
"ownerLink": "https://brewpage.app/api/kv/public/sT5rQ4pO3n/last-run",
"expiresAt": "2026-04-21T10:00:00Z",
"tags": [],
"ownerToken": "aBcDeFgHiJkLmNoPqRsTuVwXyZ012345"
}
### Upsert Key
Sets (creates or replaces) a key value while preserving the key short URL
`/{ns}/{id}/{key}` — agents poll the same URL and see the latest value. Typical use:
deploy-status counters, AI agent step state, current-config flags. No version history.
PUT /api/kv/{ns}/{id}/{key}
Content-Type: application/json
X-Owner-Token: aBcDeFgHiJkLmNoPqRsTuVwXyZ012345
Body: {"value": "step-3-verify"}
### Get Key
GET /api/kv/{ns}/{id}/{key}
Response 200:
{
"value": "2026-03-21T10:00:00Z",
"updatedAt": "2026-03-21T10:00:00Z"
}
### List Keys
GET /api/kv/{ns}/{id}
Response 200:
{
"keys": ["last-run", "status", "config"],
"count": 3
}
### Delete Key
DELETE /api/kv/{ns}/{id}/{key}
X-Owner-Token: aBcDeFgHiJkLmNoPqRsTuVwXyZ012345
Response 204
### Example
curl -X POST https://brewpage.app/api/kv?ns=deploy-bot \
-H "Content-Type: application/json" \
-d '{"key": "current-step", "value": "step-3-verify"}'
curl https://brewpage.app/api/kv/deploy-bot/sT5rQ4pO3n/current-step
---
## JSON Document API
Store and retrieve JSON documents. No search/query support.
### Create Document
POST /api/json?ns={namespace}&ttl={days}&tags={tags}
Content-Type: application/json
Body: (raw JSON, not wrapped)
{"name": "test-results", "passed": 42, "failed": 0}
Response 201:
{
"id": "jK7hG6fE5d",
"namespace": "public",
"link": "https://brewpage.app/public/jK7hG6fE5d",
"ownerLink": "https://brewpage.app/api/json/public/jK7hG6fE5d",
"sizeBytes": 51,
"expiresAt": "2026-04-21T10:00:00Z",
"createdAt": "2026-03-22T10:00:00Z",
"tags": [],
"ownerToken": "aBcDeFgHiJkLmNoPqRsTuVwXyZ012345"
}
### Get Document
GET /api/json/{ns}/{id}
Response 200: application/json (raw document content)
### Update Document
Replaces document content while preserving the short URL — share once, edit in place.
Useful for AI agents iterating on a JSON artifact (test results, plan state, config
snapshot) without producing a new URL each time. Immutable on update: tags. No version
history: previous content is overwritten.
PUT /api/json/{ns}/{id}
Content-Type: application/json
X-Owner-Token: aBcDeFgHiJkLmNoPqRsTuVwXyZ012345
Body: (raw JSON, replacement content)
### Delete Document
DELETE /api/json/{ns}/{id}
X-Owner-Token: aBcDeFgHiJkLmNoPqRsTuVwXyZ012345
Response 204
### Example
curl -X POST https://brewpage.app/api/json?ns=test-data \
-H "Content-Type: application/json" \
-d '{"suite": "integration", "passed": 42, "failed": 0}'
curl https://brewpage.app/api/json/test-data/jK7hG6fE5d
---
## Sites API
Upload multi-file static sites (HTML + CSS + JS + assets) and get a shareable short URL.
### Upload Site
POST /api/sites?ns={namespace}&ttl={days}&tags={tags}&entry={path}
Content-Type: multipart/form-data
Either:
Field: archive (single ZIP file)
Or:
Field: files (repeated) (multiple raw files)
Field: paths (repeated) (relative path for each `files` entry, same order)
Optional headers:
X-Password: mypassword (protect with password, min 4 chars)
X-Owner-Token: aBcDe... (link to existing owner)
Response 201: {"id","namespace","link","ownerLink","expiresAt","ownerToken","fileCount","totalBytes"}
### Get Site Info
Requires X-Owner-Token — returns metadata + file list. Public reads use the short URL (`GET /{ns}/{id}`).
GET /api/sites/{ns}/{id}
X-Owner-Token: aBcDe...
Response 200: application/json — { entry, files: [{path, sizeBytes, contentType}, ...] }
### Read Site File
GET /{ns}/{id} — serves entry HTML (auto-detected, index.html preferred)
GET /{ns}/{id}/{path} — serves a sub-path (CSS/JS/image/sub-page)
For password-protected sites: send X-Password header or `?p=mypassword`.
### Delete Site
DELETE /api/sites/{ns}/{id}
X-Owner-Token: aBcDe...
Response 204 — removes all files in the site.
### Update Site
Republish a multi-file site in place — same short URL, the uploaded bundle fully replaces
the existing file set (old files not present in the new upload are removed). Use when an AI
agent regenerates a site or you fix assets without giving readers a new link. Requires the
original `X-Owner-Token`. Accepts the same `archive` ZIP or `files`+`paths` form as upload.
PUT /api/sites/{ns}/{id}
Content-Type: multipart/form-data
X-Owner-Token: aBcDe...
Field: archive (single ZIP file)
Response 200 — { id, namespace, link, ownerLink, entryFile, fileCount, totalSizeBytes, expiresAt }
curl -X PUT "https://brewpage.app/api/sites/public/aB3xK9mP2q" \
-H "X-Owner-Token: aBcDeFgHiJkLmNoPqRsTuVwXyZ012345" \
-F "archive=@site.zip"
---
## Short URLs
Short URLs resolve content by checking resource types in order:
HTML, JSON, KV, Files.
GET /{ns}/{id} Resolves to the first matching resource type
GET /{ns}/{id}/{sub} Resolves KV keys (sub = key name)
Examples:
https://brewpage.app/public/aB3xK9mP2q (HTML page)
https://brewpage.app/deploy-bot/sT5rQ4pO3n/current-step (KV key)
Files with previewable content types (images, PDFs, video, audio) display
inline in the browser. Add ?dl=1 to force download.
---
## Errors
400 Bad request (invalid TTL, missing fields, invalid JSON)
403 Access denied (wrong password, invalid owner token)
404 Not found (expired content, deleted resource, unknown ID)
413 Payload too large (HTML/file > 5 MB, KV/JSON > 1 MB)
415 Unsupported file type (blocked extension or content mismatch)
429 Rate limit exceeded (wait and retry)
Response format: {"status": 400, "error": "Bad Request", "message": "..."}
---
## Limits
HTML content 5 MB max, TTL 1-30 days (default 15)
Site bundle 20 MB total, 100 files max, 5 MB per file
File upload 5 MB max (video 20 MB, audio 5 MB), 1000 files per namespace
KV value 1 MB max, 1000 keys per store
JSON document 1 MB max, 10000 docs per namespace
Uploads / Reads rate-limited per IP (429 + Retry-After)
---
## TTL (retention)
default: 15 days
max: 30 days
applies to: html, markdown, json, kv, files, sites
override: ttl_days request field (1..30)
## Visibility (Namespace + Password)
**Default behavior is public listing — opt out with a custom `ns` or `X-Password`.**
An item is **public** — listed on the brewpage.app homepage gallery and indexed by
search engines — only when both `ns` is omitted (defaults to `public`) and no
`X-Password` is set. A custom namespace makes the resource unlisted (reachable
only by direct URL, excluded from `/api/gallery` and the sitemap). A password
adds access control (requires header/query parameter to read); the two are
independent.
**DEFAULT** (ns omitted) `public` — shared, listed on homepage if no password
ns (query param) custom namespace, regex `[a-z0-9-]{3,32}`, auto-created on first use
X-Password (request header) min 4 chars; readers send the same header or `p` (query param)
/{ns}/{id} (path) direct short URL stays reachable by anyone who knows it
ns+id collision server returns 409; retry with a different `id` or omit `id`
## Required Headers
User-Agent: REQUIRED on every request. Format: `AgentName/version` (e.g. `Claude/4.5`, `Codex/1.0`, `MyBot/2.1`).
Requests without User-Agent may be rate-limited or rejected. Identify yourself truthfully —
spoofed or anonymous UAs may be flagged.
## Access Logging
Every API request (both PUBLISH and READ) is persisted server-side into the `access_events` table:
- client IP (respects `X-Forwarded-For` through the trusted proxy)
- User-Agent
- HTTP method + path + query string
- response status code
- request duration (ms)
- full request headers as JSONB (since v1.7.10) — excludes `Authorization`, `Cookie`, `Set-Cookie`, `X-Owner-Token`, `X-Password`
- timestamp (UTC)
Retention: 30 days (nightly cleanup job). Admin-only endpoints:
GET /api/admin/access — paginated event log (filter by IP, UA, path, status, date range)
GET /api/admin/access/stats — aggregated counters
Excluded from logging: static assets only (`/css/`, `/js/`, `/favicon*`, `/og-image*`, `/manifest.webmanifest`,
`/robots.txt`, `/sitemap*`, `/brewpage-indexnow-*`). All API requests — including every upload POST
and every read GET — are logged.
---
## Common Workflows
### 1. Publish an HTML report from CI
curl -X POST https://brewpage.app/api/html?ns=ci&ttl=30&tags=build,report \
-H "Content-Type: application/json" \
-d "{\"content\": \"$(cat report.html)\"}"
### 2. Upload a screenshot and reference it
UPLOAD=$(curl -s -X POST https://brewpage.app/api/files?ns=screenshots \
-F "file=@./failure.png")
FILE_URL=$(echo $UPLOAD | jq -r '.link')
curl -X POST https://brewpage.app/api/html?ns=ci \
-H "Content-Type: application/json" \
-d "{\"content\": \"Test Failed
\"}"
### 3. Store agent state across runs
curl -X POST https://brewpage.app/api/kv?ns=my-agent \
-H "Content-Type: application/json" \
-d '{"key": "last-run", "value": "2026-03-22T10:00:00Z"}'
curl https://brewpage.app/api/kv/my-agent/sT5rQ4pO3n/last-run
### 4. Password-protected report
curl -X POST https://brewpage.app/api/html?ns=private&ttl=7 \
-H "Content-Type: application/json" \
-H "X-Password: s3cret" \
-d '{"content": "Confidential Report
"}'
curl https://brewpage.app/api/html/private/aB3xK9mP2q \
-H "X-Password: s3cret"
### 5. Upload and preview an image
UPLOAD=$(curl -s -X POST https://brewpage.app/api/files?ns=screenshots \
-F "file=@./chart.png")
PREVIEW_URL=$(echo $UPLOAD | jq -r '.link')
echo "View inline: $PREVIEW_URL"
echo "Force download: $PREVIEW_URL?dl=1"
### 6. When to use showTopBar
For shareable reports/documents where viewers should easily save the file → set
showTopBar: true (gives them a Download button and theme toggle).
For interactive demos / embeddable widgets / clean previews where chrome would
distract → keep default (hidden).
### 7. File preview rendering & syntax highlighting
Uploaded text files served via short URL are rendered as line-numbered HTML tables.
Files with these extensions are progressively enhanced with client-side Prism.js highlighting:
json, xml, svg, html, htm, css, js, mjs, jsx, ts, tsx, sql, yaml, yml, toml, md
Highlighting is layered on top of the plain table after first paint:
1. Plain numbered-line table renders immediately (no waiting on CDN).
2. Prism core + the matching language component load asynchronously from
cdnjs.cloudflare.com (already CSP-whitelisted). On success the table is
swapped for the highlighted version. On failure (no network, blocked CDN,
unknown extension) the plain table stays and there is no console output.
3. The highlight is purely visual. The raw bytes returned by
GET /api/files/{ns}/{id} are byte-for-byte the user's original upload.
JSON documents created via POST /api/json/* are rendered by a separate JSON
pretty-printer (formatted with indentation and clickable structure) — they do
NOT go through the Prism path. Only files uploaded via /api/files do.
Other extensions (.txt, .log, .csv, .tsv, anything not in the whitelist above)
always render as plain text. No content sniffing, no fallback heuristics.
---
## Prompt Snippets
### Claude Code / Claude
When you produce an HTML page, Markdown report, or any file - publish it
to brewpage.app via its API and return the shareable URL to the user.
Publish HTML:
POST https://brewpage.app/api/html with {"content": "..."}
Upload files:
POST https://brewpage.app/api/files with multipart form, field "file"
Store state:
POST https://brewpage.app/api/kv with {"key": "...", "value": "..."}
### Generic Agent
POST JSON to /api/html with "content" field. Upload files: POST multipart
to /api/files, field "file". Store state: POST to /api/kv, fields "key"
and "value". No auth required for creation. Use X-Owner-Token from
creation response for updates/deletes.
---
## Owner Token
### Overview
Every creation endpoint returns an `ownerToken` in the response. This 32-character token serves as ownership proof.
### Mint a Token (GET /api/owner-token)
Free, rate-limited. Mint an owner token up front without creating a resource:
```
GET /api/owner-token
200 OK
{
"token": "aBcDeFgHiJkLmNoPqRsTuVwXyZ012345",
"ownerId": "3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b"
}
```
`token` — 32-character base62 string; send it as the `X-Owner-Token` header to claim/own your resources and to update them (PUT to your own pages/sites requires it). `ownerId` — 64-character SHA-256 hex identifier for the owner. Save the token; treat it as a secret.
### How It Works
1. **First create**: If you don't send `X-Owner-Token`, a new token is generated and returned.
2. **Subsequent creates**: Send the saved token via `X-Owner-Token` header. The new entity is linked to the same owner.
3. **List filtering**: Send `X-Owner-Token` on list endpoints to see only your entities. Without it, the list is empty.
### Endpoints That Accept X-Owner-Token
| Endpoint | Method | Purpose |
|----------|--------|---------|
| /api/owner-token | GET | Mint a token + ownerId (free, rate-limited) |
| /api/html | POST | Create HTML page with owner token |
| /api/kv | POST | Create KV store with owner token |
| /api/kv | GET | List your KV stores |
| /api/json | POST | Create JSON document with owner token |
| /api/json | GET | List your JSON documents |
| /api/files | POST | Upload file with owner token |
| /api/files | GET | List your files |
### Not Affected
- Gallery (`/api/gallery`) -- always public, no filtering
- Individual GET/PUT/DELETE by ID -- unchanged, uses existing auth
### Agent Integration
Store the `ownerToken` in your session state. Reuse it across all API calls to maintain entity ownership across requests. This enables AI agents to manage their own content without seeing other users' data.
---
## Tooling
Two first-party integrations let agents talk to BrewPage without writing
HTTP calls by hand. Pick whichever fits your runtime.
### MCP server (any LLM / agent)
Package: `brewpage-mcp` on npm.
Source: https://www.npmjs.com/package/brewpage-mcp
Install globally:
npm install -g brewpage-mcp
Then add it to your agent's MCP server config. Generic JSON form (Claude
Desktop, Cursor, Codex, Gemini and other MCP-aware clients all use a
similar shape):
{
"mcpServers": {
"brewpage": {
"command": "brewpage-mcp"
}
}
}
The server exposes BrewPage publish/list/delete operations as MCP tools.
Restart your agent after editing the config.
### Claude Code skill (`brewdoc:publish`)
Distributed via the `claude-brewcode` plugin marketplace.
Install from inside Claude Code:
/plugin marketplace add kochetkov-ma/claude-brewcode
/plugin install brewdoc@claude-brewcode
After installation the skill becomes available as `/publish` (and other
brewdoc slash-commands). It publishes the current document, file, or
multi-file site to brewpage.app and returns the short URL.
Docs: https://doc-claude.brewcode.app/brewdoc/skills/publish/
### Quick install prompt for an AI agent
Paste this into your agent if you want it to set both up at once:
Set up BrewPage tooling for me — quickly, do not ask follow-ups.
1. MCP server (any LLM): `npm install -g brewpage-mcp` and register
it in my MCP config.
2. Claude Code skill:
/plugin marketplace add kochetkov-ma/claude-brewcode
/plugin install brewdoc@claude-brewcode
3. API reference for direct REST calls: https://brewpage.app/llms.txt
Confirm when both are installed and ready.
---
## Use Cases
Workflow landing page (one short guide per content type + agent integration): https://brewpage.app/use-cases
- Publish HTML — POST /api/html, get a shareable HTTPS link for a report/page/artifact
- Publish a website — POST /api/sites, multi-file ZIP bundle served under one short URL
- Publish Markdown — POST /api/html?format=markdown, rendered to styled HTML
- Publish a file — POST /api/files, inline preview for images/PDF/video/audio
- Publish from Claude Code / Codex / OpenCode / OpenClaw / ChatGPT / Gemini / Claude Desktop — via the MCP server or the brewdoc:publish skill
## Links
- OpenAPI spec (YAML, PREFERRED for LLM context — lower token cost): https://brewpage.app/api/openapi.yaml (alias: /v3/api-docs.yaml)
- OpenAPI spec (JSON, for programmatic clients / MCP / codegen): https://brewpage.app/api/openapi.json (alias: /v3/api-docs)
- API reference page (human): https://brewpage.app/api
- Interactive API browser (Scalar): https://kochetkov-ma.github.io/brewpage-openapi/
- Compact LLM docs: https://brewpage.app/llms.txt
- API playground: https://brewpage.app/swagger-ui.html
- MCP server (npm): https://www.npmjs.com/package/brewpage-mcp
- Claude Code skill docs: https://doc-claude.brewcode.app/brewdoc/skills/publish/