- External application API: REST over HTTPS, JSON payloads, OpenAPI 3.1.
- Streaming assistant responses: Server-Sent Events (SSE) for the initial web product.
- Asynchronous operations: resource plus job-status endpoints; optional signed webhooks later.
- Internal job/event schemas: versioned messages with stable event names.
- Base path:
/v1.
- API behavior is defined by
api/openapi.yamland contract tests. - Request and response schemas are generated or shared from one schema source.
- Unknown request fields SHOULD be rejected on security-sensitive operations.
- Timestamps are RFC 3339 UTC.
- IDs are opaque UUID strings.
- All errors use one envelope and stable error codes.
- Tenant scope is derived from authenticated access and verified against path/body identifiers.
- Resource existence is not disclosed to unauthorized users.
- Writes that may be retried use
Idempotency-Key. - Pagination uses opaque cursors, not mutable offsets, for growing collections.
Authorization: Bearer <token>or secure session cookieX-Request-IDoptional client request identifierIdempotency-Keyrequired for designated write operationsIf-Matchfor optimistic concurrency on selected mutable resources
X-Request-IDserver correlation identifierETagfor versioned mutable representationsRetry-Afterfor throttling or temporary unavailability where appropriate
{
"error": {
"code": "DOCUMENT_NOT_READY",
"message": "The document has not completed ingestion.",
"request_id": "uuid",
"details": {
"document_id": "uuid",
"status": "INGESTING"
}
}
}Rules:
messageis safe for the caller.- Internal stack traces, provider payloads, SQL text, secrets, and unauthorized object metadata are never returned.
detailsis schema-controlled per error code.
GET /health/liveGET /health/readyGET /v1/me
GET /v1/workspacesPOST /v1/workspacesGET /v1/workspaces/{workspace_id}GET /v1/workspaces/{workspace_id}/projectsPOST /v1/workspaces/{workspace_id}/projects
POST /v1/workspaces/{workspace_id}/uploadsPOST /v1/workspaces/{workspace_id}/uploads/{upload_id}/completeGET /v1/workspaces/{workspace_id}/documentsGET /v1/workspaces/{workspace_id}/documents/{document_id}DELETE /v1/workspaces/{workspace_id}/documents/{document_id}POST /v1/workspaces/{workspace_id}/documents/{document_id}/ingestion-jobsGET /v1/workspaces/{workspace_id}/ingestion-jobs/{job_id}
POST /v1/workspaces/{workspace_id}/retrieval/queryGET /v1/workspaces/{workspace_id}/retrieval/traces/{trace_id}
The query operation accepts text, project/source/date filters, current/history mode, result budget, and optional debug detail gated by role.
POST /v1/workspaces/{workspace_id}/conversationsGET /v1/workspaces/{workspace_id}/conversationsGET /v1/workspaces/{workspace_id}/conversations/{conversation_id}POST /v1/workspaces/{workspace_id}/conversations/{conversation_id}/messagesGET /v1/workspaces/{workspace_id}/conversations/{conversation_id}/eventsPOST /v1/workspaces/{workspace_id}/messages/{message_id}/feedback
POST .../messages may return 202 Accepted with a run resource or establish an SSE stream depending on Accept and client capability. The server persists terminal state even if the client disconnects.
GET /v1/workspaces/{workspace_id}/memoriesGET /v1/workspaces/{workspace_id}/memory-candidatesPOST /v1/workspaces/{workspace_id}/memory-candidates/{candidate_id}/approvePOST /v1/workspaces/{workspace_id}/memory-candidates/{candidate_id}/rejectPATCH /v1/workspaces/{workspace_id}/memories/{memory_id}DELETE /v1/workspaces/{workspace_id}/memories/{memory_id}
GET /v1/workspaces/{workspace_id}/toolsPOST /v1/workspaces/{workspace_id}/tool-runsGET /v1/workspaces/{workspace_id}/tool-runs/{tool_run_id}GET /v1/workspaces/{workspace_id}/approvalsPOST /v1/workspaces/{workspace_id}/approvals/{approval_id}/decisions
Direct arbitrary tool invocation is not exposed. The server resolves a registered tool version and policy from a canonical request.
GET /v1/workspaces/{workspace_id}/audit-eventsPOST /v1/workspaces/{workspace_id}/evaluation-runsGET /v1/workspaces/{workspace_id}/evaluation-runs/{run_id}
Suggested events:
event: run.started
data: {"run_id":"...","message_id":"..."}
event: response.delta
data: {"sequence":1,"text":"..."}
event: citation.provisional
data: {"citation_id":"...","source":{...}}
event: approval.required
data: {"approval_id":"...","summary":"..."}
event: response.completed
data: {"message_id":"...","usage":{...},"citations":[...]}
event: run.failed
data: {"error":{"code":"MODEL_PROVIDER_UNAVAILABLE","request_id":"..."}}
Every event includes a monotonically increasing sequence and run ID. Reconnection SHOULD support Last-Event-ID or a run-events endpoint.
Required for:
- upload initialization/completion where duplicate resources are undesirable;
- ingestion job creation;
- message/run initiation when clients may retry;
- approval decisions;
- tool execution and any external side effect;
- deletion requests.
The idempotency record binds principal, workspace, operation, canonical request hash, status, and response reference. Reusing a key with different canonical input returns a conflict.
- Mutable settings, memories, and approval decisions use version/ETag checks.
- Message and audit records are append-only.
- A partial unique constraint or transaction ensures one current document version.
- Approval consumption and tool execution are serialized transactionally.
OIDC handles authentication. Application authorization evaluates:
- principal status;
- workspace membership and role;
- optional project membership;
- resource sensitivity;
- requested operation;
- tool risk and scopes;
- provider eligibility for the data class.
The web UI is not a security boundary. Every API handler calls the policy service or a route-level authorization wrapper.
- Additive fields are allowed within
/v1when clients can ignore them. - Renames, semantic changes, required-field additions, enum removals, and response shape changes require a versioned migration.
- Event schemas include a
schema_version. - Deprecations include telemetry, documentation, and a removal date.
- Generated clients are tested against the committed OpenAPI document.
Key internal interfaces:
interface AuthorizationService {
authorize(input: AuthorizationRequest): Promise<PolicyDecision>;
}
interface RetrievalService {
query(input: RetrievalQuery): Promise<RetrievalTraceResult>;
}
interface ObjectStorage {
createUpload(input: CreateUploadRequest): Promise<UploadTarget>;
head(key: string): Promise<StoredObjectMetadata>;
get(key: string): Promise<ReadableStream>;
delete(key: string): Promise<void>;
}
interface JobDispatcher {
enqueue<T>(name: string, payload: T, options: JobOptions): Promise<JobReference>;
}
interface ToolExecutor {
execute(input: AuthorizedToolExecution): Promise<ToolExecutionResult>;
}Interfaces use domain contracts and errors; adapters translate vendor details.