Skip to content
CADCAMFUN
Docs

Documentation

Application services

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

Playground

Send these requests to your own running sidecar. Values stay in this browser.

Not connected
How this works

The sidecar listens on a loopback port chosen at startup and prints it in its ready line; use that URL and the CADCAMFUN_TOKEN it was started with. Requests go straight from this page to that address.

The sidecar sends CORS headers only to the Tauri origins and to http://localhost or http://127.0.0.1 on any port. From the hosted docs the browser blocks the response, so run the docs locally (bun run dev in packages/web) to use the playground, or copy the request as curl. To experiment without touching real data, start the sidecar with CADCAMFUN_DATA_DIR pointed at a throwaway directory — see the API walkthrough.

Operations

10 endpoints in the misc group, generated from the sidecar's own OpenAPI document. Protected operations take Authorization: Bearer $CADCAMFUN_TOKEN; see authentication. Behaviour and limits are in the subsystem guide.

post /api/push-subscription misc.pushSubscribe
delete /api/push-subscription misc.pushUnsubscribe
post /api/app-control/notify misc.notify
post /api/desktop/auth/signin misc.desktopSignin
get /api/desktop/projects misc.desktopProjects
post /api/desktop/projects misc.desktopCreateProject
get /api/desktop/user/by-email misc.desktopUserByEmail
get /api/projects/tracked/{id} misc.trackedGet
put /api/projects/tracked/{id} misc.trackedUpdate
delete /api/projects/tracked/{id} misc.trackedRemove
Application services operations in 3D Drag to orbit · scroll to zoom · right-drag to pan
One block per operation (10), stacked per resource section of this page and coloured by method: green GET, orange POST, blue PUT, violet PATCH, red DELETE. Generated from the OpenAPI document at build time.

/api/push-subscription

post /api/push-subscription # misc.pushSubscribe

Requires Authorization: Bearer <token>.

Request body · required · application/json
{
  endpoint?: string | null
  keys?: {
    p256dh?: string | null
    auth?: string | null
  } | null
}
Responses
200 object application/json
{
  success: true
  id: string
}
400 BadRequestEncoded application/json
BadRequestEncoded
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
500 InternalErrorEncoded application/json
InternalErrorEncoded
SDK example
misc.pushSubscribe
import { CadCam } from "@cadcamfun/api/sdk"

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

// MiscPushSubscribeInput
const result = await client.misc.pushSubscribe({
  endpoint: "",
  keys: {}
})
curl
POST /api/push-subscription
curl --request POST "${CADCAMFUN_URL}/api/push-subscription" \
  --header "Authorization: Bearer ${CADCAMFUN_TOKEN}" \
  --header "Content-Type: application/json" \
  --data-binary @request.json
Try it
delete /api/push-subscription # misc.pushUnsubscribe

Requires Authorization: Bearer <token>.

Request body · required · application/json
{
  endpoint?: string | null
}
Responses
200 object application/json
{
  success: true
}
400 BadRequestEncoded application/json
BadRequestEncoded
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
500 InternalErrorEncoded application/json
InternalErrorEncoded
SDK example
misc.pushUnsubscribe
import { CadCam } from "@cadcamfun/api/sdk"

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

// MiscPushUnsubscribeInput
const result = await client.misc.pushUnsubscribe({
  endpoint: ""
})
curl
DELETE /api/push-subscription
curl --request DELETE "${CADCAMFUN_URL}/api/push-subscription" \
  --header "Authorization: Bearer ${CADCAMFUN_TOKEN}" \
  --header "Content-Type: application/json" \
  --data-binary @request.json
Try it

/api/app-control/notify

post /api/app-control/notify # misc.notify

Requires Authorization: Bearer <token>.

Request body · required · application/json
{
  userId?: string | null
  message?: unknown | null
}
Responses
200 object application/json
{
  success: true
  message: string
}
400 NotifyBadRequestEncoded application/json
NotifyBadRequestEncoded
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
500 NotifyInternalEncoded application/json
NotifyInternalEncoded
SDK example
misc.notify
import { CadCam } from "@cadcamfun/api/sdk"

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

// MiscNotifyInput
const result = await client.misc.notify({
  userId: "",
  message: null
})
curl
POST /api/app-control/notify
curl --request POST "${CADCAMFUN_URL}/api/app-control/notify" \
  --header "Authorization: Bearer ${CADCAMFUN_TOKEN}" \
  --header "Content-Type: application/json" \
  --data-binary @request.json
Try it

/api/desktop/auth

post /api/desktop/auth/signin # misc.desktopSignin

Requires Authorization: Bearer <token>.

Request body · required · application/json
{
  email?: string | null
  password?: string | null
  deviceId?: string | null
  platform?: string | null
}
Responses
200 object application/json
{
  success: true
  token: string
  user: {
    id: string
    name: string | null
    email: string | null
    image: string | null
  }
  syncData: {
    lastSync: string
    version: string
  }
}
400 DesktopBadRequestEncoded application/json
DesktopBadRequestEncoded
401 DesktopUnauthorizedEncoded | UnauthorizedEncoded application/json
DesktopUnauthorizedEncoded | UnauthorizedEncoded
500 DesktopInternalEncoded application/json
DesktopInternalEncoded
SDK example
misc.desktopSignin
import { CadCam } from "@cadcamfun/api/sdk"

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

// MiscDesktopSigninInput
const result = await client.misc.desktopSignin({
  email: "",
  password: "",
  deviceId: "",
  platform: ""
})
curl
POST /api/desktop/auth/signin
curl --request POST "${CADCAMFUN_URL}/api/desktop/auth/signin" \
  --header "Authorization: Bearer ${CADCAMFUN_TOKEN}" \
  --header "Content-Type: application/json" \
  --data-binary @request.json
Try it

/api/desktop/projects

get /api/desktop/projects # misc.desktopProjects

Requires Authorization: Bearer <token>.

Responses
200 object application/json
{
  success: true
  data: Array<{
    id: string
    name: string
    description: string | null
    owner_id: string
    organization_id: string | null
    is_public: boolean
    created_at: string
    updated_at: string
  }>
  message: string
}
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
500 DesktopInternalEncoded application/json
DesktopInternalEncoded
Example response captured · 200
GET /api/desktop/projects
{
  "success": true,
  "data": [],
  "message": "Retrieved 0 projects"
}
SDK example
misc.desktopProjects
import { CadCam } from "@cadcamfun/api/sdk"

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

// no input
const result = await client.misc.desktopProjects()
curl
GET /api/desktop/projects
curl --request GET "${CADCAMFUN_URL}/api/desktop/projects" \
  --header "Authorization: Bearer ${CADCAMFUN_TOKEN}"
Try it
post /api/desktop/projects # misc.desktopCreateProject

Requires Authorization: Bearer <token>.

Request body · required · application/json
{
  name?: unknown | null
  description?: string | null
  organization_id?: string | null
  is_public?: boolean | null
}
Responses
201 object application/json
{
  success: true
  data: {
    id: string
    name: string
    description: string | null
    owner_id: string
    organization_id: string | null
    is_public: boolean
    created_at: string
    updated_at: string
  }
  message: string
}
400 DesktopBadRequestEncoded application/json
DesktopBadRequestEncoded
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
409 DesktopConflictEncoded application/json
DesktopConflictEncoded
500 DesktopInternalEncoded application/json
DesktopInternalEncoded
SDK example
misc.desktopCreateProject
import { CadCam } from "@cadcamfun/api/sdk"

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

// MiscDesktopCreateProjectInput
const result = await client.misc.desktopCreateProject({
  name: null,
  description: "",
  organization_id: "",
  is_public: false
})
curl
POST /api/desktop/projects
curl --request POST "${CADCAMFUN_URL}/api/desktop/projects" \
  --header "Authorization: Bearer ${CADCAMFUN_TOKEN}" \
  --header "Content-Type: application/json" \
  --data-binary @request.json
Try it

/api/desktop/user

get /api/desktop/user/by-email # misc.desktopUserByEmail

Requires Authorization: Bearer <token>.

Parameters
NameInTypeRequired
email query string | null optional
Responses
200 object application/json
{
  success: true
  data: {
    id: string
    name: string | null
    email: string | null
    image: string | null
    created_at: string
    updated_at: string
  }
  message: string
}
400 DesktopBadRequestEncoded application/json
DesktopBadRequestEncoded
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
404 DesktopNotFoundEncoded application/json
DesktopNotFoundEncoded
500 DesktopInternalEncoded application/json
DesktopInternalEncoded
Example response captured · 400
GET /api/desktop/user/by-email
{
  "_tag": "DesktopBadRequest",
  "success": false,
  "error": "Email parameter is required"
}
SDK example
misc.desktopUserByEmail
import { CadCam } from "@cadcamfun/api/sdk"

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

// MiscDesktopUserByEmailInput
const result = await client.misc.desktopUserByEmail({})
curl
GET /api/desktop/user/by-email
curl --request GET "${CADCAMFUN_URL}/api/desktop/user/by-email" \
  --header "Authorization: Bearer ${CADCAMFUN_TOKEN}"
Try it

/api/projects/tracked

get /api/projects/tracked/{id} # misc.trackedGet

Requires Authorization: Bearer <token>.

Parameters
NameInTypeRequired
id path string required
Responses
200 object application/json
{
  id: string
  name: string
  description: string | null
  createdAt: string
  updatedAt: string
  ownerId: string
  organizationId: string | null
  isPublic: boolean
  owner: {
    id: string
    name: string | null
    email: string | null
  }
  organization: {
    id: string
    name: string
  } | null
  _count: {
    drawings: number | "Infinity" | "-Infinity" | "NaN"
    components: number | "Infinity" | "-Infinity" | "NaN"
  }
}
400 BadRequestEncoded application/json
BadRequestEncoded
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
404 NotFoundEncoded application/json
NotFoundEncoded
500 InternalErrorEncoded application/json
InternalErrorEncoded
SDK example
misc.trackedGet
import { CadCam } from "@cadcamfun/api/sdk"

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

// MiscTrackedGetInput
const result = await client.misc.trackedGet({
  id: "<id>"
})
curl
GET /api/projects/tracked/{id}
curl --request GET "${CADCAMFUN_URL}/api/projects/tracked/<id>" \
  --header "Authorization: Bearer ${CADCAMFUN_TOKEN}"
Try it
put /api/projects/tracked/{id} # misc.trackedUpdate

Requires Authorization: Bearer <token>.

Parameters
NameInTypeRequired
id path string required
Request body · required · application/json
{
  name?: string | null
  description?: string | null
  organizationId?: string | null
}
Responses
200 object application/json
{
  id: string
  name: string
  description: string | null
  createdAt: string
  updatedAt: string
  ownerId: string
  organizationId: string | null
  isPublic: boolean
  owner: {
    id: string
    name: string | null
    email: string | null
  }
  organization: {
    id: string
    name: string
  } | null
  _count: {
    drawings: number | "Infinity" | "-Infinity" | "NaN"
    components: number | "Infinity" | "-Infinity" | "NaN"
  }
}
400 BadRequestEncoded application/json
BadRequestEncoded
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
403 ForbiddenEncoded application/json
ForbiddenEncoded
404 NotFoundEncoded application/json
NotFoundEncoded
500 InternalErrorEncoded application/json
InternalErrorEncoded
SDK example
misc.trackedUpdate
import { CadCam } from "@cadcamfun/api/sdk"

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

// MiscTrackedUpdateInput
const result = await client.misc.trackedUpdate({
  id: "<id>",
  name: "",
  description: "",
  organizationId: ""
})
curl
PUT /api/projects/tracked/{id}
curl --request PUT "${CADCAMFUN_URL}/api/projects/tracked/<id>" \
  --header "Authorization: Bearer ${CADCAMFUN_TOKEN}" \
  --header "Content-Type: application/json" \
  --data-binary @request.json
Try it
delete /api/projects/tracked/{id} # misc.trackedRemove

Requires Authorization: Bearer <token>.

Parameters
NameInTypeRequired
id path string required
Responses
200 object application/json
{
  message: string
}
400 BadRequestEncoded application/json
BadRequestEncoded
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
403 ForbiddenEncoded application/json
ForbiddenEncoded
404 NotFoundEncoded application/json
NotFoundEncoded
500 InternalErrorEncoded application/json
InternalErrorEncoded
SDK example
misc.trackedRemove
import { CadCam } from "@cadcamfun/api/sdk"

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

// MiscTrackedRemoveInput
const result = await client.misc.trackedRemove({
  id: "<id>"
})
curl
DELETE /api/projects/tracked/{id}
curl --request DELETE "${CADCAMFUN_URL}/api/projects/tracked/<id>" \
  --header "Authorization: Bearer ${CADCAMFUN_TOKEN}"
Try it

Schemas

Named schemas reachable from this group's parameters, bodies and responses. A ? marks an optional field; | null marks a field that may be present with a null value.

BadRequestEncoded
{
  _tag: "BadRequest"
  message: string
}
DesktopBadRequestEncoded
{
  _tag: "DesktopBadRequest"
  success: false
  error: string
}
DesktopConflictEncoded
{
  _tag: "DesktopConflict"
  success: false
  error: string
}
DesktopInternalEncoded
{
  _tag: "DesktopInternal"
  success: false
  error: string
}
DesktopNotFoundEncoded
{
  _tag: "DesktopNotFound"
  success: false
  error: string
}
DesktopUnauthorizedEncoded
{
  _tag: "DesktopUnauthorized"
  success: false
  error: string
}
ForbiddenEncoded
{
  _tag: "Forbidden"
  message: string
}
InternalErrorEncoded
{
  _tag: "InternalError"
  message: string
}
NotFoundEncoded
{
  _tag: "NotFound"
  message: string
}
NotifyBadRequestEncoded
{
  _tag: "NotifyBadRequest"
  success: false
  error: string
}
NotifyInternalEncoded
{
  _tag: "NotifyInternal"
  success: false
  error: string
}
UnauthorizedEncoded
{
  _tag: "Unauthorized"
  message: string
}

Calling this group

Operation ids have the form misc.<name>. The generated Promise SDK (@cadcamfun/api/sdk) exposes most of them as client.<namespace>.<method>(input), where input is one flat object of path parameters and body fields; each card's SDK example shows the exact accessor and input type. Multipart uploads, binary or JavaScript responses and raw webhooks are not generated; those cards show fetch instead.

Errors from the Promise SDK
import { CadCam, ClientError } from "@cadcamfun/api/sdk"

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

try {
  await client.projects.list()
} catch (error) {
  if (error instanceof ClientError) {
    // Transport | UnexpectedStatus | UnsupportedContentType | MalformedResponse | SseEventTooLarge
  } else {
    // a declared error body: switch on error._tag
  }
}

Troubleshooting

SymptomLikely causeFix
401 on every callToken from a previous launch, or missing Bearer prefixSend Authorization: Bearer <token> with the token the sidecar was started with.
400 before anything happensBody or parameter does not match the schemaCompare the payload with the request schema on the card.
403 or 404 on a record you can see elsewhereThe acting account differsSend the right x-session-token, or use the local profile that owns the record.
409Conflicting state, such as a duplicate name or a stale branch headRe-read the resource and retry with current data.
Try it says "blocked by CORS"The docs are served from a non-loopback originRun the docs locally or copy the request as curl.
Connection refusedThe sidecar restarted on a new portRead the port from the new ready line.