Quick Start

This guide walks you through the typical Cadasto workflow: authenticate, create an EHR, upload a template, commit a composition, and query data. All examples use curl — replace <mycompany> and <token> with your actual values.

Developer journey — from credentials to querying clinical data in 6 steps

Prerequisites

All API requests require a Bearer token in the Authorization header. See Authentication for how to obtain one.

Base URL for all API calls:

https://<mycompany>.api.prod.cadasto.io/openehr/v1

1. Create an EHR

Create a new Electronic Health Record. The server generates a unique ehr_id.

POST /ehr
Prefer: return=representation
Authorization: Bearer <token>

Response (201 Created):

{
  "system_id": { "value": "cadasto.io" },
  "ehr_id": { "value": "7d44b88c-4199-4bad-97dc-d78268e01398" },
  "ehr_status": { ... },
  "time_created": { "value": "2025-01-15T10:30:00.000+00:00" }
}

Retrieve an existing EHR:

GET /ehr/{ehr_id}
Accept: application/json
Authorization: Bearer <token>

Understanding the response

  • ehr_id is a UUID that uniquely identifies this EHR. Use it in all subsequent API calls.
  • ehr_status contains subject information and queryable/modifiable flags.
  • You can optionally provide an EHR_STATUS body with POST /ehr to set subject references or other details at creation time.

2. Upload a template

Templates define the structure and constraints for clinical documents. You must upload at least one template before committing compositions. Upload an ADL 1.4 Operational Template (OPT) in XML format.

POST /definition/template/adl1.4
Content-Type: application/xml
Prefer: return=minimal
Authorization: Bearer <token>
<template xmlns="http://schemas.openehr.org/v1">
    <language>
        <terminology_id><value>ISO_639-1</value></terminology_id>
        <code_string>en</code_string>
    </language>
    ...
</template>

List all uploaded templates:

GET /definition/template/adl1.4
Authorization: Bearer <token>

Retrieve a specific template:

GET /definition/template/adl1.4/{template_id}
Authorization: Bearer <token>

3. Commit a composition

A Composition is a clinical document committed to an EHR. It is validated against the template specified by its archetype_node_id.

Not sure what a valid composition looks like for your template? Use the example endpoint to generate one:

GET /definition/template/adl1.4/{template_id}/example

This returns a fully populated example composition based on your template, which you can use as a starting point.

POST /ehr/{ehr_id}/composition
Content-Type: application/json
Prefer: return=representation
Authorization: Bearer <token>
{
  "archetype_node_id": "openEHR-EHR-COMPOSITION.encounter.v1",
  "name": { "value": "Vital Signs" },
  "uid": {
    "_type": "OBJECT_VERSION_ID",
    "value": "8849182c-82ad-4088-a07f-48ead4180515::openEHRSys.example.com::1"
  },
  "language": { ... },
  "territory": { ... },
  "category": { ... },
  "composer": { ... },
  "content": [ ... ]
}

Response (201 Created): The committed composition with a Location header pointing to its versioned URI.

4. Retrieve or update a composition

Compositions are versioned. There are two ways to address them:

  • Versioned object UID (e.g., 8849182c-82ad-4088-a07f-48ead4180515) — always resolves to the latest version.
  • Version UID (e.g., 8849182c-82ad-4088-a07f-48ead4180515::cadasto.io::1) — resolves to a specific version. The format is {object_id}::{system_id}::{version_tree_id}.

Latest version:

GET /ehr/{ehr_id}/composition/{versioned_object_uid}
Authorization: Bearer <token>

Specific version:

GET /ehr/{ehr_id}/composition/{version_uid}
Authorization: Bearer <token>

Update (optimistic locking with If-Match):

PUT /ehr/{ehr_id}/composition/{versioned_object_uid}
If-Match: "<latest_version_uid>"
Content-Type: application/json
Authorization: Bearer <token>

The If-Match header prevents lost updates: if another client has modified the composition since you last read it, the server returns 412 Precondition Failed. Retrieve the latest version and retry.

Delete (logical):

DELETE /ehr/{ehr_id}/composition/{version_uid}
Authorization: Bearer <token>

Deletions are logical — the data is marked as deleted but remains in the version history for audit purposes.

5. Organize with directories

Use Directories (Folders) to organize compositions within an EHR.

Note: The directory is automatically created when the EHR is created — there is no need to call POST /ehr/{ehr_id}/directory.

Update (with concurrency control):

PUT /ehr/{ehr_id}/directory
If-Match: "<latest_version_uid>"
Authorization: Bearer <token>

Fetch a path at a specific time:

GET /ehr/{ehr_id}/directory?path=episodes/a/b&version_at_time=2025-01-15T10:30:00.000+00:00
Authorization: Bearer <token>

6. Batch commit with contributions

A Contribution groups multiple versioned object changes into a single atomic commit.

POST /ehr/{ehr_id}/contribution
Content-Type: application/json
Authorization: Bearer <token>

The request body contains a versions array with the operations and audit metadata.

7. Query data with AQL

Use AQL (Archetype Query Language) to query clinical data across EHRs using archetype paths. AQL queries are portable — they work regardless of which template was used to capture the data. The recommended approach is POST with the query in the request body:

POST /query/aql
Content-Type: application/json
Authorization: Bearer <token>
{
  "q": "SELECT e/ehr_id/value, c/uid/value FROM EHR e CONTAINS COMPOSITION c WHERE e/ehr_id/value = $ehr_id",
  "query_parameters": {
    "ehr_id": "7d44b88c-4199-4bad-97dc-d78268e01398"
  }
}

See the AQL Guide for query syntax, clauses, and clinical examples.

Quick reference

Action Endpoint Method Notes
Create EHR /ehr POST Optional EHR_STATUS body
Get EHR /ehr/{ehr_id} GET 404 if not found
Create composition /ehr/{ehr_id}/composition POST 201 + Location header
Get composition (latest) /ehr/{ehr_id}/composition/{versioned_object_uid} GET Uses container ID
Get composition (version) /ehr/{ehr_id}/composition/{version_uid} GET Specific version
Update composition /ehr/{ehr_id}/composition/{versioned_object_uid} PUT If-Match required
Delete composition /ehr/{ehr_id}/composition/{version_uid} DELETE Logical delete
Upload template (ADL 1.4) /definition/template/adl1.4 POST XML body
List templates /definition/template/adl1.4 GET Returns metadata list
Get template /definition/template/adl1.4/{id} GET Returns template
Store query /definition/query/{name} PUT text/plain AQL body
Execute ad-hoc AQL /query/aql POST JSON body
Execute stored query /query/{qualified_query_name} GET Query params for variables
Create person /demographic/person POST Demographic entity
Get person /demographic/person/{person_id} GET Returns versioned party
Create organisation /demographic/organisation POST Demographic entity
Create party relationship /demographic/party_relationship POST Directed relationship

Cadasto also provides a Demographic API for managing persons, organisations, roles, and party relationships. Demographic data is versioned and separated from clinical content by design. See the openEHR Concepts guide for how demographics relate to EHRs.

Beyond the standard openEHR REST APIs above, Cadasto offers an Extra API with convenience endpoints for datamaps, episodes of care, terminology helpers, and user information. These simplify common integration tasks but are Cadasto-specific — they are not part of the openEHR specification and may change between platform releases.

Next steps