REST API overview
import { Aside } from ‘@astrojs/starlight/components’;
The REST API under /api/v1/ lets integrations and tools (including the Obsidian plugin) manage documents and collections with a stable JSON interface. This page explains behavior that applies to all endpoints. Per-operation fields and request bodies are documented in the OpenAPI reference.
Base URL
Section titled “Base URL”Use the same origin as your deployed Orimora instance:
- Production:
https://your-domain.example.com - Local (Vite):
http://localhost:5173 - Docker Compose (app service):
http://localhost:3000unless you remap the port
All paths in this document are relative to that base (e.g. GET /api/v1/documents).
Authentication
Section titled “Authentication”API keys (Bearer)
Section titled “API keys (Bearer)”- In the web app, go to Settings → Developers and create an API key.
- Keys are shown once and have the prefix
kb_. - Send the key as a Bearer token:
GET /api/v1/documents HTTP/1.1Host: your-domain.example.comAuthorization: Bearer kb_your_key_hereThe server resolves the key to a user and team. Routes that use requireUser() accept either a normal browser session or this Bearer token.
Scopes
Section titled “Scopes”Each key has one or more scopes:
| Scope | Typical use |
|---|---|
read | List and fetch documents and collections |
write | Create and update resources |
admin | Operations that change team-level settings (when exposed) |
Default for new keys is read + write. Design integrations so they use the smallest scope necessary.
Rate limiting
Section titled “Rate limiting”| Area | Limit (indicative) | Notes |
|---|---|---|
All /api/* routes | 100 requests per IP or user per 60 seconds | Global guard in the request pipeline; skipped for GET /api/health |
| Auth endpoints | Stricter (e.g. magic link / OAuth) | Protects against abuse; see implementation for exact keys |
When limited, the response is 429 Too Many Requests with JSON similar to:
{ "error": "Too many requests", "retryAfterSeconds": 60}Successful responses may include:
X-RateLimit-Limit— max requests per windowX-RateLimit-Remaining— remaining in current windowRetry-After— present on429
Treat 429 with exponential backoff in automation.
Pagination (GET /api/v1/documents)
Section titled “Pagination (GET /api/v1/documents)”Without updatedSince, list responses include:
| Field | Meaning |
|---|---|
data | Array of documents |
total | Total rows matching filters (not just this page) |
limit | Page size (capped, default 25, max 100) |
offset | Skip offset |
Use collectionId, status=published|draft, limit, and offset query parameters as needed.
Incremental sync (updatedSince)
Section titled “Incremental sync (updatedSince)”For tools that only need changed documents since a point in time:
- Pass
updatedSinceas an ISO 8601 timestamp (e.g.2026-04-01T12:00:00.000Z). - The response shape differs: there is no
total/offsetpagination in the same way; the server uses a higher effective limit for the sync window. - Add
format=markdowntogether withupdatedSinceto receive amarkdownTextfield per document for plain-text sync (used by the Obsidian selective pull).
See the OpenAPI /api/v1/documents GET operation for details.
Request bodies: Markdown vs TipTap JSON
Section titled “Request bodies: Markdown vs TipTap JSON”text: Markdown string — the server converts it to TipTap/ProseMirror JSON internally.content: Raw TipTap JSON if you already have structured content (advanced integrations).
You typically use one or the other, not both, when creating or updating body content.
Responses and errors
Section titled “Responses and errors”Success payloads usually look like:
{ "data": { /* resource */ } }List endpoints return { "data": [ … ] } plus pagination fields as documented per route.
Errors use JSON with an error string (and HTTP 4xx/5xx):
{ "error": "Document not found" }| HTTP | Typical cause |
|---|---|
| 401 | Missing or invalid API key / session |
| 403 | Authenticated but not allowed (e.g. onboarding incomplete) |
| 404 | Resource not found or wrong team |
| 429 | Rate limited |
| 400 | Validation / bad JSON |
Webhooks
Section titled “Webhooks”Document lifecycle events can trigger webhooks configured in the workspace. Webhook delivery, signing, and retries are not part of the /api/v1/ CRUD surface; configure them in the app UI. Automation should still use idempotent handlers and verify signatures when provided.
OpenAPI
Section titled “OpenAPI”The same operations are available as OpenAPI 3.1 for code generators and the Starlight UI:
Regenerate the bundled spec with:
cd docs && yarn generate:openapi(Runs automatically as part of yarn build in the docs package.)