Documentation
Users
Profiles, account resources, API keys, token records, passwords, and account removal.
Send these requests to your own running sidecar. Values stay in this browser.
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
18 endpoints in the user 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/user/profile | user.profile |
| put | /api/user/profile | user.updateProfile |
| get | /api/user/stats | user.stats |
| get | /api/user/components | user.components |
| get | /api/user/projects | user.projects |
| get | /api/user/toolpaths | user.toolpaths |
| get | /api/user/organizations | user.organizations |
| get | /api/user/api-keys | user.apiKeys |
| post | /api/user/api-keys | user.createApiKey |
| delete | /api/user/api-keys | user.revokeApiKey |
| delete | /api/user/delete-account | user.deleteAccount |
| put | /api/user/password | user.password |
| get | /api/user/tokens | user.tokens |
| post | /api/user/tokens | user.createToken |
| get | /api/user/verify-change | user.verifyChange |
| get | /api/user/git-profile | user.gitProfile |
| put | /api/user/git-profile | user.updateGitProfile |
| get | /api/user/{id} | user.byId |
/api/user/profile
user.profile Requires Authorization: Bearer <token>.
200 object application/json
{ id: string name: string | null email: string | null image: string | null bio: string | null location: string | null website: string | null company: string | null title: string | null publicProfile: boolean showEmail: boolean createdAt: string _count: { projects: number | "Infinity" | "-Infinity" | "NaN" } }
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
404 NotFoundEncoded application/json
NotFoundEncoded
500 InternalErrorEncoded application/json
InternalErrorEncoded
Example response captured · 200
{
"id": "c942817d-0162-4291-84ff-77321d387acc",
"name": "Local user",
"email": "local@cadcamfun.local",
"image": null,
"bio": null,
"location": null,
"website": null,
"company": null,
"title": null,
"publicProfile": true,
"showEmail": false,
"createdAt": "2026-10-15T04:52:06.538Z",
"_count": {
"projects": 0
}
} SDK example
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.user.profile() curl
curl --request GET "${CADCAMFUN_URL}/api/user/profile" \
--header "Authorization: Bearer ${CADCAMFUN_TOKEN}" Try it
user.updateProfile Requires Authorization: Bearer <token>.
{ name?: string | null bio?: string | null location?: string | null website?: string | null company?: string | null title?: string | null publicProfile?: string | null showEmail?: string | null profileImage?: string[] | null }
200 object application/json
{ message: string user: { id: string name: string | null email: string | null image: string | null bio: string | null location: string | null website: string | null company: string | null title: string | null publicProfile: boolean showEmail: boolean updatedAt: string } name: string | null email: string | null image: string | null }
400 BadRequestEncoded application/json
BadRequestEncoded
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
500 InternalErrorEncoded application/json
InternalErrorEncoded
fetch example
// Not generated in the Promise SDK (multipart, binary or raw body): call it with fetch.
const response = await fetch(`${process.env.CADCAMFUN_URL}/api/user/profile`, {
method: "PUT",
headers: { authorization: `Bearer ${process.env.CADCAMFUN_TOKEN}` },
}) curl
curl --request PUT "${CADCAMFUN_URL}/api/user/profile" \
--header "Authorization: Bearer ${CADCAMFUN_TOKEN}" \
--header "Content-Type: multipart/form-data" \
--data-binary @request-body Try it
This operation takes multipart/form-data; use the curl or fetch example.
/api/user/stats
user.stats Requires Authorization: Bearer <token>.
200 object application/json
{ projectsCount: number | "Infinity" | "-Infinity" | "NaN" drawingsCount: number | "Infinity" | "-Infinity" | "NaN" toolpathsCount: number | "Infinity" | "-Infinity" | "NaN" componentsCount: number | "Infinity" | "-Infinity" | "NaN" totalDesigns: number | "Infinity" | "-Infinity" | "NaN" memberSince: string }
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
500 KeyedInternalEncoded application/json
KeyedInternalEncoded
Example response captured · 200
{
"projectsCount": 0,
"drawingsCount": 0,
"toolpathsCount": 0,
"componentsCount": 0,
"totalDesigns": 0,
"memberSince": "2026-10-15T04:52:06.538Z"
} SDK example
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.user.stats() curl
curl --request GET "${CADCAMFUN_URL}/api/user/stats" \
--header "Authorization: Bearer ${CADCAMFUN_TOKEN}" Try it
/api/user/components
user.components Requires Authorization: Bearer <token>.
200 Array<object> application/json
Array<{ id: string name: string description: string | null createdAt: string updatedAt: string thumbnail: string | null projectId: string | null }>
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
500 InternalErrorEncoded application/json
InternalErrorEncoded
Example response captured · 200
[] SDK example
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.user.components() curl
curl --request GET "${CADCAMFUN_URL}/api/user/components" \
--header "Authorization: Bearer ${CADCAMFUN_TOKEN}" Try it
/api/user/projects
user.projects Requires Authorization: Bearer <token>.
200 Array<object> application/json
Array<{ id: string name: string description: string | null createdAt: string updatedAt: string }>
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
500 InternalErrorEncoded application/json
InternalErrorEncoded
Example response captured · 200
[] SDK example
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.user.projects() curl
curl --request GET "${CADCAMFUN_URL}/api/user/projects" \
--header "Authorization: Bearer ${CADCAMFUN_TOKEN}" Try it
/api/user/toolpaths
user.toolpaths Requires Authorization: Bearer <token>.
200 Array<object> application/json
Array<{ id: string name: string description: string | null createdAt: string updatedAt: string thumbnail: string | null projectId: string | null }>
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
500 InternalErrorEncoded application/json
InternalErrorEncoded
Example response captured · 200
[] SDK example
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.user.toolpaths() curl
curl --request GET "${CADCAMFUN_URL}/api/user/toolpaths" \
--header "Authorization: Bearer ${CADCAMFUN_TOKEN}" Try it
/api/user/organizations
user.organizations Requires Authorization: Bearer <token>.
200 Array<object> application/json
Array<{ id: string name: string description: string | null createdAt: string updatedAt: string role: string userCount: number | "Infinity" | "-Infinity" | "NaN" projectCount: number | "Infinity" | "-Infinity" | "NaN" }>
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
500 InternalErrorEncoded application/json
InternalErrorEncoded
Example response captured · 200
[] SDK example
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.user.organizations() curl
curl --request GET "${CADCAMFUN_URL}/api/user/organizations" \
--header "Authorization: Bearer ${CADCAMFUN_TOKEN}" Try it
/api/user/api-keys
user.apiKeys Requires Authorization: Bearer <token>.
200 Array<object> application/json
Array<{ id: string name: string createdAt: string lastUsed: string | null expiresAt: string | null }>
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
500 InternalErrorEncoded application/json
InternalErrorEncoded
Example response captured · 200
[] SDK example
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.user.apiKeys() curl
curl --request GET "${CADCAMFUN_URL}/api/user/api-keys" \
--header "Authorization: Bearer ${CADCAMFUN_TOKEN}" Try it
user.createApiKey Requires Authorization: Bearer <token>.
{ name?: unknown | null }
201 object application/json
{ message: string apiKey: string name: string }
400 BadRequestEncoded application/json
BadRequestEncoded
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
500 InternalErrorEncoded application/json
InternalErrorEncoded
SDK example
import { CadCam } from "@cadcamfun/api/sdk"
const client = CadCam.make({
baseUrl: process.env.CADCAMFUN_URL!,
headers: { authorization: `Bearer ${process.env.CADCAMFUN_TOKEN}` },
})
// UserCreateApiKeyInput
const result = await client.user.createApiKey({
name: null
}) curl
curl --request POST "${CADCAMFUN_URL}/api/user/api-keys" \
--header "Authorization: Bearer ${CADCAMFUN_TOKEN}" \
--header "Content-Type: application/json" \
--data-binary @request.json Try it
user.revokeApiKey Requires Authorization: Bearer <token>.
| Name | In | Type | Required |
|---|---|---|---|
| keyId | query | string | null | optional |
200 object application/json
{ message: string }
400 BadRequestEncoded application/json
BadRequestEncoded
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
404 NotFoundEncoded application/json
NotFoundEncoded
500 InternalErrorEncoded application/json
InternalErrorEncoded
SDK example
import { CadCam } from "@cadcamfun/api/sdk"
const client = CadCam.make({
baseUrl: process.env.CADCAMFUN_URL!,
headers: { authorization: `Bearer ${process.env.CADCAMFUN_TOKEN}` },
})
// UserRevokeApiKeyInput
const result = await client.user.revokeApiKey({}) curl
curl --request DELETE "${CADCAMFUN_URL}/api/user/api-keys" \
--header "Authorization: Bearer ${CADCAMFUN_TOKEN}" Try it
/api/user/delete-account
user.deleteAccount Requires Authorization: Bearer <token>.
200 object application/json
{ message: string }
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
404 NotFoundEncoded application/json
NotFoundEncoded
500 InternalErrorEncoded application/json
InternalErrorEncoded
SDK example
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.user.deleteAccount() curl
curl --request DELETE "${CADCAMFUN_URL}/api/user/delete-account" \
--header "Authorization: Bearer ${CADCAMFUN_TOKEN}" Try it
/api/user/password
user.password Requires Authorization: Bearer <token>.
{ currentPassword?: string | null newPassword?: string | null }
200 object application/json
{ message: string }
400 BadRequestEncoded application/json
BadRequestEncoded
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
404 NotFoundEncoded application/json
NotFoundEncoded
500 InternalErrorEncoded application/json
InternalErrorEncoded
SDK example
import { CadCam } from "@cadcamfun/api/sdk"
const client = CadCam.make({
baseUrl: process.env.CADCAMFUN_URL!,
headers: { authorization: `Bearer ${process.env.CADCAMFUN_TOKEN}` },
})
// UserPasswordInput
const result = await client.user.password({
currentPassword: "",
newPassword: ""
}) curl
curl --request PUT "${CADCAMFUN_URL}/api/user/password" \
--header "Authorization: Bearer ${CADCAMFUN_TOKEN}" \
--header "Content-Type: application/json" \
--data-binary @request.json Try it
/api/user/tokens
user.tokens Requires Authorization: Bearer <token>.
200 object application/json
{ tokens: Array<{ id: string name: string prefix: string permissions: string[] createdAt: string lastUsed?: string | null expiresAt?: string | null isActive: boolean }> }
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
500 KeyedInternalEncoded application/json
KeyedInternalEncoded
Example response captured · 200
{
"tokens": [
{
"id": "token-1",
"name": "Development Token",
"prefix": "cad_dev_abc123",
"permissions": [
"read:projects",
"write:drawings",
"read:toolpaths"
],
"createdAt": "2026-10-08T04:52:23.364Z",
"lastUsed": "2026-10-15T03:52:23.364Z",
"isActive": true
},
{
"id": "token-2",
"name": "Mobile App Token",
"prefix": "cad_mobile_xyz789",
"permissions": [
"read:projects",
"write:toolpaths"
],
"createdAt": "2026-10-01T04:52:23.364Z",
"lastUsed": "2026-10-15T01:52:23.364Z",
"expiresAt": "2026-11-14T04:52:23.364Z",
"isActive": true
},
{
"id": "token-3",
"name": "Analytics Integration",
"prefix": "cad_analytics_def456",
"permissions": [
"read:analytics",
"read:usage"
],
"createdAt": "2026-09-24T04:52:23.364Z",
"expiresAt": "2026-10-14T04:52:23.364Z",
"isActive": false
}
]
} SDK example
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.user.tokens() curl
curl --request GET "${CADCAMFUN_URL}/api/user/tokens" \
--header "Authorization: Bearer ${CADCAMFUN_TOKEN}" Try it
user.createToken Requires Authorization: Bearer <token>.
{ name?: string | null permissions?: unknown | null expiresIn?: number | "Infinity" | "-Infinity" | "NaN" | null }
201 object application/json
{ token: { id: string name: string prefix: string permissions: string[] createdAt: string lastUsed?: string | null expiresAt?: string | null isActive: boolean } fullToken: string }
400 TokenBadRequestEncoded application/json
TokenBadRequestEncoded
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
500 KeyedInternalEncoded application/json
KeyedInternalEncoded
SDK example
import { CadCam } from "@cadcamfun/api/sdk"
const client = CadCam.make({
baseUrl: process.env.CADCAMFUN_URL!,
headers: { authorization: `Bearer ${process.env.CADCAMFUN_TOKEN}` },
})
// UserCreateTokenInput
const result = await client.user.createToken({
name: "",
permissions: null,
expiresIn: 0
}) curl
curl --request POST "${CADCAMFUN_URL}/api/user/tokens" \
--header "Authorization: Bearer ${CADCAMFUN_TOKEN}" \
--header "Content-Type: application/json" \
--data-binary @request.json Try it
/api/user/verify-change
user.verifyChange Requires Authorization: Bearer <token>.
| Name | In | Type | Required |
|---|---|---|---|
| token | query | string | null | optional |
| type | query | string | null | optional |
| password | query | string | null | optional |
200 object application/json
{ message: string }
400 BadRequestEncoded application/json
BadRequestEncoded
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
404 NotFoundEncoded application/json
NotFoundEncoded
500 InternalErrorEncoded application/json
InternalErrorEncoded
Example response captured · 400
{
"_tag": "BadRequest",
"message": "Token and verification type are required"
} SDK example
import { CadCam } from "@cadcamfun/api/sdk"
const client = CadCam.make({
baseUrl: process.env.CADCAMFUN_URL!,
headers: { authorization: `Bearer ${process.env.CADCAMFUN_TOKEN}` },
})
// UserVerifyChangeInput
const result = await client.user.verifyChange({}) curl
curl --request GET "${CADCAMFUN_URL}/api/user/verify-change" \
--header "Authorization: Bearer ${CADCAMFUN_TOKEN}" Try it
/api/user/git-profile
user.gitProfile Requires Authorization: Bearer <token>.
200 object application/json
{ name: string email: string }
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
404 NotFoundEncoded application/json
NotFoundEncoded
500 InternalErrorEncoded application/json
InternalErrorEncoded
fetch example
// Not generated in the Promise SDK (multipart, binary or raw body): call it with fetch.
const response = await fetch(`${process.env.CADCAMFUN_URL}/api/user/git-profile`, {
method: "GET",
headers: { authorization: `Bearer ${process.env.CADCAMFUN_TOKEN}` },
}) curl
curl --request GET "${CADCAMFUN_URL}/api/user/git-profile" \
--header "Authorization: Bearer ${CADCAMFUN_TOKEN}" Try it
user.updateGitProfile Requires Authorization: Bearer <token>.
{ name: string email: string }
200 object application/json
{ name: string email: string }
400 BadRequestEncoded application/json
BadRequestEncoded
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
404 NotFoundEncoded application/json
NotFoundEncoded
500 InternalErrorEncoded application/json
InternalErrorEncoded
fetch example
// Not generated in the Promise SDK (multipart, binary or raw body): call it with fetch.
const response = await fetch(`${process.env.CADCAMFUN_URL}/api/user/git-profile`, {
method: "PUT",
headers: { authorization: `Bearer ${process.env.CADCAMFUN_TOKEN}` },
}) curl
curl --request PUT "${CADCAMFUN_URL}/api/user/git-profile" \
--header "Authorization: Bearer ${CADCAMFUN_TOKEN}" \
--header "Content-Type: application/json" \
--data-binary @request.json Try it
/api/user
user.byId Requires Authorization: Bearer <token>.
| Name | In | Type | Required |
|---|---|---|---|
| id | path | string | required |
200 object application/json
{ id: string name: string | null email: string | null image: string | null createdAt: string organizations: Array<{ id: string name: string role: string }> }
400 BadRequestEncoded application/json
BadRequestEncoded
401 UnauthorizedEncoded application/json
UnauthorizedEncoded
404 NotFoundEncoded application/json
NotFoundEncoded
500 InternalErrorEncoded application/json
InternalErrorEncoded
SDK example
import { CadCam } from "@cadcamfun/api/sdk"
const client = CadCam.make({
baseUrl: process.env.CADCAMFUN_URL!,
headers: { authorization: `Bearer ${process.env.CADCAMFUN_TOKEN}` },
})
// UserByIdInput
const result = await client.user.byId({
id: "<id>"
}) curl
curl --request GET "${CADCAMFUN_URL}/api/user/<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 }
InternalErrorEncoded{ _tag: "InternalError" message: string }
KeyedInternalEncoded{ _tag: "KeyedInternal" error: string }
NotFoundEncoded{ _tag: "NotFound" message: string }
TokenBadRequestEncoded{ _tag: "TokenBadRequest" error: string }
Calling this group
Operation ids have the form user.<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.
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
| Symptom | Likely cause | Fix |
|---|---|---|
| 401 on every call | Token from a previous launch, or missing Bearer prefix | Send Authorization: Bearer <token> with the token the sidecar was started with. |
| 400 before anything happens | Body or parameter does not match the schema | Compare the payload with the request schema on the card. |
| 403 or 404 on a record you can see elsewhere | The acting account differs | Send the right x-session-token, or use the local profile that owns the record. |
| 409 | Conflicting state, such as a duplicate name or a stale branch head | Re-read the resource and retry with current data. |
| Try it says "blocked by CORS" | The docs are served from a non-loopback origin | Run the docs locally or copy the request as curl. |
| Connection refused | The sidecar restarted on a new port | Read the port from the new ready line. |