API Reference
Endpoint map and auth behavior.
Data portability export
GET /api/data-export?scope=personal|workspace and POST /api/data-export create the same non-mutating ZIP snapshot; POST accepts { "scope": "personal" } or { "scope": "workspace" }. Only admins may request the workspace scope. GET is intended for browser-native streamed downloads that do not buffer the archive in JavaScript. The archive contains complete JSON and per-entity CSV (including scheduled automation definitions, personal/group chat messages, agent runs, and installed data-bearing bundled-module datasets), ICS, VCF, document and referenced media binaries, a manifest, and a README. Personal scope includes automations created by the requester; workspace scope includes all definitions. Prompts, triggers, schedules, workflow graphs, and delivery targets remain portable while webhook, Bearer, and other structured access tokens are redacted. manifest.module_export lists included installed modules and datasets. Complete JSON and CSV artifacts are serialized row by row into temporary files before Archiver reads them, avoiding a second whole-export string in the web-process heap. Personal exports include Social Media library files referenced by the requester's posts; workspace exports include the complete Social Media media library, including unused uploads. Documents referenced by exported Tax Manager receipts, generations, and export jobs are included only when the requester retains normal shared/owner visibility. Requester-owned generated-image links in personal chat messages and module records are resolved into portable files while prompt, provider, model, storage-path, and image metadata remain redacted from the exported asset rows. Social-media session data and OAuth states are excluded with all other authentication secrets. A convenience XLSX is included only while its bounded row/cell/input-size plan is safe to materialize; manifest.tabular_formats.xlsx records inclusion or the limit that caused omission. Personal exports redact private Team Chat run recovery/client context and tool results belonging to other participants. Legacy open Team Chat membership rows retain joined_at; boundary_ambiguous=true identifies rows whose pre-history rejoin gaps cannot be reconstructed, instead of treating read-receipt updated_at activity as a join boundary. Authentication secrets and private agent memory are excluded. The response is application/zip with Cache-Control: no-store. See Daten-Portabilität und Exit-Plan for archive semantics and the master/sync distinction.
This page inventories the HTTP surface of Clapilot: first-party app APIs, bundled-module APIs, hub/distribution APIs, and the internal native-runtime endpoints the app talks to.
POST /api/hub/fleet/instances/:id/actions accepts the existing stop, start, and redeploy actions. The admin-only set-shell-tools action additionally requires boolean shellToolsEnabled; it persists the capability policy for that one Fleet instance and redeploys it. If the instance is stopped, connector 1.1.0 or newer recreates the deployment with --no-start so the policy change does not start the tenant. Older or unreported connector versions are rejected with 409 fleet_connector_update_required before a job is queued; re-running the served Fleet connector installer downloads the current connector and safely restarts its user service. Omitting the boolean is rejected with 400.
POST /api/hub/fleet/agents/heartbeat uses the per-machine HMAC contract and returns { ok, connector: { latestVersion }, remoteAgent: { enabled, label } }. latestVersion is the bundled connector's x.y.z version or null when the Hub cannot read it. remoteAgent reflects the machine's persisted opt-in and current name. Probe payloads may include codexVersion; an explicit string persists it, while explicit null or an empty string clears it. Older connectors that omit the key leave the stored value unchanged.
PATCH /api/hub/fleet/machines/:id accepts remoteAgentEnabled (or remote_agent_enabled) as a boolean in addition to the existing machine fields. GET /api/hub/fleet/connector/files/:name serves only clapilot-fleet-connector.mjs, clapilot-fleet-event-outbox.mjs, and agent-orchestrator-codex-remote-runner.mjs; all other names return 404. The legacy single-file GET /api/hub/fleet/connector endpoint remains available for old installers.
GET /api/clapilot-code/install serves the dependency-free clapilot-code installer with the request-facing instance origin substituted into its login instruction. It requires no interactive session or API key, but returns 404 unless app_settings.developer_mode_enabled is true.
GET /api/clapilot-code/files/:name serves exactly clapilot-code.mjs from the image's scripts/ directory. The literal allowlist rejects every other filename with 404. The route requires no interactive session or API key and shares the install route's Developer-mode 404 gate. The downloaded CLI uses a separately created inference:execute instance API key for model requests; the code-download route never accepts or exposes that key.
The /api/modules/agent-orchestrator/api/remote-runners/* family accepts either the existing Hub shared-secret HMAC or a Fleet machine HMAC. For Fleet authentication, x-clapilot-instance-id must be that machine's UUID and the signature uses its per-machine secret. Fleet credentials are rejected for every other module API path.
-
Source of truth: route handlers under
src/app/api/**/route.ts(bundled-module endpoints are served throughsrc/app/api/modules/[slug]/api/[...endpointPath]/route.tsfrombundled-modules/<slug>/), plus the nativeclapilot-agentservice for/internal/*. -
/api/modules/agent-orchestrator/api/sessionsand/api/modules/agent-orchestrator/api/sessions/:id- Session payloads include
usageJsonandrunDiagnosticsfrom the latest associatedagent_runsrow. Failed-run diagnostics are therefore available consistently to web, iOS, and macOS detail views.
- Session payloads include
-
Organization: endpoints are grouped by feature area (Auth, Documents, Tasks, E-Mail, Chat, integrations, Hub, Admin, module platform), followed by the internal native-runtime section.
-
Not every endpoint carries a full request/response spec here; entries prioritize auth level, methods, and behavioral contracts that agents and clients rely on. Agent-facing tool contracts live in Agent Tool Contracts.
Product telemetry
POST /api/telemetry/events stores a validated product event for the authenticated user. The endpoint accepts metadata only:
{
"event_name": "module_opened",
"session_id": "browser-session-id",
"module": "athlete-brand-matching",
"route": "/modules/athlete-brand-matching",
"success": true,
"duration_ms": 120,
"error_code": null,
"properties": {
"flow": "athlete-brand-matching",
"step": "opened",
"module_slug": "athlete-brand-matching"
}
}
Unknown event names are rejected. Content-like or secret-like properties are dropped before storage.
GET /api/telemetry/report?from=<iso>&to=<iso> returns aggregate usage and friction metrics for the authenticated user. Admins may pass user=<uuid|email|name> (legacy user_id=<uuid> is still accepted) to scope the report to a specific user.
GET /api/telemetry/product-health?from=<iso>&to=<iso>&user=<uuid|email|name> returns the internal Product Health report for admins only. The response reuses product_events aggregates and adds last activity, active user/session lists, latest event metadata, and a timeseries array (bucketInterval of hour or day) for the tracking dashboards under /admin/hub. The user filter accepts a UUID for an exact match or a free-text fragment matched against email and display name; legacy user_id=<uuid> is still accepted. Non-admin users receive 401 or 403 from the server-side role check.
POST /api/telemetry/hub-sync (admin only) triggers an immediate push of pending local product events, model-usage logs, chat transcripts, and the due cached Subscription Usage snapshot to the configured remote hub. The response preserves the combined { ok, skipped, synced, error } fields and adds the individual results as { productTelemetry, modelUsage, chatTranscripts, subscriptionUsage }, each with { ok, skipped, synced, error }. Subscription Usage keeps its own persisted 15-minute report lease, so this action does not bypass its provider-refresh limit. The same combined sync runs automatically in the background after events are recorded when hub_mode is remote.
POST /api/hub/telemetry/ingest (hub instances only, HMAC-signed) accepts telemetry batches from connected instances: { instanceUrl, events: [{ id, createdAt, userId, userEmail, userName, sessionId, eventName, module, route, properties, durationMs, success, errorCode, platform }] }. Events are stored idempotently in hub_instance_product_events keyed by (instance_host, source_event_id), and the sender is auto-registered as a monitored instance with discovery source telemetry.
PATCH /api/hub/health/instances/[id] with issueTelemetryCredential: true lets a hub admin issue or reset a random per-instance telemetry credential. The plaintext value is returned only in that admin response, while the hub stores only its hash, binds it to the visible sender identity, and disables monitoring for explicit re-approval. The credential is copied to the customer instance through the remote-hub settings and stored there encrypted via POST /api/telemetry/hub-credential; GET returns only whether it is configured. Reissuing provides the authenticated recovery path after token loss.
POST /api/hub/telemetry/enroll validates an already admin-issued credential against the stable x-clapilot-instance-id; fleet-wide HMAC authentication alone cannot create or replace the binding.
POST /api/hub/telemetry/ingest and POST /api/hub/telemetry/model-usage/ingest additionally require x-clapilot-instance-credential. The credential must match both the hub-side hash and the immutable sender identity approved for that monitored instance, so one spoke cannot submit monitoring telemetry for another host.
POST /api/hub/telemetry/model-usage/ingest (hub instances only, HMAC-signed and per-instance authenticated) accepts { instanceUrl, logs: [...] }, with each log limited to { id, createdAt, userId, userEmail, userName, providerType, providerSlug, providerLabel, requestedModel, effectiveModel, requestKind, transport, status, inputTokens, outputTokens, totalTokens, cacheCreationInputTokens, cacheReadInputTokens, durationMs }. Prompt/session data, endpoints, errors, raw usage payloads, prompt-layer details, and metadata are not accepted by this contract. The hub validates UUIDs/timestamps, clamps non-negative integer counters, truncates text fields, stores rows idempotently in hub_instance_model_usage_logs by (instance_host, source_log_id), and returns { ok, received, accepted, inserted }.
POST /api/hub/subscription-usage/ingest (hub instances only, HMAC-signed and per-instance authenticated) accepts { instanceUrl, snapshot }. The sender normalizes the cached Codex, Claude Code, Grok, and Ollama snapshot before transmission; credentials and arbitrary provider metadata are never accepted. The Hub validates and normalizes the snapshot again, then replaces the latest row for that instance in hub_instance_subscription_usage_snapshots. The endpoint returns { ok, accepted, checkedAt }.
GET /api/hub/telemetry/instances (admin only) lists the local instance plus, in local hub mode, all monitored instances with telemetry summaries (totalEvents, eventsLast7d, activeUsersLast7d, tokensLast7d, lastEventAt) and health/monitoring metadata. Monitoring metadata includes the persisted classification, separate periodic status/summary/check time, telemetry state (never, fresh, stale), latest hub receipt time, 24-hour error rate/operation count, and per-host thresholds. tokensLast7d is the sum of total_tokens reported during the previous seven days.
PATCH /api/hub/health/instances/[id] (admin only) updates only the supplied instance credentials and monitoring fields, so concurrent edits do not restore stale values. Monitoring fields are classification (kunde|eigen|dev|intern), monitoringEnabled, telemetryStaleAfterHours (default 26), errorRateThreshold as a fraction (default 0.15), errorRateMinOperations (default 20), and the one-shot issueTelemetryCredential operation described above. Enabling monitoring explicitly approves the current target for scheduled outbound probes; auto-discovered targets start disabled. Invalid classification, threshold, identity, and credential responses are localized from the request UI language. This admin contract is intentionally not exposed as an agent tool.
POST /api/hub/chat-transcripts/ingest (hub instances only, HMAC-signed) accepts chat transcript batches from connected instances: { instanceUrl, records: [{ id, source, createdAt, sessionKey, sessionTitle, channelType, model, userId, userEmail, userName, messages, metadata: { toolTrace, ... } }] } with source in personal_chat|group_chat|agent_run. messages accepts user, assistant, and tool roles. Tool-calling assistants use { role: "assistant", content: "", tool_calls: [{ id, type: "function", function: { name, arguments: {} } }] }; tool results use { role: "tool", tool_call_id, name, content }. Camel-case toolCalls/toolCallId is also accepted, but function arguments must be JSON objects. Max 200 records per request and 200 messages per record; inline data: base64 URIs are stripped server-side and message content is capped. Invalid tool-call messages are discarded. Records are stored idempotently in hub_instance_chat_transcripts keyed by (instance_host, source, source_record_id); the response is { ok, received, accepted, inserted }.
GET /api/hub/chat-transcripts/stats (admin only) returns { hub_mode, chat_transcript_sync_enabled, instances: [{ instanceHost, isLocal, records, sessions, lastReceivedAt, sources: [{ source, records, sessions, lastReceivedAt }] }], totals }, always including the local instance and, in local hub mode, all instances that have synced transcripts.
GET /api/hub/chat-transcripts/export?instances=<csv>&sources=<csv>&from=<iso>&to=<iso>&format=native|messages (admin only) streams an application/x-ndjson download combining hub-synced spoke transcripts and the hub's own local chats (instances=local restricts to local data). format=native remains the full-fidelity session archive, now including tool messages and a session-level toolTrace: "complete"|"unavailable"; it never drops records. format=messages emits training samples with a leading current-persona system message, complete user/tool/assistant turns, and a top-level tools schema list whenever calls are present. Samples are windowed at complete-turn boundaries with a target maximum of 32 messages; a single larger turn remains intact. Records whose tool trace cannot be linked or is incomplete are dropped, and traceable segments on either side become separate samples. Rows synced before metadata.toolTrace existed are treated as unavailable.
A tool-bearing format=messages line has this shape:
{"tools":[{"type":"function","function":{"name":"calendar_list_events","description":"…","parameters":{"type":"object","properties":{"start":{"type":"string"}},"required":["start"]}}}],"messages":[{"role":"system","content":"Du bist Angela, der Clapilot-Copilot. …"},{"role":"user","content":"Prüfe meinen Kalender"},{"role":"assistant","content":"","tool_calls":[{"id":"call_1","type":"function","function":{"name":"calendar_list_events","arguments":{"start":"2026-07-24"}}}]},{"role":"tool","tool_call_id":"call_1","name":"calendar_list_events","content":"[]"},{"role":"assistant","content":"Es gibt keine Termine."}]}
The training contract has three strict rules: function.arguments is a JSON object, never a JSON-encoded string; every role:"tool" message has string content (structured source values are serialized); and tools is a top-level sibling of messages. Call IDs are renumbered per row and every row ends with a non-empty assistant response. Rows without calls omit tools.
Adding dryRun=1 runs the same selected messages pipeline without streaming a file and returns JSON: { ok, format, conversations, messages, toolCalls, toolMessages, conversationsWithTools, droppedTurnsUntraceable, sessionsWithDroppedTurns, runsWithIncompleteTrace, toolSchemasFromRegistry, toolSchemasDerived, derivedToolNames, suspiciousWithoutToolCall }. derivedToolNames is capped at 100 names; suspiciousWithoutToolCall counts emitted rows whose assistant text refers to likely calendar, mail, task, document, or participant data but has no tool result message.
GET /api/hub/telemetry/instances/[id]/report?from=<iso>&to=<iso>&user=<uuid|email|name> (admin only) returns the per-instance tracking report. id=local reads local product_events and agent_model_request_logs; a monitored instance UUID reads the hub-synced product and model-usage tables (requires local hub mode). The response shape matches the Product Health report plus an instance descriptor and a tokenUsage section:
{
"tokenUsage": {
"totals": {
"requests": 42,
"inputTokens": 120000,
"outputTokens": 18000,
"totalTokens": 138000,
"cacheReadTokens": 24000,
"cacheWriteTokens": 5000
},
"byModel": [
{
"providerType": "openai",
"providerSlug": "openai-main",
"providerLabel": "OpenAI",
"model": "gpt-5.1",
"requests": 42,
"inputTokens": 120000,
"outputTokens": 18000,
"totalTokens": 138000
}
],
"byProvider": [],
"timeseries": [
{ "bucket": "2026-07-17T10:00:00.000Z", "inputTokens": 120000, "outputTokens": 18000, "totalTokens": 138000 }
]
}
}
The model and provider arrays contain at most 15 entries ordered by total tokens. Token aggregation includes all request statuses and uses the same hour/day bucket interval as product-event activity.
Auth behavior
- protected APIs return
401when unauthenticated - admin routes enforce
requireAdminRole()checks - session context resolves from
clapilot_sessioncookie - native runtime service auth uses short-lived Bearer tokens for module runtime APIs; remote slave/client module calls may also use Hub HMAC headers derived from
CLAPILOT_HUB_SHARED_SECRET
Desktop updates
The Sparkle update endpoints are public (auth: none). They expose signed release metadata and archives while keeping the private-repository GitHub token on the server.
GET /api/desktop-updates/{app}/appcast.xmlappmust beclapilotorremote-runner; other values return404- returns the newest matching
appcast-clapilot.xmlorappcast-remote-runner.xmlfrom up to ten recent GitHub releases asapplication/xml; charset=utf-8 - returns
404when no recent release contains that appcast,503whenGITHUB_RELEASES_TOKENis not configured, and502when GitHub cannot be reached successfully
GET /api/desktop-updates/{app}/download/{filename}filenamemust be one traversal-free path segment ending in.zipor.deltaclapilotacceptsClapilot-*assets but excludesClapilot-Remote-Runner-*;remote-runneraccepts onlyClapilot-Remote-Runner-*- streams the exact matching asset from up to ten recent releases as
application/octet-stream, withContent-DispositionandContent-Lengthwhen known; the server does not buffer the full archive - returns
404for an invalid/unknown asset,503when the server token is missing, and502for an upstream GitHub failure
Endpoint groups
Auth
/api/auth/loginPOST: rate-limited per client IP and per email with exponential backoff (in-memory per app instance). Once the free failed-attempt budget is exhausted, further attempts return429with a localized error and aRetry-Afterheader (seconds); the lockout doubles per additional failure up to 15 minutes. A successful login clears the email counter.X-Forwarded-For/X-Real-IPare only honored whenCLAPILOT_TRUST_PROXY_HEADERS=true(set this only when the app is reachable exclusively through a proxy that overwrites those headers); otherwise the per-IP dimension is disabled entirely — spoofable headers cannot bypass the limiter, and no shared bucket exists that an attacker could lock to deny login to everyone. Without trusted headers, protection is per-email only. Known tradeoff: anyone who knows an email address can force that account into repeated lockouts (bounded at 15 minutes per episode); this is the standard cost of per-account throttling. The login form surfaces the localized 429 message including the retry window
/api/auth/logout/api/auth/me/api/auth/update/api/profileGET: return the signed-in user profile metadata used by/profil, includingdisplay_name,email,avatar_url, per-userchat_preferences, normalizedmemoryPreferences.share_with_team(defaulttrue; sharing is opt-out), andagent_pet_key(bubblesby default).chat_preferences.speech_to_text_providerisdeviceoropenai_realtimeand defaults todevicePOST: update the signed-in user profile picture with{ avatar_url }; acceptsnullto remove the stored picture and currently expects a PNG/JPG/GIF/WebP data URL payload. The same route also accepts{ chat_preferences }for per-user chat UI preferences such asshow_tool_calls,ui_language, andspeech_to_text_provider,{ memoryPreferences: { share_with_team } }for the new-memory team-sharing preference (enabled by default; explicitfalseopts out), and{ agent_pet_key }for the chat activity Pet selection
/api/profile/petsGET: return built-in and signed-in-user custom Profile Pets used bySettings -> Profile -> Pet; custom pets point at authenticated generated-image URLsPOST: register a generated image as a custom Profile Pet with{ key|agent_pet_key, label|name, preview_image_id|image_id, activity_image_id?, description?, still_prompt?, animation_prompt?, select_for_profile? }. Ifactivity_image_idis omitted or points to a static image, Clapilot derives a transparent looping laptop-working GIF frompreview_image_idfor the pet activity state.
/api/automation-result-targetsGET: list selectable result-delivery targets for automations. ReturnsHaupt-Chat, Teamchat#general, the signed-in user's accessible Teamchat channels/groups, approved Telegram/WhatsApp/Signal/iMessage DMs linked to the signed-in user, and approved Telegram/Slack/WhatsApp/Signal/iMessage/instance-bridge groups
/api/auth/agent/system-token(machine-token mint endpoint)POST: mint a short-lived Bearer token for system/skill callers authenticated viax-clapilot-agent-system-secret; acceptsscopes[], optionalttlSeconds, and optionalsubjectto issue a user-scoped token for user-owned APIs such as app integrations
/api/push/devicesPOST: register or refresh one signed-in Apple account/instance subscription with{ installationId, instanceId, token, platform, bundleId, environment, deviceName?, appVersion? }.installationIdis stable for the app installation; token rotation updates the shared installation record without replacing its other subscriptionsDELETE: unregister only the signed-in account/instance subscription with{ installationId, instanceId, platform, bundleId }; other accounts on the installation remain subscribed- APNs payloads include the subscription's
instance_idand an allowlistedtarget_route. Delivery selects only subscriptions whose user still exists in the current instance, and invalid APNs tokens deactivate the installation
/api/user/menu-preferencesGET: return the signed-in user's persisted sidebar/menu layout preferences (version: 1,groups[]withkey,itemOrder,hiddenItems)POST: save{ preferences }with the same schema; invalid shapes return400
Onboarding
/api/onboardingGET: return whether the first-login onboarding flow is enabled plus the signed-in user's persisted onboarding state (status,currentStep, timestamps, and optionaltemplateSetupmarker).POST: advance, complete, skip, or restart the flow with{ action, currentStep?, ui_language? }. Progress is stored inuser_profiles.onboarding_state_json.
/api/onboarding/templatesPOST: queue background personalized-template generation from the optional onboarding step with{ document_ids, ui_language? }. Validates that the documents are visible to the signed-in user, caps the batch at 10, and enqueues a one-off, user-owned agent task (viacreateScheduledTask) that reads each document and authors a reusable Canvas template. The agent's final reply is delivered to the user (chat + push); the call also marksonboarding_state_json.templateSetupasqueued.
Documents
/api/documentsGET: list document metadata lazily for the Dokumente UI, scoped to shared documents plus the signed-in user's private documents, including filename suggestion metadata (original_file_name,suggested_file_name,auto_renamed), extracted tax fields (amount_cents,currency,datum), andrelated_mandanten. Supportslimit,offset,search,mandant_id,kategorie,folder_view(all,none,google-drive,microsoft-365,folder),folder_id,sort_field,sort_direction, and optionalinclude_facets=1for sidebar counts.mandant_idmatches the primarydokumente.mandant_idor anydocument_mandantenrelation.document_idreturns metadata for one record so deep-linked previews can open without loading the full archive.
/api/documents/uploadPOST: accepts multipartfile,typ, andtitelplus optional document metadata includingmandant_id,datum, amounts, andfolder_id. When supplied,folder_idmust be a valid UUID for an existingdocument_foldersrow; invalid or missing folder targets return400, and the inserteddokumenterow stores the folder reference.
/api/documents/inboxPOST: accepts multipart files plus optionalfolder_id, repeateddirectoriesentries to recreate dropped folder trees in documents, and AI-processing controls for large batches:processing_mode(full,index_only,sample),processing_confirmed=1for confirmed full processing, and optionalprocessing_limitfor sample batches. Large full-processing uploads return409withrequiresProcessingConfirmationuntil explicitly confirmed.
/api/documents/foldersGET: list folder tree rows visible to the signed-in user, including the per-user privatePersönlichfolderPOST: create a folder with{ name, parent_id?, visibility_scope? }; omitted scope creates a shared folder
/api/documents/folders/[id]PATCH: rename or re-parent a folder with{ name?, parent_id? }DELETE: delete a folder and lift contained documents/subfolders one level up
/api/documents/[id]GET: download the stored document file as an attachmentPATCH: update document metadata with any subset of{ folder_id, mandant_id, typ, titel, beschreibung, datum, amount_cents|amount, currency, quartal, jahr, kategorie, related_mandant_ids }.related_mandant_idsreplaces the non-primary document relations while preserving the primarymandant_idrelation.PUT: replace the stored file bytes for an existing document and refresh document indexing metadata (max 100 MB). PDF documents keep the strict guard (requestContent-Typemust beapplication/pdfand the body must carry the%PDF-magic bytes); non-PDF documents accept a raw body whoseContent-Typematches the stored mime type (application/octet-streambypasses the mime check). Used by the native Apple iPad signing flow (PencilKit annotations) and by the macOS Documents folder sync to push local file editsDELETE: delete the document record and its stored file
/api/documents/[id]/export-pdfPOST: export a Word Editor-compatible document as A4 PDF, save the generated PDF as a sibling document record in Clapilot, and return the created document metadata plus a download URL
/api/documents/[id]/preview/api/documents/[id]/thumbnailGET: authenticated PNG thumbnail of the first PDF page (rendered viapdftoppm, cached for 300s); used by document list/grid tiles
/api/documents/[id]/analysisGET: return AI-side document extraction status plus extracted preview text, extraction metadata, generated bullet summary, and filename suggestion metadata for the document preview sidebar; the route also ensures a background index job exists when the document has a file path
/api/documents/[id]/workflowGET: ensure + return the document workflow{ automation }. Once extraction status isprocessed, Clapilot analyzes the extracted text and AUTO-EXECUTES the detected actions (no separate approval step): it returns a 1-2 sentencesummary,context_label,document_kind, matchedmandant, an arraytask_actions(a single document can yield several tasks — e.g. one per next step in a meeting summary), acalendar_action, afollow_up_action, andhighlights. Each created/updated task carriestask_idandaction_kind(createdorupdated). Tasks are created inaufgabenwithsource_type='document'(linking the document back into each task); calendar entries usesource_origin='document'. Before creating, a suggested task is matched against existing open tasks for the same client and tasks already linked to the document — a strong title match UPDATES that task (repointing a manual task to the document, or appending the document link to an email-sourced task) instead of creating a duplicate. The analysis + execution is cached per document via a content signature, so repeated reads do not re-run the model or re-create tasks; it also emits anaufgabenUI mutation reload when tasks are created/updated.automationisnulluntil extraction isprocessed. The document detail view (web + Apple) renders this as the "Workflow" timeline section. There is noPOSTapproval route — actions are applied automatically.
beA
/api/bea/importPOST: authenticated multipart upload for one beA export ZIP viafileor the firstfilesentry. Requires the admin feature flagapp_settings.bea_import_enabled; it is disabled by default. The route parses XML metadata and attachments, stores files under_inbox/bea, upsertsbea_nachrichtenbynachrichten_id, upserts imported attachment rows indokumentewithsource_type='bea', enqueues document indexing, and starts a native background run withsessionKey=system:bea-inbox:process.
Admin terminal
/api/admin/terminal/sessionsPOST: admin-only and requiresapp_settings.developer_mode_enabled=trueplus the bundledterminalmodule to be active. Creates a short-livednode-ptyBash session in the Clapilot web container and returns{ sessionId, cwd, shell, cols, rows, pid }.
/api/admin/terminal/sessions/[id]/streamGET: admin-only SSE stream for terminal output events. The stream sends JSON messages withtype=ready|output|exit|error.
/api/admin/terminal/sessions/[id]/inputPOST: admin-only input write for an existing terminal session with{ data }. Input chunks are capped server-side.
/api/admin/terminal/sessions/[id]/resizePOST: admin-only PTY resize with{ cols, rows }.
/api/admin/terminal/sessions/[id]DELETE: admin-only close for an existing terminal session. Idle and max-age cleanup also close forgotten sessions.
Terminal UI is rendered by the bundled module at /modules/terminal; module discovery hides it while Developer mode is disabled. These endpoints remain first-party app APIs because they manage process-local PTY sessions. Sessions are not resumable after container restart. Session lifecycle events are recorded in admin_terminal_audit_events without storing terminal input/output content.
Wiki
/api/wiki/pagesGET: list active Wiki pages visible to the signed-in user or a user-scoped agent system token. Supportssearch,limit,offset, andinclude_archived=true; searches title, summary, Markdown content, and tags.POST: create a manual Wiki page with{ title, slug?, markdown_content?, summary?, tags? }; creates immutable revision 1 and returns{ page }.
/api/wiki/pages/[id]GET: load one Wiki page by UUID, slug, or stabletopic_key, including provenance/evidence metadata and revision/proposal counts.PATCH: make a manual edit with any subset of{ title, slug, markdown_content, summary, tags, status, change_summary }; appends an immutable revision. The client cannot relabel the edit as generated or replace provenance fields.DELETE: archive one Wiki page and append an archive revision; returns{ page, archived: true }.
/api/wiki/pages/[id]/revisionsGET: list immutable page revisions newest first; supportslimitandoffset.
/api/wiki/pages/[id]/revisions/[revisionId]/revertPOST: admin-only. Restores a historical snapshot as a new manually owned revision; the historical row is never changed.
/api/wiki/proposalsGET: list proposals; supportspage_id, comma-separatedstate,limit, andoffset. The response includescan_reviewfor the signed-in admin UI.POST: create a generated draft with{ target_page_id?, topic_key?, slug?, title, markdown_content, summary?, tags?, source_type?, source_refs, assertion_refs, evidence_refs, evidence_checked_at?, metadata?, proposed_by_ref? }. Assertion/evidence refs are exact objects containing at least{ kind, id }. Exact duplicates or semantic candidates at/above the fixedwiki-semantic-v1Jaccard threshold (0.78) return409; the signature uses title, summary, and H1-H3 headings and is identical in the web helper, native publisher, and migration backfill.
/api/wiki/proposals/[id]GET: read one proposal.PATCH: admin-only review with{ decision: "approved" | "rejected", review_note? }. Approval does not mutate the live page. Approval rejects private, terminal, conflicted, unresolved-conflict, or evidence-pending canonical assertions. Candidate assertions promoted by this review enqueue projection work under each assertion's realinstance_key.
/api/wiki/proposals/[id]/publishPOST: admin-only. Atomically publishes an approved, non-stale proposal, appends its immutable revision, and marks the proposalpublished.
Wiki read/manual-write and proposal-create APIs accept normal signed-in user cookies and short-lived Bearer tokens minted by /api/auth/agent/system-token with modules:api:read or modules:api:write. Review, publish, and revert require a signed-in admin. Generated producers should create proposals instead of calling the manual page mutation route; manually protected pages reject unreviewed generated writes at both helper and database boundaries. Authenticated chat/Live Voice wiki_upsert_page calls are explicitly user-directed: the tool proxy sends source_type=manual and metadata.userDirected=true, producing a protected manual revision. Autonomous Dreaming remains proposal-only.
Notes and dictation
/api/notizen-audioPOST: authenticated multipart upload for a note page voice attachment; requiresfile,noteId, andpageId, accepts optionaltranscript,durationMs,contentText, andcontentHtml, stores the audio bytes, and returns{ attachment, transcriptText }
/api/notizen-audio/[id]GET: authenticated download/stream endpoint for one stored note voice attachment owned by the signed-in user
/api/modules/notizen/api/notes/[id]/duplicate-localPOST: clone a read-only source note into a normal editable local note; returns the new{ note, pages, assets?, duplicated_from_note_id }payload used by web, Apple, and agent flows
- Notizen note/folder/page payloads now also expose source metadata for synced imports:
- notes:
source_kind,source_external_id,source_synced_at,is_read_only,source_metadata - folders:
system_key,is_read_only - pages:
source_external_id,source_metadata
- notes:
- read-only source notes reject direct note/page mutation and note-audio uploads; the supported write path is the duplicate-local endpoint above
Bundled module APIs
/api/modules/canvas/api/filesGET: list recent signed-in-user Canvas.htmlfiles recursively from.clapilotaicore/canvas, with optionallimit,search, andfolderPOST: create a new Canvas file with{ title?, path?, folder?, content_html? }; omittedpathgenerates a unique.htmlfilename and creates missing subfolders as needed
/api/modules/canvas/api/files/[...path]- Add
?shared=1to read or update a shared Canvas file in the instance-wide shared scope. Shared files are collaborator-writable; delete remains owner-only. GET: load one Canvas file and return{ file, content_html }PUT/PATCH/POST: replace one Canvas file with{ title?, content_html|contentHtml|html }DELETE: delete one Canvas file
- Add
/api/modules/canvas/api/foldersPOST: create a Canvas subfolder with{ path }
/api/modules/canvas/api/templatesGET: list signed-in-user Canvas templates from.clapilotaicore/canvas-templates, with optionallimitandsearchPOST: create a template from JSON{ name, description?, kind?, source_text?, template_html? }or from multipart upload fieldfilefor PDF, Word, Excel, or CSV sources; PDF uploads are converted into image-backed template HTML with placeholder overlays for detected dynamic values, and other supported sources are stored with an extracted preview plus draft placeholder HTML for agent refinement
/api/modules/canvas/api/templates/[id]GET: load one Canvas template including{ template_html, fields, source_text_preview }PUT/PATCH/POST: update a Canvas template with{ name?, description?, kind?, template_html|templateHtml|html?, fields? }DELETE: delete one Canvas template and its stored uploaded source when present
/api/modules/canvas/api/templates/[id]/filesPOST: render a saved template into a new Canvas.htmlfile with{ title?, path?, folder?, data? }, replacing{{field}}placeholders fromdata
/api/modules/canvas/api/preview/[...path]GET: serve one Canvas HTML file as a no-store preview response for sandboxed display
/api/modules/canvas/api/foldersGET: list Canvas folder paths, including empty foldersPOST: create a Canvas folder with{ path }
/api/modules/canvas/api/folders/[...path]PUT/PATCH: rename a Canvas folder with{ path }, moving contained Canvas files under the new folder pathDELETE: delete a Canvas folder and its contained Canvas files/subfolders
/api/modules/canvas/export-pdfPOST: render submitted Canvas HTML (title, optionalpath,content_html, optionalidempotency_key) into a private PDF Documents entry. Optional print controls arepage_format(A4,A3,A5,Letter,Legal),orientation(portrait,landscape), andmargin(narrow,normal,wide, or0–50millimeters;margin_mmis the numeric alias). If none are supplied, an existing document@pagerule is preserved; HTML without@pageretains the edge-to-edge A4 portrait default. Each explicit print control overrides its matching page descriptor. The response includes the created document metadata,documentUrl,downloadUrl, and best-effortpages. HTML explicitly marked withdata-clapilot-document="a4"and.pagecontainers uses the same fixed A4 boxes as the Canvas preview; page overflow or incompatible page geometry returns422without creating a document.- repeated requests with the same authenticated owner and
idempotency_keyreturn the original Documents row withdeduped=true; agent calls derive this key from the durable run ID plus normalized export arguments so restart replay cannot create a duplicate PDF mutation
/api/canvas-styleGET/PUT/POST: read or update the instance-wide Canvas style guide (brand colors, fonts, heading/body sizes, box/table styling, default logo) stored incanvas_style_settings; the same store backs thecanvas_get_style_settings/canvas_update_style_settingsagent tools
/api/modules/cases/api/healthGET: module health for the bundled Cases module and schema readiness
/api/modules/cases/api/optionsGET: compact Mandanten and user/lawyer options for case forms
/api/modules/cases/api/casesGET: list legal cases/matters with optionalq/search,status,mandant_id,assigned_user_id,practice_area,limit, andoffsetPOST: create a legal case withtitle, optionalcase_number,status,priority,practice_area,mandant_id,assigned_user_id, court/reference fields, conflict-check fields, dates, and description
/api/modules/cases/api/cases/:idGET/PATCH/DELETE: read, update, or delete one legal case
/api/modules/cases/api/cases/:id/overviewGET: case summary plus party, key-date, communication, and linked-entity counts
/api/modules/cases/api/cases/:id/timelineGET: merged case timeline across communication logs, key dates, and linked documents/tasks/calendar/email/note records; supportsfilter,limit, andoffset
/api/modules/cases/api/cases/:id/partiesGET/POST/PATCH/DELETE: manage case parties such as client, opposing party, opposing counsel, court, witnesses, experts, insurance, and other contacts
/api/modules/cases/api/cases/:id/key-datesGET/POST/PATCH/DELETE: manage case deadlines, hearings, filings, limitation dates, appointments, and review dates; rows may reference a linked calendar event
/api/modules/cases/api/cases/:id/communicationsGET/POST: list or add communication log entries for email, phone, meeting, letter, portal, fax, or internal notes
/api/modules/cases/api/cases/:id/linksGET/POST/DELETE: link or unlink existingdocument,task,calendar_event,email,draft, ornoteentities to a case
/api/modules/cases/api/linkableGET: search existing link targets withtype=documents|tasks|calendarand optionalq
/api/modules/social-media/api/*(bundled Social Media module; replaces the legacy/api/modules/linkedin/api/*surface)GET health,GET bootstrap(legacy Settings LinkedIn card contract),GET accounts,POST accounts/mastodon,POST accounts/bluesky,DELETE accounts/:platform/:id(legacyDELETE accounts/:id= linkedin)GET/POST posts,GET/PATCH/DELETE posts/:id,POST posts/:id/publish|schedule|unschedule,POST posts/publish-due(worker/service entry, cross-user).GET postsacceptsstatus,q,limit(1-200), and a non-negativeoffset; deterministic ordering allows the UI and agent bulk workflow to enumerate every reviewable page.POST posts/:id/review-actionaccepts{ action, language?, requestId?, expectedWeeklyPrompt? }fordraftandready_for_reviewposts and claims/completes one guarded, idempotent agent rewrite; the claim atomically rechecks that status, while stale/orphanedin_progressjobs are restored before a replacement claim. Foraction=regenerate, bulk callers pass the confirmed focus inexpectedWeeklyPrompt; generation uses that exact snapshot, then final persistence takes a shortFOR UPDATEstrategy-row lock and applies only when the stored value still matches. A mismatch discards the model output, restores the claimed post's prior review status, and returns{ code: "weekly_focus_changed" }with 409 so the caller aborts the remaining batch. No database lock spans the external model call. Failed/cancelled IDs require a freshrequestId, failures restore the pre-claim status only while that job remains the current active claim, target/text changes cancel late completion, and media-only updates do not conflict.POST posts/:id/mediaatomically and idempotently appends one validated media item without replacing concurrent draft edits.POST generate(AI draft{ brief, tone?, platforms?, language? }->{ title, content, hashtags[] })GET media,POST media/import(kind: upload | video-studio | livestream-asset),GET media/file?path=,DELETE media?path=GET|POST oauth/start?platform=linkedin|youtube&accountType=&returnTo=andGET oauth/complete;oauth/completeis the only public (unauthenticated) endpoint of this module, allowlisted insrc/app/api/modules/[slug]/api/[...endpointPath]/route.ts- details: Social Media
/api/modules/whiteboard/api/*(bundled Whiteboard module; boards are visible to their owner plus, when the owner enablesteamvisibility, to every signed-in user — delete/unshare stay owner-only)GET healthGET/POST boards,GET/PATCH/DELETE boards/:id,POST boards/:id/duplicatePOST boards/:id/items,PATCH/DELETE boards/:id/items/:itemId- full-scene
PATCHwrites validate item ids and reject scenes larger than about 15 MB; agent item creation assigns missing ids/z-order and auto-places omitted coordinates - details: Whiteboard
Video Studio AI
These first-party routes are authenticated and workspace-global: every signed-in user reads, edits, and deletes
the same shared set of AI projects, scenes, characters, and voices. owner_user_id is written at creation as
creator attribution only and is never used as a read/write filter. Project detail responses are snapshots containing
project, ordered scenes, and linked characters; the project-list response intentionally contains project
summaries only.
/api/video-studio/modelsGET: list enabled video-generation providers without secrets and return the configured/default provider-model pair. Whenapp_settings.media_model_catalog.videois non-empty,providers[].modelscontains exactly those catalog entries grouped by provider anddefaultis the catalog entry markedisDefault; otherwise the route merges configured models, short-timeout best-effort live discovery, and each provider'sdefault_model, and omits providers that still have no selectable models. The response also includesmusicProviders/musicDefaultandimage: { entries, default }. Image entries come frommedia_model_catalog.image; when that catalog is empty, the image section contains only the current effective image-generation provider/model.
/api/video-studio/charactersGET: return{ characters }for the whole workspace. Each character exposesportraitStatus(generating,ready, orfailed),portraitError,voiceSampleUrl,voiceSampleUpdatedAt, and metadata-backedvoiceId; the workspace-relative voice path is not exposed through this public JSON route. Legacy rows with a portrait resolve asready, while rows without a portrait resolve asfailed. Ageneratingrow older than ten minutes is reconciled tofailedwhen listed.POST: create{ character }from JSON{ name, description?, prompt|appearance_prompt?, generatePortrait?, voice_id? }or multipart fields plus optionalimage,voice,voice_id, andelevenlabs_voice_id/elevenlabs_voice_name(the character's assigned ElevenLabs voice). A voice upload must be MP3, WAV, M4A, OGG, or FLAC and no larger than 25 MB; it is validated before character creation. The row and source uploads are persisted first and the response returns immediately withportraitStatus=generating; canonical portrait generation and appearance-prompt derivation continue in the background unless portrait generation is disabled.
/api/video-studio/characters/[id]PATCH: update any of{ name, description, appearance_prompt, voice_id, elevenlabs_voice_id, elevenlabs_voice_name }and return{ character }.voice_idis the optional preset name used by providers such as xAI;elevenlabs_voice_idassigns the character's ElevenLabs voice (preselected for scene voice changes, resolved automatically byvideo_studio_change_scene_voice, and used as the dubbing TTS voice on an ElevenLabs runtime); an empty string clears either. A changedappearance_promptstarts background portrait regeneration and returns immediately withportraitStatus=generating.DELETE: delete the character and return{ ok }.
/api/video-studio/characters/[id]/portraitPOST: start canonical portrait regeneration with optional{ prompt }and return the character immediately withportraitStatus=generating.
/api/video-studio/characters/[id]/voiceGET: stream the character's voice sample with its stored audio content type and private one-hour browser caching.POST: replace the voice sample with multipart fieldaudio(MP3, WAV, M4A, OGG, or FLAC, max. 25 MB) and return{ character }.DELETE: remove the stored voice sample and return{ character }.
/api/public/video-studio/characters/[id]/voice?token=...GET: stream a token-authorized character voice sample for provider ingestion. Video Studio creates these links only for Kie Seedance submissions, stores token hashes in character metadata, and invalidates public-access metadata whenever the sample is replaced or removed.
/api/video-studio/ai/projectsGET: return{ projects }ordered newest first. Summaries includesceneCount, project status,imageModel, andversions, but not scene snapshots or aclipReadycount. Astoryboard_generatingproject older than ten minutes with no scenes is reconciled tofailedwhen listed.POST: persist a project from{ prompt, target_duration_seconds?, scene_count?, character_ids?, aspect_ratio?, provider_slug?, model?, image_provider_slug?, image_model?, title?, voice_conditioning?, dubbing?, use_end_frames? }, transition it tostoryboard_generating, and return its snapshot immediately with201.metadata.voiceConditioningdefaults totrue,metadata.dubbingdefaults tofalse, and the selected/effective image model is stored inmetadata.imageModel; storyboard and missing start-frame generation continue as one server-side background chain. Character IDs may also be supplied as any workspace character'sportrait_image_idorsource_image_idand are resolved to the character ID; any remaining unknown IDs return400and no project is created.
/api/video-studio/ai/projects/[id]GET: return the project snapshot.PATCH: whiledraft,storyboard_ready,ready, orfailed, update{ title?, prompt?, image_provider_slug?, image_model?, aspect_ratio?, voice_conditioning?, dubbing?, use_end_frames? }and return{ project }. The image provider/model pair is resolved and stored together.aspect_ratioaccepts only16:9or9:16and is restricted todraft,storyboard_ready, orfailed; ready/running projects expose it read-only. Voice settings are booleans stored in project metadata.DELETE: delete the project and return{ ok }.
/api/video-studio/ai/projects/[id]/storyboardPOST: transition an existing project tostoryboard_generating, return the refreshed snapshot immediately, and regenerate its storyboard plus missing start frames as one server-side background chain.
/api/video-studio/ai/projects/[id]/scenesPOST: whiledraft,storyboard_ready,ready, orfailed, append an emptyaiscene atmax(scene_index)+1withpendingstatus,continuesPrevious=false, and the closest supported default duration for the project's stored model. Returns the complete snapshot. A structural edit changesreadyback tostoryboard_ready.
/api/video-studio/ai/projects/[id]/scenes/orderPOST: accept{ sceneIds }, require the array to contain every current project scene exactly once, and atomically assign contiguous indexes in that order. The immediate(project_id, scene_index)uniqueness constraint is protected by a negative temporary-index phase before final indexes are written. Returns the complete snapshot.
/api/video-studio/ai/projects/[id]/framesPOST: generate every missing AI-scene start frame and return the refreshed snapshot.
/api/video-studio/ai/projects/[id]/generatePOST: start eligible per-scene video jobs after every HTML/block scene is alreadyclip_ready; optional{ retryFailedOnly, restart, bundle_only, regenerate_frames, provider_slug, model }can restrict submission, restart the project, and override the stored video selection.bundle_only=truerequires every scene to beclip_readyand only re-runs the final concat into a new version without resubmitting any provider job.regenerate_frames=trueclears every AI scene's start/end frames and clips, then chains frame generation, clip generation, and bundling in the background. A changed provider/model is persisted before fan-out and every AI-sceneduration_secondsis re-snapped to that model's supported values.restart=trueon a ready project detaches every prior AI clip, preserves start frames, clears prior dub metadata, and submits a complete new run. Each clip uses the stored projectaspect_ratio; it is not supplied again in this request. With voice conditioning enabled, OpenAI-compatible providers receive up to three workspace samples as multipart reference audio, Kie Seedance receives up to three tokenized publicinput.reference_audio_urlswhen a public base URL exists, and xAI receives onevoice_idonly for an unambiguous single scene preset. Returns the refreshed snapshot.
/api/video-studio/ai/projects/[id]/statusGET: poll/reconcile provider jobs, advance scene states, claim pending dubbing work, and run ffmpeg concatenation when all scenes are ready. When dubbing is enabled, dialogue scenes remainclip_readywhilemetadata.dubStatusadvances throughpending|dubbing|done|failed; concat waits fordoneand usesmetadata.dubPath. Dubbing claims older than 15 minutes fail. Each concat writesvideos/<output_slug>-v<N>.mp4plus its matching thumbnail and appendsmetadata.versions[]using SQLnow();finalVideoPath/thumbnailPathpoint to the latest version. A legacy unversioned final is adopted as v1 before the next concat writes v2.
/api/video-studio/ai/projects/[id]/cancelPOST: cancel the active project state, reset generating scenes, and return the snapshot instoryboard_ready.
/api/video-studio/ai/projects/[id]/versions/[version]DELETE: delete one non-latest tracked MP4/thumbnail pair and remove its metadata entry. The latest version cannot be deleted through this route.
/api/video-studio/ai/scenes/[id]PATCH: update{ video_prompt?, script?, duration_seconds?, character_ids?, continues_previous?, kind?, html_source? };continues_previousis stored in scene metadata, is forced tofalsefor scene 1, and lets start-frame generation reference the immediately preceding ready AI-scene frame.kind=htmlwithhtml_source.videoSlugvalidates and links an existing Video Studio gallery slug. Block-rendered sources usehtml_source.blocks[],renderedVideoSlug, andrenderStatusthrough the dedicated render route below. Character IDs may also be supplied as any workspace character'sportrait_image_idorsource_image_idand are resolved to the character ID; any remaining unknown IDs return400and the scene is not updated. Returns{ scene }.DELETE: while the project is structurally editable, delete the scene, require at least one scene to remain, and renumber the rest contiguously in one transaction using temporary negative indexes. Returns the complete snapshot.
/api/video-studio/ai/scenes/[id]/render-blocksPOST: accept ordered{ blocks: [{ slug, durationSeconds?, textOverrides?: [{ find, replace, scope? }], contentPrompt? }] }, validate every slug and overridefindvalue against the installed Video Studio block catalog, optionally fill declared slots through the configured storyboard-model candidates, persist a token-guardedclip_generatingclaim, and return202 { scene }.scopeishtml,js, orboth; omission defaults to both. Explicit overrides win over AI-filled values for the same slot. The background chain invokes the Video Studio module'srenderhandler in-process with project aspect, block durations, and flattened scoped overrides; the handler composes the normal manifest and renders HyperFrames into deterministicvideos/ai-scene-<scene-id-prefix>.mp4. Success probes the MP4 and writesrenderedVideoSlug,renderStatus=ready,duration_seconds, andmetadata.htmlRenderDurationSeconds. A matching-token failure is localized; a block render older than 15 minutes without a result reconciles tofailed.
/api/video-studio/ai/scenes/[id]/dubPOST: requireclip_readyand at least one non-empty script line, atomically claimmetadata.dubPreview.status=generating, and return202 { scene }while character-aware speech synthesis and timeline sequencing continue in the background. Success stores a workspace-relative M4AaudioPathwithstatus=ready; failure storesstatus=failedanderror. Project polling marks a claim stale after ten minutes.GET: for an authenticated workspace user, stream the ready preview asaudio/mp4with private no-store caching. Byte ranges are intentionally unnecessary for these short preview files.DELETE: delete the preview file and remove onlymetadata.dubPreview, then return{ scene }.
/api/video-studio/ai/scenes/[id]/dub/applyPOST: require a ready preview, remux it onto the current scene clip while ducking existing audio to -30 dB, atomically replace the deterministic applied MP4, keep the sceneclip_ready, and store both the compatibilitydubStatus=done/dubPathfields andmetadata.dubApplied. The applied file becomes the scene's active clip and concat source. Areadyproject returns tostoryboard_readyso the next generation creates a new version. Returns{ scene }.
/api/video-studio/ai/scenes/[id]/voice-changePOST: accept{ voice_id, voice_name? }for aclip_readyscene, atomically claimmetadata.voiceChange.status=generating, and return202 { scene }while the background chain extracts the current clip audio (applied dub clip when present), converts it with the ElevenLabs speech-to-speech voice changer, remuxes the converted track over the clip, and stores a workspace-relative replacementclipPathwithstatus=ready(failure storesstatus=failedanderror; claims older than ten minutes reconcile to failed). Concatenation prefers a ready voice-change clip over the dub/raw clip, and areadyproject returns tostoryboard_ready.DELETE: while not generating, delete the converted clip, removemetadata.voiceChange, and return{ scene }with the original audio active.
/api/video-studio/ai/voicesGET: return{ voices: [{ voiceId, name, category, previewUrl, isCustom }] }from the configured ElevenLabs account — own/custom voices (cloned, generated, professional) first, then provider default voices. Errors surface the upstream ElevenLabs message.GET: stream the active applied MP4 to authenticated workspace users with normal video range support.
/api/video-studio/ai/block-contentPOST: accept{ block: { slug, durationSeconds?, textOverrides? }, content_prompt }, load the block's curated or HTML-extractedtextSlots, and ask the storyboard LLM route for strict JSON whose keys exactly equal the slot keys. Missing, extra, empty, non-string, refusal-shaped, or malformed output fails closed; success returns the canonical block selection with{ find, replace, scope }overrides for user review before rendering.
/api/video-studio/ai/scenes/[id]/framePOST: generate or edit the scene start frame with{ prompt, mode: "generate" | "edit", image_provider_slug?, image_model? }; returns{ scene }. Overrides apply to this call only; omission usesproject.imageModel. If the chosen provider cannot edit images, edit routing falls back to an edit-capable configured provider while generation continues to honor the exact project selection. The result is dimension-probed and, when its ratio misses the project's canonical frame ratio by more than five percent, scale-to-cover center-cropped without padding and imported as a new lineage-linked generated image before the scene is updated.
/api/video-studio/ai/scenes/[id]/retryPOST: resubmit one failed AI scene and return{ scene }. Optional{ provider_slug, model }overrides the provider/model for this scene submission only; with no override the stored project selection is used, while a provider-only override uses that provider's default model. The project default is never changed. Duration support is resolved against the effective model andduration_secondsis persisted only when it must be snapped so the UI matches the submitted clip. The used selection is returned asclipProviderSlug/clipModeland stored inmetadata.lastClipModel. Optional{ force: true }also permits aclip_readyscene: the oldgenerated_video_idis detached, a ready project transitions back togenerating, and the existing reconcile/concat path rebuilds the final MP4 once all clips are ready.
Social media video generation
/api/social-media/video-generationPOST: submit a text-to-video job through the configured livestream media-generation providers with{ prompt, title?, model?, provider_slug?, duration_seconds? }; returns202 { assetId, status: "generating" }
/api/social-media/video-generation/[id]GET: poll one generation job; returns{ assetId, status: "generating" | "ready" | "failed", mediaPath, thumbnailPath, error }; ready assets are attached to posts via the module'smedia/importendpoint withkind: "livestream-asset"
reMarkable integration
/api/integrations/remarkable/statusGET: return the signed-in user's reMarkable connection status, last sync time, last error, and enabled service flags
/api/integrations/remarkable/connectPOST: exchange the one-time 8-character reMarkable device code for persisted device/user tokensDELETE: disconnect the signed-in user's reMarkable connection
/api/integrations/remarkable/syncPOST: perform a manual pull sync into Notizen and Dokumente; notebook.rmpages are converted into Notizenscribble_data, while PDF-only documents stay in Dokumente as previewable files underremarkable/pdf/...
X integration
/api/integrations/x/oauth/startPOST: start the signed-in user's X OAuth flow; accepts optionalscope_presets[]and now defaults to identity plus tweet read/write plus media-write scopes so user-scoped posting and media upload can be enabled from the same connection flow
/api/integrations/x/oauth/completeGET: OAuth callback endpoint used by X after consent; persists or refreshes the signed-in user's X tokens and account metadataPOST: manual callback-complete helper for pasted callback URLs/codes in the settings UI
/api/integrations/x/oauth/statusGET: return the signed-in user's X connection status, granted scopes, reconnect requirement, token expiry metadata, and last OAuth/API error
/api/integrations/xDELETE: disconnect the signed-in user's X integration and revoke stored tokens where possible
/api/integrations/x/meGET: return the connected X account profile fromusers/me
/api/integrations/x/postsGET: list the connected X account's own posts with optionalmax_results,pagination_token,exclude_replies,exclude_retweets,since_id, anduntil_idPOST: create a new X post with{ text?, reply_to_tweet_id?, quote_tweet_id?, media_ids?, tagged_user_ids? }; accepts text-only, media-only, or mixed text+media posts, but rejects quote-posts with attached media andtagged_user_idswithoutmedia_ids; text-only posts require tweet read/write and users scopes, while media posts also requiremedia.write
/api/integrations/x/posts/[id]GET: load one X post by idDELETE: delete one X post by id
/api/integrations/x/mediaPOST: multipart upload endpoint for one or more media files from the connected X account; accepts repeatedfileparts (orfiles), optional repeatedalt_text, optionalmedia_category, and optionalshared, uploads to X, waits for async media processing when needed, and returns the uploadedmedia_idvalues for laterPOST /api/integrations/x/postscalls
/api/integrations/x/mentionsGET: list mentions for the connected X account with the same timeline query options as/api/integrations/x/posts
/api/integrations/x/timelineGET: list the connected X account's reverse-chronological home timeline with the same timeline query options as/api/integrations/x/posts
/api/integrations/x/users/by-username/[username]GET: resolve one public X user profile by username
Tasks
/api/aufgabenGET: list tasks for the signed-in user session, scoped to shared boards plus the user's private boards, with optionalboard_id,mandant_id, configuredstatuskey,prioritaet,faellig,zugewiesen,wiedervorlage,tag,umsatzrelevant,sort,limit, andviewquery params;sortacceptsfrist_desc,wiedervorlage, ordeal_wert.alle_offenmeans every status whose category is notdone. The defaultview=fullincludes normalized attachment URLs.view=compactkeeps list fields but omits attachment payloads and the source context snapshot,view=summaryreturns aggregate total/urgent/overdue and per-status counts, andview=assignee_countsreturns the filtered count map used by the task sidebar.POST: create a new task; optionalstatusmust be a currently configured key, otherwise the firstopencategory status is used. Manual tasks persist the same traceability shape with a manual source label, context snapshot, optional CRM/follow-up/deal fields, and optionalattachments[]entries using the shared chat attachment shape (type,name,size,mimeType, optionaldata/filePath/url).
/api/aufgaben/statusesGET: return the workspace-global ordered status definitions as{ statuses: [{ key, label, category, sort_order, is_system }] }.POST: create a status with{ label, category }; the server generates a unique stable ASCII key and appends it to the order.
/api/aufgaben/statuses/[key]PATCH: rename with{ label }, change a non-system category with{ category }, or set{ sort_order }. The three system keys keep their locked categories.DELETE: delete a non-system status with?reassign_to=<key>; task and scheduled-task rows are reassigned transactionally first.
/api/aufgaben/statuses/orderPUT: reorder every status with{ keys: string[] }; the array must contain each configured key exactly once.
/api/aufgaben/boardsGET: list shared boards, the signed-in user's privatePrivatboard, and preset board templates (akquise,marketing,finanzen) so users can quickly create common task board structuresPOST: create a board with{ name, visibility_scope? }or create a preset board with{ template_key: "akquise" | "marketing" | "finanzen" }; omitted scope creates a shared board
/api/aufgaben/boards/[id]PATCH: rename a board with{ name }DELETE: delete a board; requires{ target_board_id }so contained tasks are moved to the target board instead of being orphaned
/api/aufgaben/assignees/api/aufgaben/[id]GET: load one task plus optionaltraceabilitymetadata when the task originated from inbox automation; the payload includes source type, a deep link back to the original email, a short context snapshot, and normalizedattachments[]with authenticated preview/download URLs for stored attachments. Attachment URLs prefer the configuredpublic_base_url.PATCH: update task fields, optional CRM/follow-up/deal fields, and replaceattachments[]with the normalized shared attachment shape;statusmust be a currently configured task status key.
/api/aufgaben/[id]/attachments/[index]GET: authenticated inline/download endpoint for one stored task attachment; resolves the metadata index from the task'sattachments[]and streams persisteddata:bytes or redirects a storedurl
/api/aufgaben/[id]/commentsGET: list task comments with author metadata, mentions, and normalizedattachments[]with authenticated preview/download URLs for stored comment attachmentsPOST: create a task comment with text, optionalattachments[], or both; an attachment-only comment is valid
/api/aufgaben/[id]/comments/[commentId]/attachments/[index]GET: authenticated inline/download endpoint for one stored task-comment attachment, scoped through the parent task's board permissions
/api/aufgaben/[id]/delegate/api/scheduled-tasksGET: list scheduled tasks from DB metadata synchronized against native runtime jobs, including protected native system automations and bundled automations such as the Agent Orchestrator Supervisor for admins. Reads overlay currentagent_jobsenabled/next-run/last-run state so system rows remain accurate even when the compatibility metadata row is stale. Bundled/system rows include protection metadata, are shown in their own UI section, and cannot be deleted; returnspublicBaseUrlso the UI can render absolute webhook URLsPOST: create an automation with eithertrigger_kind="schedule"plus schedule fields, or one of the event triggersnew_mail,new_document,new_calendar_entry,webhook; accepts optionalexecution_scope="user"|"team"(teamis admin-only and runs as the built-inglobal_team_serviceprincipal whilecreated_byremains the audit creator; team runs clear creator-bound user/chat/UI context and do not replay conversation history between runs), optionalaction="agent_prompt"|"performance_check"(defaultagent_prompt) — whenaction="performance_check"the automation is a deterministic instance performance/health probe (maps to theclapilotPerformanceCheckjob payload;promptbecomes optional) and an optionalperformance_configobject (windowHours,maxFailureRatePct,maxInteractiveP90Ms) sets the lookback window and pass/fail thresholds; accepts optionalprofileImageUrl, optionalmodelto pin the runtime model, optionalmailbox_scope="all"|"personal"|"agent"fornew_mail, optionalwebhook_tokenfor pre-generated webhook URLs, optionalnotify_targetto assign the automation's implicit destination (main_session,main_sessionplussessionIdfor a concrete web chat,team_chatfor Teamchat#general,team_chatplusroomIdfor a selected Teamchat channel/group, or approvedchannel_approvalTelegram/Slack/WhatsApp/Signal/iMessage groups or Telegram/Slack/WhatsApp/Signal/iMessage DMs), and optionalnotify_result_mode="always"|"informational"|"errors"|"never"to control whether run results are posted there. Also accepts optionalworkflow_configfor the node editor (schema_version:1, trigger/agent/output nodes, edges, node positions). The compatibility fields still define the primary trigger/agent/output; additional event/webhook trigger nodes can dispatch the same automation, and additional output nodes fan out result delivery to multiple validated targets. Agent nodes acceptconfig.specialized_agent_id,config.model,config.prompt(per-step work order for chained agents), andconfig.skill_keys(max 12 installed-skill keys injected additively into that agent's run, for default and specialized agents). Multiple agent nodes are executed as a linear chain alongagent -> agentedges; normalization enforces linearity (one incoming/outgoing agent edge per node, no cycles) by dropping violating edges. The first chain agent uses the flatprompt; each later agent receives the previous agent's output plus its ownconfig.prompt. For saved workflows, output nodes are authoritative for result delivery; output nodes wired from an intermediate agent deliver that step's result, unwired outputs deliver the final chain result, and removing all output nodes makes the automation run-log-only.alwaysposts all results including background status,informationalposts failures and only user-relevant contextual success updates,errorsposts failures only, andneverposts nothing. Automation priority is no longer configurable and new rows default internally tomittel. Time-based automations still create native runtime jobs and accept 1-10080 minute intervals, event-triggered automations stay app-managed rows and normally dispatch direct native runs when events arrive;new_mailfires after mail AI analysis and respects the configured mailbox scope, the protected document post-extractionnew_documentautomation persists revisions intoscheduled_task_event_queuefor sequential native draining and provider-limit resumption, othernew_documentautomations receive enriched context after document AI processing, and eachwebhookdelivery runs in a fresh event-scoped session when/api/automation-webhooks/{token}is called. Webhook runs never replay stored history or a prior session summary, so an already oversized legacy automation session is bypassed automatically; event session keys are deterministic for retries and capped at 500 characters.
/api/scheduled-tasks/[id]GET: load one scheduled task plus recent runtime runs/events for its automation sessionPATCH: toggle enabled state, manually trigger immediate execution viarun_now=true(without mutating schedule timing), or update title, prompt, admin-onlyexecution_scope, optional profile avatar URL, optional pinnedmodel, optionalmailbox_scopefornew_mail, optionalwebhook_tokenforwebhook, optionalworkflow_confignode graph,notify_target,notify_result_mode, metadata, trigger kind, and supported schedules; switching between schedule and event modes converts the automation between native-job-backed and app-managed execution as needed. Automation priority is no longer part of the editable API surfaceDELETE: remove the native runtime job when present and delete the DB row; preinstalled system and bundled automations are protected and can only be paused, not deleted
/api/scheduled-tasks/profile-iconPOST: signed-in image-generation helper for the automation editor; accepts{ titel?/title?, prompt?, trigger_kind?/triggerKind?, schedule_mode?/scheduleMode? }, generates a square automation avatar through the configured image-generation runtime using the Clapilot tint palette/style guide, stores it as a generated image asset, and returns{ profile_image_url, asset }so the caller can save the URL on the automation
/api/automation-webhooks/[token]GET/POST/PUT/PATCH: public token URL for one enabledwebhookautomation. Dispatches only the matching automation and forwards method, query params, selected request headers, and parsed JSON/form/text body as the event payload
/api/internal/automation-eventsPOST: internal-only endpoint guarded byx-clapilot-agent-secretorAuthorization: Bearer <internal-secret>; dispatches event-triggered automations fornew_mail,new_document, ornew_calendar_entry. The protected document post-extraction automation durably acknowledgesnew_documentafter enqueue even if runtime-job reconciliation is temporarily unavailable; identical pending/processed payloads deduplicate, while changed payloads advance the queue revision.
Widgets (routes remain under /api/mini-apps)
/api/mini-appsGET: list the current user's installed Widgets, optionally filtered bysearchanddashboard_only=truePOST: create a structured Widget with{ name, description?, widget_definition?, latest_data? }- Widgets use
widget_definitionwith supported typesstats,list,table,notice, orsections - if
widget_definitionis omitted, Clapilot infers a structured widget fromlatest_data
/api/mini-apps/[id]GET: load one WidgetPATCH: update{ name?, description?, widget_definition? }DELETE: delete the Widget
/api/mini-apps/[id]/dataPATCH: update the latest data payload with{ data, source? }- when richer collection payloads arrive, basic inferred Widgets can auto-upgrade their structured layout during this data update
/api/mini-apps/[id]/dashboardPATCH: update personal dashboard placement, per-widget dashboard settings, and visibility for the current user with{ dashboard_visible?, dashboard_settings?, dashboard_x?, dashboard_y?, dashboard_w?, dashboard_h?, dashboard_z? }
/api/dashboard/layoutGET: load the current user's built-in dashboard widget layout mapPATCH: update one built-in widget placement for the current user with{ widget_id, x?, y?, w?, h?, z? }
Email and drafts
/api/emailsGET: read-only list of unified personal mailbox messages from the persisted inbox cache when available, with a provider read fallback for an empty cache or explicit search. Acceptsfolder(INBOX,ARCHIVE,SENT,DRAFTS,TRASH, or a provider-specific folder key such asmicrosoft-folder:{id}),search,limit,offset, and optionalsearch_scope(alldefault for searches,folderfor folder-scoped search). Global searches walk available IMAP/iCloud folders, use all-mail Gmail search, and use Microsoft Graph message search so Outlook custom folders and subfolders can be returned. Inbox summary rows includemailbox_provider(imap,gmail,microsoft, orapple) /mailbox_addresswhen a source mailbox is known and can also return optionalsender_image_urlplussender_image_fit(coverorcontain) when the sender maps to a matched Mandant profile or logoPOST: explicit personal-inbox refresh used by the E-Mail refresh action. Accepts the same folder/search/paging fields in JSON, refreshes enabled providers, updates persisted summaries, and applies matching Gmail/IMAP inbox filter rules. Provider mutations therefore do not occur during normalGETnavigation.
/api/emails/foldersGET: list personal mailbox folder options for the E-Mail UI. The response includes the unified system folders, custom IMAP folders from the configured Kanzlei mailbox, and nested Microsoft 365 / Outlook folders with provider-specific keys, depth, unread counts where available, and mailbox address metadata.GET /api/emails/filter-rules: list the signed-in user's persistent sender/keyword rules.POSTadds a case-insensitive pattern andDELETE ?id=removes one. Matching Gmail and IMAP inbox messages are moved toNicht relevante mailsand marked read during inbox synchronization; the destination label/folder is created on demand.
/api/email-sendersGET: return selectable senders for manual compose, currently the configured local IMAP/SMTP identity plus enabled personal and Agent Google Gmail identities and Apple Mail
/api/emails/automation/backfillPOST: authenticated catch-up trigger for personal IMAP inbox rows that are still unanalysed; accepts{ ids: string[] }, acknowledges queued work with202/{ queued: true }, then loads cached or IMAP-backed message detail and runs the same prepared-answer workflow in the background batch. The inbox UI uses the per-message automation endpoint for Gmail, Microsoft 365 Mail, and Apple iCloud rows so provider-backed visible messages can also be analysed without opening the detail view first.
/api/emails/[id]GET: loads one personal mailbox message plus prepared-answer metadata (automation) for the email detail flow, visible attachment metadata, linked privatedokumenterecords for attachments, timing badges, detected tasks/deadlines/highlights, synced sharedmandantcontext, friendly retry-safe failure states, detected sender language (detected_language:de,en, orit), and an optionalprepared_document/document_actionpayload only when the workflow created a new private document draft, not merely because the mail contained an attachment; acceptsfolder. The automation payload can includeassignment_suggestionwith confidence, alternatives, and linked attachment document ids so low-confidence Mandanten/Vorgang matches stay reviewable. Inline/signature images such asimage001.pngare filtered out of the normal attachment list before import. Visible personal attachments are imported idempotently into the user's privatePersönlichfolder withsource_type='email_attachment'and a stablesource_id, then queued for document indexing; scanned PDFs fall back frompdftotextto local page OCR before optional vision extraction.
/api/emails/[id]/automationGET: return the current prepared-answer automation state for one personal mailbox message as{ automation }(status,summary,context_label,reply_reason,draft,task_action,calendar_action,highlights,processing); acceptsfolderand resolves provider-prefixed Gmail / Microsoft 365 / Apple iCloud message ids as well as cached IMAP messages. Clients poll this endpoint for progressiveprocessing.stageupdates (context→attachments→analysis→draft→done).automation.source_attachments[]entries can carryanalysis_summary/extracted_text_previewonce extraction finished, andautomation.metricsincludesattachments_considered(whether all analyzable attachments were content-extracted before drafting),attachments_pending_count,attachments_total_count, andattachments_skipped_count.POST: ensure the prepared-answer workflow has run for the message (summary, Mandant context, reply decision, optional auto-generated reply draft with the user's outgoing signature appended) and return the same{ automation }payload; reuses the persisted automation when it is already final. Consumed by the web inbox detail flow and the native Apple Mail detail view.
/api/emails/[id]/assignmentPOST: confirm or change the Mandanten/Vorgang assignment for one prepared email workflow. Accepts{ mailbox_scope, mailbox_email, mandant_id, document_ids? }, updatesemail_thread_automations.mandant_id, records a confirmedassignment_suggestion, and assigns the listed imported attachment documents to the same Mandant.
/api/emails/[id]/attachments/[index]GET: authenticated on-demand download for one visible personal mailbox attachment; acceptsfolder, resolves provider-prefixed message IDs for Gmail, Microsoft 365 Mail, and Apple iCloud Mail, and streams the selected attachment with a download content disposition instead of storing attachment bytes in the mailbox cache. Theindexis based on the filtered visible attachment list, not raw inline MIME parts.
/api/emails/sendPOST: send a manually composed message through the selected sender. Local identities use SMTP/IMAP sent-folder storage; Gmail identities use the connected Google Workspace Gmail send permission; Apple Mail identities use iCloud SMTP/IMAP with the saved app-specific password
/api/emails/[id]/delegatePOST: create or reuse a prepared reply draft for the selected personal mailbox message; acceptsfolder. The source message language is detected across supported UI languages and persisted assource_language; generated replies default to that same language.
/api/emails/[id]/actionsPOST: apply email-detail quick actions such ascreate_task,create_calendar,mark_read,mark_unread,archive,delete, ormove; acceptsfolderand optional{ targetFolder }- Gmail personal mailbox rows support
mark_read,mark_unread, archive, inbox restore, and trash through the Google Gmailgmail.modifyscope; moving Gmail rows into provider-specific IMAP/Outlook custom folders remains unsupported because the personal inbox intentionally exposes Gmail as a label-backed mailbox, not as a foreign folder tree - Microsoft 365 / Outlook rows now support
mark_read,mark_unread, archive, delete, and move into system folders plus provider-specific custom folder ids through Microsoft GraphMail.ReadWrite; existing users connected before this scope upgrade must reconnect Microsoft 365 once to grant write access - successful mailbox mutations now also persist a UI mutation event so
/emailscan patch/flash the affected row in place, andcreate_taskadditionally emits anaufgabenrefresh mutation for open task views
/api/emails/batch-actionsPOST: apply mailbox mutations to multiple personal inbox rows in one request; accepts{ action: "mark_read" | "mark_unread" | "delete" | "move", items: [{ id, folder }], targetFolder? }and returns per-message success/failure rows plus aggregatesuccessCount/failureCountfor optimistic inbox rollback handling. Uses the same provider paths as/api/emails/[id]/actions, including IMAP, Gmail, Microsoft 365, and Apple iCloud Mail
/api/draftsPOST: create a personal email draft with{ von, an, cc?, betreff, inhalt, inhalt_html?, mandant_id?, quell_email_id?, agent_mailbox_email?, source_language?, reply_language? }. For personal drafts, the current user's configured outgoing email signature is appended before persistence unless the body already ends with that signature. When an HTML signature is configured, Clapilot storesinhalt_htmlas the HTML alternative and keepsinhaltas the plaintext fallback; uploaded signature logos remain embedded data images in drafts and are converted to CID inline assets during send. The Athlete-Brand Matching module uses this endpoint for outreach drafts, then deep-links to/emails?tab=entwuerfe&draft=:idfor review and sending
/api/drafts/[id]PATCH: updates draft fields (an,cc,betreff,inhalt,inhalt_html). Passing{ reply_language: "de" | "en" | "it" }on an auto-generated source-email draft regenerates the reply from the cached original message in the requested supported language, preserving the user's outgoing signature for personal drafts.POST /api/drafts/:id/send: sends a reviewed draft idempotently. SMTP success and the IMAP Sent-folder copy are persisted separately with a stable Message-ID. The response includesdelivery.smtp,delivery.sentCopy,delivery.sentFolder, anddelivery.messageId; an append failure returnsok: trueplus a warning, and repeating the request retries only the copy. IMAP Sent discovery uses\\SentSPECIAL-USE and common IONOS/Gmail/Outlook aliases;IMAP_SENT_FOLDERandAGENT_EMAIL_SENT_FOLDERprovide explicit mappings.
/api/drafts/[id]/sendPOST: sends a draft and now returns only user-facing failures for the prepared-answer UX
/api/email-recipient-suggestionsGET: signed-in compose autocomplete withqandlimit(1-200, default 100); merges Mandanten, app users, and previously used draft recipients into deduplicated suggestions
/api/emails/[id]/inline/[contentId]GET: authenticated inline image (CID) delivery for one personal mailbox message so HTML bodies can render embedded images; the agent mailbox mirror is/api/angela/emails/[id]/inline/[contentId]
/api/internal/emails/automation/personalPOST: internal-only endpoint guarded byx-clapilot-agent-secret; runs the personal-inbox auto-analysis batch (runPersonalEmailAutomationBatch) and returns{ started, skipped, failed }; no-ops withdisabled: truewhenemail_auto_analysis_enabledis off
/api/email-settingsGET: load the current user's personal mailbox credentials state plus outgoing email signature fields (outgoing_email_signature,outgoing_email_signature_html). If no saved signature exists, Clapilot can refreshoutgoing_email_signature_suggestionfrom recent sent personal drafts and connected IMAP/Gmail/Microsoft/Apple Mail sent mail samples.POST: update personal mailbox credentials, plaintextoutgoing_email_signature, and sanitizedoutgoing_email_signature_html. Sanitized HTML signatures may include normal links (https,mailto,tel) and uploaded PNG/JPG/GIF/WebP logos as data images up to the send-time inline asset limit; unsupported data images are removed. Saving mailbox credentials can also populate a signature suggestion from recent sent mail; callers should treat suggestions as reviewable user-facing text, not as an automatically accepted signature.
Call & Fax Agent
/api/call-agent/configGET: admin-only load of the singleton SIP/router configuration record plus provider-specific Realtime model dropdown options derived from configured ClapilotAICore provider rowsPOST: admin-only upsert of the singleton SIP/router configuration record, returning the saved config and refreshed Realtime model dropdown options- config now includes
published_ipandoutbound_published_ipso inbound and outbound NAT/public-address routing can be managed in the UI instead of only via env vars - config now also persists
realtime_provider,realtime_model, andrealtime_voiceso the phone worker can target either OpenAI Realtime or Google Gemini Live - config also persists fax capability on the same SIP line:
fax_enabled,fax_station_id,fax_header_text,fax_transport_mode,fax_supports_inbound, andfax_supports_outbound - config now also persists
approved_incoming_numbers; only those inbound caller numbers get the full internal Call Agent tool surface, while all other inbound calls are limited to general public information about clapilot.com
/api/call-agent/statusGET: signed-in runtime status snapshot combining the persisted worker state with the active SIP identity and feature toggles- when inbound calling is enabled, the native worker now keeps a live SIP listener registered and exposes its current registration state here
- the status payload includes
realtime_providerin addition to the activerealtime_modelandrealtime_voice - shared-line runtime status now also includes
active_kind,active_fax_id, and fax feature toggles so the UI and agents can respect the voice-or-fax lock - the status payload now also exposes
sip_local_port,published_ip,outbound_published_ip, andexpected_inbound_udp_portsso inbound forwarding/listener mismatches can be diagnosed from the product UI - if
CLAPILOT_CALL_AGENT_SIP_LOCAL_PORTis set in env, the status payload exposes that effective runtime port even if the stored config record still contains a differentsip_local_port
/api/call-agent/callsGET: signed-in recent call history fromcall_agent_calls- each call row may include a generated post-call summary in
metadata_json.summary - live-call summaries are generated from captured caller transcripts, assistant transcripts, and in-call tool results when available
/api/call-agent/faxesGET: signed-in recent fax history fromcall_agent_faxes, including linked document and mandant labels when available- outbound rows end in
sentonly after the nativeg711fax bridge reports a successful transmission; failed real sends stayfailedwith audit metadata
/api/call-agent/faxes/[id]GET: signed-in fax detail with fax audit events fromcall_agent_fax_events
/api/call-agent/faxes/sendPOST: signed-in outbound fax enqueue request for either an existingdocument_idor plaintext_content; the native worker reuses the Call & Fax Agent SIP line, rejects the request while the shared line is already active with voice or fax, and infax_transport_mode=g711renders the transmission into TIFF before starting a real outbound SIP fax call
/api/call-agent/faxes/[id]/retryPOST: signed-in retry endpoint for failed, blocked, or cancelled faxes
/api/call-agent/faxes/[id]/cancelPOST: signed-in cancel endpoint for queued or active outbound faxes
/api/call-agent/customersGET: signed-in customer lookup for the Call Agent module; searches Mandanten by name, company, phone, or email so the call UI can prefill the target number
/api/contacts/import/vcfPOST: signed-in multipart VCF import used bySettings -> Contacts; acceptsfileplus optionalui_language, parses standard vCard fields (FN,N,ORG,EMAIL,TEL,ADR), creates matchingmandantenrows without triggering per-contact web enrichment, skips exact email duplicates already present inmandanten, and returns{ parsed, created, skipped, failed, results[] }
/api/mandantenGET: signed-in Mandanten list for the overview page; supportsq,typ,activity,openTasks,deadlines(today,week,month),sort(first_name,last_name,organization,updated,created), andlimit. Name sorting uses company/organization names for non-person clients, and the overview persists the selected order in the URL. The response returns the list metadata used by thePriorität / Aufgaben / Mails / Typ / Aktivitättable view, includingunread_email_count,unreplied_email_count, one direct mail target (email_link_mailbox_scope,email_link_id), and today/deadline context (today_deadline_count,today_deadline_title,due_soon_task_count,next_due_task_title,stale_unreplied_email_count,stale_unreplied_email_subject) so the UI can filter byFrist heuteand deep-link into customer-specific work without a second API callPOST: signed-in Mandanten create path; after insert, Clapilot now attempts an optional web-profile match and persistswebsite_url,logo_url, andprofile_image_urlonly when the result clears the built-in confidence checks and the admin feature togglemandant_profile_web_crawl_enabledis enabled. The shared enrichment path prefers Brave when available, but automatically falls back to headless browser search when Brave is missing or rate-limited- agent-driven
mandanten_*tool writes now emitmandanten.client.updatedUI mutation events so/mandantenlist/detail views can refresh and highlight in place
/api/mandanten/[id]GET: signed-in Mandanten detail fetch used by the manual create/edit form when an existing client is opened for editingPATCH: signed-in Mandanten manual update path for the shared create/edit form; updates the core Stammdaten fields (typ,name,vorname,firmenname,adresse,telefon,email,steuernummer,rechtsform,branche) and returns the updated record
/api/mandanten/searchGET: signed-in lightweight Mandanten typeahead withqandlimit(default 6); used by pickers and reference autocompletes
/api/mandanten/duplicatesPOST: signed-in duplicate check before create/update with any of{ typ, name, vorname, firmenname, email, exclude_id }; returns likely duplicate rows
/api/mandanten/[id]/ai-summaryGET: signed-in AI-generated customer summary for the Mandant detail page; cached, withforce=1to regenerate
/api/mandanten/[id]/emailsGET: signed-in list of up to 250 mailbox messages matched to the Mandant's known addresses for the customer communication tab
/api/mandanten/[id]/enrichmentPOST: signed-in manual rerun for one Mandant’s web research; returns the refreshed Mandant row includingenrichment_status,enrichment_source,enrichment_started_at,enrichment_last_checked_at,enrichment_error, andenrichment_suggestion; returns409when the admin feature toggle disables profile crawling. With bodyaction: "accept_suggestion"it applies the pending review suggestion (filling only emptywebsite_url/logo_url/profile_image_urlfields, statusmatched); withaction: "dismiss_suggestion"it clears the pending suggestion (statusnot_found); both action variants work independently of the crawl toggle
/api/mandanten/[id]/overviewGET: signed-in compact detail-page overview payload for/mandanten/[id]; returns actionable counters for offene/überfällige Aufgaben, Fristen heute bzw. diese Woche, unread/unreplied communication counts, workflow counters for linked calendar events, documents, notes, and email automation agent runs, the preferred direct mail target (email_link_mailbox_scope,email_link_id), and the latest matched mail so the default Vorgang tab can render a rule-based work-first summary without loading the full timeline
/api/mandanten/[id]/timelineGET: signed-in merged customer timeline feed across received mails (email_thread_automations+ mailbox cache), sent replies (email_drafts), created tasks, created calendar entries, and uploaded documents; acceptsfilter,limit, andoffsetfor timeline pagination in the Mandant detail page
/api/aufgaben/liveGET: signed-in SSE bridge for PostgresNOTIFYupdates onaufgaben; used by the task board to refetch changed tasks directly from DB state so status/column moves animate in place even when the initiating mutation did not originate from the visible chat stream
/api/admin/mandanten/enrichmentGET: admin-only status counts for Mandanten web research (pending,running,matched,not_found,skipped,error)POST: admin-only backfill runner for existing Mandanten; acceptslimit, optionalstatuses[], and optionalforceand processes the selected rows through the shared enrichment path with Brave plus headless-browser fallback; returns409when the admin feature toggle disables profile crawling
/api/call-agent/calls/startPOST: signed-in outbound call enqueue request; forwards to the nativeclapilot-agentcall worker- active outbound calls now use the native RTP/live-audio bridge when
CLAPILOT_CALL_AGENT_LIVE_AUDIO_ENABLEDis not disabled - live caller transcription defaults to German (
CLAPILOT_CALL_AGENT_TRANSCRIPTION_LANGUAGE=de) so phone-call transcripts stay in German unless intentionally overridden - the payload can now include a selected
customer_idplus per-callallow_customer_infoandallow_documentsflags - live phone calls now forward Realtime function calls into
/api/agent-runtime/tool-proxyusing the initiating signed-in user as execution context - the live bridge now follows the Call Agent setting
realtime_provider, using OpenAI Realtime foropenaiand Gemini Live forgoogle_gemini
/api/call-agent/calls/[id]/endPOST: signed-in hang-up request for the selected active call; recordsended_byfrom the current user
- calls and faxes share the same line lock; voice start requests fail immediately while
active_kind = fax - inbound calls are created directly by the native worker in
call_agent_callswhen the registered SIP listener receives a call - inbound calls now persist an access-policy marker in
call_agent_calls.metadata_json; approved inbound callers receive full tool access through the built-inglobal_team_serviceprincipal, while unapproved callers stay in a public-info-only mode - inbound faxes currently enter
call_agent_faxesonly through the external/native receive handoff endpointPOST /internal/call-agent/faxes/receive, which writes the fax intomandanten/_inbox/..., links a placeholderdokumenterow, and then hands it into the existing inbox/document processing flow /api/call-agent/test-connectionPOST: admin-only SIP registration probe through the nativepjsuapath
- native runtime endpoints under
/internal/call-agent/*mirror the same fax surface forfaxes,faxes/:id,faxes/send,faxes/:id/retry,faxes/:id/cancel, andfaxes/receive
Agent mailbox
/api/angela/emailsGET: list agent mailbox messages; the dedicated Agent Google account's Gmail is preferred when enabled, with the configured agent IMAP mailbox retained as fallback. Acceptsfolder,search,limit, and optionalforce=1. Agent Gmail message IDs use the collision-safegmail:agent:prefix. Inbox summary rows share the same optionalsender_image_urlandsender_image_fitenrichment as/api/emails
/api/angela/emails/[id]GET: load one agent mailbox message plus automation metadata and linkeddokumenterecords for visible attachments; acceptsfolder. Inline/signature images are filtered out before import. Visible attachments are imported idempotently into Dokumente withsource_type='email_attachment'and a stablesource_id
/api/angela/emails/[id]/attachments/[index]GET: authenticated on-demand download for one visible shared agent mailbox attachment; acceptsfolderand resolves Agent Gmail or IMAP attachments
/api/angela/emails/[id]/delegatePOST: create or reuse a prepared reply draft for the selected agent mailbox message; acceptsfolder. The source language is stored with the draft and generated agent-mailbox replies default to that language.
/api/angela/emails/[id]/actionsPOST: apply agent mailbox quick actions such ascreate_task,create_calendar,mark_read,mark_unread,archive,delete, ormove; acceptsfolderand optional{ targetFolder }. Agent Gmail mutations use the dedicated account'sgmail.modifygrant
/api/angela/emails/batch-actionsPOST: apply agent-mailbox batch mutations with{ action: "mark_read" | "mark_unread" | "delete" | "move", items: [{ id, folder }], targetFolder? }; responses include per-message results plus aggregate counts so web and Apple clients can optimistically update and refetch on partial failure
/api/angela/overviewGET: aggregate KI-Assistent dashboard data including running email jobs, recent autonomous activity, synchronized scheduled native jobs, and per-task log entries for the expandable dashboard cards
Hub catalog and distribution
/api/module-store/catalogGET: signed-in module hub catalog for/modules; resolves the hub target fromAdmin Hub, serves the local hub registry directly inhub_mode=local, and otherwise proxies the configured remote hub
/api/module-store/publishPOST: admin-only publish of a workspace module to the configured hub target; writes into the local hub registry whenhub_mode=local
/api/module-store/installPOST: admin-only install of one module version from the configured hub target into the local workspace
/api/skill-store/catalogGET: signed-in skill hub catalog for/skills; resolves the hub target fromAdmin Hub, serves the local hub registry directly inhub_mode=local, and otherwise proxies the configured remote hub
/api/skill-store/publishPOST: admin-only publish of a workspace skill to the configured hub target; writes into the local hub registry whenhub_mode=local
/api/skill-store/installPOST: admin-only install of one skill version from the configured hub target into the local workspace
/api/widget-store/localGET: signed-in local widget list for/modules?tab=mini-apps, plusis_adminfor publish/install controls
/api/widget-store/catalogGET: signed-in widget hub catalog for/modules?tab=mini-apps; resolves the hub target fromAdmin Hub, serves the local hub registry directly inhub_mode=local, and otherwise proxies the configured remote hub
/api/widget-store/publishPOST: admin-only publish of one local structured widget to the configured hub target; writes into the local hub registry whenhub_mode=local
/api/widget-store/installPOST: admin-only install of one widget version from the configured hub target into the local widget registry by slug
/api/agent-store/catalogGET: signed-in specialized-agent hub catalog for/modules?tab=agentsandSettings -> Agent -> Spezialisierte Agenten; resolves the hub target fromAdmin Hub, serves the local hub registry directly inhub_mode=local, and otherwise proxies the configured remote hub
/api/agent-store/publishPOST: admin-only publish of one local specialized agent to the configured hub target as a portable JSON definition; exported data excludes embed deployments, API keys, secrets, and runtime permission bypass
/api/agent-store/installPOST: admin-only install or update of one specialized-agent version from the configured hub target into the shared specialist catalog; install forcesallowRuntimePermissionBypass=false
/api/v1/modulesGET: local hub catalog endpoint for published modules, available only when the instance runs in hub mode
/api/v1/modules/publishPOST: signed local hub publish endpoint for modules
/api/v1/modules/[slug]/[version]/downloadGET: local hub artifact download endpoint for one published module version
/api/v1/skillsGET: local hub catalog endpoint for published skills, available only when the instance runs in hub mode
/api/v1/skills/publishPOST: signed local hub publish endpoint for skills
/api/v1/skills/[slug]/[version]/downloadGET: local hub artifact download endpoint for one published skill version
/api/v1/widgetsGET: local hub catalog endpoint for published widgets, available only when the instance runs in hub mode
/api/v1/widgets/publishPOST: signed local hub publish endpoint for widgets
/api/v1/widgets/[slug]/[version]/downloadGET: local hub artifact download endpoint for one published widget version
/api/v1/agentsGET: local hub catalog endpoint for published specialized agents, available only when the instance runs in hub mode
/api/v1/agents/publishPOST: signed local hub publish endpoint for specialized-agent JSON snapshots
/api/v1/agents/[slug]/[version]/downloadGET: local hub artifact download endpoint for one published specialized-agent version
Chat and calendar
-
/api/chat/transcription/realtime/sessionPOST(authenticated): accepts{ ui_language?: "de" | "en" | "it" }and requires the signed-in profile to havechat_preferences.speech_to_text_provider="openai_realtime"- also requires
app_settings.api_live_transcribe_enabled=true; resolves the OpenAI API-key Realtime provider and compatible model selected inSettings -> ClapilotAICore -> Audio, then creates a transcription-only client secret with 24 kHz PCM input, automatic spoken-language detection, balanced-delay streaming, explicit turn commit, a two-minute connection TTL, and a hashed per-user safety identifier - returns
{ client_secret, expires_at, model, webrtc_url, websocket_url }withCache-Control: no-store; it never returns the long-lived provider key.websocket_urlintentionally has nomodelquery because the transcription model is already bound inside the transcription session; passing it as a Realtime conversation model causes the upstream connection to be rejected. - web uses
webrtc_url; Apple clients usewebsocket_urland send base64 PCM chunks. Provider/configuration failures are localized and surfaced instead of silently falling back to remote transcription
-
/api/chat- normal chat keeps shell/bash snippets inside the normal agent prompt instead of intercepting them server-side
- provider/model identity questions such as
openai oder anthropic?,welches llm?, orbist du gpt-5.4?are answered deterministically from the current session runtime instead of relying on model self-reporting - the agent decides from full message context whether to execute a local command or just analyze/explain it
- direct commands like
whoami,pwd,git status --short,/run <command>, and fencedbashblocks are treated as normal user input, not as transport-level shortcuts - local shell execution and structured package installs now flow through the runtime agent tool path (
exec_command,package_install) - Teamchat/group-chat turns can additionally bind the built-in
global_team_serviceexecution principal while still keeping persisted history on the room-scoped session key - attachment payloads still carry uploaded file bytes for supported image/document types, and may now also include optional hidden
filePathmetadata so web, floating chat, and Apple chat clients can reference the original file location without exposing that path in the visible transcript UI - personal history responses from
GET /api/chat/sessions/:sessionId/messagesreplace persisted inline attachmentdataURLs with authenticated/api/chat/sessions/:sessionId/messages/:messageId/attachments/:attachmentIndexURLs. This keeps large historical images, files, and audio out of the history JSON while web, iOS, and macOS load the same user-owned bytes on demand. - personal-chat document uploads remain active runtime context for up to four subsequent text-only user turns in the same session. The backend rehydrates the most recent stored file bytes for the agent run without copying them into each follow-up row; a new upload, explicit document/reply reference, or conversation-reset phrase replaces or clears that inherited context
-
personal-chat attachment payloads may include
type: "audio"with base64data,mimeType,name, optionaldurationMs, and optional hiddenfilePath;/api/chatstores the audio as a user-owned chat asset, runs STT on the backend, injects the transcript into the normal agent turn, and marks the turn for an assistant audio reply. Web and native file pickers classify imported WAV, MP3, M4A, and OGG files as audio attachments (up to 25 MB); in the Apple chat composer this payload can also be produced by pressing and holding the mic button, while a short mic tap remains speech-to-text dictation. -
team-chat/group-chat turns sent through
/api/chatmay now also includetype: "audio"; the backend runs the same STT step for prompt assembly and persists the recorded user audio inline on the room message so the team-chat timeline can keep rendering it after reload -
finalized Team Chat agent and automation replies resolve owned audio references from
.clapilot/agent-media/<owner>/...into persistedtype: "audio"attachment metadata before local paths are removed. Automation delivery carries the persisted service-principal ID as the media owner, matching first-party TTS/image creation instead of borrowing a creator or viewer user scope. First-party TTS creation records owner, canonical path, MIME type, size, and SHA-256 provenance inagent_media_assets; derived audio assembled by ffmpeg/HyperFrames must callmedia_register_audioonce after writing the final file, which records or idempotently verifies the same provenance without synthesizing or uploading anything. Delivery requires that immutable record in addition to owner-directory containment and rejects traversal, symlink, hard-link, replacement, and type/size mismatches. The resolver accepts absolute, workspace-relative, and Markdown-link references and caps the combined audio payload at 15 MB across at most four files. Ownedautomation output is materialized into a persistent Team Chat image attachment at the same delivery boundary; the authenticated source URL is removed from the stored reply so room viewers never depend on the automation creator's user scope. History responses expose stable authenticated attachment URLs instead of repeating audio Base64 bytes; web and native Apple Team Chat timelines load those URLs on demand through their playback controls.- personal audio-origin turns now persist
message_meta.audioReplyRequested = true, while the final assistant text reply can additionally persistmessage_meta.assistantAudiowith the generated TTS attachment metadata (type,name,size,mimeType,url, optionaltranscript, optionaldurationMs) - assistant TTS audio replies are currently still limited to personal
/chat; team-chat/group-chat audio turns currently return the normal text assistant reply only - personal chat and assistant-backed team-chat turns sent through
/api/chatno longer support a deterministic/image <prompt>transport shortcut; image-related text remains normal chat input, and the runtime agent may dynamically callimages_generateorimages_editwhen the full conversation context warrants it - when a current
/api/chatturn includes uploaded image attachments, the backend imports those images as user-owned generated-image assets and passes their ids throughclientContext.currentImageAttachmentAssetIds, allowing a later dynamicimages_edittool call to target the latest chat image without bypassing the agent decision - personal and team-chat requests may include
documentReferences[](document id/title/type plus optional metadata) from the#reference autocomplete flow;/api/chatpersists those refs inchat_nachrichten.message_meta.documentReferencesfor personal chat and inchat_group_messages.message_meta.documentReferencesfor group-room Angela turns, then injects document summaries/excerpts into the current prompt as prioritized document context - personal-chat and team-chat Angela turns may also include
replyReference(messageId,messageRole,authorName,text);/api/chatpersists that quoted-message snapshot in message metadata and injects it back into the current prompt. The server also loads images/files from the quoted row's stored attachment JSON and from markdown image links to generated-image assets or workspace files, attaches materialized media only to the agent run, and passes existing generated-image asset ids through to image/video tools without duplicating those assets - pending team-chat Angela turns now also persist
chat_group_messages.message_meta.assistantToolStatuseswhile tools are still running so every room viewer can see the same live progress state in the sidebar Angela card - persisted
assistantToolStatusesentries (personalchat_nachrichtenand teamchat_group_messagesmessage meta) carry{ id, label, state, toolName? };toolNameis the raw runtime tool identifier (for exampleBash,emails_list_messages) and lets clients pick the matching icon in the chat tool-call timeline log. The retained list keeps the most recent 24 tool calls per assistant turn; web chat renders the latest five by default and reveals the older retained calls on demand - while a model is streaming a thinking block before its visible answer, web and Apple chat surfaces keep the latest ten rendered lines visible by default and provide an inline disclosure for the full block; collapsing again returns to the latest-ten-line view
clapilot.toolSSE frames may includeevent.todoList: Array<{ id, label, status }>withstatus = pending|active|done; each frame replaces the current checklist, and todo-producing tools are omitted from the generic tool-status list- personal and team assistant rows persist the latest checklist as
message_meta.assistantTodos, including pending writes and the final write without forcing unfinished items todone; chat history and floating-chat history hydrate the same field after reload - one enabled specialized
@agentHandlemention in a personal chat turn routes that turn into the mentioned specialist; personal chat accepts one specialist target per turn. In Team Chat, every explicitly mentioned invited specialist is queued in parallel as one exclusive target set, so Angela does not also produce a duplicate reply - team-chat room specialists are stored as room-scoped invitations with
reply_mode=mention_only|all_messages; unmentioned team-chat turns fan out to every invited enabled specialist whose mode isall_messages, using the same detached specialist pending/finalization flow as explicit@agentHandlementions - team-chat specialist mentions run with the current user request plus a compact visible room-context bundle of the previous relevant team-chat messages (currently capped at 10), including prior named specialist replies; Angela/main-agent turns keep the normal broader team-chat transcript replay
- the floating personal chat now uses the same specialized
@agentHandlecomposer flow as/chat, so specialists can also be invoked from the sidebar widget - specialized
@agentHandlementions are now detached background tasks:/api/chatpersists the pending specialist bubble immediately, returns control to the parent chat route without blocking on the specialist run, finalizes that same bubble later when the specialist task completes, and now persists liveassistantToolStatusesupdates for those backend specialist runs as tools start/finish - direct specialist replies are persisted as separate assistant rows instead of only reusing the original personal user-turn
antwort; personal specialist rows usemessage_origin = assistant_specialist|assistant_specialist_delegated, async main-agent follow-up rows usemessage_origin = assistant_async_callback, while team-chat rows reusesender_display_nameplus assistant identity inmessage_meta - specialist assistant rows may carry
message_meta.assistantAgentId,assistantAgentHandle,assistantAgentName, optionaldelegatedByAgentId, optionaldelegatedByAgentName, andinvocationType = mention|delegationso the frontend can render named assistant bubbles consistently after reload - when the main agent delegates via
delegate_to_specialized_agent, the tool now returns immediately with a queued task payload; once the specialist finishes, the backend asynchronously triggers a second main-agent run and persists that later follow-up as a separate assistant message - when the main agent fans out via
spawn_clapilot_subagents, the tool creates oneclapilot_subagent_tasksrow per generic worker inside aclapilot_subagent_batchesrow, persists visible pending worker bubbles usingmessage_origin = assistant_subagentin personal chat, and triggers one final async main-agent callback usingmessage_origin = assistant_subagent_callbackafter every worker is completed or failed - when no explicit personal
sessionIdis provided,/api/chatnow resolves or creates the user’s main personal session instead of falling back to the latest active custom session - the first user turn in a fresh custom personal session now triggers automatic session naming from that first prompt; manual session renames stay authoritative and are not overwritten later
- group-chat requests accept
groupChat=trueplus optionalroomIdso/team-chatcan keep the shared team room separate from future room-based chat variants while still reusing the KI-Assistent streaming path - each streamed turn records its native runtime gateway key as
message_meta.assistantRunSessionKeyon the pending user-turn/room row; because the runtime stores the chat message id as theagent_runsidempotency key, history reads reconcile stuck placeholders against the backing run: a terminal run without a delivered answer clears the placeholder within ~2 minutes (message_meta.assistantRunExpired), and a run that completed while no web producer was alive (e.g. web container restart mid-turn) back-fills itsoutput_textas the reply (message_meta.assistantRunRecovered) instead of losing the answer; rows without run linkage keep the coarse created_at/updated_at staleness backstop - persisted KI-Assistent replies in personal chat sessions now also trigger Apple push notifications through APNs when device registration is configured
- personal audio-origin turns now persist
-
/api/chat/steer- signed-in endpoint used by the web chat queued-message "send now" control
POSTwith{ sessionId, groupChat?, message?, attachments? }resolves the same native runtimesessionKeyas/api/chat, then forwards toPOST /internal/runs/steer- succeeds for running OpenAI-Codex subscription bridge turns through Codex app-server
turn/steer - succeeds for running Claude subscription bridge turns by writing a realtime user message into the active
claude -p --input-format stream-json --output-format stream-jsonprocess - also supports live steering for active native/embedded-PI runs: during a tool call the follow-up is injected into that tool result; during model generation the runtime aborts the active provider request, keeps the original stream alive, and immediately starts a continuation provider step with the follow-up
- native steering is acknowledged only while a provider/tool step owns a guaranteed delivery path; the small transition/finalization gap returns
409withreason=native_boundary_transition, leaves the browser message queued, and lets the normal queue dispatcher send it as the next turn - when no live steering channel exists, the native runtime checks the latest persisted
agent_runsrow instead of claiming that no native engine exists: still-running rows return409withreason=run_not_steerableand remain queued, while terminal rows that still own the pending chat placeholder returnretryAsNewTurn=truewithreason=run_interrupted|run_finished; an older completed run cannot trigger recovery for a newer turn still in preflight - for
retryAsNewTurn=true, the web endpoint immediately reconciles the terminal run's stale assistant placeholder; the chat page and floating widget abort any stale browser stream, reload history, and let the existing queue dispatcher start the message as a new turn - assistant-origin automation/system alerts are persisted into the same personal chat timeline and reuse the same APNs delivery path
- persisted KI-Assistent replies in group-chat rooms now trigger Apple push notifications through APNs when device registration is configured
-
/api/chat/stop- signed-in endpoint used by the chat composer stop control (web chat page and floating widget)
POSTwith{ sessionId, groupChat? }resolves the same native runtimesessionKeyas/api/chat/steer, finalizes every pending assistant placeholder in that personal session or team room (assistant_pending = FALSE, stop notice,message_meta.assistantRunStopped = true), and forwards toPOST /internal/runs/abortfor the session's default gateway key plus every distinctmessage_meta.assistantRunSessionKeyrecorded on the cleared placeholders- works without a live browser stream: after a reload or runtime restart the stop control still clears the stuck turn and cancels the backing
agent_runsrows, so the composer unblocks immediately - responds
{ ok, stoppedMessages, agentAbort: { ok, aborted: { orchestrator, native, dbRuns, terminated }, errors[] } };agentAbort.terminatedistrueonly when every targeted runtime confirms that its exact live run stopped (or no live/persisted run remains). An unreachable runtime or a pending cancellation keeps the outer placeholder-cleanup response successful but returnsagentAbort.ok = false,terminated = false, and a runtime error inerrors[].
-
/api/chat/audio/[id]GET: authenticated byte-range-capable streaming endpoint for one stored personal chat audio asset owned by the signed-in user; used for both recorded user audio messages and assistant TTS replies in web and Apple chat timelines
-
/api/chat/link-previewGET: signed-in URL metadata extraction (urlquery param) returning{ url, final_url, title, description, image_url, site_name }for chat link preview cards
-
/api/chat/group/directoryGET: signed-in list of the user's accessible team-chat rooms as a compact directory payload (used by pickers such as automation result targets and share flows)
-
/api/chat/group/messagesGET: load room history fromchat_group_messagesfor the requested room (room=<room-id>), includingmessage_meta.documentReferencesfor referenced documents/images,message_meta.replyReferencefor quoted replies, optionalmessage_meta.assistantToolStatusesfor in-flight Angela work, and update the current member heartbeat. Large inline agent avatars inmessage_meta.assistantAgentProfileImageUrlare replaced with stable entity URLs (/api/specialized-agents/:id/profile-imageor/api/scheduled-tasks/:id/profile-image) at the shared persistence boundary. Owned agent-audio attachments similarly expose authenticated/api/chat/group/messages/:messageId/attachments/:attachmentIndexURLs instead of returning their bytes in every history poll.GET /api/specialized-agents/:id/profile-imageandGET /api/scheduled-tasks/:id/profile-image: authenticated, cacheable delivery for stored inline avatar data. Team Chat references include a content-hashvparameter, allowing the browser to retain matching private responses as immutable cache entries while an avatar change automatically produces a new URL. Unversioned legacy references keep the short revalidation policy. Oversized inline values are decoded only at this delivery boundary and are not copied into new Team Chat messages.GET /api/chat/group/messages/:messageId/attachments/:attachmentIndex: authenticated delivery for one stored agent-audio attachment. Access requires membership in the message's room; the server revalidates the creation-time database provenance, attachment owner, path containment, file identity, single-link state, type, size, and content hash before reading it through a no-follow file handle.POST: persist a human room message for the requested room; used for direct messages in/team-chat, accepts the same attachment JSON shape used by the chat UIs (including optional hiddenfilePathmetadata) plus optionaldocumentReferences[]and optionalreplyReference, and now also fans out Apple push notifications to the other room participants
-
/api/chat/group/roomsGET: load the signed-in user’s team-chat room list, the member directory including heartbeat presence (is_online,last_seen_at), and atypingByRoommap with short-lived room typing indicators. The list contains active memberships plus every non-deleted public channel; app admins additionally see every private channel, but never other users'directorgroup_dmrooms. Each room includesis_member; discovered non-member rooms reportunread_count: 0and the real activemember_count. The web and native Apple clients additionally combine this with the enabled specialized-agent catalog for direct specialist DMs and channel invitation search without treating specialists as human room members.POST: create a team-chat room. Channels acceptkind: "channel_public"|"channel_private", default to public in the first-party UI, and start with the creator plus explicitly suppliedmemberUserIdsinstead of every global user. All new channels/groups start without invited specialists. PassingspecializedAgentIdopens or creates a signed-in-user direct specialist room backed by a persistedagent:<handle>room default.GET /api/chat/group/rooms/[id]: return the accessible room's active human members,agent_to_agent_enabled, the built-inmainAgentmembership/reply mode, and invited specialized agents. Opening a public channel auto-joins a signed-in non-member; app admins may inspect private channels without becoming members. Private channels remain membership-only for regular users.PATCH /api/chat/group/rooms/[id]: channel owners, room admins, and app admins can setvisibility: "public"|"private"; direct/group rooms reject visibility changes.clapilot-members(#general) is public by default, but admins may make it private, which suspends auto-join and enables member exclusion; while it is public,memberUserIdschanges remain rejected because auto-join includes everyone. Room managers can also replace active human membership withmemberUserIds, setagentToAgentEnabledfor public/private channels, invite/update/remove the main agent, or independently invite/update/remove specialized agents. The creator remains a member, removed people lose private-room visibility, presence and mention eligibility, and can be re-invited safely.
-
/api/chat/group/rooms/[id]GET: load one accessible room plus humanmembers[], built-inmainAgent, and room-scopedspecializedAgents[]invitations; the room and agent records exposemention_only|all_messagesreply policyPATCH: update room metadata/member lists, optionalvisibility: "public"|"private", and optionalagentToAgentEnabled; manage the main agent with{ action: "inviteMainAgent"|"updateMainAgent"|"removeMainAgent", replyMode? }; or manage specialist invitations with{ action: "inviteSpecializedAgent"|"updateSpecializedAgent"|"removeSpecializedAgent", specializedAgentId, replyMode? }. Channel owners, room admins, and app admins can manage channels even when an app admin is not a member. Agent settings and visibility apply only tochannel_publicandchannel_private. The default general channel starts public; admins may make it private to suspend auto-join and manage exclusions, and switching it back to public resumes auto-join for everyone.
-
/api/chat/group/typingPOST: refresh or clear the signed-in user’s short-lived room typing heartbeat with{ roomId, active };active=falseremoves the typing marker immediately
-
/api/chat/group/room-configGET: return the effective main-agent runtime model for the requested team-chat room (room=<room-id>), combining the persisted room override with the current runtime session model lookup, plusmainAgentmembership/reply policy and the room-scopedspecializedAgents[]invitation list used by team-chat mention autocompletePATCH: update the requested team-chat room model via{ roomId, model };nullor omittedmodelclears back to the room default, specialistagent:<handle>refs are ignored for team rooms, and the route also best-effort syncs the runtime session model so the next team-chat turn uses the new selection immediately
-
/api/specialized-agentsGET: signed-in users receive the enabled shared specialist catalog for direct specialist DMs and room invitation search (id,handle,name,description, optionalprofile_image_url,enabled,sort_order); team-chat channel mention autocomplete filters this catalog to the active room's invited specialists. Admins receive the full admin-managed catalog including prompt, optionaldefault_model_ref,profile_image_url, channel link state (telegram_channel_enabled,telegram_allow_without_approval,has_telegram_bot_token,telegram_bot_token_hint,whatsapp_channel_enabled,whatsapp_allow_without_approval,whatsapp_number),skill_keys,allowed_tool_names,allowed_auth_resource_keys,include_core_memory_tools,personal_memory_enabled,allow_runtime_permission_bypass, bundled metadata, and resolved local skill metadata. Bundled specialists such asagent-orchestrator-supervisorandpet-creatorappear in their own UI section, can be edited for allowed fields such as model/prompt, but cannot be deleted or re-keyed.POST: admin-only create path for one shared specialized agent with{ handle, name, description?, profileImageUrl?, prompt?, defaultModelRef?, telegramChannelEnabled?, telegramAllowWithoutApproval?, telegramBotToken?, clearTelegramBotToken?, whatsappChannelEnabled?, whatsappAllowWithoutApproval?, skillKeys?, allowedToolNames?, allowedAuthResourceKeys?, includeCoreMemoryTools?, personalMemoryEnabled?, allowRuntimePermissionBypass?, enabled?, sortOrder? }.personalMemoryEnableddefaults totrue; P1 persists and forwards it but does not expose a UI control. IfprofileImageUrlis omitted or invalid, Clapilot stores a deterministic built-in SVG fallback avatar derived from the agent name/handle/description. Uploaded profile pictures may be PNG, JPG/JPEG, or WebP data URLs up to 2 MB. Telegram bot tokens are stored encrypted and are never returned in cleartext.whatsappNumberis not user-entered; the native runtime derives and persists it from the QR-linked WhatsApp account.- Runtime session requests carry this setting as
specializedAgent.personalMemoryEnabled; changing it alters tool scope and invalidates reusable bridge-session scope hashes.
-
/api/specialized-agents/[id]GET: admin-only fetch for one specialized agent including resolved local skill metadata and the same prompt/tool/auth/approval fields used by the specialist editor.PATCH: admin-only update path for any subset of the same specialist definition fields; prompt, tool allowlist, auth scope, and permission-bypass changes are persisted on the specialist record rather than a separate side table.DELETE: admin-only delete path for user-created specialists; bundled specialists return400because shipped system workflows reference them by stablebundled_key
-
/api/specialized-agents/[id]/channels/whatsapp/authGET: admin-only status for the specialist's dedicated WhatsApp Web session; returns the same shape as/api/agent-runtime/channels/whatsapp/auth, includinglinked,connected, derivedselfE164,authDir, and any active QR login state.POST: admin-only specialist WhatsApp auth actions with{ action: "start" | "wait" | "logout", force?, timeoutMs? };startgenerates a QR code,waitchecks whether the QR scan completed, andlogoutremoves the specialist-scoped WhatsApp auth state. The native runtime stores the derived linked number back on the specialist after successful login.
-
/api/specialized-agents/[id]/channel-approvalsGET: admin-only list of Telegram/WhatsApp approval rows scoped to that specialist only; these rows are excluded from the generalClapilotAICore -> Kanäleapproval queues.POST: admin-only approval decision with{ id, status }where status isapproved,denied, orpending. Specialist approvals do not require a Clapilot user mapping; inbound runs execute in the specialist envelope with the specialist prompt, tool allowlist, auth scopes, default model, and permission mode.
-
/api/specialized-agents/profile-iconPOST: admin-only image-generation helper for the specialized-agent editor; accepts{ name?, handle?, description?, prompt? }, generates a square profile avatar through the configured image-generation runtime using the Clapilot tint palette/style guide, stores it as a generated image asset, and returns{ profile_image_url, asset }so the caller can save the URL on the agent. Image-generation transport errors are normalized to a user-facing retry/upload message instead of exposing provider internals.
-
/api/specialized-agents/[id]/embedGET: admin-only fetch for one specialist's external embed deployment; returns the stored deployment plus a placeholder HTML snippet template using the current Clapilot base URL. The deployment includespublic_allowed_tool_names[], which is the only tool allowlist used by public website/API-key runs.PUT: admin-only upsert path for{ publicSlug, enabled, runtimeAccessMode, publicAllowedToolNames, supportsFileAttachments, allowedOrigins, welcomeMessage }; also ensures a restrictedagent_service_principalsrow exists for that public specialist deployment.runtimeAccessModeis forced topublic_safe;publicAllowedToolNamesis filtered to public-safe tools and is independent from the specialist's internalallowed_tool_names, Core Memory, auth scopes, and runtime-bypass settings.
-
/api/specialized-agents/[id]/embed/keysPOST: admin-only create path for one publishable embed API key tied to the specialist deployment; accepts optional{ label, expiresAt }and returns{ api_key, plain_text_key, snippet, deployment }, whereplain_text_keyis shown only once. Each key also owns a stablesession_idmapping so external callers can omit a session header and still continue the key-bound specialist session.
-
/api/specialized-agents/[id]/embed/keys/[keyId]DELETE: admin-only revoke path for one specialist embed API key
-
/api/specialized-agents/embed-abuseGET: admin-only overview of blocked/rate-limited public embed traffic; accepts optionalagentIdandlimit(default 80) and returns recent abuse events plus per-deployment counters for the specialist embed settings UI
-
specialized-agent hub snapshots
- schema:
{ kind: "clapilot.specialized-agent", schema_version: 1, handle, name, description, prompt, default_model_ref, skill_keys, allowed_tool_names, allowed_auth_resource_keys, include_core_memory_tools } - intentionally omitted: public embed config, API keys, secrets, service principals, and runtime permission bypass
- schema:
-
/api/public/agents/[slug]OPTIONS: CORS preflight for public/embed agent metadata requestsGET: public metadata endpoint for one enabled embedded specialist; requiresX-Clapilot-Embed-Key, checks the deployment origin allowlist against the incomingOrigin, and returns{ agent, deployment }for widget bootstrapping without a normal user session, including deployment flags such asruntime_access_modeandsupports_file_attachments
-
/api/public/agents/[slug]/messagesOPTIONS: CORS preflight for public/embed message requestsPOST: public message endpoint for one enabled embedded specialist; requiresX-Clapilot-Embed-Key, checks the same origin allowlist, accepts{ sessionId?, message }, runs the specialist in isolated public-embed scope, and returns{ sessionId, agent, reply, run }so a website widget can keep lightweight continuity without using the normal personal/team chat routes. IfsessionIdis omitted, the endpoint uses the API key's storedsession_idmapping instead of creating a new random session.- the endpoint now also applies server-side safety and abuse guards before any model run:
- obvious prompt-injection attempts targeting hidden instructions/system prompts are blocked
- obvious requests for secrets, credentials, or tokens are blocked
- obvious requests for internal/private workspace activity are blocked
- per deployment + IP limits cap both the number of new sessions per 24 hours and the message frequency per 10 minutes / 24 hours
- blocked public requests return a safe assistant reply instead of executing the specialist, and rate-limited JSON responses include
Retry-After
-
/api/v1/modelsGET: OpenAI-compatible model list for a generated specialist embed API key supplied asAuthorization: Bearer <key>orX-Clapilot-Embed-Key. The key is scoped to one enabled specialist deployment, so the response lists only aliases for that specialist such as the public slug, handle,agent:<handle>, andclapilot/<slug>./v1/modelsis also supported as a compatibility alias for clients that expect the standard OpenAI path at the domain root.
-
/api/v1/chat/completionsPOST: OpenAI-compatible chat-completions endpoint for generated specialist embed API keys. Accepts normal{ model, messages, stream?, user? }payloads and returns OpenAI-stylechat.completionJSON ortext/event-streamchunks.modelmust match one of the aliases returned by/api/v1/models; the API key determines the underlying specialist, prompt, public embed tool allowlist, service principal, and public-safe runtime envelope./v1/chat/completionsis also supported as a compatibility alias for clients that expect the standard OpenAI path at the domain root.- server-side execution defaults to the public embed guardrails: no authenticated user context, only
public_allowed_tool_names[]from the embed deployment, no fallback to internal specialist tools, no stored auth scopes, no Codex/Claude subscription bridge routing, prompt/secret/internal-data safety checks, and deployment/IP rate limits. An empty public allowlist means exactly zero tools.X-Clapilot-Session-Idorusermay override the lightweight session key for rate-limit continuity; when both are omitted, the API key's storedsession_idmapping is used so the same key continues the same specialist session. Safety checks inspect the latest user message only, so upstream system/developer instructions that mention secrets or API keys do not trigger the public-safe canned reply by themselves. Non-streaming responses includeclapilot_session_id, and both streaming and non-streaming responses exposeX-Clapilot-Session-Id. - publishable embed/API keys cannot switch to the normal internal specialist runtime. Full internal specialist capability requires an authenticated signed-in Clapilot route, not these public endpoints.
- vision input supports OpenAI-style
image_urlcontent parts withdata:image/...;base64,...values and raw base64 image fields such asimage_base64,base64, ordatawhen paired withtype: "input_image"/type: "image". - when an allowed public specialist uses
images_generate, generated images are stored under the embed service principal and returned as tokenized public links. Non-streaming responses include these links inchoices[0].message.contentand in the extension fieldclapilot_images[]. - the specialist settings dialog shows these exact OpenAI-compatible paths in
Externe Kanaele -> Web / UI Embed -> API Keysalongside the generated key. The API uses/api/v1/chat/completionsas the stable path and selects the specialist through the OpenAImodelfield.
-
/api/public/generated-images/:id?token=...GET: public-safe generated image download used by public specialist/API and Team Chat image output. The image id alone is not enough; the per-image token must match the hash stored in the asset metadata.
-
/api/public/generated-videos/:id?token=...GET: public-safe ready-video download used by Team Chat. The raw token is returned only in the generated link; its SHA-256 hash and room scope are stored ingenerated_videos.metadata.public_access.
-
/api/specialized-agents/overviewGET: signed-in lightweight overview for the end-user-friendly Agenten segment inside/geplante-aufgaben?view=agents; returns{ summary, agents, running, is_admin }with per-agent counts, optionalprofile_image_url, last activity, running-session counters, active specialist sessions, and per-agentrecent_runs[]history previews for expandable row drill-down. Non-admin responses scope running/history entries to the caller’s own personal specialist runs plus accessible team-chat rooms instead of exposing global chat content
-
/api/agent-runtime/tool-catalogGET: admin-only native tool-catalog endpoint for the specialized-agent settings UI; returns the current ClapilotAICore tool inventory with normalized{ name, description, category, parameterNames, requiredParameterNames, isCore, isMainAgentOnly, selectableForSpecialists, selectableReason }- the response also includes
core_tool_names,specialist_blocked_tool_names, andselectable_toolsso the admin UI can render a searchable picker instead of a freeform allowlist textarea
-
/api/agent-runtime/auth-catalogGET: admin-only specialized-agent auth/access catalog endpoint; returns{ auth_resources, default_selected_keys }for the current provider/runtime auth scopes (for example image generation, TTS/STT, OpenAI, Gemini, GitHub, Brave, and Perplexity) so the settings UI can render an explicit access picker instead of implicit global secret access
-
/api/chat/sessionsGET: list personal chat sessions for the signed-in user, with the main session first and other pinned sessions sorted ahead of the remaining recentsPOST: withensureScope=<key>(e.g.video-studio), get-or-create a stable, non-main feature workspace session keyed per (scope, user) with a deterministicchat-<scope>-<user>id (kept separate from the main session); withcreateFresh=true, create a new custom personal session; without either, resolve or create the user’s main personal session
-
/api/chat/sessions/[id]GET: load one personal sessionPATCH: update{ title?, model?, isPinned? }; settingtitleis treated as a manual rename and prevents later auto-title overwrites, whileisPinnedtoggles persisted session pinning for custom personal sessionsDELETE: delete one custom personal session; the main personal session is protected and returns a validation error instead of being removedPOST /api/chat/sessions/[id]/reset: clear one personal session's visible message history, rotate its runtimesession_user, and best-effort reset the attached agent runtime session so the next turn starts with fresh context while keeping the chat session itself
-
/api/chat/modelsGET: returns signed-in user's available chat models as{ models }- model entries include
runtimeProviderandsupportsSteering; the web chat usessupportsSteeringto show queued-message direct steering only for currently steerable models such as OpenAI-Codex, Claude subscription rows, or non-specialized models when the active core isembedded_pi(the internal adapter behind the Agent Orchestratorclapilot-codeharness)
-
/api/chat/live/session- returns provider-specific live connection metadata based on the configured Realtime provider/model selection
- OpenAI API responses use the GA Realtime API:
/realtime/client_secretsfor the short-livedclient_secretand/realtime/callsfor the WebRTC SDP handshake, withrealtime_api: "ga"in the response; OpenAI-family responses also includewebsocket_urlso native Apple clients connect to the configured Realtime provider URL instead of hard-coding OpenAI - OpenAI-compatible or Azure responses may return
realtime_api: "beta"when routed through their provider-specific legacy-compatible Realtime surface - Google Gemini responses include
transport: "gemini_websocket"pluswebsocket_url,access_token,instructions, and Gemini tool declarations
-
/api/chat/live/relay/sessionPOST: authenticated Apple Watch live entrypoint; creates the provider Realtime session server-side, opens the upstream provider WebSocket from Clapilot, and returnstransport: "clapilot_relay"plusrelay_session_idGET /api/chat/live/relay/[sessionId]/events: authenticated SSE stream of upstream Realtime JSON events back to the watchPOST /api/chat/live/relay/[sessionId]/input: accepts one Realtime JSON event from the watch, includinginput_audio_buffer.append, tool responses, and cancellation events, then forwards it to the upstream provider WebSocketDELETE /api/chat/live/relay/[sessionId]: closes the server-held upstream WebSocket; relay sessions also expire automatically after inactivity
-
/api/chat/live/tools- live tool execution may return
triggerReload,refreshTopic,uiActions[], andmutationEventId - includes
navigate_user_to_page, which resolves validated internal Clapilot routes and emitsnavigation.openso chat/live agents can move the user directly into pages like E-Mail detail, calendar event, document folder (/dokumente?folder=:folder_id), documents preview/editor, tasks, Mandanten, Website Canvas, or other internal app destinations - includes
google_meetfor Live Voice so spoken sessions can join, inspect, speak in, transcribe, summarize, and leave managed Google Meet browser participants. Join first validates the meeting space through the Meet REST API with the dedicated Agent Google account. The session payload reportsaccountEmailplusbrowserAccountMode:signed_inwhen the persistent managed-browser profile already has Google login cookies, orguest_fallbackwhen OAuth access was verified but Google browser login is still absent. Successful join automatically requests captions and starts the server-side voice-to-voice bridge when enabled and remote Meet audio is available - the live tool catalog now includes
exec_commandfor direct shell/bash execution inside the native runtime workspace - the live tool catalog now includes
mini_apps_*andwidgets_*operations for listing, creating, updating, and filling Widgets from chat/live-agent flows
- live tool execution may return
-
widget tool calls stay structured-only and never accept raw HTML;
widget_definitioncan be omitted on create so Clapilot infers a native layout fromlatest_data- the live tool catalog includes
notizen_*operations for folder, note, and page management inside the Notizen module, includingnotizen_duplicate_localfor read-only reMarkable imports - the live and native tool catalogs now include
faxes_list,faxes_get,faxes_send,faxes_retry, andfaxes_cancelfor the shared Call Agent fax workflow - the native runtime tool proxy mirrors calendar CRUD through
calendar_list_events,calendar_get_event,calendar_create_event,calendar_update_event, andcalendar_delete_event; list results defensively collapse provider duplicates by canonical calendar, external event ID, and instance start time before briefings or agents receive them;calendar_create_eventaccepts optionalcalendar_nameto create directly in a matching Apple/iCloud calendar and returns an error when the Apple calendar name is missing or ambiguous; create/update acceptattendees: string[]and send Google invitations viasendUpdates=all(an empty update list removes all guests), and also acceptcreate_google_meetorconference_type="google_meet"to create/add a Google Meet link. Agent-created Google events prefer the dedicated Agent Google account configured under App Connections and fall back to the user's connected account. Google updates useevents.patchwith stored ETag/If-Match, returning conflicts instead of overwriting newer remote changes. - the native runtime tool proxy mirrors Aufgaben board/task operations through
aufgaben_list_boards,aufgaben_create_board,aufgaben_list_statuses,aufgaben_manage_statuses,aufgaben_list_tasks,aufgaben_get_task,aufgaben_create_task,aufgaben_move_status,aufgaben_assign_task,aufgaben_update_task, andaufgaben_delete_task; status filters and mutations accept the workspace's configured keys, invalid keys return the valid list, board/task reads are scoped to shared boards plus the authenticated user's private boards, board listing includes the preset templatesakquise,marketing, andfinanzen, and task create/update tools accept the structured CRM/follow-up/deal fields used by Akquise and partner workflows - the live/native tool catalogs include
cases_list,cases_get,cases_create,cases_update,cases_delete,cases_link_entity,cases_unlink_entity,cases_add_communication, andcases_add_key_datefor the optional bundled Cases module - the native runtime tool proxy mirrors mailbox and draft flows through
emails_list_messages,emails_get_message,emails_apply_message_action,emails_list_drafts,emails_get_draft,emails_create_draft,emails_update_draft,emails_delete_draft, andemails_send_draft; personalemails_list_messagessearches are global across available mail folders unless the tool call supplies a folder, which keeps folder-scoped searches explicit, andemails_apply_message_actionuses the same action routes as the E-Mail UI for read/unread/move/archive/delete actions - the live/native Website Canvas bridge exposes
website_sync_reposo chat/live agents can refresh the active repo clone to the latest remote fast-forward state - long-running
website_ensure_sessionandwebsite_apply_changecalls usePOST /api/modules/website-canvas/api/operation/{ensure|apply}and return an operation ID with HTTP 202;GET /api/modules/website-canvas/api/operation/:operationIdprovides idempotentqueued/running/succeeded/failedstatus, optionally waiting up to 20 seconds throughwaitMs, and an unknown ID is explicitlynot_started. Native provider loops allow up to 60 all-passive operation polls beyond their normal mutation-step budget, covering the Website Canvas 20-minute execution window without permitting unbounded polling. One checkout-scoped queue serializes async operations with direct ensure/sync/chat/commit/push mutations against the same shared repo or isolated checkout. Explicit idempotency keys are additionally fingerprinted with the authenticated caller and normalized payload.forceNewSessionignores a supplied existing session and creates a fresh isolated checkout. Completed records stay queryable for eight hours. Failed operations release their keys immediately for retry; successful operations retain a five-minute same-key deduplication window. - the native/live tool surfaces include
copilot_ui_render; it returns a structuredcopilot.ui.renderaction and persists normalized assistant UI payloads undermessage_meta.assistantUiElementsso web chat, floating chat, and the Apple native chat client can render CopilotKit-style response UI inline - the native runtime tool proxy mirrors document workflow operations through
documents_create,documents_list_folders,documents_create_folder,documents_update_folder,documents_delete_folder,documents_update,documents_move,documents_delete,documents_create_share, anddocuments_revoke_share; document reads are scoped to shared documents plus the authenticated user's private documents, anddocuments_updateaccepts extracted tax fields plusrelated_mandant_idsfor multi-party document assignment.documents_createcan create Word/Excel/Markdown records directly in Root-Dokumente even when the storedfile_pathends up under_inbox/..., and acceptstemplate_key="vollmacht",mandant_id, plus optionalmatter,deadline, andlocationto generate a Mandant-linked standard power-of-attorney Word draft through Word Editor - the live/native tool surfaces now also mirror physical-post workflows through
postal_mail_list,postal_mail_get,postal_mail_send, andpostal_mail_refresh - request body also accepts optional
userUtteranceso the backend can reuse the last spoken user request during fallback delegation - lookup-oriented direct-tool misses can auto-fallback server-side into
clapilot_delegatebefore the result is returned to Realtime - delegated execution routes through the native
clapilot-agentruntime backend - current structured UI mutation examples:
excel.cells.updated,excel.sheet.updated,word.document.updated
- the live tool catalog includes
-
/api/ui-mutation-eventsGET: authenticated SSE stream of persisted user-scoped UI mutation events emitted by live tools, native tool proxy executions, and chat context actionsGET ?format=json&since=<cursor>&topic=<topic>: bounded JSON cursor read for native clients; returnsevents[]plus the nextcursor, supportssince=latestinitialization without replay, and filters server-side so an open native Aufgaben view does not repeatedly download the full task collection- each SSE item includes a stable
id/mutationEventId, optionaltopic,triggerReload,actions[], andcreatedAt - the authenticated web app shell consumes the SSE stream, while Apple clients consume the lightweight cursor form and refetch only affected task IDs, so visible pages can react to agent-driven mutations without a hard refresh
-
/api/documents/[id]/shareGET: return the active public share metadata for one document, if presentPOST: create or reuse a cryptographically random public share link for one document; accepts optionalexpires_in(24h,7d,permanent) or an absolute expiry timestampDELETE: revoke the active public share link for one document
-
/share/[hash]GET: public file delivery endpoint for an active document share; validates expiry and active state, incrementsaccess_count, and applies a simple per-IP rate limit before streaming the original file without requiring login
Physische Post (E-POST)
/api/postal-mailGET: list recent physical-post jobs from the shared E-POSTBUSINESS outbound queue; acceptslimit(1-100, default 20)
/api/postal-mail/[id]GET: return one physical-post job including persisted event history
/api/postal-mail/sendPOST: send an existing PDF document as physical post; V1 rejects non-PDF inputs and stores provider status snapshots locallyregistered_letteraccepts exactly the provider optionsEinschreiben,Einwurf Einschreiben,Einschreiben Rückschein(common synonyms are normalized; unknown values returninvalidRegisteredLetter)countryis only for international mail (German uppercase ISO 3166-1 country names, e.g.ÖSTERREICH); domestic values likeDE/Deutschlandare dropped before submission- test-mode submissions attach the configured
epost_test_emailas providertestEMail, so the rendered test letter is mailed back instead of printed
/api/postal-mail/[id]/refreshPOST: refresh one physical-post job by polling the provider status endpoint
/api/internal/postal-mail/syncPOST: internal endpoint (agent-secret header) used by the preinstalledPostal Mail Status Syncsystem automation to refresh all open physical-post jobs (statusessubmitted,processing,in_print_center) in batches
/api/postal-mail/admin/sms-requestPOST: admin-only bootstrap step to request the E-POST SMS code
/api/postal-mail/admin/set-passwordPOST: admin-only bootstrap step to set the provider password and persist the returned secret into shared app settings
/api/postal-mail/admin/test-connectionPOST: admin-only provider connectivity check using the current shared E-POST settings
/api/calendarGET: returns the signed-in user's entries for the requestedfrom/tointerval. Entry colors are normalized as lowercase six-digit hex values without palette quantization and are resolved through the same display-color helper used by the Kalender server-rendered initial state and installed web app.GET /api/calendar/calendars: lists writable calendar targets for the create-entry modal, including the local Clapilot calendar and connected Apple/iCloud CalDAV calendarsPOST /api/calendar/ai-prefill: authenticated Kalender modal helper. Sends the natural-language description toClapilotAICoreas a tool-free structured extraction run and returns{ prefill }with title, description, location, optionalcalendarName, start/end, and all-day state. The endpoint does not use deterministic client parsing and returns a validation error instead of inventing missing required details.POST: creates a calendar entry; accepts optionalcalendar_nameto write the event into a matching Apple/iCloud calendar first, mirroring the nativecalendar_create_eventtool behavior; acceptscreate_google_meet/conference_type="google_meet"to create the event in Google Calendar with generatedconferenceDataand returngoogle_conference_urlplus provider-agnosticconference_url.
/api/calendar/icalGET: exports the authenticated user's calendar entries for the requestedfrom/torange as a downloadabletext/calendar.icsfilePOST: imports iCalendar data from JSON{ content }, JSON{ url }, rawtext/calendar, or multipart.icsupload;webcal://feed URLs are normalized tohttps://before server-side fetches; recurring events are expanded into bounded local entries, deduped by iCal UID throughexternal_id+sync_source='ical', and stored as mirrored calendar rows
/api/calendar/ical/subscriptionsGET: lists the signed-in user's saved iCal subscriptions and their sync statusPOST: creates or updates a saved iCal feed subscription withname,feed_url, optionalcolor, optionalcontext_label,enabled, andsync_interval_minutes;webcal://feed URLs are normalized tohttps://; iCal subscriptions are read-only mirrors (sync_mode = read_only) and feeds are refreshed by the iCal subscription poller or when the Kalender page opens a due range
/api/calendar/ical/subscriptions/[id]PATCH: updates a saved iCal subscriptionDELETE: removes the subscription and deletes its mirrored imported entries
/api/calendar/ical/subscriptions/[id]/syncPOST: immediately syncs one saved iCal subscription for the signed-in user
/api/calendar/ical/subscriptions/syncPOST: syncs the signed-in user's enabled subscriptions, withdue_onlydefaulting totrue
/api/internal/calendar/ical-subscriptions/sync-duePOST: internal-only endpoint guarded byx-clapilot-agent-secret; the container iCal poller calls it to refresh due saved iCal subscriptions in the background
/api/integrations/apple/statusGET: returns the signed-in user's Apple iCloud connection status and service toggles for CalDAV calendar, CardDAV contacts, and iCloud Mail, including the optionalmail_addressPATCH: updates Apple iCloud service toggles (calendar_enabled,contacts_enabled,mail_enabled)
/api/integrations/apple/connectPOST: connects or updates Apple iCloud usingapple_id, an app-specific password, optionaldisplay_name, optionalmail_address, and service toggles; Clapilot validates CalDAV/CardDAV discovery before saving when those services are enabledDELETE: disconnects the signed-in user's Apple iCloud credentials
/api/integrations/apple/calendar/syncPOST: syncs Apple iCloud CalDAV calendars into localcalendar_entrieswithsync_source = apple; ordinary non-recurring Apple events can be edited, deleted, or moved between local Clapilot and Apple/iCloud calendar targets from Clapilot and written back via CalDAV
/api/integrations/apple/contactsGET: reads Apple iCloud CardDAV contacts for the signed-in user, with optionalqandmaxquery parameters
/settings/contacts- user-facing Contacts settings entry for contact import sources; the first supported import source is VCF upload into
mandanten, while Apple iCloud, Google Contacts, and Microsoft 365 contact imports are presented as future source slots tied to the existing app-connection model
- user-facing Contacts settings entry for contact import sources; the first supported import source is VCF upload into
/api/calendar/liveGET: authenticated SSE stream backed by PostgresLISTEN/NOTIFYoncalendar_entries- accepts
from/toso only changes intersecting the visible calendar range are forwarded - intended for background refetch/diff animation of created, moved, updated, or deleted events without a hard refresh
/api/calendar/[id]- calendar entries now support optional deadline metadata fields
source_type,source_origin,source_label,detected_date, andmandant_id - calendar payloads include the unified sync fields
external_id,sync_source,sync_status, andlinked_entities; Microsoft/Outlook imports are exposed assync_source='outlook'mirrored records, and iCal imports usesync_source='ical' - calendar payloads include provider-agnostic
conference_urlandconference_providerfields for online meetings; the Kalender UI also extracts Teams/Meet/Zoom/Webex links fromlocationanddescriptionas a fallback for Apple/iCal imports - entries with
source_type = fristrender with deadline countdowns, critical badges, and a deadline-only filter in the Kalender UI - calendar payloads also expose optional
mandant_idso Mandant-linked events can round-trip through the customer timeline and agent-created calendar flows PATCHacceptscalendar_namefor local/Apple events to move the entry between the local Clapilot calendar and a matching Apple/iCloud calendar; it also acceptscreate_google_meet/conference_type="google_meet"for existing Google-synced events and stores the generated Meet link ingoogle_conference_urlandconference_url.
- calendar entries now support optional deadline metadata fields
/api/generated-images/generatePOST: generate a persisted image asset via the default entry inapp_settings.media_model_catalog.imagewhen that catalog is non-empty, otherwise via the global ClapilotAICore image-generation provider/model default. Callers may pass optionalprovider_slugplusmodelto select one exact enabled runtime provider without fallback; explicit per-request values are not replaced by the catalog. Recognized model-family overrides withoutprovider_slugremain supported for compatibility. Returns asset metadata plus a renderable markdown image reference. Agent tool calls that includesource_image_pathare treated as source-image edits for compatibility so local reference images do not degrade into text-only generation.
/api/generated-images/editPOST: edit a persisted, uploaded, current chat-attachment, selected Notizen, or workspace-localsource_image_pathimage source via an edit-capable ClapilotAICore image provider and return a new persisted asset. Optionalprovider_slugplusmodelselects one exact provider without fallback. Workspace paths are constrained to the configured workspace root, imported as source assets, and recorded in generated-image metadata. If no explicit provider was requested and the configured image-generation default is an OpenAI-compatible text-to-image-only model such as Ideogram, edit calls bypass that provider and fall back to OpenAI-Codex, OpenAI API, or Gemini image routing. When the selected provider isOpenAI-Codex, Clapilot routes throughchatgpt.com/backend-api/codex/responseswith the hostedimage_generationtool and stored Codex OAuth instead of requiringOPENAI_API_KEY.
/api/generated-images/importPOST: import an uploaded/external image (up to 20 MB) as a user-owned generated-image asset and return asset metadata plus renderable markdown; used when chats and tools need a persisted asset id for a non-generated source image
/api/generated-images/[id]GET: stream the authenticated user-owned generated image binary
/api/generated-videos/generatePOST: start a persisted text-to-video or image-to-video job through the configured AI media video provider (media_generation_provider_configs). In addition toprompt, callers can pass a user-ownedimage_id/source_image_idor workspace-localsource_image_path; workspace sources are imported intogenerated_images, ownership is checked, and the source asset lineage is stored ingenerated_videos.metadata. Image-to-video is currently implemented for xAI Grok: image inputs are sent to/videos/generationsas a base64 data URI inimage.url, and the source aspect ratio is preserved by default. OpenAI-compatible video providers additionally accept reference-based generation:last_frame_image_id/last_frame_path,reference_image_ids/reference_image_paths(9 images max including the start image),reference_video_paths(3 max),reference_audio_paths(3 max), and thefit(auto/cover/contain/stretch),ref_detail(match/max) anduse_video_audiocontrols. Files are sent as repeated multipart fields (ref_image,ref_video,ref_audio,last_frame); workspace-local reference paths are constrained to the workspace root. Caps are enforced server-side before the request, and reference inputs sent to a non-OpenAI-compatible provider are rejected. Underfit=autothe configuredsizeacts as a pixel budget rather than the literal output geometry, so the responsesizefield is not authoritative. When no image is supplied and the configured default is the image-onlygrok-imagine-video-1.5, Clapilot selects the configured text-capablegrok-imagine-videomodel instead. Returns the generated-video asset metadata, provider response, and an initial poll result. Async jobs staygeneratinguntil status polling downloads the provider output.
/api/generated-videos/[id]/statusGET: read and, when still generating, poll a generated-video job by id. Any authenticated user may poll any job so workspace-global Video Studio storyboards reconcile for non-creators. Ready jobs includevideoUrlandvideoMarkdown. Chat-started async jobs also create a hidden one-shot wake-up tied to the originating web/Team Chat target; it silently reschedules status checks and posts the terminal result without requiring another user message.
/api/generated-videos/[id]GET: stream a generated video binary by id once status isready. Any authenticated user may fetch any generated video so shared Video Studio storyboards render for non-creators; creation still stamps the requesting user asowner_user_id. Markdown links to this route render as inline, controllable video players in assistant chat messages.
/api/integrations/google/oauth/startPOST: starts Google OAuth. Acceptsscope_presets/scopes, optionalaccount_type="user"|"agent", optionalredirect_path, and optionalinclude_granted_scopes(defaultfalse). Workspace connections keep historical Google grants isolated so previously approved YouTube and Drive permissions are not merged into an incompatible consent request. The dedicated agent preset uses Calendar, Gmail, Drive, and Meet-space-read scopes. Other presets includegmail,meet,youtube_live_chat, andyoutube_live_chat_write.
/api/integrations/google/oauth/api/integrations/google/oauth/complete/api/integrations/google/oauth/statusGET: returns connection state, granted scopes, connected account info, and per-service enablement flagsPATCH: updates one or more per-user Google service toggles viaservice_settings
/api/integrations/google/meet/browser-loginGET: returns the authenticated user's active managed Agent Google browser-login status;screenshot=1returns the current managed-browser viewport as a non-cached PNGPOST: starts or controls the one-time managed-browser Google sign-in withaction=start|click|type|press|refresh|close. The route never returns browser cookies and keeps the resulting Google web session in the account-isolated persistent Meet profile
/api/integrations/google/calendar/sync/api/integrations/google/contacts/api/integrations/google/docs-sheets/api/integrations/google/drive/syncPOST: synchronizes Drive files into Dokumente; accepts optionalaccount_type="agent"to use the dedicated Agent Google identity and its isolated Drive subtree
/api/integrations/microsoft/oauth/startPOST: starts Microsoft OAuth. Acceptsscope_presets/scopesas before plus optionalredirect_pathfor same-origin app paths such as/?onboarding_step=1; when present, the OAuth callback redirects back to that path withmicrosoft_oauthresult parameters instead of defaulting to/settings/app-verbindungen.
/api/integrations/microsoft/oauth/api/integrations/microsoft/oauth/complete/api/integrations/microsoft/oauth/statusGET: returns connection state, granted scopes, connected account info, and per-service enablement flags including Microsoft Mail and OneDrivePATCH: updates one or more per-user Microsoft service toggles viaservice_settings
/api/integrations/x/oauth/start/api/integrations/x/oauth/api/integrations/x/oauth/complete/api/integrations/x/oauth/statusGET: returns connection state, granted scopes, connected account info, and per-service enablement flagsPATCH: updates one or more per-user X service toggles viaservice_settings
/api/integrations/microsoft/calendar/syncPOST: imports enabled Microsoft calendar events intocalendar_entries; accepts optionalfrom,to,max_results, andcalendar_id.
/api/integrations/microsoft/contacts/api/integrations/microsoft/files/api/integrations/microsoft/drive/syncPOST: imports enabled Microsoft OneDrive files into the virtualMicrosoft 365document folder; the sync walks nested OneDrive folders up tomax_filesand upserts matchingdokumenterows.
Heartbeat
/api/heartbeat/settingsGET: read the heartbeat config, job status, and open watchlist for?scope=user(own config) or?scope=teamchat(admin only); status includeslastRunAt,nextRunAt,lastDeliveryStatus(delivered/suppressed/error), andlastErrorPOST: save{ scope, config }withconfig = { enabled, intervalMinutes, instructions, historyLimit, dndStart?, dndEnd?, sessionId? | roomId? }; the runtime reconciles the schedule within about a minute
/api/heartbeat/triggerPOST: run the heartbeat immediately with{ scope }(teamchat scope requires admin); proxies to the native runtimePOST /internal/heartbeat/triggerand returns{ ok, delivered, suppressed, text, outputPreview, watchlistAdded, watchlistResolved, runId }without shifting the regular schedule
/api/heartbeat/watchlistDELETE: remove one open watch item with?scope=user|teamchat&id=<uuid>(teamchat scope requires admin); returns the remaining watchlist
Admin and app settings
/api/admin/usersGET: list all users plus mergeduser_profilesrole/display-name/avatar data andusers.last_login_atfor the admin settings pagePOST: create a user and return a one-time temporary password for the new accountPATCH: update a user's role, update profile/account fields with{ action: "update-profile", userId, email, display_name, avatar_url }, set a password directly with{ action: "set-password", userId, password }, or with{ action: "reset-password", userId }rotate the password and return a new one-time temporary passwordDELETE: remove a user after clearing legacy non-cascading references inmandanten,dokumente,aufgaben, andnotizen; self-delete is rejected
/api/admin/backup/exportPOST: admin-only export that generates a ZIP download containingdatabase.sqlfrompg_dump,workspace/**from the full configured Clapilot workspace directory, and a smallmanifest.json
/api/admin/backup/importPOST: admin-only multipart import for a previously exported backup ZIP; requiresbackupfile plus confirmation text, restoresdatabase.sqlwithpsql --single-transaction, and replaces the configured workspace directory fromworkspace/**; olderdocuments/**backups are still accepted and only replace the sharedmandanten/document tree
/api/admin/demo-dataGET: admin-only demo-seed status for the current admin user, including current seeded record counts, mailbox/document preflight, active scenario (steuerberaterkanzleiorrechtsanwaltskanzlei), scenario options, last run metadata, and the shipped demo storylines for the active scenarioPOST: admin-only demo-seed execution; accepts{ action, scenarioId }wherescenarioIdis one ofsteuerberaterkanzleiorrechtsanwaltskanzlei- the
rechtsanwaltskanzleiscenario seeds 20 distinct synthetic legal demo documents across Kanzlei/Berufsrecht, Zivilrecht, Verkehrsrecht, Arbeitsrecht, Familienrecht, and M&A/Due-Diligence workflows; fixtures are first-party demo texts with fiktive parties, dates, file metadata, and workflow-ready deadlines/tasks reset_and_seedperforms a destructive demo reset for the current admin user's seeded Mandanten, Dokumente, Aufgaben, Kalender, Drafts, Automationen, mailbox cache rows, and tagged IMAP demo mails before rebuilding the selected scenario; seeded dates are generated relative to the reset time and kept in the active month where possible, so demo deadlines and recording flows do not age into stale fixed dates- seeded automations may include scenario-specific
draftSubjectanddraftBodyTextcopy so demo replies can contain concrete legal/tax reasoning instead of generic acknowledgements reset_emails,reset_tasks, andgenerate_activityalways operate on the currently active seeded scenario, even if a differentscenarioIdis sent, so partial resets cannot accidentally mix two different Kanzlei demoswipe_operational_datadeletes all app-local Mandanten, Dokumente, Aufgaben, Kalender, local email cache rows, drafts, automations, document folders, and the physical files under the shared document storage across the instance while keeping users, roles, passwords, global settings, and external IMAP mailbox contents unchanged
/api/admin/agent-runtime/filesGET: list editable native runtime files (clapilotaicore.json, workspace markdown, native state markdown)PUT: update the selected native runtime file; JSON writes are validated and normalized
/api/admin/agent-runtime/restartPOST: returns410because the packaged OpenClaw gateway restart path was removed; restart native services via Docker/deployment tooling instead
/api/admin/agent-runtime/terminalGET: list builtin native runtime diagnostics onlyPOST: run builtin diagnostics likenode-version,ls-state-dir,show-clapilotaicore-json, anddb-host-check
/api/admin/anthropic/oauth/startPOST: deprecated for Anthropic setup-token auth and now returns an instructional error; Anthropic-Claude expects a finishedclaude setup-tokenvalue instead of a browser callback flow
/api/admin/anthropic/oauth/completePOST: accepts a Claudesetup-token(sk-ant-oat01-...), validates it, and stores it as the subscription secret forAnthropic-Claude
/api/admin/anthropic/oauth/clearPOST: admin-only removal of the stored Anthropic-Claude subscription secret/setup-token
/api/admin/openai-codex/oauth/startPOST: starts a short-lived Codex app-serverchatgptDeviceCodelogin and returnslogin_id,verification_url,user_code, andexpires_at; no localhost callback or pasted redirect URL is required
/api/admin/openai-codex/oauth/statusPOST: acceptslogin_idplusprovider_slug, returnspendingwhile OpenAI authorization is outstanding, and on completion imports the Codex-managed credential, synchronizes the native Codex auth stores, and saves the encrypted provider secret
/api/admin/openai-codex/oauth/completePOST: legacy compatibility endpoint for completing an already-started authorization-code flow from a callback URL/query; current web and Apple provider settings use device-code status polling instead
/api/admin/rag/statusGET: return RAG health, queue diagnostics, the resolved embedding provider/model currently used by native memory + document RAG, current document vision fallback config, and vision-capable model options derived fromProvider & ModellePOST: update the explicit document vision fallback toggle and selected vision model ref
/api/admin/rag/reindex/api/app-settingsGET: returns global app settings for the current user role; responses includememory_dreaming_modelas an exactprovider/modelref or""for automatic Dreaming-model selection,main_agent_tool_restrictions_enabled(defaultfalse) for the explicit main-agent opt-in, andmain_agent_disabled_tool_namesas the stored per-tool denylist. Admins also receiveemail_auto_analysis_enabled,email_analysis_model, andemail_auto_process_blocklistfor the mail automation flowPOST: admin-only update of global app settings; acceptsmemory_dreaming_modelas an exactprovider/modelref or an empty string, returning400for malformed refs, plusmain_agent_tool_restrictions_enabledandmain_agent_disabled_tool_namesto activate and configure exact main-agent tool restrictions. Unknown tool names are discarded against the canonical runtime catalog. It also acceptsemail_auto_analysis_enabled,email_analysis_model, andemail_auto_process_blocklistto control automatic personal inbox analysis, the preferred workflow model, and the global sender/domain skip list for automatic mail processing- persists global app integrations including
github_token, the optionalgithub_pr_review_token, Google OAuth client credentials, Microsoft OAuth client credentials plus tenant hint, X OAuth client credentials, LinkedIn OAuth client credentials, plus legacy fallback audio provider secrets used outside native provider rows GET: return persisted global app toggles including document-processing mode, native runtime base URL, chat transport mode, the global search-provider choice (default_search_provider), the SearXNG instance URL (searxng_search_base_url), the first-login onboarding toggle (user_onboarding_enabled), the Mandanten profile crawl toggle (mandant_profile_web_crawl_enabled), the LiteLLM base URL (litellm_api_base_url), and admin-only key presence flags such ashas_brave_search_api_key,has_perplexity_api_key,has_litellm_api_key,has_linkedin_oauth_client_id,has_linkedin_oauth_client_secret,has_x_oauth_client_id, andhas_x_oauth_client_secretGET: admin responses still include legacychat_tts_provider,chat_tts_model,chat_tts_voice,has_google_gemini_api_key, andhas_elevenlabs_api_keyfields for compatibility, but the active global TTS/STT/image defaults now live under/api/agent-runtime/configPOST: update persisted global app toggles and global provider keys used outside per-provider runtime config, including the X OAuth client id/secret used by the X app connection flow, the LinkedIn OAuth client id/secret used by the bundled Social Media module's LinkedIn platform, optional Gemini and ElevenLabs fallback API keys, the global search-provider choice, Brave Search / Perplexity API keys, andsearxng_search_base_urlused by native web-search/enrichment paths, the LiteLLM base URL/API key used by the LiteLLM usage inspector, the first-login onboarding toggle, the Mandanten profile crawl toggle, and the admin-only Developer mode toggle
/api/app-connections/githubGET: admin-only list of named GitHub integrations with masked tokens and update timestamps (used by Website Canvas, Agent Orchestrator, and Issue Reporter target selection)POST: admin-only manage action with{ action: "create" | "update" | "delete", name, token?, previous_name? }
/api/app-connections/gitlabGET: admin-only list of named GitLab integrations with instance URL, masked token presence, and update timestampsPOST: admin-only manage action with{ action: "create" | "update" | "delete", name, token?, base_url?, previous_name? };base_urlsupports GitLab.com and self-managed GitLab
/api/integrations/browser-use/settingsGET: admin-only Browser Use Cloud configuration status; returns only{ configured }and never returns the saved keyPOST: admin-only save or removal of the encrypted Browser Use API key via{ api_key?, clear_api_key? }; accepted keys start withbu_
/api/developer/e2eGET: admin-only endpoint that requiresapp_settings.developer_mode_enabled=true; returns the in-instance Developer E2E suites and model options used bySettings -> DeveloperPOST: admin-only execution endpoint for one suite with{ suiteId, model?, keepArtifacts? }; runs against the current Clapilot instance and returns a structured result with suite status, runtime session/run identifiers, model, cleanup state, per-check results, output preview, and runtime metadatawebchat-history-replay-contextseeds stale completed webchatagent_runsplus persisted synthetic transcript wrappers, executes one current live webchat turn through ClapilotAICore, and verifies the current run stores only the latest user message, caps stored-history replay, reports dropped synthetic history turns, and avoids stale marker outputcanvas-create-edit-filesends the two German chat requests for creating a tax-declaration Canvas file and then editing it toMax MusterFrauwith a4000 EURrefund; it verifies the created HTML file exists, contains the global Canvas style colors, and is edited in place with the requested data- by default suites delete their seeded
agent_runs,agent_events,agent_context_messages,agent_session_state, and suite-owned generated Canvas files;keepArtifacts=trueleaves them behind for diagnostics
- Native runtime
/internal/runs- accepts optional
idempotencyKey/messageIdfor per-session turn deduplication; webchat sends the persisted user message row id - serializes turns per
sessionKey; queued requests stay pending and emit a lifecycle event withphase="queued"before the normal start/end stream completes
- accepts optional
/api/litellm/usageGET: admin-only proxy to the configured LiteLLM/user/daily/activityendpoint; returns normalized totals plus day-by-day model/provider/api-key breakdowns forSettings -> ClapilotAICore -> LiteLLM
/api/litellm/logsGET: admin-only proxy to the configured LiteLLM/spend/logsendpoint withsummarize=false; returns normalized individual spend-log rows plus raw metadata payloads for drill-down inspection
/api/subscription-usageGET: admin-only live subscription/quota snapshot for Codex, Claude Code, Grok, and Ollama, with 60-second server caching and normalized progress-window data for theSettings -> ClapilotAICore -> Subscription Usagepageinclude_connected=1returns{ checkedAt, hubMode, reportIntervalMs, staleAfterMs, instances }for the compactSettings -> Hub -> Subscription Usagepage.instances[0]is the API Hub itself; on a local Hub, later entries are the latest pushed snapshots from connected instances. Loading this aggregate does not contact remote instances or their providers- each
windows[]entry includes the stable upstreamkey, a normalized Englishlabel,usedPercent,utilization,resetAt, andlimitWindowSeconds. Codex labels are derived fromlimitWindowSecondsinstead of assumingprimary_windowis five hours orsecondary_windowis seven days; absent upstream windows are omitted. Claude recognizes the Fable 5 weekly bucket asseven_day_overage_includedand labels it7d Fable 5 - Claude Code live usage is served from Clapilot-owned credentials only. Full Claude OAuth credentials use Anthropic's OAuth endpoints (
/api/oauth/usagefor windows,/api/oauth/profilefor the plan) with the Claude OAuth beta header and a Claude Code user agent. Claude web-session credentials use Claude'sclaude.ai/api/organizations/.../usagepath with the storedsessionKeyplus full browser cookie header when Cloudflare requires it. The credential chain is:CLAPILOT_CLAUDE_OAUTH_TOKEN, the Claude CLI login home$CLAUDE_CLI_HOME/.claude/.credentials.jsonwritten by the settings Claude Auth flow (sourceclaude_cli_home), Anthropic provider rows withauth_mode=oauth_token,app_settings.anthropic_oauth_token, and~/.claude/.credentials.json - full Claude Code OAuth credentials (scopes include
user:profile) are refreshed automatically againstplatform.claude.com/v1/oauth/tokenwhen expired, and rotated tokens are written back to the credentials file shared with the agent runtime CLI - bare
sk-ant-oat01-...setup-token provider rows first run the Docker-local Claude CLI usage probe with the sameCLAUDE_CODE_OAUTH_TOKENbridge environment used for inference. If the CLI does not return subscription windows, the endpoint checks Anthropic's OAuth usage endpoint only as diagnostics; Anthropic rejects setup-tokens there with 403user:profile - credential candidates holding the same token are deduplicated per snapshot, and scope-rejected tokens are remembered in-process for 6 hours so auto-refreshing panels do not repeatedly hit (and rate-limit) the upstream usage endpoint
- Grok usage reuses an xAI provider configured with
auth_mode=oauth_token, refreshes that OAuth credential through the existing xAI flow when needed, and reads the current subscription credit percentage/reset from grok.com'sGrokBuildBilling/GetGrokCreditsConfiggRPC-web endpoint - Ollama Cloud usage reads the plan, account, session/hourly percentage, weekly percentage, and reset timestamps from
https://ollama.com/settings. Ollama API keys authenticate inference and return per-request metrics, but do not expose these account plan windows. The required browser Cookie header is stored in the encrypted Ollama provider secret bundle and remains eligible when that provider has no routed models;CLAPILOT_OLLAMA_COOKIEis an optional deployment override
/api/admin/developer/api-keysGET: admin-only list of instance API-key metadata plussubscription_usage_url,notifications_url,memory_url,tools_url,issue_reports_url, and the current Issue Reporter app/repository catalog, built from the configuredapp_settings.public_base_url; requiresapp_settings.developer_mode_enabled=trueand never returns key hashes or plaintext secretsPOST: admin-only create path with{ name, scopes, expires_at?, allowed_repositories? }; acceptssubscription_usage:read,notifications:read,memory:read,memory:write,inference:execute, and the high-privilegetools:executescope in any non-empty combination.issue_reports:writemust be the key's only scope and requires at least one full repository from the current Issue Reporter catalog. Public-client issue keys use theclp_public_prefix. The plaintext key is returned once, while only its SHA-256 hash and display prefix are persisted. Notification, memory, and tool execution are bound to the admin user who created the key
/api/admin/developer/api-keys/[keyId]DELETE: admin-only immediate revocation for an active instance API key; requires Developer mode
/api/v1/subscription-usageGET: versioned device/API-client endpoint returning the same 60-second-cached normalized four-provider snapshot as/api/subscription-usage- by default the response contains only the subscription accounts connected to the instance serving the API. Add
include_connected=1(orinclude_connected=true) on a local Hub to receive the aggregate{ checkedAt, hubMode, reportIntervalMs, staleAfterMs, instances }, including the Hub followed by every connected instance that has reported a valid snapshot - aggregate entries contain
{ id, host, sourceInstanceId, instanceUrl, isLocal, checkedAt, reportedAt, receivedAt, stale, snapshot }. A report becomes stale after 45 minutes; the stored snapshot remains visible so clients can distinguish missing data from an outdated report - clients must use each window's
labelandlimitWindowSecondsrather than assigning durations by array position or by Codexprimary_window/secondary_window; upstream providers can temporarily remove or reorder quota windows - authenticate with
Authorization: Bearer clp_live_...(preferred) orX-API-Key; the key must be active, unexpired, and grantsubscription_usage:read - returns stable JSON auth errors with
401for missing/invalid/expired/revoked keys and403for a missing scope or disabled Developer mode; successful requests update the key'slast_used_at - examples:
curl -H 'Authorization: Bearer clp_live_...' https://your-instance.example/api/v1/subscription-usageand, on a Hub,curl -H 'Authorization: Bearer clp_live_...' 'https://your-hub.example/api/v1/subscription-usage?include_connected=1'
/api/v1/notificationsGET: read-only polling endpoint for the API-key creator's durable message notification inbox. It returns personal assistant replies and Team Chat messages with the sameclapilot_type, title/body,message_id,session_id/room_id,sender_name, andauthor_kindrouting metadata used by Apple push notifications- authenticate with an active
clp_live_...key grantingnotifications:read; Developer mode remains the instance-wide kill switch. A key without an associated creating user is rejected with403 user_scope_required - accepts
limit=1..100(default20) and an opaqueaftercursor. Responses contain{ notifications, has_more, next_cursor, poll_after_ms }; clients should retainnext_cursor, pass it asafteron the next poll, and continue immediately whilehas_more=true, otherwise waiting at leastpoll_after_ms - the first request without
afterreturns the latest page in chronological order. Polling is non-destructive and does not change chat read state; in this contract, "unread" means notification events newer than the consumer's saved cursor - example:
curl -H 'Authorization: Bearer clp_live_...' 'https://your-instance.example/api/v1/notifications?limit=20', followed by...?after=<next_cursor>
/api/v1/memoryGET: creator-bound semantic search over approved, active native memory visible to the user who created the API key. Requiresmemory:read, a non-emptyqueryof at most 1,000 characters, and optionallimit=1..20(default6). Results contain{ id, title, content, score, memory_scope, visibility_scope, source_type, retrieval_mode }POST: submit explicit durable memory with amemory:writekey and JSON{ content, title?, visibility_scope? }.contentis required and limited to 20,000 characters;titleis limited to 200 characters;visibility_scopemay beprivateorteam. The nativestoreManualMemorypath applies content safety, audience derivation, user sharing preferences, content-hash deduplication, assertion status, embeddings, and the Learning review path rather than inserting raw memory rows- safe, non-conflicting facts may return
201with an approved memoryid. Deduplicated submissions return200. Content requiring review returns202withid=null,assertion_status="candidate", andneeds_review=true; it does not become searchable until approved. Stable response fields are{ memory: { id, assertion_id, assertion_status, needs_review, deduplicated, title, memory_scope, visibility_scope } } - Developer mode, key expiration/revocation, and the creating user remain enforced on every request. A
memory:writekey does not implymemory:read, and amemory:readkey does not implymemory:write - rate limits are enforced atomically in PostgreSQL per API key: reads allow 120 requests per 10 minutes and 5,000 per day; writes allow 60 requests per 10 minutes and 500 per day.
429 rate_limitedresponses includeRetry-After - examples:
curl -H 'Authorization: Bearer clp_live_...' 'https://your-instance.example/api/v1/memory?query=project%20preferences&limit=6'andcurl -X POST -H 'Authorization: Bearer clp_live_...' -H 'Content-Type: application/json' --data '{"title":"Project preference","content":"Prefer live runtime evidence.","visibility_scope":"private"}' 'https://your-instance.example/api/v1/memory'
/api/v1/memory/[memoryId]GET: retrieve one approved, active memory by UUID withmemory:read. The runtime applies the same creator-bound visibility check as search and returns404 memory_not_foundwhen the entry does not exist or is not visible to that key- successful responses contain
{ memory: { id, title, content, memory_scope, visibility_scope, source_type, line_start, line_end, total_lines } }; internal metadata and source paths are not exposed - exact reads share the
memory:readper-key rate-limit buckets with semantic search
/api/v1/tools/catalogGET: returns the native runtime's curatedcoding_coretool profile as OpenAI function-tool definitions shaped as{ tools: [{ type: "function", function: { name, description, parameters } }] }. The catalog includes creator-bound memory, context, Knowledge, Learning, web-search, session/status, and scoped task-comment tools; it does not expose the broad business-action catalog- authenticate exactly like
/api/v1/tools/executewith an active privateclp_live_...key grantingtools:execute. Developer mode remains the instance-wide gate. Catalog reads do not consume the tool-execution rate limit - example:
curl -H 'Authorization: Bearer clp_live_...' 'https://your-instance.example/api/v1/tools/catalog'
/api/v1/tools/executePOST: creator-bound remote execution for the same agent-tool catalog exposed byclapilot-cli. Authenticate with an active privateclp_live_...key grantingtools:executeand send{ tool_name, arguments?, client_context?, ui_language? }- the server derives
userId,sessionKey, andoriginSessionKeyexclusively from the verified key. Client-supplied identity, service-principal, channel, run, and session fields are ignored, preventing a key from changing its creator-bound scope - calls reuse the native tool-proxy dispatcher, module availability checks, main-agent restrictions, approval workflows, UI mutation publication, and error contract. Tool-level failures remain HTTP
200with top-levelok=false; authentication, malformed input, payload limits, and rate limits use normal4xxresponses tools:executeis intentionally high privilege and includes read operations, mutations, outbound-capable tools, andexec_command. Grant it only to trusted server-side clients or coding agents, store it outside source control, set an expiration, and revoke it when no longer needed- request bodies are limited to 512 KiB. Rate limits are atomic per key: 300 calls per 10 minutes and 10,000 per day;
429 rate_limitedincludesRetry-After - example:
curl -X POST -H 'Authorization: Bearer clp_live_...' -H 'Content-Type: application/json' --data '{"tool_name":"documents_list","arguments":{"limit":5}}' 'https://your-instance.example/api/v1/tools/execute'
/api/v1/inference/modelsGET: OpenAI-compatible model list for stateless instance inference. Authenticate withAuthorization: Bearer clp_live_...; the active private key must grantinference:execute, and Developer mode must be enabled- returns
{ "object": "list", "data": [{ "id": "provider-slug/model-id", "object": "model", "owned_by": "Provider label", "clapilot": { "tools": true } }] }.clapilot.toolsis a non-standard capability flag indicating whether that model's resolved transport forwards client-supplied tool definitions. IDs are the same configured model references used by ClapilotAICore and include only models the inference provider layer can route without the server-side session/agent loop - example:
curl -H 'Authorization: Bearer clp_live_...' 'https://your-instance.example/api/v1/inference/models'
/api/v1/inference/chat/completions-
POST: OpenAI-compatible, stateless provider passthrough for remote CLIs and coding clients. Authenticate with an active privateclp_live_...key grantinginference:execute; provider credentials remain inside the Clapilot instance and are never returned to the client -
accepts
{ model, messages, tools?, tool_choice?, temperature?, max_tokens?, max_completion_tokens?, stream?, stop?, response_format? }.modelis one of the IDs returned by/api/v1/inference/models;messagesuses the OpenAI chat-completions format. When both token-limit fields are present,max_completion_tokenstakes precedence. Unknown request properties are ignored.n > 1returns400 unsupported_n; the legacyfunctionsproperty returns400 legacy_functions_not_supportedand clients must usetools -
non-streaming responses use the OpenAI
chat.completionshape:{ id, object, created, model, choices: [{ index, message: { role, content, tool_calls? }, finish_reason }], usage? }. Provider/auth/quota failures use{ error: { message, type, code } }with an appropriate4xx/5xxstatus and never include provider credentials, provider base URLs, or the internal agent secret. Supplying a non-emptytoolsarray for a model whoseclapilot.toolscapability isfalsereturns400withtype: "invalid_request_error"andcode: "tools_unsupported_for_model"; the request is rejected before any provider call rather than silently dropping tool definitions -
stream=truereturnstext/event-streamwith OpenAIchat.completion.chunkdata records and a finaldata: [DONE]. Text deltas are forwarded as they arrive on streaming-capable provider transports. If a provider buffers tool calls, the completedtool_callsdelta is emitted as one chunk before the terminal finish-reason chunk -
this endpoint is deliberately not the Clapilot agent loop: it does not create agent runs or sessions, load Clapilot memory, or execute tools. Client-supplied tool definitions are forwarded to the selected model and any returned
tool_callsmust be executed by the client, which may then send tool results in a subsequent stateless request -
request bodies are limited to 1 MiB. The model-list and completion endpoints share atomic per-key
inference:executelimits of 300 requests per 10 minutes and 10,000 per day;429 rate_limit_exceededincludesRetry-After -
non-streaming example:
curl -X POST \ -H 'Authorization: Bearer clp_live_...' \ -H 'Content-Type: application/json' \ --data '{"model":"provider-slug/model-id","messages":[{"role":"user","content":"Reply with one short sentence."}]}' \ 'https://your-instance.example/api/v1/inference/chat/completions' -
streaming example: add
"stream":trueto the JSON body and usecurl -Nso chunks are displayed without client-side buffering
-
/api/v1/issue-reportsPOST: public-client issue intake for JSON requests authenticated with an activeclp_public_...key granting the isolatedissue_reports:writescope.appandtitleare required. The app is resolved to its full repository and must be present in the key's immutableallowed_repositories; checking only the repository basename is not sufficient- accepted optional fields are
details,reporter_email,platform,route_path,route_url,context,installation_id,app_version,build_number,os_version,device_model,locale, andimage_attachments. Attachments are base64-encoded PNG, JPEG, HEIC, HEIF, or WebP images, limited to three images, 5 MB each and 10 MB combined; the complete streamed JSON body is capped at 15 MB - accepted reports always enter
hub_reported_issueswith statusopen. They never directly create GitHub issues or Agent Orchestrator tasks; an admin must review and approve them in the Hub Issue Reporter queue - rate limits are enforced atomically in PostgreSQL per API key and per hashed client IP (10-minute and daily buckets).
429responses includeRetry-After. Send a stable uniqueIdempotency-Keyfor retries; repeating it with the same key returns the original report withcreated=false - the mobile key is a public identifier and abuse-limiting credential, not a confidential client secret. Prefer a B2C backend or App Attest/DeviceCheck exchange that mints short-lived report credentials; repository scoping, moderation, rate limits, expiration, and revocation remain defense in depth
/api/email-processing-blocklistPOST: admin-only helper endpoint used by the/emailsrow/detail action menus; extracts the sender address from the selected message and upserts it intoapp_settings.email_auto_process_blocklist, preserving optional reason metadata such asmanualorauto-classified:marketing
/api/agent-runtime/assistant-messagePOST: internal runtime-only endpoint guarded byx-clapilot-agent-secret; persists an assistant-origin automation/system message into the user’s main personal chat session, Teamchat#general, a concrete TeamchatroomId, or an approved external channel depending on the provided target payload
/api/agent-runtime/channel-mirrorPOST: internal runtime-only endpoint guarded byx-clapilot-agent-secret; mirrors one external Telegram/WhatsApp/Slack/Signal/iMessage/instance-bridge group message into an explicitly mapped Team Chat room. Participant requests use{ kind: "participant", channelType, roomId, text, sender: { key?, name?, username? }, eventId?, attachments? }; agent requests use{ kind: "agent", channelType, roomId, text, agentName?, attachments? }. Returns{ ok: true, messageId, roomId }. The endpoint rejects empty or unknown rooms instead of falling back to Teamchat#generaland does not append agent replies to runtime session context.
/api/agent-runtime/channel-audio-transcriptionPOST: internal runtime-only endpoint guarded byx-clapilot-agent-secret; accepts{ filePath, mimeType? }for an audio file already persisted inside the shared workspace, transcribes it through the configured STT runtime, and returns{ ok: true, transcript, provider, providerType, model }. It is used by native channel ingestion before an agent run and never returns provider credentials.
/api/agent-runtime/request-logsGET: admin-only list of persisted native model request logs with provider, model, duration, status, derived token counts, estimated prompt-layer attribution (promptLayerTokens), and raw usage/metadata payloads for the ClapilotAICoreLogsinspector
/api/agent-runtime/learningGET: admin-only list of learning objects, recent learning audit events, and grouped stats for the ClapilotAICoreLearninginspector and exception-review queuePOST: admin-only create path for controlled durable facts, procedure/skill proposals, or hot memory snapshots; this records an initial learning audit event and creates pending approval state when required
/api/agent-runtime/learning/[id]GET: admin-only detail view for one learning object with linked approval decisions and audit events
/api/agent-runtime/learning/[id]/decisionPOST: admin-only approval ledger path forapproved,rejected,changes_requested,revoked, orauto_approved_by_policydecisions; it updates the object's lifecycle state, appends an audit event, and backs both versioned system-policy activation and Learning settings exception-review actions
/api/build-infoGET: return runtime build metadata for both the web app container (clapilot) and the native agent service (clapilotAgent) so settings pages can detect version drift between the two services
/api/issue-reporterPOST: create an issue report using the configured Issue Reporter target (github,task_board,local_hub, orremote_hub) and attach the current page context, build info, and active chat transcript. JSON and multipart requests may sendappas a repository basename without its owner prefix, for exampleapp=clapilot-website; the backend resolves the full repository and mapped Task Board from the Agent Orchestrator repository matrix. Missingappremains backward-compatible and routes asclapilot. Unknown or ambiguous basenames are rejected. The request also accepts optionalplatform(web_ios_mac,web,ios,mac, orgeneral) and multipartimages[]. Created GitHub issues and Task Board tasks use the reporter summary as their title and record the Issue Reporter source, app, and repository in runtime context. The GitHub target uses the named Issue Reporter GitHub integration selected in Settings -> Issue Reporter; Hub approvals retain the submitted app mapping.
/api/issue-reporter/appsGET: admin-only app catalog for the Issue Reporter selector. Local Hub instances return their own Agent Orchestrator repository-to-board mappings; remote-Hub spokes fetch the catalog from the configured Hub through the signed/api/hub/issues/appscontract and fall back to local mappings when the remote endpoint is unavailable.
/api/hub/statusGET: admin-only hub-mode status for the current normal Clapilot instance
/api/hub/validatePOST: signed hub handshake endpoint; when the sender includesinstance_url, the local hub now auto-discovers or refreshes that instance in the monitored health list
/api/hub/connection-testPOST: admin-only connectivity test against the configured hub target (local or remote mode); validates URL/secret before saving hub settings
/api/hub/channel-bridge/roomsPOST: HMAC-signed peer-room discovery for instance channel bridges; verifies the fleet hub signature (x-clapilot-instance-id,x-clapilot-ts,x-clapilot-signature) on the raw body, accepts{}, and returns this instance's mappable team-chat rooms as{ rooms: [{ id, name, kind }] }. Available on every instance, not only in hub mode, so both bridge sides can serve it
/api/hub/channel-bridge/registerPOST: HMAC-signed peer-side bridge registration; accepts{ action: "upsert" | "remove", bridgeId, peerInstanceId, peerInstanceLabel, peerBaseUrl, peerRoomId, peerRoomLabel, localRoomId, localRoomLabel? }.upsertvalidateslocalRoomIdagainst the mappable-room list, creates or updates the local approvedinstance_bridgechannel-approval row with rolepeer, and enables theinstance_bridgechannel config;removedeletes the local approval row bymetadata.bridge_id
/api/hub/issues/reportPOST: signed inbound issue intake used when another Clapilot instance reports into this instance running in hub mode; also auto-discovers or refreshes the sending instance in the monitored health list wheninstance_urlis present
/api/hub/issues/appsPOST: signed app-catalog endpoint used by remote-Hub spokes to render the same repository selector as the local Hub without exposing the catalog publicly
/api/hub/issuesGET: admin-only list of issue reports received by this hub-mode instance; accepts optional repository-basenameappandstatusfiltering. Supported status values areopen,approved,denied(including legacydismissedrows),github_failed,github_queued,task_failed, andresolved. The response also returns the configured app/repository/Task Board options for the Issue Reporter selector.
/api/hub/issues/[id]GET: admin-only detail payload for one inbound issue report, including transcript and attachment URLsPATCH: admin-only review action for one inbound issue report;{ "action": "approve" }creates either a GitHub issue or an agent task depending on the hub instance's Settings -> Issue Reporter target and stores the resulting GitHub metadata or Aufgabe id, while{ "action": "deny" }marks the report as denied without forwarding
/api/hub/health/instancesGET: admin-only list of monitored Clapilot tenants for this hub-mode instance, including manually added and auto-discovered rows plus discovery metadata such assource_instance_id,instance_url,discovery_source, andlast_seen_atPOST: admin-only add a monitored tenant with optional admin credentials for login verification
/api/hub/health/instances/[id]PATCH: admin-only update one monitored tenantDELETE: admin-only remove one monitored tenant
/api/hub/health/instances/checkPOST: admin-only run health checks for one or all monitored tenants
/api/hub/fleet/instancesGET: admin-only Fleet instance inventory in local Hub mode; encrypted environment content is removed from responsesPOST: creates a new Fleet instance fromname, optionalmachineId,sipEnabled, whitelisted stringoverrides, and optionalprovisioningSettings.mainAgentToolRestrictionsEnabled(defaulttrue). Provisioning settings are persisted separately from raw environment overrides. The generated instance environment seeds the restriction flag exactly once, so later changes inside the spawned instance are not overwritten on restart
/api/local-db
Module platform
/api/module-store/localGET: signed-in local module inventory for/modules; returnsall,effective, redacted paths for non-admins, and aninstalledboolean on every entry. Workspace/managed entries are always installed; bundled entries reflect the instance-wide DB policy and overrides, and uninstalled bundled entries remain inallbut are excluded fromeffective. Manifest metadata includesicon,categories(store category keys, multiple per module), andhiddenInMenu; each entry also carriesiconFilewhen the module ships an icon image (icon.png/icon.svg/icon.webp/icon.jpg) in its root, served via/api/modules/[slug]/assets/<iconFile>
/api/module-store/local/[slug]GET: return only one effective module manifest for the module runtime page, with the same developer/admin visibility checks, localization, and non-admin path redaction as the full inventory. The module page uses this endpoint so renderer selection does not wait for the complete store payload.
/api/module-store/catalog/api/module-store/publish/api/module-store/install/api/module-store/install-bundledPOST: admin-only install of a non-fixed bundled module. Runs unapplied bundled SQL migrations, upsertsmodule_installs.installed = true, and synchronizes the legacy disabled file; it no longer copies bundled source into the workspace
/api/module-store/deactivate-bundledPOST: admin-only uninstall of a non-fixed bundled module. Upsertsmodule_installs.installed = false, synchronizes the legacy disabled file, and removes a marked workspace clone left by the former copy-based install flow
/api/module-store/delete/api/module-store/set-iconPOST: admin-only update of the persisted module manifest icon inmodule.json
/api/module-store/set-menu-visibilityPOST: admin-only update ofmodule.json.hiddenInMenu; keeps the module active while removing or restoring its automatic sidebar menu entry
/api/modules/scaffold/new/api/modules/[slug]/assets/[...assetPath]/api/modules/[slug]/api/[...endpointPath]/api/modules/[slug]/storage- All module runtime endpoints resolve only installed/effective modules and return
404with{"error":"module_not_installed"}when the slug is unavailable
- All module runtime endpoints resolve only installed/effective modules and return
Appointment booking module API highlights:
/api/appointments/overviewGET: signed-in overview for the Termine module with settings, appointment types, availability windows, and upcoming appointments for an optionalfrom/todate range
/api/appointments/settingsGET,PATCH: signed-in booking settings including timezone, slot step, minimum notice, booking horizon, and public embed copy/enabled state
/api/appointments/typesGET,POST: signed-in appointment type list and upsert for fields such asname,duration_minutes, optionalprice_cents/price_currency, buffers, color, and active state
/api/appointments/availabilityGET,POST,DELETE /api/appointments/availability/[id]: signed-in weekly bookable day/time windows, optionally scoped to one appointment type
/api/appointments/slotsGET: signed-in free-slot preview for one appointment type and date range; returns available slots only, with existing appointments used only as blockers
/api/appointments/daysGET: signed-in per-day free-slot availability (daysarray of{ date, free_count }plus the resolvedfrom/to/horizon_endrange) for one appointment type; used for calendar-style day pickers
/api/appointments/appointmentsGET,POST,PATCH /api/appointments/appointments/[id]/status,DELETE /api/appointments/appointments/[id]: signed-in appointment listing, internal booking, status update, confirmation, completion, and cancellation. Status values arepending,booked,cancelled, andcompleted; confirming a pending appointment by settingstatus: "booked"sends the customer confirmation email when the agent mailbox SMTP settings are configured.
/api/public/book-appointment/config,/api/public/book-appointment/days,/api/public/book-appointment/slots,/api/public/book-appointment/appointments- unauthenticated public embed API for active appointment types, per-day free-slot availability, free slots, and requesting one selected free slot. Public bookings require
customer_email, creatependingappointments, send the customer a request-received email when the agent mailbox SMTP settings are configured, and never return existing appointments or customer records.
- unauthenticated public embed API for active appointment types, per-day free-slot availability, free slots, and requesting one selected free slot. Public bookings require
/embed/book-appointment- public iframe-ready booking UI for websites with a month calendar for the date and a time grid for the selected day; use a width up to about
1040pxand a height around680pxto show the date/time picker and contact details side by side
- public iframe-ready booking UI for websites with a month calendar for the date and a time grid for the selected day; use a width up to about
Native agent tool proxy appointment contracts:
appointments_list_types: public-safe list of active appointment types, durations, and optional pricesappointments_list_free_slots: public-safe free-slot lookupappointments_list_free_days: public-safe per-day free-slot availability for day/week overviewsappointments_book: public-safe booking mutation for a selected free slot; requirescustomer_email, creates a pending appointment request, and triggers the request-received customer email when mail transport is configured
Athlete-Brand Matching module API highlights under /api/modules/athlete-brand-matching/api:
GET /state: returns the signed-in user's module-local athlete, brand, review, follow-up, and outreach state plus persistence metadataPUT /stateorPOST /state: replaces the signed-in user's module-local state; used by the iframe after manual capture, CSV/JSON import, review decisions, matching/outreach updates, and follow-up edits
Excel Editor module API highlights under /api/modules/excel-canvas/api:
GET /docs/:id: returns raw cells plus a workbook-awaresheetSnapshotpayload for merges, hidden rows/columns, style metadata, comments, hyperlinks, and unsupported feature warningsPATCH /docs/:id: accepts plain cell updates or workbook-awareoperations[]batches. Operation vocabulary:set_cells,set_styles(targetref/range/cells plus style and optional fullreplace),merge,resize,hide_show,insert_delete, andset_pane(xSplit,ySplit).
Agent Orchestrator module API highlights under /api/modules/agent-orchestrator/api:
GET /toolsPOST /reposGET /statusGET /pollPOST /configGET /webhook/:tokenPOST /webhook/:tokenPOST /orchestrator/startPOST /orchestrator/stopGET /remote-runnersPOST /remote-runners/security-preflightPOST /remote-runners/heartbeatPOST /remote-runners/claimGET /remote-runners/[runnerId]/codex-sessionsGET /remote-runners/[runnerId]/codex-sessions/[sessionId]POST /remote-runners/[runnerId]/codex-sessions/[sessionId]/follow-upPOST /remote-runners/jobs/[id]/eventsGET /jobsPOST /jobs; repository jobs acceptforgeProvider,forgeIntegrationName,forgeBaseUrl, andcloneUrl, but authenticated remotes are derived server-side from the resolved named connection so caller-controlled origins never receive stored credentials. Detached jobs may set canonicalprovider: "clapilot-code"plus a non-subscription catalogmodelto run through Clapilot's in-process coding loop (pi,embedded_pi,embedded-pi, andclapilot_coderemain accepted aliases), detached Codex jobs may setexecutionTarget: "remote"so a connected remote Codex runner claims the work over the pull-based remote-runner API, and Codex or Claude jobs may setcodexGoalEnabled: trueto prepend/goal <task goal>to the first turn. Local Codex, Claude Code, and Clapilot Code jobs receive the restrictedcoding_coretool profile: repository shell/edit capabilities plus read-only Clapilot context, memory, Knowledge, Learning, search, and status tools. The only business mutation isaufgaben_add_comment, and it succeeds only when the coding session is bound to the exact originating Symphony task; memory writes, generic catalog dispatch, and every other business-action tool remain excludedGET /jobs/[id]GET /jobs/[id]/streamGET /jobs/[id]/workspace-files?q=...&limit=...to search bounded, Git-ignore-aware relative paths in an owned local job workspace. Linked jobs use the linked session cwd; remote jobs return unavailableGET /jobs/[id]/workspaceto inspect an owned local job workspace through a bounded read-only snapshot: relative file inventory plus Git branch, porcelain status, unstaged diff, and staged diff. The endpoint accepts no command input, applies trusted-root and ownership checks, and is unavailable for remote jobsPOST /jobs/[id]/follow-upto continue a detached job with another prompt. Session-backed jobs resume the linked background session; plain CLI jobs, including Claude CLI jobs, run the follow-up in the original job workspace. Remote Codex jobs are requeued for the same remote runner workspace. Local jobs accept text, optionalattachments[], validated relativefileReferences[], or a combination; remote jobs reject file references because their workspaces are not server-localDELETE /jobs/[id]GET /sessions?view=summary|full&limit=...;summaryis the default and omits embedded event/chat-history arrays while keeping compact status, model, activity, and latest-output previews.view=fullremains available for compatibility and diagnostics; clients should load one selected session through its detail endpoint instead of polling full listsPOST /sessionswith the initial session turn payload; accepts text, optionalattachments[], or both, canonicalprovider: "clapilot-code"plusmodelfor the internalembedded_piadapter, plus optionalcodexGoalEnabled: truefor Codex or Claude sessions. Repository sessions also acceptforgeProvider,forgeIntegrationName,forgeBaseUrl, andcloneUrl; named-connection and GitLab sessions use the embedded runtime so provider credentials remain session-scoped.GET /sessions/[id]DELETE /sessions/[id]GET /sessions/[id]/workspace-files?q=...&limit=...to search bounded, Git-ignore-aware relative paths in the owned local session cwdGET /sessions/[id]/workspaceto inspect an owned local coding-session workspace through the same bounded read-only file and Git snapshot contractPOST /sessions/[id]/turnsto continue an interactive session; accepts text, optionalattachments[], validated relativefileReferences[], or a combination. Referenced files are inspected from the active cwd rather than uploaded into the turn; the request is rejected if a selected path is stale or no longer resolves inside that cwdGET /sessions/[id]/stream; optionalreplay=0sends the initial session snapshot without re-emitting every historical event after it, which is the preferred selected-session reconnect contractPOST /sessions/[id]/forkPOST /sessions/[id]/archive
Remote runner heartbeats may include activeJobIds[], authenticated active claim proofs as activeJobs[] entries shaped like { id, claimToken }, codexSessions[], codexSessionsScannedAt, codexSessionScanError, and codexSessionDetails[]; heartbeat and claim responses may include cancelJobIds[]. Every session summary and nested detail session carries harness: "codex" | "clapilot-code"; the server defaults an absent field from older runners to "codex". Active claim proofs let the module reconcile an in-flight remote assignment after its own process restarts without accepting a claim from a different runner. Cancellation-aware Node runners identify as codex-remote-runner/0.2.2 or newer, and the macOS runner identifies as clapilot-remote-runner-mac/0.2.0 or newer. POST /remote-runners/security-preflight returns 200 when a shell-policy transition is safe, or 409 with REMOTE_RUNNER_UPDATE_REQUIRED or REMOTE_RUNNER_CANCELLATION_PENDING while active remote work cannot yet be safely drained. The runner builds its session snapshot from state_*.sqlite rows plus CLI/Desktop history files under the selected Codex home (session_index.jsonl and sessions/**/rollout-*.jsonl), and from Clapilot Code JSONL sessions under ~/.clapilot-code/sessions or the configured override. The server stores the latest per-runner snapshot in memory. GET /remote-runners/[runnerId]/codex-sessions returns the latest session summaries for the selected machine. GET /remote-runners/[runnerId]/codex-sessions/[sessionId] returns cached transcript detail when available; otherwise it records a detail request and returns requested: true, then the pull-based runner includes the transcript excerpt in a later heartbeat.
POST /remote-runners/[runnerId]/codex-sessions/[sessionId]/follow-up uses the same authenticated module browser/admin context as the sibling remote-runner inspector calls and accepts { message: string, model?: string }. It returns { jobId, status }, creates a queued job pinned to the selected runner, and stores the scanned session cwd and harness for execution. Empty messages return 400; unknown runners or sessions return 404; an instance with CLAPILOT_SHELL_TOOLS_ENABLED=false returns 403 with CLAPILOT_SHELL_TOOLS_DISABLED. Resume assignments use mode: "resume-session", resumeSessionId, resumeCwd, resumeHarness: "codex" | "clapilot-code", and reuseWorkspace: false. Codex assignments invoke codex exec resume; an explicit request model is forwarded while an omitted model preserves the session model. Clapilot Code assignments use command: "clapilot-code" with arguments: ["exec", "resume", sessionId, prompt]; the runner resolves the installed launcher, adds --cd, and relies on the model already saved in the session. Codex resumes require codex-remote-runner/0.2.3 or newer, Clapilot Code resumes require codex-remote-runner/0.2.4 or newer, and clapilot-remote-runner-mac/* is excluded from both.
GET /status now also returns richer tracked-PR follow-up observability, including the latest tracked scan results plus recent handled/failure entries for guarded PR comment triage and follow-up dispatches. Each repoConfigs[] entry can include githubTriggerMode, githubWebhookPath, and githubWebhookUrl so Settings -> Agent Orchestrator can show a repo-specific tokenized GitHub webhook endpoint. Enabled repository automations may additionally carry prReviewModel, issueObserverModel, and mentionObserverModel objects shaped as { provider: "codex" | "claude" | "clapilot-code", model: string }; the concrete model implies the runtime harness, and Main-CI fixes reuse issueObserverModel.
GET /status also returns effectiveMaxConcurrentAgents and a capacity object with active and synchronously reserved run counts, available slots, the current blocking reason, and total/free/reserved/per-run memory figures in MiB. The configured maximum defaults to one safe local run. Every local Symphony or repository-automation dispatch is gated by the shared slot count and the instance memory reserve before asynchronous preparation begins; stopped CLI jobs terminate their complete process group so coding subprocesses cannot survive as orphan workers.
POST /orchestrator/start and POST /orchestrator/stop now persist the Symphony enabled state in app_settings.agent_orchestrator_symphony_enabled. GET /status returns enabled; when disabled, the poll loop and manual poll endpoint do not dispatch aufgaben candidates or retry queued Symphony tasks. GitHub automations are controlled separately by the per-repository automation matrix, so issue observer, PR review, mention observer, and tracked-PR follow-up can continue even when Symphony task-board dispatch is disabled.
Symphony aufgaben dispatch is scoped by the default board in app_settings.agent_orchestrator_symphony_task_board_id plus repo-specific task-board mappings stored in app_settings.agent_orchestrator_repo_automation_config. POST /config accepts taskBoardId/symphonyTaskBoardId for the default board and accepts repoConfigs[] entries with optional taskBoardId; GET /status returns taskBoardId, taskBoardName, observedTaskBoardIds, and repoTaskBoardMappings. When neither a default board nor a repo board mapping is configured, no aufgaben candidates are dispatched. Tasks in mapped repo boards inherit the GitHub repo from the board mapping and use that repository's concrete issueObserverModel for the coding job, including the implied harness; legacy rows without a model use the global issue-observer provider fallback. Tasks in the default board still need repo:owner/name in their description before Symphony starts a coding job.
Container bootstrap does not start Symphony by default; deployments that intentionally want boot-time activation must set CLAPILOT_AGENT_ORCHESTRATOR_BOOTSTRAP_ENABLED=true.
Symphony repository tasks now require PR traceability in the generated pull request body: Requested-by: Symphony task ... plus Clapilot task: .../aufgaben/{id}. The URL uses the configured public app URL from app_settings.public_base_url or public URL environment aliases (PUBLIC_BASE_URL, CLAPILOT_PUBLIC_BASE_URL, NEXT_PUBLIC_APP_URL, CLAPILOT_EXTERNAL_URL) and falls back to the app-relative task path; internal service URLs such as CLAPILOT_BASE_URL=http://clapilot:3000 are not used for this public PR link. Symphony and issue-observer PRs must also include a ## Testing Instructions section with concrete validation commands or manual checks; the web PR live-browser check and iOS/Mac Codex E2E workflow extract that section from the PR body and pass it into their Codex prompt context. The job record retains symphonyTaskId, and local coding MCP session keys append :symphony-task:{id}. The aufgaben_add_comment contract accepts { id, comment }, requires that full UUID to match the scoped origin, and writes a deduplicated Symphony agent comment for progress, implementation evidence, blockers, or questions; shared-board writes publish an Aufgaben reload. After detecting an opened PR, Symphony also writes its canonical URL, PR number, and open status as a system comment on the originating task independently of optional tracked-PR registration. The visible PR-link comment is generated in the task creator's persisted UI language (de, en, or it), with private-board owner and German fallbacks. A dedicated transaction takes a typed UUID advisory lock before the URL lookup and insert, making retries and concurrent completion paths idempotent while different PR URLs accumulate.
For regression tasks with exact session.*.failed signatures, the persisted job record also retains the linked PR and observation phase. The three-hour production window begins at the confirmed merge timestamp rather than PR creation, is reconciled after runtime restarts, and prevents both job cleanup and task completion while it is pending.
POST /config persists one GitHub/GitLab automation matrix (repoConfigs) plus review, issue-observer, mention-observer, and CI settings. Each entry records forgeProvider, integrationName, and forgeBaseUrl in addition to the existing trigger and feature fields, plus the optional per-automation model objects described above. Legacy global prReviewProvider, issueObserverProvider, and mentionObserverProvider values remain accepted as fallbacks for older rows without concrete models. POST /repos accepts connectionKeys (github:<name> or gitlab:<name>) and returns the union with provider, source connection, clone URL, and base URL metadata; legacy GitHub integrationNames remain accepted. POST /webhook/:token accepts GitHub repository webhooks and GitLab project webhooks, normalizes their issue, pull/merge-request, discussion/note, check/pipeline, status, and push event families, and scopes dispatch to the matching provider and repository.
Issue observer runs now close a GitHub issue as soon as implementation is picked up and comment that the observer is working on it, preventing another scan from starting a second implementation for the same issue. Existing issue sessions are reconciled through the persisted agent_events.event_data.sessionId linkage, and active issue-session conflicts are treated as already in progress instead of reopening the issue. Manual/detached jobs that explicitly target a GitHub issue use the same issue-level lock and are rejected while an implementation session is active or once an open PR already closes the issue. When the run produces a PR, the observer comments the PR link on the already-closed issue; if the run fails and no PR can be recovered, it reopens the issue and applies the normal failure backoff.
Tracked PR follow-up comment triage can return follow_up, reply, or ignore. reply posts a GitHub PR conversation comment for direct questions, status requests, and clarification comments that do not require a code change; follow_up remains reserved for low-risk code fixes on the existing PR branch and may include a follow-up result reply_body so the orchestrator posts a PR conversation reply after the branch update.
Apple native share workflow endpoints:
GET /api/apple/share-targets/telegramreturns approved Telegram group targets that the iOS share workflow can present after a user shares a file into Clapilot.POST /api/apple/share-targets/telegram/sendaccepts authenticated multipart form data withapprovalId, optionalmessage, andfiles[]. The route stages the uploaded files briefly in the workspace, sends them through ClapilotAICore's approved Telegram channel delivery, and removes the temporary staged files after the delivery attempt.- The native Apple share workflow also presents
Issue meldenfor image/screenshot imports. That path reusesPOST /api/issue-reporterwith multipartimages[], native Apple page context, and the user-entered text as the issue summary/details. The dedicated web and Apple issue reporter screens additionally expose the optional affected-platform selector described above.
News module API highlights under /api/modules/news/api:
GET /items- lists persisted news tiles; accepts
limit,search,source_kind,athlete_name,review_status, andrefresh=trueto force an RSS sync before reading
- lists persisted news tiles; accepts
POST /items- creates or idempotently upserts one news item for manual workflows, automations, and agent tool calls; clipping payloads may include
athlete_name,project_name,partner_name,rating(1-3),relevance,source_reach,article_type,review_status,report_preview_url,screenshot_url, andimport_source
- creates or idempotently upserts one news item for manual workflows, automations, and agent tool calls; clipping payloads may include
PATCH /items/:id- updates a news item and its Presseclipping metadata for manual review and report preparation
GET/POST /settings- reads or updates RSS auto-ingest behavior and feed import limits
GET/POST/PUT/DELETE /rss-sources- manages configured RSS sources for the module
POST /rss-sync- forces an immediate RSS synchronization run
Accounting module API highlights under /api/modules/accounting/api:
GET /bootstrap- returns Mandanten, Kategorien, linked Dokumente, period-filtered entries, and the current accounting report snapshot for the selected client
GET /categories- lists all accounting categories
POST /categories- creates a custom accounting category
PATCH /categories/:id- updates one accounting category
GET /entries- lists accounting entries with
mandant_id,period_kind,year, optionalmonth/quarter, and optional direction/type filters
- lists accounting entries with
POST /entries- creates one accounting row with category/document linkage plus netto/steuer/brutto values
PATCH /entries/:id- updates one accounting row
DELETE /entries/:id- deletes one accounting row
GET /reports- generates the current bookkeeping and VAT-style period report including totals, category split, and VAT-code breakdown
Finanzen / Steuer-Manager module API highlights under /api/modules/tax-manager/api (UStVA transfer aids and EÜR drafts; full calculation and field details live in the module documentation):
GET /- returns module identity, legal notice, and the active endpoint inventory
GET /bootstrap- ensures the global
Steuerbelegedocument folder and returns its UUID astax_folder_idtogether with Mandanten, the owner's 50 most recent generations, per-user settings, and the legal notice
- ensures the global
GET /settings,PUT /settings,POST /settings- reads or upserts the authenticated owner's
{ agent_model_ref }; empty values inherit the normal runtime default
- reads or upserts the authenticated owner's
GET /candidate-documents- requires
mandant_idplus period selection and returns accessiblebeleg,rechnung, andustdocuments for that Mandant and period
- requires
GET /overview-documents- returns all visible
beleg,rechnung, andustdocuments plus visible documents in the globalSteuerbelegefolder. Supports optional title searchq,mandant_id, andlimit(default 200, maximum 500), and returnstax_folder_idwith each document'stitel, type/date/amount/currency, Mandant identity, and folder flag
- returns all visible
GET /generations,POST /generations- lists owner-scoped UStVA/EÜR generation history or creates a generation from
{ kind, period_kind, year, period_index?, mandant_id?, source, document_ids[] }with a heuristic line-item baseline
- lists owner-scoped UStVA/EÜR generation history or creates a generation from
GET /generations/:id,DELETE /generations/:id- loads one generation with all source-document line items or deletes it with its dependent line items
POST /generations/:id/line-items- bulk-upserts per-document extraction/classification results and sets the generation to
extracted; monetary fields are non-negative integer cents
- bulk-upserts per-document extraction/classification results and sets the generation to
POST /generations/:id/finalize- deterministically recalculates UStVA/EÜR totals and Prüfhinweise, stores report HTML, and sets the generation to
finalized; it can be rerun after corrections
- deterministically recalculates UStVA/EÜR totals and Prüfhinweise, stores report HTML, and sets the generation to
GET /generations/:id/html,GET /generations/:id/pdf- returns the finalized stored HTML or an on-demand PDF; both return
409until finalization
- returns the finalized stored HTML or an on-demand PDF; both return
GET /health- returns the lightweight module health status
Dedicated Steuer-Manager agent trigger (outside the bundled-module API base, runs in the Next.js app context):
POST /api/modules/tax-manager/run-agent- body:
{ generation_id }. Requires an authenticated owner of the generation. Resolves the enabledsteuer-managerspecialist, creates a dedicated chat session, enqueues a background task, marks the generationextracting, and returns{ ok, task_id, generation_id, chat_session_id, pending_message_id, agent }. The per-user module model is stored on the session and passed as the task fallback. Migration 007 clears the bundled specialist default; an admin-set specialist default intentionally takes precedence over the per-user fallback. The specialist reads every source document, submits classifications, and invokes deterministic finalization.
- body:
GET /api/modules/tax-manager/run-agent?task_id=…- authenticated status poll for the task returned by POST. Returns task timestamps/error state,
running,tool_statuses, and an optionalreply_previewfor the generating step.
- authenticated status poll for the task returned by POST. Returns task timestamps/error state,
The current agent tools are tax_manager_list_generations, tax_manager_get_generation, tax_manager_submit_extraction, and tax_manager_finalize_generation. Their detailed schemas and live-voice exposure are documented in Agent Tool Contracts.
Native runtime machine-token scopes (for /api/modules/[slug]/api/...):
modules:api:readforGET/HEAD/OPTIONSmodules:api:writefor mutating methods
Skill platform
/api/skill-store/local/api/skill-store/catalog/api/skill-store/publish/api/skill-store/install/api/skill-store/delete/api/skill-store/agent-skill
GET /api/skill-store/local returns local/effective skill entries plus computed setup metadata:
requiredToolNames[]: optional specialist tool permissions declared by skill frontmatterrequiredAuthResourceKeys[]: optional specialist auth/API scopes declared by skill frontmattersetup.status:ready,needs_setup, ordisabledsetup.unmetRequirements[]: unmetenv/app_settingrequirementssetup.installRecipe: optional one-click setup action for the admin UI
POST /api/skill-store/delete deletes one local non-bundled, human-authored skill directory by id. Bundled and agent-authored skills are explicitly protected; agent-authored skills must be archived.
POST /api/skill-store/agent-skill is admin-only and updates the lifecycle of one workspace origin: agent skill by dir_name. It accepts status (active, draft, or archived) and/or pinned; it never deletes files or mutates human/bundled skills.
Widget platform
/api/mini-apps/api/mini-apps/[id]/api/mini-apps/[id]/data/api/mini-apps/[id]/dashboard/api/widget-store/local/api/widget-store/catalog/api/widget-store/publish/api/widget-store/install
POST /api/widget-store/publish publishes the current structured widget snapshot as a versioned hub artifact.
POST /api/widget-store/install downloads a published widget snapshot, creates or updates the shared local catalog entry by slug, and installs it for the current user while preserving that user's dashboard placement on re-install where possible.
Specialized agent platform
/api/specialized-agents/api/specialized-agents/[id]/api/agent-store/catalog/api/agent-store/publish/api/agent-store/install
POST /api/agent-store/publish serializes a specialist into a versioned hub JSON snapshot for the Store's Special Agents tab and the admin specialist settings. POST /api/agent-store/install downloads that snapshot and creates or updates a local specialist by handle, while keeping deployment-specific access such as embed API keys and permission bypass out of the imported state.
Mixture of Agents
Admin-only. Manages moa/<slug> virtual-model presets that combine one aggregator model with N reference models. See Mixture of Agents.
GET /api/agent-runtime/moa-presets→{ presets: AgentMoaPreset[] }.POST /api/agent-runtime/moa-presetswith{ slug, label, enabled, aggregatorModelRef, referenceModelRefs, settings }→{ preset }. Returns400for invalid input (bad slug, missing aggregator/references, or a MoA ref used as aggregator/reference).DELETE /api/agent-runtime/moa-presets?slug=<slug>→{ ok: true, slug }.
All three proxy to the native runtime's GET/POST/DELETE /internal/moa-presets. AgentMoaPreset.settings carries referenceMaxTokens, maxReferenceTurns, referenceTimeoutMs, synthesisInstruction, and exposeReferenceOutputs. Enabled presets are surfaced in listModels() as selectable moa/<slug> models.
Model Routing
Admin-only. Manages route/<slug> virtual models used by native request classification and model selection.
GET /api/agent-runtime/routing-models→{ routing_models: AgentRoutingModel[], capabilities: string[], properties: string[] }.POST /api/agent-runtime/routing-modelswith{ slug, label, description, enabled, members, settings }→{ routing_model }. Each member has{ model_ref, capabilities: string[], properties: string[], note: string }.DELETE /api/agent-runtime/routing-models?slug=<slug>→{ ok: true, slug }.
The capability and property arrays returned by GET are the runtime taxonomy the settings UI uses for its member chips. Enabled Routing Models are exposed to model catalogs as route/<slug> when global Routing Models are enabled. Management through agent/chat tools is intentionally not exposed in this iteration; this API backs the admin web UI only.
Agent-focused usage map
- documents:
/api/documents,/api/documents/upload,/api/documents/inbox,/api/documents/folders,/api/documents/folders/[id],/api/documents/[id],/api/documents/[id]/preview,/api/documents/[id]/analysis - mini apps:
/api/mini-apps,/api/mini-apps/[id],/api/mini-apps/[id]/data,/api/mini-apps/[id]/dashboard - emails (user):
/api/emails*,/api/drafts* - emails (agent):
/api/angela/emails*andscripts/agent-email-poller.mjs - modules:
/api/module-store/*and/api/modules/[slug]/* - cases module:
/api/modules/cases/api/* - call agent:
/api/call-agent/*
Detailed flow and tool contract:
Internal native runtime
The native clapilot-agent service exposes internal-only endpoints used by the app runtime client:
GET /healthGET /metricsGET /internal/models- returns runtime providers, memory description, and chat model entries; model entries include
runtimeProviderandsupportsSteering
- returns runtime providers, memory description, and chat model entries; model entries include
GET /internal/provider-models?slug=<provider-slug>GET /internal/sessionsPOST /internal/sessions/modelPOST /internal/chat/completionsPOST /internal/responsesPOST /internal/runs- streams NDJSON lifecycle, tool, assistant, and completion events for the native agent loop
- accepts optional
servicePrincipalId/servicePrincipalSlugalongsideuserIdso execution identity can differ from the persisted room/thread history - accepts optional
timeoutSecondsto place an explicit per-run cap on native execution; when omitted, the Claude CLI bridge path is no longer hard-limited to180s - current native tool events may include
exec_command,package_install,web_search,context_search,context_get,memory_search,memory_get,memory_grep,memory_describe,memory_expand,knowledge_search,knowledge_get_entity,knowledge_neighbors,knowledge_explain_claim,learning_search,learning_get_object,session_status,tool_catalog_search,tool_catalog_expand,tool_execute, and Clapilot-owned mutation tools proxied through the app/runtime bridge
POST /internal/runs/steer- internal-only direct steering endpoint for a currently running hidden Codex subscription bridge turn, Claude CLI bridge turn, or native/embedded-PI run
- accepts
{ sessionKey, message?, attachments? }, locates the matching:subscription-bridge:codexorchestrator session, and forwards text/base64 attachments through Codex app-serverturn/steer - for Claude subscription bridge runs, writes a realtime user-message event to the active Claude CLI
stream-jsonstdin pipe - for native/embedded-PI runs, appends a
LIVE USER STEERnotice to an active tool result or, when the provider is generating without a tool call, aborts the current provider HTTP request and immediately continues the same run with the new instruction; the original NDJSON stream stays open through that continuation so pending animation and final delivery remain intact - returns
409when the current run is idle, in its transition/finalization gap, or otherwise lacks a steerable active turn; native transition responses usereason=native_boundary_transitionand are deliberately not acknowledged so the browser queue cannot lose them
POST /internal/runs/abort- internal-only user-stop endpoint for whatever run currently backs a chat session key
- accepts
{ sessionKey }; interrupts a running:subscription-bridge:codexorchestrator turn through Codex app-serverturn/interrupt, aborts an active native/embedded-PI provider request (or flags an active tool call to stop at its boundary) and finalizes it ascancelled(error_code = user_abort), and sweeps every queued/runningagent_runsrow for the session key — covering runs whose executing process died in a runtime restart - after requesting cancellation, waits for the exact captured live run to terminate. Confirmed termination returns HTTP
200with{ ok: true, aborted: { orchestrator, native, dbRuns, terminated: true } }; an unconfirmed tool/provider stop or failed persistence sweep returns HTTP409with{ ok: false, aborted: { orchestrator, native, dbRuns, terminated: false }, error }. Both outcomes log arun.abortedagent event.
GET /internal/learning- returns passive learning-object dashboard data: recent objects, recent audit events, and grouped stats
GET|POST /internal/learning-objects- lists or creates durable facts, procedure/skill proposals, and hot memory snapshots in the native learning ledger
POST /internal/learning-objects/retrieve- internal runtime retrieval path for prompt-ready approved learning objects; enforces approval, expiry, visibility, subject matching, per-run limits, and a token budget before returning the
Approved learned contextprompt block
- internal runtime retrieval path for prompt-ready approved learning objects; enforces approval, expiry, visibility, subject matching, per-run limits, and a token budget before returning the
POST /internal/learning-objects/extract- internal diagnostics/runtime path for conservative post-response extraction; creates canonical durable facts or low-risk procedure drafts from shared-fact/explicit-memory input. The opt-out policy activates eligible evidence-backed facts and preferences immediately; exceptions remain candidates.
POST /internal/learning-objects/curate- internal diagnostics/runtime path for the targeted deterministic safety pass. Optional
assertionIds/assertion_idslimits the scan to Learning projections for those canonical assertions and returnstargetedAssertionIds; Dreaming v2 uses this targeted path immediately after each completed audience partition. Supported Dream assertions receive system-policy approval, while unsupported Dream assertions receive a terminal system-policy rejection instead of remaining in the human-review queue. The protected scheduledLearning Curatoruses a separate model-backed runtime path configured through the job payload fieldsmodel,batchSize, andminimumRejectConfidence.
- internal diagnostics/runtime path for the targeted deterministic safety pass. Optional
GET /internal/learning-objects/:id- returns one learning object with linked approvals and audit events
POST /internal/learning-objects/:id/decision- records approval-state decisions and appends matching audit events
GET /internal/learning-objects/:id/audit- returns audit events for one learning object
GET|POST|PATCH|DELETE /internal/jobs- scheduled automations only; heartbeat jobs (
job_type = 'heartbeat') are owned by the heartbeat module and excluded from this listing
- scheduled automations only; heartbeat jobs (
POST /internal/heartbeat/trigger- runs a configured heartbeat immediately with
{ scope: "user" | "teamchat", userId? }and returns{ ok, delivered, suppressed, text, outputPreview, runId }; the regular interval schedule is left untouched
- runs a configured heartbeat immediately with
GET|POST /internal/orchestrator-sessionsGET|DELETE /internal/orchestrator-sessions/:idPOST /internal/orchestrator-sessions/:id/turnsGET /internal/orchestrator-sessions/:id/streamPOST /internal/orchestrator-sessions/:id/forkPOST /internal/orchestrator-sessions/:id/archivePOST /internal/channels/:channel/inbound- accepts the native
telegram,slack,whatsapp,signal,imessage, andinstance_bridgechannel types instance_bridgepayloads arrive pre-verified (the app route checks the fleet hub HMAC signature before proxying), are deduplicated by the payloadeventId, and are matched against an existing approved bridge row;kind: "participant"messages mirror with the original sender name and may trigger the local main agent per the room's reply settings, whilekind: "agent"messages mirror as agent messages and never trigger a local agent run- Telegram can stream natively: one visible reply message is created and then updated in place while deltas arrive
- Telegram photo and document attachments are normalized into native
input_image/input_filemessage parts before the run - Telegram forum/group topics now use
chat.id:message_thread_id|rootas the internal thread key, so agent memory/session scope is topic-aware while approvals still stay bound to the parent chat/group - approved group thread bindings may also carry the built-in
global_team_serviceexecution principal so the bot can run with service-level rights while preserving thread-local history
- accepts the native
POST /api/agent-runtime/channel-mirror- internal-secret-only channel-to-Team-Chat display-copy endpoint for participant and agent messages
- accepts optional
attachments(maximum 10) with{ type: "image" | "file" | "audio", name, mimeType, relativePath, size?, durationMs? };relativePathmust be workspace-relative and traversal-free - requires message text or at least one valid attachment; readable files contained by the configured workspace become URL-backed Team Chat attachments, and images receive the same URL as
preview - participant mirrors also dispatch room-invited specialized agents (one or more explicit
@handlementions → exclusive parallel dispatch to that invited target set, no mention → allall_messagesinvitees) and return{ specialistDispatched, suppressChannelReply };suppressChannelReply: truetells the channel runtime to skip its own default-agent reply for that inbound message - final-result-equivalent agent mirrors may set
automationDelivery: truetogether with the persisted automationrunId; only this explicit signal suppresses the mirror itself through durable run-and-room deduplication. Explicit tool sends from a scheduled run useautomationRun: truewith the samerunIdto tag each independently persisted mirror for later correlation; they do not reserve or suppress one another. A duplicate final result returns{ ok: true, duplicate: true, run_id, roomId }. Normal channel runs may carry a run ID for tracing but never enter either automation boundary.
POST /api/agent-runtime/channel-audio-transcription- internal-secret-only bridge from
clapilot-agentchannel ingestion to the configured STT runtime - accepts a traversal-safe workspace
filePathplus optionalmimeType; the existing agent-media workspace guard rejects paths outside the shared workspace - returns the transcript and resolved provider/model metadata, while provider credentials remain server-side
- internal-secret-only bridge from
POST /internal/channels/send- internal-only outbound send path used by ClapilotAICore tool proxy for approved Telegram/Slack/WhatsApp/Signal/iMessage/instance-bridge sends from normal chat runs
instance_bridgesends resolve the bridge approval row, build the signed bridge message payload, and POST it to the peer instance's/api/agent-runtime/channels/instance_bridge/inbound; bridge targets receive raw text plus structured sender fields instead of the[Name via Clapilot]/[AgentName]text framing, and attachments degrade to name-only placeholders in v1- successful sends return
{ channel, recipient, text, mediaCount, targetLabel, approvalId, subjectKey, groupRoomId, mirroredRoomId };groupRoomIdidentifies the Team Chat room mapped by the matched approval, whilemirroredRoomIdis present only after the outbound message was actually persisted in that room. Thechannel_send_messagetool proxy separately normalizes these fields to snake_case for its public tool result. messageOrigin: "team_chat_forward"sends to the provider without running the normal outbound Team Chat mirror; Telegram payloads containing bothtextandmedia[]send the text first and then the media, while other origins retain media-first ordering- every successful explicit tool call is mirrored independently, including multiple sends from one scheduled automation. Structured send metadata travels separately from the truncated human tool preview and is retained across native stream recovery. Persisted Team Chat mirrors carry the stable automation run ID; after an ambiguous mirror timeout, the automatic final-result path waits briefly for that row and suppresses itself only if the row appears. If it does not appear within the bounded wait, the configured final result is delivered normally. Database-backed final-result delivery reservations can be reclaimed after failure or a stale in-progress reservation; approved external-channel reservations remain at-most-once.
GET /internal/channels/whatsapp/auth- returns native WhatsApp Web linking/runtime status including linked identity, auth dir, reconnect state, and any active QR-login session
POST /internal/channels/whatsapp/auth- accepts
{ action: "start" | "wait" | "logout", force?, timeoutMs? } startgenerates a QR-backed login session and returns aqrDataUrlwhen pairing is neededwaitpolls for scan completion against the active backend-owned login sessionlogoutclears the persisted native WhatsApp Web auth state under.clapilotaicore
- accepts
POST /internal/packages/install- internal-only structured installer endpoint used by ClapilotAICore tool proxy; accepts
kind = apt|brew|node|go|uvplus package-specific fields and executes the install inside theclapilot-agentcontainer
- internal-only structured installer endpoint used by ClapilotAICore tool proxy; accepts
GET /internal/memory/knowledge-graph- internal/admin diagnostics path for structured knowledge graph search; accepts
query,limit, optionaldreamId, optionalinstanceKey(defaultdefault),scope = personal|team|channel|all, anduserIdfor the personal scope. It returns{ entities, claims, edges, diagnostics }from the matching instance'sagent_knowledge_*rows. The active graph is maintained automatically from approved/current assertion projections;dreamIdnarrows claims/edges bysource_refsand entities by matching evidence from that Memory Dreaming run. - agent bootstrap and agent-facing
knowledge_*tools still use the runtime visibility model; this all-scope behavior is limited to the internal/admin diagnostics path
- internal/admin diagnostics path for structured knowledge graph search; accepts
POST /internal/memory/knowledge-graph/extract- internal/admin diagnostic repair path for rebuilding/backfilling graph items from approved canonical assertions associated with a dream; accepts
{ dreamId, memoryIds?, model? }, prunes prior graph source refs/evidence for that dream before re-extraction, and returns inserted/upserted entity, claim, edge, source-memory, and cleanup counts. Normal graph maintenance does not require this endpoint.
- internal/admin diagnostic repair path for rebuilding/backfilling graph items from approved canonical assertions associated with a dream; accepts
POST /internal/memory/retention- internal/admin maintenance path for the memory retention sweep; accepts optional
{ enabled?, supersededAfterDays?, evidenceMaxPerItem?, contextMessagesEnabled?, contextMessagesAfterDays? }overrides and returns purge/prune counts; also runs automatically after each nightly Memory Dreaming job
- internal/admin maintenance path for the memory retention sweep; accepts optional
POST /internal/memory/reembed- internal/admin maintenance path for the embedding backfill; accepts optional
{ limit? }, re-embeds memories whose chunks were stored with a different embedding strategy/model than the active provider, and returns{ reembeddedCount, candidateCount, targetKey }; skipped when no embedding provider is configured
- internal/admin maintenance path for the embedding backfill; accepts optional
GET /internal/memory/profile?userId=<uuid>&refresh=<0|1>- internal/admin diagnostics path for the precomputed per-user memory profile; returns
{ profile }withstaticFacts(user-entity knowledge claims plus durable user facts),dynamicContext(recent user memories), the composedprofileTextinjected at bootstrap, build stats, andbuiltAt;refresh=1forces a rebuild instead of serving the cachedagent_user_profilesrow
- internal/admin diagnostics path for the precomputed per-user memory profile; returns
POST /internal/tools/execute- internal-only native tool execution endpoint used when internal Clapilot services need the same native tools as
/internal/runs - currently covers
exec_command,web_search,context_search,context_get,memory_search,memory_store,memory_get,memory_grep,memory_describe,memory_expand,knowledge_search,knowledge_get_entity,knowledge_neighbors,knowledge_explain_claim,learning_search,learning_get_object,session_status,tool_catalog_expand, and Clapilot-owned module/document tools proxied through/api/agent-runtime/tool-proxy, includingnotizen_*andnotizen_duplicate_local. Broadcontext_searchresults use reciprocal-rank fusion, canonical assertion/topic identities, confidence tie weight, and a per-source reservation before the final limit.
- internal-only native tool execution endpoint used when internal Clapilot services need the same native tools as
Admin config for the native runtime is exposed through Clapilot itself:
GET /api/agent-runtime/configPOST /api/agent-runtime/config- returns and stores
{ providers, channels, model_routing }; both methods also returnwarnings, including{ providerSlug, providerLabel }entries when an enabled fallback chain has no enabled provider slug outside its own failure domain - each provider's explicit
enabledvalue is authoritative. Disabled providers retain their encrypted credentials and model configuration but are excluded from model catalogs, selection, and fallback routing. Enabled providers may have no text models when they are used only for audio, image, embedding, or other non-chat capabilities; text defaults and fallback routing consider only compatible configured text models. - provider enable/disable transitions are recorded transactionally in
agent_provider_config_audit_eventswith the provider slug, authenticated admin when available, change source, previous/next state, and model/label context - provider rows accept
provider_type=ollama; local base URLs require no API key, whilehttps://ollama.comuses the encryptedapi_key. The optionalollama_session_cookieandclear_ollama_session_cookiefields update only the browser session used for Subscription Usage. Admin responses expose masked presence/hint metadata and never return the cookie value - successful config writes invalidate the Subscription Usage snapshot and last-good cache so newly saved, replaced, or removed provider credentials are applied on the next usage request
- rejects enabled Codex OAuth provider rows that contain non-OpenAI chat models (for example
grok-4.5); Grok chat models must be configured on anxaiprovider - saving an enabled OpenAI API-key or Codex OAuth provider performs a minimal write preflight against every configured chat transport that runtime routing can use (
/chat/completionsand/or/responses; Codex OAuth uses the Codex Responses base). Saving or activating an OpenAI-compatible provider performs a one-token/chat/completionscapability probe for each configured model and persists token-freemetadata.modelAvailabilityresults. Definitive model-load failures exclude only that model from catalogs/default routing; inconclusive connectivity failures remain routable. A failed provider-wide preflight clears default eligibility. - each channel accepts
enabled,allow_direct_messages, encrypted credential fields, and provider-specificsettings;settings.mention_only = truemakes approved group/channel traffic run only when Clapilot is explicitly mentioned model_routing.priorityis an ordered list of fully qualified model refs such asopenai/latestfor the newest Codex OAuth GPT coding model,claude-default/latestfor the newest Claude subscription coding model (claude-opus-5), concrete pins such asopenai/gpt-5.6-sol,openai/gpt-5.6-terra,openai/gpt-5.6-luna,openai/gpt-5.5,claude-default/claude-opus-5, orclaude-default/claude-fable-5, or provider-specific refs such asgoogle-gemini-default/gemini-2.5-flashmodel_routing.routing_enabledis a boolean feature gate forroute/<slug>virtual models and defaults tofalsemodel_routing.default_routing_model_slugis the Routing Model slug used when a request does not explicitly select a model; an empty string leaves the existing provider/model default path unchangedlatestrefs are moving Clapilot aliases resolved from the enabled provider catalog at execution time; concrete model IDs remain explicit pins- the first entry is the global default model for native runs; later entries are cross-provider fallbacks
model_routing.embedding_provider_slugandmodel_routing.embedding_modelselect the provider/model used for native memory embeddings and the document RAG indexer/retrievermodel_routing.realtime_provider_slugandmodel_routing.realtime_modelstore the separate Realtime provider/model choice for live/call audio routingmodel_routing.ttsstores the global TTS provider slug, model, and voice used for async chat audio replies and other server-side speech synthesis defaults. Agentmedia_tts_speakaccepts exactprovider_slugandmodeloverrides; explicit slugs must resolve to that enabled provider and are never replaced by the default. OpenAI-compatible providers are supported through their configuredbase_urlplus/audio/speech; the model may be an exact gateway alias such aschatterbox, and authless compatible endpoints omit the bearer header.model_routing.sttstores the global STT provider slug and model used for chat audio uploads and note dictation transcription defaults. Agentmedia_stt_transcribeaccepts exactprovider_slugandmodeloverrides and passes the resolved runtime config into the outbound request instead of resolving the default again. OpenAI-compatible rows call their configuredbase_urlat/audio/transcriptions, accept an exact/manual model alias, send the stored key as a bearer token when present, and omit authorization for authless local endpoints.model_routing.image_generationstores the global image-generation provider slug and model used by/api/generated-images/*and agent image tools. Both image endpoints/tools accept optional exactprovider_slugandmodeloverrides; explicit providers never fall back to the global default, while legacy recognized model-family overrides select the matching provider type. OpenAI API-key rows use/images/*; OpenAI-compatible rows call the selected providerbase_urlwith the OpenAI-compatible/images/generationspath, and only use/images/editswhen the provider metadata explicitly marks image edits as supported; OpenAI-compatible text-to-image defaults are skipped for edit calls only when no explicit provider was requested. OpenAI-Codex OAuth rows use the Codex Responsesimage_generationtool withgpt-image-2-class models. Agentimages_editcan import workspace-localsource_image_pathinputs before handing image bytes to the selected provider.media_generation_provider_configsstores AI media provider configuration for video and music.app_settings.media_model_catalogstores curatedvideo,image, andmusicarrays of{ providerSlug, model, isDefault }; saves require enabled compatible providers and normalize every non-empty list to exactly one default. A non-empty capability catalog overrides its legacy single default, while an empty list preserves the old behavior. Each enabled OpenAI-compatible runtime provider with a base URL is mirrored into the video-provider selector and uses the OpenAI Videos lifecycle: multipartPOST /videos,GET /videos/{id}polling, and authenticated or authlessGET /videos/{id}/contentdownload. Those rows inherit the mapped runtime provider's base URL by default; the optionalsettings.videoBaseUrloverrides it for the whole video lifecycle, andsettings.videoAuthDisabledsuppresses theAuthorizationheader. Use the override when the video backend is reachable directly but chat runs through a gateway — job ids issued by a gateway are encoded routing tokens and are not interchangeable with the backend's own ids, so submit, status, and content must all target one host. Both keys survive the automatic runtime-provider sync and are editable underSettings -> ClapilotAICore -> AI media -> Video generation.GETandPOST /api/media-generation/providersreturn the catalog alongside provider rows, augment compatible video rows withavailable_modelsfrom the mapped runtime provider's live/internal/provider-modelsdiscovery, and augment xAI rows from/video-generation-models;model_discovery_errorreports fallback to saved/manual models without invalidating the current selection. The chat-facingvideos_generate/videos_statuspath uses the video catalog default when no explicit provider/model is supplied, acceptsimage_id/source_image_pathfor image-to-video, persists jobs and source-image lineage ingenerated_videos, and streams ready files through/api/generated-videos/[id].livestream_generate_musicapplies the same rule to the music catalog. Explicit tool/API provider and model arguments still win. Live Stream Studio keeps usinglivestream_generate_videofor livestream assets.model_routing.non_specialized_agent_corestores the default agent-core selection for providers without their own specialized bridge:nativeorembedded_pi; Agent Orchestrator exposes the latter as theclapilot-codecoding harnessembedded_pikeeps the chosen provider/model transport, but runs normal agent turns with the selected runtime tool profile and expanded tool-loop budget; Agent Orchestrator coding runs explicitly selectcoding_core, which keeps shell/package primitives plus read-only Clapilot recall and excludes shared-memory writes and business mutationsmodel_routing.adaptive_routingconfigures native per-request model/profile routing:mode:off,shadow(default), orapplycandidate_limit: maximum number of orderedmodel_routing.priorityentries considered, clamped to2..8exploration_rate: bounded exploration probability, clamped to0..0.25min_samples: observations required before learned outcomes receive their full configured influenceswitch_margin: minimum score advantage required to leave the base/recent session modelroute_harness: whether apply mode may choose between Clapilot-code Assistant (native) and Coding (embedded_pi)
- explicit request/session model or profile choices, specialized agents, and Mixture-of-Agents presets bypass adaptive application. Shadow/apply decisions and technical outcomes are persisted in
agent_adaptive_route_decisions. - routing-model (
route/<slug>) selections are not bypassed but scoped: learned outcomes may reorder members within the routing model's tie band (bounded bymin_samplesandswitch_margin, capability tags always win); the decision row records the routing model inrouting_model_slugwith the static pick as base and the outcome pick as recommendation
- returns and stores
GET /api/agent-runtime/adaptive-routing/decisions- admin-only read endpoint backing the adaptive-routing data view in
Settings -> ClapilotAICore -> Model Routing - accepts
?limit=(1–200, default 50) for the recent-decisions list - returns
summary(total, last-7-days, outcome-status counts, protected count, recommended vs. applied switches, routing-model totals and agreement count),stats(per task class and selected model over the 90-day learning window: samples, completed, failed, average success score, average duration), anddecisions(most recent rows fromagent_adaptive_route_decisionsincl.routing_model_slug, base/recommended/selected model, protection/decision reason, and technical outcome) - Codex OAuth provider metadata can include
modelReasoningEfforts, a map from configured model id to an explicit Codex effort (minimal,low,medium,high,xhigh,max, orultra). Missing entries keep the model's Codex-advertised default. Explicit per-session Agent Orchestrator effort overrides the provider value.
- admin-only read endpoint backing the adaptive-routing data view in
GET /api/agent-runtime/channel-approvals- returns pending, approved, and denied native channel approval records in
approvalsplusrooms, the admin's non-archived mappable public/private team-chat channels and group rooms, for the ClapilotAICore settings UI
- returns pending, approved, and denied native channel approval records in
POST /api/agent-runtime/channel-approvals- admin-only approval decision endpoint; accepts
{ id, status }wherestatusisapproved,pending, ordenied - DM approvals should additionally send
{ linkedUserId }; the runtime then maps the external DM thread onto that user's canonical main web-chat session key - group approvals can additionally send
{ groupRoomId, mirrorToChannel? }; non-empty room ids must identify an existing, non-deleted, non-direct team-chat room, and the runtime then maps the external group thread onto that room's session key, defaulting toclapilot-members;mirrorToChannelpersists the opt-in reverse-mirroring flag asmetadata.mirror_to_channel - already approved entries can be re-saved with a different mapping, or reset back to
pendingto block replies again without deleting the approval record
- admin-only approval decision endpoint; accepts
GET /api/agent-runtime/channel-bridges- admin-only list of this instance's
instance_bridgechannel-approval rows (bothinitiatorandpeerroles) with resolved local room names, for the ClapilotAICore Channels settings UI
- admin-only list of this instance's
POST /api/agent-runtime/channel-bridges- admin-only bridge creation on the initiating instance; accepts
{ peerInstanceId, peerRoomId, localRoomId }wherepeerInstanceIdis ahub_monitored_instancesid or a fleet instance - the server resolves the peer base URL and label, generates the shared
bridge_id, calls the peer's signedPOST /api/hub/channel-bridge/register, and only on success creates the local approval row with roleinitiator; a failed peer call returns502and creates nothing locally
- admin-only bridge creation on the initiating instance; accepts
POST /api/agent-runtime/channel-bridges/peer-rooms- admin-only server-side signed call to the selected peer's
POST /api/hub/channel-bridge/rooms; accepts{ peerInstanceId }and returns the peer's mappable room list for the create dialog
- admin-only server-side signed call to the selected peer's
DELETE /api/agent-runtime/channel-bridges/[id]- admin-only bridge removal; deletes the local approval row and sends a best-effort signed
removeto the peer — peer failure is logged and the local delete still succeeds
- admin-only bridge removal; deletes the local approval row and sends a best-effort signed
POST /api/agent-runtime/channel-response- internal-only Clapilot channel execution bridge used by
clapilot-agent; runs approved channel messages through the same Clapilot delegation path that powers broader app actions - this route executes directly through the native ClapilotAICore run path; legacy gateway fallback is compatibility-only
- now fail-closed: requires a valid
x-clapilot-agent-secretheader and refuses requests when no internal secret is configured
- internal-only Clapilot channel execution bridge used by
POST /api/agent-runtime/channels/:channel/inbound- optional public webhook ingress for external channel providers; the app forwards the payload to native
clapilot-agent/internal/channels/:channel/inbound imessageaccepts only BlueBubblesnew-messagewebhooks and requires apasswordorguidquery parameter matching the encrypted iMessage channel credential; mismatches return403instance_bridgeis not a blind proxy: the fleet hub HMAC signature (x-clapilot-instance-id,x-clapilot-ts,x-clapilot-signature) is verified on the raw body before proxying, a bad or missing signature returns401, andGETis not supported for this channel. Unknown bridges are rejected without creating pending approvals. The signed bridge message wire payload posted by the sending instance's agent service is:
- optional public webhook ingress for external channel providers; the app forwards the payload to native
{
"bridgeId": "…",
"originInstanceId": "…",
"originRoomId": "…",
"eventId": "<originInstanceId>:<chat_group_messages.id>:<participant|agent>",
"kind": "participant" | "agent",
"senderName": "Alexander Deutsch",
"senderKey": "user:<uuid>",
"agentName": "Clapilot",
"text": "…",
"attachments": [{ "name": "a.pdf" }],
"sentAt": "ISO-8601"
}
agentNameis present only forkind: "agent";attachmentscarries names only in v1 (the receiving side renders📎 <name>placeholders)GET /api/agent-runtime/channels/whatsapp/inbound- public WhatsApp Cloud / Meta webhook verification handshake; validates
hub.verify_tokenagainst the native channel settings JSON (webhook_verify_token,webhookVerifyToken,verify_token, orverifyToken) and returns the plainhub.challenge
- public WhatsApp Cloud / Meta webhook verification handshake; validates
GET /api/agent-runtime/channels/whatsapp/auth- admin-only native WhatsApp Web status endpoint used by the ClapilotAICore Channels settings UI
POST /api/agent-runtime/channels/whatsapp/auth- admin-only QR-login control endpoint for native WhatsApp Web; proxies
start,wait, andlogoutactions intoclapilot-agent
- admin-only QR-login control endpoint for native WhatsApp Web; proxies
GET /api/agent-runtime/provider-models?slug=<provider-slug>- loads the current provider model catalog so the ClapilotAICore UI can populate the provider model dropdowns
- the dedicated
AudioandAI Mediarouting tabs consume this live provider catalog directly for realtime/TTS/STT/image model selection instead of reusing only the manually added chat-model entries. OpenAI-compatible TTS additionally keeps the model field editable, because gateway aliases do not have to contain attsmarker and some speech-only servers do not implement/models. - Gemini provider catalogs can feed both media routing and chat routing; chat selectors exclude obvious Gemini media-only model ids while text-capable Gemini models run through the native
generateContentadapter - OpenAI Codex OAuth providers use the local Codex app-server
model/listcatalog for this lookup, including the current GPT-5.6 Sol/Terra/Luna lineup, GPT-5.5, GPT-5.4, GPT-5.4 Mini, subscription-only GPT-5.3 Codex Spark, advertised per-model speed tiers, supported reasoning efforts, and each model's default reasoning effort; OpenAI API-key providers still use the OpenAI/modelsendpoint and do not receive Spark as a shipped default
- Anthropic providers backed by a Claude
setup-tokenuse the shipped Claude subscription catalog, includingclaude-opus-5andclaude-fable-5, and execute chat requests through the local Claude CLI bridge rather than direct Anthropic/v1/messagescalls- the runtime now persists one hidden Claude bridge session id per Clapilot
session_key, so follow-up turns resume the same Claude Code conversation until the session model is changed or cleared - AWS Bedrock providers use the Bedrock bearer-token/API-key path in the supported admin flow; the loader attempts to return both foundation-model ids and Bedrock inference profiles, but manual model entry may still be required when Bedrock control-plane discovery is unavailable on that auth path
- Azure OpenAI providers normalize the configured resource URL onto
/openai/v1, keep requests under that path, and only appendapiVersionwhen it is a preview/date-style value instead ofv1; the runtime accepts both Azure API-key auth and OpenAI-style bearer auth for Azurev1 - when the upstream model list exposes token limits, Clapilot forwards optional per-model metadata such as
contextWindow/outputTokenLimit - session execution does not call this endpoint live; it uses persisted provider config first, then the shipped OpenAI/Anthropic model-limit fallback catalog, and only then the generic
32,000/4,096emergency defaults - provider discovery still understands legacy
openai-codex/...refs, but Codex OAuth GPT models are exposed as canonicalopenai/gpt-*refs; standard native chat may selectOpenAI-Codex, execute it through the Codex bridge, and now keep a hidden reusable Codex thread per Clapilotsession_keyfor follow-up turns - direct OpenAI/Azure GPT-5.6 API models (
gpt-5.6,gpt-5.6-sol,gpt-5.6-terra,gpt-5.6-luna) execute through/responseseven for text-only turns; this preserves the supported reasoning-plus-tools path instead of using Chat Completions with GPT-5.6's reasoning default - provider config metadata may also include
modelExtendedContextWindows, a per-model boolean map that re-enables the larger public OpenAI fallback profile for eligible Codex-auth models when admins explicitly turn it on
- the runtime now persists one hidden Claude bridge session id per Clapilot
GET /api/agent-runtime/provider-status?slug=<provider-slug>- admin-only provider health endpoint for the ClapilotAICore settings UI
- returns whether the saved provider is configured and whether auth/connectivity is currently working; failed OpenAI write preflights return
status: "missing_scope"when applicable, plusmissingScopesand a token-freerepairHint. OpenAI Codex setups are allowed to validate from the stored OAuth credential and do not fail just because a stale OpenAI API key is also present, AWS Bedrock setups validate against the configured region plus the stored Bedrock API key, and Azure OpenAI setups validate against the normalized Azurev1endpoint plus stored API key
GET /api/agent-runtime/memory- returns native memory diagnostics including shared workspace path, mounted legacy compatibility state path, detected bootstrap files, detected
memory/**/*.mdfiles, detected legacy session transcript files, embedding backend/model, retrieval tuning, native pre-compaction memory-flush settings, sync state, current native DB layer/chunk counts, Memory v2 assertion/evidence/embedding/outbox health, visibility-scope counts, active/superseded memory-state counts, Memory Dreaming counts, structured knowledge graph counts, typed memory-relation counts, per-user profile counts, and lossless context graph counts - the Runtime Memory UI now explicitly distinguishes durable-memory ownership (
Clapilot Native) from context-window maintenance ownership (nativeprovider loop vsembedded_pi) and shows recent Memory Dreaming runs plus the Knowledge Graph inspector - the shared bootstrap-file editor uses this endpoint's
promptFilesinventory but is shown on the dedicatedBootstrap-Dateiensettings subpage next toRuntime Memory
- returns native memory diagnostics including shared workspace path, mounted legacy compatibility state path, detected bootstrap files, detected
GET|PUT /api/agent-runtime/bootstrap-files- admin-only read/update endpoints for the native runtime bootstrap/prompt files backing the
Bootstrap-Dateiensettings subpage
- admin-only read/update endpoints for the native runtime bootstrap/prompt files backing the
POST /api/agent-runtime/memory- accepts optional
{ mode: "workspace" | "compatibility" | "all" } - default
workspacemode runs an idempotent synchronization from the shared workspacememory/**/*.mdtree into nativeagent_memories+agent_memory_chunks compatibilitymode migrates persisted legacy transcript memory fromOPENCLAW_STATE_DIR/agents/*/sessions/*.jsonlinto the native recall store, reusingsessions.jsonmetadata when available to preserve original session keys
- accepts optional
GET /api/agent-runtime/memory/dreams- admin-only list of recent Memory Dreaming runs with status, trigger, input/output refs, stats, model, and rollback state
POST /api/agent-runtime/memory/dreams- admin-only manual Memory Dreaming v2 run; accepts optional
{ triggerKind, force, model }, validates strict structured output, applies the versioned deterministic automatic assertion policy, and creates every Wiki change only as a review-required draft - after each completed audience partition, the runtime immediately curates that partition's returned
assertionIdsbefore starting the next one and processes the matching projection work. Safe, durable, evidence-backed facts, preferences, decisions, constraints, and procedures can therefore reach recall and extend the Knowledge Graph without human review or the recurring curator schedule; unsupported, sensitive, transient, time-bounded, conflicting, or insufficiently supported Dream assertions are automatically rejected. The response includes an aggregatecurationresult pluspartitionCurations. If a Dream persists but immediate curation/projection fails, the response keeps the Dream result and returnscuration.ok=false; the Runtime Memory UI reports this as a partial failure instead of a successful graph build - an explicit model on a manual run may be a configured Codex or Claude subscription model and is honored exactly for that Dream and its graph extraction; scheduled runs continue to exclude subscription bridges, and unavailable explicit models fail closed without provider fallback
- the Memory settings UI sends the current global priority model by default and can override it per manual run; malformed, empty, truncated, or ungrounded structured output is rejected and the partition is failed/skipped without a deterministic fallback or Wiki publication.
- admin-only manual Memory Dreaming v2 run; accepts optional
POST /api/agent-runtime/memory/dreams/{id}/rollback- admin-only rollback for one dream run. Dreaming v2 compensates candidates, system-policy activations that have not received a human decision, drafts, outbox items, projections, and conflicts. A human-reviewed assertion/proposal or a published proposal blocks rollback. Legacy dream-v1 rows retain the older inserted-memory removal and superseded-source restoration behavior.
GET /api/agent-runtime/memory/knowledge-graph- admin-only proxy for structured knowledge graph diagnostics; accepts
query,limit, optionaldreamId, andscope = personal|team|channel|all(defaultpersonal), returning entities, claims, edges, and coherence diagnostics for that inspector view. The proxy derives the personal owner id from the authenticated admin session rather than accepting it from the browser. The active graph is maintained automatically from approved/current assertion projections; the UI can also filter the selected scope to one Memory Dreaming run.
- admin-only proxy for structured knowledge graph diagnostics; accepts
POST /api/agent-runtime/memory/knowledge-graph- admin-only diagnostic repair path for graph rebuild/backfill; forwards
{ dreamId, memoryIds?, model? }to the native runtime and is not required during normal automatic graph maintenance
- admin-only diagnostic repair path for graph rebuild/backfill; forwards
- Learning object contracts for durable facts, procedure/skill proposals, hot memory snapshots, approval/audit state, visibility scopes, and token-cost attribution now have admin/native storage endpoints, an internal approved-learning prompt retrieval path, read-only agent tools (
learning_search,learning_get_object) for approved visible objects, unified read access throughcontext_search/context_get, an internal conservative extraction path, opt-out safe fact/preference activation, and a configurable model-backed scheduled curator. There are still no agent-facing learning mutation tools; activation, curation, and exception review remain runtime/control-plane paths. See Clapilot-Agent Learning Contracts. GET /api/agent-runtime/sessions- admin-only session diagnostics endpoint for the ClapilotAICore Sessions settings page
- without query params, returns the runtime session list from
agent_session_stateenriched with chat-session mapping, user labels, runtime path / maintenance owner, last-run status, aggregate run/event counts, lossless context counters, shared-fact counters, memory-flush/compaction counts, last compaction marker, last observed prompt-budget telemetry, andchat_nachrichtenmessage counts where a matchingchat_sessionsrow can be resolved; channel-bound interactive Agent Orchestrator / Codex app-server sessions fromagent_external_sessionsare also surfaced when they share the same Clapilotsession_key - with
sessionKey=<runtime-session-key>, returns one session plus recentagent_runs, recentagent_events, resolved app chat transcript rows fromchat_nachrichten, rawbootstrap_meta, rawstate_json, optional external-session metadata fromagent_external_sessions, shared-memory stats, lossless-context stats, normalizedpromptBudgetStats, normalizedcompactionStats, normalizedmemoryFlushStats, and the current safeguard strategy snapshot used by the Sessions inspector - the Sessions UI now shows both the native session
runtimePathand the resolved execution harness/bridge fromexternalSessionmetadata, including the preferred external harness session id when a Codex or Claude subscription bridge is attached - the Agent Orchestrator web module also consumes this endpoint to surface Clapilot-code (
embedded_pi) and Claude bridge sessions inside its activity rail. Claude bridge details use the same turn-card timeline format as interactive Codex output and include a footer composer for same-session follow-ups; Clapilot-code entries retain same-session follow-ups through the native runtime path. promptBudgetStatsincludes model-limit provenance so the inspector can distinguish explicit provider limits, shipped model fallbacks, and the generic emergency fallbackcompactionStats/memoryFlushStatsinclude the current maintenance owner metadata for the native session layer
POST /api/agent-runtime/sessions?sessionKey=...- admin-only runtime-session follow-up endpoint used by the Agent Orchestrator module for Claude CLI bridge sessions
- accepts
{ message?, attachments?, model?, preferSteer?, steerOnly? };attachments[]use the same base64/data-url shape as orchestrator session attachments - with
preferSteer/steerOnly, forwards first toPOST /internal/runs/steerso active Claude CLI bridge streams can receive the prompt through stdin; otherwise it starts a normal native runtime turn with stored history enabled, which resumes the persisted Claude bridge session for the samesessionKey
GET /api/media-generation/providers- admin-only settings endpoint for media-generation providers and the curated
catalog. Returns redacted Gemini video/music and Kie.ai video/music configs including capability, enabled flag, base URL, model list, live-discoveredavailable_models, default model, settings JSON, and API-key hint. Gemini media uses the configured Gemini Runtime provider key instead of a second media-specific key. Kie.ai video model options include Veo 3 presets pluskling-3.0/video,bytedance/seedance-2,bytedance/seedance-2-fast, andbytedance/seedance-2-5.
- admin-only settings endpoint for media-generation providers and the curated
POST /api/media-generation/providers- admin-only update endpoint for those provider configs and optional
catalog. API keys are encrypted before storage; leavingapi_keyempty preserves the stored key unlessclear_api_key=true. Catalog entries must reference enabled compatible providers, duplicate provider/model pairs are removed, and exactly one default is assigned per non-empty capability list.
- admin-only update endpoint for those provider configs and optional
POST /api/internal/livestream/topup- internal-only endpoint called by
clapilot-streamerwithx-clapilot-agent-secretplusAuthorization: Bearer <internal-secret>. It wakes ClapilotAICore with queue/buffer context when the stream's agent top-up loop is due and logsagent.topup.*events.
- internal-only endpoint called by
POST /api/internal/livestream/media-generation/poll- internal-only endpoint called by
clapilot-streamerwithx-clapilot-agent-secretplusAuthorization: Bearer <internal-secret>. It polls pending Kie.ai livestream media jobs by stored task ID, downloads completed provider result files into the shared media output directory, updates asset status/provenance, and records completion/failure events.
- internal-only endpoint called by
POST /api/internal/livestream/youtube-chat/poll- internal-only endpoint called by
clapilot-streamerwithx-clapilot-agent-secretplusAuthorization: Bearer <internal-secret>. When YouTube chat ingest is enabled, it uses the linked Google OAuth user with YouTube readonly scope to discover the active broadcast, pollliveChatMessages, persist deduplicated chat messages, classify viewer questions/music/video/topic wishes into audience requests, and update chat poll health on the livestream channel.
- internal-only endpoint called by
POST /api/agent-runtime/tool-proxy- internal-only bridge for Clapilot-owned tool delegation
- authentication accepts either the configured global internal secret or a random run-scoped execution capability issued to an active
queued,running, orcancellingrun. The run-scoped capability is sent inx-clapilot-agent-secretand requires a bodysessionKey; whenoriginSessionKeyis present, the capability is bound to that originating session so same-identity delegated calls can still target another session. Any supplieduserId,servicePrincipalId, orservicePrincipalSlugmust match the persisted originating-session identity. Malformed, expired, cross-session, or identity-mismatched capabilities return401. Shell children receive only the scoped capability, never the global internal secret. - session scope is resolved from persisted runtime state, not from a
group:-looking key. Team execution requires a live room plus the persistedglobal_team_serviceprincipal;actor_user_idretains the verified triggering room member only for personal integrations and audit fields. Persisted active service-principal sessions are also valid without a Team Chat room for userless system automations such as Morning Briefing TTS; this does not grant Team Chat identity, and caller-asserted global principals without persisted session binding remain rejected.originSessionKeybinds CLI/MCP/rescue calls to their originating identity: Team Chat delegation must retain room, principal, and actor, while system automation delegation must retain the same persisted service-principal ID. - proxies Clapilot UI tools plus native
agent_todo_update,exec_command,web_search,context_search,context_get,memory_search,memory_get,memory_grep,memory_describe,memory_expand,knowledge_search,knowledge_get_entity,knowledge_neighbors,knowledge_explain_claim,learning_search,learning_get_object,session_status,package_install,issue_reporter_create,calendar_*,aufgaben_*,scheduled_tasks_*,specialized_agents_*,notizen_*includingnotizen_duplicate_local,documents_*,google_drive_list_files,mandanten_*,cases_*,excel_*,word_*,google_meet,livestream_*, andx_create_postinto the correct backend path; direct MCP calls andtool_executeuse the same native proxy registry; native provider loops and MCP bridges can discover these concrete tools throughtool_catalog_searchand execute bridge-discovered tools throughtool_executewithout exposing the entire concrete catalog as model-facing functions up front;google_drive_list_filesuses the dedicated Agent Google OAuth connection directly and never requires browser login;web_searchuses the ClapilotAICore Search Providers setting and returns result titles, URLs, snippets, provider, and fallback attempts;context_searchis the preferred unified read-only retrieval path across Learning, Wiki, native memory, exact session history/summaries, and the Knowledge Graph, whilecontext_getreads one source-qualified hit;learning_searchandlearning_get_objectare read-only and return only approved, visible, prompt-eligible Learning objects;x_create_postpublishes through the current user's connected X/Twitter OAuth account, validates the requested post shape against the exact required X scopes before calling the API, and returnstweet_idplusurlonly after the X API confirms creation;clapilot_context_statusreturns the active ClapilotAICoremediaDefaultsplusmediaDefaultsGuidanceso agents treat configured TTS as a Clapilot runtime route rather than inspecting raw provider secret fields;google_meetsupportssetup_status,join,status,speak,start_transcription,transcript,audio_transcript,start_voice,voice_status,stop_voice,stop_transcription,create_summary_document, andleavefor managed browser-participant Google Meet sessions, with join automatically requesting captions and starting the server-side Realtime voice-to-voice bridge when admitted and enabled in Live Voice settings,audio_transcriptrecording/transcribing short incoming-audio fallback blocks,speakusing configured chat TTS to play one-shot audio into the Meet microphone stream, and transcription before writing summary documents into Clapilot;livestream_*covers Live Stream Studio status, YouTube chat audience requests, clip briefs, local HTML/SVG+Gemini-TTS video rendering, rendered asset registration, approval, queueing, RTMPS start/stop desired-state changes, agent top-up configuration, and media-generation provider job submission;specialized_agents_list,specialized_agents_get,specialized_agents_create, andspecialized_agents_updateexpose admin-only, main-agent-only specialist catalog management without accepting channel-token secrets;scheduled_tasks_createandscheduled_tasks_updatenow accept optionalspecialized_agent_idin addition to plain model pinning, optionalnotify_result_modefor result delivery, andtrigger_kind="webhook"for token-backed inbound triggers; specialist-bound automations inherit the selected agent's default model instead of exposing a second execution-model override - returns top-level
okin sync with the nested JSON tool output, so ClapilotAICore treats normalized HTTP-200 tool failures as failures; handled validation failures retaincode="tool_error"unless the tool supplies a more specific code; successfulaufgaben_*mutations on shared boards and shared-board creation fan out one audience-scoped UI mutation row visible to every user's live stream for both user-bound and privileged userless sessions, while private-board mutations remain scoped to the owning user; shared-to-private moves use an owner-excluded audience removal plus the full update on the owner's stream; Team Chat tasks retainsource_type="team_chat"and an origin-room source ID decoded by web and Apple clients documents_getnow enriches reads with Word Editor text for supported writing files when available and otherwise falls back to document-analysis preview text instead of metadata-only responses- fail-closed: requires a valid global internal secret or active run-scoped capability in
x-clapilot-agent-secret; requests without either credential are rejected even when no global secret is configured
/api/livestream/studioGET: admin-only Live Stream Studio summary with the default YouTube channel config, redacted stream-key state, queued clips, assets, scanned video files from the shared livestream media directory, recent FFmpeg runs, recent events, YouTube chat messages, detected audience requests, queue buffer seconds, approved buffer seconds, and current asset.POST: admin-only action endpoint. Supportsupdate_channel,set_agent_direction,run_agent_topup,create_asset,update_asset,enqueue_asset,enqueue_media_file,delete_media_file,reorder_queue,update_queue_item,set_stream_state,update_youtube_chat, andpoll_youtube_chat. Stream keys are encrypted before storage;update_channelalso persistsagent_topup_*controls;update_youtube_chatlinks the current admin's Google OAuth connection for YouTube chat ingest;set_agent_directionstores the natural-language stream briefing and can immediately wake the livestream agent; file queueing/deletion is restricted to videos inside the shared livestream media directory;delete_media_fileblocks active pending/playing queue references and archives linked assets after removing the file; asset queueing requires an approved asset with a renderedmedia_path;update_queue_itemcan setloop_countso a queue row stays in the loop and appears that many times per playlist cycle.
/api/livestream/availabilityGET: authenticated lightweight reachability endpoint for the sidebar. Returns the livestream streamer status, last heartbeat, heartbeat age, stale threshold, reason, andavailable=trueonly whenclapilot-streamerhas written a fresh non-offline heartbeat.
/api/livestream/mediaGET: admin-only inline video preview endpoint for files inside the shared livestream media directory. Acceptspath, validates that it resolves inside the media directory, and supports byte ranges so the Studio's video-library tiles can use native browser playback controls without exposing arbitrary filesystem reads.
/api/clapilotaicore/live-voice-settingsGET: authenticated Realtime and Live Voice settings payload for the ClapilotAICore Audio settings page, including the general Realtime provider/model routing dropdown options and provider readiness (enabled, API-key presence, and Live Transcribe readiness),api_live_transcribe_enabled,api_live_transcribe_model, compatible live-transcription model options, Google Meet enablement, optional Meet-specific Realtime model override, Meet-specific voice, and default Meet participant display namePOST: admin-only update endpoint for those Live Voice settings; API Live Transcribe can only be enabled when the selected Realtime provider is enabled, is an OpenAI API-key provider with a stored key, and the model is compatible with live browser transcription. Text-model preflight health does not gate audio-only use. Invalid configuration returns a localized400response instead of persisting an unusable gate. The general Realtime provider/model pair is persisted inapp_settings.native_model_routing; API transcription values useapp_settings.api_live_transcribe_enabledandapi_live_transcribe_model; Google Meet values useapp_settings.google_meet_live_voice_enabled,google_meet_live_model,google_meet_live_voice, andgoogle_meet_agent_display_name
/api/chat/transcription/realtime/sessionPOST: authenticated two-minute OpenAI Realtime transcription client-secret creation. Disabled, missing-key, wrong-auth-mode, or administrator-disabled provider configuration returns localized409 realtime_transcription_configuration_error; upstream OpenAI failures retain the upstream status, while unexpected session-creation failures return502.
/api/clapilotaicore/dgx-telemetry-settingsGET: admin-only load of the DGX telemetry endpoint settings forSettings -> ClapilotAICore -> DGX Cluster; returns the raw saved URL, effective URL, default URL, and edit capabilityPOST: admin-only update ofapp_settings.dgx_telemetry_api_base_url; accepts{ api_base_url }, allows an empty value for the default endpoint, and validates HTTP/HTTPS URLs
/api/clapilotaicore/dgx-telemetry/statsGET: admin-only proxy to the configured upstream/api/stats; returns the JSON snapshot as-is, including schema v2{ schema_version, has_logo, clusters: [{ cluster_id, cluster_name, up, nodes, static, hist, ...metrics }] }, and maps unreachable upstreams to502 { error: "upstream_unreachable" }; the web consumer also accepts the legacy schema v1 flat snapshot
/api/clapilotaicore/dgx-telemetry/healthGET: admin-only proxy to the saved upstream/api/health; passes through schema v2{ ok, schema_version, clusters: [{ cluster_id, up, model, endpoint }] }with status200when any cluster is serving or503when none are servingPOST: admin-only test-connection proxy for an unsaved{ api_base_url }override; passes through the same upstream JSON and200/503status
/api/clapilotaicore/dgx-telemetry/schemaGET: admin-only proxy to the configured upstream/api/schema; maps unreachable upstreams to502 { error: "upstream_unreachable" }
/api/clapilotaicore/dgx-telemetry/streamGET: admin-only SSE pass-through proxy to the configured upstream/api/stream; returnstext/event-streamand lets the browser reconnect manually when the upstream is unavailable
Automation webhook durability
GET|POST|PUT|PATCH /api/automation-webhooks/{token} returns run_id only after the corresponding agent_runs reservation and webhook payload queue row commit atomically. Repeated provider delivery IDs return the original run. Runtime termination leaves auditable terminal fields and the queue retries the payload; result delivery is idempotent by run_id.
Video Studio voiceover
GET /api/video-studio/voiceover?slug=<project> returns the persisted voice, provider, scene timings, editable
texts, and generated segment metadata for an admin-owned Video Studio project. POST /api/video-studio/voiceover
accepts action=generate-all, generate-segment, or remix, together with slug, provider (openai, gemini,
or openai_compatible), voice, optional owned-character UUID voice_character_id, and the scene segments.
When voice_character_id is set, the character must have an uploaded sample and the provider must be
openai_compatible; the sample is supplied to every synthesized segment as the voice-clone reference. Generation
resolves credentials through Clapilot's configured server-side TTS runtime. The
remix action performs audio-only FFmpeg muxing; refreshBase=true snapshots a newly visual-rendered MP4 first.
Model training and evaluation
All routes below require an administrator session and run in the Node.js runtime. Upstream network/timeouts return 502 { "error": "upstream_unreachable", "detail": "..." }. Other upstream failures return upstream_error; a one-run-at-a-time conflict from job creation returns 409 { "error": "training_already_running", "detail": "..." }.
| Method | Route | Request | Response |
|---|---|---|---|
GET | /api/clapilotaicore/model-training/settings | - | {api_base_url,effective_api_base_url,default_api_base_url,can_edit} |
PUT | /api/clapilotaicore/model-training/settings | {api_base_url}; empty means the default | Same settings payload |
GET | /api/clapilotaicore/model-training/stats | - | {up,ts,node:{ram_total_gb,ram_avail_gb,ram_used_gb,gpu_util,gpu_temp,gpu_watts},docker,active,total_runs,completed,failed,current,last} |
GET | /api/clapilotaicore/model-training/runs | - | TrainingRun[], including history: [[step,loss]], progress, ETA, state, paths, and hyperparameters |
GET | /api/clapilotaicore/model-training/jobs | - | FineTuneJob[] (the upstream list wrapper is normalized away) |
POST | /api/clapilotaicore/model-training/jobs | {training_file,suffix?,hyperparameters:{targets?,rank?,alpha?,learning_rate?,seq_len?,batch_size?,grad_accum?,max_steps?,epochs?}} | FineTuneJob |
GET | /api/clapilotaicore/model-training/jobs/:jobId | - | FineTuneJob |
GET | /api/clapilotaicore/model-training/jobs/:jobId/events | - | FineTuneJobEvent[] |
POST | /api/clapilotaicore/model-training/jobs/:jobId/cancel | - | Cancelled/cancelling FineTuneJob |
POST | /api/clapilotaicore/model-training/datasets/upload | Multipart file | {id,lines} |
POST | /api/clapilotaicore/model-training/datasets/from-chat-export | `{instances?:string[],sources?:('personal_chat' | 'group_chat' |
GET | /api/clapilotaicore/model-training/compare/models | - | {eval:{up,running,models,base,adapters},gateway} |
POST | /api/clapilotaicore/model-training/compare/start | - | Upstream start result |
POST | /api/clapilotaicore/model-training/compare/stop | - | Upstream stop result |
POST | /api/clapilotaicore/model-training/compare/load | {run_id} | {loaded} |
POST | /api/clapilotaicore/model-training/compare/chat | {model,messages,max_tokens?,temperature?,seed?} | {model,content,seconds,tok_per_s} plus upstream metadata |
POST | /api/clapilotaicore/model-training/compare/verify | {run_id?:string,model?:string,prompt?,max_tokens?} | {base:{content,seconds,tok_per_s},adapter:{...},identical} |
GET | /api/clapilotaicore/model-training/stream | SSE | Every three seconds: data: {stats,runs}; upstream failures use an SSE error event |
The verify route resolves ft:<run_id> and the current base model from the models endpoint. Both requests use the same prompt, temperature 0, and fixed seed. identical: true is an inert-adapter warning, not success.
