API reference

Everything the web app can do is available over the same JSON API — authenticate with a personal access token and automate away.

Authentication

Create a token under Settings → API access and send it as a Bearer header. Tokens act with your account's permissions — verification gates and case visibility apply to API calls exactly as in the browser.

curl -H "Authorization: Bearer smk_XXXXXXXXXXXX" \
  https://cases.smatch.cloud/api/me

Keep tokens secret, rotate them when a machine is decommissioned and revoke unused ones — every token action is audit-logged.

Conventions

  • Base URL: https://cases.smatch.cloud — HTTPS only.
  • Requests and responses are JSON (content-type: application/json), uploads are multipart/form-data.
  • Errors share one shape: { code, message, fieldErrors?, requestId } — quote requestId when contacting support.
  • Rate limits are per token/user (e.g. 60 reads/min, stricter for writes); expect 429 RATE_LIMITED and back off.
  • Clinical files never have public URLs — always stream them through /api/assets/… with auth.

Endpoints

Identity

GET/api/meThe authenticated account, profile and verification status.
GET/api/specialtiesActive specialty taxonomy (localized names).
GET/api/notificationsIn-app notifications; PATCH marks them read.

Cases

GET/api/casesPermission-aware case list. Query: q, specialty, status, kind, unanswered=1, filter=mine, sort, page, pageSize.
POST/api/casesCreate a draft. Body: title, summary, description, clinicalQuestion, visibility, specialtyIds[].
GET/api/cases/{id}Full case detail (id or slug) with files and attestation.
PATCH/api/cases/{id}Edit a draft (visibility/specialties freeze after publishing).
POST/api/cases/{id}/publishPublish. Body: attestPatientConsent: true, legalBasisType.
POST/api/cases/{id}/statusLifecycle: OPEN | SOLVED | ARCHIVED (+ solutionSummary).
DELETE/api/cases/{id}Soft-delete an own case.
POST/api/cases/{id}/participantsInvite a verified colleague. Body: handle, role.

Files

POST/api/cases/{id}/assetsUpload into a draft (multipart: file, role). Validated server-side.
GET/api/assets/{id}/rawAccess-checked file stream (?download=1 for attachment).
GET/api/assets/{id}/thumbPhoto thumbnail (WebP).
PATCH/api/assets/{id}Save layer transform/opacity/color/role (owner or editor).
DELETE/api/assets/{id}Remove a file from a draft.

Collaboration

GET/api/cases/{id}/chatMessages (optionally ?after=ISO-date).
POST/api/cases/{id}/chatPost a message. Body: body, replyToId?
GET/api/cases/{id}/contributionsPublished expert opinions (+ own drafts).
POST/api/cases/{id}/contributionsCreate an opinion. Body: title, body, publish?
PATCH/api/contributions/{id}Edit, or action: publish | withdraw.
POST/api/contributions/{id}/helpful-voteVote helpful (DELETE removes the vote).
PUT/api/cases/{id}/accepted-contributionOwner marks the most helpful opinion (contributionId or null).
GET/api/cases/{id}/annotations3D annotations with world coordinates.
POST/api/cases/{id}/annotationsCreate POINT/MEASURE/… annotation. Body: type, label, color, data.points[].

Account

GET/api/settings/exportFull personal data export (JSON).
GET/api/settings/tokensList active API tokens; POST creates one; DELETE /{id} revokes.
POST/api/reportsReport content. Body: targetType, targetId, reason, details?
GET/api/healthLiveness probe (no auth).

Worked example — post a case end to end

TOKEN="smk_XXXXXXXXXXXX"
BASE="https://cases.smatch.cloud"

# 1. Who am I? (verification must be VERIFIED to create cases)
curl -s -H "Authorization: Bearer $TOKEN" $BASE/api/me

# 2. Pick a specialty id
curl -s -H "Authorization: Bearer $TOKEN" $BASE/api/specialties

# 3. Create a draft
CASE=$(curl -s -X POST $BASE/api/cases \
  -H "Authorization: Bearer $TOKEN" -H "content-type: application/json" \
  -d '{"title":"Full-arch rehab — screw axis question",
       "summary":"Edentulous maxilla, six implants, distal divergence.",
       "description":"Longer anonymised description of the situation …",
       "clinicalQuestion":"ASC monolithic bridge or bar-retained?",
       "visibility":"SPECIALISTS_ONLY",
       "specialtyIds":["<specialty-id>"]}')
ID=$(echo $CASE | jq -r .id)

# 4. Upload a scan into the draft
curl -s -X POST $BASE/api/cases/$ID/assets \
  -H "Authorization: Bearer $TOKEN" \
  -F file=@upper-arch.stl -F role=UPPER_SCAN

# 5. Attest & publish
curl -s -X POST $BASE/api/cases/$ID/publish \
  -H "Authorization: Bearer $TOKEN" -H "content-type: application/json" \
  -d '{"attestPatientConsent":true,"legalBasisType":"ANONYMIZED_DATA"}'
API reference · Smatch Cases