Skip to content
CADCAMFUN
Docs

Documentation

API reference

The complete HTTP resource reference, authenticated local access, streaming contracts, and clients generated from shared schemas.

Overview

The sidecar is a single Effect HttpApi. Every endpoint is a typed HttpApiEndpoint with schema-checked request and response bodies, so this reference, the generated SDK and the running server come from the same declaration in packages/api.

Surface
325 operations

Across 232 paths and 35 resource groups.

Types
56 schemas

Request, response and error shapes, each linked from the operations that use it.

Contract
OpenAPI 3.1.0

Emitted by the sidecar at /api/openapi.json; the snapshot in packages/web is checked by bun run check:api-reference.

Clients
One surface

The desktop webview, the mobile companion, the AI bridge and scripts all call these same routes.

Base URL

There is no hosted CADCAMFUN API. The sidecar runs on your machine, binds 127.0.0.1 on a port the operating system picks (it listens on port 0), checks its own /api/health, and only then prints one JSON line on stdout. The base URL is http://127.0.0.1:<port> from that line.

Start a disposable sidecar and read its port
export CADCAMFUN_TOKEN=dev-token
CADCAMFUN_DATA_DIR=$(mktemp -d) \
CADCAMFUN_MIGRATIONS_DIR=$PWD/packages/db/drizzle \
CADCAMFUN_AI_OFFLINE=true \
  bun --no-env-file apps/sidecar/src/main.ts
# stdout: {"event":"ready","port":46709}
export CADCAMFUN_URL=http://127.0.0.1:46709

The port changes on every launch

Read it from the ready line (the desktop shell does exactly that) instead of assuming a fixed number. Logs go to stderr so stdout carries only the ready or error event.

Authentication

The contract declares one security scheme, bearer (HTTP Bearer). 324 of 325 operations require it; only GET /api/health is public.

CredentialSent asUsed by
Launch tokenAuthorization: Bearer <token>The desktop webview and local scripts; the value of CADCAMFUN_TOKEN.
Companion tokenAuthorization: Bearer <token>A paired phone; narrower access, see companion pairing.
Account sessionx-session-tokenSelects the acting account on top of the bearer token; see identity below.
Public and protected
curl -s "$CADCAMFUN_URL/api/health"
curl -s "$CADCAMFUN_URL/api/projects" -H "Authorization: Bearer $CADCAMFUN_TOKEN"

Conventions

  • JSON in, JSON out. Bodies are application/json unless a card says otherwise: two multipart uploads, one octet-stream webhook, a JavaScript bootstrap, a zip download, a binary plugin file, and two event streams.
  • Operation ids are dotted. projects.get, vcs.commit: the group tag, a dot, the method name used by the generated clients.
  • Errors are typed. Failures are declared per endpoint and carry a _tag; switch on it instead of parsing messages. Across the contract, 401 is declared on 269 operations, 500 on 264 and 400 on 206.
  • Operation anchors are stable. Each card is linkable as #op-<method>-<path>, for example /docs/api/projects#op-get-api-projects-id.

Streaming

PathShapeCarries
GET /api/projects/{id}/eventsSSEChange events for one project.
POST /api/ai/chat/streamSSEAssistant output as it is produced, plus heartbeats; see AI streaming.
Follow a project's events
curl -N "$CADCAMFUN_URL/api/projects/$PROJECT_ID/events" \
  -H "Authorization: Bearer $CADCAMFUN_TOKEN"

Clients

@cadcamfun/api/sdk is generated from this same contract: every operation id below is a typed method on CadCam.make(...), taking one flat input of path parameters and body fields. 259 of the 325 operations are generated; each card shows its exact call.

@cadcamfun/api/sdk
import { CadCam } from "@cadcamfun/api/sdk"

const client = CadCam.make({
  baseUrl: process.env.CADCAMFUN_URL!,
  headers: { authorization: `Bearer ${process.env.CADCAMFUN_TOKEN}` },
})

const projects = await client.projects.list()
const created = await client.projects.create({ name: "Bracket" })

Resources

325 operations in 35 groups, arranged by what they serve.

Core

Design

Manufacturing

Resources

Extensions

Accounts

OpenAPI document

Download /docs/api/openapi.json (the checked-in snapshot this site renders) or fetch the live document from a running sidecar at /api/openapi.json. Regenerate the snapshot with bun run generate:api-reference in packages/web after changing an endpoint.

Contract and server

@cadcamfun/api defines request and response schemas with Effect HttpApi. It exports the root Api, domain records, tagged errors, and clients. Request handlers, authorization decisions, database queries, and provider calls run in the sidecar. Importing a schema does not start a server.

The sidecar publishes its served contract at GET /api/openapi.json. Use that running document to inspect methods, path parameters, payloads, and status codes for the application you are connected to. The server assembles its groups in apps/sidecar/src/layers.ts; the shared contract is assembled in packages/api/src/index.ts.

Authentication and identity

Protected routes require Authorization: Bearer <token>. The desktop receives a new application token when its sidecar starts. GET /api/health is the public health probe; native /health and /version are protected. Application bearer tokens are compared with a timing-safe comparison.

An optional x-session-token carries an account session JWT. The bearer token admits the local application; the session selects its acting account. An absent, expired, invalid, or orphaned session falls back to the installation's local profile. Resource handlers then check ownership or organization access through repository authorization helpers.

A scoped bridge token admits only GET /api/ai/actions and POST /api/ai/actions/invoke. It does not grant access to project CRUD, credential settings, or other HTTP routes. Its project and read/write scope are checked again by the action bridge.

Resource families

  • Design: projects, drawings, components, drawing versions, entity import/export, and exact CAD analysis, STEP export, and assembly analysis.
  • Manufacturing: toolpaths and versions, comments, generator suggestions, parsing, replay verification, native manufacture jobs, materials, tools, machine configurations, library items, and production costs.
  • Assistant: providers, credentials, models, sessions, streaming turns, session controls, actions, project memory, workspace context, and stateless advice.
  • Collaboration: branches, commits, diffs, pull requests, reviews, GitHub mirrors, workflow files and runs, live events, and companion pairing.
  • Application services: users, authentication, organizations, notifications, files, plugins, billing, analytics, waitlist, MCP configuration, and local key-value storage.

The contract groups retain their endpoint-specific response shapes. A client should decode the schema of the operation it calls instead of assuming a single application-wide JSON envelope.

Responses and failures

Common tagged errors map to HTTP 400 (BadRequest), 401 (Unauthorized), 403 (Forbidden), 404 (NotFound), 405 (MethodNotAllowed), 409 (Conflict), and 500 (InternalError). Their declared schemas carry a human-readable message. Some groups use an envelope with success: false, message, and errors; a small number use an error field.

Success responses can be a record, an array, a nullable value, or an envelope. Envelope includes success, message, and data; EnvelopeOpt makes the message optional. Creation endpoints explicitly declare 201 where appropriate. Do not infer success solely from a JSON field without checking the HTTP status and endpoint schema.

Schema decoding validates transport input before the handler executes. Business validation still runs in the service: a structurally valid request may refer to an inaccessible drawing, contain a stale manufacturing artifact, or request a conflicting branch operation.

Use the shared client

ApiClient.layer takes a baseUrl and application token. It supplies the fetch transport and the client authorization middleware. Its methods are derived directly from Api, so this client also covers operations omitted by code generation.

Read projects with the Effect client
import { ApiClient } from "@cadcamfun/api"
import { Effect } from "effect"

const projects = Effect.gen(function* () {
  const api = yield* ApiClient
  return yield* api.projects.list()
}).pipe(Effect.provide(ApiClient.layer({ baseUrl, token })))

The base URL is the sidecar's loopback address and assigned port. Resolve it from the desktop connection, rather than persisting a port across launches. Keep tokens out of URLs and logs.

Design and manufacturing requests

Project operations use /api/projects; drawings and toolpaths have their own collections and detail routes. POST /api/toolpaths/generate produces G-code, parsed program data, warnings, and statistics from generator settings and geometry. /suggest, /parse, and /verify expose parameter advice, G-code interpretation, and stock replay. These computations do not create a saved toolpath.

POST /api/toolpaths/manufacture accepts a versioned CAD snapshot and returns a kernel result with NC, tool assignments, cutting data, claims, issues, and a release level. Save a resulting document separately through a toolpath create or update operation. See Setups for evidence validation during persistence.

POST /api/cad/exact/analyze, /step, and /assembly accept explicit elements or a stored drawing identifier. Reading a stored drawing applies the caller's normal drawing access checks.

Streaming and recovery

The AI stream carries typed events for text, reasoning, tool calls and results, permission and question requests, retries, turn state, context, and completion. Clients must consume events incrementally and retain the session identifier. An HTTP connection ending is not sufficient evidence that a model turn finished: session state can be read again after reconnecting.

AI event schemas live in packages/api/src/ai-events.ts and packages/ai/src/events.ts. General live events use the events group. Binary downloads, JavaScript plugin bootstrap responses, and signed raw webhook bodies require their own transport handling.

List routes that page their results use page and limit query parameters. For machine configurations, page defaults to 1, limit defaults to 20 and is clamped to 1–100, and the response carries pagination with page, limit, total, and totalPages (apps/sidecar/src/http/machine-configs.ts). Check each group's reference page for the parameters it actually declares.

Generated SDKs

@cadcamfun/httpapi-codegen reflects HttpApi groups into operation metadata and generated clients. The API generator writes a Promise SDK to packages/api/src/sdk/generated and Effect clients to packages/api/src/client/generated. The public Promise SDK is exported as @cadcamfun/api/sdk.

Regenerate or check client drift
bun run --filter @cadcamfun/api generate
bun run --filter @cadcamfun/api generate:check

Both generated targets omit profile multipart upload, plugin multipart installation, MCP creation with multiple success schemas, MCP update with colliding identifiers, project toolpath creation with duplicate input names, and plugin file serving with stream headers. The Promise target also omits Stripe raw webhooks, plugin JavaScript bootstrap, binary file download, and the generator's generate/suggest requests. These omissions are explicit in packages/api/scripts/generate-clients.ts; use the contract client or the appropriate raw transport for those operations.

Source organization

groups/ contains resource contracts. Shared geometry and CAM schemas come from @cadcamfun/core; cad-exact.ts, cam-kernel.ts, and cam-program.ts describe rich CAD/CAM results and portable documents. client.ts builds the contract client, while the generation script owns generated targets and omission lists.

Integration rules

Reuse contract schemas at transport boundaries and keep database dependencies in the sidecar. Introduce an endpoint through its contract, handler, service or repository, and focused HTTP coverage together. Generated files are outputs: edit their contract or generator and regenerate them. An API schema version, a portable file version, and a plugin API version describe separate contracts.

Resource reference

325 operations across 232 paths and 35 resource groups, with 56 named schemas. Each resource page lists its operations and shows declared path/query/header parameters, required and optional fields, nullable values, content types, success and error statuses, and full schemas.

The data is emitted from packages/api/src/index.ts, the same composed HttpApi contract used by the clients and sidecar. The pages describe the checked-out contract; inspect the running server's /api/openapi.json if you connect to another version.

HTTP resource

Health

Public process health probe with status and timestamp.

HTTP resource

System

Authenticated readiness and application version used by native clients.

HTTP resource

Projects

Create, list, read, update, and remove projects with owner and organization access checks.

HTTP resource

Workspace

Read-only project drawings, components, toolpaths, library resources, and bounded previews for companion clients.

HTTP resource

Drawings

Project drawings and their saved geometry, metadata, and update operations.

HTTP resource

Components

Reusable project components and their persisted design data.

HTTP resource

Exact CAD

Analyze exact geometry, export STEP, and inspect assembly relationships from scene snapshots or saved drawings.

HTTP resource

Toolpaths

Saved machining programs, drawing associations, and validated portable manufacturing documents.

HTTP resource

Project toolpaths

Project-scoped toolpath listing and creation with endpoint-specific response envelopes.

HTTP resource

Machining

Native manufacture, settings-driven G-code generation, suggestions, parsing, and replay verification.

HTTP resource

Toolpath history

Toolpath versions, restoration, library discovery, and threaded program comments.

HTTP resource

Materials

Material records, application machining properties, and resource access.

HTTP resource

Material storage

Material storage attachments and JSON import/export for library interchange.

HTTP resource

Tools

Cutter records and dimensions used by application machining workflows.

HTTP resource

Tool storage

Tool storage data and collection or per-tool import/export.

HTTP resource

Machines

Machine configuration records, updates, removal, and cloning.

HTTP resource

Machine storage

Machine storage attachments and configuration import/export.

HTTP resource

Library

Shared library records and component, material, and tool lookup collections.

HTTP resource

Production costs

Estimates, calculation requests, material costs, operation costs, and tool-wear records.

HTTP resource

AI sessions and actions

Providers, credentials, conversations, streaming turns, action invocation, bridge tokens, skills, and session recovery.

HTTP resource

History and workflows

Project Git-compatible commits, branches, restores, reviews, GitHub mirroring, and workflow dispatch.

HTTP resource

Project events

Project-scoped server-sent events for live clients.

HTTP resource

Companion pairing

Desktop gateway state, enable/disable, device pairing, and device revocation.

HTTP resource

Plugins

Plugin registry, package installation, configuration, enable/disable, and served plugin assets.

HTTP resource

MCP configuration

MCP connection configuration CRUD and server-info requests.

HTTP resource

Files

Upload and download operations with endpoint-specific payload and response encoding.

HTTP resource

Key-value storage

JSON-compatible preference and context entries with prefix listing and per-key operations.

HTTP resource

Organizations

Organization lists and managed organization records.

HTTP resource

Notifications

Notification listing, read-state updates, deletion, and mark-all-read.

HTTP resource

Authentication

Account sign-in, sign-up, recovery, verification, magic links, session lookup, and passkey registration.

HTTP resource

Users

Profiles, account resources, API keys, token records, passwords, and account removal.

HTTP resource

Billing

Subscription information, Stripe checkout/portal integration, trial maintenance, and signed webhook ingestion.

HTTP resource

Analytics

Application metrics, recent activity, usage queries, and tracking requests.

HTTP resource

Application services

Desktop integration routes, tracked project operations, notifications, and push-subscription records.

HTTP resource

Waitlist

Submit waitlist registration through the local application API.

Download OpenAPI JSON · Follow requests with captured responses

Connection and request conventions

The API is supplied by the local sidecar rather than a fixed hosted endpoint. Tauri obtains its dynamically selected loopback URL and launch token. A manually started sidecar announces its port in a JSON ready event. A paired mobile client connects through its configured HTTPS gateway instead.

Read with your current sidecar connection
curl --silent --show-error "$CADCAMFUN_URL/api/projects" \
  --header "Authorization: Bearer $CADCAMFUN_TOKEN"

Set both variables from the actual connection. Request templates on resource pages deliberately use placeholders and payload files. Optional transport fields are not promises that every business operation can omit them: project creation, for example, rejects a missing name in its handler.

ConventionClient behavior
Path parametersReplace the named segment and URL-encode its value. Treat an identifier as a single segment.
Query parametersEncode declared values. Pagination and filtering are per-endpoint; there is no universal page-size contract.
JSON payloadSend the declared object with Content-Type: application/json. Required presence and accepting null are independent.
Multipart payloadBuild form parts with the upload client or FormData; let the transport choose its boundary.
Binary, JavaScript, or stream responseConsume the declared media type. Do not call response.json() unconditionally.
ErrorsCheck HTTP status and decode the endpoint's declared failure shape. Error envelopes differ across resource families.
Retried writesRead state after an interrupted operation before resubmitting a mutation. The contract does not provide a universal idempotency-key mechanism.

Generated reference maintenance

packages/web/script/generate-api-reference.mjs reads the composed contract using the API package's installed Effect implementation and writes the reference JSON. The documentation Worker consumes the generated content; it does not initialize the application server to answer documentation requests.

From packages/web
bun run generate:api-reference
bun run check:api-reference
bun run check:docs-index

Resource coverage is checked against every declared operation. A newly added group must receive reader-facing metadata and navigation, and a changed request or response must be regenerated. Handwritten guides still explain authorization rules, side effects, service configuration, and limits that an HTTP schema alone cannot express.

Integration recipes

Start with captured HTTP requests to see how project creation, business validation, bearer rejection, related records, and key-value persistence actually respond. Use typed client integration to reproduce those operations with the Promise SDK or Effect client and handle their distinct failure channels.

IntegrationProcedureKey state to retain
Project editorCreate, save, and reopen workProject/resource identity, saved data, actual update semantics.
Manufacturing pipelineGenerate and persist a native jobCaptured request, exact NC/program, release claims, matching portable document.
Assistant UIConsume events and recover sessionsProject/session identity, pending permissions/questions, terminal turn state.
External capabilityAuthor a supported pluginManifest, module exports, capability grant, argument validation and tool result.
Review automationVersion and review project workCommit/ref, structural diff, reviews, committed workflow, individual check outputs.
Paired clientEnable and manage device accessGateway address, certificate fingerprint, individually revocable device token.

These recipes connect HTTP contracts to real service behavior. A schema can describe required presence, encoding, and a returned shape; its linked guide explains access rules, persistence effects, supported recovery, and limits that cannot be inferred from those types alone.

Operations per resource group

The contract currently declares 270 operations in 34 groups, all under a single bearer HTTP security scheme. The only operation without bearer security is the public health probe. The table is computed from the generated OpenAPI document: operations per group, the HTTP methods used, how many distinct paths, and one representative path.

GroupTagOpsMethodsPathsExample path
Healthhealth1GET 11/api/health
Systemsystem2GET 22/health
Projectsprojects5DELETE 1, GET 2, POST 1, PUT 12/api/projects
Drawingsdrawings5DELETE 1, GET 2, POST 1, PUT 12/api/drawings/{id}
Componentscomponents5DELETE 1, GET 2, POST 1, PUT 12/api/components/{id}
Exact CADcadExact3POST 33/api/cad/exact/analyze
Toolpathstoolpaths7DELETE 1, GET 3, POST 2, PUT 13/api/drawings/{id}/toolpaths
Project toolpathsprojectToolpaths2GET 1, POST 11/api/projects/{id}/toolpaths
MachiningtoolpathGenerator5POST 55/api/toolpaths/generate
Toolpath historytoolpathExtras8DELETE 1, GET 3, POST 3, PUT 15/api/toolpaths/library
Materialsmaterials5DELETE 1, GET 2, POST 1, PUT 12/api/materials
Material storagematerialsStorage5DELETE 1, GET 2, POST 22/api/materials/export-import
Toolstools5DELETE 1, GET 2, POST 1, PUT 12/api/tools
Tool storagetoolsStorage7DELETE 1, GET 3, POST 33/api/tools/export-import
MachinesmachineConfigs6DELETE 1, GET 2, POST 2, PUT 13/api/machine-configs
Machine storagemachineConfigsStorage5DELETE 1, GET 2, POST 22/api/machine-configs/export-import
Librarylibrary8DELETE 1, GET 5, POST 1, PUT 15/api/library
Production costsproduction-costs21DELETE 4, GET 8, POST 5, PUT 49/api/production-costs/estimates
AI sessions and actionsai34DELETE 3, GET 8, POST 21, PUT 232/api/ai/actions
History and workflowsvcs22GET 10, POST 11, PUT 119/api/projects/{id}/actions/dispatch
Project eventsevents1GET 11/api/projects/{id}/events
Companion pairingcompanion5DELETE 1, GET 1, POST 35/api/companion
Pluginsplugins16DELETE 1, GET 8, PATCH 1, POST 4, PUT 212/api/plugins
MCP configurationmcp8DELETE 2, GET 2, POST 2, PUT 23/api/mcp/config
Filesfiles2GET 1, POST 12/api/download
Key-value storagekv4DELETE 1, GET 2, PUT 12/api/kv
Organizationsorganizations5DELETE 1, GET 2, POST 1, PUT 12/api/organizations
Notificationsnotifications4DELETE 1, GET 1, POST 1, PUT 13/api/notifications
Authenticationauth12GET 1, POST 1112/api/auth/forgot-password
Usersuser16DELETE 2, GET 10, POST 2, PUT 212/api/user/api-keys
Billingbilling15DELETE 1, GET 5, POST 8, PUT 110/api/better-auth-stripe/billing-portal
Analyticsanalytics10DELETE 1, GET 7, POST 29/api/analytics
Application servicesmisc10DELETE 2, GET 3, POST 4, PUT 16/api/app-control/notify
Waitlistwaitlist1POST 11/api/waitlist

Status codes across the contract

Counting each declared response once per operation gives this picture of what a client must be ready to decode:

StatusDeclared onTypical body
200242 operationsResource, array, nullable value or Envelope
20128 operationsThe created record (for example POST /api/projects)
2041 operationNo body
400206 operationsBadRequest, EnvBadRequest and family-specific variants
401269 operationsUnauthorized (bearer middleware)
403101 operationsForbidden / EnvForbidden
404149 operationsNotFound / EnvNotFound
40530 operationsEnvMethodNotAllowed / KeyedMethodNotAllowed
40929 operationsConflict / EnvConflict
500264 operationsInternalError, EnvInternal, KeyedInternal and family variants
501, 5031 operation eachEndpoint-specific

Every error is an Effect tagged error, so its JSON body always contains a _tag discriminator next to its fields. There are three body families, inherited from the legacy handlers so existing clients keep working:

Plain error (message only)
{ "_tag": "NotFound", "message": "Project not found" }
Envelope error
{ "_tag": "EnvNotFound", "success": false, "message": "Material not found", "errors": null }
Keyed error (a few library routes)
{ "_tag": "KeyedInternal", "error": "Failed to load components" }

Success envelopes mirror the error envelope: { success: true, message, data }, where data may be null. The EnvelopeOpt variant omits message when the handler did not provide one. Switch on _tag rather than on the presence of message or error.

How a request is processed

clientfetch / SDK route matchmethod + path bearer check401 Unauthorized schema decode400 on bad input handleraccess + logic encodesuccess / _tag x-session-token picks the acting account; absent or invalid falls back to the local profile
  1. The router matches method and path. Unknown routes never reach a handler.
  2. The bearer middleware compares the token in constant time. A missing or wrong token stops the request with 401 before any decoding.
  3. Path, query, headers and body are decoded against the operation's schemas. Structural problems become 400 without running business code.
  4. The handler resolves the acting account, checks ownership or organization membership (403/404) and runs the service.
  5. The result is encoded with the declared success schema, or the failure with its tagged error schema and status.

Responses that are not JSON

OperationMedia typeHow to consume
POST /api/ai/chat/streamtext/event-streamRead incrementally; each data: line is one typed assistant event.
GET /api/projects/{id}/eventstext/event-streamLive project events; reconnect and re-read state after a drop.
GET /api/plugins/bootstrap.jsapplication/javascriptLoaded by the plugin host, not parsed as JSON.
GET /api/plugins/serveapplication/octet-streamPlugin file bytes.
GET /api/downloadapplication/zipSave as a file; use response.blob() or stream to disk.

The generated Promise SDK rejects a streaming response whose content type is not text/event-stream with ClientError("UnsupportedContentType"), and a single SSE event larger than 16 MiB with SseEventTooLarge.

Calling the API without a client

Minimal typed fetch wrapper
type TaggedError = { _tag: string; message?: string; error?: string }

async function call<T>(base: string, token: string, method: string, path: string, body?: unknown): Promise<T> {
  const response = await fetch(new URL(path, base), {
    method,
    headers: {
      authorization: `Bearer ${token}`,
      ...(body === undefined ? {} : { "content-type": "application/json" }),
    },
    body: body === undefined ? undefined : JSON.stringify(body),
  })
  if (response.status === 204) return undefined as T
  const payload = await response.json()
  if (!response.ok) {
    const failure = payload as TaggedError
    throw new Error(`${response.status} ${failure._tag}: ${failure.message ?? failure.error}`)
  }
  return payload as T
}

const project = await call<{ id: string; name: string }>(
  process.env.CADCAMFUN_URL!, process.env.CADCAMFUN_TOKEN!,
  "POST", "/api/projects", { name: "Bracket" },
)

Prefer the generated clients in TypeScript: they know each operation's success status and declared error statuses, and treat anything else as UnexpectedStatus instead of guessing.

In 3D

API groups by size Drag to orbit · scroll to zoom · right-drag to pan
Every API group as a column, height = operations counted from the generated OpenAPI document (270 in total). Rows are the six sidebar categories; ai (34), history (22) and costs (21) are the largest groups.