dorfteich/docs/manual/api-guide.md
Claude Fable 5 ffcc337ed0
Some checks failed
CD / Build and push images (push) Successful in 3m57s
CD / Deploy to Test (push) Successful in 9s
CI / Lint, typecheck, test (push) Failing after 4m16s
CI / Auth e2e pack (push) Has been skipped
CI / Import/export fidelity gate (push) Has been skipped
CI / Build container images (push) Has been skipped
CD / Smoke tests against Test (push) Successful in 1m19s
CD / Promote to Int (push) Successful in 11s
Page-tree parity for the public REST API and MCP (#110)
The slug-based machine surfaces now see and shape the hierarchy:

- REST: page list/detail carry parent (the parent page's slug, nulled
  when the token's user may not read it — same no-leak rule as the
  internal list); create accepts parent; PATCH accepts parent
  (slug nests, null moves to the top level, appended at the end of the
  new sibling group via the new PagesService.moveToEnd). Cycle/depth
  refusals keep their regular error codes. OpenAPI updated.
- MCP: list_pages returns parent, create_page takes an optional parent
  slug, update_page moves with parent (slug|null); tool errors carry
  the api code (page_cycle covered in the e2e pack).
- ZIP export deliberately stays flat — noted in features.md; the
  hierarchy is organizational only.

e2e: REST pack covers nested create, list shape, move/root-move, 409
page_cycle, 404 unknown parent; MCP pack covers nested create, list
parent, and the cycle tool error.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 10:49:52 +02:00

135 lines
4.8 KiB
Markdown

# API guide
_Deutsche Fassung: [docs/de/manual/api-guide.md](../de/manual/api-guide.md)_
How to talk to Dorfteich from scripts and integrations. The public REST
API lives at `/api/public/v1`; its machine-readable description is
served at `/api/public/v1/openapi.json`.
## Switching it on
The API is **off by default**, twice:
1. A **site admin** enables the instance switch (Admin → Settings →
Public API).
2. Each **pond** that should be reachable opts in (pond settings →
"Expose this pond through the public API").
Anything not enabled answers `404` — indistinguishable from an instance
without the feature.
## Personal access tokens
Create tokens under **Settings → API tokens**: a name, a scope
(`read` or `read+write`), an optional expiry date, and optionally a
restriction to selected ponds. The secret (`dt_pat_…`) is shown **once**
— copy it immediately. Tokens are revocable and show their last use.
A token acts **as you**: it can read and write exactly what you can,
narrowed by its scope and pond restriction — never more. Token
management itself always requires the browser session; a leaked token
cannot mint new tokens.
Authenticate with a bearer header:
```sh
curl -H "Authorization: Bearer dt_pat_..." \
https://wiki.example.com/api/public/v1/me
```
`GET /me` is the smoke test — it returns your user, the token scope,
and any pond restriction.
## Reading
```sh
# The ponds this token can reach
curl -H "$AUTH" https://wiki.example.com/api/public/v1/ponds
# Pages of a pond: slug, title, parent (page-tree slug), labels, timestamps
curl -H "$AUTH" https://wiki.example.com/api/public/v1/ponds/team/pages
# One page — Markdown source AND rendered, sanitized HTML
curl -H "$AUTH" https://wiki.example.com/api/public/v1/ponds/team/pages/meeting-notes
# Full-text search (optionally ?pond=<slug>&label=<labelId>)
curl -H "$AUTH" "https://wiki.example.com/api/public/v1/search?q=seerose"
# The whole pond as a Markdown ZIP
curl -H "$AUTH" -o team.zip \
https://wiki.example.com/api/public/v1/ponds/team/export/markdown
```
Search snippets mark hits with `**…**`; results carry pond and page
slugs for follow-up calls.
## Writing (requires the `write` scope)
```sh
# Create a page from Markdown (optional "parent": a page slug nests it)
curl -H "$AUTH" -H 'Content-Type: application/json' \
-d '{"title": "Meeting notes", "markdown": "# Agenda\n\n- Ducks\n"}' \
https://wiki.example.com/api/public/v1/ponds/team/pages
# Rename, REPLACE the content, and/or move in the page tree
# ("parent": <slug> nests the page, "parent": null moves it to the top level)
curl -X PATCH -H "$AUTH" -H 'Content-Type: application/json' \
-d '{"markdown": "New content."}' \
https://wiki.example.com/api/public/v1/ponds/team/pages/meeting-notes
# Move a page to the trash
curl -X DELETE -H "$AUTH" \
https://wiki.example.com/api/public/v1/ponds/team/pages/meeting-notes
```
A content `PATCH` **replaces** the whole page. It is applied through the
live collaborative document: anyone editing the page at that moment sees
the change appear, nothing forks, and the previous state remains in the
version history as a restorable snapshot (the update itself shows up as
a version named "API update").
## Labels
```sh
GET /ponds/{pond}/labels # the label tree
POST /ponds/{pond}/labels # {name, color?, parentId?}
PATCH /ponds/{pond}/labels/{labelId} # rename/recolor/move in one call
DELETE /ponds/{pond}/labels/{labelId}
PUT /ponds/{pond}/pages/{page}/labels/{labelId} # assign
DELETE /ponds/{pond}/pages/{page}/labels/{labelId} # unassign
```
Label-tree management needs pond-admin rights (like in the app).
## Comments
```sh
GET /ponds/{pond}/pages/{page}/comments?filter=all|open|resolved
POST /ponds/{pond}/pages/{page}/comments # {body, parentId?} — Markdown
POST /ponds/{pond}/pages/{page}/comments/{id}/resolve
DELETE /ponds/{pond}/pages/{page}/comments/{id}/resolve # reopen
```
The pond's comment policy applies exactly as in the app.
## Errors, limits, semantics
- Errors carry the uniform body `{ "code": "...", "message": "...",
"details": {...} }`. The `code` is stable and machine-checkable.
- **404 vs 403**: what you may not _read_ answers 404 (existence stays
hidden — including ponds without the API opt-in); a write on
something you may read but not change answers 403. A token without
the `write` scope gets `403 scope_required` on every write route.
- **Rate limit** per token; `429` responses carry a `Retry-After`
header.
- No cookies are involved anywhere — there is no CSRF surface, and
browser sessions cannot call the public API.
## Out of scope (for now)
Attachment upload, version endpoints, and webhooks are deliberately not
part of v1.
_Operator's view of the same feature (switches, security notes):
[`docs/self-hosting/public-api.md`](../self-hosting/public-api.md)._