Appearance
API Design
The Medipal API is a versioned REST API over HTTPS with JSON bodies. It is described by an OpenAPI document generated from the platform schema and served by every instance. This page explains the conventions that apply to all endpoints; the practical steps for obtaining credentials and calling the API are in API Access.
Resources and paths
- Every entity is a resource with a stable path under a versioned prefix. Collections are listed, created, read, updated and deleted with the usual HTTP methods.
- Identifiers are opaque strings; never derive meaning from them.
- Related actions that are not plain CRUD (publish a questionnaire, link a patient to a clinical record, invoke a plugin action) are exposed as explicit sub-resources rather than hidden in update calls.
- Deleting a resource is a soft delete: the record keeps a deletion timestamp and disappears from default listings.
The OpenAPI document
The document is the contract. It lists every operation, its request and response models, the scopes it requires and the error codes it can return. The typed TypeScript clients used by the web and mobile apps are generated from it, and integrators can generate clients for their own language with any standard OpenAPI tool. The document is served by the instance together with interactive documentation.
Collection endpoints
All collection endpoints share one query interface.
| Capability | How it works |
|---|---|
| Pagination | limit and offset query parameters. The response carries total, has_next and has_previous, so clients do not compute page state. |
| Sorting | sort_by with a field name and sort_dir (asc or desc). Without sort_by, a stable default order keeps pages consistent. |
| Filtering | Field name equals value for equality. Other operators are suffixed to the field name: __ne, __lt, __lte, __gt, __gte, __in, __not_in, __ilike. Filters combine with AND. |
| Type safety | Each field accepts only the operators valid for its type; a boolean cannot be pattern-matched, a timestamp can be ranged. |
| Soft delete | Deleted records are hidden by default. include_deleted returns both, only_deleted returns the trash view. |
| Discoverable | An unsupported sort or filter field returns a validation error listing the accepted values, so a client can correct itself without reading the source. |
The response envelope is the same everywhere: the items under a resource-named key, followed by the paging fields.
json
{
"webhooks": [],
"total": 57,
"limit": 25,
"offset": 0,
"has_next": true,
"has_previous": false
}Errors
Every error uses one envelope:
json
{
"error": {
"code": "QUERY_VALIDATION_ERROR",
"message": "Unsupported sort field: colour",
"details": {
"field": "colour",
"allowed_values": ["created_at", "id", "name"]
}
}
}| Status | Family |
|---|---|
| 400 | Validation errors: malformed body, unsupported query field or operator, business rule violations. |
| 401 | The request is not authenticated, or the token is expired or malformed. |
| 403 | The caller is authenticated but lacks a required scope or permission, or must complete a pending step first. |
| 404 | The resource does not exist or is not visible to the caller. |
| 409 | Conflict with the current state, for example a slot that already has a submission. |
| 502 | An upstream system (a FHIR server, an identity provider) could not be reached. |
| 500 | Unexpected server error. No internal details are included. |
Codes are stable strings meant for programmatic handling; messages are for logs and developers and may change between releases.
Validation
Requests are validated against the generated models before any business logic runs. Validation covers types, required fields, formats such as timestamps and identifiers, and enumerations. Business validation (a schedule that ends before it starts, a publish request on a questionnaire without a schedule) happens in the service layer and is reported through the same envelope.
Idempotency and retries
- Reads and deletes are safe to retry.
- Creates are not automatically idempotent; a retried create after a network timeout may produce a duplicate. Look the resource up before retrying, or use a natural key where the resource has one (vault entries and roles have unique keys).
- Submissions are protected by the schedule slot: a second submission for the same slot is rejected with a conflict, so a retried submission cannot double-count.
- Treat 5xx and connection errors as retryable with backoff; treat 4xx as final.
Public endpoints
A small number of endpoints accept anonymous requests by design: reading published consent documents and submitting an anonymous questionnaire through its public link. Everything else requires a principal. See Anonymous Questionnaires.
Compatibility
The API version prefix changes only for breaking changes. Within a version, fields are added but not removed or retyped, so clients should ignore unknown fields. The web app and the API are released together on the same minor version so that their contract always matches.