Skip to content
CADCAMFUN
Docs

Documentation

Analytics

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

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 analytics 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.

get /api/analytics/system-metrics analytics.systemMetrics
get /api/analytics analytics.index
get /api/analytics/dashboard-data analytics.dashboardData
post /api/analytics/log-view analytics.logView
get /api/analytics/recent-activity analytics.recentActivity
get /api/analytics/user-history analytics.userHistory
get /api/analytics/user-metrics analytics.userMetrics
get /api/analytics/user-usage analytics.userUsage
delete /api/analytics/user-usage analytics.clearUserUsage
post /api/analytics/track analytics.track
Analytics 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/analytics/system-metrics

get /api/analytics/system-metrics # analytics.systemMetrics

Requires Authorization: Bearer <token>.

Responses
200 object application/json
{
  cpuUsage: number | "Infinity" | "-Infinity" | "NaN"
  memoryUsage: number | "Infinity" | "-Infinity" | "NaN"
  storageUsed: number | "Infinity" | "-Infinity" | "NaN"
  networkLatency: number | "Infinity" | "-Infinity" | "NaN"
  activeConnections: number | "Infinity" | "-Infinity" | "NaN"
  cacheHitRatio: number | "Infinity" | "-Infinity" | "NaN"
  errorRate: number | "Infinity" | "-Infinity" | "NaN"
  responseTime: number | "Infinity" | "-Infinity" | "NaN"
}
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
500 KeyedInternalEncoded application/json
KeyedInternalEncoded
Example response captured · 200
GET /api/analytics/system-metrics
{
  "cpuUsage": 6,
  "memoryUsage": 79,
  "storageUsed": 72,
  "networkLatency": 15,
  "activeConnections": 145,
  "cacheHitRatio": 98,
  "errorRate": 0.04,
  "responseTime": 52
}
SDK example
analytics.systemMetrics
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.analytics.systemMetrics()
curl
GET /api/analytics/system-metrics
curl --request GET "${CADCAMFUN_URL}/api/analytics/system-metrics" \
  --header "Authorization: Bearer ${CADCAMFUN_TOKEN}"
Try it

/api/analytics

get /api/analytics # analytics.index

Requires Authorization: Bearer <token>.

Parameters
NameInTypeRequired
startDate query string | null optional
endDate query string | null optional
itemType query string | string[] | null optional
action query string | string[] | null optional
groupBy query string | null optional
userFilter query string | string[] | null optional
Responses
200 object application/json
{
  success: true
  data: {
    countByType: Array<{
      itemType: string
      _count: number | "Infinity" | "-Infinity" | "NaN"
    }>
    countByAction: Array<{
      action: string
      _count: number | "Infinity" | "-Infinity" | "NaN"
    }>
  }
  isAdmin: boolean
  filters: unknown
}
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
500 AnalyticsFailureEncoded application/json
AnalyticsFailureEncoded
Example response captured · 200
GET /api/analytics
{
  "success": true,
  "data": {
    "countByType": [],
    "countByAction": []
  },
  "isAdmin": true,
  "filters": {
    "groupBy": "day"
  }
}
SDK example
analytics.index
import { CadCam } from "@cadcamfun/api/sdk"

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

// AnalyticsIndexInput
const result = await client.analytics.index({})
curl
GET /api/analytics
curl --request GET "${CADCAMFUN_URL}/api/analytics" \
  --header "Authorization: Bearer ${CADCAMFUN_TOKEN}"
Try it

/api/analytics/dashboard-data

get /api/analytics/dashboard-data # analytics.dashboardData

Requires Authorization: Bearer <token>.

Responses
200 object application/json
{
  components: {
    total: number | "Infinity" | "-Infinity" | "NaN"
    trend: number | "Infinity" | "-Infinity" | "NaN"
    recentActivity: number | "Infinity" | "-Infinity" | "NaN"
  }
  projects: {
    total: number | "Infinity" | "-Infinity" | "NaN"
    trend: number | "Infinity" | "-Infinity" | "NaN"
    activeProjects: number | "Infinity" | "-Infinity" | "NaN"
  }
  tools: {
    total: number | "Infinity" | "-Infinity" | "NaN"
    trend: number | "Infinity" | "-Infinity" | "NaN"
    mostUsed: string
  }
  materials: {
    total: number | "Infinity" | "-Infinity" | "NaN"
    trend: number | "Infinity" | "-Infinity" | "NaN"
    lowStock: number | "Infinity" | "-Infinity" | "NaN"
  }
}
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
500 KeyedInternalEncoded application/json
KeyedInternalEncoded
Example response captured · 200
GET /api/analytics/dashboard-data
{
  "components": {
    "total": 0,
    "trend": 0,
    "recentActivity": 0
  },
  "projects": {
    "total": 0,
    "trend": 0,
    "activeProjects": 0
  },
  "tools": {
    "total": 0,
    "trend": 0,
    "mostUsed": "No tools used yet"
  },
  "materials": {
    "total": 0,
    "trend": 0,
    "lowStock": 0
  }
}
SDK example
analytics.dashboardData
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.analytics.dashboardData()
curl
GET /api/analytics/dashboard-data
curl --request GET "${CADCAMFUN_URL}/api/analytics/dashboard-data" \
  --header "Authorization: Bearer ${CADCAMFUN_TOKEN}"
Try it

/api/analytics/log-view

post /api/analytics/log-view # analytics.logView

Requires Authorization: Bearer <token>.

Request body · required · application/json
{
  path?: string | null
  query?: unknown | null
}
Responses
200 object application/json
{
  success: true
}
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
500 InternalErrorEncoded application/json
InternalErrorEncoded
SDK example
analytics.logView
import { CadCam } from "@cadcamfun/api/sdk"

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

// AnalyticsLogViewInput
const result = await client.analytics.logView({
  path: "",
  query: null
})
curl
POST /api/analytics/log-view
curl --request POST "${CADCAMFUN_URL}/api/analytics/log-view" \
  --header "Authorization: Bearer ${CADCAMFUN_TOKEN}" \
  --header "Content-Type: application/json" \
  --data-binary @request.json
Try it

/api/analytics/recent-activity

get /api/analytics/recent-activity # analytics.recentActivity

Requires Authorization: Bearer <token>.

Parameters
NameInTypeRequired
limit query string | null optional
Responses
200 Array<object> application/json
Array<{
  id: string
  type: string
  action: string
  itemName: string
  timestamp: string
  userId: string
  userName: string
}>
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
500 KeyedInternalEncoded application/json
KeyedInternalEncoded
Example response captured · 200
GET /api/analytics/recent-activity
[]
SDK example
analytics.recentActivity
import { CadCam } from "@cadcamfun/api/sdk"

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

// AnalyticsRecentActivityInput
const result = await client.analytics.recentActivity({})
curl
GET /api/analytics/recent-activity
curl --request GET "${CADCAMFUN_URL}/api/analytics/recent-activity" \
  --header "Authorization: Bearer ${CADCAMFUN_TOKEN}"
Try it

/api/analytics/user-history

get /api/analytics/user-history # analytics.userHistory

Requires Authorization: Bearer <token>.

Parameters
NameInTypeRequired
limit query string | null optional
offset query string | null optional
itemType query string | string[] | null optional
action query string | string[] | null optional
startDate query string | null optional
endDate query string | null optional
Responses
200 object application/json
{
  logs: unknown[]
  total: number | "Infinity" | "-Infinity" | "NaN"
}
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
500 InternalErrorEncoded application/json
InternalErrorEncoded
Example response captured · 200
GET /api/analytics/user-history
{
  "logs": [],
  "total": 0
}
SDK example
analytics.userHistory
import { CadCam } from "@cadcamfun/api/sdk"

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

// AnalyticsUserHistoryInput
const result = await client.analytics.userHistory({})
curl
GET /api/analytics/user-history
curl --request GET "${CADCAMFUN_URL}/api/analytics/user-history" \
  --header "Authorization: Bearer ${CADCAMFUN_TOKEN}"
Try it

/api/analytics/user-metrics

get /api/analytics/user-metrics # analytics.userMetrics

Requires Authorization: Bearer <token>.

Parameters
NameInTypeRequired
startDate query string | null optional
endDate query string | null optional
groupBy query string | null optional
metric query string | null optional
Responses
200 object application/json
{
  summary: {
    totalAiRequests: number | "Infinity" | "-Infinity" | "NaN"
    totalCadDrawings: number | "Infinity" | "-Infinity" | "NaN"
    totalStorageUsage: number | "Infinity" | "-Infinity" | "NaN"
    totalProjects: number | "Infinity" | "-Infinity" | "NaN"
    totalComponents: number | "Infinity" | "-Infinity" | "NaN"
    totalToolpaths: number | "Infinity" | "-Infinity" | "NaN"
    totalActivityCount?: number | "Infinity" | "-Infinity" | "NaN" | null
  }
  chartData: Array<{
    [key: string]: string | number | "Infinity" | "-Infinity" | "NaN"
  }>
}
400 AnalyticsKeyedBadRequestEncoded application/json
AnalyticsKeyedBadRequestEncoded
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
500 KeyedInternalEncoded application/json
KeyedInternalEncoded
Example response captured · 200
GET /api/analytics/user-metrics
{
  "summary": {
    "totalAiRequests": 0,
    "totalCadDrawings": 0,
    "totalStorageUsage": 0,
    "totalProjects": 0,
    "totalComponents": 0,
    "totalToolpaths": 0,
    "totalActivityCount": 0
  },
  "chartData": [
    {
      "date": "2026-09-15",
      "activityCount": 0,
      "toolpathsGenerated": 0,
      "connections": 0,
      "programRuns": 0,
      "aiRequests": 0,
      "cadDrawings": 0,
      "storageUsage": 0,
      "projects": 0,
      "components": 0,
      "toolpaths": 0
    },
    {
      "date": "2026-09-16",
      "activityCount": 0,
      "toolpathsGenerated": 0,
      "connections": 0,
      "programRuns": 0,
      "aiRequests": 0,
      "cadDrawings": 0,
      "storageUsage": 0,
      "projects": 0,
      "components": 0,
      "toolpaths": 0
    },
    {
      "date": "2026-09-17",
      "activityCount": 0,
      "toolpathsGenerated": 0,
      "connections": 0,
      "programRuns": 0,
      "aiRequests": 0,
      "cadDrawings": 0,
      "storageUsage": 0,
      "projects": 0,
      "components": 0,
      "toolpaths": 0
    },
    {
      "date": "2026-09-18",
      "activityCount": 0,
      "toolpathsGenerated": 0,
      "connections": 0,
      "programRuns": 0,
      "aiRequests": 0,
      "cadDrawings": 0,
      "storageUsage": 0,
      "projects": 0,
      "components": 0,
      "toolpaths": 0
    },
    {
      "date": "2026-09-19",
      "activityCount": 0,
      "toolpathsGenerated": 0,
      "connections": 0,
      "programRuns": 0,
      "aiRequests": 0,
      "cadDrawings": 0,
      "storageUsage": 0,
      "projects": 0,
      "components": 0,
      "toolpaths": 0
    },
    {
      "date": "2026-09-20",
      "activityCount": 0,
      "toolpathsGenerated": 0,
      "connections": 0,
      "programRuns": 0,
      "aiRequests": 0,
      "cadDrawings": 0,
      "storageUsage": 0,
      "projects": 0,
      "components": 0,
      "toolpaths": 0
    },
    {
      "date": "2026-09-21",
      "activityCount": 0,
      "toolpathsGenerated": 0,
      "connections": 0,
      "programRuns": 0,
      "aiRequests": 0,
      "cadDrawings": 0,
      "storageUsage": 0,
      "projects": 0,
      "components": 0,
      "toolpaths": 0
    },
    {
      "date": "2026-09-22",
      "activityCount": 0,
      "toolpathsGenerated": 0,
      "connections": 0,
      "programRuns": 0,
      "aiRequests": 0,
      "cadDrawings": 0,
      "storageUsage": 0,
      "projects": 0,
      "components": 0,
      "toolpaths": 0
    },
    {
      "
…
SDK example
analytics.userMetrics
import { CadCam } from "@cadcamfun/api/sdk"

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

// AnalyticsUserMetricsInput
const result = await client.analytics.userMetrics({})
curl
GET /api/analytics/user-metrics
curl --request GET "${CADCAMFUN_URL}/api/analytics/user-metrics" \
  --header "Authorization: Bearer ${CADCAMFUN_TOKEN}"
Try it

/api/analytics/user-usage

get /api/analytics/user-usage # analytics.userUsage

Requires Authorization: Bearer <token>.

Parameters
NameInTypeRequired
userId query string | null optional
startDate query string | null optional
endDate query string | null optional
period query string | null optional
Responses
200 object application/json
{
  summary?: unknown | null
  breakdown?: unknown | null
  users?: unknown[] | null
  systemStats?: unknown | null
}
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
403 AnalyticsKeyedForbiddenEncoded application/json
AnalyticsKeyedForbiddenEncoded
500 KeyedInternalEncoded application/json
KeyedInternalEncoded
Example response captured · 200
GET /api/analytics/user-usage
{
  "users": [],
  "systemStats": {
    "totalUsers": 0,
    "totalTokens": 0,
    "totalCost": 0,
    "totalRequests": 0,
    "averageCostPerUser": 0,
    "topSpendingUsers": [],
    "modelDistribution": {}
  }
}
SDK example
analytics.userUsage
import { CadCam } from "@cadcamfun/api/sdk"

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

// AnalyticsUserUsageInput
const result = await client.analytics.userUsage({})
curl
GET /api/analytics/user-usage
curl --request GET "${CADCAMFUN_URL}/api/analytics/user-usage" \
  --header "Authorization: Bearer ${CADCAMFUN_TOKEN}"
Try it
delete /api/analytics/user-usage # analytics.clearUserUsage

Requires Authorization: Bearer <token>.

Responses
200 object application/json
{
  message: string
}
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
500 KeyedInternalEncoded application/json
KeyedInternalEncoded
SDK example
analytics.clearUserUsage
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.analytics.clearUserUsage()
curl
DELETE /api/analytics/user-usage
curl --request DELETE "${CADCAMFUN_URL}/api/analytics/user-usage" \
  --header "Authorization: Bearer ${CADCAMFUN_TOKEN}"
Try it

/api/analytics/track

post /api/analytics/track # analytics.track

Requires Authorization: Bearer <token>.

Request body · required · application/json
{
  itemId?: string | null
  itemType?: string | null
  action?: string | null
  details?: unknown | 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
analytics.track
import { CadCam } from "@cadcamfun/api/sdk"

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

// AnalyticsTrackInput
const result = await client.analytics.track({
  itemId: "",
  itemType: "",
  action: "",
  details: null
})
curl
POST /api/analytics/track
curl --request POST "${CADCAMFUN_URL}/api/analytics/track" \
  --header "Authorization: Bearer ${CADCAMFUN_TOKEN}" \
  --header "Content-Type: application/json" \
  --data-binary @request.json
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.

AnalyticsFailureEncoded
{
  _tag: "AnalyticsFailure"
  success: false
  message: string
}
AnalyticsKeyedBadRequestEncoded
{
  _tag: "AnalyticsKeyedBadRequest"
  error: string
}
AnalyticsKeyedForbiddenEncoded
{
  _tag: "AnalyticsKeyedForbidden"
  error: string
}
BadRequestEncoded
{
  _tag: "BadRequest"
  message: string
}
InternalErrorEncoded
{
  _tag: "InternalError"
  message: string
}
KeyedInternalEncoded
{
  _tag: "KeyedInternal"
  error: string
}
UnauthorizedEncoded
{
  _tag: "Unauthorized"
  message: string
}

Calling this group

Operation ids have the form analytics.<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.