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/meKeep 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 aremultipart/form-data. - Errors share one shape:
{ code, message, fieldErrors?, requestId }— quoterequestIdwhen contacting support. - Rate limits are per token/user (e.g. 60 reads/min, stricter for writes); expect
429 RATE_LIMITEDand back off. - Clinical files never have public URLs — always stream them through
/api/assets/…with auth.
Endpoints
Identity
| GET | /api/me | The authenticated account, profile and verification status. |
| GET | /api/specialties | Active specialty taxonomy (localized names). |
| GET | /api/notifications | In-app notifications; PATCH marks them read. |
Cases
| GET | /api/cases | Permission-aware case list. Query: q, specialty, status, kind, unanswered=1, filter=mine, sort, page, pageSize. |
| POST | /api/cases | Create 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}/publish | Publish. Body: attestPatientConsent: true, legalBasisType. |
| POST | /api/cases/{id}/status | Lifecycle: OPEN | SOLVED | ARCHIVED (+ solutionSummary). |
| DELETE | /api/cases/{id} | Soft-delete an own case. |
| POST | /api/cases/{id}/participants | Invite a verified colleague. Body: handle, role. |
Files
| POST | /api/cases/{id}/assets | Upload into a draft (multipart: file, role). Validated server-side. |
| GET | /api/assets/{id}/raw | Access-checked file stream (?download=1 for attachment). |
| GET | /api/assets/{id}/thumb | Photo 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}/chat | Messages (optionally ?after=ISO-date). |
| POST | /api/cases/{id}/chat | Post a message. Body: body, replyToId? |
| GET | /api/cases/{id}/contributions | Published expert opinions (+ own drafts). |
| POST | /api/cases/{id}/contributions | Create an opinion. Body: title, body, publish? |
| PATCH | /api/contributions/{id} | Edit, or action: publish | withdraw. |
| POST | /api/contributions/{id}/helpful-vote | Vote helpful (DELETE removes the vote). |
| PUT | /api/cases/{id}/accepted-contribution | Owner marks the most helpful opinion (contributionId or null). |
| GET | /api/cases/{id}/annotations | 3D annotations with world coordinates. |
| POST | /api/cases/{id}/annotations | Create POINT/MEASURE/… annotation. Body: type, label, color, data.points[]. |
Account
| GET | /api/settings/export | Full personal data export (JSON). |
| GET | /api/settings/tokens | List active API tokens; POST creates one; DELETE /{id} revokes. |
| POST | /api/reports | Report content. Body: targetType, targetId, reason, details? |
| GET | /api/health | Liveness 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"}'