trans2 / docs /en-US /reference /http-api.md
Mayo
docs: update to match current implementation
725264a unverified
---
title: HTTP API Reference
---
# HTTP API Reference
Koharu exposes a local HTTP API under:
```text
http://127.0.0.1:<PORT>/api/v1
```
This is the same API used by the desktop UI and the headless Web UI.
## Runtime model
Important current behavior:
- the API is served by the same process as the GUI or headless runtime
- the server binds to `127.0.0.1` by default; use `--host` to bind elsewhere
- the API and MCP server share the same loaded project, models, and pipeline state
- when no `--port` is provided, Koharu chooses a random local port
- everything except `/api/v1/downloads`, `/api/v1/operations`, and `/api/v1/events` returns `503 Service Unavailable` until the app finishes bootstrapping
## Resource model
The API is project-centric. A single project is open at a time and contains:
- a list of `Pages` indexed by `PageId`
- per-page `Nodes` (image layers, masks, text blocks) referenced by `NodeId`
- a content-addressed `Blob` store that holds raw image bytes by Blake3 hash
- a `Scene` snapshot built from those pieces, advanced by an `epoch` counter
- a history of `Op` mutations that can be undone or redone
Mutations always go through the history layer (`POST /history/apply`) so the scene, autosave, and event subscribers stay in sync.
## Common response shapes
Frequently used response types include:
- `MetaInfo` β€” app version and ML device label
- `EngineCatalog` β€” installable engine ids per pipeline stage
- `ProjectSummary` β€” id, name, path, page count, last opened
- `SceneSnapshot` β€” `{ epoch, scene }`
- `LlmState` β€” current LLM load state (status, target, error)
- `LlmCatalog` β€” local + provider models grouped by family
- `JobSummary` β€” `{ id, kind, status, error }`
- `DownloadProgress` β€” package id, byte counts, status
## Endpoints
### Meta
| Method | Path | Purpose |
| ------ | ----------- | ------------------------------------------ |
| `GET` | `/meta` | get app version and active ML backend |
| `GET` | `/engines` | list registered pipeline engines per stage |
### Fonts
| Method | Path | Purpose |
| ------ | ------------------------------------- | ---------------------------------------------------- |
| `GET` | `/fonts` | combined system + Google Fonts catalog for rendering |
| `GET` | `/google-fonts` | Google Fonts catalog as a standalone list |
| `POST` | `/google-fonts/{family}/fetch` | download and cache one Google Fonts family |
| `GET` | `/google-fonts/{family}/{file}` | serve the cached TTF/WOFF file |
### Projects
Every project lives under the managed `{data.path}/projects/` directory; clients never supply filesystem paths.
| Method | Path | Purpose |
| -------- | --------------------------------- | --------------------------------------------------------- |
| `GET` | `/projects` | list managed projects |
| `POST` | `/projects` | create a new project (body `{ name }`) |
| `POST` | `/projects/import` | extract a `.khr` archive into a fresh dir and open it |
| `PUT` | `/projects/current` | open a managed project by `id` |
| `DELETE` | `/projects/current` | close the current session |
| `POST` | `/projects/current/export` | export the current project; returns binary bytes |
`POST /projects/current/export` accepts `{ format, pages? }` where `format` is one of `khr`, `psd`, `rendered`, `inpainted`. When the format produces multiple files, the response is `application/zip`.
### Pages
| Method | Path | Purpose |
| ------ | --------------------------------------- | ---------------------------------------------------- |
| `POST` | `/pages` | create pages from N uploaded image files (multipart) |
| `POST` | `/pages/from-paths` | Tauri-only fast path that imports by absolute path |
| `POST` | `/pages/{id}/image-layers` | add a Custom image node from an uploaded file |
| `PUT` | `/pages/{id}/masks/{role}` | upsert a mask node from raw PNG bytes |
| `GET` | `/pages/{id}/thumbnail` | get the page thumbnail (cached as WebP) |
`role` is `segment` or `brushInpaint`. `POST /pages` accepts an optional `replace=true` field; the import is filename-sorted using natural order.
### Scene and blobs
| Method | Path | Purpose |
| ------ | ------------------- | ------------------------------------------------------------- |
| `GET` | `/scene.json` | full scene snapshot for web/UI clients |
| `GET` | `/scene.bin` | postcard-encoded `Snapshot { epoch, scene }` for Tauri client |
| `GET` | `/blobs/{hash}` | raw blob bytes by Blake3 hash |
`/scene.bin` includes the current epoch in the `x-koharu-epoch` response header.
### History (mutations)
All scene mutations go through here. Each response returns `{ epoch }`.
| Method | Path | Purpose |
| ------ | ------------------- | ---------------------------------------- |
| `POST` | `/history/apply` | apply an `Op` (including `Op::Batch`) |
| `POST` | `/history/undo` | revert the last applied op |
| `POST` | `/history/redo` | re-apply the last undone op |
`Op` is the discriminated union that covers add/remove/update node, add/remove page, batch, and other scene transitions. The body is the JSON-tagged variant.
### Pipelines
| Method | Path | Purpose |
| ------ | ------------- | -------------------------------------- |
| `POST` | `/pipelines` | start a pipeline run as an operation |
Body fields:
- `steps` β€” engine ids to run in order (validated against the registry)
- `pages` β€” optional subset of `PageId`s; omit to process the whole project
- `region` β€” optional bounding box for the inpainter (repair-brush flow)
- `targetLanguage`, `systemPrompt`, `defaultFont` β€” optional per-run overrides
The response carries an `operationId`. Progress and completion arrive on `/events` as `JobStarted`, `JobProgress`, `JobWarning`, and `JobFinished`.
### Operations
`/operations` is the unified registry for in-flight and recently-completed jobs (pipelines + downloads).
| Method | Path | Purpose |
| -------- | --------------------- | ---------------------------------------------------------- |
| `GET` | `/operations` | snapshot of every in-flight or recent operation |
| `DELETE` | `/operations/{id}` | cancel a pipeline run; best-effort eviction for downloads |
### Downloads
| Method | Path | Purpose |
| ------ | ------------------- | ------------------------------------------ |
| `GET` | `/downloads` | snapshot of every active or recent download |
| `POST` | `/downloads` | start a model-package download (`{ modelId }`) |
`modelId` is a package id declared via `declare_hf_model_package!` (e.g. `"model:comic-text-detector:yolo-v5"`). The response is `{ operationId }` reusing the package id.
### LLM control
The loaded model is a singleton resource at `/llm/current`.
| Method | Path | Purpose |
| -------- | ---------------- | --------------------------------------------- |
| `GET` | `/llm/current` | current state (status, target, error) |
| `PUT` | `/llm/current` | load the given target (local or provider) |
| `DELETE` | `/llm/current` | unload / release the model |
| `GET` | `/llm/catalog` | list available local + provider-backed models |
`PUT /llm/current` accepts an `LlmLoadRequest`:
- provider targets β€” `{ kind: "provider", providerId, modelId }`
- local targets β€” `{ kind: "local", modelId }`
- optional `options { temperature, maxTokens, customSystemPrompt }`
`PUT /llm/current` returns `204` once the load task is queued. The actual ready state is published as `LlmLoaded` on `/events`.
### Config
| Method | Path | Purpose |
| -------- | --------------------------------------- | ----------------------------------------------- |
| `GET` | `/config` | read the current `AppConfig` |
| `PATCH` | `/config` | apply a `ConfigPatch`; persists and broadcasts |
| `PUT` | `/config/providers/{id}/secret` | save (or overwrite) a provider's API key |
| `DELETE` | `/config/providers/{id}/secret` | clear a provider's stored API key |
`AppConfig` exposes top-level `data`, `http`, `pipeline`, and `providers`:
- `data.path` β€” local data directory used for runtime, model cache, and projects
- `http { connectTimeout, readTimeout, maxRetries }` β€” shared HTTP client used by downloads and provider-backed requests
- `pipeline { detector, fontDetector, segmenter, bubbleSegmenter, ocr, translator, inpainter, renderer }` β€” engine id selected for each stage
- `providers[] { id, baseUrl?, apiKey? }` β€” saved API keys round-trip as the redacted placeholder `"[REDACTED]"`; never the raw secret
Built-in provider ids:
- `openai`
- `gemini`
- `claude`
- `deepseek`
- `deepl`
- `google-translate`
- `caiyun`
- `openai-compatible`
API keys are stored in the platform credential store, not in `config.toml`. PATCHing `apiKey: ""` clears the saved key; PATCHing `"[REDACTED]"` leaves it unchanged. The dedicated `/config/providers/{id}/secret` routes are the explicit, non-PATCH way to manage one provider's secret.
## Events stream
Koharu exposes a Server-Sent Events stream at:
```text
GET /events
```
Behavior:
- a fresh connection (no `Last-Event-ID` header) starts with a `Snapshot` event holding the current jobs and downloads registries
- on reconnect, the server replays buffered events with `seq > Last-Event-ID` in order; if the requested id has scrolled out of the ring, the server re-sends a `Snapshot`
- each live event is emitted with its `seq` as the SSE `id:` field
- a 15-second keep-alive is maintained
Event variants currently include:
- `Snapshot` β€” full state seed for fresh and lag-recovery clients
- `JobStarted`, `JobProgress`, `JobWarning`, `JobFinished` β€” pipeline job lifecycle
- `DownloadProgress` β€” package download progress ticks
- `ConfigChanged` β€” config was applied via `PATCH /config` or a secret route
- `LlmLoaded`, `LlmUnloaded` β€” LLM lifecycle transitions
- `SceneAdvanced` β€” emitted when a scene mutation advances the epoch
## Typical workflow
The normal API order for one new project is:
1. `POST /projects` β€” create the project
2. `POST /pages` (or `/pages/from-paths` from Tauri) β€” import images
3. `PUT /llm/current` β€” load a translation model (local or provider)
4. `POST /pipelines` β€” kick off `detect β†’ ocr β†’ translate β†’ inpaint β†’ render`
5. tail `GET /events` until `JobFinished`
6. `POST /projects/current/export` with `format = "rendered"` or `"psd"`
For finer control, post `POST /history/apply` with explicit `Op` payloads instead of running a full pipeline.
If you want agent-oriented access instead of HTTP endpoint orchestration, see [MCP Tools Reference](mcp-tools.md).