Cadmus API

Cadmus collects intra-oral scan orders from IOS portals and exposes them through a single, normalised REST API. This guide walks you through authentication, retrieving orders, and downloading scan files.

Base URL

All endpoints are relative to the base URL for your environment. Use HTTPS in all environments.

Staging
https://api.staging.cadmuslabs.nl

Shared sandbox environment. Requires a valid user account.

Production
https://api.cadmuslabs.nl

Live environment. Requires a valid user account.

All examples below use https://api.cadmuslabs.nl as the base URL. Replace it with https://api.staging.cadmuslabs.nl when working against the staging environment.

Step 1 — Authenticate

Every API call requires a JSON Web Token (JWT). Obtain one by posting your credentials to /auth/login. The token is valid for 8 hours.

POST https://api.cadmuslabs.nl/auth/login
Request body
{
  "email": "you@example.com",
  "password": "your-password"
}
curl
curl -s -X POST https://api.cadmuslabs.nl/auth/login \
     -H "Content-Type: application/json" \
     -d '{"email":"you@example.com","password":"your-password"}'
Response (200 OK)
{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "expiresAt": "2026-03-09T18:30:00Z"
}

Copy the token value. You will pass it as Authorization: Bearer <token> on every subsequent request.

Step 2 — Retrieve orders

Orders are exposed through the /unified-cases resource. Every order is mapped to a single consistent schema — scan files, dentist, worktypes, and patient data always appear in the same place regardless of which IOS portal the order came from.

GET https://api.cadmuslabs.nl/unified-cases
curl
curl -s https://api.cadmuslabs.nl/unified-cases \
     -H "Authorization: Bearer <token>"
Response (200 OK) — trimmed for clarity
{
  "items": [
    {
      "guid": "16ad2e12-fb26-4931-ba16-321285d74550",
      "organizationGuid": "8f3d2c1a-9b4e-4f7d-b2e8-1a5c6d7e8f90",
      "status": "new",
      "acceptedData": {
        "uid": "16ad2e12-fb26-4931-ba16-321285d74550",
        "source": "DSCore",
        "externalId": "abc-123",
        "receivedDate": "2026-03-08T09:14:00Z",
        "deliveryDate": "2026-03-10",
        "sentTo": "Cadmus Lab",
        "customer": {
          "clinic": { "name": "SmileCo Dental", "city": "Amsterdam" },
          "dentist": { "fullName": "Dr. A. Smith" }
        },
        "patient": { "fullName": "J. Doe", "referenceNo": "P-001" },
        "remark": "",
        "scanFiles": [
          { "type": "preparationScan", "filename": "upper.stl", "jaw": "upper", "fileType": "stl", "fileLink": "gs://..." }
        ],
        "worktypes": [
          { "categoryId": "Fixed", "restorationTypeId": "Crown", "materialId": "Zirconia", "fdi": "16", "jaw": "Upper" }
        ],
        "administrative": { "priority": false, "remake": false, "contactRequired": false, "additionalInfo": false }
      }
    }
  ],
  "page": 1,
  "pageSize": 20,
  "total": 183
}

Supported query parameters: page, pageSize, from (YYYY-MM-DD), to (YYYY-MM-DD), status (new | accepted).

Step 3 — Download files

All files (scan files and the order form PDF) are stored in cloud object storage (Google Cloud Storage) — they are not served directly from the database. The fileLink fields in acceptedData are internal storage paths, not public URLs.

Request a pre-authenticated signed URL from the API. Signed URLs are valid for 15 minutes and can be used directly in a browser, a 3D viewer, or a download client — no extra headers needed.

Cloud scanFiles[] fields

  • filenameFile name, e.g. upper.stl
  • fileTypeFormat: stl, ply, preview
  • jawPosition: upper, lower, none
  • typeScan type: preparationScan, biteScan, prePreparationScan, abutmentScan, dentureScan
  • fileLinkInternal storage path — use the signed-URL endpoint to get a download link
GET https://api.cadmuslabs.nl/unified-cases/{guid}/files/{filename}?fileType=stl
curl
curl -s "https://api.cadmuslabs.nl/unified-cases/16ad2e12-fb26-4931-ba16-321285d74550/files/upper.stl?fileType=stl" \
     -H "Authorization: Bearer <token>"
Response (200 OK)
{
  "url": "https://storage.googleapis.com/cadmus_collector_bucket/...&X-Goog-Signature=...",
  "filename": "upper.stl",
  "fileType": "stl",
  "expiresAt": "2026-03-09T10:45:00Z"
}

The order form is a single PDF attached to the case (acceptedData.orderForm). Use the dedicated endpoint to get a signed URL for it — no fileType parameter needed.

GET https://api.cadmuslabs.nl/unified-cases/{guid}/order-form
curl
curl -s "https://api.cadmuslabs.nl/unified-cases/16ad2e12-fb26-4931-ba16-321285d74550/order-form" \
     -H "Authorization: Bearer <token>"
Response (200 OK)
{
  "url": "https://storage.googleapis.com/cadmus_collector_bucket/...&X-Goog-Signature=...",
  "filename": "DS Core_orderform.pdf",
  "expiresAt": "2026-03-09T10:45:00Z"
}

Miscellaneous files are additional non-scan attachments — photos, X-rays, shade or margin-line images, implant reports, and similar supporting files (acceptedData.miscellaneousFiles). Match by the filename at the end of the path, same as scan files.

GET https://api.cadmuslabs.nl/unified-cases/{guid}/miscellaneous-files/{filename}
curl
curl -s "https://api.cadmuslabs.nl/unified-cases/16ad2e12-fb26-4931-ba16-321285d74550/miscellaneous-files/Measurement%201.png" \
     -H "Authorization: Bearer <token>"
Response (200 OK)
{
  "url": "https://storage.googleapis.com/cadmus_collector_bucket/...&X-Goog-Signature=...",
  "filename": "Measurement 1.png",
  "expiresAt": "2026-03-09T10:45:00Z"
}

Pass the url directly to a PDF viewer or trigger a download. Request a fresh URL if the link has expired.

Step 4 — Look up portal information

Use these endpoints to resolve portals to human-readable names.

IOS portals

GET /portals/ios

All active IOS portal types. Returns id, name, className, url, axisMaping, quantizationBits.

Configured portals

GET /portals/configured

Configured portal connections for your organisation. Returns guid, organizationGuid, iosPortalId, displayName, username, region, lastFetch, portalName.

Reference — acceptedData fields

Each case has top-level fields guid (case identifier), organizationGuid, and status (new | accepted). The acceptedData object contains the normalised case fields below. Fields may be null or absent when not provided by the originating portal.

Identity & routing

  • guidCase identifier — used in all URLs (top-level)
  • organizationGuidOrganisation GUID (top-level)
  • acceptedData.organizationTypeDental | Orthodontics
  • acceptedData.sourceOriginating portal (e.g. DSCore, MyiTero)
  • acceptedData.externalIdCase ID in the source system
  • acceptedData.sentToDestination lab name

Dates

  • receivedDateDate & time received in Cadmus
  • deliveryDateRequested delivery date (or date+time)
  • statusnew | accepted

Clinic

  • customer.clinic.externalIdClinic ID in source system
  • customer.clinic.nameClinic name
  • customer.clinic.addressStreet address
  • customer.clinic.zipPostal code
  • customer.clinic.cityCity
  • customer.clinic.countryCountry
  • customer.clinic.fullAddressFull formatted address
  • customer.clinic.phoneNumberPhone
  • customer.clinic.mailAddressEmail

Dentist

  • customer.dentist.externalIdDentist ID in source system
  • customer.dentist.firstNameFirst name
  • customer.dentist.lastNameLast name
  • customer.dentist.fullNameFull name
  • customer.dentist.phoneNumberPhone
  • customer.dentist.mailAddressEmail

Patient

  • patient.externalIdPatient ID in source system
  • patient.genderGender — M or F
  • patient.firstNameFirst name
  • patient.lastNameLast name
  • patient.fullNameFull name
  • patient.referenceNoPatient reference number
  • patient.dateOfBirthDate of birth

Remark & Administrative

  • remarkFree-text clinical remark ("" if none)
  • administrative.priorityUrgent order flag
  • administrative.remakeRemake order flag
  • administrative.contactRequiredContact requested flag
  • administrative.additionalInfoAdditional info sent flag

Worktypes

Each item in worktypes[] describes a single clinical work item. The units[] array within a worktype lists individual tooth-level units that share the same field set (minus jaw, from, to).

  • categoryIdFixed | Removable | Appliance | Orthodontics
  • restorationTypeIdRestoration type (e.g. Crown, Bridge, Aligners)
  • restorationDetailIdRestoration detail (e.g. Full, Partial, Veneer)
  • materialIdMaterial (e.g. Zirconia, PMMA, Acrylic)
  • settingIdSetting (e.g. Monolithic, Layered)
  • fdiFDI tooth number(s)
  • shadeShade code
  • jawUpper | Lower | Both | None
  • fromFrom tooth — integer FDI number
  • toTo tooth — integer FDI number
  • tags[]Key/value tags (type, value)
  • units[]Individual units — same fields except jaw, from, to

Order form

  • orderForm.filenameFile name, always a PDF (e.g. DSCore_orderform.pdf)
  • orderForm.fileLinkInternal storage path — use GET /unified-cases/{guid}/order-form for a 15-min signed URL
  • orderForm.plainTextPlain-text extraction of the PDF (may be null)

Miscellaneous files

  • miscellaneousFiles[]Additional non-scan attachments — photos, X-rays, shade/margin-line images, implant reports, etc. Internal storage paths — use GET /unified-cases/{guid}/miscellaneous-files/{filename} for a 15-min signed URL. Omitted when the case has none.

Enum Reference

Valid string values for typed fields. Worktype fields marked Dental apply when categoryId is Fixed, Removable, or Appliance. Orthodontics applies when categoryId is Orthodontics.

Case & identity

  • organizationTypeDental  ·  Orthodontics
  • statusnew  ·  accepted
  • organizations[].typeGroup  ·  Dental  ·  Orthodontics  ·  CAM  ·  CAD
  • patient.genderM  ·  F

Source portals (list will expand)

CommunicatePortalMyiTeroDSCore MeditLinkCSConnectDexisISConnect Shining3DDentalCloudFreqtyCloud StraumannAXSAiditeRunyes

Scan files

  • typepreparationScan  ·  biteScan  ·  prePreparationScan  ·  abutmentScan  ·  dentureScan
  • jawupper  ·  lower  ·  none
  • fileTypestl  ·  ply  ·  preview

worktypes[].categoryId

FixedRemovableApplianceOrthodontics

worktypes[].jaw

UpperLowerBothNone

worktypes[].restorationTypeId

Dental
CrownBridgeImplantCrownImplantBridge DentureImplantDentureWireRetainerClearOverlay SplintBleachingTrayMouthguardSurgicalGuide AlignersMandibularRepositioningApplianceModel ImpressionTrayBiteRegistrationWaxUp OrthodonticApplianceNone
Orthodontics
ActivatorAlignersBleachingTray ExpansionPlateFixedApplianceIndirectBondingTray ModelMouthguardMandibularRepositioningAppliance RetentionPlateSplintSurgicalGuide OrthodonticInvisibleRetainerWireRetainer BiteRegistrationNone

worktypes[].restorationDetailId

Dental
FullPartialVeneerTemporary TelescopePostPonticNone
Orthodontics
BionatorDucovatorEVAAFrankel HalfOpenActivatorLRMMonoBlock NewTApplianceOpenActivatorTAppliance TwinBlockUApplianceVanBeek BertoniPlateDistalizerMesializerHerbst HerbstRPERMELLATPAMARPENance RPERMEBandedRPERMEBondedRPERMEHybrid SpaceMaintainerQuadHelixStudyModel WorkModelVirtualModelDamonSplintNone

worktypes[].materialId

Dental
ZirconiaLithiumDisilicatePMMA CompositeFeldspathicMetalFlexible PEEKThermoformAcrylicDigitalNone
Orthodontics
DigitalMetalPEEKNone

worktypes[].settingId — Dental only

MonolithicLayeredHardSoft HardSoftNone

Explore all endpoints

The interactive API reference lets you authenticate and call every endpoint directly in the browser. The OpenAPI JSON spec can be imported into Postman, Insomnia, or any compatible tooling.