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
- Open Management → Endpoints.
- Click + New endpoint.
- Fill in the configuration (below).
- Paste your code and Save. The workspace compiles and hot-loads.

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 Acceptedwith anMSK-ENDPOINT-KEYheader. - 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:
- The endpoint can run on a read-only replica (useful for scaling read-heavy workloads).
- The runtime swaps
CodeEndpointExecutionScopeforReadOnlyCodeEndpointExecutionScope, which exposes aReadOnlyGraphand 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:
- Export the endpoint definition from the workspace UI (Management → Endpoints → ⋯ → Export).
- Commit the exported file to git.
- Re-import on promotion to staging / production.
See the production deployment checklist for the surrounding flow.
Cross-links
- Execution scopes — every helper you can call from inside the endpoint.
- Calling endpoints
- Security best practices
- Custom endpoint from scratch — end-to-end tutorial.