@karmaniverous/jeeves-server
    Preparing search index...

    API & Integration Guide

    How to interact with Jeeves Server programmatically — for scripts, bots, AI assistants, and CI/CD pipelines.

    All API requests (except /health and /api/status) authenticate via ?key=<insider-key> URL parameter or session cookie.

    When an unauthenticated browser hits a SPA route (/, /browse/*, /runner/*), the server returns a branded sign-in page instead of the SPA. The page shows an email login form as the primary action (when email auth is configured), with a "Sign in with Google" button below (when Google OAuth is also configured). When only Google auth is active, the Google button is shown alone. When only key auth is active, an API key required message is displayed. The page reflects instance branding (name, emoji) when configured. After successful sign-in, the user is redirected back to the originally requested page.

    API routes continue returning JSON { error: 'Unauthorized' } for programmatic clients — the sign-in page only applies to browser-navigated SPA paths.

    {
    "keys": {
    "ci-bot": "random-seed-string",
    "webhook": { "key": "another-seed", "scopes": ["/event"] }
    }
    }

    The config contains seeds. The actual URL key is derived via HMAC:

    curl -s "http://localhost:1934/insider-key" -H "X-API-Key: <seed>"
    # Returns: { "key": "a1b2c3d4..." }

    Or compute it yourself:

    const crypto = require('crypto');
    function insiderKey(seed) {
    return crypto
    .createHmac('sha256', seed)
    .update('insider')
    .digest('hex')
    .substring(0, 32);
    }
    Method Path Description
    GET /health Simple health check (200 OK)
    GET /api/status Server metadata: version, uptime, services, capabilities. Add ?events=N for recent event log entries
    Method Path Description
    GET /api/file/<path> File content (rendered HTML for markdown, raw for others)
    GET /api/raw/<path> Raw file bytes with appropriate Content-Type
    GET /api/link-info/<path> Query available views and export formats for a path
    Method Path Description
    GET /api/drives List available drives (Windows) or roots (Linux)
    GET /api/path/<path> List directory contents (or file metadata for a file path)
    Method Path Description
    GET /api/export/<path>?format=pdf|docx|zip|tar Export file or directory
    GET /api/mermaid-export/<path>?format=svg|png|pdf Export Mermaid diagram
    GET /api/plantuml-export/<path>?format=svg|png|pdf|eps Export PlantUML diagram
    Method Path Description
    GET /insider-key Get derived insider key (requires X-API-Key header with seed)
    GET /key?path=<path> Compute outsider key for a path
    POST /api/share Generate share link (path, expiry as epoch ms, depth, dirs)
    POST /api/util/share-for Generate share link for a specific audience (insiders, enforceOutsiderPolicy)
    POST /api/rotate-key Rotate an insider's key (invalidates all their outsider links)

    Content routes (/api/path, /api/file, /api/raw, /api/export, /api/export-cache, /api/mermaid-export, /api/plantuml-export, /api/link-info) verify ?key= against the content path after the route prefix, so share keys work on all of them. For scoped identities:

    Status Body When
    400 { "error": "Invalid path" } The content path contains a .. segment
    401 { "error": "Unauthorized" } No valid session or key
    403 { "error": "Path is outside your access scope" } Authenticated, but the path is outside the identity's scopes

    Directory listings and link info admit ancestors of in-scope paths (for navigation) and only list reachable entries; every other content route requires the path itself to be in scope. See Sharing → How scopes are enforced.

    Method Path Description
    PUT /api/file/<path> Overwrite file content
    POST /api/file/<path> Apply structured mutations to .md files (edit-block, delete-block, insert-block, edit-cell, toggle-checkbox)
    Method Path Description
    DELETE /api/export-cache/<path> Clear export and diagram caches for a path
    Method Path Description
    GET /api/auth/status Check authentication status and mode (no auth required)
    POST /api/auth/magic Request a magic login link (no auth required, always returns 200 with { verifyUrl })
    GET /auth/magic/verify OTP verification page — server-rendered page where users enter the emailed code (top-level route, no auth required)
    GET /auth/magic/callback Magic link callback — verifies signed token, sets session cookie (top-level route, no auth required)
    Method Path Description
    POST /api/oauth/start Initiate OAuth2 authorization flow (returns auth URL)
    GET /api/oauth/status?provider=&account= Check credential existence and expiry
    GET /api/oauth/token?provider=&account= Retrieve valid access token (auto-refreshes if expired)
    Method Path Description
    POST /event Send a webhook (matched against configured schemas)
    Method Path Description
    POST /api/search Semantic search (proxied to jeeves-watcher)
    GET /api/search/facets Get filter facets for search UI (cached)
    D:\\docs\\design.md  →  /d/docs/design.md
    E:\\projects\\foo → /e/projects/foo

    Conversion formula:

    1. Replace backslashes with forward slashes
    2. Replace the drive letter + colon with lowercase letter
    3. Prepend the route prefix (/browse/ for SPA, /api/file/ for API, /path/ for legacy)
    function winPathToUrl(winPath, prefix = '/browse/') {
    return (
    prefix +
    winPath
    .replace(/\\\\/g, '/')
    .replace(/^([A-Z]):/, (_, d) => d.toLowerCase())
    );
    }
    const insiderKey = computeInsiderKey(seed);
    const url = \`https://jeeves.example.com/browse/d/docs/design.md?key=\${insiderKey}\`;
    const crypto = require('crypto');

    function outsiderKey(seed, path) {
    const normalized = path.toLowerCase().replace(/^\/+|\/+$/g, '');
    return crypto
    .createHmac('sha256', seed)
    .update(normalized)
    .digest('hex')
    .substring(0, 32);
    }

    See the Sharing guide for details on expiring links and directory sharing.

    If you're an AI assistant working with Jeeves Server:

    1. Use the OpenClaw plugin if available — it provides tools for browsing (server_browse, server_link_info, server_drives), sharing (server_share), export (server_export, server_export_cache_clear), file mutation (server_file_write, server_file_mutate), auth (server_auth_status, server_rotate_key), events (server_event_status), and OAuth credential management (oauth_authorize, oauth_status, oauth_token)
    2. Convert Windows paths to URL paths using the formula above
    3. Use /api/status for health checks (no auth required)
    4. Prefer /browse/ routes for links you share with humans (renders the SPA)
    5. Use /api/export/ routes for direct PDF/DOCX downloads