Curiosity

Creating Endpoints

A custom endpoint is C# code that runs inside the workspace process and is reachable over HTTP. You author and deploy them through the workspace UI — there's no separate build step.

For the full hands-on walkthrough see Custom endpoint from scratch. This page is the reference for the dialog itself.

Create

  1. Open Management → Endpoints.
  2. Click + New endpoint.
  3. Fill in the configuration (below).
  4. Paste your code and Save. The workspace compiles and hot-loads.

Curiosity Workspace Custom Endpoints

Configuration

Setting Values What it does
Endpoint path hello-world, kb/answer URL segment. Use slashes for hierarchy.
Mode Sync / Pooling Sync holds the HTTP connection. Pooling returns 202 Accepted and lets the client poll.
Authorization Unrestricted / Restricted Unrestricted endpoints are reachable without a token. Restricted requires a user session or an endpoint token.
Read only true / false When true, the endpoint can run on a read-only replica; the runtime blocks writes.
Run as admin true / false Bypasses the caller's ACL filtering. Use sparingly and never for endpoints called by end users.
Mode picker
Sub-second response, no LLM work Sync
Calls ChatAI.CompleteAsync on a large prompt Pooling
Periodic batch run with no caller Use a scheduled task instead.

Code shape

The body of an endpoint runs inside an *ExecutionScope — the type depends on whether the endpoint is marked read-only. Every member documented in Endpoint execution scopes is available as a top-level identifier.

Minimal sync endpoint:

return $"Hello! The current time is {DateTimeOffset.UtcNow:u}";

Typed JSON request and response:

public record EchoRequest (string Message);
public record EchoResponse(string Message, DateTimeOffset At);

var req = Body.FromJson<EchoRequest>();
return Ok(new EchoResponse(req.Message, DateTimeOffset.UtcNow));

Returning an HTTP error explicitly:

if (string.IsNullOrWhiteSpace(req.Message))
    return BadRequest("Message is required.");

How callers reach it

URL When
{workspace}/api/endpoints/external/{path} Unrestricted endpoints (public).
{workspace}/api/endpoints/token/run/{path} Restricted endpoints (Bearer token).
await Mosaik.API.Endpoints.CallAsync<T>(path, body?) From a Tesserae front-end (session-authenticated).
await client.CallAsync<T>(path, body) From a connector or external service (EndpointsClient).

See Calling endpoints for the full request shapes, including pooling.

Pooling mode

When the endpoint may run longer than the proxy / browser allows on a single connection, switch to Pooling:

  • The first call returns 202 Accepted with an MSK-ENDPOINT-KEY header.
  • The caller polls the same URL (passing the key) until it gets 200 OK.
  • RelayStatusAsync(string) from the endpoint streams status updates to the caller.

The built-in EndpointsClient and Mosaik.API.Endpoints.CallAsync handle the polling transparently. From curl / external clients see Calling endpoints.

Read-only endpoints

Marking an endpoint read only has two effects:

  1. The endpoint can run on a read-only replica (useful for scaling read-heavy workloads).
  2. The runtime swaps CodeEndpointExecutionScope for ReadOnlyCodeEndpointExecutionScope, which exposes a ReadOnlyGraph and removes the write methods.

If you need to write from a read-only endpoint, call RunEndpointOnPrimaryAsync<T>(path, body) to forward to the primary node.

Versioning and promotion

Endpoints live inside the workspace graph as nodes. Treat them like deployable code:

  1. Export the endpoint definition from the workspace UI (Management → Endpoints → ⋯ → Export).
  2. Commit the exported file to git.
  3. Re-import on promotion to staging / production.

See the production deployment checklist for the surrounding flow.

© 2026 Curiosity. All rights reserved.