---
openapi: 3.0.1
info:
  title: API V2
  version: v2
  description: 'Machine-to-machine REST API over the Canonical Data Model. Rate limits:
    authenticated traffic is limited to 300 requests per minute per API client (HTTP
    429 when exceeded). The OAuth token endpoint (POST /oauth/token) is separately
    limited to 10 requests per minute per source IP.'
components:
  securitySchemes:
    oauth2:
      type: oauth2
      description: OAuth2 client_credentials flow. Create an API client in the Connect
        settings to obtain a client id and secret. Access tokens expire after two
        hours and there are no refresh tokens, so request another when one expires.
        Revoking the client refuses its credentials here with `unauthorized_client`
        and rejects the tokens it has already been issued.
      flows:
        clientCredentials:
          tokenUrl: "/oauth/token"
          scopes:
            patients:read: Read patients
            patients:write: Create and update patients
            scheduler:read: Read scheduler events
            scheduler:write: Create and update scheduler events
            users:read: Read staff members
            users:write: Update staff external identifiers
            settings:read: Read account settings catalogues
            settings:write: Manage account settings catalogues
  parameters:
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: false
      description: Optional client-generated key (a UUIDv4 is recommended) that makes
        this write safe to retry. Repeating the request with the same key replays
        the original response for 24 hours instead of applying the change twice.
      schema:
        type: string
        maxLength: 255
paths:
  "/api/v2/locations":
    get:
      summary: List locations
      tags:
      - Locations
      security:
      - oauth2: []
      parameters:
      - name: page
        in: query
        required: false
        description: 1-based page number
        schema:
          type: integer
      - name: items
        in: query
        required: false
        description: Page size (capped at 100)
        schema:
          type: integer
      responses:
        '200':
          description: the principal's clinics as CDM locations, paginated in the
            { data, meta } envelope
          content:
            application/json:
              schema:
                type: object
                required:
                - data
                - meta
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      required:
                      - id
                      - name
                      properties:
                        id:
                          type: integer
                        name:
                          type: string
                        location_type:
                          type: string
                          nullable: true
                          description: "`clinic` or `satellite`"
                        address_line_1:
                          type: string
                          nullable: true
                        town_or_city:
                          type: string
                          nullable: true
                        country:
                          type: string
                          nullable: true
                        postal_code:
                          type: string
                          nullable: true
                        is_active:
                          type: boolean
                          nullable: true
                        created_at:
                          type: string
                          format: date-time
                        updated_at:
                          type: string
                          format: date-time
                        source_system:
                          type: string
                        deleted:
                          type: string
                          format: date-time
                          nullable: true
                          description: Soft-delete timestamp; null when the record
                            is live
                  meta:
                    type: object
                    required:
                    - page
                    - items
                    - count
                    - pages
                    properties:
                      page:
                        type: integer
                      items:
                        type: integer
                      count:
                        type: integer
                      pages:
                        type: integer
                      next:
                        type: integer
                        nullable: true
                      prev:
                        type: integer
                        nullable: true
  "/api/v2/locations/{id}":
    get:
      summary: Show a location
      tags:
      - Locations
      security:
      - oauth2: []
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: integer
      responses:
        '200':
          description: the location in CDM shape
          content:
            application/json:
              schema:
                type: object
                required:
                - id
                - name
                properties:
                  id:
                    type: integer
                  name:
                    type: string
                  location_type:
                    type: string
                    nullable: true
                    description: "`clinic` or `satellite`"
                  address_line_1:
                    type: string
                    nullable: true
                  town_or_city:
                    type: string
                    nullable: true
                  country:
                    type: string
                    nullable: true
                  postal_code:
                    type: string
                    nullable: true
                  is_active:
                    type: boolean
                    nullable: true
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
                  source_system:
                    type: string
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
                    description: Soft-delete timestamp; null when the record is live
        '404':
          description: no such location in the principal's scope
  "/api/v2/me":
    get:
      summary: Show the authenticated principal
      tags:
      - Principal
      security:
      - oauth2: []
      responses:
        '200':
          description: authenticated
          content:
            application/json:
              schema:
                type: object
                required:
                - id
                - name
                - scopes
                - account_id
                properties:
                  id:
                    type: integer
                  name:
                    type: string
                  scopes:
                    type: array
                    items:
                      type: string
                  clinic_ids:
                    type: array
                    items:
                      type: integer
                    nullable: true
                  account_id:
                    type: integer
        '401':
          description: missing or invalid bearer token
  "/api/v2/patients/{patient_id}/diagnoses":
    get:
      summary: List a patient's diagnoses
      tags:
      - Patient diagnoses
      security:
      - oauth2: []
      parameters:
      - name: patient_id
        in: path
        required: true
        schema:
          type: integer
      - name: page
        in: query
        required: false
        schema:
          type: integer
      - name: items
        in: query
        required: false
        schema:
          type: integer
      responses:
        '200':
          description: the patient's diagnoses, paginated in the { data, meta } envelope
          content:
            application/json:
              schema:
                type: object
                required:
                - data
                - meta
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      required:
                      - id
                      - patient_id
                      properties:
                        id:
                          type: integer
                        patient_id:
                          type: integer
                        diagnosis_label:
                          type: string
                          nullable: true
                        diagnosis_code:
                          type: string
                          nullable: true
                        diagnosis_code_source:
                          type: string
                          nullable: true
                        diagnosed_by:
                          type: integer
                          nullable: true
                        category:
                          type: string
                          nullable: true
                        is_active:
                          type: boolean
                          nullable: true
                        onset_date:
                          type: string
                          format: date
                          nullable: true
                        resolved_date:
                          type: string
                          format: date
                          nullable: true
                        sort_order:
                          type: integer
                          nullable: true
                        notes:
                          type: string
                          nullable: true
                        created_at:
                          type: string
                          format: date-time
                        updated_at:
                          type: string
                          format: date-time
                        source_system:
                          type: string
                        deleted:
                          type: string
                          format: date-time
                          nullable: true
                  meta:
                    type: object
                    required:
                    - page
                    - items
                    - count
                    - pages
                    properties:
                      page:
                        type: integer
                      items:
                        type: integer
                      count:
                        type: integer
                      pages:
                        type: integer
                      next:
                        type: integer
                        nullable: true
                      prev:
                        type: integer
                        nullable: true
        '404':
          description: no such patient in the principal's scope
  "/api/v2/patients/{patient_id}/diagnoses/{id}":
    get:
      summary: Show a patient diagnosis
      tags:
      - Patient diagnoses
      security:
      - oauth2: []
      parameters:
      - name: patient_id
        in: path
        required: true
        schema:
          type: integer
      - name: id
        in: path
        required: true
        schema:
          type: integer
      responses:
        '200':
          description: the diagnosis in CDM shape
          content:
            application/json:
              schema:
                type: object
                required:
                - id
                - patient_id
                properties:
                  id:
                    type: integer
                  patient_id:
                    type: integer
                  diagnosis_label:
                    type: string
                    nullable: true
                  diagnosis_code:
                    type: string
                    nullable: true
                  diagnosis_code_source:
                    type: string
                    nullable: true
                  diagnosed_by:
                    type: integer
                    nullable: true
                  category:
                    type: string
                    nullable: true
                  is_active:
                    type: boolean
                    nullable: true
                  onset_date:
                    type: string
                    format: date
                    nullable: true
                  resolved_date:
                    type: string
                    format: date
                    nullable: true
                  sort_order:
                    type: integer
                    nullable: true
                  notes:
                    type: string
                    nullable: true
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
                  source_system:
                    type: string
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
        '404':
          description: no such diagnosis for this patient
  "/api/v2/patients/{patient_id}/external_identifiers":
    get:
      summary: List a patient's external identifiers
      tags:
      - Patient external identifiers
      security:
      - oauth2: []
      parameters:
      - name: patient_id
        in: path
        required: true
        schema:
          type: integer
      - name: page
        in: query
        required: false
        schema:
          type: integer
      - name: items
        in: query
        required: false
        schema:
          type: integer
      responses:
        '200':
          description: the patient's external identifiers, including document types
            that do not yet have a value, paginated in the { data, meta } envelope
          content:
            application/json:
              schema:
                type: object
                required:
                - data
                - meta
                properties:
                  data:
                    type: array
                    items:
                      title: canonical.v0.patient_external_identifier record
                      description: The resource's current CDM state, as projected
                        by canonical_v0_patient_external_identifiers_v01. Generated
                        from the vendored CDM DDL, so it cannot fall behind the columns
                        the view returns.
                      type: object
                      required:
                      - id
                      properties:
                        id:
                          type: integer
                        patient_id:
                          type: integer
                          nullable: true
                        identifier_type:
                          type: string
                          nullable: true
                          description: Either one of the CDM's own document types
                            — health_card, passport, nhs, insurance_membership, rodne_cislo,
                            pps, bsn, cnp, codice_fiscale, ihi — or an externally-sourced
                            type under the custom- namespace, e.g. custom-MRN. Document
                            types are writable here when enabled in Settings > Patient
                            Identification. SSN identifiers are not returned or writable
                            on this API.
                        identifier_value:
                          type: string
                          nullable: true
                        issuing_jurisdiction:
                          type: string
                          nullable: true
                          description: The authority that issued the identifier, as
                            an ISO 3166-1 alpha-2 country code (GB, DK). Free text,
                            so not validated against that list.
                        valid_from:
                          type: string
                          format: date
                          nullable: true
                          description: 'Read-only, and always null on this resource:
                            nothing populates it yet.'
                        valid_to:
                          type: string
                          format: date
                          nullable: true
                          description: The document expiry for types that have one
                            (passport, health_card). Writable on those types; always
                            null on an externally-sourced identifier.
                        source_system:
                          type: string
                          nullable: true
                          description: 'Read-only provenance: which system the record
                            came from. Always wawa for one written through this API.'
                        deleted:
                          type: string
                          format: date-time
                          nullable: true
                          description: Read-only. Null while the identifier is live,
                            and set to the time it was discarded by DELETE.
                        created_at:
                          type: string
                          format: date-time
                          nullable: true
                        updated_at:
                          type: string
                          format: date-time
                          nullable: true
                        primary:
                          type: boolean
                          description: Whether this is the patient's primary identifier.
                  meta:
                    type: object
                    required:
                    - page
                    - items
                    - count
                    - pages
                    properties:
                      page:
                        type: integer
                      items:
                        type: integer
                      count:
                        type: integer
                      pages:
                        type: integer
                      next:
                        type: integer
                        nullable: true
                      prev:
                        type: integer
                        nullable: true
        '404':
          description: no such patient in the principal's scope
    post:
      summary: Create a patient external identifier
      tags:
      - Patient external identifiers
      security:
      - oauth2: []
      parameters:
      - "$ref": "#/components/parameters/IdempotencyKey"
      - name: patient_id
        in: path
        required: true
        schema:
          type: integer
      responses:
        '201':
          description: the created identifier in CDM shape; one canonical.v0.patient_external_identifier.created
            event is published
          content:
            application/json:
              schema:
                title: canonical.v0.patient_external_identifier record
                description: The resource's current CDM state, as projected by canonical_v0_patient_external_identifiers_v01.
                  Generated from the vendored CDM DDL, so it cannot fall behind the
                  columns the view returns.
                type: object
                required:
                - id
                properties:
                  id:
                    type: integer
                  patient_id:
                    type: integer
                    nullable: true
                  identifier_type:
                    type: string
                    nullable: true
                    description: Either one of the CDM's own document types — health_card,
                      passport, nhs, insurance_membership, rodne_cislo, pps, bsn,
                      cnp, codice_fiscale, ihi — or an externally-sourced type under
                      the custom- namespace, e.g. custom-MRN. Document types are writable
                      here when enabled in Settings > Patient Identification. SSN
                      identifiers are not returned or writable on this API.
                  identifier_value:
                    type: string
                    nullable: true
                  issuing_jurisdiction:
                    type: string
                    nullable: true
                    description: The authority that issued the identifier, as an ISO
                      3166-1 alpha-2 country code (GB, DK). Free text, so not validated
                      against that list.
                  valid_from:
                    type: string
                    format: date
                    nullable: true
                    description: 'Read-only, and always null on this resource: nothing
                      populates it yet.'
                  valid_to:
                    type: string
                    format: date
                    nullable: true
                    description: The document expiry for types that have one (passport,
                      health_card). Writable on those types; always null on an externally-sourced
                      identifier.
                  source_system:
                    type: string
                    nullable: true
                    description: 'Read-only provenance: which system the record came
                      from. Always wawa for one written through this API.'
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
                    description: Read-only. Null while the identifier is live, and
                      set to the time it was discarded by DELETE.
                  created_at:
                    type: string
                    format: date-time
                    nullable: true
                  updated_at:
                    type: string
                    format: date-time
                    nullable: true
                  primary:
                    type: boolean
                    description: Whether this is the patient's primary identifier.
        '422':
          description: the identifier is invalid (duplicate type, disabled document
            type, blank value)
        '404':
          description: no such patient in the principal's scope
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                primary:
                  type: boolean
                  description: Optional, defaults to false. Only one kept identifier
                    per patient can be primary. Clear the existing primary before
                    selecting another; a second primary returns 422.
                identifier_type:
                  type: string
                  description: Either a CDM document type (health_card, passport,
                    nhs, insurance_membership, rodne_cislo, pps, bsn, cnp, codice_fiscale,
                    ihi) or the issuing system's own name, namespaced as it reads
                    back, e.g. custom-MRN. A type that is neither is rejected. Document
                    types are gated by Settings > Patient Identification; a namespaced
                    type is not. Health card variant (OHIP, RAMQ, …) is not a field
                    on this resource. SSN is omitted from this API.
                identifier_value:
                  type: string
                  description: The identifier itself. Cannot be blank.
                issuing_jurisdiction:
                  type: string
                  description: Optional. The authority that issued the identifier,
                    as an ISO 3166-1 alpha-2 country code (GB, DK). Free text, so
                    not validated against that list.
                valid_to:
                  type: string
                  format: date
                  description: Optional. The document expiry, accepted on passport
                    and health_card. Rejected as 400 on every other type. valid_from
                    is always read-only.
              required:
              - identifier_type
              - identifier_value
  "/api/v2/patients/{patient_id}/external_identifiers/{id}":
    get:
      summary: Show a patient external identifier
      tags:
      - Patient external identifiers
      security:
      - oauth2: []
      parameters:
      - name: patient_id
        in: path
        required: true
        schema:
          type: integer
      - name: id
        in: path
        required: true
        schema:
          type: integer
      responses:
        '200':
          description: the external identifier in CDM shape
          content:
            application/json:
              schema:
                title: canonical.v0.patient_external_identifier record
                description: The resource's current CDM state, as projected by canonical_v0_patient_external_identifiers_v01.
                  Generated from the vendored CDM DDL, so it cannot fall behind the
                  columns the view returns.
                type: object
                required:
                - id
                properties:
                  id:
                    type: integer
                  patient_id:
                    type: integer
                    nullable: true
                  identifier_type:
                    type: string
                    nullable: true
                    description: Either one of the CDM's own document types — health_card,
                      passport, nhs, insurance_membership, rodne_cislo, pps, bsn,
                      cnp, codice_fiscale, ihi — or an externally-sourced type under
                      the custom- namespace, e.g. custom-MRN. Document types are writable
                      here when enabled in Settings > Patient Identification. SSN
                      identifiers are not returned or writable on this API.
                  identifier_value:
                    type: string
                    nullable: true
                  issuing_jurisdiction:
                    type: string
                    nullable: true
                    description: The authority that issued the identifier, as an ISO
                      3166-1 alpha-2 country code (GB, DK). Free text, so not validated
                      against that list.
                  valid_from:
                    type: string
                    format: date
                    nullable: true
                    description: 'Read-only, and always null on this resource: nothing
                      populates it yet.'
                  valid_to:
                    type: string
                    format: date
                    nullable: true
                    description: The document expiry for types that have one (passport,
                      health_card). Writable on those types; always null on an externally-sourced
                      identifier.
                  source_system:
                    type: string
                    nullable: true
                    description: 'Read-only provenance: which system the record came
                      from. Always wawa for one written through this API.'
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
                    description: Read-only. Null while the identifier is live, and
                      set to the time it was discarded by DELETE.
                  created_at:
                    type: string
                    format: date-time
                    nullable: true
                  updated_at:
                    type: string
                    format: date-time
                    nullable: true
                  primary:
                    type: boolean
                    description: Whether this is the patient's primary identifier.
        '404':
          description: no such identifier for this patient
    patch:
      summary: Update a patient external identifier
      tags:
      - Patient external identifiers
      security:
      - oauth2: []
      parameters:
      - "$ref": "#/components/parameters/IdempotencyKey"
      - name: patient_id
        in: path
        required: true
        schema:
          type: integer
      - name: id
        in: path
        required: true
        schema:
          type: integer
      responses:
        '200':
          description: the updated identifier in CDM shape; one canonical.v0.patient_external_identifier.updated
            event is published when something changed
          content:
            application/json:
              schema:
                title: canonical.v0.patient_external_identifier record
                description: The resource's current CDM state, as projected by canonical_v0_patient_external_identifiers_v01.
                  Generated from the vendored CDM DDL, so it cannot fall behind the
                  columns the view returns.
                type: object
                required:
                - id
                properties:
                  id:
                    type: integer
                  patient_id:
                    type: integer
                    nullable: true
                  identifier_type:
                    type: string
                    nullable: true
                    description: Either one of the CDM's own document types — health_card,
                      passport, nhs, insurance_membership, rodne_cislo, pps, bsn,
                      cnp, codice_fiscale, ihi — or an externally-sourced type under
                      the custom- namespace, e.g. custom-MRN. Document types are writable
                      here when enabled in Settings > Patient Identification. SSN
                      identifiers are not returned or writable on this API.
                  identifier_value:
                    type: string
                    nullable: true
                  issuing_jurisdiction:
                    type: string
                    nullable: true
                    description: The authority that issued the identifier, as an ISO
                      3166-1 alpha-2 country code (GB, DK). Free text, so not validated
                      against that list.
                  valid_from:
                    type: string
                    format: date
                    nullable: true
                    description: 'Read-only, and always null on this resource: nothing
                      populates it yet.'
                  valid_to:
                    type: string
                    format: date
                    nullable: true
                    description: The document expiry for types that have one (passport,
                      health_card). Writable on those types; always null on an externally-sourced
                      identifier.
                  source_system:
                    type: string
                    nullable: true
                    description: 'Read-only provenance: which system the record came
                      from. Always wawa for one written through this API.'
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
                    description: Read-only. Null while the identifier is live, and
                      set to the time it was discarded by DELETE.
                  created_at:
                    type: string
                    format: date-time
                    nullable: true
                  updated_at:
                    type: string
                    format: date-time
                    nullable: true
                  primary:
                    type: boolean
                    description: Whether this is the patient's primary identifier.
        '403':
          description: the identifier is readable but not the caller's to change
        '422':
          description: another kept identifier is already primary
        '404':
          description: no such identifier for this patient
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                primary:
                  type: boolean
                  description: Optional, defaults to false. Only one kept identifier
                    per patient can be primary. Clear the existing primary before
                    selecting another; a second primary returns 422.
                identifier_type:
                  type: string
                  description: Either a CDM document type (health_card, passport,
                    nhs, insurance_membership, rodne_cislo, pps, bsn, cnp, codice_fiscale,
                    ihi) or the issuing system's own name, namespaced as it reads
                    back, e.g. custom-MRN. A type that is neither is rejected. Document
                    types are gated by Settings > Patient Identification; a namespaced
                    type is not. Health card variant (OHIP, RAMQ, …) is not a field
                    on this resource. SSN is omitted from this API.
                identifier_value:
                  type: string
                  description: The identifier itself. Cannot be blank.
                issuing_jurisdiction:
                  type: string
                  description: Optional. The authority that issued the identifier,
                    as an ISO 3166-1 alpha-2 country code (GB, DK). Free text, so
                    not validated against that list.
                valid_to:
                  type: string
                  format: date
                  description: Optional. The document expiry, accepted on passport
                    and health_card. Rejected as 400 on every other type. valid_from
                    is always read-only.
    delete:
      summary: Discard a patient external identifier
      tags:
      - Patient external identifiers
      security:
      - oauth2: []
      parameters:
      - "$ref": "#/components/parameters/IdempotencyKey"
      - name: patient_id
        in: path
        required: true
        schema:
          type: integer
      - name: id
        in: path
        required: true
        schema:
          type: integer
      responses:
        '200':
          description: the discarded identifier in CDM shape; one canonical.v0.patient_external_identifier.deleted
            event is published
          content:
            application/json:
              schema:
                title: canonical.v0.patient_external_identifier record
                description: The resource's current CDM state, as projected by canonical_v0_patient_external_identifiers_v01.
                  Generated from the vendored CDM DDL, so it cannot fall behind the
                  columns the view returns.
                type: object
                required:
                - id
                properties:
                  id:
                    type: integer
                  patient_id:
                    type: integer
                    nullable: true
                  identifier_type:
                    type: string
                    nullable: true
                    description: Either one of the CDM's own document types — health_card,
                      passport, nhs, insurance_membership, rodne_cislo, pps, bsn,
                      cnp, codice_fiscale, ihi — or an externally-sourced type under
                      the custom- namespace, e.g. custom-MRN. Document types are writable
                      here when enabled in Settings > Patient Identification. SSN
                      identifiers are not returned or writable on this API.
                  identifier_value:
                    type: string
                    nullable: true
                  issuing_jurisdiction:
                    type: string
                    nullable: true
                    description: The authority that issued the identifier, as an ISO
                      3166-1 alpha-2 country code (GB, DK). Free text, so not validated
                      against that list.
                  valid_from:
                    type: string
                    format: date
                    nullable: true
                    description: 'Read-only, and always null on this resource: nothing
                      populates it yet.'
                  valid_to:
                    type: string
                    format: date
                    nullable: true
                    description: The document expiry for types that have one (passport,
                      health_card). Writable on those types; always null on an externally-sourced
                      identifier.
                  source_system:
                    type: string
                    nullable: true
                    description: 'Read-only provenance: which system the record came
                      from. Always wawa for one written through this API.'
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
                    description: Read-only. Null while the identifier is live, and
                      set to the time it was discarded by DELETE.
                  created_at:
                    type: string
                    format: date-time
                    nullable: true
                  updated_at:
                    type: string
                    format: date-time
                    nullable: true
                  primary:
                    type: boolean
                    description: Whether this is the patient's primary identifier.
        '204':
          description: a seeded identifier that never had a number, discarded to free
            the type with no CDM body
        '403':
          description: the identifier is readable but not the caller's to remove
        '404':
          description: no such identifier for this patient
  "/api/v2/patients/{patient_id}/fund_source":
    patch:
      summary: Assign a patient's fund source
      tags:
      - Patients
      security:
      - oauth2: []
      parameters:
      - "$ref": "#/components/parameters/IdempotencyKey"
      - name: patient_id
        in: path
        required: true
        schema:
          type: integer
      responses:
        '200':
          description: the patient in CDM shape, carrying the assigned fund source
          content:
            application/json:
              schema:
                title: canonical.v0.patient record
                description: The resource's current CDM state, as projected by canonical_v0_patients_v01.
                  Generated from the vendored CDM DDL, so it cannot fall behind the
                  columns the view returns.
                type: object
                required:
                - id
                properties:
                  id:
                    type: integer
                  first_name:
                    type: string
                    nullable: true
                  last_name:
                    type: string
                    nullable: true
                  external_identifier:
                    type: string
                    nullable: true
                  title:
                    type: string
                    nullable: true
                  patient_identity_management_id:
                    type: string
                    nullable: true
                  middle_name:
                    type: string
                    nullable: true
                  preferred_name:
                    type: string
                    nullable: true
                  full_legal_name:
                    type: string
                    nullable: true
                  date_of_birth:
                    type: string
                    format: date
                    nullable: true
                  email:
                    type: string
                    nullable: true
                  sex_assigned_at_birth:
                    type: string
                    nullable: true
                  gender_identity:
                    type: string
                    nullable: true
                  pronouns:
                    type: string
                    nullable: true
                  ethnicity:
                    type: string
                    nullable: true
                  fathers_ethnicity:
                    type: string
                    nullable: true
                  mothers_ethnicity:
                    type: string
                    nullable: true
                  country_of_birth:
                    type: string
                    nullable: true
                  town_or_city_of_birth:
                    type: string
                    nullable: true
                  preferred_language:
                    type: string
                    nullable: true
                  marital_status:
                    type: string
                    nullable: true
                  blood_group:
                    type: string
                    nullable: true
                  rhesus_factor:
                    type: string
                    nullable: true
                  address_line_1:
                    type: string
                    nullable: true
                  address_line_2:
                    type: string
                    nullable: true
                  town_or_city:
                    type: string
                    nullable: true
                  state_or_province:
                    type: string
                    nullable: true
                  postcode:
                    type: string
                    nullable: true
                  country:
                    type: string
                    nullable: true
                  is_donor:
                    type: boolean
                    nullable: true
                  is_deceased:
                    type: boolean
                    nullable: true
                  primary_user_id:
                    type: integer
                    nullable: true
                  brand_id:
                    type: integer
                    nullable: true
                  fund_source_id:
                    type: integer
                    nullable: true
                  metadata:
                    type: object
                    nullable: true
                  initial_contact_at:
                    type: string
                    format: date-time
                    nullable: true
                  first_seen_at:
                    type: string
                    format: date-time
                    nullable: true
                  source_system:
                    type: string
                    nullable: true
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
                  created_at:
                    type: string
                    format: date-time
                    nullable: true
                  updated_at:
                    type: string
                    format: date-time
                    nullable: true
        '422':
          description: the fund source id is not one of the principal's fund sources
        '404':
          description: no such patient in the principal's scope
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - fund_source_id
              properties:
                fund_source_id:
                  type: integer
                  nullable: true
                  description: The CDM fund source id, or null to leave the patient
                    with no fund source
  "/api/v2/patients/{patient_id}/locations":
    get:
      summary: List a patient's clinic assignments
      tags:
      - Patient locations
      security:
      - oauth2: []
      parameters:
      - name: patient_id
        in: path
        required: true
        schema:
          type: integer
      - name: page
        in: query
        required: false
        schema:
          type: integer
      - name: items
        in: query
        required: false
        schema:
          type: integer
      responses:
        '200':
          description: the patient's clinic assignments as CDM patient_locations,
            paginated
          content:
            application/json:
              schema:
                type: object
                required:
                - data
                - meta
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      required:
                      - id
                      - patient_id
                      - location_id
                      properties:
                        id:
                          type: integer
                        patient_id:
                          type: integer
                        location_id:
                          type: integer
                          description: Clinic id (CDM locations)
                        created_at:
                          type: string
                          format: date-time
                        updated_at:
                          type: string
                          format: date-time
                        source_system:
                          type: string
                        deleted:
                          type: string
                          format: date-time
                          nullable: true
                  meta:
                    type: object
                    required:
                    - page
                    - items
                    - count
                    - pages
                    properties:
                      page:
                        type: integer
                      items:
                        type: integer
                      count:
                        type: integer
                      pages:
                        type: integer
                      next:
                        type: integer
                        nullable: true
                      prev:
                        type: integer
                        nullable: true
        '404':
          description: no such patient in the principal's scope
  "/api/v2/patients/{patient_id}/locations/{id}":
    get:
      summary: Show a patient clinic assignment
      tags:
      - Patient locations
      security:
      - oauth2: []
      parameters:
      - name: patient_id
        in: path
        required: true
        schema:
          type: integer
      - name: id
        in: path
        required: true
        schema:
          type: integer
      responses:
        '200':
          description: the clinic assignment in CDM patient_locations shape
          content:
            application/json:
              schema:
                type: object
                required:
                - id
                - patient_id
                - location_id
                properties:
                  id:
                    type: integer
                  patient_id:
                    type: integer
                  location_id:
                    type: integer
                    description: Clinic id (CDM locations)
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
                  source_system:
                    type: string
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
        '404':
          description: no such assignment for this patient
  "/api/v2/patients/{patient_id}/phones":
    get:
      summary: List a patient's phones
      tags:
      - Patient phones
      security:
      - oauth2: []
      parameters:
      - name: patient_id
        in: path
        required: true
        schema:
          type: integer
      - name: page
        in: query
        required: false
        schema:
          type: integer
      - name: items
        in: query
        required: false
        schema:
          type: integer
      responses:
        '200':
          description: the patient's kept phone numbers, paginated in the { data,
            meta } envelope
          content:
            application/json:
              schema:
                type: object
                required:
                - data
                - meta
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      required:
                      - id
                      - patient_id
                      - phone_number
                      properties:
                        id:
                          type: integer
                        patient_id:
                          type: integer
                        phone_type:
                          type: string
                          nullable: true
                        phone_number:
                          type: string
                        country_code:
                          type: string
                          nullable: true
                        preferred_at:
                          type: string
                          format: date-time
                          nullable: true
                        created_at:
                          type: string
                          format: date-time
                        updated_at:
                          type: string
                          format: date-time
                        source_system:
                          type: string
                        deleted:
                          type: string
                          format: date-time
                          nullable: true
                          description: Soft-delete timestamp; null when the record
                            is live
                  meta:
                    type: object
                    required:
                    - page
                    - items
                    - count
                    - pages
                    properties:
                      page:
                        type: integer
                      items:
                        type: integer
                      count:
                        type: integer
                      pages:
                        type: integer
                      next:
                        type: integer
                        nullable: true
                      prev:
                        type: integer
                        nullable: true
        '404':
          description: no such patient in the principal's scope
    post:
      summary: Create a patient phone
      tags:
      - Patient phones
      security:
      - oauth2: []
      parameters:
      - "$ref": "#/components/parameters/IdempotencyKey"
      - name: patient_id
        in: path
        required: true
        schema:
          type: integer
      responses:
        '201':
          description: the created phone in CDM shape; one canonical.v0.patient_phone.created
            event is published
          content:
            application/json:
              schema:
                type: object
                required:
                - id
                - patient_id
                - phone_number
                properties:
                  id:
                    type: integer
                  patient_id:
                    type: integer
                  phone_type:
                    type: string
                    nullable: true
                  phone_number:
                    type: string
                  country_code:
                    type: string
                    nullable: true
                  preferred_at:
                    type: string
                    format: date-time
                    nullable: true
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
                  source_system:
                    type: string
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
                    description: Soft-delete timestamp; null when the record is live
        '422':
          description: a second kept primary is rejected
        '404':
          description: no such patient in the principal's scope
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                phone_type:
                  type: string
                  enum:
                  - primary
                  - mobile
                  - home
                  - work
                  - other
                phone_number:
                  type: string
                country_code:
                  type: string
                preferred_at:
                  type: string
                  format: date-time
                  nullable: true
              required:
              - phone_type
              - phone_number
  "/api/v2/patients/{patient_id}/phones/{id}":
    get:
      summary: Show a patient phone
      tags:
      - Patient phones
      security:
      - oauth2: []
      parameters:
      - name: patient_id
        in: path
        required: true
        schema:
          type: integer
      - name: id
        in: path
        required: true
        schema:
          type: integer
      responses:
        '200':
          description: the phone in CDM shape
          content:
            application/json:
              schema:
                type: object
                required:
                - id
                - patient_id
                - phone_number
                properties:
                  id:
                    type: integer
                  patient_id:
                    type: integer
                  phone_type:
                    type: string
                    nullable: true
                  phone_number:
                    type: string
                  country_code:
                    type: string
                    nullable: true
                  preferred_at:
                    type: string
                    format: date-time
                    nullable: true
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
                  source_system:
                    type: string
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
                    description: Soft-delete timestamp; null when the record is live
        '404':
          description: no such kept phone for this patient — also the case for a discarded
            phone
    patch:
      summary: Update a patient phone
      tags:
      - Patient phones
      security:
      - oauth2: []
      parameters:
      - "$ref": "#/components/parameters/IdempotencyKey"
      - name: patient_id
        in: path
        required: true
        schema:
          type: integer
      - name: id
        in: path
        required: true
        schema:
          type: integer
      responses:
        '200':
          description: the updated phone in CDM shape; one canonical.v0.patient_phone.updated
            event is published when something changed
          content:
            application/json:
              schema:
                type: object
                required:
                - id
                - patient_id
                - phone_number
                properties:
                  id:
                    type: integer
                  patient_id:
                    type: integer
                  phone_type:
                    type: string
                    nullable: true
                  phone_number:
                    type: string
                  country_code:
                    type: string
                    nullable: true
                  preferred_at:
                    type: string
                    format: date-time
                    nullable: true
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
                  source_system:
                    type: string
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
                    description: Soft-delete timestamp; null when the record is live
        '404':
          description: no such kept phone for this patient
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                phone_type:
                  type: string
                  enum:
                  - primary
                  - mobile
                  - home
                  - work
                  - other
                phone_number:
                  type: string
                country_code:
                  type: string
                preferred_at:
                  type: string
                  format: date-time
                  nullable: true
    delete:
      summary: Discard a patient phone
      tags:
      - Patient phones
      security:
      - oauth2: []
      parameters:
      - "$ref": "#/components/parameters/IdempotencyKey"
      - name: patient_id
        in: path
        required: true
        schema:
          type: integer
      - name: id
        in: path
        required: true
        schema:
          type: integer
      responses:
        '200':
          description: the discarded phone in CDM shape; one canonical.v0.patient_phone.deleted
            event is published
          content:
            application/json:
              schema:
                type: object
                required:
                - id
                - patient_id
                - phone_number
                properties:
                  id:
                    type: integer
                  patient_id:
                    type: integer
                  phone_type:
                    type: string
                    nullable: true
                  phone_number:
                    type: string
                  country_code:
                    type: string
                    nullable: true
                  preferred_at:
                    type: string
                    format: date-time
                    nullable: true
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
                  source_system:
                    type: string
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
                    description: Soft-delete timestamp; null when the record is live
        '404':
          description: no such kept phone for this patient — an already-discarded
            phone cannot be discarded again
  "/api/v2/patients/{patient_id}/relationships":
    get:
      summary: List a patient's relationships
      tags:
      - Patient relationships
      security:
      - oauth2: []
      parameters:
      - name: patient_id
        in: path
        required: true
        schema:
          type: integer
      - name: page
        in: query
        required: false
        description: 1-based page number
        schema:
          type: integer
      - name: items
        in: query
        required: false
        description: Page size (capped at 100)
        schema:
          type: integer
      responses:
        '200':
          description: the patient's active relationships, from both directions of
            the link, paginated in the { data, meta } envelope
          content:
            application/json:
              schema:
                type: object
                required:
                - data
                - meta
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      required:
                      - id
                      - patient_id
                      - related_patient_id
                      - relationship_type
                      properties:
                        id:
                          type: integer
                        patient_id:
                          type: integer
                        related_patient_id:
                          type: integer
                        relationship_type:
                          type: string
                        same_sex_couple:
                          type: boolean
                          nullable: true
                        active_from:
                          type: string
                          format: date
                          nullable: true
                        active_to:
                          type: string
                          format: date
                          nullable: true
                        deleted:
                          type: string
                          format: date-time
                          nullable: true
                          description: Soft-delete timestamp; null when the record
                            is live
                        created_at:
                          type: string
                          format: date-time
                        updated_at:
                          type: string
                          format: date-time
                        source_system:
                          type: string
                  meta:
                    type: object
                    required:
                    - page
                    - items
                    - count
                    - pages
                    properties:
                      page:
                        type: integer
                      items:
                        type: integer
                      count:
                        type: integer
                      pages:
                        type: integer
                      next:
                        type: integer
                        nullable: true
                      prev:
                        type: integer
                        nullable: true
        '404':
          description: no such patient in the principal's scope
    post:
      summary: Link a partner
      tags:
      - Patient relationships
      security:
      - oauth2: []
      parameters:
      - "$ref": "#/components/parameters/IdempotencyKey"
      - name: patient_id
        in: path
        required: true
        schema:
          type: integer
      responses:
        '201':
          description: the created relationship in CDM shape; one canonical.v0.patient_relationship.created
            event is published
          content:
            application/json:
              schema:
                type: object
                required:
                - id
                - patient_id
                - related_patient_id
                - relationship_type
                properties:
                  id:
                    type: integer
                  patient_id:
                    type: integer
                  related_patient_id:
                    type: integer
                  relationship_type:
                    type: string
                  same_sex_couple:
                    type: boolean
                    nullable: true
                  active_from:
                    type: string
                    format: date
                    nullable: true
                  active_to:
                    type: string
                    format: date
                    nullable: true
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
                    description: Soft-delete timestamp; null when the record is live
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
                  source_system:
                    type: string
        '200':
          description: the patients were already linked — the existing active relationship,
            unchanged, and no event
        '422':
          description: the link is invalid — here a related patient outside the principal's
            scope
        '404':
          description: no such patient in the principal's scope
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - related_patient_id
              - relationship_type
              properties:
                related_patient_id:
                  type: integer
                relationship_type:
                  type: string
                  enum:
                  - partner
                  - married
  "/api/v2/patients/{patient_id}/relationships/{id}":
    get:
      summary: Show a relationship
      tags:
      - Patient relationships
      security:
      - oauth2: []
      parameters:
      - name: patient_id
        in: path
        required: true
        schema:
          type: integer
      - name: id
        in: path
        required: true
        schema:
          type: integer
      responses:
        '200':
          description: the relationship in CDM shape
          content:
            application/json:
              schema:
                type: object
                required:
                - id
                - patient_id
                - related_patient_id
                - relationship_type
                properties:
                  id:
                    type: integer
                  patient_id:
                    type: integer
                  related_patient_id:
                    type: integer
                  relationship_type:
                    type: string
                  same_sex_couple:
                    type: boolean
                    nullable: true
                  active_from:
                    type: string
                    format: date
                    nullable: true
                  active_to:
                    type: string
                    format: date
                    nullable: true
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
                    description: Soft-delete timestamp; null when the record is live
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
                  source_system:
                    type: string
        '404':
          description: no such active relationship for this patient — also the case
            for an ended link
    delete:
      summary: End a relationship
      tags:
      - Patient relationships
      security:
      - oauth2: []
      parameters:
      - "$ref": "#/components/parameters/IdempotencyKey"
      - name: patient_id
        in: path
        required: true
        schema:
          type: integer
      - name: id
        in: path
        required: true
        schema:
          type: integer
      responses:
        '200':
          description: the ended relationship in its final CDM state; one canonical.v0.patient_relationship.ended
            event is published
          content:
            application/json:
              schema:
                type: object
                required:
                - id
                - patient_id
                - related_patient_id
                - relationship_type
                properties:
                  id:
                    type: integer
                  patient_id:
                    type: integer
                  related_patient_id:
                    type: integer
                  relationship_type:
                    type: string
                  same_sex_couple:
                    type: boolean
                    nullable: true
                  active_from:
                    type: string
                    format: date
                    nullable: true
                  active_to:
                    type: string
                    format: date
                    nullable: true
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
                    description: Soft-delete timestamp; null when the record is live
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
                  source_system:
                    type: string
        '404':
          description: no such active relationship for this patient — an already-ended
            link cannot be ended again
  "/api/v2/patients":
    get:
      summary: List patients
      tags:
      - Patients
      security:
      - oauth2: []
      parameters:
      - name: page
        in: query
        required: false
        description: 1-based page number
        schema:
          type: integer
      - name: items
        in: query
        required: false
        description: Page size (capped at 100)
        schema:
          type: integer
      - name: q[search]
        in: query
        required: false
        description: 'Free-text query: name, identity-management id, or date of birth'
        schema:
          type: string
      - name: q[first_name_cont]
        in: query
        required: false
        description: First name contains
        schema:
          type: string
      - name: q[last_name_cont]
        in: query
        required: false
        description: Last name contains
        schema:
          type: string
      - name: q[email_eq]
        in: query
        required: false
        description: Email equals
        schema:
          type: string
      - name: q[date_of_birth_eq]
        in: query
        schema:
          type: string
          format: date
        required: false
        description: Date of birth equals (ISO8601 date)
      - name: q[external_identifier_type_eq]
        in: query
        required: false
        description: Active external identifier type equals, namespaced as it reads
          back (e.g. custom-MRN)
        schema:
          type: string
      - name: q[external_identifier_value_eq]
        in: query
        required: false
        description: Active external identifier value equals; combined with the type
          filter both must match the same identifier
        schema:
          type: string
      - name: q[external_identifier_eq]
        in: query
        required: false
        description: Exact, case-sensitive external identifier
        schema:
          type: string
      responses:
        '200':
          description: the principal's patients (matching the q filters when given),
            paginated in the { data, meta } envelope
          content:
            application/json:
              schema:
                type: object
                required:
                - data
                - meta
                properties:
                  data:
                    type: array
                    items:
                      title: canonical.v0.patient record
                      description: The resource's current CDM state, as projected
                        by canonical_v0_patients_v01. Generated from the vendored
                        CDM DDL, so it cannot fall behind the columns the view returns.
                      type: object
                      required:
                      - id
                      properties:
                        id:
                          type: integer
                        first_name:
                          type: string
                          nullable: true
                        last_name:
                          type: string
                          nullable: true
                        external_identifier:
                          type: string
                          nullable: true
                        title:
                          type: string
                          nullable: true
                        patient_identity_management_id:
                          type: string
                          nullable: true
                        middle_name:
                          type: string
                          nullable: true
                        preferred_name:
                          type: string
                          nullable: true
                        full_legal_name:
                          type: string
                          nullable: true
                        date_of_birth:
                          type: string
                          format: date
                          nullable: true
                        email:
                          type: string
                          nullable: true
                        sex_assigned_at_birth:
                          type: string
                          nullable: true
                          enum:
                          - not_specified
                          - female
                          - male
                        gender_identity:
                          type: string
                          nullable: true
                        pronouns:
                          type: string
                          nullable: true
                        ethnicity:
                          type: string
                          nullable: true
                        fathers_ethnicity:
                          type: string
                          nullable: true
                        mothers_ethnicity:
                          type: string
                          nullable: true
                        country_of_birth:
                          type: string
                          nullable: true
                        town_or_city_of_birth:
                          type: string
                          nullable: true
                        preferred_language:
                          type: string
                          nullable: true
                          description: 'ISO 639-1 two-letter language code, lowercase
                            (for example en, ro, ar). A full BCP 47 tag is narrowed
                            to its language subtag, so en-GB records as en. Also accepted,
                            for languages ISO 639-1 cannot express: yue, ckb, prs.'
                        marital_status:
                          type: string
                          nullable: true
                          enum:
                          - single
                          - married
                          - separated
                          - divorced
                          - widowed
                          - never_married
                          - in_civil_partnership
                        blood_group:
                          type: string
                          nullable: true
                        rhesus_factor:
                          type: string
                          nullable: true
                        address_line_1:
                          type: string
                          nullable: true
                        address_line_2:
                          type: string
                          nullable: true
                        town_or_city:
                          type: string
                          nullable: true
                        state_or_province:
                          type: string
                          nullable: true
                        postcode:
                          type: string
                          nullable: true
                        country:
                          type: string
                          nullable: true
                        is_donor:
                          type: boolean
                          nullable: true
                        is_deceased:
                          type: boolean
                          nullable: true
                        primary_user_id:
                          type: integer
                          nullable: true
                        brand_id:
                          type: integer
                          nullable: true
                        fund_source_id:
                          type: integer
                          nullable: true
                        metadata:
                          type: object
                          nullable: true
                        initial_contact_at:
                          type: string
                          format: date-time
                          nullable: true
                        first_seen_at:
                          type: string
                          format: date-time
                          nullable: true
                        source_system:
                          type: string
                          nullable: true
                        deleted:
                          type: string
                          format: date-time
                          nullable: true
                        created_at:
                          type: string
                          format: date-time
                          nullable: true
                        updated_at:
                          type: string
                          format: date-time
                          nullable: true
                  meta:
                    type: object
                    required:
                    - page
                    - items
                    - count
                    - pages
                    properties:
                      page:
                        type: integer
                      items:
                        type: integer
                      count:
                        type: integer
                      pages:
                        type: integer
                      next:
                        type: integer
                        nullable: true
                      prev:
                        type: integer
                        nullable: true
    post:
      summary: Create a patient
      tags:
      - Patients
      security:
      - oauth2: []
      parameters:
      - "$ref": "#/components/parameters/IdempotencyKey"
      responses:
        '201':
          description: the created patient in CDM shape
          content:
            application/json:
              schema:
                title: canonical.v0.patient record
                description: The resource's current CDM state, as projected by canonical_v0_patients_v01.
                  Generated from the vendored CDM DDL, so it cannot fall behind the
                  columns the view returns.
                type: object
                required:
                - id
                properties:
                  id:
                    type: integer
                  first_name:
                    type: string
                    nullable: true
                  last_name:
                    type: string
                    nullable: true
                  external_identifier:
                    type: string
                    nullable: true
                  title:
                    type: string
                    nullable: true
                  patient_identity_management_id:
                    type: string
                    nullable: true
                  middle_name:
                    type: string
                    nullable: true
                  preferred_name:
                    type: string
                    nullable: true
                  full_legal_name:
                    type: string
                    nullable: true
                  date_of_birth:
                    type: string
                    format: date
                    nullable: true
                  email:
                    type: string
                    nullable: true
                  sex_assigned_at_birth:
                    type: string
                    nullable: true
                    enum:
                    - not_specified
                    - female
                    - male
                  gender_identity:
                    type: string
                    nullable: true
                  pronouns:
                    type: string
                    nullable: true
                  ethnicity:
                    type: string
                    nullable: true
                  fathers_ethnicity:
                    type: string
                    nullable: true
                  mothers_ethnicity:
                    type: string
                    nullable: true
                  country_of_birth:
                    type: string
                    nullable: true
                  town_or_city_of_birth:
                    type: string
                    nullable: true
                  preferred_language:
                    type: string
                    nullable: true
                    description: 'ISO 639-1 two-letter language code, lowercase (for
                      example en, ro, ar). A full BCP 47 tag is narrowed to its language
                      subtag, so en-GB records as en. Also accepted, for languages
                      ISO 639-1 cannot express: yue, ckb, prs.'
                  marital_status:
                    type: string
                    nullable: true
                    enum:
                    - single
                    - married
                    - separated
                    - divorced
                    - widowed
                    - never_married
                    - in_civil_partnership
                  blood_group:
                    type: string
                    nullable: true
                  rhesus_factor:
                    type: string
                    nullable: true
                  address_line_1:
                    type: string
                    nullable: true
                  address_line_2:
                    type: string
                    nullable: true
                  town_or_city:
                    type: string
                    nullable: true
                  state_or_province:
                    type: string
                    nullable: true
                  postcode:
                    type: string
                    nullable: true
                  country:
                    type: string
                    nullable: true
                  is_donor:
                    type: boolean
                    nullable: true
                  is_deceased:
                    type: boolean
                    nullable: true
                  primary_user_id:
                    type: integer
                    nullable: true
                  brand_id:
                    type: integer
                    nullable: true
                  fund_source_id:
                    type: integer
                    nullable: true
                  metadata:
                    type: object
                    nullable: true
                  initial_contact_at:
                    type: string
                    format: date-time
                    nullable: true
                  first_seen_at:
                    type: string
                    format: date-time
                    nullable: true
                  source_system:
                    type: string
                    nullable: true
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
                  created_at:
                    type: string
                    format: date-time
                    nullable: true
                  updated_at:
                    type: string
                    format: date-time
                    nullable: true
        '422':
          description: invalid patient attributes
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                external_identifier:
                  type: string
                  nullable: true
                  description: Integrator-assigned identifier, unique per account
                    and resource type. Omit to preserve; null clears it.
                first_name:
                  type: string
                middle_name:
                  type: string
                last_name:
                  type: string
                email:
                  type: string
                date_of_birth:
                  type: string
                  format: date
                  description: ISO8601 date — maps to core birthday
                sex_assigned_at_birth:
                  type: string
                  enum:
                  - not_specified
                  - female
                  - male
                marital_status:
                  type: string
                  enum:
                  - single
                  - married
                  - separated
                  - divorced
                  - widowed
                  - never_married
                  - in_civil_partnership
                ethnicity:
                  type: string
                preferred_language:
                  type: string
                  description: 'ISO 639-1 two-letter language code, lowercase (for
                    example en, ro, ar). A full BCP 47 tag is narrowed to its language
                    subtag, so en-GB records as en. Also accepted, for languages ISO
                    639-1 cannot express: yue, ckb, prs.'
                address_line_1:
                  type: string
                address_line_2:
                  type: string
                town_or_city:
                  type: string
                state_or_province:
                  type: string
                postcode:
                  type: string
                country:
                  type: string
                  description: the address country, not a phone dialling code
                patient_identity_management_id:
                  type: string
                  description: the identity-management id; create only, rejected on
                    update
                clinic_ids:
                  type: array
                  items:
                    type: integer
                  description: assigns the patient to these clinics; create only,
                    rejected on update
  "/api/v2/patients/{id}":
    get:
      summary: Show a patient
      tags:
      - Patients
      security:
      - oauth2: []
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: integer
      responses:
        '200':
          description: the patient in CDM shape
          content:
            application/json:
              schema:
                title: canonical.v0.patient record
                description: The resource's current CDM state, as projected by canonical_v0_patients_v01.
                  Generated from the vendored CDM DDL, so it cannot fall behind the
                  columns the view returns.
                type: object
                required:
                - id
                properties:
                  id:
                    type: integer
                  first_name:
                    type: string
                    nullable: true
                  last_name:
                    type: string
                    nullable: true
                  external_identifier:
                    type: string
                    nullable: true
                  title:
                    type: string
                    nullable: true
                  patient_identity_management_id:
                    type: string
                    nullable: true
                  middle_name:
                    type: string
                    nullable: true
                  preferred_name:
                    type: string
                    nullable: true
                  full_legal_name:
                    type: string
                    nullable: true
                  date_of_birth:
                    type: string
                    format: date
                    nullable: true
                  email:
                    type: string
                    nullable: true
                  sex_assigned_at_birth:
                    type: string
                    nullable: true
                    enum:
                    - not_specified
                    - female
                    - male
                  gender_identity:
                    type: string
                    nullable: true
                  pronouns:
                    type: string
                    nullable: true
                  ethnicity:
                    type: string
                    nullable: true
                  fathers_ethnicity:
                    type: string
                    nullable: true
                  mothers_ethnicity:
                    type: string
                    nullable: true
                  country_of_birth:
                    type: string
                    nullable: true
                  town_or_city_of_birth:
                    type: string
                    nullable: true
                  preferred_language:
                    type: string
                    nullable: true
                    description: 'ISO 639-1 two-letter language code, lowercase (for
                      example en, ro, ar). A full BCP 47 tag is narrowed to its language
                      subtag, so en-GB records as en. Also accepted, for languages
                      ISO 639-1 cannot express: yue, ckb, prs.'
                  marital_status:
                    type: string
                    nullable: true
                    enum:
                    - single
                    - married
                    - separated
                    - divorced
                    - widowed
                    - never_married
                    - in_civil_partnership
                  blood_group:
                    type: string
                    nullable: true
                  rhesus_factor:
                    type: string
                    nullable: true
                  address_line_1:
                    type: string
                    nullable: true
                  address_line_2:
                    type: string
                    nullable: true
                  town_or_city:
                    type: string
                    nullable: true
                  state_or_province:
                    type: string
                    nullable: true
                  postcode:
                    type: string
                    nullable: true
                  country:
                    type: string
                    nullable: true
                  is_donor:
                    type: boolean
                    nullable: true
                  is_deceased:
                    type: boolean
                    nullable: true
                  primary_user_id:
                    type: integer
                    nullable: true
                  brand_id:
                    type: integer
                    nullable: true
                  fund_source_id:
                    type: integer
                    nullable: true
                  metadata:
                    type: object
                    nullable: true
                  initial_contact_at:
                    type: string
                    format: date-time
                    nullable: true
                  first_seen_at:
                    type: string
                    format: date-time
                    nullable: true
                  source_system:
                    type: string
                    nullable: true
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
                  created_at:
                    type: string
                    format: date-time
                    nullable: true
                  updated_at:
                    type: string
                    format: date-time
                    nullable: true
        '404':
          description: no such patient in the principal's scope
    patch:
      summary: Update a patient
      tags:
      - Patients
      security:
      - oauth2: []
      parameters:
      - "$ref": "#/components/parameters/IdempotencyKey"
      - name: id
        in: path
        required: true
        schema:
          type: integer
      responses:
        '200':
          description: the updated patient in CDM shape
          content:
            application/json:
              schema:
                title: canonical.v0.patient record
                description: The resource's current CDM state, as projected by canonical_v0_patients_v01.
                  Generated from the vendored CDM DDL, so it cannot fall behind the
                  columns the view returns.
                type: object
                required:
                - id
                properties:
                  id:
                    type: integer
                  first_name:
                    type: string
                    nullable: true
                  last_name:
                    type: string
                    nullable: true
                  external_identifier:
                    type: string
                    nullable: true
                  title:
                    type: string
                    nullable: true
                  patient_identity_management_id:
                    type: string
                    nullable: true
                  middle_name:
                    type: string
                    nullable: true
                  preferred_name:
                    type: string
                    nullable: true
                  full_legal_name:
                    type: string
                    nullable: true
                  date_of_birth:
                    type: string
                    format: date
                    nullable: true
                  email:
                    type: string
                    nullable: true
                  sex_assigned_at_birth:
                    type: string
                    nullable: true
                    enum:
                    - not_specified
                    - female
                    - male
                  gender_identity:
                    type: string
                    nullable: true
                  pronouns:
                    type: string
                    nullable: true
                  ethnicity:
                    type: string
                    nullable: true
                  fathers_ethnicity:
                    type: string
                    nullable: true
                  mothers_ethnicity:
                    type: string
                    nullable: true
                  country_of_birth:
                    type: string
                    nullable: true
                  town_or_city_of_birth:
                    type: string
                    nullable: true
                  preferred_language:
                    type: string
                    nullable: true
                    description: 'ISO 639-1 two-letter language code, lowercase (for
                      example en, ro, ar). A full BCP 47 tag is narrowed to its language
                      subtag, so en-GB records as en. Also accepted, for languages
                      ISO 639-1 cannot express: yue, ckb, prs.'
                  marital_status:
                    type: string
                    nullable: true
                    enum:
                    - single
                    - married
                    - separated
                    - divorced
                    - widowed
                    - never_married
                    - in_civil_partnership
                  blood_group:
                    type: string
                    nullable: true
                  rhesus_factor:
                    type: string
                    nullable: true
                  address_line_1:
                    type: string
                    nullable: true
                  address_line_2:
                    type: string
                    nullable: true
                  town_or_city:
                    type: string
                    nullable: true
                  state_or_province:
                    type: string
                    nullable: true
                  postcode:
                    type: string
                    nullable: true
                  country:
                    type: string
                    nullable: true
                  is_donor:
                    type: boolean
                    nullable: true
                  is_deceased:
                    type: boolean
                    nullable: true
                  primary_user_id:
                    type: integer
                    nullable: true
                  brand_id:
                    type: integer
                    nullable: true
                  fund_source_id:
                    type: integer
                    nullable: true
                  metadata:
                    type: object
                    nullable: true
                  initial_contact_at:
                    type: string
                    format: date-time
                    nullable: true
                  first_seen_at:
                    type: string
                    format: date-time
                    nullable: true
                  source_system:
                    type: string
                    nullable: true
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
                  created_at:
                    type: string
                    format: date-time
                    nullable: true
                  updated_at:
                    type: string
                    format: date-time
                    nullable: true
        '422':
          description: invalid patient attributes
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                external_identifier:
                  type: string
                  nullable: true
                  description: Integrator-assigned identifier, unique per account
                    and resource type. Omit to preserve; null clears it.
                first_name:
                  type: string
                middle_name:
                  type: string
                last_name:
                  type: string
                email:
                  type: string
                date_of_birth:
                  type: string
                  format: date
                  description: ISO8601 date — maps to core birthday
                sex_assigned_at_birth:
                  type: string
                  enum:
                  - not_specified
                  - female
                  - male
                marital_status:
                  type: string
                  enum:
                  - single
                  - married
                  - separated
                  - divorced
                  - widowed
                  - never_married
                  - in_civil_partnership
                ethnicity:
                  type: string
                preferred_language:
                  type: string
                  description: 'ISO 639-1 two-letter language code, lowercase (for
                    example en, ro, ar). A full BCP 47 tag is narrowed to its language
                    subtag, so en-GB records as en. Also accepted, for languages ISO
                    639-1 cannot express: yue, ckb, prs.'
                address_line_1:
                  type: string
                address_line_2:
                  type: string
                town_or_city:
                  type: string
                state_or_province:
                  type: string
                postcode:
                  type: string
                country:
                  type: string
                  description: the address country, not a phone dialling code
  "/api/v2/rooms":
    get:
      summary: List rooms
      tags:
      - Rooms
      security:
      - oauth2: []
      parameters:
      - name: page
        in: query
        required: false
        description: 1-based page number
        schema:
          type: integer
      - name: items
        in: query
        required: false
        description: Page size (capped at 100)
        schema:
          type: integer
      responses:
        '200':
          description: the principal's bookable rooms, paginated in the { data, meta
            } envelope
          content:
            application/json:
              schema:
                type: object
                required:
                - data
                - meta
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      required:
                      - id
                      - name
                      properties:
                        id:
                          type: integer
                        name:
                          type: string
                        location_id:
                          type: integer
                          nullable: true
                          description: The clinic this room belongs to
                        is_active:
                          type: boolean
                          nullable: true
                        created_at:
                          type: string
                          format: date-time
                        updated_at:
                          type: string
                          format: date-time
                        source_system:
                          type: string
                        deleted:
                          type: string
                          format: date-time
                          nullable: true
                          description: Soft-delete timestamp; null when the record
                            is live
                  meta:
                    type: object
                    required:
                    - page
                    - items
                    - count
                    - pages
                    properties:
                      page:
                        type: integer
                      items:
                        type: integer
                      count:
                        type: integer
                      pages:
                        type: integer
                      next:
                        type: integer
                        nullable: true
                      prev:
                        type: integer
                        nullable: true
  "/api/v2/rooms/{id}":
    get:
      summary: Show a room
      tags:
      - Rooms
      security:
      - oauth2: []
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: integer
      responses:
        '200':
          description: the room in CDM shape
          content:
            application/json:
              schema:
                type: object
                required:
                - id
                - name
                properties:
                  id:
                    type: integer
                  name:
                    type: string
                  location_id:
                    type: integer
                    nullable: true
                    description: The clinic this room belongs to
                  is_active:
                    type: boolean
                    nullable: true
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
                  source_system:
                    type: string
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
                    description: Soft-delete timestamp; null when the record is live
        '404':
          description: no such room in the principal's scope
  "/api/v2/scheduler/calendars":
    get:
      summary: List calendars
      tags:
      - Scheduler calendars
      security:
      - oauth2: []
      parameters:
      - name: page
        in: query
        required: false
        schema:
          type: integer
      - name: items
        in: query
        required: false
        schema:
          type: integer
      responses:
        '200':
          description: the principal's calendars, paginated in the { data, meta }
            envelope
          content:
            application/json:
              schema:
                type: object
                required:
                - data
                - meta
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      required:
                      - id
                      properties:
                        id:
                          type: integer
                        name:
                          type: string
                          nullable: true
                        created_at:
                          type: string
                          format: date-time
                        updated_at:
                          type: string
                          format: date-time
                        source_system:
                          type: string
                        deleted:
                          type: string
                          format: date-time
                          nullable: true
                  meta:
                    type: object
                    required:
                    - page
                    - items
                    - count
                    - pages
                    properties:
                      page:
                        type: integer
                      items:
                        type: integer
                      count:
                        type: integer
                      pages:
                        type: integer
                      next:
                        type: integer
                        nullable: true
                      prev:
                        type: integer
                        nullable: true
  "/api/v2/scheduler/calendars/{id}":
    get:
      summary: Show a calendar
      tags:
      - Scheduler calendars
      security:
      - oauth2: []
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: integer
      responses:
        '200':
          description: the calendar in CDM shape
          content:
            application/json:
              schema:
                type: object
                required:
                - id
                properties:
                  id:
                    type: integer
                  name:
                    type: string
                    nullable: true
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
                  source_system:
                    type: string
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
        '404':
          description: no such calendar in the principal's scope
  "/api/v2/scheduler/event_statuses":
    get:
      summary: List scheduler event statuses
      tags:
      - Scheduler event statuses
      security:
      - oauth2: []
      parameters:
      - name: page
        in: query
        required: false
        description: 1-based page number
        schema:
          type: integer
      - name: items
        in: query
        required: false
        description: Page size (capped at 100)
        schema:
          type: integer
      responses:
        '200':
          description: the principal's scheduler event statuses, paginated in the
            { data, meta } envelope
          content:
            application/json:
              schema:
                type: object
                required:
                - data
                - meta
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      required:
                      - id
                      - name
                      properties:
                        id:
                          type: integer
                        name:
                          type: string
                        is_active:
                          type: boolean
                          description: Whether the status can still be applied to
                            an appointment. A deactivated status stays on any appointment
                            already holding it
                        created_at:
                          type: string
                          format: date-time
                        updated_at:
                          type: string
                          format: date-time
                        source_system:
                          type: string
                        deleted:
                          type: string
                          format: date-time
                          nullable: true
                          description: 'Soft-delete timestamp. Always null: event
                            statuses are deactivated, not deleted'
                  meta:
                    type: object
                    required:
                    - page
                    - items
                    - count
                    - pages
                    properties:
                      page:
                        type: integer
                      items:
                        type: integer
                      count:
                        type: integer
                      pages:
                        type: integer
                      next:
                        type: integer
                        nullable: true
                      prev:
                        type: integer
                        nullable: true
    post:
      summary: Create a scheduler event status
      tags:
      - Scheduler event statuses
      security:
      - oauth2: []
      parameters:
      - "$ref": "#/components/parameters/IdempotencyKey"
      responses:
        '201':
          description: the created scheduler event status in CDM shape
          content:
            application/json:
              schema:
                type: object
                required:
                - id
                - name
                properties:
                  id:
                    type: integer
                  name:
                    type: string
                  is_active:
                    type: boolean
                    description: Whether the status can still be applied to an appointment.
                      A deactivated status stays on any appointment already holding
                      it
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
                  source_system:
                    type: string
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
                    description: 'Soft-delete timestamp. Always null: event statuses
                      are deactivated, not deleted'
        '422':
          description: invalid — name already taken
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - name
              properties:
                name:
                  type: string
                is_active:
                  type: boolean
                  description: Whether staff can apply the status straight away. Defaults
                    to false; afterwards use the activate / deactivate endpoints
  "/api/v2/scheduler/event_statuses/{id}":
    get:
      summary: Show a scheduler event status
      tags:
      - Scheduler event statuses
      security:
      - oauth2: []
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: integer
      responses:
        '200':
          description: the scheduler event status in CDM shape
          content:
            application/json:
              schema:
                type: object
                required:
                - id
                - name
                properties:
                  id:
                    type: integer
                  name:
                    type: string
                  is_active:
                    type: boolean
                    description: Whether the status can still be applied to an appointment.
                      A deactivated status stays on any appointment already holding
                      it
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
                  source_system:
                    type: string
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
                    description: 'Soft-delete timestamp. Always null: event statuses
                      are deactivated, not deleted'
        '404':
          description: no such scheduler event status in the principal's scope
    patch:
      summary: Rename a scheduler event status
      tags:
      - Scheduler event statuses
      security:
      - oauth2: []
      parameters:
      - "$ref": "#/components/parameters/IdempotencyKey"
      - name: id
        in: path
        required: true
        schema:
          type: integer
      responses:
        '200':
          description: the updated scheduler event status in CDM shape
          content:
            application/json:
              schema:
                type: object
                required:
                - id
                - name
                properties:
                  id:
                    type: integer
                  name:
                    type: string
                  is_active:
                    type: boolean
                    description: Whether the status can still be applied to an appointment.
                      A deactivated status stays on any appointment already holding
                      it
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
                  source_system:
                    type: string
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
                    description: 'Soft-delete timestamp. Always null: event statuses
                      are deactivated, not deleted'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - name
              properties:
                name:
                  type: string
  "/api/v2/scheduler/event_statuses/{id}/activate":
    post:
      summary: Activate a scheduler event status
      tags:
      - Scheduler event statuses
      security:
      - oauth2: []
      parameters:
      - "$ref": "#/components/parameters/IdempotencyKey"
      - name: id
        in: path
        required: true
        schema:
          type: integer
      responses:
        '200':
          description: the activated scheduler event status in CDM shape
          content:
            application/json:
              schema:
                type: object
                required:
                - id
                - name
                properties:
                  id:
                    type: integer
                  name:
                    type: string
                  is_active:
                    type: boolean
                    description: Whether the status can still be applied to an appointment.
                      A deactivated status stays on any appointment already holding
                      it
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
                  source_system:
                    type: string
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
                    description: 'Soft-delete timestamp. Always null: event statuses
                      are deactivated, not deleted'
  "/api/v2/scheduler/event_statuses/{id}/deactivate":
    post:
      summary: Deactivate a scheduler event status
      tags:
      - Scheduler event statuses
      security:
      - oauth2: []
      parameters:
      - "$ref": "#/components/parameters/IdempotencyKey"
      - name: id
        in: path
        required: true
        schema:
          type: integer
      responses:
        '200':
          description: the deactivated scheduler event status in CDM shape
          content:
            application/json:
              schema:
                type: object
                required:
                - id
                - name
                properties:
                  id:
                    type: integer
                  name:
                    type: string
                  is_active:
                    type: boolean
                    description: Whether the status can still be applied to an appointment.
                      A deactivated status stays on any appointment already holding
                      it
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
                  source_system:
                    type: string
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
                    description: 'Soft-delete timestamp. Always null: event statuses
                      are deactivated, not deleted'
  "/api/v2/scheduler/event_types":
    get:
      summary: List scheduler event types
      tags:
      - Scheduler event types
      security:
      - oauth2: []
      parameters:
      - name: page
        in: query
        required: false
        description: 1-based page number
        schema:
          type: integer
      - name: items
        in: query
        required: false
        description: Page size (capped at 100)
        schema:
          type: integer
      responses:
        '200':
          description: the principal's bookable event types, paginated in the { data,
            meta } envelope
          content:
            application/json:
              schema:
                type: object
                required:
                - data
                - meta
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      required:
                      - id
                      - name
                      properties:
                        id:
                          type: integer
                        code:
                          type: string
                          nullable: true
                        name:
                          type: string
                        category:
                          type: string
                          nullable: true
                        description:
                          type: string
                          nullable: true
                        duration:
                          type: integer
                          nullable: true
                        is_physical:
                          type: boolean
                          nullable: true
                        is_phone_call:
                          type: boolean
                          nullable: true
                        created_at:
                          type: string
                          format: date-time
                        updated_at:
                          type: string
                          format: date-time
                        source_system:
                          type: string
                        deleted:
                          type: string
                          format: date-time
                          nullable: true
                          description: Soft-delete timestamp; null when the record
                            is live
                  meta:
                    type: object
                    required:
                    - page
                    - items
                    - count
                    - pages
                    properties:
                      page:
                        type: integer
                      items:
                        type: integer
                      count:
                        type: integer
                      pages:
                        type: integer
                      next:
                        type: integer
                        nullable: true
                      prev:
                        type: integer
                        nullable: true
  "/api/v2/scheduler/event_types/{id}":
    get:
      summary: Show a scheduler event type
      tags:
      - Scheduler event types
      security:
      - oauth2: []
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: integer
      responses:
        '200':
          description: the scheduler event type in CDM shape
          content:
            application/json:
              schema:
                type: object
                required:
                - id
                - name
                properties:
                  id:
                    type: integer
                  code:
                    type: string
                    nullable: true
                  name:
                    type: string
                  category:
                    type: string
                    nullable: true
                  description:
                    type: string
                    nullable: true
                  duration:
                    type: integer
                    nullable: true
                  is_physical:
                    type: boolean
                    nullable: true
                  is_phone_call:
                    type: boolean
                    nullable: true
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
                  source_system:
                    type: string
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
                    description: Soft-delete timestamp; null when the record is live
        '404':
          description: no such event type in the principal's scope — also the case
            for a discarded one
  "/api/v2/scheduler/events/{event_id}/resources":
    get:
      summary: List an event's resources
      tags:
      - Scheduler event resources
      security:
      - oauth2: []
      parameters:
      - name: event_id
        in: path
        required: true
        schema:
          type: integer
      - name: page
        in: query
        required: false
        schema:
          type: integer
      - name: items
        in: query
        required: false
        schema:
          type: integer
      responses:
        '200':
          description: the event's resources, paginated in the { data, meta } envelope
          content:
            application/json:
              schema:
                type: object
                required:
                - data
                - meta
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      required:
                      - id
                      - scheduler_event_id
                      properties:
                        id:
                          type: integer
                        scheduler_event_id:
                          type: integer
                        user_id:
                          type: integer
                          nullable: true
                        team_id:
                          type: integer
                          nullable: true
                        room_id:
                          type: integer
                          nullable: true
                        calendar_id:
                          type: integer
                          nullable: true
                        created_at:
                          type: string
                          format: date-time
                        updated_at:
                          type: string
                          format: date-time
                        source_system:
                          type: string
                        deleted:
                          type: string
                          format: date-time
                          nullable: true
                  meta:
                    type: object
                    required:
                    - page
                    - items
                    - count
                    - pages
                    properties:
                      page:
                        type: integer
                      items:
                        type: integer
                      count:
                        type: integer
                      pages:
                        type: integer
                      next:
                        type: integer
                        nullable: true
                      prev:
                        type: integer
                        nullable: true
        '404':
          description: no such event in the principal's scope
  "/api/v2/scheduler/events/{event_id}/resources/{id}":
    get:
      summary: Show an event resource
      tags:
      - Scheduler event resources
      security:
      - oauth2: []
      parameters:
      - name: event_id
        in: path
        required: true
        schema:
          type: integer
      - name: id
        in: path
        required: true
        schema:
          type: integer
      responses:
        '200':
          description: the event resource in CDM shape
          content:
            application/json:
              schema:
                type: object
                required:
                - id
                - scheduler_event_id
                properties:
                  id:
                    type: integer
                  scheduler_event_id:
                    type: integer
                  user_id:
                    type: integer
                    nullable: true
                  team_id:
                    type: integer
                    nullable: true
                  room_id:
                    type: integer
                    nullable: true
                  calendar_id:
                    type: integer
                    nullable: true
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
                  source_system:
                    type: string
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
        '404':
          description: no such resource for this event
  "/api/v2/scheduler/events":
    get:
      summary: List scheduler events
      tags:
      - Scheduler events
      security:
      - oauth2: []
      parameters:
      - name: page
        in: query
        required: false
        description: 1-based page number
        schema:
          type: integer
      - name: items
        in: query
        required: false
        description: Page size (capped at 100)
        schema:
          type: integer
      - name: q[start_at_gteq]
        in: query
        schema:
          type: string
          format: date-time
        required: false
        description: Starts at or after (ISO8601)
      - name: q[start_at_lteq]
        in: query
        schema:
          type: string
          format: date-time
        required: false
        description: Starts at or before (ISO8601)
      - name: q[end_at_gteq]
        in: query
        schema:
          type: string
          format: date-time
        required: false
        description: Ends at or after (ISO8601)
      - name: q[end_at_lteq]
        in: query
        schema:
          type: string
          format: date-time
        required: false
        description: Ends at or before (ISO8601)
      - name: q[external_identifier_eq]
        in: query
        required: false
        description: Exact, case-sensitive external identifier
        schema:
          type: string
      - name: include
        in: query
        required: false
        description: Child resources to return under top-level `included`. Currently
          `scheduler_event_resources`. An unknown value is 400. Show and create wrap
          the record in `{ data, included }` when this is present; without it the
          body is unchanged. A misspelled `includes=` (plural) is ignored.
        schema:
          type: string
      responses:
        '200':
          description: the principal's scheduler events (matching the q filters when
            given), paginated in the { data, meta } envelope
          content:
            application/json:
              schema:
                type: object
                required:
                - data
                - meta
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      required:
                      - id
                      properties:
                        id:
                          type: integer
                        external_identifier:
                          type: string
                          nullable: true
                        event_type:
                          type: string
                          nullable: true
                        patient_id:
                          type: integer
                          nullable: true
                        scheduler_event_type_id:
                          type: integer
                          nullable: true
                        title:
                          type: string
                          nullable: true
                        start_at:
                          type: string
                          format: date-time
                          nullable: true
                        end_at:
                          type: string
                          format: date-time
                          nullable: true
                        all_day:
                          type: boolean
                          nullable: true
                        appointment_status:
                          type: string
                          nullable: true
                        location_id:
                          type: integer
                          nullable: true
                        meeting_type:
                          type: string
                          nullable: true
                          enum:
                          - in_person
                          - virtual
                          - phone_call
                          - external
                        source_system:
                          type: string
                          nullable: true
                  included:
                    type: object
                    properties:
                      scheduler_event_resources:
                        type: array
                        items:
                          type: object
                          required:
                          - id
                          - scheduler_event_id
                          properties:
                            id:
                              type: integer
                            scheduler_event_id:
                              type: integer
                            user_id:
                              type: integer
                              nullable: true
                            team_id:
                              type: integer
                              nullable: true
                            room_id:
                              type: integer
                              nullable: true
                  meta:
                    type: object
                    required:
                    - page
                    - items
                    - count
                    - pages
                    properties:
                      page:
                        type: integer
                      items:
                        type: integer
                      count:
                        type: integer
                      pages:
                        type: integer
                      next:
                        type: integer
                        nullable: true
                      prev:
                        type: integer
                        nullable: true
    post:
      summary: Book an appointment
      tags:
      - Scheduler events
      security:
      - oauth2: []
      parameters:
      - "$ref": "#/components/parameters/IdempotencyKey"
      - name: include
        in: query
        required: false
        description: Child resources to return under top-level `included`. Currently
          `scheduler_event_resources`. An unknown value is 400. Show and create wrap
          the record in `{ data, included }` when this is present; without it the
          body is unchanged. A misspelled `includes=` (plural) is ignored.
        schema:
          type: string
      responses:
        '201':
          description: the booked appointment in CDM shape (the slot payload plus
            a patient_id)
          content:
            application/json:
              schema:
                type: object
                required:
                - id
                properties:
                  id:
                    type: integer
                  external_identifier:
                    type: string
                    nullable: true
                  event_type:
                    type: string
                    nullable: true
                  patient_id:
                    type: integer
                    nullable: true
                  scheduler_event_type_id:
                    type: integer
                    nullable: true
                  title:
                    type: string
                    nullable: true
                  start_at:
                    type: string
                    format: date-time
                    nullable: true
                  end_at:
                    type: string
                    format: date-time
                    nullable: true
                  all_day:
                    type: boolean
                    nullable: true
                  appointment_status:
                    type: string
                    nullable: true
                  location_id:
                    type: integer
                    nullable: true
                  meeting_type:
                    type: string
                    nullable: true
                    enum:
                    - in_person
                    - virtual
                    - phone_call
                    - external
                  source_system:
                    type: string
                    nullable: true
        '422':
          description: the booking is invalid — here a chosen host is already booked
            in the interval, rejected unless allow_overlap is sent
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - patient_id
              - event_type_id
              - start_at
              - end_at
              properties:
                external_identifier:
                  type: string
                  nullable: true
                  description: Optional integrator-assigned identifier, unique per
                    account and resource type.
                patient_id:
                  type: integer
                event_type_id:
                  type: integer
                  description: CDM scheduler event type id; maps to an appointment
                    category
                start_at:
                  type: string
                  format: date-time
                  description: ISO8601 slot start
                end_at:
                  type: string
                  format: date-time
                  description: ISO8601 slot end
                user_ids:
                  type: array
                  items:
                    type: integer
                  description: CDM user ids of the hosting staff
                team_ids:
                  type: array
                  items:
                    type: integer
                room_ids:
                  type: array
                  items:
                    type: integer
                title:
                  type: string
                  description: Optional. Omitted, null or blank uses the event type's
                    patient-facing name. Stored and returned, but the clinic app calendar
                    shows the appointment type name, and saving there overwrites the
                    stored title.
                notes:
                  type: string
                  description: 'Optional. Patient-facing: shown in the patient portal
                    and included in reminder emails.'
                internal_notes:
                  type: string
                  description: Optional. Staff-only in the wawa UI; the CDM still
                    projects it, so it reaches every subscribed webhook endpoint.
                location_id:
                  type: integer
                  description: Optional CDM location id (a clinic). Omitted or null
                    inherits the event type's clinic. Not required for in-person bookings.
                    A clinic-restricted client may only send a location in its own
                    list.
                scheduler_event_status_id:
                  type: integer
                  description: Optional. Omitted leaves status unset. There is no
                    default BOOKED status; read ids from GET /scheduler/event_statuses.
                meeting_type:
                  type: string
                  enum:
                  - in_person
                  - virtual
                  - phone_call
                  - external
                  description: Appointment format. Defaults to the event type's configuration.
                allow_overlap:
                  type: boolean
                  description: Book even if a chosen user, team or room is already
                    booked in the interval. Does not waive a patient conflict. Defaults
                    to false.
                allow_patient_overlap:
                  type: boolean
                  description: Book even if the patient already has a kept appointment
                    in the interval. Does not waive a staff, team or room conflict.
                    Defaults to false.
  "/api/v2/scheduler/events/{id}":
    patch:
      summary: Update an appointment
      tags:
      - Scheduler events
      security:
      - oauth2: []
      parameters:
      - "$ref": "#/components/parameters/IdempotencyKey"
      - name: id
        in: path
        required: true
        schema:
          type: integer
      - name: include
        in: query
        required: false
        description: Child resources to return under top-level `included`. Currently
          `scheduler_event_resources`. An unknown value is 400. Show and create wrap
          the record in `{ data, included }` when this is present; without it the
          body is unchanged. A misspelled `includes=` (plural) is ignored.
        schema:
          type: string
      responses:
        '200':
          description: the updated appointment in CDM shape
          content:
            application/json:
              schema:
                type: object
                required:
                - id
                properties:
                  id:
                    type: integer
                  external_identifier:
                    type: string
                    nullable: true
                  event_type:
                    type: string
                    nullable: true
                  patient_id:
                    type: integer
                    nullable: true
                  scheduler_event_type_id:
                    type: integer
                    nullable: true
                  title:
                    type: string
                    nullable: true
                  start_at:
                    type: string
                    format: date-time
                    nullable: true
                  end_at:
                    type: string
                    format: date-time
                    nullable: true
                  all_day:
                    type: boolean
                    nullable: true
                  appointment_status:
                    type: string
                    nullable: true
                  location_id:
                    type: integer
                    nullable: true
                  meeting_type:
                    type: string
                    nullable: true
                    enum:
                    - in_person
                    - virtual
                    - phone_call
                    - external
                  source_system:
                    type: string
                    nullable: true
        '422':
          description: invalid update; no fields are changed
      requestBody:
        content:
          application/json:
            schema:
              type: object
              description: Partial update of a patient appointment. Omitted fields
                are preserved. Supplied resource arrays replace that resource type;
                [] clears it. Meetings and blocked time are not supported. Requires
                scheduler:write.
              properties:
                patient_id:
                  type: integer
                event_type_id:
                  type: integer
                start_at:
                  type: string
                  format: date-time
                end_at:
                  type: string
                  format: date-time
                title:
                  type: string
                notes:
                  type: string
                  nullable: true
                internal_notes:
                  type: string
                  nullable: true
                location_id:
                  type: integer
                  nullable: true
                scheduler_event_status_id:
                  type: integer
                  nullable: true
                meeting_type:
                  type: string
                  nullable: true
                  enum:
                  - in_person
                  - virtual
                  - phone_call
                  - external
                  -
                  description: Null resets to virtual.
                user_ids:
                  type: array
                  items:
                    type: integer
                  description: CDM User IDs, not account-user IDs.
                team_ids:
                  type: array
                  items:
                    type: integer
                room_ids:
                  type: array
                  items:
                    type: integer
                allow_overlap:
                  type: boolean
                  description: Override staff, team and room conflicts. Defaults to
                    false.
                allow_patient_overlap:
                  type: boolean
                  description: Override patient conflicts independently. Defaults
                    to false.
                external_identifier:
                  type: string
                  nullable: true
                  description: Unique per account and resource type. Omit to preserve;
                    null clears it.
    get:
      summary: Show a scheduler event
      tags:
      - Scheduler events
      security:
      - oauth2: []
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: integer
      - name: include
        in: query
        required: false
        description: Child resources to return under top-level `included`. Currently
          `scheduler_event_resources`. An unknown value is 400. Show and create wrap
          the record in `{ data, included }` when this is present; without it the
          body is unchanged. A misspelled `includes=` (plural) is ignored.
        schema:
          type: string
      responses:
        '200':
          description: the scheduler event in CDM shape
          content:
            application/json:
              schema:
                type: object
                required:
                - id
                properties:
                  id:
                    type: integer
                  external_identifier:
                    type: string
                    nullable: true
                  event_type:
                    type: string
                    nullable: true
                  patient_id:
                    type: integer
                    nullable: true
                  scheduler_event_type_id:
                    type: integer
                    nullable: true
                  title:
                    type: string
                    nullable: true
                  start_at:
                    type: string
                    format: date-time
                    nullable: true
                  end_at:
                    type: string
                    format: date-time
                    nullable: true
                  all_day:
                    type: boolean
                    nullable: true
                  appointment_status:
                    type: string
                    nullable: true
                  location_id:
                    type: integer
                    nullable: true
                  meeting_type:
                    type: string
                    nullable: true
                    enum:
                    - in_person
                    - virtual
                    - phone_call
                    - external
                  source_system:
                    type: string
                    nullable: true
        '404':
          description: no such scheduler event in the principal's scope
  "/api/v2/scheduler/events/{event_id}/status":
    patch:
      summary: Change a scheduler event's status
      tags:
      - Scheduler events
      security:
      - oauth2: []
      parameters:
      - "$ref": "#/components/parameters/IdempotencyKey"
      - name: event_id
        in: path
        required: true
        schema:
          type: integer
      responses:
        '200':
          description: the scheduler event in CDM shape, with the new status
          content:
            application/json:
              schema:
                type: object
                required:
                - id
                properties:
                  id:
                    type: integer
                  external_identifier:
                    type: string
                    nullable: true
                  event_type:
                    type: string
                    nullable: true
                  patient_id:
                    type: integer
                    nullable: true
                  scheduler_event_type_id:
                    type: integer
                    nullable: true
                  title:
                    type: string
                    nullable: true
                  start_at:
                    type: string
                    format: date-time
                    nullable: true
                  end_at:
                    type: string
                    format: date-time
                    nullable: true
                  all_day:
                    type: boolean
                    nullable: true
                  appointment_status:
                    type: string
                    nullable: true
                  location_id:
                    type: integer
                    nullable: true
                  meeting_type:
                    type: string
                    nullable: true
                    enum:
                    - in_person
                    - virtual
                    - phone_call
                    - external
                  source_system:
                    type: string
                    nullable: true
        '422':
          description: the scheduler event status id is not one of the principal's
            statuses
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - scheduler_event_status_id
              properties:
                scheduler_event_status_id:
                  type: integer
                  description: The CDM scheduler event status id
  "/api/v2/scheduler/slots":
    get:
      summary: List available slots
      tags:
      - Scheduler slots
      security:
      - oauth2: []
      parameters:
      - name: event_type_id
        in: query
        required: false
        description: CDM scheduler event type id; maps to an appointment category
        schema:
          type: integer
      - name: from
        in: query
        schema:
          type: string
          format: date
        required: false
        description: ISO8601 date — window start (defaults to today)
      - name: to
        in: query
        schema:
          type: string
          format: date
        required: false
        description: ISO8601 date — window end (capped at 30 days from start)
      - name: patient_id
        in: query
        required: false
        schema:
          type: integer
      - name: duration_minutes
        in: query
        required: false
        description: Overrides the event type's duration
        schema:
          type: integer
      - name: user_ids
        in: query
        required: false
        style: form
        explode: true
        schema:
          type: array
          items:
            type: integer
        description: When present, slots come from that user's matching schedule blocks
          and from matching blocks on their teams. When omitted with event_type_id,
          any user or team with a matching schedule block is its own slot. Repeated
          keys, a comma-separated list and user_ids[] are all accepted; present with
          no values is a 400
      - name: team_ids
        in: query
        required: false
        style: form
        explode: true
        schema:
          type: array
          items:
            type: integer
        description: When present without user_ids, slots come from those teams' matching
          schedule blocks
      - name: room_ids
        in: query
        required: false
        style: form
        explode: true
        schema:
          type: array
          items:
            type: integer
        description: Ignored. Slot lookup does not assign rooms
      - name: page
        in: query
        required: false
        description: 1-based page number
        schema:
          type: integer
      - name: items
        in: query
        required: false
        description: Page size (capped at 100)
        schema:
          type: integer
      responses:
        '200':
          description: available slots ascending in the { data, meta } envelope; the
            first element is the first available slot, and each slot is one bookable
            set (POST it with a patient_id)
          content:
            application/json:
              schema:
                type: object
                required:
                - data
                - meta
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      required:
                      - start_at
                      - end_at
                      - event_type_id
                      - user_ids
                      - team_ids
                      - room_ids
                      properties:
                        start_at:
                          type: string
                          format: date-time
                        end_at:
                          type: string
                          format: date-time
                        event_type_id:
                          type: integer
                          nullable: true
                        user_ids:
                          type: array
                          items:
                            type: integer
                          description: CDM user ids of the hosting staff
                        team_ids:
                          type: array
                          items:
                            type: integer
                        room_ids:
                          type: array
                          items:
                            type: integer
                  meta:
                    type: object
                    required:
                    - page
                    - items
                    - count
                    - pages
                    properties:
                      page:
                        type: integer
                      items:
                        type: integer
                      count:
                        type: integer
                      pages:
                        type: integer
                      next:
                        type: integer
                        nullable: true
                      prev:
                        type: integer
                        nullable: true
        '404':
          description: no such event type in the principal's scope
  "/api/v2/settings/cycle_protocols":
    get:
      summary: List cycle protocols
      tags:
      - Settings
      security:
      - oauth2: []
      parameters:
      - name: page
        in: query
        required: false
        schema:
          type: integer
      - name: items
        in: query
        required: false
        schema:
          type: integer
      responses:
        '200':
          description: kept protocols, paginated in the { data, meta } envelope
          content:
            application/json:
              schema:
                type: object
                required:
                - data
                - meta
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      required:
                      - id
                      - cycle_treatment_type_id
                      - protocol_name
                      properties:
                        id:
                          type: integer
                        cycle_treatment_type_id:
                          type: integer
                        protocol_name:
                          type: string
                        created_at:
                          type: string
                          format: date-time
                        updated_at:
                          type: string
                          format: date-time
                        source_system:
                          type: string
                        deleted:
                          type: string
                          format: date-time
                          nullable: true
                  meta:
                    type: object
                    required:
                    - page
                    - items
                    - count
                    - pages
                    properties:
                      page:
                        type: integer
                      items:
                        type: integer
                      count:
                        type: integer
                      pages:
                        type: integer
                      next:
                        type: integer
                        nullable: true
                      prev:
                        type: integer
                        nullable: true
  "/api/v2/settings/cycle_protocols/{id}":
    get:
      summary: Show a cycle protocol
      tags:
      - Settings
      security:
      - oauth2: []
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: integer
      responses:
        '200':
          description: the protocol in CDM shape
          content:
            application/json:
              schema:
                type: object
                required:
                - id
                - cycle_treatment_type_id
                - protocol_name
                properties:
                  id:
                    type: integer
                  cycle_treatment_type_id:
                    type: integer
                  protocol_name:
                    type: string
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
                  source_system:
                    type: string
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
        '404':
          description: no such protocol in the principal's scope
  "/api/v2/settings/cycle_treatment_types":
    get:
      summary: List cycle treatment types
      tags:
      - Settings
      security:
      - oauth2: []
      parameters:
      - name: page
        in: query
        required: false
        schema:
          type: integer
      - name: items
        in: query
        required: false
        schema:
          type: integer
      responses:
        '200':
          description: kept treatment types, paginated in the { data, meta } envelope
          content:
            application/json:
              schema:
                type: object
                required:
                - data
                - meta
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      required:
                      - id
                      - treatment_name
                      properties:
                        id:
                          type: integer
                        treatment_name:
                          type: string
                        primary_treatment_classification:
                          type: string
                          nullable: true
                        created_at:
                          type: string
                          format: date-time
                        updated_at:
                          type: string
                          format: date-time
                        source_system:
                          type: string
                        deleted:
                          type: string
                          format: date-time
                          nullable: true
                  meta:
                    type: object
                    required:
                    - page
                    - items
                    - count
                    - pages
                    properties:
                      page:
                        type: integer
                      items:
                        type: integer
                      count:
                        type: integer
                      pages:
                        type: integer
                      next:
                        type: integer
                        nullable: true
                      prev:
                        type: integer
                        nullable: true
  "/api/v2/settings/cycle_treatment_types/{id}":
    get:
      summary: Show a cycle treatment type
      tags:
      - Settings
      security:
      - oauth2: []
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: integer
      responses:
        '200':
          description: the treatment type in CDM shape
          content:
            application/json:
              schema:
                type: object
                required:
                - id
                - treatment_name
                properties:
                  id:
                    type: integer
                  treatment_name:
                    type: string
                  primary_treatment_classification:
                    type: string
                    nullable: true
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
                  source_system:
                    type: string
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
        '404':
          description: no such treatment type in the principal's scope
  "/api/v2/settings/fund_sources":
    get:
      summary: List fund sources
      tags:
      - Settings
      security:
      - oauth2: []
      parameters:
      - name: page
        in: query
        required: false
        description: 1-based page number
        schema:
          type: integer
      - name: items
        in: query
        required: false
        description: Page size (capped at 100)
        schema:
          type: integer
      responses:
        '200':
          description: the principal's fund sources, paginated in the { data, meta
            } envelope
          content:
            application/json:
              schema:
                type: object
                required:
                - data
                - meta
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      required:
                      - id
                      - name
                      properties:
                        id:
                          type: integer
                        name:
                          type: string
                        created_at:
                          type: string
                          format: date-time
                        updated_at:
                          type: string
                          format: date-time
                        source_system:
                          type: string
                        deleted:
                          type: string
                          format: date-time
                          nullable: true
                          description: Soft-delete timestamp, set once the fund source
                            is deleted
                  meta:
                    type: object
                    required:
                    - page
                    - items
                    - count
                    - pages
                    properties:
                      page:
                        type: integer
                      items:
                        type: integer
                      count:
                        type: integer
                      pages:
                        type: integer
                      next:
                        type: integer
                        nullable: true
                      prev:
                        type: integer
                        nullable: true
    post:
      summary: Create a fund source
      tags:
      - Settings
      security:
      - oauth2: []
      parameters:
      - "$ref": "#/components/parameters/IdempotencyKey"
      responses:
        '201':
          description: the created fund source in CDM shape
          content:
            application/json:
              schema:
                type: object
                required:
                - id
                - name
                properties:
                  id:
                    type: integer
                  name:
                    type: string
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
                  source_system:
                    type: string
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
                    description: Soft-delete timestamp, set once the fund source is
                      deleted
        '422':
          description: invalid — no name
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - name
              properties:
                name:
                  type: string
  "/api/v2/settings/fund_sources/{id}":
    get:
      summary: Show a fund source
      tags:
      - Settings
      security:
      - oauth2: []
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: integer
      responses:
        '200':
          description: the fund source in CDM shape
          content:
            application/json:
              schema:
                type: object
                required:
                - id
                - name
                properties:
                  id:
                    type: integer
                  name:
                    type: string
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
                  source_system:
                    type: string
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
                    description: Soft-delete timestamp, set once the fund source is
                      deleted
        '404':
          description: no such fund source in the principal's scope
    patch:
      summary: Rename a fund source
      tags:
      - Settings
      security:
      - oauth2: []
      parameters:
      - "$ref": "#/components/parameters/IdempotencyKey"
      - name: id
        in: path
        required: true
        schema:
          type: integer
      responses:
        '200':
          description: the updated fund source in CDM shape
          content:
            application/json:
              schema:
                type: object
                required:
                - id
                - name
                properties:
                  id:
                    type: integer
                  name:
                    type: string
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
                  source_system:
                    type: string
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
                    description: Soft-delete timestamp, set once the fund source is
                      deleted
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - name
              properties:
                name:
                  type: string
    delete:
      summary: Delete a fund source
      tags:
      - Settings
      security:
      - oauth2: []
      parameters:
      - "$ref": "#/components/parameters/IdempotencyKey"
      - name: id
        in: path
        required: true
        schema:
          type: integer
      responses:
        '200':
          description: the deleted fund source in its final CDM shape
          content:
            application/json:
              schema:
                type: object
                required:
                - id
                - name
                properties:
                  id:
                    type: integer
                  name:
                    type: string
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
                  source_system:
                    type: string
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
                    description: Soft-delete timestamp, set once the fund source is
                      deleted
  "/api/v2/teams":
    get:
      summary: List teams
      tags:
      - Teams
      security:
      - oauth2: []
      parameters:
      - name: page
        in: query
        required: false
        description: 1-based page number
        schema:
          type: integer
      - name: items
        in: query
        required: false
        description: Page size (capped at 100)
        schema:
          type: integer
      responses:
        '200':
          description: the principal's bookable teams, paginated in the { data, meta
            } envelope
          content:
            application/json:
              schema:
                type: object
                required:
                - data
                - meta
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      required:
                      - id
                      - name
                      properties:
                        id:
                          type: integer
                        name:
                          type: string
                        is_active:
                          type: boolean
                          nullable: true
                        created_at:
                          type: string
                          format: date-time
                        updated_at:
                          type: string
                          format: date-time
                        source_system:
                          type: string
                        deleted:
                          type: string
                          format: date-time
                          nullable: true
                          description: Soft-delete timestamp; null when the record
                            is live
                  meta:
                    type: object
                    required:
                    - page
                    - items
                    - count
                    - pages
                    properties:
                      page:
                        type: integer
                      items:
                        type: integer
                      count:
                        type: integer
                      pages:
                        type: integer
                      next:
                        type: integer
                        nullable: true
                      prev:
                        type: integer
                        nullable: true
  "/api/v2/teams/{id}":
    get:
      summary: Show a team
      tags:
      - Teams
      security:
      - oauth2: []
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: integer
      responses:
        '200':
          description: the team in CDM shape
          content:
            application/json:
              schema:
                type: object
                required:
                - id
                - name
                properties:
                  id:
                    type: integer
                  name:
                    type: string
                  is_active:
                    type: boolean
                    nullable: true
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
                  source_system:
                    type: string
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
                    description: Soft-delete timestamp; null when the record is live
        '404':
          description: no such team in the principal's scope
  "/api/v2/users":
    get:
      summary: List staff members
      tags:
      - Users
      security:
      - oauth2: []
      parameters:
      - name: page
        in: query
        required: false
        description: 1-based page number
        schema:
          type: integer
      - name: items
        in: query
        required: false
        description: Page size (capped at 100)
        schema:
          type: integer
      - name: q[search]
        in: query
        required: false
        description: 'Free-text query: name or email'
        schema:
          type: string
      - name: q[first_name_cont]
        in: query
        required: false
        description: First name contains
        schema:
          type: string
      - name: q[last_name_cont]
        in: query
        required: false
        description: Last name contains
        schema:
          type: string
      - name: q[external_identifier_eq]
        in: query
        required: false
        description: Exact, case-sensitive external identifier
        schema:
          type: string
      responses:
        '200':
          description: the account's staff members (matching the q filters when given),
            paginated in the { data, meta } envelope; ids are the CDM user ids the
            slot and booking endpoints accept
          content:
            application/json:
              schema:
                type: object
                required:
                - data
                - meta
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      required:
                      - id
                      properties:
                        id:
                          type: integer
                        external_identifier:
                          type: string
                          nullable: true
                        first_name:
                          type: string
                          nullable: true
                        last_name:
                          type: string
                          nullable: true
                        email:
                          type: string
                          nullable: true
                        role:
                          type: string
                          nullable: true
                        provider_number:
                          type: string
                          nullable: true
                        is_active:
                          type: boolean
                          nullable: true
                        created_at:
                          type: string
                          format: date-time
                        updated_at:
                          type: string
                          format: date-time
                        source_system:
                          type: string
                        deleted:
                          type: string
                          format: date-time
                          nullable: true
                          description: Soft-delete timestamp; null when the record
                            is live
                  meta:
                    type: object
                    required:
                    - page
                    - items
                    - count
                    - pages
                    properties:
                      page:
                        type: integer
                      items:
                        type: integer
                      count:
                        type: integer
                      pages:
                        type: integer
                      next:
                        type: integer
                        nullable: true
                      prev:
                        type: integer
                        nullable: true
  "/api/v2/users/{id}":
    patch:
      summary: Update a staff member's external identifier
      tags:
      - Users
      security:
      - oauth2: []
      parameters:
      - "$ref": "#/components/parameters/IdempotencyKey"
      - name: id
        in: path
        required: true
        schema:
          type: integer
      responses:
        '200':
          description: the updated staff member in CDM shape
          content:
            application/json:
              schema:
                type: object
                required:
                - id
                properties:
                  id:
                    type: integer
                  external_identifier:
                    type: string
                    nullable: true
                  first_name:
                    type: string
                    nullable: true
                  last_name:
                    type: string
                    nullable: true
                  email:
                    type: string
                    nullable: true
                  role:
                    type: string
                    nullable: true
                  provider_number:
                    type: string
                    nullable: true
                  is_active:
                    type: boolean
                    nullable: true
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
                  source_system:
                    type: string
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
                    description: Soft-delete timestamp; null when the record is live
        '422':
          description: invalid external identifier
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                external_identifier:
                  type: string
                  nullable: true
                  description: Unique per account and resource type. Omit to preserve;
                    null clears it. Requires users:write.
    get:
      summary: Show a staff member
      tags:
      - Users
      security:
      - oauth2: []
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: integer
      responses:
        '200':
          description: the staff member in CDM shape
          content:
            application/json:
              schema:
                type: object
                required:
                - id
                properties:
                  id:
                    type: integer
                  external_identifier:
                    type: string
                    nullable: true
                  first_name:
                    type: string
                    nullable: true
                  last_name:
                    type: string
                    nullable: true
                  email:
                    type: string
                    nullable: true
                  role:
                    type: string
                    nullable: true
                  provider_number:
                    type: string
                    nullable: true
                  is_active:
                    type: boolean
                    nullable: true
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
                  source_system:
                    type: string
                  deleted:
                    type: string
                    format: date-time
                    nullable: true
                    description: Soft-delete timestamp; null when the record is live
        '404':
          description: no such staff member in the principal's account
servers:
- url: "{defaultHost}"
  variables:
    defaultHost:
      default: https://clinic.wawafertility.com
