openapi: 3.1.0
info:
  title: APX — APDS Parking eXtensions
  version: 0.16.0
  summary: An open companion standard to APDS 4.1
  license:
    name: MIT
    url: https://opensource.org/licenses/MIT
  contact:
    name: APX Standard Working Group (stewarded by Umojo)
    email: rneubauer@umojo.com
  x-apds-extension:
    extensionName: apx
    extensionVersion: '1.0'
    apdsVersion: '4.1'
  description: |-
    **APX (APDS Parking eXtensions)** is an additive companion standard to the
    [APDS 4.1 API](https://github.com/parkingdata/spec) (Alliance for Parking
    Data Standards, core model published as ISO/TS 5206-1).

    ## The prime directive

    Wherever APDS 4.1 already defines a route, schema, or convention, APX uses
    it **verbatim**, by `$ref` into the vendored, unmodified `apds-api-4.1.yaml`.
    APX never redefines, subsets, or re-shapes an APDS entity, and a plain
    APDS 4.1 client works against an APX implementation without modification.
    Everything here is what APDS deliberately leaves out.

    ## Five ideas, used everywhere

    | Concept | Plain meaning |
    |---|---|
    | **Place** | Anywhere a vehicle can park, broken into levels, lanes, and spaces |
    | **Right** | Permission to park. A *specification* is the product; an *assigned right* is that product granted to someone |
    | **Session** | An actual stay: a vehicle using a right, with a start and an end |
    | **Rate** | Pricing: hourly tables, flat fees, event rates |
    | **Observation** | Something a sensor saw, with a timestamp, a confidence score, and imagery |

    Supporting players: an **Organisation** or **Contact**, a **Credential**
    (the thing presented at the lane), and a **Device** (gate, pay station,
    camera). All of them are APDS classes; none is redefined here.

    ## Conventions

    - Every APX resource carries an `id` (UUID) and an integer `version`.
      Objects reference each other as `{"id": "…", "className": "Session"}`.
    - Timestamps are RFC 3339 UTC. Money is the APDS shape
      `{"currencyType": "USD", "currencyValue": 9.00}`.
    - Errors are RFC 9457 `application/problem+json` with a registered
      `type` URI you can program against, never a bare string.
    - Mutating operations a device may retry require an `Idempotency-Key`.
      Replaying a key with the same body returns the resource as it stands
      now (Part 4 §4.2a), never a second copy; with a
      different body it is a conflict.
    - Lifecycles are audited: resources with states carry an immutable,
      append-only `statusHistory[]`.

    ## Access

    OAuth 2.0 client credentials. Two independent bounds apply to every call:
    **scopes** (`apx.<domain>:<verb>`, what kinds of thing you may do) and
    **grants** (the token claims `apx_org` and `apx_places`, which facilities
    you may do them at). Grants are fail-closed: absent or empty means no
    places. A vendor hired for one garage cannot act on another.

    ## Not everything is mandatory

    APX is partitioned into named **conformance classes**. `apx-data` and
    `apx-events` are the base; every other class is optional and
    independently claimable, with objective per-requirement criteria in
    Annex A of the written standard. An implementation advertises the classes
    it satisfies at `/.well-known/apx-configuration`.

    ## How to read this document

    Operations are grouped by domain in the navigation, and each group opens
    with what APDS already provides, what APX adds on top, and a link to the
    governing Part of the **written standard** in
    [docs/standard/](https://github.com/rneubauer/apx/tree/main/docs/standard).
    Where prose and this description disagree for an APX-defined path, this
    document prevails and the prose is a defect to be corrected; for
    APDS-native paths the vendored APDS document prevails.

    End-to-end worked examples, every payload machine-validated against this
    bundle, are in
    [docs/scenarios/](https://github.com/rneubauer/apx/tree/main/docs/scenarios).
servers:
  - url: https://api.apx-implementation.example
    description: |-
      One host serves both surfaces: APDS-native routes at their verbatim
      paths (/places, /sessions, /webhooks, …) and APX routes under the
      explicit /v1 prefix.
security:
  - apxOAuth: []
paths:
  /places:
    get:
      summary: List Places
      security:
        - oAuth:
            - po
            - sp
            - ep
            - ad
      description: |-
        Returns a list of places potentially filtered by a combination of :
        * __latitude__, __longitude__ and __radius__ : retrieve all places within a geographic area,
        * __types__ : retrieve all places of the given type,
        * __right_type__ : retrieve all places associated with the right specification type,
        * __structure_type__ : retrieve all places associated with the specified structure type,
        * __structure_grade__ : retrieve all places associated with the specified structure grade,
        * __name__ : retrieve all places which match the name of the facilities,
        * __layer__ : specify the maximum hierarchy element layer desired,
        * __operator__ : the id of the operator of this location
        * __modified_since__ : retrieve all places that have changed from that given instant onwards,
        * __expand__ : a comma-separated list of optional object attributes associated to a place that should be included in the result set.
      operationId: get-places
      tags:
        - Places
      parameters:
        - $ref: '#/components/parameters/latitude'
        - $ref: '#/components/parameters/longitude'
        - $ref: '#/components/parameters/radius'
        - $ref: '#/components/parameters/place_types'
        - $ref: '#/components/parameters/right_spec_types'
        - $ref: '#/components/parameters/structure_type'
        - $ref: '#/components/parameters/structure_grade'
        - $ref: '#/components/parameters/place_name'
        - $ref: '#/components/parameters/place_layer'
        - $ref: '#/components/parameters/operator'
        - $ref: '#/components/parameters/modified_since'
        - $ref: '#/components/parameters/places_expand'
        - $ref: '#/components/parameters/page'
        - $ref: '#/components/parameters/ModeParam'
        - $ref: '#/components/parameters/CursorParam'
        - $ref: '#/components/parameters/place_ids'
      responses:
        '200':
          description: Ok
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/HierarchyElementList'
                  - $ref: '#/components/schemas/ChangeFeedPage'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: 'mode=change only: the cursor is unknown, older than the retention window, or was issued for another (class, credential, filter set) — problem type `target-not-found`; re-sync with mode=full (Part 5 §5.2 rules 2 and 5). The cursor is an APX parameter, so this refusal is always a Problem.'
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    post:
      summary: Create Place
      security:
        - oAuth:
            - po
      description: Create a new place.
      operationId: create-place
      tags:
        - Places
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/HierarchyElement'
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                ok:
                  value:
                    status: ok
                    code: 201
                    message: Place created successfully.
        '400':
          description: 'Bad Request. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `invalid-request` (with `errors[]`) instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                missing-data:
                  value:
                    status: error
                    code: 400
                    message: Place can not be created due to missing required attributes.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: 'Conflict. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `id-collision` (client-supplied id already exists) instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                conflict:
                  value:
                    status: error
                    code: 409
                    message: Place can not be created due to conflicting data.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: A lane's `apds-ext:apx:lane-cameras@1.0` names a `cameraId` already configured on another lane of the same Place (problem type `request-unprocessable`, Part 13 §13.3a(5)); nothing is written.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /places/{id}:
    parameters:
      - schema:
          type: string
        name: id
        in: path
        required: true
        description: Unique identifier for the place.
    get:
      summary: Get Place
      security:
        - oAuth:
            - po
            - sp
            - ep
            - ad
      description: Returns the latest version of a given place by its identifier (or a specific version provided as a query parameter).
      operationId: get-place
      parameters:
        - $ref: '#/components/parameters/version'
        - $ref: '#/components/parameters/places_expand'
      tags:
        - Places
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HierarchyElement'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: 'Not Found. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `target-not-found` instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                not_found:
                  value:
                    status: error
                    code: 404
                    message: Place not found.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    put:
      summary: Update Place
      security:
        - oAuth:
            - po
      description: Update an existing place using its identifier.
      operationId: update-place
      tags:
        - Places
      requestBody:
        required: true
        content:
          application/json:
            schema:
              anyOf:
                - $ref: '#/components/schemas/HierarchyElement'
                - $ref: '#/components/schemas/HierarchyElementChangePayload'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                ok:
                  value:
                    status: ok
                    code: 200
                    message: Place updated successfully.
        '400':
          description: 'Bad Request. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `invalid-request` (with `errors[]`) instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                missing-data:
                  value:
                    status: error
                    code: 400
                    message: Place can not be updated due to missing required attributes.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: 'Not Found. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `target-not-found` instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                not-found:
                  value:
                    status: error
                    code: 404
                    message: Place can not be updated as it has not been found.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: 'Conflict. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `version-conflict` (stale `version`) instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                conflict:
                  value:
                    status: error
                    code: 409
                    message: Place can not be updated due to conflicting data.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: A lane's `apds-ext:apx:lane-cameras@1.0` names a `cameraId` already configured on another lane of the same Place (problem type `request-unprocessable`, Part 13 §13.3a(5)); nothing is written.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
      parameters:
        - name: APX-Update-Mode
          in: header
          required: false
          description: 'APX data profile (Part 5 §5.1). `full` (default, stock APDS behavior): the body is the complete current state. `change`: the body is a ChangePayload — identity plus only the changed members; absent = unchanged, explicit null = clear. A stale `version` in change mode is 409 `version-conflict`.'
          schema:
            type: string
            enum:
              - full
              - change
            default: full
    delete:
      summary: Delete Place
      security:
        - oAuth:
            - po
      description: Delete an existing place using its identifier.
      operationId: delete-place
      tags:
        - Places
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                ok:
                  value:
                    status: ok
                    code: 200
                    message: Place deleted successfully.
        '400':
          description: 'Bad Request. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `invalid-request` (with `errors[]`) instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                missing-data:
                  value:
                    status: error
                    code: 400
                    message: Place can not be deleted due to missing required attributes.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: 'Not Found. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `target-not-found` instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                not-found:
                  value:
                    status: error
                    code: 404
                    message: Place can not be deleted as it has not been found.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: 'Conflict. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives the most specific registered problem type (Part 12 §12.4) instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                conflict:
                  value:
                    status: error
                    code: 409
                    message: Place can not be deleted due to conflicting data.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /observations:
    get:
      summary: get list of recorded observations
      tags:
        - Observation
      operationId: get-observations
      description: |-
        Lists `Observations` and allows searching/filtering by:

        * latitude, longitude, radius: to check for `Observations` within a geographic area
        * a list of `Places`, to retrieve all Observations within a set of parking locations
        * start_before: to get observations starting before a given instant
        * end_before: to get observations ending before a given instant
        * start_after: to get observations starting after a given instant
        * end_after: to get observations ending after a given instant
        * a modification instant: to only display changed resources from that point onwards

        Additionally, supports providing a comma-separated list of optional object attributes associated to an `Observation` that should be included in the result set. If unused or left blank, `none` will be assumed.
      parameters:
        - $ref: '#/components/parameters/place_ids'
        - $ref: '#/components/parameters/latitude'
        - $ref: '#/components/parameters/longitude'
        - $ref: '#/components/parameters/radius'
        - $ref: '#/components/parameters/modified_since'
        - $ref: '#/components/parameters/start_before'
        - $ref: '#/components/parameters/end_before'
        - $ref: '#/components/parameters/start_after'
        - $ref: '#/components/parameters/end_after'
        - $ref: '#/components/parameters/ModeParam'
        - $ref: '#/components/parameters/CursorParam'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                oneOf:
                  - allOf:
                      - $ref: '#/components/schemas/PaginatedListMeta'
                      - type: object
                        properties:
                          data:
                            type: array
                            items:
                              $ref: '#/components/schemas/ObservationElement'
                  - $ref: '#/components/schemas/ChangeFeedPage'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: 'mode=change only: the cursor is unknown, older than the retention window, or was issued for another (class, credential, filter set) — problem type `target-not-found`; re-sync with mode=full (Part 5 §5.2 rules 2 and 5). The cursor is an APX parameter, so this refusal is always a Problem.'
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    post:
      summary: create an Observation or Observation Set
      tags:
        - Observation
      operationId: post-observations
      description: create a singular `Observation` or an `Observation Set`
      requestBody:
        required: true
        content:
          application/json:
            examples:
              single-element:
                value:
                  type: ObservationElement
                  method: visual
                  observer: Officer Peterson
                  observationStartTime: '2026-01-01T10:02:00Z'
                  creationDateTime: '2026-01-01T10:04:00Z'
                  observedCredentialId: BD51 SMR
                  location:
                    observerLocation:
                      type: Point
                      coordinates:
                        - -2.3058626
                        - 53.4723193
                  observerOrganisation:
                    id: SAMPLECITY
                    version: 1
            schema:
              oneOf:
                - $ref: '#/components/schemas/ObservationElement'
                - $ref: '#/components/schemas/ObservationSet'
      responses:
        '201':
          description: Observation (or ObservationSet) created (APDS ResponseStatus, as on the other native creates).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
        '400':
          description: 'Observation can not be created due to invalid or missing data. APX (Part 5 §5.1a, Part 12 §12.1): with `Accept: application/problem+json`, problem type `invalid-request` (with `errors[]`).'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: 'Observation can not be created due to conflict (id already exists). APX: with `Accept: application/problem+json`, problem type `id-collision`.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /observations/{id}:
    get:
      summary: get a specific observation element
      tags:
        - Observation
      operationId: get-observation-id
      description: get the latest version of a given `Observation` by its identifier (or a particular previous version when provided as a query parameter)
      parameters:
        - schema:
            type: string
          name: id
          in: path
          required: true
          description: unique observation identifier
        - $ref: '#/components/parameters/version'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ObservationElement'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: 'Not Found. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `target-not-found` instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    put:
      summary: update a specific observation element
      tags:
        - Observation
      operationId: update-observation-id
      description: update the given  `Observation`
      parameters:
        - schema:
            type: string
          name: id
          in: path
          required: true
          description: unique observation identifier
        - name: APX-Update-Mode
          in: header
          required: false
          description: 'APX data profile (Part 5 §5.1). `full` (default, stock APDS behavior): the body is the complete current state. `change`: the body is a ChangePayload — identity plus only the changed members; absent = unchanged, explicit null = clear. A stale `version` in change mode is 409 `version-conflict`.'
          schema:
            type: string
            enum:
              - full
              - change
            default: full
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
        '400':
          description: 'Observation can not be updated due to invalid or missing data. APX: with `Accept: application/problem+json`, problem type `invalid-request`.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: 'Not Found. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `target-not-found` instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                not-found:
                  value:
                    status: error
                    code: 404
                    message: observation with given id does not exist
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: 'Conflict. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `version-conflict` (stale `version`) instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                not-found:
                  value:
                    status: error
                    code: 409
                    message: outdated version number provided
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
      requestBody:
        required: false
        description: The Observation as it now stands (full mode) or its identity plus the changed members (change mode). Undeclared in APDS 4.1 (candidate C-026, not yet filed).
        content:
          application/json:
            schema:
              anyOf:
                - $ref: '#/components/schemas/ObservationElement'
                - $ref: '#/components/schemas/ObservationElementChangePayload'
    delete:
      summary: delete a specific observation element
      tags:
        - Observation
      operationId: delete-observation-id
      description: delete the given  `Observation`
      parameters:
        - schema:
            type: string
          name: id
          in: path
          required: true
          description: unique observation identifier
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: 'Not Found. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `target-not-found` instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                not-found:
                  value:
                    status: error
                    code: 404
                    message: observation with given id does not exist
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /contacts:
    get:
      summary: Get List of Organisations (Contacts)
      security:
        - oAuth:
            - po
            - sp
            - ep
            - ad
      description: Returns the latest list of all organisations and their public ids
      operationId: get-contacts
      parameters:
        - in: query
          name: type
          required: false
          description: filter by this type of organisation/contact
          schema:
            $ref: '#/components/schemas/ContactPointTypeEnum'
      tags:
        - Organisations
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/ContactPoint'
              examples:
                found:
                  value:
                    meta:
                      referenceInstant: 1746684020
                      pageSize: 100
                      offset: 0
                      total: 2
                    data:
                      - id: TESTCOUNCIL
                        version: 1
                        organisationName:
                          - language: en
                            string: Test Council
                        type: operator
                        contactType: contactPoint
                      - id: PROVIDER1
                        version: 1
                        organisationName:
                          - language: en
                            string: Service Provider 1
                        type: serviceProvider
                        contactType: contactPoint
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                internal-error:
                  value:
                    status: error
                    code: 500
                    message: internal server error
    post:
      summary: create a new contact
      description: create a new contact point record which can then be referenced by other data elements
      operationId: post-contact
      tags:
        - Organisations
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ContactPoint'
      responses:
        '201':
          description: CREATED
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
        '400':
          description: 'BAD REQUEST. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `invalid-request` (with `errors[]`) instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                missing-fields:
                  value:
                    status: error
                    code: 400
                    message: missing require fields
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: 'CONFLICT. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `id-collision` (client-supplied id already exists) instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                duplicate-id:
                  value:
                    status: error
                    code: 409
                    message: a contact point with this id already exists
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /contacts/{contactId}:
    parameters:
      - schema:
          type: string
        name: contactId
        in: path
        required: true
        description: Unique identifier for the contact/organisation.
    get:
      summary: get details of particular contact / organisation
      security:
        - oAuth:
            - po
            - sp
            - ep
            - ad
      description: returns the details of the contact identified by {contactId}
      operationId: get-single-contact
      tags:
        - Organisations
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ContactPoint'
              examples:
                found:
                  value:
                    contactType: contactPoint
                    id: TESTCOUNCIL
                    version: 1
                    organisationName:
                      - language: en
                        string: Test Council
                    type: operator
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: 'contact not found. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `target-not-found` instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                not-found:
                  value:
                    status: error
                    code: 404
                    message: contact not found
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                internal-error:
                  value:
                    status: error
                    code: 500
                    message: internal server error
    put:
      summary: update existing contact
      description: update an existing contact point record which can then be referenced by other data elements
      operationId: put-contact
      tags:
        - Organisations
      requestBody:
        required: true
        content:
          application/json:
            schema:
              anyOf:
                - $ref: '#/components/schemas/ContactPoint'
                - $ref: '#/components/schemas/ContactPointChangePayload'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                contact-updated:
                  value:
                    status: ok
                    code: 200
                    message: contact 359e20ec-a836-4365-aa62-07de0993cb20 successfully updated
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: 'NOT FOUND. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `target-not-found` instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                duplicate-id:
                  value:
                    status: error
                    code: 404
                    message: a contact point with this id does not exist
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
      parameters:
        - name: APX-Update-Mode
          in: header
          required: false
          description: 'APX data profile (Part 5 §5.1). `full` (default, stock APDS behavior): the body is the complete current state. `change`: the body is a ChangePayload — identity plus only the changed members; absent = unchanged, explicit null = clear. A stale `version` in change mode is 409 `version-conflict`.'
          schema:
            type: string
            enum:
              - full
              - change
            default: full
    delete:
      summary: delete existing contact
      description: delete an existing contact point record
      operationId: delete-contact
      tags:
        - Organisations
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                contact-updated:
                  value:
                    status: ok
                    code: 200
                    message: contact 359e20ec-a836-4365-aa62-07de0993cb20 successfully deleted
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: 'NOT FOUND. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `target-not-found` instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                duplicate-id:
                  value:
                    status: error
                    code: 404
                    message: a contact point with this id does not exist
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: 'CONFLICT. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives the most specific registered problem type (Part 12 §12.4) instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                duplicate-id:
                  value:
                    status: error
                    code: 409
                    message: contact point cannot be deleted as it is referenced by existing record(s)
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /rights/specs:
    get:
      summary: List RightSpecifications
      security:
        - oAuth:
            - po
            - sp
            - ep
            - ad
      description: |-
        Returns a list of right specifications potentially filtered by a combination of :
        * __latitude__, __longitude__ and __radius__ : retrieve all right specifications used in a geographic area (via their associated place),
        * a list of __Places__ : retrieve all right specifications connected to any of the given places,
        * __issuer__ : the id of the entity that issued the right specification
        * __modified_since__ : retrieve all right specifications that have changed from that given instant onwards, 
        * __expand__ : a comma-separated list of optional object attributes associated to a right specification that should be included in the result set.
      operationId: get-right_specs
      tags:
        - Right Specifications
      parameters:
        - $ref: '#/components/parameters/latitude'
        - $ref: '#/components/parameters/longitude'
        - $ref: '#/components/parameters/radius'
        - $ref: '#/components/parameters/place_ids'
        - $ref: '#/components/parameters/place_types'
        - $ref: '#/components/parameters/modified_since'
        - $ref: '#/components/parameters/issuer'
        - $ref: '#/components/parameters/right_specs_expand'
        - $ref: '#/components/parameters/page'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RightSpecificationList'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    post:
      summary: Create RightSpecification
      security:
        - oAuth:
            - po
      description: Create a new right specification.
      operationId: create-right_specs
      tags:
        - Right Specifications
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RightSpecification'
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                ok:
                  value:
                    status: ok
                    code: 201
                    message: RightSpecification created successfully.
        '400':
          description: 'Bad Request. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `invalid-request` (with `errors[]`) instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                missing-data:
                  value:
                    status: error
                    code: 400
                    message: RightSpecification can not be created due to missing required attributes.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: 'Conflict. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `id-collision` (client-supplied id already exists) instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                conflict:
                  value:
                    status: error
                    code: 409
                    message: RightSpecification can not be created due to conflicting data.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /rights/specs/{id}:
    parameters:
      - schema:
          type: string
        name: id
        in: path
        required: true
        description: Unique identifier for the right specification.
    get:
      summary: Get RightSpecification
      security:
        - oAuth:
            - po
            - sp
            - ep
            - ad
      description: Returns the latest version of a given right specification by its identifier (or the specific version provided as a query parameter).
      operationId: get-right_spec
      tags:
        - Right Specifications
      parameters:
        - $ref: '#/components/parameters/version'
        - $ref: '#/components/parameters/right_specs_expand'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RightSpecification'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: 'Not Found. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `target-not-found` instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                not_found:
                  value:
                    status: error
                    code: 404
                    message: RightSpecification not found.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    put:
      summary: Update RightSpecification
      security:
        - oAuth:
            - po
      description: Update an existing right specification
      operationId: update-right_spec
      tags:
        - Right Specifications
      requestBody:
        required: true
        content:
          application/json:
            schema:
              anyOf:
                - $ref: '#/components/schemas/RightSpecification'
                - $ref: '#/components/schemas/RightSpecificationChangePayload'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                ok:
                  value:
                    status: ok
                    code: 200
                    message: RightSpecification updated successfully.
        '400':
          description: 'Bad Request. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `invalid-request` (with `errors[]`) instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                missing-data:
                  value:
                    status: error
                    code: 400
                    message: RightSpecification can not be updated due to missing required attributes.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: 'Not Found. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `target-not-found` instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                not-found:
                  value:
                    status: error
                    code: 404
                    message: RightSpecification can not be updated as it has not been found.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: 'Conflict. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `version-conflict` (stale `version`) instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                conflict:
                  value:
                    status: error
                    code: 409
                    message: RightSpecification can not be updated due to conflicting data.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
      parameters:
        - name: APX-Update-Mode
          in: header
          required: false
          description: 'APX data profile (Part 5 §5.1). `full` (default, stock APDS behavior): the body is the complete current state. `change`: the body is a ChangePayload — identity plus only the changed members; absent = unchanged, explicit null = clear. A stale `version` in change mode is 409 `version-conflict`.'
          schema:
            type: string
            enum:
              - full
              - change
            default: full
    delete:
      summary: Delete RightSpecification
      security:
        - oAuth:
            - po
      description: Delete an existing right specification using its identifier.
      operationId: delete-right_spec
      tags:
        - Right Specifications
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                ok:
                  value:
                    status: ok
                    code: 200
                    message: RightSpecification deleted successfully.
        '400':
          description: 'Bad Request. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `invalid-request` (with `errors[]`) instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                missing-data:
                  value:
                    status: error
                    code: 400
                    message: RightSpecification can not be deleted due to missing required attributes.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: 'Not Found. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `target-not-found` instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                not-found:
                  value:
                    status: error
                    code: 404
                    message: RightSpecification can not be deleted as it has not been found.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: 'Conflict. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives the most specific registered problem type (Part 12 §12.4) instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                conflict:
                  value:
                    status: error
                    code: 409
                    message: RightSpecification can not be deleted due to conflicting data.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /rates:
    get:
      summary: List RateTables
      security:
        - oAuth:
            - po
            - sp
            - ep
            - ad
      description: |-
        Returns a list of rate potentially filtered by a combination of : 
        * __latitude__, __longitude__ and __radius__ : retrieve all rates used in a geographic area (via their associated assigned rights and place), 
        * a list of __places__ : retrieve all rates connected to assigned rights that belong to any of the given places, 
        * a list of __right specifications__ : retrieve all rates connected to any of the given right specifications, 
        * __issuer__ : the id of the rate responsible party (i.e. the issuer of the rate table)
        * __modified_since__ : retrieve all rates that have changed from that given instant onwards, 
        * __expand__ : a comma-separated list of optional object attributes associated to a rate that should be included in the result set.
      operationId: get-rates
      tags:
        - Rate Tables
      parameters:
        - $ref: '#/components/parameters/latitude'
        - $ref: '#/components/parameters/longitude'
        - $ref: '#/components/parameters/radius'
        - $ref: '#/components/parameters/place_ids'
        - $ref: '#/components/parameters/right_spec_ids'
        - $ref: '#/components/parameters/modified_since'
        - $ref: '#/components/parameters/rates_expand'
        - $ref: '#/components/parameters/issuer'
        - $ref: '#/components/parameters/page'
        - $ref: '#/components/parameters/ModeParam'
        - $ref: '#/components/parameters/CursorParam'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/RateTableList'
                  - $ref: '#/components/schemas/ChangeFeedPage'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: 'mode=change only: the cursor is unknown, older than the retention window, or was issued for another (class, credential, filter set) — problem type `target-not-found`; re-sync with mode=full (Part 5 §5.2 rules 2 and 5). The cursor is an APX parameter, so this refusal is always a Problem.'
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    post:
      summary: Create RateTable
      security:
        - oAuth:
            - po
      description: Create a new rate table.
      operationId: create-rate
      tags:
        - Rate Tables
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RateTable'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
        '400':
          description: 'RateTable can not be created due to invalid or missing data. APX: with `Accept: application/problem+json`, problem type `invalid-request`.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: 'RateTable can not be created due to conflict (id already exists). APX: with `Accept: application/problem+json`, problem type `id-collision`.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /rates/{id}:
    parameters:
      - schema:
          type: string
        name: id
        in: path
        required: true
        description: Unique identifier for the rate table.
    get:
      summary: Get RateTable
      security:
        - oAuth:
            - po
            - sp
            - ep
            - ad
      description: Returns the latest version of a given rate table by its identifier (or the specific version provided as a query parameter).
      operationId: get-rate
      tags:
        - Rate Tables
      parameters:
        - $ref: '#/components/parameters/version'
        - $ref: '#/components/parameters/rates_expand'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RateTable'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: 'Not Found. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `target-not-found` instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                ok:
                  value:
                    status: error
                    code: 404
                    message: Rate table not found.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    put:
      summary: Update RateTable
      security:
        - oAuth:
            - po
      description: Update an existing rate table using its identifier, by providing new attributes.
      operationId: update-rate
      tags:
        - Rate Tables
      requestBody:
        required: true
        content:
          application/json:
            schema:
              anyOf:
                - $ref: '#/components/schemas/RateTable'
                - $ref: '#/components/schemas/RateTableChangePayload'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
        '400':
          description: 'Bad Request. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `invalid-request` (with `errors[]`) instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                missing-data:
                  value:
                    status: error
                    code: 400
                    message: Rate table can not be updated due to missing required attributes.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: 'Not Found. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `target-not-found` instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                not-found:
                  value:
                    status: error
                    code: 404
                    message: Rate table can not be updated as it has not been found.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: 'Conflict. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `version-conflict` (stale `version`) instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                conflict:
                  value:
                    status: error
                    code: 409
                    message: Rate table can not be updated due to conflicting data.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
      parameters:
        - name: APX-Update-Mode
          in: header
          required: false
          description: 'APX data profile (Part 5 §5.1). `full` (default, stock APDS behavior): the body is the complete current state. `change`: the body is a ChangePayload — identity plus only the changed members; absent = unchanged, explicit null = clear. A stale `version` in change mode is 409 `version-conflict`.'
          schema:
            type: string
            enum:
              - full
              - change
            default: full
    delete:
      summary: Delete RateTable
      security:
        - oAuth:
            - po
      description: Delete an existing rate table using its identifier.
      operationId: delete-rate
      tags:
        - Rate Tables
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                ok:
                  value:
                    status: ok
                    code: 200
                    message: Rate table deleted successfully.
        '400':
          description: 'Bad Request. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `invalid-request` (with `errors[]`) instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                missing-data:
                  value:
                    status: error
                    code: 400
                    message: Rate table can not be deleted due to missing required attributes.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: 'Not Found. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `target-not-found` instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                not-found:
                  value:
                    status: error
                    code: 404
                    message: Rate table can not be deleted as it has not been found.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: 'Conflict. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives the most specific registered problem type (Part 12 §12.4) instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                conflict:
                  value:
                    status: error
                    code: 409
                    message: Rate table can not be deleted due to conflicting data.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /sessions:
    get:
      summary: List Sessions
      security:
        - oAuth:
            - po
            - sp
            - ep
            - ad
      description: |-
        Returns a list of sessions potentially filtered by a combination of : 
        * __latitude__, __longitude__ and __radius__ : retrieve all sessions occurring in a geographic area (via their associated place), 
        * a list of __Places__ : retrieve all sessions connected to any of the given places, 
        * a list of __RightSpecifications__ : retrieve all sessions with segments using any of the given right specifications, 
        * a list of __Credentials__ : retrieve all sessions linked to the given credentials, 
        * __start_before__ : retrieve all sessions starting before that given instant, 
        * __end_before__ : retrieve all sessions ending before that given instant, 
        * __start_after__ : retrieve all sessions starting after that given instant, 
        * __end_after__ : retrieve all sessions ending after that given instant, 
        * __modified_since__ : retrieve all sessions that have changed from that given instant onwards, 
        * __expand__ : a comma-separated list of optional object attributes associated to a session or its segment.s that should be included in the result set.
      operationId: get-sessions
      tags:
        - Sessions
      parameters:
        - $ref: '#/components/parameters/latitude'
        - $ref: '#/components/parameters/longitude'
        - $ref: '#/components/parameters/radius'
        - $ref: '#/components/parameters/place_ids'
        - $ref: '#/components/parameters/place_types'
        - $ref: '#/components/parameters/credential_ids'
        - $ref: '#/components/parameters/credential_types'
        - $ref: '#/components/parameters/right_spec_ids'
        - $ref: '#/components/parameters/right_spec_types'
        - $ref: '#/components/parameters/start_before'
        - $ref: '#/components/parameters/end_before'
        - $ref: '#/components/parameters/start_after'
        - $ref: '#/components/parameters/end_after'
        - $ref: '#/components/parameters/modified_since'
        - $ref: '#/components/parameters/sessions_expand'
        - $ref: '#/components/parameters/page'
        - $ref: '#/components/parameters/ModeParam'
        - $ref: '#/components/parameters/CursorParam'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/SessionList'
                  - $ref: '#/components/schemas/ChangeFeedPage'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: 'mode=change only: the cursor is unknown, older than the retention window, or was issued for another (class, credential, filter set) — problem type `target-not-found`; re-sync with mode=full (Part 5 §5.2 rules 2 and 5). The cursor is an APX parameter, so this refusal is always a Problem.'
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    post:
      summary: Create Session
      security:
        - oAuth:
            - sp
      description: Creates a new session, along with one or more segment.s. It also allows the creation of assigned rights, for scenarios in which they must be created simultaneously (e.g. off-street and on-street short stays).
      operationId: create-session
      tags:
        - Sessions
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Session'
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                ok:
                  value:
                    status: ok
                    code: 201
                    message: Session created successfully.
        '400':
          description: 'Bad Request. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `invalid-request` (with `errors[]`) instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                missing-data:
                  value:
                    status: error
                    code: 400
                    message: Session can not be created due to missing required attributes.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: 'Conflict. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `id-collision` (client-supplied id already exists), or `read-already-bound` (a read in `apds-ext:apx:session-detail@1.0` is bound as `entry` or `exit` to another Session of the same place that the write does not name in `supersedes`, Part 5 §5.8 rule 2), instead of ResponseStatus; nothing is written.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                conflict:
                  value:
                    status: error
                    code: 409
                    message: Session can not be created due to conflicting data.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: The Session's `apds-ext:apx:session-detail@1.0` breaks a consistency rule of Part 5 §5.8 — more than one `representative` read, `lifecycle` `open` with an `actualEnd` or any other `lifecycle` without one, or a `parent` whose `hierarchyElement` is not an ancestor of this Session's (problem type `request-unprocessable`); or a read naming no Observation visible to the caller (`reference-unknown`). Nothing is written.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /sessions/{id}:
    parameters:
      - schema:
          type: string
        name: id
        in: path
        required: true
        description: Unique identifier for the session.
    get:
      summary: Get Session
      security:
        - oAuth:
            - po
            - sp
            - ep
            - ad
      description: Returns the latest version of a given session by its identifier (or the specific version provided as a query parameter).
      operationId: get-session
      tags:
        - Sessions
      parameters:
        - $ref: '#/components/parameters/version'
        - $ref: '#/components/parameters/sessions_expand'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Session'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: 'Not Found. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `target-not-found` instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                not_found:
                  value:
                    status: error
                    code: 404
                    message: Session not found.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    put:
      summary: Update Session
      security:
        - oAuth:
            - sp
      description: Updates an existing session using its identifier, by providing new attributes. Segments may also be deleted by removing them from the list of segments in the session.
      operationId: update-session
      tags:
        - Sessions
      requestBody:
        required: true
        content:
          application/json:
            schema:
              anyOf:
                - $ref: '#/components/schemas/Session'
                - $ref: '#/components/schemas/SessionChangePayload'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                ok:
                  value:
                    status: ok
                    code: 200
                    message: Session updated successfully.
        '400':
          description: 'Bad Request. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `invalid-request` (with `errors[]`) instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                missing-data:
                  value:
                    status: error
                    code: 400
                    message: Session can not be updated due to missing required attributes.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: 'Not Found. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `target-not-found` instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                not-found:
                  value:
                    status: error
                    code: 404
                    message: Session can not be updated as it has not been found.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: 'Conflict. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `version-conflict` (stale `version`), or `read-already-bound` (a read in `apds-ext:apx:session-detail@1.0` is bound as `entry` or `exit` to another Session of the same place that the write does not name in `supersedes`, Part 5 §5.8 rule 2), instead of ResponseStatus; nothing is written.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                conflict:
                  value:
                    status: error
                    code: 409
                    message: Session can not be updated due to conflicting data.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: The Session's `apds-ext:apx:session-detail@1.0` breaks a consistency rule of Part 5 §5.8 — more than one `representative` read, `lifecycle` `open` with an `actualEnd` or any other `lifecycle` without one, or a `parent` whose `hierarchyElement` is not an ancestor of this Session's (problem type `request-unprocessable`); or a read naming no Observation visible to the caller (`reference-unknown`). Nothing is written.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
      parameters:
        - name: APX-Update-Mode
          in: header
          required: false
          description: 'APX data profile (Part 5 §5.1). `full` (default, stock APDS behavior): the body is the complete current state. `change`: the body is a ChangePayload — identity plus only the changed members; absent = unchanged, explicit null = clear. A stale `version` in change mode is 409 `version-conflict`.'
          schema:
            type: string
            enum:
              - full
              - change
            default: full
    delete:
      summary: Delete Session
      security:
        - oAuth:
            - sp
      description: Deletes an existing session using its identifier. segments should be deleted by updating the session instead.
      operationId: delete-session
      tags:
        - Sessions
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                ok:
                  value:
                    status: ok
                    code: 200
                    message: Session deleted successfully.
        '400':
          description: 'Bad Request. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `invalid-request` (with `errors[]`) instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                missing-data:
                  value:
                    status: error
                    code: 400
                    message: Session can not be deleted due to missing required attributes.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: 'Not Found. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `target-not-found` instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                not-found:
                  value:
                    status: error
                    code: 404
                    message: Session can not be deleted as it has not been found.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: 'Conflict. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives the most specific registered problem type (Part 12 §12.4) instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                conflict:
                  value:
                    status: error
                    code: 409
                    message: Session can not be deleted due to conflicting data.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /rights/assigned:
    get:
      summary: List AssignedRights
      security:
        - oAuth:
            - po
            - sp
            - ep
            - ad
      description: |-
        Returns a list of assigned rights potentially filtered by a combination of :
        * __latitude__, __longitude__ and __radius__ : retrieve all assigned rights occurring in a geographic area (via their associated place)
        * a list of __places__ : retrieve all assigned rights connected to any of the given places,
        * a list of __right specifications__ : retrieve all assigned rights with segments using any of the given right specifications, 
        * a list of __credentials__ : retrieve all assigned rights linked to the given credentials,
        * __start_before__ : retrieve all assigned rights starting before that given instant, 
        * __end_before__ : retrieve all assigned rights ending before that given instant, 
        * __start_after__ : retrieve all assigned rights starting after that given instant, 
        * __end_after__ : retrieve all assigned rights ending after that given instant, 
        * __modified_since__ : retrieve all assigned rights that have changed from that given instant onwards, 
        * __expand__ : a comma-separated list of optional object attributes associated to an assigned right that should be included in the result set.
      operationId: get-assigned_rights
      tags:
        - Assigned Rights
      parameters:
        - $ref: '#/components/parameters/latitude'
        - $ref: '#/components/parameters/longitude'
        - $ref: '#/components/parameters/radius'
        - $ref: '#/components/parameters/place_ids'
        - $ref: '#/components/parameters/place_types'
        - $ref: '#/components/parameters/credential_ids'
        - $ref: '#/components/parameters/credential_types'
        - $ref: '#/components/parameters/right_spec_ids'
        - $ref: '#/components/parameters/right_spec_types'
        - $ref: '#/components/parameters/start_before'
        - $ref: '#/components/parameters/end_before'
        - $ref: '#/components/parameters/start_after'
        - $ref: '#/components/parameters/end_after'
        - $ref: '#/components/parameters/modified_since'
        - $ref: '#/components/parameters/assigned_expand'
        - $ref: '#/components/parameters/page'
        - $ref: '#/components/parameters/ModeParam'
        - $ref: '#/components/parameters/CursorParam'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/AssignedRightList'
                  - $ref: '#/components/schemas/ChangeFeedPage'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: 'mode=change only: the cursor is unknown, older than the retention window, or was issued for another (class, credential, filter set) — problem type `target-not-found`; re-sync with mode=full (Part 5 §5.2 rules 2 and 5). The cursor is an APX parameter, so this refusal is always a Problem.'
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    post:
      summary: Create AssignedRight
      security:
        - oAuth:
            - sp
      description: Create a new assigned right based on a given object.
      operationId: create-assigned_right
      tags:
        - Assigned Rights
      requestBody:
        required: true
        description: This method allows an issuer to assign a parking right specification to a holder
        content:
          application/json:
            schema:
              oneOf:
                - $ref: '#/components/schemas/AssignedRight'
                - $ref: '#/components/schemas/ReferenceToQuote'
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                ok:
                  value:
                    status: ok
                    code: 201
                    message: Assigned right created successfully.
        '400':
          description: 'Bad Request. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `invalid-request` (with `errors[]`) instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                missing-data:
                  value:
                    status: error
                    code: 400
                    message: Assigned right can not be created due to missing required attributes.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: 'Conflict. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `id-collision` (client-supplied id already exists) instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                conflict:
                  value:
                    status: error
                    code: 409
                    message: Assigned right can not be created due to conflicting data.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /rights/assigned/{id}:
    parameters:
      - schema:
          type: string
        name: id
        in: path
        description: Unique identifier for the assigned right.
        required: true
    get:
      summary: Get AssignedRight
      security:
        - oAuth:
            - po
            - sp
            - ep
            - ad
      description: Returns the latest version of a given assigned right by its identifier (or a specific version provided as a query parameter).
      operationId: get-assigned_right
      tags:
        - Assigned Rights
      parameters:
        - $ref: '#/components/parameters/version'
        - $ref: '#/components/parameters/assigned_expand'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AssignedRight'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: 'Not Found. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `target-not-found` instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                not_found:
                  value:
                    status: error
                    code: 404
                    message: Assigned right not found.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    put:
      summary: Update AssignedRight
      security:
        - oAuth:
            - sp
      description: Update an existing assigned right using its identifier, by providing new attributes. If the provided quote refers to a session extension, this request shall also update the referenced session.
      operationId: update-assigned_right
      tags:
        - Assigned Rights
      requestBody:
        required: true
        content:
          application/json:
            schema:
              anyOf:
                - $ref: '#/components/schemas/AssignedRight'
                - $ref: '#/components/schemas/AssignedRightChangePayload'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                ok:
                  value:
                    status: ok
                    code: 200
                    message: Assigned right updated successfully.
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                ok:
                  value:
                    status: ok
                    code: 200
                    message: Assigned right created successfully.
        '400':
          description: 'Bad Request. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `invalid-request` (with `errors[]`) instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                missing-data:
                  value:
                    status: error
                    code: 400
                    message: Assigned right can not be created due to missing required attributes.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: 'AssignedRight can not be updated as it has not been found (servers that upsert answer 201 instead). APX: with `Accept: application/problem+json`, problem type `target-not-found`.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: 'Conflict. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `version-conflict` (stale `version`) instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                conflict:
                  value:
                    status: error
                    code: 409
                    message: Assigned right can not be created due to conflicting data.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
      parameters:
        - name: APX-Update-Mode
          in: header
          required: false
          description: 'APX data profile (Part 5 §5.1). `full` (default, stock APDS behavior): the body is the complete current state. `change`: the body is a ChangePayload — identity plus only the changed members; absent = unchanged, explicit null = clear. A stale `version` in change mode is 409 `version-conflict`.'
          schema:
            type: string
            enum:
              - full
              - change
            default: full
    delete:
      summary: Delete AssignedRight
      security:
        - oAuth:
            - sp
      description: Delete an existing assigned right using its identifier.
      operationId: delete-assigned_right
      tags:
        - Assigned Rights
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                ok:
                  value:
                    status: ok
                    code: 200
                    message: Assigned right deleted successfully.
        '400':
          description: 'Bad Request. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `invalid-request` (with `errors[]`) instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                missing-data:
                  value:
                    status: error
                    code: 400
                    message: Assigned right can not be deleted due to missing required attributes.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: 'Not Found. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `target-not-found` instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                not-found:
                  value:
                    status: error
                    code: 404
                    message: Assigned right can not be deleted as it has not been found.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: 'Conflict. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives the most specific registered problem type (Part 12 §12.4) instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                conflict:
                  value:
                    status: error
                    code: 409
                    message: Assigned right can not be deleted due to conflicting data.
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /quotes:
    get:
      summary: get quotes
      description: get quotes matching specified criteria
      operationId: get-quote
      tags:
        - Quote
      parameters:
        - $ref: '#/components/parameters/latitude'
        - $ref: '#/components/parameters/longitude'
        - $ref: '#/components/parameters/radius'
        - $ref: '#/components/parameters/modified_since'
        - $ref: '#/components/parameters/place_ids'
        - $ref: '#/components/parameters/right_spec_ids'
        - $ref: '#/components/parameters/quote_type'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/QuoteRightRequest'
                  - $ref: '#/components/schemas/QuoteRightResponse'
                  - $ref: '#/components/schemas/QuoteSessionExtensionRequest'
                  - $ref: '#/components/schemas/QuoteSessionExtensionResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    post:
      summary: create quote request
      description: submit a request for a quote
      operationId: post-quote
      tags:
        - Quote
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/PaginatedListMeta'
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          oneOf:
                            - $ref: '#/components/schemas/QuoteRightResponse'
                            - $ref: '#/components/schemas/QuoteSessionExtensionResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/TooManyRequests'
      requestBody:
        required: false
        description: 'The quote request: a QuoteRightRequest (new right) or a QuoteSessionExtensionRequest (extend a session). Undeclared in APDS 4.1 (APX erratum 007).'
        content:
          application/json:
            schema:
              oneOf:
                - $ref: '#/components/schemas/QuoteRightRequest'
                - $ref: '#/components/schemas/QuoteSessionExtensionRequest'
  /quotes/{id}:
    parameters:
      - schema:
          type: string
        name: id
        in: path
        required: true
        description: unique id of the quote
    get:
      summary: get details of a specific quote
      description: get details of quote identified by `id`
      operationId: get-quote-id
      tags:
        - Quote
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/QuoteRightRequest'
                  - $ref: '#/components/schemas/QuoteRightResponse'
                  - $ref: '#/components/schemas/QuoteSessionExtensionRequest'
                  - $ref: '#/components/schemas/QuoteSessionExtensionResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: 'Not Found. APX (Part 5 §5.1a, Part 12 §12.1): a client sending `Accept: application/problem+json` receives problem type `target-not-found` instead of ResponseStatus.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
              examples:
                not-found:
                  value:
                    status: error
                    code: 404
                    message: requested item does not exist
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/places/{id}/occupancy:
    get:
      operationId: get-apx-v1-places-id-occupancy
      security:
        - apxOAuth:
            - apx.data:read
      tags:
        - Data
      summary: Current occupancy snapshot for a place element
      description: |-
        "How full is it right now" for one HierarchyElement, without pulling
        the Place hierarchy. A pure convenience READ over the APDS occupancy
        model (Supply + DemandTable) — the Place payload remains the source
        of truth. Fields the implementation does not know are simply absent.
        Threshold crossings publish apx.data.occupancy.v1 and SHOULD raise
        an occupancyThresholdExceeded alert (Part 7). Scope apx.data:read;
        the place grant must cover the element.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: HierarchyElement UUID (Place, Level, Area, …).
      responses:
        '200':
          description: The occupancy snapshot.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OccupancySnapshot'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such place element.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /webhooks:
    post:
      operationId: post-webhooks
      security:
        - apxOAuth:
            - apx.subscriptions:manage
        - oAuth:
            - po
            - sp
            - ad
      tags:
        - Subscription
      summary: Subscribe to event topics (APDS-compatible superset)
      description: |-
        Creates a subscription. A stock APDS 4.1 `EventSubscription`
        (`{endpoint, topics[]}` with EventTypeEnum values) is a valid body;
        APX fields (transport, filters, secret) are additive.

        **Response negotiation (normative, Part 8 §8.1):** the stock APDS
        4.1 response contract is preserved — a request WITHOUT
        `Prefer: return=representation` receives the native APDS `200`/`202`
        with `ResponseStatus`, exactly as APDS documents. An APX client
        sends `Prefer: return=representation` and receives `201` with the
        full subscription INCLUDING the signing secret (returned exactly
        once, in that response only; webhook transport only).

        Refusals at creation (Part 8 §8.1): a topic the credential could
        not read synchronously is 403 `insufficient-scope` (Part 9 §9.6(4));
        a `filters.places` entry outside the token's `apx_places` grant is
        403 `insufficient-grant`. Send `Idempotency-Key` to make a retried
        create safe.
      parameters:
        - name: Prefer
          in: header
          required: false
          description: |-
            RFC 7240. `return=representation` selects the APX-rich 201
            response (subscription + one-time secret). Absent, the server
            answers with the stock APDS 200/202 ResponseStatus contract.
          schema:
            type: string
            enum:
              - return=representation
        - $ref: '#/components/parameters/IdempotencyKeyOptional'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ApxEventSubscription'
      responses:
        '200':
          description: |-
            Stock APDS contract — subscription approved and activated
            (request did not ask for the APX representation). `ids[]`
            carries the new subscription's id as its single entry, so a
            stock client can later revoke it (Part 8 §8.1).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
        '201':
          description: |-
            APX contract (Prefer: return=representation) — subscription
            created; includes the signing secret, exactly once.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApxEventSubscription'
        '202':
          description: |-
            Stock APDS contract — subscription request received; will be
            processed and then approved/declined. `ids[]` carries the new
            subscription's id as its single entry (Part 8 §8.1).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
        '400':
          description: |-
            An unregistered topic (`unknown-topic`), or a body that fails the
            schema or a field rule (`invalid-request`, with `errors[]`): a
            webhook-transport subscription without `endpoint`, an empty
            `topics[]`, a secret under 32 bytes of entropy, or an
            `extensions` key outside the Part 4 §4.3 pattern.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: |-
            The `Idempotency-Key` was already used with a different body
            (`idempotency-conflict`). A replay with the same body returns
            the subscription as it now stands (Part 4 §4.2a) — never the
            secret a second time.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    get:
      operationId: get-webhooks
      security:
        - apxOAuth:
            - apx.subscriptions:manage
        - oAuth:
            - po
            - sp
            - ad
      tags:
        - Subscription
      summary: List subscriptions (APX additive operation)
      description: Lists subscriptions visible to the caller. Secrets are never returned.
      parameters:
        - $ref: '#/components/parameters/page'
      responses:
        '200':
          description: Paginated subscription list (APDS PaginatedList shape).
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/ApxEventSubscription'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /webhooks/{id}:
    parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Unique identifier for the existing subscription
    get:
      operationId: get-webhooks-id
      security:
        - apxOAuth:
            - apx.subscriptions:manage
        - oAuth:
            - po
            - sp
            - ad
      tags:
        - Subscription
      summary: Read one subscription (APX additive operation)
      description: |-
        Returns one subscription the caller may see — its status,
        `activeKeyIds`, and filters — without paging through `GET
        /webhooks`. Secrets are never returned. Readable in every state,
        including `failed` (Part 8 §8.1).
      responses:
        '200':
          description: The subscription (secret never returned).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApxEventSubscription'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    patch:
      operationId: patch-webhooks-id
      security:
        - apxOAuth:
            - apx.subscriptions:manage
        - oAuth:
            - po
            - sp
            - ad
      tags:
        - Subscription
      summary: Update a subscription (APX additive operation)
      description: |-
        Update topics, endpoint, filters, or status (pause, resume a paused
        or failed subscription), or rotate the secret. The body is a JSON
        Merge Patch over the subscription: send only what changes
        (Part 8 §8.1). The precondition is `If-Match` or the body
        `version`; a stale one is 409 `version-conflict` (Part 4 §4.2a).
        While the subscription is `failed`, the only PATCH accepted is one
        that sets `status: active`; any other is 410
        `subscription-failed`.
      parameters:
        - $ref: '#/components/parameters/IfMatch'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ApxEventSubscriptionPatch'
      responses:
        '200':
          description: Updated subscription (secret never returned).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApxEventSubscription'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such subscription.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: Stale `If-Match` or body `version` (`version-conflict`, Part 4 §4.2a).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '410':
          description: |-
            The subscription is `failed` and the body does not set
            `status: active` (`subscription-failed`, Part 8 §8.1).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    delete:
      operationId: delete-webhooks-id
      security:
        - apxOAuth:
            - apx.subscriptions:manage
        - oAuth:
            - po
            - sp
            - ad
      tags:
        - Subscription
      summary: Revoke (delete) existing subscription
      description: Native APDS 4.1 operation, unchanged (APDS ResponseStatus shape).
      responses:
        '200':
          description: Subscription deleted.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: Subscription not found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseStatus'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /webhooks/{id}/deliveries:
    get:
      operationId: get-webhooks-id-deliveries
      security:
        - apxOAuth:
            - apx.subscriptions:manage
        - oAuth:
            - po
            - sp
            - ad
      tags:
        - Subscription
      summary: Delivery ledger for a subscription
      description: |-
        Returns the delivery records for auditing: one per (event,
        subscription), with the attempt count, status, last HTTP code, and
        the per-attempt history (`attemptHistory`: each attempt's
        `APX-Delivery-Id`, time, and code — Part 8 §8.3). Newest first.
        Readable in every subscription state. An event held while the
        subscription is `paused` has no record until its first attempt.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
        - $ref: '#/components/parameters/page'
        - name: status
          in: query
          required: false
          description: Only records in this delivery status.
          schema:
            type: string
            enum:
              - delivered
              - retrying
              - failed
        - name: eventId
          in: query
          required: false
          description: Only the record of this EventEnvelope.id.
          schema:
            type: string
            format: uuid
        - name: since
          in: query
          required: false
          description: Only records whose latest attempt is at or after this instant (RFC 3339).
          schema:
            type: string
            format: date-time
      responses:
        '200':
          description: Delivery records.
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/DeliveryRecord'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such subscription.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/events/stream:
    get:
      operationId: get-apx-v1-events-stream
      security:
        - apxOAuth:
            - apx.subscriptions:manage
      tags:
        - Subscription
      summary: Server-Sent Events stream (conformance class apx-events-sse)
      description: |-
        Streams EventEnvelopes for a subscription with `transport: sse`.
        Frame grammar (normative, Part 8 §8.4): one event per frame, an
        `id:` line carrying the per-subscription sequence (a decimal
        integer), a single `data:` line carrying the envelope JSON, and a
        blank line; `retry:` and comment lines MAY appear. Reconnect with
        `Last-Event-ID` to resume strictly after that sequence.

        Checks run in this order: the subscription exists and is visible
        (else 404), its transport is `sse` (else 404 `target-not-found` —
        there is no stream for it), it is not `failed` (else 410
        `subscription-failed`), and `Last-Event-ID` is still buffered (else
        410 `stream-position-expired`; re-sync through the Part 5 change
        feed, then reconnect without `Last-Event-ID`).
      parameters:
        - name: subscription
          in: query
          required: true
          schema:
            type: string
            format: uuid
        - name: Last-Event-ID
          in: header
          required: false
          schema:
            type: string
      responses:
        '200':
          description: |-
            text/event-stream of EventEnvelope objects, one per frame
            (`id: <sequence>`, `data: <EventEnvelope JSON>`, blank line).
          content:
            text/event-stream:
              schema:
                type: string
                description: SSE frames per Part 8 §8.4; each `data:` line validates as an EventEnvelope.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: |-
            No such subscription, or its transport is not sse — both
            `target-not-found` (transport is checked before status).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '410':
          description: |-
            The subscription exhausted its retry schedule and is failed
            (`subscription-failed`), or `Last-Event-ID` is older than the
            server's buffer (`stream-position-expired`) — Part 8 §8.4.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/commands:
    post:
      operationId: post-apx-v1-commands
      security:
        - apxOAuth:
            - apx.control:execute
      tags:
        - Control
      summary: Execute a command (idempotent, perishable, audited)
      description: |-
        Requests an operational action (vendGate, lostTicket, pushRate,
        applyValidation, …). Idempotency-Key REQUIRED. Returns 202 with the
        Command; poll GET /v1/commands/{id} or subscribe to
        apx.control.command.status.v1. Requires scope apx.control:execute
        AND a place grant covering the target.
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Command'
      responses:
        '200':
          description: |-
            Idempotent replay — same key + same body returns the command as
            it currently stands, not a snapshot of the first response (Part 4
            §4.2a, Part 6 §6.1).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Command'
        '202':
          description: Command accepted for asynchronous execution.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Command'
        '400':
          description: |-
            Missing Idempotency-Key (`idempotency-key-required`); an unknown
            `commandType`, a missing `target`, or a parameter that fails its
            §6.1 definition (`invalid-request`, with `errors[]`); or a command
            that requires `agent` without one (`agent-required`) — Part 12.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: |-
            Insufficient scope or place grant (Part 9), the current
            resolution context evaluated the action as not allowed
            (`action-not-allowed`), or approval evidence is missing
            (`approval-required`) — Part 17 §17.3.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: |-
            Idempotency-Key replayed with a different body
            (`idempotency-conflict`), or `pushNegotiatedRate` / `matchTicket`
            at a lane with no transaction in progress
            (`lane-no-current-transaction`) — Part 12.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: |-
            Refused synchronously, nothing dispatched: command expired before
            dispatch (`command-expired`); unknown validation provider
            (`validation-provider-unknown`); `lostTicket` at a place whose
            applicable rate deck has no `lostTicketFee` line
            (`lost-ticket-fee-undefined`, Part 6 §6.1); a RateTable not
            flagged negotiable (`rate-not-negotiable`); a session that is not
            open (`session-not-open`); or a parameter Reference that names
            nothing (`reference-unknown`) — Part 12.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    get:
      operationId: get-apx-v1-commands
      security:
        - apxOAuth:
            - apx.control:read
      tags:
        - Control
      summary: List and filter commands (the audit query)
      description: |-
        The commands the caller may see, newest first by the time the
        command was received, each with its full `statusHistory` (Part 6
        §6.1b). Only commands whose target lies inside the token's
        `apx_places` grant are returned; naming a `place` outside the grant
        is 403 `insufficient-grant`. All filters combine with AND.
      parameters:
        - $ref: '#/components/parameters/ModeParam'
        - $ref: '#/components/parameters/CursorParam'
        - name: target
          in: query
          schema:
            type: string
            format: uuid
          description: Commands whose `target.id` is this device, lane, or place.
        - name: place
          in: query
          style: form
          explode: false
          schema:
            type: array
            items:
              type: string
              format: uuid
          description: Comma-separated HierarchyElement ids; subtree-inclusive (a command at a lane matches its parent Place).
        - name: commandType
          in: query
          schema:
            type: string
          description: An apx-command-types value (or an implementer's own).
        - name: status
          in: query
          schema:
            type: string
            enum:
              - received
              - accepted
              - rejected
              - dispatched
              - executing
              - succeeded
              - failed
              - expired
              - cancelled
        - name: agent
          in: query
          schema:
            type: string
          description: Commands whose `agent` equals this principal.
        - name: since
          in: query
          schema:
            type: string
            format: date-time
          description: Received at or after this instant (the first `statusHistory` entry).
        - name: until
          in: query
          schema:
            type: string
            format: date-time
          description: Received before this instant.
        - $ref: '#/components/parameters/page'
      responses:
        '200':
          description: Paginated commands (APDS PaginatedList shape); with `mode=change`, the changes after `cursor` in the same envelope (Part 5 §5.2 rule 8).
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Command'
                  updateMode:
                    $ref: '#/components/schemas/ChangeFeedUpdateMode'
                  cursor:
                    $ref: '#/components/schemas/ChangeFeedCursor'
                  deleted:
                    $ref: '#/components/schemas/ChangeFeedTombstones'
                  grantAdditions:
                    $ref: '#/components/schemas/ChangeFeedGrantAdditions'
                  next:
                    $ref: '#/components/schemas/ChangeFeedNext'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/CursorRefused'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/commands/{id}:
    get:
      operationId: get-apx-v1-commands-id
      security:
        - apxOAuth:
            - apx.control:read
      tags:
        - Control
      summary: Read a command (lifecycle + audit trail)
      description: Returns the Command including its immutable statusHistory.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: The command.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Command'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such command.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/commands/{id}/cancel:
    post:
      operationId: post-apx-v1-commands-id-cancel
      security:
        - apxOAuth:
            - apx.control:execute
      tags:
        - Control
      summary: Cancel a command before dispatch
      description: Allowed in received/accepted states; afterwards 409 command-not-cancellable.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Cancelled command.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Command'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: Not cancellable from the current state (`command-not-cancellable`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/devices:
    get:
      operationId: get-apx-v1-devices
      security:
        - apxOAuth:
            - apx.control:read
      tags:
        - Control
      summary: List device status overlays
      description: |-
        Live DeviceStatus for every SupplementalEquipment the caller may
        see, optionally narrowed by place and state (Part 6 §6.4). Naming a
        `place` outside the token's `apx_places` grant is 403
        `insufficient-grant`.
      parameters:
        - name: place
          in: query
          style: form
          explode: false
          schema:
            type: array
            items:
              type: string
              format: uuid
          description: Comma-separated HierarchyElement ids; subtree-inclusive (a device on a lane matches its parent Place).
        - name: deviceState
          in: query
          schema:
            type: string
          description: An apx-device-states value, e.g. `fault` for everything in fault.
        - $ref: '#/components/parameters/page'
      responses:
        '200':
          description: Device status list.
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/DeviceStatus'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/devices/{id}:
    get:
      operationId: get-apx-v1-devices-id
      security:
        - apxOAuth:
            - apx.control:read
      tags:
        - Control
      summary: Read one device's status overlay
      description: DeviceStatus keyed by the SupplementalEquipment id.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Device status.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeviceStatus'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such device.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/lanes/{id}/current:
    get:
      operationId: get-apx-v1-lanes-id-current
      security:
        - apxOAuth:
            - apx.control:read
      tags:
        - Control
      summary: Lane inquiry — current transaction context (screen-pop)
      description: |-
        The ticket/credential currently in the machine at this lane, amount
        due, applied validations, latest LPR read, and monthly-credential
        context including the last 10 activity events. When no ticket is in
        the machine — or when a lookup parameter is given — also
        `matchCandidates[]`: the open sessions at the place that plausibly
        belong to the vehicle in the lane (Part 6 §6.7), for a driver who
        has lost the ticket.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: VehicularAccess (lane) UUID.
        - name: plate
          in: query
          schema:
            type: string
          description: Ticket-matching override — the plate as the driver reads it, when the camera missed or misread (Part 6 §6.7).
        - name: phone
          in: query
          schema:
            type: string
          description: Ticket-matching override — a permit holder's phone number, resolved through the account registry (Part 13 §13.1); never a call-routing identifier (Part 17 §17.1).
        - name: credential
          in: query
          schema:
            type: string
          description: Ticket-matching override — a credential identification (card number, tag) the driver names.
      responses:
        '200':
          description: Current lane status.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LaneStatus'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such lane or no live state.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/validations/providers:
    get:
      operationId: get-apx-v1-validations-providers
      security:
        - apxOAuth:
            - apx.control:read
      tags:
        - Control
      summary: List validation providers for a place
      description: The venues allowed to validate tickets at the place.
      parameters:
        - name: place
          in: query
          required: true
          schema:
            type: string
            format: uuid
        - $ref: '#/components/parameters/page'
      responses:
        '200':
          description: Validation providers.
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/ValidationProvider'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tolling/transactions:
    post:
      operationId: post-apx-v1-tolling-transactions
      security:
        - apxOAuth:
            - apx.tolling:manage
      tags:
        - Tolling
      summary: Create a toll transaction (idempotent)
      description: |-
        Binds Observation refs + credential + pricing. Idempotency-Key
        REQUIRED. Created `priced` when `pricing` is given, otherwise
        `created` (priced later via `POST …/{id}/price`; Part 15 §15.1).
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TollTransaction'
      responses:
        '200':
          description: |-
            Idempotent replay — same key + same body returns the transaction
            the key created, in its current representation (`version` and
            `transactionStatus` may have advanced; Part 4 §4.2a).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TollTransaction'
        '201':
          description: Created toll transaction.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TollTransaction'
        '400':
          description: |-
            Missing Idempotency-Key (`idempotency-key-required`) or a body
            that fails the schema, e.g. no `tollPoint` (`invalid-request`,
            Part 12).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: Idempotency-Key replayed with a different body.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    get:
      operationId: get-apx-v1-tolling-transactions
      security:
        - apxOAuth:
            - apx.tolling:manage
      tags:
        - Tolling
      summary: List/filter toll transactions
      description: |-
        Filter by plate or credential, status, toll point, place, and time
        window; all filters combine with AND (Part 15 §15.2). Results are
        constrained to the caller's grant.
      parameters:
        - $ref: '#/components/parameters/ModeParam'
        - $ref: '#/components/parameters/CursorParam'
        - name: plate
          in: query
          description: Convenience alias for `credentialType=licensePlate&credentialIdentification=<plate>`.
          schema:
            type: string
        - name: status
          in: query
          description: |-
            A `transactionStatus` value. A value outside that enum is 400
            `invalid-request`, never an empty list.
          schema:
            type: string
        - name: tollPoint
          in: query
          description: The toll point (SupplementalEquipment id) that produced the transaction.
          schema:
            type: string
            format: uuid
        - name: place
          in: query
          description: |-
            Comma-separated HierarchyElement ids, subtree-inclusive. A place
            outside the caller's grant is 403 `insufficient-grant`.
          style: form
          explode: false
          schema:
            type: array
            items:
              type: string
              format: uuid
        - name: credentialType
          in: query
          description: Matches `credential.credentialType` (an APDS CredentialTypeEnum value, e.g. `rfid`).
          schema:
            type: string
        - name: credentialIdentification
          in: query
          description: Matches `credential.credentialIdentification` exactly (a plate string or tag id).
          schema:
            type: string
        - name: since
          in: query
          description: Only transactions created at or after this instant (`statusHistory[0].time`), RFC 3339.
          schema:
            type: string
            format: date-time
        - name: until
          in: query
          description: Only transactions created before this instant (`statusHistory[0].time`), RFC 3339.
          schema:
            type: string
            format: date-time
        - $ref: '#/components/parameters/page'
      responses:
        '200':
          description: Matching transactions; with `mode=change`, the changes after `cursor` in the same envelope (Part 5 §5.2 rule 8).
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/TollTransaction'
                  updateMode:
                    $ref: '#/components/schemas/ChangeFeedUpdateMode'
                  cursor:
                    $ref: '#/components/schemas/ChangeFeedCursor'
                  deleted:
                    $ref: '#/components/schemas/ChangeFeedTombstones'
                  grantAdditions:
                    $ref: '#/components/schemas/ChangeFeedGrantAdditions'
                  next:
                    $ref: '#/components/schemas/ChangeFeedNext'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/CursorRefused'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tolling/transactions/{id}:
    get:
      operationId: get-apx-v1-tolling-transactions-id
      security:
        - apxOAuth:
            - apx.tolling:manage
      tags:
        - Tolling
      summary: Read a toll transaction
      description: Includes dispute state and the immutable statusHistory.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: The transaction.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TollTransaction'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such transaction.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tolling/transactions/{id}/payment:
    post:
      operationId: post-apx-v1-tolling-transactions-id-payment
      security:
        - apxOAuth:
            - apx.tolling:manage
      tags:
        - Tolling
      summary: Attach the settling Payment reference
      description: |-
        Transitions the transaction to paid. Allowed from `priced`, and from
        `resolved` with resolution `upheld` or `adjusted` on an unpaid
        transaction; anything else is 409 `toll-transition-illegal` (Part 15
        §15.1). Re-attaching the payment already attached returns 200
        unchanged, so a replayed billing batch is harmless.
        Idempotency-Key optional (Part 4 §4.2a).
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - $ref: '#/components/parameters/IdempotencyKeyOptional'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TollPaymentAttachment'
      responses:
        '200':
          description: Paid transaction.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TollTransaction'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such transaction.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: |-
            The transaction's state does not accept a payment (`created`,
            `disputed`, `voided`, `resolved` as `refunded` or already paid,
            or `paid` with a different payment — `toll-transition-illegal`),
            or Idempotency-Key replayed with a different body
            (`idempotency-conflict`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tolling/transactions/{id}/price:
    post:
      operationId: post-apx-v1-tolling-transactions-id-price
      security:
        - apxOAuth:
            - apx.tolling:manage
      tags:
        - Tolling
      summary: Price a created toll transaction
      description: |-
        For pricing engines outside the APX server: sets `pricing` on a
        `created` transaction and moves it to `priced` (Part 15 §15.1).
        From any other state 409 `toll-transition-illegal`; a later price
        change goes through a dispute. Idempotency-Key optional.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - $ref: '#/components/parameters/IdempotencyKeyOptional'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TollPricing'
      responses:
        '200':
          description: The transaction, now `priced`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TollTransaction'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: |-
            Not `created` (`toll-transition-illegal`), or Idempotency-Key
            replayed with a different body (`idempotency-conflict`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tolling/transactions/{id}/void:
    post:
      operationId: post-apx-v1-tolling-transactions-id-void
      security:
        - apxOAuth:
            - apx.tolling:manage
      tags:
        - Tolling
      summary: Void a toll transaction
      description: |-
        Terminal: the charge should never have been raised (a duplicate, an
        exempt service vehicle, a misread). Allowed from `created` and
        `priced` only; a paid charge is corrected by a dispute resolved
        `refunded`, so `paid`, `disputed`, `resolved`, and `voided` are 409
        `toll-transition-illegal` (Part 15 §15.1). Idempotency-Key optional.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - $ref: '#/components/parameters/IdempotencyKeyOptional'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TollVoid'
      responses:
        '200':
          description: The transaction, now `voided`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TollTransaction'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: |-
            Not `created` or `priced` (`toll-transition-illegal`), or
            Idempotency-Key replayed with a different body
            (`idempotency-conflict`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tolling/transactions/{id}/disputes:
    post:
      operationId: post-apx-v1-tolling-transactions-id-disputes
      security:
        - apxOAuth:
            - apx.tolling:manage
      tags:
        - Tolling
      summary: Open a dispute
      description: |-
        Opened by the operator, on the holder's behalf or on its own
        initiative (Part 15 §15.1). Allowed from `priced` and `paid`.
        Re-disputing a `resolved` transaction is 409 `dispute-closed`; a
        `created`, `voided`, or already `disputed` transaction is 409
        `toll-transition-illegal`.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TollDisputeOpen'
      responses:
        '200':
          description: Disputed transaction.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TollTransaction'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: |-
            The dispute is already resolved (`dispute-closed`), or the
            transaction's state does not allow a dispute
            (`toll-transition-illegal`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tolling/transactions/{id}/disputes/resolve:
    post:
      operationId: post-apx-v1-tolling-transactions-id-disputes-resolve
      security:
        - apxOAuth:
            - apx.tolling:manage
      tags:
        - Tolling
      summary: Resolve a dispute
      description: |-
        Allowed from `disputed` only. Base resolution values upheld |
        refunded | adjusted | withdrawn (Part 15 §15.1); `adjusted` carries
        `adjustedPricing`, which replaces `pricing` (the old amount moves to
        `dispute.originalPricing`).
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TollDisputeResolution'
      responses:
        '200':
          description: Resolved transaction.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TollTransaction'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: |-
            No open dispute: the dispute is already resolved
            (`dispute-closed`), or the transaction was never disputed
            (`toll-transition-illegal`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/violations:
    post:
      operationId: post-apx-v1-violations
      security:
        - apxOAuth:
            - apx.violations:manage
      tags:
        - Violations
      summary: Create a violation from a detection (idempotent)
      description: |-
        Records a detected violation — from an automated camera/sensor
        pipeline, a guided-enforcement handheld, or an officer directly
        (`detection.mode`). The `Idempotency-Key` header is REQUIRED:
        cameras and handhelds retry, and a retry must not create a second
        violation. Same key + same body returns the violation's current
        representation (200, Part 4 §4.2a); same key + different body is
        409 idempotency-conflict. The server
        performs the eligibility check at creation and records it in
        `eligibilityCheck`; a vehicle found entitled is still recorded (as
        `dismissed`, with the basis) so the audit trail is complete.
        Publishes `apx.violations.detected.v1`.
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Violation'
      responses:
        '200':
          description: Idempotent replay — same key + same body returns the violation's current representation (Part 4 §4.2a).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Violation'
        '201':
          description: Violation recorded (status `detected`, or `dismissed` when the vehicle was entitled).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Violation'
        '400':
          description: |-
            Missing Idempotency-Key (`idempotency-key-required`), or a body
            that fails the schema or a §19.9 field rule — e.g. no
            `detection`, or a position whose first element is outside
            −180..180 (`invalid-request`, with `errors[]`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: Idempotency-Key replayed with a different body.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: |-
            `reference-unknown` — `place`, `space`, or another body
            Reference names nothing visible to the caller, or
            `violationType` is outside the served registries and code lists.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    get:
      operationId: get-apx-v1-violations
      security:
        - apxOAuth:
            - apx.violations:read
      tags:
        - Violations
      summary: List/filter violations
      description: |-
        Filter by plate (credentialIdentification), notice number, status,
        type, place (subtree-inclusive), detection mode, the
        `since`..`until` window on detectedTime, and — for violations
        imported from another enforcement system (Part 19 §19.13) — the
        source system and the source's record id. Results are constrained
        to the caller's place grant; a lookup that names no place (by
        plate or notice number) returns only violations at granted places
        (Part 9 §9.3a). Plate values appear only under `apx.violations:*`
        scopes (Part 9 §9.6).
      parameters:
        - $ref: '#/components/parameters/ModeParam'
        - $ref: '#/components/parameters/CursorParam'
        - name: plate
          in: query
          schema:
            type: string
        - name: noticeNumber
          in: query
          required: false
          schema:
            type: string
          description: Exact match on `notice.noticeNumber` — the number the driver holds, and the payment `reference` (§19.6).
        - name: status
          in: query
          schema:
            type: string
            enum:
              - detected
              - confirmed
              - dismissed
              - issued
              - paid
              - appealed
              - closed
              - voided
        - name: type
          in: query
          schema:
            type: string
        - name: place
          in: query
          schema:
            type: string
            format: uuid
        - name: detectionMode
          in: query
          schema:
            type: string
            enum:
              - automated
              - guided
              - manual
        - name: since
          in: query
          schema:
            type: string
            format: date-time
        - name: until
          in: query
          required: false
          schema:
            type: string
            format: date-time
          description: Upper bound (exclusive) on `detection.detectedTime`.
        - name: sourceSystem
          in: query
          required: false
          schema:
            type: string
          description: Imported violations from this source system only (`system` of `apds-ext:apx:violation-source@1.0`, Part 19 §19.13).
        - name: sourceRecordId
          in: query
          required: false
          schema:
            type: string
          description: Exact match on the source's record id (`recordId`); like `noticeNumber`, it names no place (Part 9 §9.3a rule 3).
        - $ref: '#/components/parameters/page'
      responses:
        '200':
          description: Paginated violations (APDS PaginatedList shape); with `mode=change`, the changes after `cursor` in the same envelope (Part 5 §5.2 rule 8).
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Violation'
                  updateMode:
                    $ref: '#/components/schemas/ChangeFeedUpdateMode'
                  cursor:
                    $ref: '#/components/schemas/ChangeFeedCursor'
                  deleted:
                    $ref: '#/components/schemas/ChangeFeedTombstones'
                  grantAdditions:
                    $ref: '#/components/schemas/ChangeFeedGrantAdditions'
                  next:
                    $ref: '#/components/schemas/ChangeFeedNext'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/CursorRefused'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/violations/{id}:
    get:
      operationId: get-apx-v1-violations-id
      security:
        - apxOAuth:
            - apx.violations:read
      tags:
        - Violations
      summary: Read a violation
      description: Returns the violation including evidence links, the eligibility check, notice, appeal, and the immutable statusHistory.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: The violation.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Violation'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such violation.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/violations/{id}/review:
    post:
      operationId: post-apx-v1-violations-id-review
      security:
        - apxOAuth:
            - apx.violations:manage
      tags:
        - Violations
      summary: Review a detected candidate (guided enforcement)
      description: |-
        Transition `detected → confirmed` or `detected → dismissed`. The
        officer's decision is recorded with reason and reviewer; a
        `violationType` in the body corrects the detector's classification.
        `dismiss` without `reason` is 400 `invalid-request`. Any other
        starting state is 409 `violation-transition-illegal`.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ViolationReview'
      responses:
        '200':
          description: Reviewed violation.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Violation'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such violation.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: Illegal transition (not in `detected`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/violations/{id}/issue:
    post:
      operationId: post-apx-v1-violations-id-issue
      security:
        - apxOAuth:
            - apx.violations:manage
      tags:
        - Violations
      summary: Issue the notice or citation
      description: |-
        Transition `confirmed → issued` — or `detected → issued` for
        `automated` detections where the policy in force permits
        unreviewed issuance (`EnforcementPolicy.unreviewedIssuance`, or
        the operator's published documentation where the policy is
        silent); a `guided` or `manual` detection still in `detected`, or
        an automated one the policy does not permit, is 409
        `violation-not-issuable`. Whatever the detection mode, `issue` is
        also 409 `violation-not-issuable` while any LPR read in
        `observations[]` has plate review `pending` or `rejected` (Part 13
        §13.3a(4a), Part 19 §19.4 rule 6), and when the `relatedSession`
        link rests on match evidence with `plate.method: lenient` or
        `applied: false` (Part 5 §5.8, Part 19 §19.4 rule 5). Sets
        `notice`, `amount`, and `dueTime`.

        The server resolves the EnforcementPolicy in force at `place`
        (Part 19 §19.10) and refuses with 422 when the request breaks it:
        `delivery-method-not-permitted`, `notice-deadline-passed`,
        `penalty-exceeds-cap` (or clamps, per the policy), or
        `signage-required`. On success `policy`, `signage[]`,
        `unpaidAmount`, `capAmount`, and the first `amountHistory` entry
        (`reason: issued`, or `reason: cap` with `requestedAmount` when
        clamped) are frozen onto the violation. Publishes
        `apx.violations.issued.v1`.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ViolationIssue'
      responses:
        '200':
          description: Issued violation.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Violation'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such violation.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: |-
            Not issuable from the current state or detection mode, while an
            evidence read's plate review is `pending` or `rejected`, or on
            lenient or unapplied match evidence (`violation-not-issuable`,
            Part 19 §19.4); or an illegal transition
            (`violation-transition-illegal`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: Refused by the enforcement policy in force (delivery method, notice deadline, penalty cap, or signage).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/violations/{id}/payment:
    post:
      operationId: post-apx-v1-violations-id-payment
      security:
        - apxOAuth:
            - apx.violations:manage
      tags:
        - Violations
      summary: Attach the settling Payment reference
      description: |-
        Transition `issued → paid`. The payment itself is taken through the
        Part 13 surface (`POST /v1/payments`, a payment link, or an APDS
        Payment ingested from a pay station); this attaches its reference.
        Not in `issued` is 409 `violation-transition-illegal`. A body
        `amount` below what is outstanding is a partial payment (Part 19
        §19.6a): it is appended to `payments[]`, `amountPaid` grows, and
        the violation stays `issued`; it moves to `paid` when `amountPaid`
        reaches `amount`.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ViolationPaymentAttachment'
      responses:
        '200':
          description: Paid violation.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Violation'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such violation.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: Illegal transition (not in `issued`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/violations/{id}/appeals:
    post:
      operationId: post-apx-v1-violations-id-appeals
      security:
        - apxOAuth:
            - apx.violations:manage
      tags:
        - Violations
      summary: Open an appeal
      description: |-
        Transition `issued → appealed`, or `paid → appealed` within the
        policy's `appealWindowDays` (pay-then-appeal, Part 19 §19.6); the
        state it came from is recorded as `appeal.openedFrom`. One appeal
        per violation: a second appeal, an appeal on a closed or voided
        violation, or one outside the appeal window is 409
        `appeal-closed`. From a state that was never issued (`detected`,
        `confirmed`, `dismissed`) it is 409 `violation-transition-illegal`.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ViolationAppealOpen'
      responses:
        '200':
          description: Appealed violation.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Violation'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such violation.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: Appeal already opened once, violation closed/voided, or window passed (`appeal-closed`); or a state that was never issued (`violation-transition-illegal`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/violations/{id}/appeals/resolve:
    post:
      operationId: post-apx-v1-violations-id-appeals-resolve
      security:
        - apxOAuth:
            - apx.violations:manage
      tags:
        - Violations
      summary: Resolve an appeal
      description: |-
        `upheld` → back to `appeal.openedFrom` (`issued`, or `paid` for a
        pay-then-appeal); `reduced` → the same, with `amount` replaced by
        `adjustedAmount` (400 `invalid-request` when it is absent);
        `dismissed` → `closed`. A pay-then-appeal resolved `reduced` or
        `dismissed` carries the Part 13 `refund` reference. No open
        appeal, in whatever state, is 409 `appeal-closed`.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ViolationAppealResolution'
      responses:
        '200':
          description: Resolved violation.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Violation'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such violation.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: No open appeal.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/violations/{id}/void:
    post:
      operationId: post-apx-v1-violations-id-void
      security:
        - apxOAuth:
            - apx.violations:manage
      tags:
        - Violations
      summary: Void a violation
      description: |-
        Valid from every non-terminal state (`detected`, `confirmed`,
        `issued`, `appealed`, `paid`); the record and its statusHistory
        remain readable. Voiding a `paid` violation SHOULD carry the Part
        13 `refund` reference. From a terminal state (`dismissed`,
        `closed`, `voided`) it is 409 `violation-transition-illegal`.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ViolationVoid'
      responses:
        '200':
          description: Voided violation.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Violation'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such violation.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: Already terminal (`dismissed`, `closed`, or `voided`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/enforcement/eligibility:
    get:
      operationId: get-apx-v1-enforcement-eligibility
      security:
        - apxOAuth:
            - apx.violations:read
      tags:
        - Violations
      summary: Is this vehicle entitled to be here right now?
      description: |-
        The guided-enforcement screen-pop (Part 19 §19.3): one call answers
        whether a credential is covered at a place at an instant, and by
        what — composing the APDS AssignedRights (APDS's own enforcement
        source of truth), Sessions, and the reservation/permit profiles the
        server holds. A convenience READ in the spirit of lane inquiry and
        the occupancy snapshot: the AssignedRight remains authoritative and
        a client MAY derive the same answer from the native routes. Lives
        under `/v1/enforcement` (not `/v1/violations/…`) because no
        violation exists yet when the question is asked.
      parameters:
        - name: credential
          in: query
          required: true
          schema:
            type: string
          description: The credential value — plate string, permit number, transponder id.
        - name: credentialType
          in: query
          required: false
          schema:
            $ref: '#/components/schemas/CredentialTypeEnum'
          description: APDS CredentialTypeEnum; defaults to `licensePlate`.
        - name: place
          in: query
          required: true
          schema:
            type: string
            format: uuid
          description: HierarchyElement UUID the vehicle is observed at (subtree semantics for rights bound to an ancestor).
        - name: at
          in: query
          required: false
          schema:
            type: string
            format: date-time
          description: The instant to evaluate; defaults to now.
      responses:
        '200':
          description: The entitlement answer with its basis.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EligibilityResult'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such place element.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/enforcement/policies:
    post:
      operationId: post-apx-v1-enforcement-policies
      security:
        - apxOAuth:
            - apx.violations:manage
      tags:
        - Violations
      summary: Create an enforcement policy (idempotent)
      description: |-
        Binds jurisdictional rules to a HierarchyElement. `Idempotency-Key`
        REQUIRED. The policy applies to the element and its subtree from
        `effectiveFrom` unless a descendant carries its own.
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EnforcementPolicy'
      responses:
        '200':
          description: Idempotent replay — same key + same body returns the policy's current representation (Part 4 §4.2a).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EnforcementPolicy'
        '201':
          description: Policy created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EnforcementPolicy'
        '400':
          description: Missing Idempotency-Key (`idempotency-key-required`) or a body that fails the schema (`invalid-request`, with `errors[]`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: Idempotency-Key replayed with a different body.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: |-
            `reference-unknown` — `place` names nothing visible to the
            caller; or `request-unprocessable` — an inconsistent policy,
            e.g. `effectiveTo` before `effectiveFrom`, or an escalation step
            whose fixed `addAmount` alone exceeds
            `overallCeiling.maximumAmount`. (Steps that only might reach
            the ceiling are lawful: the ceiling clamps, §19.10 rule 3.)
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    get:
      operationId: get-apx-v1-enforcement-policies
      security:
        - apxOAuth:
            - apx.violations:read
      tags:
        - Violations
      summary: List enforcement policies
      description: Policies bound at or below `place`, optionally filtered by status.
      parameters:
        - name: place
          in: query
          schema:
            type: string
            format: uuid
        - name: status
          in: query
          schema:
            type: string
            enum:
              - active
              - superseded
              - retired
        - $ref: '#/components/parameters/ModeParam'
        - $ref: '#/components/parameters/CursorParam'
        - $ref: '#/components/parameters/page'
      responses:
        '200':
          description: Paginated policies (APDS PaginatedList shape); with `mode=change`, the changes after `cursor` in the same envelope (Part 5 §5.2 rule 8).
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/EnforcementPolicy'
                  updateMode:
                    $ref: '#/components/schemas/ChangeFeedUpdateMode'
                  cursor:
                    $ref: '#/components/schemas/ChangeFeedCursor'
                  deleted:
                    $ref: '#/components/schemas/ChangeFeedTombstones'
                  grantAdditions:
                    $ref: '#/components/schemas/ChangeFeedGrantAdditions'
                  next:
                    $ref: '#/components/schemas/ChangeFeedNext'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/CursorRefused'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/enforcement/policies/effective:
    get:
      operationId: get-apx-v1-enforcement-policies-effective
      security:
        - apxOAuth:
            - apx.violations:read
      tags:
        - Violations
      summary: The policy in force at a place
      description: |-
        Resolves inheritance: the nearest ancestor-or-self `active` policy
        whose effective window covers `at` (default now). This is exactly
        what the server applies at `issue` and for escalation, so
        handhelds, pipelines, and appeals portals see the same rules.
      parameters:
        - name: place
          in: query
          required: true
          schema:
            type: string
            format: uuid
        - name: at
          in: query
          required: false
          schema:
            type: string
            format: date-time
      responses:
        '200':
          description: The effective policy.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EnforcementPolicy'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such place, or no policy in force for it.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/enforcement/policies/{id}:
    parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
    get:
      operationId: get-apx-v1-enforcement-policies-id
      security:
        - apxOAuth:
            - apx.violations:read
      tags:
        - Violations
      summary: Read an enforcement policy
      description: Returns the policy including its immutable statusHistory.
      responses:
        '200':
          description: The policy.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EnforcementPolicy'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such policy.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    put:
      operationId: put-apx-v1-enforcement-policies-id
      security:
        - apxOAuth:
            - apx.violations:manage
      tags:
        - Violations
      summary: Update an enforcement policy (full update, versioned)
      description: |-
        Full-update semantics. The precondition is the `version` last
        read, sent as `If-Match: "<version>"` or as the body's `version`
        (Part 4 §4.2a); a stale one is 409 `version-conflict` and nothing
        is written. Changes apply to issuance and escalation from the
        update onward; violations already issued keep the `policy`
        version they were issued under.
      parameters:
        - $ref: '#/components/parameters/IfMatch'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EnforcementPolicy'
      responses:
        '200':
          description: Updated policy.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EnforcementPolicy'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such policy.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: Stale version (`version-conflict`, current version in `detail`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: '`reference-unknown` (unknown `place`) or `request-unprocessable` (an inconsistent policy, as on create).'
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/enforcement/signage:
    post:
      operationId: post-apx-v1-enforcement-signage
      security:
        - apxOAuth:
            - apx.violations:manage
      tags:
        - Violations
      summary: Record posted signage (idempotent)
      description: |-
        Records the text, photo, and position of a sign at a place.
        `Idempotency-Key` REQUIRED. To change the wording later, create a
        new record (or new version) with the new `effectiveFrom` and set
        the old one's `effectiveTo` — historical text is never rewritten.
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Signage'
      responses:
        '200':
          description: Idempotent replay — same key + same body returns the record's current representation (Part 4 §4.2a).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Signage'
        '201':
          description: Signage recorded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Signage'
        '400':
          description: Missing Idempotency-Key (`idempotency-key-required`) or a body that fails the schema (`invalid-request`, with `errors[]`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: Idempotency-Key replayed with a different body.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: '`reference-unknown` — `place` or `policy` names nothing visible to the caller.'
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    get:
      operationId: get-apx-v1-enforcement-signage
      security:
        - apxOAuth:
            - apx.violations:read
      tags:
        - Violations
      summary: List signage records
      description: Signage bound at or below `place`, optionally filtered by status.
      parameters:
        - name: place
          in: query
          schema:
            type: string
            format: uuid
        - name: status
          in: query
          schema:
            type: string
            enum:
              - active
              - superseded
              - removed
        - $ref: '#/components/parameters/ModeParam'
        - $ref: '#/components/parameters/CursorParam'
        - $ref: '#/components/parameters/page'
      responses:
        '200':
          description: Paginated signage (APDS PaginatedList shape); with `mode=change`, the changes after `cursor` in the same envelope (Part 5 §5.2 rule 8).
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Signage'
                  updateMode:
                    $ref: '#/components/schemas/ChangeFeedUpdateMode'
                  cursor:
                    $ref: '#/components/schemas/ChangeFeedCursor'
                  deleted:
                    $ref: '#/components/schemas/ChangeFeedTombstones'
                  grantAdditions:
                    $ref: '#/components/schemas/ChangeFeedGrantAdditions'
                  next:
                    $ref: '#/components/schemas/ChangeFeedNext'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/CursorRefused'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/enforcement/signage/effective:
    get:
      operationId: get-apx-v1-enforcement-signage-effective
      security:
        - apxOAuth:
            - apx.violations:read
      tags:
        - Violations
      summary: The signage in force at a place
      description: |-
        Every `active` Signage record bound to `place` or an ancestor whose
        effective window covers `at` (default now) — what the server
        freezes onto a violation at `issue`.
      parameters:
        - name: place
          in: query
          required: true
          schema:
            type: string
            format: uuid
        - name: at
          in: query
          required: false
          schema:
            type: string
            format: date-time
      responses:
        '200':
          description: Signage in force (may be empty).
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Signage'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such place.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/enforcement/signage/{id}:
    parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
    get:
      operationId: get-apx-v1-enforcement-signage-id
      security:
        - apxOAuth:
            - apx.violations:read
      tags:
        - Violations
      summary: Read a signage record
      description: Returns the record including its immutable statusHistory.
      responses:
        '200':
          description: The signage record.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Signage'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such record.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    put:
      operationId: put-apx-v1-enforcement-signage-id
      security:
        - apxOAuth:
            - apx.violations:manage
      tags:
        - Violations
      summary: Update a signage record (full update, versioned)
      description: |-
        Full-update semantics. The precondition is the `version` last
        read, sent as `If-Match: "<version>"` or as the body's `version`
        (Part 4 §4.2a); a stale one is 409 `version-conflict`. Changing
        `text` on a record that any issued violation references is
        refused (422 `signage-referenced`) — supersede it instead.
      parameters:
        - $ref: '#/components/parameters/IfMatch'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Signage'
      responses:
        '200':
          description: Updated record.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Signage'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such record.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: Stale version (`version-conflict`, current version in `detail`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: Text change on a referenced record (`signage-referenced`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/validations/programs:
    post:
      operationId: post-apx-v1-validations-programs
      security:
        - apxOAuth:
            - apx.validations:manage
      tags:
        - Validations
      summary: Enrol a validation program (idempotent)
      description: |-
        Enrols a merchant to validate parking at a place. `Idempotency-Key`
        REQUIRED. The program becomes a row in the Part 6 provider lookup
        for that place while `active`. Publishes
        `apx.validations.program.status.v1`.
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ValidationProgram'
      responses:
        '200':
          description: Idempotent replay — same key + same body returns the program's current representation (Part 4 §4.2a).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationProgram'
        '201':
          description: Program enrolled.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationProgram'
        '400':
          description: Missing Idempotency-Key (`idempotency-key-required`) or a body that fails the schema (`invalid-request`, with `errors[]`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: Idempotency-Key replayed with a different body.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: |-
            `reference-unknown` — `place`, `provider`, or an
            `applicableRateTables` entry names nothing visible to the
            caller; or `request-unprocessable` — a benefit carrying none or
            more than one of amount/duration/percentage (§20.1).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    get:
      operationId: get-apx-v1-validations-programs
      security:
        - apxOAuth:
            - apx.validations:read
        - apxOAuth:
            - apx.validations:redeem
      tags:
        - Validations
      summary: List/filter validation programs
      description: |-
        Filter by place (subtree-inclusive), provider, and status. A
        `apx.validations:redeem` token sees only programs whose provider is
        its own `apx_org` (Part 20 §20.5).
      parameters:
        - $ref: '#/components/parameters/ModeParam'
        - $ref: '#/components/parameters/CursorParam'
        - name: place
          in: query
          schema:
            type: string
            format: uuid
        - name: provider
          in: query
          schema:
            type: string
            format: uuid
        - name: status
          in: query
          schema:
            type: string
            enum:
              - active
              - suspended
              - ended
        - $ref: '#/components/parameters/page'
      responses:
        '200':
          description: Paginated programs (APDS PaginatedList shape); with `mode=change`, the changes after `cursor` in the same envelope (Part 5 §5.2 rule 8).
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/ValidationProgram'
                  updateMode:
                    $ref: '#/components/schemas/ChangeFeedUpdateMode'
                  cursor:
                    $ref: '#/components/schemas/ChangeFeedCursor'
                  deleted:
                    $ref: '#/components/schemas/ChangeFeedTombstones'
                  grantAdditions:
                    $ref: '#/components/schemas/ChangeFeedGrantAdditions'
                  next:
                    $ref: '#/components/schemas/ChangeFeedNext'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/CursorRefused'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/validations/programs/{id}:
    parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
    get:
      operationId: get-apx-v1-validations-programs-id
      security:
        - apxOAuth:
            - apx.validations:read
        - apxOAuth:
            - apx.validations:redeem
      tags:
        - Validations
      summary: Read a validation program
      description: |-
        Returns the program including rules, billing, and the immutable
        statusHistory. A `redeem` token reading another provider's program
        receives 404, exactly as for a program that does not exist (Part 9
        §9.3a rule 2; Part 20 §20.5).
      responses:
        '200':
          description: The program.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationProgram'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such program, or another provider's program under a `redeem` token (`target-not-found`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    put:
      operationId: put-apx-v1-validations-programs-id
      security:
        - apxOAuth:
            - apx.validations:manage
      tags:
        - Validations
      summary: Update a validation program (full update, versioned)
      description: |-
        Full-update semantics (Part 5 §5.1): the body carries the complete
        program. The precondition is the `version` last read, sent as
        `If-Match: "<version>"` or as the body's `version` (Part 4 §4.2a);
        a stale one is 409 `version-conflict`. Status transitions:
        `active ⇄ suspended`, either → `ended` (terminal; 422
        `program-not-active` for any transition out of `ended`). Benefit
        and rule changes apply to redemptions from the update onward;
        existing instruments keep the benefit they were issued with.
      parameters:
        - $ref: '#/components/parameters/IfMatch'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ValidationProgram'
      responses:
        '200':
          description: Updated program.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationProgram'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such program.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: Stale version (`version-conflict`, current version in `detail`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: |-
            `program-not-active` — a transition out of `ended`;
            `request-unprocessable` — a benefit carrying none or more than
            one of amount/duration/percentage; `reference-unknown` — a body
            Reference names nothing visible to the caller.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/validations/programs/{id}/issuances:
    parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
    post:
      operationId: post-apx-v1-validations-programs-id-issuances
      security:
        - apxOAuth:
            - apx.validations:manage
        - apxOAuth:
            - apx.validations:redeem
      tags:
        - Validations
      summary: Issue a batch of validation instruments (idempotent)
      description: |-
        Issues `quantity` instruments of `method` to the program the path
        names; the body need not repeat `program` (a value that differs
        from the path is 422 `request-unprocessable`). `Idempotency-Key`
        REQUIRED — a retried print job must not double the stock. For
        `code`/`qrCode`/`digital`, the generated `codes[]` are returned in
        THIS response only. Program must be `active` (422
        `program-not-active`).
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ValidationIssuanceRequest'
      responses:
        '200':
          description: Idempotent replay — returns the issuance's current representation, without codes (Part 4 §4.2a).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationIssuance'
        '201':
          description: Batch issued; includes `codes[]` exactly once.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationIssuance'
        '400':
          description: Missing Idempotency-Key (`idempotency-key-required`) or a body that fails the schema (`invalid-request`, with `errors[]`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such program.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: Idempotency-Key replayed with a different body.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: |-
            `program-not-active` — the program is not `active`;
            `request-unprocessable` — `method` is not in the program's
            `issuanceMethods`, or a body `program` differs from the path.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    get:
      operationId: get-apx-v1-validations-programs-id-issuances
      security:
        - apxOAuth:
            - apx.validations:read
        - apxOAuth:
            - apx.validations:redeem
      tags:
        - Validations
      summary: List issuances for a program
      description: Batches issued to the program, newest first. Codes are never returned here.
      parameters:
        - $ref: '#/components/parameters/ModeParam'
        - $ref: '#/components/parameters/CursorParam'
        - $ref: '#/components/parameters/page'
      responses:
        '200':
          description: Paginated issuances (APDS PaginatedList shape); with `mode=change`, the changes after `cursor` in the same envelope (Part 5 §5.2 rule 8).
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/ValidationIssuance'
                  updateMode:
                    $ref: '#/components/schemas/ChangeFeedUpdateMode'
                  cursor:
                    $ref: '#/components/schemas/ChangeFeedCursor'
                  deleted:
                    $ref: '#/components/schemas/ChangeFeedTombstones'
                  grantAdditions:
                    $ref: '#/components/schemas/ChangeFeedGrantAdditions'
                  next:
                    $ref: '#/components/schemas/ChangeFeedNext'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such program, or (`mode=change`) a refused cursor (`target-not-found`; Part 5 §5.2 rules 2 and 5).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/validations/instruments/{code}:
    get:
      operationId: get-apx-v1-validations-instruments-code
      security:
        - apxOAuth:
            - apx.validations:read
        - apxOAuth:
            - apx.validations:redeem
      tags:
        - Validations
      summary: Check a validation code
      description: |-
        "Is this code good?" — the pay-station / merchant-app read before
        applying. Returns status, program, validity window, and the
        benefit. A code the caller's grant cannot see is 404, never 403
        (no oracle for guessing codes).
      parameters:
        - name: code
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: The instrument.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationInstrument'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: Unknown code (or outside the caller's grant).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/validations/programs/{id}/issuances/{issuanceId}/void:
    parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - name: issuanceId
        in: path
        required: true
        schema:
          type: string
          format: uuid
    post:
      operationId: post-apx-v1-validations-programs-id-issuances-issuanceid-void
      security:
        - apxOAuth:
            - apx.validations:manage
        - apxOAuth:
            - apx.validations:redeem
      tags:
        - Validations
      summary: Void an issuance batch
      description: |-
        Transition `issued → void` for the batch, and every instrument in
        it that is `valid` or `expired` → `void` (Part 20 §20.2 rule 5) —
        the stolen sheet of QR codes. Instruments already `redeemed` are
        unaffected; their redemptions stand until reversed. The result's
        `voidDetail.voidedCount` says how many codes were voided. A `redeem`
        token may void only its own provider's batches (another
        provider's is 404, §20.5). Voiding a batch already `void` returns
        it unchanged (200). No event is published; the instrument read is
        the source of truth.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ValidationVoid'
      responses:
        '200':
          description: The voided issuance.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationIssuance'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such program or issuance, or another provider's under a `redeem` token (`target-not-found`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/validations/instruments/{code}/void:
    parameters:
      - name: code
        in: path
        required: true
        schema:
          type: string
    post:
      operationId: post-apx-v1-validations-instruments-code-void
      security:
        - apxOAuth:
            - apx.validations:manage
        - apxOAuth:
            - apx.validations:redeem
      tags:
        - Validations
      summary: Void a single validation code
      description: |-
        Transition one instrument `valid` or `expired` → `void` (Part 20
        §20.2 rule 5) — a single leaked code. A `redeemed` code cannot be
        voided (422 `instrument-invalid`; reverse the redemption first).
        Voiding a code already `void` returns it unchanged (200). As on
        the read, a code outside the caller's grant or provider is 404,
        never 403.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ValidationVoid'
      responses:
        '200':
          description: The voided instrument.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationInstrument'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: Unknown code (or outside the caller's grant or provider).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: The code is already `redeemed` (`instrument-invalid`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/validations/redemptions:
    post:
      operationId: post-apx-v1-validations-redemptions
      security:
        - apxOAuth:
            - apx.validations:manage
        - apxOAuth:
            - apx.validations:redeem
      tags:
        - Validations
      summary: Record a redemption (idempotent)
      description: |-
        Applies a validation to a ticket/session from a pay station,
        merchant app, or lane device — the data-plane counterpart of the
        Part 6 `applyValidation` command (which agents use to act on a
        lane; it materializes the same resource). `Idempotency-Key`
        REQUIRED. The server evaluates the program rules (Part 20 §20.3):
        422 `program-not-active`, `request-unprocessable` (the body's
        `place` is not the program's place or within its subtree),
        `instrument-invalid`, `redemption-limit-exceeded`. On success the session gains the APDS
        `Segment.validationId` and `amountReduced` reflects the ACTUAL
        reduction. Publishes `apx.validations.redeemed.v1`.
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ValidationRedemption'
      responses:
        '200':
          description: Idempotent replay — same key + same body returns the redemption's current representation (Part 4 §4.2a).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationRedemption'
        '201':
          description: Redemption applied.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationRedemption'
        '400':
          description: Missing Idempotency-Key (`idempotency-key-required`) or a body that fails the schema (`invalid-request`, with `errors[]`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: Idempotency-Key replayed with a different body.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: |-
            In §20.3 order: `program-not-active` (program not `active`);
            `request-unprocessable` (place mismatch — `detail` names the
            program's place); `instrument-invalid` (unknown, void, expired,
            or used code, or a required instrument absent);
            `redemption-limit-exceeded` (a program rule refuses it);
            `reference-unknown` (a body Reference names nothing visible).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    get:
      operationId: get-apx-v1-validations-redemptions
      security:
        - apxOAuth:
            - apx.validations:read
        - apxOAuth:
            - apx.validations:redeem
      tags:
        - Validations
      summary: List/filter redemptions
      description: |-
        Filter by program, place, ticket, session, the Part 6 command that
        applied it, channel, status, and `since` (appliedTime). A `redeem`
        token sees only its own provider's redemptions (§20.5).
      parameters:
        - $ref: '#/components/parameters/ModeParam'
        - $ref: '#/components/parameters/CursorParam'
        - name: program
          in: query
          schema:
            type: string
            format: uuid
        - name: command
          in: query
          required: false
          schema:
            type: string
            format: uuid
          description: The `applyValidation` Command (Part 6 §6.3) whose redemption to find — matches `ValidationRedemption.command`.
        - name: place
          in: query
          schema:
            type: string
            format: uuid
        - name: ticket
          in: query
          schema:
            type: string
        - name: session
          in: query
          schema:
            type: string
            format: uuid
        - name: channel
          in: query
          schema:
            type: string
            enum:
              - lane
              - payStation
              - merchantApp
              - callCenter
              - api
        - name: status
          in: query
          schema:
            type: string
            enum:
              - applied
              - reversed
        - name: since
          in: query
          schema:
            type: string
            format: date-time
        - $ref: '#/components/parameters/page'
      responses:
        '200':
          description: Paginated redemptions (APDS PaginatedList shape); with `mode=change`, the changes after `cursor` in the same envelope (Part 5 §5.2 rule 8).
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/ValidationRedemption'
                  updateMode:
                    $ref: '#/components/schemas/ChangeFeedUpdateMode'
                  cursor:
                    $ref: '#/components/schemas/ChangeFeedCursor'
                  deleted:
                    $ref: '#/components/schemas/ChangeFeedTombstones'
                  grantAdditions:
                    $ref: '#/components/schemas/ChangeFeedGrantAdditions'
                  next:
                    $ref: '#/components/schemas/ChangeFeedNext'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/CursorRefused'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/validations/redemptions/{id}:
    get:
      operationId: get-apx-v1-validations-redemptions-id
      security:
        - apxOAuth:
            - apx.validations:read
        - apxOAuth:
            - apx.validations:redeem
      tags:
        - Validations
      summary: Read a redemption
      description: |-
        Returns the redemption including any reversal and the immutable
        statusHistory. Another provider's redemption under a `redeem`
        token is 404 (Part 9 §9.3a rule 2).
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: The redemption.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationRedemption'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such redemption, or another provider's under a `redeem` token (`target-not-found`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/validations/redemptions/{id}/reverse:
    post:
      operationId: post-apx-v1-validations-redemptions-id-reverse
      security:
        - apxOAuth:
            - apx.validations:manage
      tags:
        - Validations
      summary: Reverse a redemption
      description: |-
        Transition `applied → reversed`; the amount due on the session is
        restored while the session is still open (Part 20 §20.4), and the
        instrument (if any) returns to `valid` while still within its
        window. Already reversed is 409 `redemption-reversed`. A
        redemption already billed on a CLOSED statement is reversed too:
        the closed statement is never edited; `reversal.closedStatement`
        names it, and the next statement closed for the program carries a
        negative `credit` line (`reversal.creditedOn` is set when it
        closes, §20.6).
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ValidationRedemptionReversal'
      responses:
        '200':
          description: Reversed redemption.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationRedemption'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such redemption.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: Already reversed (`redemption-reversed`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/validations/programs/{id}/statement:
    get:
      operationId: get-apx-v1-validations-programs-id-statement
      security:
        - apxOAuth:
            - apx.validations:read
        - apxOAuth:
            - apx.validations:redeem
      tags:
        - Validations
      summary: Preview a billing statement for a period
      description: |-
        Computes the program's redemptions and billable total for
        `from`..`to` under its billing model — a preview
        (`statementStatus: preview`, no `id`), including the `credit`
        lines the period would carry. Closing the period is
        `POST …/statements`. `from` not before `to` is 400
        `invalid-request`.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: from
          in: query
          required: true
          schema:
            type: string
            format: date-time
        - name: to
          in: query
          required: true
          schema:
            type: string
            format: date-time
      responses:
        '200':
          description: The computed statement.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationStatement'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such program.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/validations/programs/{id}/statements:
    parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
    post:
      operationId: post-apx-v1-validations-programs-id-statements
      security:
        - apxOAuth:
            - apx.validations:manage
      tags:
        - Validations
      summary: Close a billing period (idempotent)
      description: |-
        Freezes the period into an immutable statement the operator's
        accounting invoices from. `Idempotency-Key` REQUIRED. Periods MUST
        NOT overlap an existing closed statement (409 `statement-overlap`).
        The statement carries a negative `credit` line for every
        redemption reversed since an earlier statement billed it, and
        sets `reversal.creditedOn` on each (Part 20 §20.6). Publishes
        `apx.validations.statement.closed.v1`.
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ValidationStatementClose'
      responses:
        '200':
          description: Idempotent replay — same key + same body returns the statement (Part 4 §4.2a; a closed statement never changes).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationStatement'
        '201':
          description: Period closed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationStatement'
        '400':
          description: Missing Idempotency-Key (`idempotency-key-required`), or a period whose `periodStart` is not before `periodEnd` or a body that fails the schema (`invalid-request`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such program.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: Overlaps a closed statement, or Idempotency-Key replayed with a different body.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    get:
      operationId: get-apx-v1-validations-programs-id-statements
      security:
        - apxOAuth:
            - apx.validations:read
        - apxOAuth:
            - apx.validations:redeem
      tags:
        - Validations
      summary: List closed statements for a program
      description: Closed statements, newest period first; `lines[]` omitted.
      parameters:
        - $ref: '#/components/parameters/ModeParam'
        - $ref: '#/components/parameters/CursorParam'
        - $ref: '#/components/parameters/page'
      responses:
        '200':
          description: Paginated statements (APDS PaginatedList shape); with `mode=change`, the changes after `cursor` in the same envelope (Part 5 §5.2 rule 8).
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/ValidationStatement'
                  updateMode:
                    $ref: '#/components/schemas/ChangeFeedUpdateMode'
                  cursor:
                    $ref: '#/components/schemas/ChangeFeedCursor'
                  deleted:
                    $ref: '#/components/schemas/ChangeFeedTombstones'
                  grantAdditions:
                    $ref: '#/components/schemas/ChangeFeedGrantAdditions'
                  next:
                    $ref: '#/components/schemas/ChangeFeedNext'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such program, or (`mode=change`) a refused cursor (`target-not-found`; Part 5 §5.2 rules 2 and 5).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/validations/statements/{id}:
    get:
      operationId: get-apx-v1-validations-statements-id
      security:
        - apxOAuth:
            - apx.validations:read
        - apxOAuth:
            - apx.validations:redeem
      tags:
        - Validations
      summary: Read a closed statement
      description: |-
        The immutable statement with `lines[]`. Another provider's
        statement under a `redeem` token is 404 (Part 9 §9.3a rule 2).
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: The statement.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationStatement'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such statement, or another provider's under a `redeem` token (`target-not-found`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/credentials:
    post:
      operationId: post-apx-v1-credentials
      security:
        - apxOAuth:
            - apx.credentials:manage
      tags:
        - Credentials
      summary: Issue a credential (idempotent)
      description: |-
        Creates a CredentialRecord in `issued`. It becomes `active` either
        by a later `activate` call or, when the body sets
        `activateOnStart: true`, by the server itself at `validity.start`
        (at once when that is absent or past), with actor `system` (Part 21
        §21.1 rule 6). `Idempotency-Key` REQUIRED.
        `credentialIdentification` MUST be unique per `credentialType`
        among non-terminal records (409 `credential-identification-in-use`,
        whose `detail` MUST NOT identify the holding record, holder, or
        place — §21.5). Server-assigned members in the body (`id`,
        `version`, `credentialStatus`, `suspension`, `replacedBy`,
        `statusHistory`, `recordInfo`) are ignored. Publishes
        `apx.credentials.status.v1`.
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CredentialRecord'
      responses:
        '200':
          description: Idempotent replay — same key + same body returns the record as it stands now (Part 4 §4.2a).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CredentialRecord'
        '201':
          description: Credential issued.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CredentialRecord'
        '400':
          description: Missing Idempotency-Key (`idempotency-key-required`) or a record that fails the schema (`invalid-request`, with `errors[]`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: Identification already in use for this type (`credential-identification-in-use`), or Idempotency-Key replayed with a different body (`idempotency-conflict`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: |-
            Unknown holder, account, assigned right, or place
            (`reference-unknown`); or a validity window that is already over
            or inverted — `validity.end` not in the future, or before
            `validity.start` (`request-unprocessable`, Part 21 §21.1 rule 7).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    get:
      operationId: get-apx-v1-credentials
      security:
        - apxOAuth:
            - apx.credentials:read
      tags:
        - Credentials
      summary: List/filter credentials
      description: |-
        Filter by holder, account, type, identification, status, and place
        (subtree-inclusive). Results are constrained to the caller's place
        grant; identification values are personal data under Part 9 §9.6.
        A lookup by `identification` that matches only records outside the
        grant returns an empty 200 (Part 9 §9.3a).
      parameters:
        - $ref: '#/components/parameters/ModeParam'
        - $ref: '#/components/parameters/CursorParam'
        - name: holder
          in: query
          schema:
            type: string
            format: uuid
        - name: account
          in: query
          schema:
            type: string
            format: uuid
        - name: type
          in: query
          schema:
            $ref: '#/components/schemas/CredentialTypeEnum'
        - name: identification
          in: query
          schema:
            type: string
        - name: status
          in: query
          schema:
            type: string
            enum:
              - issued
              - active
              - suspended
              - lost
              - revoked
              - expired
              - replaced
        - name: place
          in: query
          schema:
            type: string
            format: uuid
        - $ref: '#/components/parameters/page'
      responses:
        '200':
          description: Paginated credentials (APDS PaginatedList shape); with `mode=change`, the changes after `cursor` in the same envelope (Part 5 §5.2 rule 8).
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/CredentialRecord'
                  updateMode:
                    $ref: '#/components/schemas/ChangeFeedUpdateMode'
                  cursor:
                    $ref: '#/components/schemas/ChangeFeedCursor'
                  deleted:
                    $ref: '#/components/schemas/ChangeFeedTombstones'
                  grantAdditions:
                    $ref: '#/components/schemas/ChangeFeedGrantAdditions'
                  next:
                    $ref: '#/components/schemas/ChangeFeedNext'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/CursorRefused'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/credentials/{id}:
    get:
      operationId: get-apx-v1-credentials-id
      security:
        - apxOAuth:
            - apx.credentials:read
      tags:
        - Credentials
      summary: Read a credential
      description: Returns the record including media, replacement links, and the immutable statusHistory.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: The credential.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CredentialRecord'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such credential.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/credentials/{id}/activate:
    post:
      operationId: post-apx-v1-credentials-id-activate
      security:
        - apxOAuth:
            - apx.credentials:manage
      tags:
        - Credentials
      summary: Activate a credential
      description: Transition `issued → active`; materializes the APDS CredentialAssigned (§21.2). Any other state is 409 `credential-transition-illegal`.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CredentialTransition'
      responses:
        '200':
          description: Active credential.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CredentialRecord'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such credential.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: Illegal transition.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/credentials/{id}/suspend:
    post:
      operationId: post-apx-v1-credentials-id-suspend
      security:
        - apxOAuth:
            - apx.credentials:manage
      tags:
        - Credentials
      summary: Suspend a credential
      description: Transition `active → suspended` (optionally `until`, which MUST be in the future — else 422 `request-unprocessable`); the lane MUST deny it meanwhile. Any other state is 409 `credential-transition-illegal`.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CredentialTransition'
      responses:
        '200':
          description: Suspended credential.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CredentialRecord'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such credential.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: Illegal transition.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: '`until` is not in the future (`request-unprocessable`, Part 21 §21.1 rule 7); nothing is written.'
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/credentials/{id}/resume:
    post:
      operationId: post-apx-v1-credentials-id-resume
      security:
        - apxOAuth:
            - apx.credentials:manage
      tags:
        - Credentials
      summary: Resume a suspended credential
      description: Transition `suspended → active`. Any other state is 409 `credential-transition-illegal`.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CredentialTransition'
      responses:
        '200':
          description: Active credential.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CredentialRecord'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such credential.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: Illegal transition.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/credentials/{id}/report-lost:
    post:
      operationId: post-apx-v1-credentials-id-report-lost
      security:
        - apxOAuth:
            - apx.credentials:manage
      tags:
        - Credentials
      summary: Report a credential lost or stolen
      description: Transition `active | suspended → lost`; the lane MUST deny it from this instant. Follow with `replace` or `revoke`. Any other state is 409 `credential-transition-illegal`.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CredentialTransition'
      responses:
        '200':
          description: Credential marked lost.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CredentialRecord'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such credential.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: Illegal transition.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/credentials/{id}/revoke:
    post:
      operationId: post-apx-v1-credentials-id-revoke
      security:
        - apxOAuth:
            - apx.credentials:manage
      tags:
        - Credentials
      summary: Revoke a credential (terminal)
      description: Transition `issued | active | suspended | lost → revoked`; removes the APDS CredentialAssigned. Terminal states are 409 `credential-transition-illegal`.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CredentialTransition'
      responses:
        '200':
          description: Revoked credential.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CredentialRecord'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such credential.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: Illegal transition.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/credentials/{id}/replace:
    post:
      operationId: post-apx-v1-credentials-id-replace
      security:
        - apxOAuth:
            - apx.credentials:manage
      tags:
        - Credentials
      summary: Replace a credential with a successor (idempotent)
      description: |-
        Issues a successor `active` record inheriting holder, account,
        assigned rights, places, and validity; links `replaces`/`replacedBy`;
        moves THIS record to `replaced` and swaps the APDS CredentialAssigned
        atomically. The predecessor keeps every other field it had (§21.3).
        Allowed from `active`, `suspended`, or `lost`. From `issued` it is
        409 `credential-transition-illegal` (revoke it and issue anew);
        `credential-not-replaceable` is reserved for the terminal states
        `revoked`, `expired`, `replaced`. `Idempotency-Key` REQUIRED.
        Returns the successor.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: Idempotency-Key
          in: header
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CredentialReplaceRequest'
      responses:
        '200':
          description: Idempotent replay — returns the successor as it stands now (Part 4 §4.2a).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CredentialRecord'
        '201':
          description: The successor credential.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CredentialRecord'
        '400':
          description: Missing Idempotency-Key (`idempotency-key-required`) or a body that fails the schema (`invalid-request`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such credential.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: |-
            Terminal record (`credential-not-replaceable`), a record still
            `issued` (`credential-transition-illegal`), successor
            identification in use (`credential-identification-in-use`), or
            key replayed with a different body (`idempotency-conflict`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/credentials/{id}/access-events:
    get:
      operationId: get-apx-v1-credentials-id-access-events
      security:
        - apxOAuth:
            - apx.credentials:read
      tags:
        - Credentials
      summary: Access-event history for a credential
      description: |-
        Entry/exit attempts with this credential, newest first — granted
        or denied, where, and why. The same events are published as
        `apx.credentials.access.v1`. Retention per Part 9 §9.6.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: since
          in: query
          schema:
            type: string
            format: date-time
        - name: until
          in: query
          description: Exclusive upper bound on `occurredAt`.
          schema:
            type: string
            format: date-time
        - name: outcome
          in: query
          schema:
            type: string
            enum:
              - granted
              - denied
        - name: direction
          in: query
          schema:
            type: string
            enum:
              - entry
              - exit
        - $ref: '#/components/parameters/page'
      responses:
        '200':
          description: Paginated access events (APDS PaginatedList shape).
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/CredentialAccessEvent'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such credential.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/access-events:
    get:
      operationId: get-apx-v1-access-events
      security:
        - apxOAuth:
            - apx.credentials:read
      tags:
        - Credentials
      summary: Access events by place, lane, or reader
      description: |-
        Every access attempt at the caller's granted places, newest first —
        including presentations that matched no CredentialRecord
        (`denialReason: unknownCredential`, carrying `presented`). "Every
        denial at lane 1 tonight" is `?lane=…&outcome=denied&since=…`.
        Results are constrained to the caller's place grant; naming a
        place, lane, or device outside it is 403 `insufficient-grant`
        (Part 9 §9.3a). Retention per Part 9 §9.6. The same events are
        published as `apx.credentials.access.v1` (Part 21 §21.4).
      parameters:
        - $ref: '#/components/parameters/ModeParam'
        - $ref: '#/components/parameters/CursorParam'
        - name: place
          in: query
          description: HierarchyElement ids, comma-separated; subtree-inclusive.
          style: form
          explode: false
          schema:
            type: array
            items:
              type: string
              format: uuid
        - name: lane
          in: query
          description: The VehicularAccess.
          schema:
            type: string
            format: uuid
        - name: device
          in: query
          description: The reader (SupplementalEquipment).
          schema:
            type: string
            format: uuid
        - name: credential
          in: query
          description: A CredentialRecord id.
          schema:
            type: string
            format: uuid
        - name: outcome
          in: query
          schema:
            type: string
            enum:
              - granted
              - denied
        - name: denialReason
          in: query
          description: definedValue from `apx-access-denial-reasons` (or an implementer code list).
          schema:
            type: string
        - name: direction
          in: query
          schema:
            type: string
            enum:
              - entry
              - exit
        - name: since
          in: query
          description: Inclusive lower bound on `occurredAt`.
          schema:
            type: string
            format: date-time
        - name: until
          in: query
          description: Exclusive upper bound on `occurredAt`.
          schema:
            type: string
            format: date-time
        - $ref: '#/components/parameters/page'
      responses:
        '200':
          description: Paginated access events (APDS PaginatedList shape); with `mode=change`, the changes after `cursor` in the same envelope (Part 5 §5.2 rule 8).
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/AccessEvent'
                  updateMode:
                    $ref: '#/components/schemas/ChangeFeedUpdateMode'
                  cursor:
                    $ref: '#/components/schemas/ChangeFeedCursor'
                  deleted:
                    $ref: '#/components/schemas/ChangeFeedTombstones'
                  grantAdditions:
                    $ref: '#/components/schemas/ChangeFeedGrantAdditions'
                  next:
                    $ref: '#/components/schemas/ChangeFeedNext'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/CursorRefused'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/valet/tickets:
    post:
      operationId: post-apx-v1-valet-tickets
      security:
        - apxOAuth:
            - apx.valet:manage
      tags:
        - Valet
      summary: Take custody of a vehicle (drop-off, idempotent)
      description: |-
        Creates the ValetTicket in `dropped` with the drop-off condition
        report. `Idempotency-Key` REQUIRED (handhelds and scanning devices
        retry). The server SHOULD open the APDS Session for the stay and
        reference it, unless the body already references one. `storage`,
        `retrieval`, `handback`, `statusHistory`, and `recordInfo` in the
        body are ignored — the server writes them (Part 22 §22.1 rule 5).
        A `customer.contactChannel.handle` that carries a raw phone number
        or e-mail address SHOULD be refused with 422
        `personal-data-not-permitted` rather than stored or silently
        masked (§22.6). Publishes `apx.valet.ticket.status.v1`.
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ValetTicket'
      responses:
        '200':
          description: Idempotent replay — same key + same body returns the ticket as it stands now (Part 4 §4.2a).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValetTicket'
        '201':
          description: Custody taken.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValetTicket'
        '400':
          description: Missing Idempotency-Key (`idempotency-key-required`) or a ticket that fails the schema (`invalid-request`, with `errors[]`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: Idempotency-Key replayed with a different body (`idempotency-conflict`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: |-
            Unknown place, lane, session, or customer reference
            (`reference-unknown`), or a raw phone number or e-mail address
            where an opaque handle is required (`personal-data-not-permitted`,
            §22.6).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    get:
      operationId: get-apx-v1-valet-tickets
      security:
        - apxOAuth:
            - apx.valet:read
      tags:
        - Valet
      summary: List/filter valet tickets
      description: Filter by place (subtree-inclusive), status, plate, ticket number, customer account, and `since` (dropOff.time).
      parameters:
        - $ref: '#/components/parameters/ModeParam'
        - $ref: '#/components/parameters/CursorParam'
        - name: place
          in: query
          schema:
            type: string
            format: uuid
        - name: status
          in: query
          schema:
            type: string
            enum:
              - dropped
              - parked
              - requested
              - retrieving
              - staged
              - handedBack
              - closed
              - cancelled
        - name: plate
          in: query
          schema:
            type: string
        - name: ticketNumber
          in: query
          schema:
            type: string
        - name: account
          in: query
          schema:
            type: string
            format: uuid
        - name: since
          in: query
          schema:
            type: string
            format: date-time
        - $ref: '#/components/parameters/page'
      responses:
        '200':
          description: Paginated tickets (APDS PaginatedList shape); with `mode=change`, the changes after `cursor` in the same envelope (Part 5 §5.2 rule 8).
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/ValetTicket'
                  updateMode:
                    $ref: '#/components/schemas/ChangeFeedUpdateMode'
                  cursor:
                    $ref: '#/components/schemas/ChangeFeedCursor'
                  deleted:
                    $ref: '#/components/schemas/ChangeFeedTombstones'
                  grantAdditions:
                    $ref: '#/components/schemas/ChangeFeedGrantAdditions'
                  next:
                    $ref: '#/components/schemas/ChangeFeedNext'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/CursorRefused'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/valet/queue:
    get:
      operationId: get-apx-v1-valet-queue
      security:
        - apxOAuth:
            - apx.valet:read
      tags:
        - Valet
      summary: The retrieval queue for a place (attendant board)
      description: |-
        Tickets in `requested`, `retrieving`, or `staged` at the place,
        ordered by `retrieval.promisedTime` ascending — what the runners
        and the stand see. Scheduled pickups (`requestedFor`) appear when
        they fall inside `horizonMinutes` (default 60).
      parameters:
        - name: place
          in: query
          required: true
          schema:
            type: string
            format: uuid
        - name: horizonMinutes
          in: query
          required: false
          schema:
            type: integer
            minimum: 0
            default: 60
        - $ref: '#/components/parameters/page'
      responses:
        '200':
          description: The queue (APDS PaginatedList shape).
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/ValetTicket'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such place.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/valet/tickets/{id}:
    get:
      operationId: get-apx-v1-valet-tickets-id
      security:
        - apxOAuth:
            - apx.valet:read
        - apxOAuth:
            - apx.valet:request
      tags:
        - Valet
      summary: Read a valet ticket
      description: |-
        Full record for operator scopes. A `apx.valet:request` token sees
        only its own ticket, as the minimized projection of Part 22 §22.5
        — `id`, `version`, `place`, `ticketNumber`, `vehicle`,
        `customer.displayName`, `dropOff.time`, `retrieval.{requestedTime,
        requestedFor, channel, etaMinutes, promisedTime, stagingLane,
        stagedTime, cancelledTime}`, `handback.time`, `valetStatus`, and
        `extensions`; everything else, including `statusHistory`, is
        omitted. The same projection applies to the ticket a
        `apx.valet:request` token gets back from `retrieve` and
        `cancel-retrieval`. An operator token gets 403 `insufficient-grant` for a
        ticket at a place outside its grant (Part 9 §9.3a).
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: The ticket.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValetTicket'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such ticket, or — for an `apx.valet:request` token — a ticket it is not bound to (`target-not-found`; existence is never disclosed, Part 9 §9.3a).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/valet/tickets/{id}/park:
    post:
      operationId: post-apx-v1-valet-tickets-id-park
      security:
        - apxOAuth:
            - apx.valet:manage
      tags:
        - Valet
      summary: Record the parked position and key location
      description: |-
        Transition `dropped → parked`; update `storage` while `parked`; or
        re-park a `staged` car the customer is not collecting yet
        (`staged → parked`: records the new `storage`, clears
        `retrieval.stagingLane`/`stagedTime`, and sets
        `retrieval.cancelledTime` and `cancelReason: re-parked`). Any
        other state is 409 `valet-transition-illegal`. Send `If-Match`
        with the version last read so two runners cannot overwrite each
        other's `storage`: a stale value is 409 `version-conflict` (Part 4
        §4.2a); without it the write is last-writer-wins.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - $ref: '#/components/parameters/IfMatch'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ValetParkRequest'
      responses:
        '200':
          description: Parked ticket.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValetTicket'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such ticket.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: Illegal transition (`valet-transition-illegal`), or a stale `If-Match` (`version-conflict`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/valet/tickets/{id}/retrieve:
    post:
      operationId: post-apx-v1-valet-tickets-id-retrieve
      security:
        - apxOAuth:
            - apx.valet:manage
        - apxOAuth:
            - apx.valet:request
      tags:
        - Valet
      summary: Request the vehicle (now or scheduled)
      description: |-
        Transition `parked → requested`. The customer's text, app, web
        page, or voice bot calls this on `apx.valet:request` for its own
        ticket; attendants and the call center on `apx.valet:manage`. The
        server sets `retrieval.etaMinutes` and `promisedTime` and
        publishes `apx.valet.retrieval.requested.v1`. A repeat while
        `requested` or `retrieving` ("CAR" texted twice) is not an error:
        200 with the current ticket and ETA, nothing appended or
        republished, and the body's `requestedFor` ignored (to reschedule,
        `cancel-retrieval` then `retrieve`). From `dropped` (not yet
        parked) it is 409 `valet-vehicle-not-located`; from `staged`,
        `handedBack`, `closed`, or `cancelled` it is 409
        `valet-transition-illegal`.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ValetRetrievalRequest'
      responses:
        '200':
          description: Requested ticket with ETA (or the unchanged ticket, for a repeat while `requested`/`retrieving`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValetTicket'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such ticket, or — for an `apx.valet:request` token — a ticket it is not bound to (`target-not-found`, Part 9 §9.3a). An operator token gets 403 `insufficient-grant` for a ticket outside its grant.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: Vehicle not yet located, or illegal transition.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/valet/tickets/{id}/cancel-retrieval:
    post:
      operationId: post-apx-v1-valet-tickets-id-cancel-retrieval
      security:
        - apxOAuth:
            - apx.valet:manage
        - apxOAuth:
            - apx.valet:request
      tags:
        - Valet
      summary: Cancel an open retrieval request
      description: Transition `requested | retrieving → parked`. A staged car is re-parked by the operator with `park`, not cancelled here. Any other state is 409 `valet-transition-illegal`.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ValetCancelRetrievalRequest'
      responses:
        '200':
          description: Ticket back in `parked`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValetTicket'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such ticket, or — for an `apx.valet:request` token — a ticket it is not bound to (`target-not-found`, Part 9 §9.3a). An operator token gets 403 `insufficient-grant` for a ticket outside its grant.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: Illegal transition.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/valet/tickets/{id}/stage:
    post:
      operationId: post-apx-v1-valet-tickets-id-stage
      security:
        - apxOAuth:
            - apx.valet:manage
      tags:
        - Valet
      summary: Vehicle at the staging lane
      description: Transition `requested | retrieving → staged`; sets `retrieval.stagingLane`/`stagedTime` and notifies the customer's contact channel. Any other state is 409 `valet-transition-illegal`.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ValetStageRequest'
      responses:
        '200':
          description: Staged ticket.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValetTicket'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such ticket.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: Illegal transition.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/valet/tickets/{id}/handback:
    post:
      operationId: post-apx-v1-valet-tickets-id-handback
      security:
        - apxOAuth:
            - apx.valet:manage
      tags:
        - Valet
      summary: Hand the vehicle to a verified customer
      description: |-
        Transition `staged → handedBack` (or `dropped → handedBack` before
        the car moved). The attendant verifies the claimant
        (`verificationMethod`) — a mismatch is 403
        `valet-verification-failed` and MUST be recorded in
        `statusHistory`. Records the handback condition report. The APDS
        Session closes per the operator's flow; `closed` follows
        server-side when it settles.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ValetHandbackRequest'
      responses:
        '200':
          description: Handed back.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValetTicket'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: Insufficient scope/grant, or claimant verification failed.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '404':
          description: No such ticket.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: Illegal transition.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/valet/tickets/{id}/pickup:
    post:
      operationId: post-apx-v1-valet-tickets-id-pickup
      security:
        - apxOAuth:
            - apx.valet:manage
      tags:
        - Valet
      summary: A runner has gone for the car
      description: |-
        Transition `requested → retrieving`; sets
        `retrieval.retrievingBy` (the body's value, else the calling
        principal) — what the runner board shows as "on its way". Optional:
        `stage` from `requested` remains valid, and a server MAY infer
        `retrieving` from its own runner assignment instead (Part 22 §22.1
        rule 2). Any other state is 409 `valet-transition-illegal`.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ValetPickupRequest'
      responses:
        '200':
          description: Ticket in `retrieving`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValetTicket'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: Illegal transition (`valet-transition-illegal`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/valet/tickets/{id}/cancel:
    post:
      operationId: post-apx-v1-valet-tickets-id-cancel
      security:
        - apxOAuth:
            - apx.valet:manage
      tags:
        - Valet
      summary: Abandon a drop-off before custody (terminal)
      description: |-
        Transition `dropped → cancelled` — the driver left before the car
        moved, or the ticket was opened in error. Appends
        `statusHistory[]` and publishes `apx.valet.ticket.status.v1`; the
        server SHOULD close the APDS Session it opened at drop-off at no
        charge. A customer who changes their mind *after* the walk-around
        but takes the car back is `handback` from `dropped` instead. Any
        other state is 409 `valet-transition-illegal`.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ValetCancelRequest'
      responses:
        '200':
          description: Ticket `cancelled`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValetTicket'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: Illegal transition (`valet-transition-illegal`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/valet/tickets/{id}/condition:
    post:
      operationId: post-apx-v1-valet-tickets-id-condition
      security:
        - apxOAuth:
            - apx.valet:manage
      tags:
        - Valet
      summary: Append a condition-report correction
      description: |-
        Records a finding made after drop-off — the door ding a runner sees
        at P3 — without editing the drop-off report (Part 22 §22.2 rule 3).
        Each `damage[]` entry is appended to
        `dropOff.conditionReport.damage[]` stamped with a server-set
        `recordedTime` and `recordedBy` (the body's `recordedBy`, else the
        calling principal); `imageLinks[]` are appended to the report's
        `imageLinks[]`; `notes` becomes the `detail` of a new
        `statusHistory[]` entry whose `state` is the unchanged
        `valetStatus`. The report's original `notes`, `recordedTime`,
        `recordedBy`, and `customerAcknowledged` never change, and
        `customerAcknowledged` in the body is ignored. Legal in any state
        except `closed` and `cancelled` (409 `valet-transition-illegal`).
        Send `Idempotency-Key` when retrying: an append retried without
        one is appended twice.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - $ref: '#/components/parameters/IdempotencyKeyOptional'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ConditionReport'
      responses:
        '200':
          description: The ticket with the correction appended (or, on an idempotent replay, the current ticket).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValetTicket'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: Ticket `closed` or `cancelled` (`valet-transition-illegal`), or Idempotency-Key replayed with a different body (`idempotency-conflict`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/charging/points:
    get:
      operationId: get-apx-v1-charging-points
      security:
        - apxOAuth:
            - apx.charging:read
        - apxOAuth:
            - apx.charging:status
      tags:
        - Charging
      summary: List live charging-point status for a place
      description: |-
        ChargingPointStatus for every ElectricChargingEquipment under the
        place (subtree-inclusive), optionally filtered by `availability`
        — "is there a free charger". A `apx.charging:status` token
        receives the minimized form (no `bay.vehicle`, no `bay.imageLink`,
        no `currentSession`; Part 23 §23.6).
      parameters:
        - name: place
          in: query
          required: true
          schema:
            type: string
            format: uuid
        - name: availability
          in: query
          schema:
            type: string
            enum:
              - available
              - occupied
              - charging
              - reserved
              - blocked
              - inoperative
              - outOfOrder
              - unknown
        - $ref: '#/components/parameters/page'
      responses:
        '200':
          description: Charging-point status list (APDS PaginatedList shape).
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/ChargingPointStatus'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such place.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/charging/points/{id}:
    get:
      operationId: get-apx-v1-charging-points-id
      security:
        - apxOAuth:
            - apx.charging:read
        - apxOAuth:
            - apx.charging:status
      tags:
        - Charging
      summary: Read one charging point's live status
      description: ChargingPointStatus keyed by the ElectricChargingEquipment id. Minimized for `apx.charging:status` (Part 23 §23.6).
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: The status overlay.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChargingPointStatus'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such charging point (or outside the caller's grant).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/charging/points/{id}/status:
    put:
      operationId: put-apx-v1-charging-points-id-status
      security:
        - apxOAuth:
            - apx.charging:manage
      tags:
        - Charging
      summary: Bridge pushes the point's availability
      description: |-
        The charging-network bridge (the operator's OCPP/OCPI integration)
        replaces the point-level and per-connector `availability`,
        `currentSession`, `reservedFor`, and `lastCommunication`. The `bay`
        block is NOT written here — it comes from `…/bay` and is fused by
        the server (Part 23 §23.3); a `bay` in this body is ignored.
        Publishes `apx.charging.point.status.v1` when availability
        changes.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ChargingPointStatus'
      responses:
        '200':
          description: The fused status after the update.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChargingPointStatus'
        '400':
          description: Body `chargingPoint` does not match the path id.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such charging point.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/charging/points/{id}/bay:
    post:
      operationId: post-apx-v1-charging-points-id-bay
      security:
        - apxOAuth:
            - apx.charging:manage
      tags:
        - Charging
      summary: Camera or sensor reports what is in the bay
      description: |-
        An overhead-camera analytics system, ground sensor, or attendant
        reports the bay's physical presence: empty, vehicle plugged in,
        vehicle NOT plugged in, blocked. The server fuses it with the
        charger's connector state (Part 23 §23.3 table) into
        `ChargingPointStatus.bay` and derives `availability: blocked` when
        no cable is connected (a connected cable wins). A vehicle not
        plugged in past the place's grace SHOULD raise the proposed
        `evBayNotCharging` alert — or the seeded `iceInEvSpace` when
        `vehicle.evCapable` is false; an obstructed bay SHOULD raise the
        proposed `evBayBlocked` alert (Part 7; Part 23 §23.3).
        `Idempotency-Key` REQUIRED (cameras re-send).
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: Idempotency-Key
          in: header
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ChargingBayPresence'
      responses:
        '200':
          description: The fused status after the observation.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChargingPointStatus'
        '400':
          description: Missing Idempotency-Key or invalid observation.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such charging point.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/charging/sessions:
    post:
      operationId: post-apx-v1-charging-sessions
      security:
        - apxOAuth:
            - apx.charging:manage
      tags:
        - Charging
      summary: Open a charging session (authorization, idempotent)
      description: |-
        Creates the ChargingSession in `authorized` with the authorization,
        the point and connector, the parking Session it belongs to, the
        settlement mode, and the idle policy snapshot; the plug-in itself
        arrives as a `pluggedIn` event (Part 23 §23.2). `Idempotency-Key`
        REQUIRED. 409 `charging-point-unavailable` when the point or
        connector is inoperative, out of order, reserved for someone else,
        or already serving an active session. Publishes
        `apx.charging.session.status.v1`.
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ChargingSession'
      responses:
        '200':
          description: Idempotent replay — same key + same body returns the ORIGINAL session.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChargingSession'
        '201':
          description: Session opened.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChargingSession'
        '400':
          description: Missing Idempotency-Key or invalid session.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: Point/connector unavailable, or Idempotency-Key replayed with a different body.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: Unknown place, charging point, parking session, or credential reference; or `settlement.mode` parkingSession without `parkingSession`.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    get:
      operationId: get-apx-v1-charging-sessions
      security:
        - apxOAuth:
            - apx.charging:read
      tags:
        - Charging
      summary: List/filter charging sessions
      description: Filter by place (subtree-inclusive), charging point, status, plate, parking session, account, and `since` (timeline.authorizedTime).
      parameters:
        - $ref: '#/components/parameters/ModeParam'
        - $ref: '#/components/parameters/CursorParam'
        - name: place
          in: query
          schema:
            type: string
            format: uuid
        - name: chargingPoint
          in: query
          schema:
            type: string
            format: uuid
        - name: status
          in: query
          schema:
            type: string
            enum:
              - authorized
              - pluggedIn
              - charging
              - suspended
              - complete
              - idle
              - unplugged
              - closed
              - cancelled
              - faulted
        - name: plate
          in: query
          schema:
            type: string
        - name: parkingSession
          in: query
          schema:
            type: string
            format: uuid
        - name: account
          in: query
          schema:
            type: string
            format: uuid
        - name: since
          in: query
          schema:
            type: string
            format: date-time
        - $ref: '#/components/parameters/page'
      responses:
        '200':
          description: Paginated sessions (APDS PaginatedList shape); with `mode=change`, the changes after `cursor` in the same envelope (Part 5 §5.2 rule 8).
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/ChargingSession'
                  updateMode:
                    $ref: '#/components/schemas/ChangeFeedUpdateMode'
                  cursor:
                    $ref: '#/components/schemas/ChangeFeedCursor'
                  deleted:
                    $ref: '#/components/schemas/ChangeFeedTombstones'
                  grantAdditions:
                    $ref: '#/components/schemas/ChangeFeedGrantAdditions'
                  next:
                    $ref: '#/components/schemas/ChangeFeedNext'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/CursorRefused'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/charging/sessions/{id}:
    get:
      operationId: get-apx-v1-charging-sessions-id
      security:
        - apxOAuth:
            - apx.charging:read
        - apxOAuth:
            - apx.charging:status
      tags:
        - Charging
      summary: Read a charging session
      description: |-
        Full record for operator scopes. A `apx.charging:status` token sees
        only its own session(s), minimized (Part 23 §23.6): status, energy
        and state of charge, timeline, idle policy and idle clock, cost
        totals, the point and connector — no plate, no credential or
        contract id, no network identifiers. Enough for "your car is at
        62%, charging ends in about 40 minutes; 10 minutes grace, then
        $0.40 per minute".
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: The session.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChargingSession'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such session (or outside the caller's grant).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/charging/sessions/{id}/events:
    post:
      operationId: post-apx-v1-charging-sessions-id-events
      security:
        - apxOAuth:
            - apx.charging:manage
      tags:
        - Charging
      summary: Bridge reports a physical-timeline event
      description: |-
        The APX counterpart of an OCPP 2.0.1 TransactionEvent. Applies the
        transition for `eventType` per Part 23 §23.2 — `pluggedIn`,
        `chargingStarted`, `suspended`/`resumed`, `chargingEnded`,
        `unplugged`, `fault`, `cancelled` — or, for `meterValue`, updates
        `energy` in place. Events MUST be applied in `time` order; one that
        is illegal from the current state is 409
        `charging-transition-illegal` (a `meterValue` after `unplugged`, a
        `pluggedIn` after `charging`). `Idempotency-Key` REQUIRED. Every
        state change appends `statusHistory` and publishes
        `apx.charging.session.status.v1`; `complete → idle` is server-side
        after `idlePolicy.graceMinutes` and additionally publishes
        `apx.charging.idle.started.v1`.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: Idempotency-Key
          in: header
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ChargingEvent'
      responses:
        '200':
          description: The session after the event.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChargingSession'
        '400':
          description: Missing Idempotency-Key or invalid event.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such session.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: Illegal transition from the current state, or Idempotency-Key replayed with a different body.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/charging/sessions/{id}/payment:
    post:
      operationId: post-apx-v1-charging-sessions-id-payment
      security:
        - apxOAuth:
            - apx.charging:manage
      tags:
        - Charging
      summary: Attach the settling payment or the network's CDR
      description: |-
        For `settlement.mode: directPayment`, attaches the settling
        Payment reference and moves an `unplugged` session to `closed`;
        before `unplugged` the final cost is unknown and it is 409
        `charging-settlement-conflict`. For `chargingNetwork`, records the
        charge detail record id. For `parkingSession` it is 409
        `charging-settlement-conflict` — that session closes when the APDS
        Session settles. Also 409 when the session is already `closed`.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ChargingPaymentAttachment'
      responses:
        '200':
          description: The settled session.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChargingSession'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such session.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: Settlement mode does not take a payment here, session not yet unplugged, or already closed.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/lpr/reads/{observation}:
    get:
      operationId: get-apx-v1-lpr-reads-observation
      security:
        - apxOAuth:
            - apx.lpr:read
      tags:
        - LPR
      summary: Read back one ingested LPR read by its Observation id
      description: |-
        One `LprRead` for the Observation (Part 13 §13.3). The same
        projection as `GET /v1/lpr/reads?observation=`, addressed by path
        like the revision routes. A read at a place outside the caller's
        `apx_places` grant is 403 `insufficient-grant`; an unknown or purged
        read is 404 `target-not-found` (§13.3b).
      parameters:
        - name: observation
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: The read.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LprRead'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/lpr/reads/{observation}/plate:
    put:
      operationId: put-apx-v1-lpr-reads-observation-plate
      security:
        - apxOAuth:
            - apx.data:write
      tags:
        - LPR
      summary: A reviewer confirms, corrects, or rejects a read's plate
      description: |-
        Read-level plate review (Part 13 §13.3a(4a)), the counterpart of
        the access-event revision: a reviewer's decision on one read,
        before any Session exists and however many Sessions the read
        feeds. `corrected` writes the winning values into the
        Observation's `observedCredentialId` and
        `vehicleAncillaryIdentification` and into `detail.plate`,
        `.country`, `.stateProvince`, keeping the engine's values, with
        their confidences, in `detail.review.original` — set on the first
        correction and never changed afterwards. Every decision that
        changes the read sets `detail.review`, increments the Observation
        `version`, and publishes `apx.data.observation.updated.v1`.
        Resending the decision and values the read already has is a
        no-op: 200 with the current `version`, no new version, no event.
        `If-Match` carries the Observation `version` last read (409
        `version-conflict` when stale; nothing is written). `corrected`
        without `plate`, or `plate`, `country`, or `stateProvince` with
        any other decision, is 422 `request-unprocessable`. A `pending` or
        `rejected` read is not issuable evidence (Part 19 §19.4 rule 6).
        The write changes no Session.

        The 200 is the read as it now stands when the caller also holds
        `apx.lpr:read`; otherwise (scope `apx.data:write` alone suffices
        for the write) it is the access-event-style minimal echo, which
        carries only the plate values the caller itself supplied and
        discloses no other plate-bearing data (Part 9 §9.6).
      parameters:
        - name: observation
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - $ref: '#/components/parameters/IfMatch'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PlateCorrection'
      responses:
        '200':
          description: The read after the decision.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/LprRead'
                  - type: object
                    required:
                      - observation
                      - version
                      - review
                    properties:
                      observation:
                        $ref: '#/components/schemas/Reference'
                      version:
                        type: integer
                        minimum: 1
                      review:
                        type: object
                        properties:
                          state:
                            type: string
                            enum:
                              - pending
                              - confirmed
                              - corrected
                              - rejected
                              - notRequired
                      plate:
                        type: string
                        description: Echoed only when the caller sent it.
                      country:
                        type: string
                        description: Echoed only when the caller sent it.
                      stateProvince:
                        type: string
                        description: Echoed only when the caller sent it.
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: '`If-Match` names a stale Observation version (`version-conflict`); nothing is written.'
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: '`corrected` without a `plate`, or `plate`, `country`, or `stateProvince` sent with another decision (`request-unprocessable`); nothing is written.'
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/lpr/reads:search:
    post:
      operationId: post-apx-v1-lpr-reads-search
      security:
        - apxOAuth:
            - apx.lpr:read
      tags:
        - LPR
      summary: The reads lookup with the plate in a body, never a URL
      description: |-
        The same lookup as `GET /v1/lpr/reads`, with the keys in the body
        so a plate never enters a URL that proxies, gateways, and access
        logs keep (Part 9 §9.6; Part 13 §13.3). Same rules, grant
        behaviour, and response. The `GET` keeps working; a deployment
        that crosses a network boundary SHOULD use this form.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/LprReadSearch'
      responses:
        '200':
          description: Matching reads.
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/LprRead'
        '400':
          description: None of `plate`, `ticket`, `observation`, or `session` given (`invalid-request`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/accounts:search:
    post:
      operationId: post-apx-v1-accounts-search
      security:
        - apxOAuth:
            - apx.accounts:read
      tags:
        - Accounts
      summary: The account lookup with personal data in a body, never a URL
      description: |-
        The same lookup as `GET /v1/accounts` (Part 13 §13.1) with the keys
        in the body (Part 9 §9.6). Same rules, grant behaviour, and
        response; a card number pasted into `card` is 422
        `personal-data-not-permitted`.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AccountSearch'
      responses:
        '200':
          description: Matching accounts.
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Account'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          description: More than truncated card digits in `card` (`personal-data-not-permitted`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/payments:search:
    post:
      operationId: post-apx-v1-payments-search
      security:
        - apxOAuth:
            - apx.accounts:read
      tags:
        - Accounts
      summary: The payment-history lookup with the keys in a body
      description: |-
        The same lookup as `GET /v1/payments` (Part 13 §13.2) with the keys
        in the body (Part 9 §9.6). Same keys rule (at least one), 8-hour
        window on truncated keys, hold rules, grant behaviour, and response.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PaymentSearch'
      responses:
        '200':
          description: Matching payments.
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/PaymentRecord'
        '400':
          description: No key given (`invalid-request`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          description: More than four card digits in `cardLast4` (`personal-data-not-permitted`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/violations:search:
    post:
      operationId: post-apx-v1-violations-search
      security:
        - apxOAuth:
            - apx.violations:read
      tags:
        - Violations
      summary: The violations lookup with the plate in a body
      description: |-
        The same lookup as `GET /v1/violations` (Part 19 §19.2) with the
        keys in the body (Part 9 §9.6). Same rules and response.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                plate:
                  type: string
                noticeNumber:
                  type: string
                status:
                  type: string
                  enum:
                    - detected
                    - confirmed
                    - dismissed
                    - issued
                    - paid
                    - appealed
                    - closed
                    - voided
                type:
                  type: string
                place:
                  type: string
                  format: uuid
                detectionMode:
                  type: string
                  enum:
                    - automated
                    - guided
                    - manual
                since:
                  type: string
                  format: date-time
                until:
                  type: string
                  format: date-time
                sourceSystem:
                  type: string
                sourceRecordId:
                  type: string
                page:
                  type: integer
                  minimum: 1
      responses:
        '200':
          description: Matching violations.
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Violation'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/enforcement/eligibility:check:
    post:
      operationId: post-apx-v1-enforcement-eligibility-check
      security:
        - apxOAuth:
            - apx.violations:read
      tags:
        - Violations
      summary: The eligibility check with the credential in a body
      description: |-
        The same question as `GET /v1/enforcement/eligibility` (Part 19
        §19.3) with the credential in the body (Part 9 §9.6). Same answer.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - credential
                - place
              properties:
                credential:
                  type: string
                credentialType:
                  $ref: '#/components/schemas/CredentialTypeEnum'
                place:
                  type: string
                  format: uuid
                at:
                  type: string
                  format: date-time
      responses:
        '200':
          description: The eligibility result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EligibilityResult'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/enforcement/violation-imports:
    post:
      operationId: post-apx-v1-enforcement-violation-imports
      security:
        - apxOAuth:
            - apx.violations:manage
      tags:
        - Violations
      summary: Import a violation an external enforcement system issued (idempotent)
      description: |-
        Records a citation, warning, or notice that another system
        detected and issued, in whatever state the source reports it,
        with the `statusHistory[]` times the source recorded (Part 19
        §19.13). The path is under `/v1/enforcement`, like the eligibility
        check, so it cannot be mistaken for `/v1/violations/{id}` (§19.2).

        `Idempotency-Key` is REQUIRED and the record is also keyed on the
        decoration's `system` + `recordId`: a later import with a higher
        `sourceRevision` — or, when the source keeps no counter, a later
        `sourceUpdatedTime` — updates the record (200, version + 1,
        `apx.violations.status.v1`); the same revision is a no-op 200; an
        older one is 409 `version-conflict`. `statusHistory[]` is
        append-only: the server keeps the entries it holds and appends only
        the source's later ones, never rewriting history.

        A state at or past issuance (`issued`, `paid`, `appealed`,
        `closed`) without `notice` (with `noticeNumber` and `issuedTime`)
        or `amount` is 400 `invalid-request`; `paid` with `amountPaid`
        below `amount` is 422 `request-unprocessable`. The server performs
        no eligibility check and applies no policy clamp to an imported
        amount: the source decided. Publishes `apx.violations.detected.v1`
        on first import, and `.issued.v1` when the imported state is at or
        beyond `issued`.
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ViolationImport'
      responses:
        '200':
          description: An existing import updated, the same revision again (no change), or an idempotent replay.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Violation'
        '201':
          description: Imported.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Violation'
        '400':
          description: |-
            Missing `Idempotency-Key` (`idempotency-key-required`), or a body
            that fails the schema — no `apds-ext:apx:violation-source@1.0`,
            or a state at or past issuance without `notice` or `amount`
            (`invalid-request`, with `errors[]`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: '`Idempotency-Key` replayed with a different body (`idempotency-conflict`), or a source revision older than the one held (`version-conflict`).'
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: |-
            Unknown `place` or a `violationType` outside the served
            registries (`reference-unknown`); `violationStatus: paid` with
            `amountPaid` below `amount`, or a payment in another currency
            than `amount` (`request-unprocessable`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/violations/{id}/session:
    post:
      operationId: post-apx-v1-violations-id-session
      security:
        - apxOAuth:
            - apx.violations:manage
      tags:
        - Violations
      summary: Set, correct, or clear the Session a violation relates to
      description: |-
        Sets, corrects, or clears (`session: null`) `relatedSession` after
        creation, with the match evidence (Part 19 §19.13;
        `apds-ext:apx:match-evidence@1.0` is written onto the violation).
        The link is not a lifecycle transition: it is valid in every
        state, terminal ones included, and appends nothing to
        `statusHistory[]`. `If-Match` carries the Violation `version` last
        read (409 `version-conflict` when stale; nothing is written). On a
        change `version` increments and `apx.violations.status.v1` is
        published; resending what the violation already holds is a no-op
        (200, no new version, no event). A Session that does not exist or
        is not visible to the caller is 422 `reference-unknown`; one at a
        place outside the hierarchy of the violation's `place` (neither
        the same element, an ancestor, nor a descendant) is 422
        `request-unprocessable`.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - $ref: '#/components/parameters/IfMatch'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ViolationSessionLink'
      responses:
        '200':
          description: The violation with its Session link as it now stands.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Violation'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: Stale `If-Match` (`version-conflict`); nothing is written.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: |-
            `reference-unknown` — the Session names nothing visible to the
            caller; `request-unprocessable` — the Session is at a place
            outside the hierarchy of the violation's `place`.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/places/{id}/occupancy/history:
    get:
      operationId: get-apx-v1-places-id-occupancy-history
      security:
        - apxOAuth:
            - apx.data:read
      tags:
        - Data
      summary: Occupancy per clock interval for one element
      description: |-
        The history behind the §5.5 snapshot (Part 5 §5.5a), derived from
        the APDS DemandTable records the implementation holds for the
        element. Buckets align to `interval` boundaries in the place's time
        zone; an element the implementation holds no occupancy for is 404
        `target-not-found`; the `apx_places` grant must cover the element.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: from
          in: query
          required: true
          schema:
            type: string
            format: date-time
        - name: to
          in: query
          required: true
          schema:
            type: string
            format: date-time
        - name: interval
          in: query
          description: Bucket length (ISO 8601 duration); default `PT1H`. Servers MAY refuse an interval shorter than their sampling with 400.
          schema:
            type: string
            default: PT1H
      responses:
        '200':
          description: The buckets.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OccupancyHistoryPage'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/plate-lists:
    get:
      operationId: get-apx-v1-plate-lists
      security:
        - apxOAuth:
            - apx.platelists:read
      tags:
        - Plate lists
      summary: List plate lists
      description: |-
        The lists visible to the caller: those with a `places[]` entry
        inside the grant, and those owned by the caller's `apx_org`.
        `mode=change&cursor=` serves the Part 5 §5.2 feed of lists
        (entries have their own feed).
      parameters:
        - $ref: '#/components/parameters/ModeParam'
        - $ref: '#/components/parameters/CursorParam'
        - name: place
          in: query
          schema:
            type: string
            format: uuid
          description: Lists that apply at this element or its subtree.
        - name: category
          in: query
          schema:
            type: string
        - name: status
          in: query
          schema:
            type: string
            enum:
              - active
              - suspended
              - retired
        - $ref: '#/components/parameters/page'
      responses:
        '200':
          description: Paginated lists; with `mode=change`, the changes after `cursor` in the same envelope (Part 5 §5.2 rule 8).
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/PlateList'
                  updateMode:
                    $ref: '#/components/schemas/ChangeFeedUpdateMode'
                  cursor:
                    $ref: '#/components/schemas/ChangeFeedCursor'
                  deleted:
                    $ref: '#/components/schemas/ChangeFeedTombstones'
                  grantAdditions:
                    $ref: '#/components/schemas/ChangeFeedGrantAdditions'
                  next:
                    $ref: '#/components/schemas/ChangeFeedNext'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/CursorRefused'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    post:
      operationId: post-apx-v1-plate-lists
      security:
        - apxOAuth:
            - apx.platelists:manage
      tags:
        - Plate lists
      summary: Create a plate list
      description: |-
        Creates a list owned by the caller's `apx_org` (Part 24 §24.1).
        Every `places[].place` must lie inside the grant (403
        `insufficient-grant`). `Idempotency-Key` optional (Part 4 §4.2a).
        Publishes `apx.platelists.changed.v1`.
      parameters:
        - $ref: '#/components/parameters/IdempotencyKeyOptional'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PlateList'
      responses:
        '200':
          description: Idempotent replay.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlateList'
        '201':
          description: Created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlateList'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: '`Idempotency-Key` replayed with a different body (`idempotency-conflict`).'
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: A `category` outside the served registries, or a `places[].place` that does not exist (`reference-unknown`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/plate-lists/{id}:
    get:
      operationId: get-apx-v1-plate-lists-id
      security:
        - apxOAuth:
            - apx.platelists:read
      tags:
        - Plate lists
      summary: Read a plate list
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: The list.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlateList'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    put:
      operationId: put-apx-v1-plate-lists-id
      security:
        - apxOAuth:
            - apx.platelists:manage
      tags:
        - Plate lists
      summary: Replace a plate list's policy (name, category, places, status)
      description: |-
        Full replacement with the version last read as `If-Match` or body
        `version` (409 `version-conflict`, Part 4 §4.2a). Entries are not
        part of this body. Publishes `apx.platelists.changed.v1`.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - $ref: '#/components/parameters/IfMatch'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PlateList'
      responses:
        '200':
          description: The list as it now stands.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlateList'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: Stale version (`version-conflict`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: A `category` outside the served registries, or an unknown place (`reference-unknown`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/plate-lists/{id}/entries:
    get:
      operationId: get-apx-v1-plate-lists-id-entries
      security:
        - apxOAuth:
            - apx.platelists:read
      tags:
        - Plate lists
      summary: List a plate list's entries
      description: |-
        Entries of one list, optionally by exact credential value;
        `mode=change&cursor=` serves the Part 5 §5.2 feed of entries so a
        screening module keeps a local copy current. Plate values appear
        only under `apx.platelists:*` (Part 9 §9.6); a consumer holding
        only `apx.data:read` may subscribe to digests instead (§9.6 rule 6).
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - $ref: '#/components/parameters/ModeParam'
        - $ref: '#/components/parameters/CursorParam'
        - name: credential
          in: query
          schema:
            type: string
          description: Exact `credential.credentialIdentification` match.
        - name: activeAt
          in: query
          schema:
            type: string
            format: date-time
          description: Only entries whose validity contains this instant.
        - $ref: '#/components/parameters/page'
      responses:
        '200':
          description: Paginated entries; with `mode=change`, the changes after `cursor` in the same envelope (Part 5 §5.2 rule 8).
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/PlateListEntry'
                  updateMode:
                    $ref: '#/components/schemas/ChangeFeedUpdateMode'
                  cursor:
                    $ref: '#/components/schemas/ChangeFeedCursor'
                  deleted:
                    $ref: '#/components/schemas/ChangeFeedTombstones'
                  grantAdditions:
                    $ref: '#/components/schemas/ChangeFeedGrantAdditions'
                  next:
                    $ref: '#/components/schemas/ChangeFeedNext'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    post:
      operationId: post-apx-v1-plate-lists-id-entries
      security:
        - apxOAuth:
            - apx.platelists:manage
      tags:
        - Plate lists
      summary: Add an entry to a plate list
      description: |-
        Adds a credential to the list (Part 24 §24.2). An entry whose
        credential is already on the list with an overlapping validity is
        updated in place (200) rather than duplicated. `Idempotency-Key`
        optional. Publishes `apx.platelists.changed.v1` with the list.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - $ref: '#/components/parameters/IdempotencyKeyOptional'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PlateListEntry'
      responses:
        '200':
          description: An existing entry for the credential updated, or an idempotent replay.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlateListEntry'
        '201':
          description: Added.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlateListEntry'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: '`Idempotency-Key` replayed with a different body (`idempotency-conflict`).'
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: An inverted validity window (`request-unprocessable`), or a full card number where a plate is expected (`personal-data-not-permitted`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/plate-lists/{id}/entries/{entryId}:
    get:
      operationId: get-apx-v1-plate-lists-id-entries-entryid
      security:
        - apxOAuth:
            - apx.platelists:read
      tags:
        - Plate lists
      summary: Read one entry
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: entryId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: The entry.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlateListEntry'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    delete:
      operationId: delete-apx-v1-plate-lists-id-entries-entryid
      security:
        - apxOAuth:
            - apx.platelists:manage
      tags:
        - Plate lists
      summary: Remove an entry
      description: Removes the credential from the list; the entry feed emits a tombstone. Publishes `apx.platelists.changed.v1`.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: entryId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '204':
          description: Removed.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/digest-keys:
    get:
      operationId: get-apx-v1-digest-keys
      security:
        - apxOAuth:
            - apx.digest:use
      tags:
        - Discovery
      summary: The keys behind `apds-ext:apx:credential-digest@1.0`
      description: |-
        The digest keys the implementation currently signs credential
        digests with, so an authorised consumer can compute the digest of
        a plate it holds and match it to decorated records without ever
        receiving plates (Part 9 §9.6 rule 6). Rotation is by `keyId`;
        both keys are served during an overlap. The normalization the
        implementation applies before hashing is stated per key.
      responses:
        '200':
          description: The keys.
          content:
            application/json:
              schema:
                type: object
                required:
                  - keys
                properties:
                  keys:
                    type: array
                    items:
                      type: object
                      required:
                        - keyId
                        - alg
                        - key
                      properties:
                        keyId:
                          type: string
                        alg:
                          type: string
                          enum:
                            - HS256
                        key:
                          type: string
                          description: base64url key material, at least 32 bytes.
                        validFrom:
                          $ref: '#/components/schemas/DateTime'
                        validTo:
                          $ref: '#/components/schemas/DateTime'
                        normalization:
                          type: string
                          description: The normalization applied before hashing, e.g. `upper; strip non-alphanumerics; jurisdiction appended as `|<ISO 3166-2>``.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/reservations/recent:
    get:
      operationId: get-apx-v1-reservations-recent
      security:
        - apxOAuth:
            - apx.reservations:manage
      tags:
        - Reservations
      summary: A customer's last 10 reservations
      description: |-
        Customer history for screen-pops and dispute handling: the same
        holder's most recent reservations (newest planned start first),
        resolved from a plate or an explicit RightHolder id. At least one
        of `plate` or `holder` is REQUIRED (400 `invalid-request`
        otherwise); when both are given the result is their intersection
        (reservations of that holder carrying that plate). `from`/`to`,
        `state`, `country`, and `stateProvince` narrow further (Part 14
        §14.1a).
      parameters:
        - name: plate
          in: query
          schema:
            type: string
        - name: holder
          in: query
          schema:
            type: string
            format: uuid
        - name: country
          in: query
          description: |-
            Plate issuing country (APDS VehicleAncillaryIdentification.country
            vocabulary). Qualifies `plate`; absent, the plate string alone
            is matched.
          schema:
            type: string
            examples:
              - US
        - name: stateProvince
          in: query
          description: Plate issuing state/province (APDS VehicleAncillaryIdentification.stateProvince vocabulary). Qualifies `plate`.
          schema:
            type: string
            examples:
              - FL
        - name: from
          in: query
          description: |-
            Only reservations whose `plannedStart` is at or after this
            instant. `from` later than `to` is 400 `invalid-request`.
          schema:
            type: string
            format: date-time
        - name: to
          in: query
          description: Only reservations whose `plannedStart` is before this instant.
          schema:
            type: string
            format: date-time
        - name: state
          in: query
          description: Only reservations currently in this `reservationState`.
          schema:
            type: string
            enum:
              - confirmed
              - amended
              - cancelled
              - checkedIn
              - noShow
        - name: place
          in: query
          description: |-
            Scope results to one location (for implementations fronting
            multiple places). Holder ids are LOCAL to each implementation —
            there is no central user catalog; cross-system correlation is
            by plate (Part 14 §14.1a).
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Up to 10 reservation summaries.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    maxItems: 10
                    items:
                      $ref: '#/components/schemas/ReservationSummary'
        '400':
          description: |-
            Neither plate nor holder given, or an inverted `from`/`to`
            window (problem type `invalid-request`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: |-
            The named `place` does not exist (problem type
            `target-not-found`). A place that exists outside the caller's
            grant is 403 `insufficient-grant` (Part 9 §9.3a).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/sessions/{id}/assigned-right:
    put:
      operationId: put-apx-v1-sessions-id-assigned-right
      security:
        - apxOAuth:
            - apx.reservations:manage
      tags:
        - Reservations
        - Resolution
      summary: Link a session to its AssignedRight (reservation/permit)
      description: |-
        The explicit reservation↔session link for facilities where the
        plate cannot be the link (barcode-only reservations, unreadable
        plates). Mirrors plate correction (Part 17 §17.5): a transactional
        domain action, naturally idempotent (PUT).

        NORMATIVE (Part 14 §14.1b): the link MUST materialize in the
        underlying APDS Session (`segments[].assignedRight`), MUST publish
        SessionUpdated, and MUST be visible to plain APDS clients reading
        /sessions/{id} — a façade over APDS-modeled state, never a
        parallel store. Pricing consequences (the prepaid rate replacing
        the drive-up rate) follow from the link per the implementation's
        normal rating.

        Re-sending the same link is a no-op 200. A link naming a DIFFERENT
        right on a session already linked to one is 409
        `right-not-linkable` ("session already linked"); undo the first
        link with POST /v1/sessions/{id}/assigned-right/unlink. `If-Match`
        carries the APDS Session `version` the client read (Part 4 §4.2a).
        Where the resolution context gated this action, the approval
        evidence rides `approval`; a policy refusal is 403
        `action-not-allowed` or `approval-required` (Part 17 §17.3).
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: APDS Session UUID.
        - $ref: '#/components/parameters/IfMatch'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - assignedRight
              properties:
                assignedRight:
                  description: The AssignedRight (reservation or permit) this session consumes.
                  $ref: '#/components/schemas/Reference'
                reservationCode:
                  type: string
                  description: The presented code, kept as audit evidence for the link.
                reason:
                  type: string
                approval:
                  description: Approval evidence, when the resolution context marked this action requiresApproval (Part 17 §17.3).
                  $ref: '#/components/schemas/Approval'
      responses:
        '200':
          description: The link, applied.
          content:
            application/json:
              schema:
                type: object
                required:
                  - session
                  - assignedRight
                properties:
                  session:
                    $ref: '#/components/schemas/Reference'
                  assignedRight:
                    $ref: '#/components/schemas/Reference'
                  version:
                    type: integer
                    minimum: 1
                    description: The APDS Session `version` after the write (Part 4 §4.2a).
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such session or AssignedRight.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: |-
            The AssignedRight is not linkable (`right-not-linkable`: already
            consumed elsewhere, outside its validity, wrong place, in
            reservationState `cancelled` or `noShow`, or the session is
            already linked to a different right), or `If-Match` names a
            stale Session version (`version-conflict`, Part 4 §4.2a).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/sessions/{id}/assigned-right/unlink:
    post:
      operationId: post-apx-v1-sessions-id-assigned-right-unlink
      security:
        - apxOAuth:
            - apx.reservations:manage
      tags:
        - Reservations
      summary: Undo a session's link to its AssignedRight
      description: |-
        The audited undo of PUT /v1/sessions/{id}/assigned-right (Part 14
        §14.1b): removes the linked AssignedRight from the session's
        current segment, reverts the segment to the implementation's
        drive-up right, and returns the reservation to its pre-check-in
        `reservationState` (`confirmed` or `amended`, clearing
        `checkInSession`). MUST materialize in the underlying APDS Session
        and MUST publish SessionUpdated, like the link. `reason` is
        REQUIRED. Unlinking a session that carries no linked right is a
        no-op 200 without `unlinkedRight`. A closed Session is 422
        `session-not-open`.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: APDS Session UUID.
        - $ref: '#/components/parameters/IfMatch'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reason
              properties:
                reason:
                  type: string
                  minLength: 1
                  description: Why the link is being undone (audit).
                approval:
                  description: Approval evidence, when the resolution context marked this action requiresApproval (Part 17 §17.3).
                  $ref: '#/components/schemas/Approval'
      responses:
        '200':
          description: The session, unlinked.
          content:
            application/json:
              schema:
                type: object
                required:
                  - session
                properties:
                  session:
                    $ref: '#/components/schemas/Reference'
                  unlinkedRight:
                    description: The AssignedRight the session no longer consumes. Absent when there was nothing to unlink.
                    $ref: '#/components/schemas/Reference'
                  version:
                    type: integer
                    minimum: 1
                    description: The APDS Session `version` after the write.
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: '`If-Match` names a stale Session version (`version-conflict`, Part 4 §4.2a).'
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: The Session is closed (`session-not-open`); pricing has settled.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/permits/pools/{rightSpecId}/availability:
    get:
      operationId: get-apx-v1-permits-pools-rightspecid-availability
      security:
        - apxOAuth:
            - apx.permits:manage
      tags:
        - Permits
      summary: Pool availability for a pooled RightSpecification
      description: |-
        Profile over APDS RightPool — capacity, issued, available — for one
        pool of the RightSpecification. With neither `pool` nor `at`, the
        pool whose validity contains now, else the earliest future pool
        (Part 14 §14.2).
      parameters:
        - name: rightSpecId
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: pool
          in: query
          description: A RightPool id of this RightSpecification; takes precedence over `at`.
          schema:
            type: string
            format: uuid
        - name: at
          in: query
          description: Select the pool whose validity contains this instant (e.g. a date in November for a November pool), RFC 3339.
          schema:
            type: string
            format: date-time
      responses:
        '200':
          description: Availability.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PoolAvailability'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No pool for this RightSpecification.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/permits/issue:
    post:
      operationId: post-apx-v1-permits-issue
      security:
        - apxOAuth:
            - apx.permits:manage
      tags:
        - Permits
      summary: Issue a permit from a pool (multi-vehicle credentials)
      description: |-
        Creates a native AssignedRight (APDS annual-permit pattern — one
        right, many vehicles), materialized per Part 14 §14.2. Pool
        exhaustion is 409 pool-exhausted. A client that may retry SHOULD
        send `Idempotency-Key`: a retried issue without one consumes a
        second pool slot.
      parameters:
        - $ref: '#/components/parameters/IdempotencyKeyOptional'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PermitIssueRequest'
      responses:
        '200':
          description: |-
            Idempotent replay — same key + same body returns the AssignedRight
            the key issued, in its current representation; no second slot is
            consumed (Part 4 §4.2a).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AssignedRight'
        '201':
          description: The issued AssignedRight (native APDS entity).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AssignedRight'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: |-
            Pool exhausted (`pool-exhausted`); Idempotency-Key replayed with a
            different body (`idempotency-conflict`); a stale
            `rightSpecification.version` (`version-conflict`); or a credential
            identification already active on another permit at the place
            (`credential-identification-in-use`, Part 14 §14.2).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: |-
            The `rightSpecification` or `holder` names nothing that exists
            or is visible (`reference-unknown`); or the RightSpecification has
            no `rightPools`, or a `credentialType` is not in its
            `credentials` allow-list (`request-unprocessable`, `detail` names
            the rule; Part 14 §14.2).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/accounts:
    get:
      operationId: get-apx-v1-accounts
      security:
        - apxOAuth:
            - apx.accounts:read
      tags:
        - Accounts
      summary: Look up accounts by name/phone/email/card/plate
      description: |-
        Any combination of filters; returns accounts with balances and
        status. Results are constrained to the caller's `apx_places` grant
        (Part 13 §13.5); under an absent or empty grant the answer is an
        empty 200 (Part 9 §9.3a).
      parameters:
        - name: name
          in: query
          schema:
            type: string
        - name: phone
          in: query
          schema:
            type: string
        - name: email
          in: query
          description: Exact contact e-mail (case-insensitive). Personal data (Part 9 §9.6).
          schema:
            type: string
        - name: card
          in: query
          schema:
            type: string
        - name: plate
          in: query
          schema:
            type: string
        - name: place
          in: query
          description: |-
            Narrow results below the grant (Part 13 §13.5(3)): comma-separated
            HierarchyElement ids, subtree-inclusive. A place outside the
            caller's grant is 403 `insufficient-grant`. Servers that do not
            implement narrowing ignore it.
          style: form
          explode: false
          schema:
            type: array
            items:
              type: string
              format: uuid
        - $ref: '#/components/parameters/ModeParam'
        - $ref: '#/components/parameters/CursorParam'
        - $ref: '#/components/parameters/page'
      responses:
        '200':
          description: Matching accounts; with `mode=change`, the changes after `cursor` in the same envelope (Part 5 §5.2 rule 8).
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Account'
                  updateMode:
                    $ref: '#/components/schemas/ChangeFeedUpdateMode'
                  cursor:
                    $ref: '#/components/schemas/ChangeFeedCursor'
                  deleted:
                    $ref: '#/components/schemas/ChangeFeedTombstones'
                  grantAdditions:
                    $ref: '#/components/schemas/ChangeFeedGrantAdditions'
                  next:
                    $ref: '#/components/schemas/ChangeFeedNext'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/CursorRefused'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/accounts/{id}:
    get:
      operationId: get-apx-v1-accounts-id
      security:
        - apxOAuth:
            - apx.accounts:read
      tags:
        - Accounts
      summary: Full account info
      description: Returns the account including balance and status.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: The account.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Account'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such account.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/payments:
    post:
      operationId: post-apx-v1-payments
      security:
        - apxOAuth:
            - apx.payments:write
      tags:
        - Accounts
      summary: Take a payment (idempotent)
      description: |-
        Takes a payment against an account or ticket. Idempotency-Key
        REQUIRED. `channel: autoAttendant` = a PCI-compliant IVR captures the
        card out of band; APX never carries PANs. Declines are 422. With
        `captureLater: true` the payment is authorized only: a hold,
        created `paymentStatus: approved` with `captureStatus: authorized`,
        returned to this caller but not published or listed by default
        until captured (Part 13 §13.1a).
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PaymentRecord'
      responses:
        '200':
          description: |-
            Idempotent replay — same key + same body returns the payment the
            key created, in its current representation (Part 4 §4.2a).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaymentRecord'
        '201':
          description: Approved payment with transactionID (a hold with `captureStatus` `authorized` when `captureLater` was asked).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaymentRecord'
        '400':
          description: |-
            Missing Idempotency-Key (`idempotency-key-required`), or a body
            that fails the schema or names neither `account` nor
            `ticketNumber` to settle (`invalid-request`, Part 12).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: Idempotency-Key replayed with a different body (`idempotency-conflict`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: |-
            Payment declined (`payment-declined`; the problem SHOULD carry a
            `payment` member referencing the recorded declined PaymentRecord,
            Part 13 §13.1); a body carrying card data beyond the truncated
            last four (`personal-data-not-permitted`, refused before it is
            persisted or logged); `captureLater` on a server without an
            authorization lifecycle, or `apds-ext:apx:payment-detail@1.0`
            lines whose `paymentType: payment` values do not sum to
            `amount` or whose `paymentType` contradicts the `validation`
            code (`request-unprocessable`, nothing charged, Part 13 §13.6a).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    get:
      operationId: get-apx-v1-payments
      security:
        - apxOAuth:
            - apx.accounts:read
      tags:
        - Accounts
      summary: Payment history by ticket, card digits, or account
      description: |-
        Payments made on a ticket or an account (Part 13 §13.2). At least
        one key — `ticketLast4`, `cardLast4`, `ticketNumber`, or `account` —
        is REQUIRED; `date` and `place` only narrow, and a query with no key
        is 400 `invalid-request`. Privacy rule: a truncated-key lookup
        without a `date` is constrained to the last 8 hours; `ticketNumber`
        and `account` are exempt. Results are constrained to the caller's
        grant (§13.5). Holds (`captureStatus: authorized`) are omitted
        unless `captureStatus=authorized` is asked for.
      parameters:
        - $ref: '#/components/parameters/ModeParam'
        - $ref: '#/components/parameters/CursorParam'
        - name: ticketLast4
          in: query
          schema:
            type: string
        - name: cardLast4
          in: query
          description: |-
            Truncated payment-card digits — the transient-parker lookup of
            last resort (no LPR, no readable ticket). Same recent-window
            privacy rule as ticketLast4. At most four digits: a value
            carrying more is refused with 422 `personal-data-not-permitted`
            before the request is logged (Part 13 §13.2).
          schema:
            type: string
        - name: ticketNumber
          in: query
          description: Full ticket number, exact match. Exempt from the 8-hour window.
          schema:
            type: string
        - name: account
          in: query
          description: Account id — every payment on the account (a statement view). Exempt from the 8-hour window.
          schema:
            type: string
            format: uuid
        - name: date
          in: query
          schema:
            type: string
            format: date
        - name: place
          in: query
          description: |-
            Narrow results below the grant (Part 13 §13.5(3)): comma-separated
            HierarchyElement ids, subtree-inclusive. A place outside the
            caller's grant is 403 `insufficient-grant`. Never a key on its own.
          style: form
          explode: false
          schema:
            type: array
            items:
              type: string
              format: uuid
        - name: captureStatus
          in: query
          description: |-
            `authorized` lists only holds (authorization-only payments not
            yet captured), which are otherwise never returned; `captured`
            lists only collected payments (the default behaviour made
            explicit). Absent = holds excluded (Part 13 §13.2). Never a key
            on its own.
          schema:
            type: string
            enum:
              - authorized
              - captured
        - $ref: '#/components/parameters/page'
      responses:
        '200':
          description: Matching payments; with `mode=change`, the changes after `cursor` in the same envelope (Part 5 §5.2 rule 8).
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/PaymentRecord'
                  updateMode:
                    $ref: '#/components/schemas/ChangeFeedUpdateMode'
                  cursor:
                    $ref: '#/components/schemas/ChangeFeedCursor'
                  deleted:
                    $ref: '#/components/schemas/ChangeFeedTombstones'
                  grantAdditions:
                    $ref: '#/components/schemas/ChangeFeedGrantAdditions'
                  next:
                    $ref: '#/components/schemas/ChangeFeedNext'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/CursorRefused'
        '422':
          description: |-
            A query parameter carries more card digits than the truncated
            last four (`personal-data-not-permitted`, Part 13 §13.2). The
            server refuses before logging the request.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/payments/{id}/postings:
    post:
      operationId: post-apx-v1-payments-id-postings
      security:
        - apxOAuth:
            - apx.payments:write
      tags:
        - Accounts
      summary: Accounting write-back (PARIS-style)
      description: |-
        Posts the payment to the monthly-parking/AR system; returns
        confirmation and new balance. Only an `approved` payment can be
        posted; any other state is 409 `payment-state-illegal` (Part 13
        §13.1a).
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PostingRequest'
      responses:
        '201':
          description: Posting result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Posting'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such payment.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: The payment is not `approved` (`payment-state-illegal`, Part 13 §13.1a).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/payments/{id}/refund:
    post:
      operationId: post-apx-v1-payments-id-refund
      security:
        - apxOAuth:
            - apx.payments:write
      tags:
        - Accounts
      summary: Refund a payment (financial domain action)
      description: |-
        Refunds the payment fully, or partially per `amount`. A financial
        action per Part 17 §17.4 — never a control command. Idempotency-Key
        REQUIRED; approval evidence required when the resolution context's
        AllowedAction said so. Scope apx.payments:write.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: Idempotency-Key
          in: header
          required: true
          schema:
            type: string
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                amount:
                  $ref: '#/components/schemas/AmountInCurrency'
                reasonCode:
                  type: string
                  description: Why, as a definedValue of apx-refund-reasons (Part 11) so refunds can be reported by cause across operators; `reason` stays the free-text note.
                  examples:
                    - doubleCharge
                reason:
                  type: string
                approval:
                  $ref: '#/components/schemas/Approval'
      responses:
        '200':
          description: |-
            The payment with `refundedAmount` increased; `reversed` once the
            cumulative refund reaches `amount`, otherwise still `approved`
            (Part 13 §13.1a).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaymentRecord'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such payment.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: |-
            Not refundable in its current state — only `approved` is
            (`payment-state-illegal`, Part 13 §13.1a) — or Idempotency-Key
            replayed with a different body (`idempotency-conflict`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: |-
            The requested `amount` exceeds what remains refundable (`amount`
            minus `refundedAmount`) — `request-unprocessable`.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/payments/{id}/void:
    post:
      operationId: post-apx-v1-payments-id-void
      security:
        - apxOAuth:
            - apx.payments:write
      tags:
        - Accounts
      summary: Void a hold (an authorized, uncaptured payment)
      description: |-
        Financial domain action (Part 17 §17.4). Releases a hold
        (`captureStatus: authorized`): `paymentStatus` becomes `reversed`,
        nothing was collected, and no event is published (Part 13 §13.1a).
        Idempotency-Key REQUIRED. Scope apx.payments:write.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: Idempotency-Key
          in: header
          required: true
          schema:
            type: string
      responses:
        '200':
          description: The voided payment, now `reversed`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaymentRecord'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such payment.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: |-
            Not a hold — already captured, declined, or reversed
            (`payment-state-illegal`) — or Idempotency-Key replayed with a
            different body (`idempotency-conflict`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/payments/{id}/capture:
    post:
      operationId: post-apx-v1-payments-id-capture
      security:
        - apxOAuth:
            - apx.payments:write
      tags:
        - Accounts
      summary: Capture a hold (a previously authorized payment)
      description: |-
        Financial domain action (Part 17 §17.4). Settles a hold:
        `captureStatus` `authorized → captured` (`paymentStatus` stays
        `approved`), optionally for a lower `amount` than was authorized.
        The capture is when the payment is published and materialized
        (Part 13 §13.1a). Idempotency-Key REQUIRED. Scope
        apx.payments:write.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: Idempotency-Key
          in: header
          required: true
          schema:
            type: string
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                amount:
                  description: Amount to capture; at most the authorized amount. Omit to capture in full.
                  $ref: '#/components/schemas/AmountInCurrency'
      responses:
        '200':
          description: The captured payment, now `captureStatus` `captured` with `amount` = the captured amount.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaymentRecord'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such payment.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: |-
            Not a hold — already captured, declined, or reversed
            (`payment-state-illegal`, Part 13 §13.1a) — or Idempotency-Key
            replayed with a different body (`idempotency-conflict`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: Capture `amount` exceeds the authorized amount (`request-unprocessable`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/payment-links:
    post:
      operationId: post-apx-v1-payment-links
      security:
        - apxOAuth:
            - apx.payments:write
      tags:
        - Accounts
        - Resolution
      summary: Send a hosted payment link
      description: |-
        The customer-service payment action of first resort (Part 13
        §13.1a): sends a hosted payment link via the given channel for an
        account, ticket, or session. APX never carries PANs. Idempotency-Key
        REQUIRED. Scope apx.payments:write. Payment completion arrives as
        apx.accounts.payment.recorded.v1.
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PaymentLink'
      responses:
        '200':
          description: |-
            Idempotent replay — same key + same body returns the link the key
            created, in its current representation (`status` may have
            advanced; Part 4 §4.2a).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaymentLink'
        '201':
          description: The link, sent.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaymentLink'
        '400':
          description: |-
            Missing Idempotency-Key (`idempotency-key-required`), or a body
            that fails the schema or names no account, ticket, or session to
            settle (`invalid-request`, Part 12).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: Idempotency-Key replayed with a different body.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: |-
            A `channel` this server does not deliver on
            (`request-unprocessable`), or a body carrying card data
            (`personal-data-not-permitted`, refused before it is persisted or
            logged; Part 13 §13.1).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/payment-links/{id}:
    get:
      operationId: get-apx-v1-payment-links-id
      security:
        - apxOAuth:
            - apx.accounts:read
        - apxOAuth:
            - apx.payments:write
      tags:
        - Accounts
      summary: Read a payment link
      description: |-
        The link's current lifecycle state (`sent → opened → paid | expired
        | cancelled`, Part 13 §13.1a) and, once paid, the resulting
        PaymentRecord. Grant-checked on the link's `place`.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: The payment link.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaymentLink'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/payment-links/{id}/cancel:
    post:
      operationId: post-apx-v1-payment-links-id-cancel
      security:
        - apxOAuth:
            - apx.payments:write
      tags:
        - Accounts
      summary: Cancel a payment link
      description: |-
        Kills a link before the customer pays (sent to the wrong number,
        paid another way): `sent | opened → cancelled`. The hosted page MUST
        stop accepting payment from that instant. A link that is `paid`,
        `expired`, or already `cancelled` is 409 `payment-state-illegal`
        (Part 13 §13.1a). Idempotency-Key optional (Part 4 §4.2a).
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - $ref: '#/components/parameters/IdempotencyKeyOptional'
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PaymentLinkCancel'
      responses:
        '200':
          description: The link, now `cancelled` (or its current representation on an idempotent replay).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaymentLink'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: |-
            The link is `paid`, `expired`, or already `cancelled`
            (`payment-state-illegal`), or Idempotency-Key replayed with a
            different body (`idempotency-conflict`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/sessions/{id}/plate:
    put:
      operationId: put-apx-v1-sessions-id-plate
      security:
        - apxOAuth:
            - apx.data:write
      tags:
        - LPR
        - Resolution
      summary: Associate or correct the plate on a session
      description: |-
        The write side of plate correction (Part 17 §17.5): sets the
        session's plate, optionally citing the chosen Observation candidate
        (GET /v1/lpr/candidates). A transactional domain action — not a
        control command. Naturally idempotent (PUT). Scope apx.data:write.

        NORMATIVE (Part 17 §17.5): the correction MUST materialize in the
        underlying APDS Session (identifiedCredentials /
        identifiedVehicle), MUST publish SessionUpdated, and MUST be
        visible to plain APDS clients reading /sessions/{id} — this route
        is a business-action façade over APDS-modeled state, never a
        parallel store.

        `If-Match` carries the APDS Session `version` the client read; a
        stale one is 409 `version-conflict` (Part 4 §4.2a). A closed
        Session may be corrected only inside the operator's dispute
        window and only with `reason`; otherwise 422 `session-not-open`
        (Part 17 §17.5). The 200 echoes only the plate values the caller
        supplied and discloses no other plate-bearing data; candidate
        reads stay under apx.lpr:read (Part 9 §9.6). Where the resolution
        context gated this action, the approval evidence rides `approval`;
        a policy refusal is 403 `action-not-allowed` or
        `approval-required` (Part 17 §17.3).
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: APDS Session UUID.
        - $ref: '#/components/parameters/IfMatch'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - plate
              properties:
                plate:
                  type: string
                country:
                  type: string
                  examples:
                    - US
                  description: APDS VehicleAncillaryIdentification.country vocabulary.
                stateProvince:
                  type: string
                  examples:
                    - FL
                observation:
                  description: The Observation candidate this correction is based on.
                  $ref: '#/components/schemas/Reference'
                reason:
                  type: string
                approval:
                  description: Approval evidence, when the resolution context marked this action requiresApproval (Part 17 §17.3).
                  $ref: '#/components/schemas/Approval'
      responses:
        '200':
          description: The corrected association.
          content:
            application/json:
              schema:
                type: object
                required:
                  - session
                  - plate
                properties:
                  session:
                    $ref: '#/components/schemas/Reference'
                  plate:
                    type: string
                  country:
                    type: string
                  stateProvince:
                    type: string
                  observation:
                    $ref: '#/components/schemas/Reference'
                  version:
                    type: integer
                    minimum: 1
                    description: The APDS Session `version` after the write (Part 4 §4.2a).
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such session.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: '`If-Match` names a stale Session version (`version-conflict`, Part 4 §4.2a); nothing is written.'
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: |-
            The Session is closed and outside the operator's dispute
            window, or closed and the correction carries no `reason`
            (`session-not-open`, Part 17 §17.5).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/lpr/reads:
    get:
      operationId: get-apx-v1-lpr-reads
      security:
        - apxOAuth:
            - apx.lpr:read
      tags:
        - LPR
      summary: Bidirectional plate/ticket cross-lookup
      description: |-
        plate → ticket/session with accuracy + screenshot; ticket → plate;
        Session → the reads behind it. A pure profile over APDS
        Observations (ingest = native POST /observations). Where the
        ingested Observation carried the `apds-ext:apx:lpr-read@1.0`
        decoration, each read returns `detail` (per-attribute confidences
        for plate, state, make, model, color, class; alternate reads;
        passage geometry; and `accessEvent` — entry or exit — as the LPR
        system reported it; Part 13 §13.3a).

        At least one of `plate`, `ticket`, `observation`, or `session` is
        REQUIRED;
        a call with none is 400 `invalid-request`, never a bulk export
        (Part 9 §9.6). Keys given together intersect. Results are bounded
        by the caller's `apx_places` grant (Part 13 §13.5); a value-keyed
        lookup under an empty grant is an empty 200 (Part 9 §9.3a).
      parameters:
        - name: plate
          in: query
          schema:
            type: string
        - name: ticket
          in: query
          schema:
            type: string
        - name: observation
          in: query
          description: |-
            Lookup by the underlying APDS Observation id. Returns the
            LprRead projection of one ingested read; the stored
            ObservationElement itself is native GET /observations/{id}.
          schema:
            type: string
            format: uuid
        - name: session
          in: query
          description: |-
            The reads behind one APDS Session — its entry and exit reads
            and every read of their passages (Part 13 §13.3a(6)). A Session
            at a place outside the caller's `apx_places` grant is 403
            `insufficient-grant` (Part 13 §13.5(4)).
          schema:
            type: string
            format: uuid
        - name: place
          in: query
          description: |-
            Narrow results below the grant to one HierarchyElement and its
            subtree (Part 13 §13.5(3)). A place outside the caller's
            `apx_places` grant is 403 `insufficient-grant`. Servers that do
            not narrow MAY ignore it.
          schema:
            type: string
            format: uuid
        - $ref: '#/components/parameters/page'
      responses:
        '200':
          description: Matching reads.
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/LprRead'
        '400':
          description: None of `plate`, `ticket`, `observation`, or `session` given (problem type `invalid-request`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/lpr/reads/{observation}/access-event:
    put:
      operationId: put-apx-v1-lpr-reads-observation-access-event
      security:
        - apxOAuth:
            - apx.data:write
      tags:
        - LPR
      summary: Revise a read's access event
      description: |-
        The LPR system's revision of `accessEvent` on a read it ingested
        (Part 13 §13.3a(4)) — for example after pairing the reads of one
        `captureGroup`, or an entry read with an exit read. APDS 4.1 has no
        route that replaces one Observation, so this is the revision route.

        The server writes the value into the Observation's
        `apds-ext:apx:lpr-read@1.0` decoration, increments the Observation
        `version`, and publishes `apx.data.observation.updated.v1` with the
        Observation as it now stands (Part 13 §13.4). Sending the value
        the read already has is a no-op: 200 with the current `version`,
        no new version, no event. `If-Match` carries the Observation
        `version` the caller last saw; a stale one is 409
        `version-conflict` and nothing is written (Part 4 §4.2a). A read
        at a place outside the caller's `apx_places` grant is 403
        `insufficient-grant`. The 200 carries no plate-bearing data.
      parameters:
        - name: observation
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The APDS Observation id of the read.
        - $ref: '#/components/parameters/IfMatch'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - accessEvent
              properties:
                accessEvent:
                  type: string
                  enum:
                    - entry
                    - exit
                    - unknown
                  description: The revised access event (Part 13 §13.3a(4)).
      responses:
        '200':
          description: The read's access event as it now stands.
          content:
            application/json:
              schema:
                type: object
                required:
                  - observation
                  - accessEvent
                  - version
                properties:
                  observation:
                    $ref: '#/components/schemas/Reference'
                  accessEvent:
                    type: string
                    enum:
                      - entry
                      - exit
                      - unknown
                  version:
                    type: integer
                    minimum: 1
                    description: The Observation `version` after the write (Part 4 §4.2a).
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such LPR read (`target-not-found`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '409':
          description: '`If-Match` names a stale Observation version (`version-conflict`, Part 4 §4.2a); nothing is written.'
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/alerts:
    post:
      operationId: post-apx-v1-alerts
      security:
        - apxOAuth:
            - apx.alerts:write
      tags:
        - Alerts
      summary: Raise an alert (idempotent)
      description: |-
        Raises an alert. The `Idempotency-Key` header is REQUIRED: replaying
        the same key with the same body returns the alert as it currently
        stands (200, Part 4 §4.2a); the same key with a different body is
        409 idempotency-conflict. A client MAY supply `id` (Part 7 §7.1).
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Alert'
      responses:
        '200':
          description: |-
            Idempotent replay — same key + same body returns the alert as it
            currently stands (e.g. already acknowledged), not a snapshot of the
            first response (Part 4 §4.2a).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Alert'
        '201':
          description: Alert raised.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Alert'
        '400':
          description: |-
            Missing Idempotency-Key (`idempotency-key-required`) or a body that
            fails the Alert schema, e.g. an unknown `severity` or no
            `detectionTime` (`invalid-request`, with `errors[]`) — Part 12.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: |-
            Idempotency-Key replayed with a different body
            (`idempotency-conflict`), or a client-supplied `id` that already
            exists (`id-collision`) — Part 12.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    get:
      operationId: get-apx-v1-alerts
      security:
        - apxOAuth:
            - apx.alerts:read
      tags:
        - Alerts
      summary: List/filter alerts
      description: |-
        Filter by status, severityFloor, type, place (subtree-inclusive),
        device, relatedEntity, since. Alerts with no place binding (e.g.
        `webhookDeliveryFailed`) are visible to tokens of the owning
        organisation and are excluded whenever `place` is given (Part 7
        §7.1).
      parameters:
        - $ref: '#/components/parameters/ModeParam'
        - $ref: '#/components/parameters/CursorParam'
        - name: status
          in: query
          schema:
            type: string
            enum:
              - raised
              - acknowledged
              - resolved
              - expired
        - name: severityFloor
          in: query
          schema:
            type: string
            enum:
              - info
              - warning
              - minor
              - major
              - critical
        - name: type
          in: query
          schema:
            type: string
        - name: place
          in: query
          schema:
            type: string
            format: uuid
        - name: device
          in: query
          schema:
            type: string
            format: uuid
          description: Alerts whose `source.device.id` is this SupplementalEquipment.
        - name: relatedEntity
          in: query
          schema:
            type: string
            format: uuid
          description: Alerts whose `relatedEntity.id` is this entity (a Session, a Subscription, a Command…).
        - name: since
          in: query
          schema:
            type: string
            format: date-time
        - $ref: '#/components/parameters/page'
      responses:
        '200':
          description: Paginated alerts (APDS PaginatedList shape); with `mode=change`, the changes after `cursor` in the same envelope (Part 5 §5.2 rule 8).
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Alert'
                  updateMode:
                    $ref: '#/components/schemas/ChangeFeedUpdateMode'
                  cursor:
                    $ref: '#/components/schemas/ChangeFeedCursor'
                  deleted:
                    $ref: '#/components/schemas/ChangeFeedTombstones'
                  grantAdditions:
                    $ref: '#/components/schemas/ChangeFeedGrantAdditions'
                  next:
                    $ref: '#/components/schemas/ChangeFeedNext'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/CursorRefused'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/alerts/{id}:
    get:
      operationId: get-apx-v1-alerts-id
      security:
        - apxOAuth:
            - apx.alerts:read
      tags:
        - Alerts
      summary: Read an alert
      description: Returns the alert including its immutable statusHistory.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: The alert.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Alert'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such alert.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/alerts/{id}/acknowledge:
    post:
      operationId: post-apx-v1-alerts-id-acknowledge
      security:
        - apxOAuth:
            - apx.alerts:write
      tags:
        - Alerts
      summary: Acknowledge an alert
      description: |-
        Transition raised → acknowledged. Illegal transitions are 409
        `alert-transition-illegal`. The optional body annotates the history
        entry this transition appends (Part 7 §7.2); a request with no body
        is unchanged.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AlertTransition'
      responses:
        '200':
          description: Acknowledged alert.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Alert'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: Illegal transition from the current state (`alert-transition-illegal`, Part 7 §7.3).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/alerts/{id}/resolve:
    post:
      operationId: post-apx-v1-alerts-id-resolve
      security:
        - apxOAuth:
            - apx.alerts:write
      tags:
        - Alerts
      summary: Resolve an alert
      description: |-
        Transition raised|acknowledged → resolved. Illegal transitions are 409
        `alert-transition-illegal`. The optional body annotates the history
        entry this transition appends (Part 7 §7.2); a request with no body
        is unchanged.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AlertTransition'
      responses:
        '200':
          description: Resolved alert.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Alert'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: Illegal transition from the current state (`alert-transition-illegal`, Part 7 §7.3).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/resolution/contexts:
    post:
      operationId: post-apx-v1-resolution-contexts
      security:
        - apxOAuth:
            - apx.resolution:read
      tags:
        - Resolution
      summary: Resolve a customer-service context from any known identifiers
      description: |-
        THE aggregation call (Part 17 §17.2): accepts whatever
        parking-domain identifiers are known (lane, device, plate, ticket,
        credential, reservation code…) — telephony mapping stays on the
        call platform's side (§17.1) — and returns everything the server
        can resolve —
        issue classification, lane status, vehicle, session, account,
        passback, device status, recent overrides, support history — plus
        the policy-decided allowedActions. Sections the caller's scopes and
        `apx_places` grant could not read directly are omitted. May return
        `status: partial` with `pendingSources` rather than waiting on a
        slow source; re-read to refresh. Scope apx.resolution:read.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ResolutionResolveRequest'
      responses:
        '201':
          description: The resolved context (possibly partial).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResolutionContext'
        '400':
          description: |-
            No usable identifier supplied: the body carries none of the
            identifying members (device, place, lane, session, holder,
            credential, plate, ticketNumber, reservationCode) — problem type
            `invalid-request` (Part 17 §17.1).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No identifier resolved to anything this implementation knows.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: A `commsPoint`, `callerId`, `dialedNumber` or `commsDeviceId` this implementation does not hold (`comms-point-unknown`, Part 17 §17.1 and Part 26 §26.4), or a registered code value outside the served registries (`reference-unknown`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/resolution/contexts/{id}:
    get:
      operationId: get-apx-v1-resolution-contexts-id
      security:
        - apxOAuth:
            - apx.resolution:read
      tags:
        - Resolution
      summary: Re-read (recompute) a resolution context
      description: |-
        Returns the context recomputed against current state — `version`
        increments when anything material changed. Use after events arrive
        or when the initial response was partial. Scope apx.resolution:read.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: The current context.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResolutionContext'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such context (contexts MAY expire; re-resolve).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/resolution/contexts/{id}/allowed-actions:
    get:
      operationId: get-apx-v1-resolution-contexts-id-allowed-actions
      security:
        - apxOAuth:
            - apx.resolution:read
      tags:
        - Resolution
      summary: Re-evaluate the allowed actions for a context
      description: |-
        The policy layer's current decisions (Part 17 §17.3) — cheaper than
        a full context recompute; call before executing when time has
        passed. The consuming agent (human or AI) MUST NOT decide
        permissibility itself. Scope apx.resolution:read.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Current decisions.
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/AllowedAction'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such context.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/lpr/candidates:
    get:
      operationId: get-apx-v1-lpr-candidates
      security:
        - apxOAuth:
            - apx.lpr:read
      tags:
        - LPR
        - Resolution
      summary: Plate candidates for correction workflows
      description: |-
        Candidate plate reads (with confidence and imagery links) for a
        session or lane — the read side of plate correction (Part 17
        §17.5); the write is PUT /v1/sessions/{id}/plate. Scope apx.lpr:read.
      parameters:
        - name: session
          in: query
          schema:
            type: string
            format: uuid
          description: Session UUID.
        - name: lane
          in: query
          schema:
            type: string
            format: uuid
          description: VehicularAccess UUID.
        - name: since
          in: query
          schema:
            type: string
            format: date-time
        - $ref: '#/components/parameters/page'
      responses:
        '200':
          description: Candidates, best confidence first.
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/PlateCandidate'
        '400':
          description: Neither session nor lane given (problem type `invalid-request`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/credentials/{id}/passback:
    get:
      operationId: get-apx-v1-credentials-id-passback
      security:
        - apxOAuth:
            - apx.control:read
      tags:
        - Resolution
      summary: Anti-passback status for a credential
      description: |-
        The credential's passback overlay: state, expected vs recorded
        presence, last access. The write side is the `resetPassback` /
        `forceIn` / `forceOut` commands (Part 17 §17.4). Scope
        apx.control:read; the place grant must cover the credential's
        last-access place.

        A credential the server knows but does not track for passback (a
        transient ticket at a site without anti-passback) is 200 with
        `state: unknown`, not 404; 404 means the credential does not
        exist (Part 17 §17.3a).
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: APDS Credential UUID.
      responses:
        '200':
          description: Passback status (`state` is `unknown` for a known credential whose passback is not tracked).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PassbackStatus'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No such credential (problem type `target-not-found`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/support/interactions:
    post:
      operationId: post-apx-v1-support-interactions
      security:
        - apxOAuth:
            - apx.support:manage
      tags:
        - Support
      summary: Record a support interaction
      description: |-
        Records one customer-service interaction (human or AI) so future
        resolution contexts can surface it. Summaries, not transcripts
        (Part 9 §9.6). Scope apx.support:manage.

        A console MAY record the interaction when the call is answered and
        complete it later with PUT /v1/support/interactions/{id}. Clients
        that retry SHOULD send `Idempotency-Key`: a replay returns the
        current record with 200, a different body under the same key is
        409 `idempotency-conflict` (Part 4 §4.2a).
      parameters:
        - $ref: '#/components/parameters/IdempotencyKeyOptional'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SupportInteraction'
      responses:
        '200':
          description: Idempotent replay — the interaction's current representation (Part 4 §4.2a).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SupportInteraction'
        '201':
          description: Recorded interaction.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SupportInteraction'
        '400':
          description: Invalid interaction (problem type `invalid-request`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: Same `Idempotency-Key` replayed with a different body (`idempotency-conflict`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    get:
      operationId: get-apx-v1-support-interactions
      security:
        - apxOAuth:
            - apx.support:manage
      tags:
        - Support
      summary: Support history for a subject
      description: |-
        Recent interactions filtered by any subject key. At least one
        filter is required; none is 400 `invalid-request`. `correlationId`, `interactionId`, and
        `credential` each suffice on their own, so one correlation id
        reconstructs the episode (Part 17 §17.7). Scope
        apx.support:manage (or apx.resolution:read for read-only
        consumers).
      parameters:
        - name: plate
          in: query
          schema:
            type: string
        - name: holder
          in: query
          schema:
            type: string
            format: uuid
        - name: account
          in: query
          schema:
            type: string
            format: uuid
        - name: session
          in: query
          schema:
            type: string
            format: uuid
        - name: place
          in: query
          schema:
            type: string
            format: uuid
        - name: since
          in: query
          schema:
            type: string
            format: date-time
        - name: correlationId
          in: query
          description: Correlation chain id (Part 17 §17.7). Exact match.
          schema:
            type: string
            format: uuid
        - name: interactionId
          in: query
          description: The calling application's opaque interaction identifier. Exact match.
          schema:
            type: string
        - name: credential
          in: query
          description: APDS Credential UUID (matches `subjects.credential`).
          schema:
            type: string
            format: uuid
        - $ref: '#/components/parameters/page'
      responses:
        '200':
          description: Paginated interactions (APDS PaginatedList shape).
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/SupportInteraction'
        '400':
          description: No filter given (problem type `invalid-request`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/support/interactions/{id}:
    parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: SupportInteraction id.
    get:
      operationId: get-apx-v1-support-interactions-id
      security:
        - apxOAuth:
            - apx.support:manage
        - apxOAuth:
            - apx.resolution:read
      tags:
        - Support
      summary: Read one support interaction
      description: |-
        One recorded interaction by id (Part 17 §17.6). Scope
        apx.support:manage, or apx.resolution:read for read-only
        consumers; the interaction's `place` must be inside the caller's
        grant.
      responses:
        '200':
          description: The interaction.
          headers:
            ETag:
              description: The interaction's `version` as an entity tag (Part 4 §4.2a).
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SupportInteraction'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    put:
      operationId: put-apx-v1-support-interactions-id
      security:
        - apxOAuth:
            - apx.support:manage
      tags:
        - Support
      summary: Update (complete) a support interaction
      description: |-
        Replaces the interaction — typically to complete a record opened
        when the call was answered with `endedAt`, `resolution`, `summary`,
        and `actions` (Part 17 §17.6). Optimistic concurrency per Part 4
        §4.2a: send the `version` last read as `If-Match` (or in the
        body); a stale one is 409 `version-conflict`. The server
        increments `version` and publishes
        `apx.support.interaction.recorded.v1` again; consumers tell a
        create from an update by `version`. `id` in the body, when
        present, MUST equal the path id. Scope apx.support:manage.
      parameters:
        - $ref: '#/components/parameters/IfMatch'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SupportInteraction'
      responses:
        '200':
          description: The updated interaction.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SupportInteraction'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: Stale `version` (`version-conflict`, Part 4 §4.2a); nothing is written.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/discovery:
    get:
      operationId: get-apx-v1-discovery
      security:
        - apxOAuth: []
      tags:
        - Discovery
      summary: Credential-scoped capability document
      description: |-
        Reflects the presented token's scopes and grants exactly: the
        endpoints, command types, topics, and place subtrees THIS client can
        use. Soundness rule: everything listed is callable; APX endpoints
        not listed fail with 403.
      responses:
        '200':
          description: The capability document for this credential.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DiscoveryDocument'
        '401':
          description: Missing/invalid token.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /.well-known/apx-configuration:
    get:
      operationId: get-well-known-apx-configuration
      tags:
        - Discovery
      summary: Bootstrap configuration document
      security: []
      description: |-
        Unauthenticated bootstrap document. Advertises the token endpoint,
        the APDS version this implementation extends, supported APX
        conformance classes, and code-list registry locations.

        Served at the server root (NOT under `/v1`), per RFC 8615.
      responses:
        '200':
          description: Bootstrap configuration
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApxConfiguration'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/ui/launches:
    get:
      operationId: get-apx-v1-ui-launches
      security:
        - apxOAuth:
            - apx.ui:read
      tags:
        - UI launch
      summary: List launches
      description: |-
        The launch records visible to the caller, newest first (Part 25
        §25.3). `url` is never included on a list read.
      parameters:
        - name: place
          in: query
          schema:
            type: string
            format: uuid
          description: Launches at this place or its subtree.
        - name: agent
          in: query
          schema:
            type: string
        - name: status
          in: query
          schema:
            type: string
            enum:
              - issued
              - opened
              - closed
              - expired
        - name: correlationId
          in: query
          schema:
            type: string
            format: uuid
        - name: interactionId
          in: query
          schema:
            type: string
        - $ref: '#/components/parameters/page'
      responses:
        '200':
          description: Paginated launches.
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/UiLaunch'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    post:
      operationId: post-apx-v1-ui-launches
      security:
        - apxOAuth:
            - apx.ui:launch
      tags:
        - UI launch
      summary: Open a vendor screen for an agent (handshake launch)
      description: |-
        The host sends its normal APX token and gets back a single-use
        `url` that logs the named agent into the surface, valid for at
        most 60 seconds (Part 25 §25.2). This is the launch mode for
        vendors who want header-based authentication, since a browser
        cannot add headers when it opens a page. `place` must lie inside
        the grant (403 `insufficient-grant`). `Idempotency-Key` optional
        (Part 4 §4.2a). Publishes `apx.ui.launch.changed.v1`.
      parameters:
        - $ref: '#/components/parameters/IdempotencyKeyOptional'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UiLaunchRequest'
      responses:
        '200':
          description: Idempotent replay.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UiLaunch'
        '201':
          description: Issued. `url` and `expiresAt` are set; `status` is `issued`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UiLaunch'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: '`Idempotency-Key` replayed with a different body (`idempotency-conflict`).'
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: |-
            A `surface` this implementation does not offer, or not at this
            place (`ui-surface-unknown`); a `displayMode` the surface does
            not support (`ui-display-mode-unsupported`); or a `subject`,
            `place` or `lane` that does not exist (`reference-unknown`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/ui/launches/{id}:
    get:
      operationId: get-apx-v1-ui-launches-id
      security:
        - apxOAuth:
            - apx.ui:read
      tags:
        - UI launch
      summary: Read a launch and what was done in it
      description: |-
        The launch with its `actions[]` (Part 25 §25.3). `url` is present
        only while the launch is `issued` and before `expiresAt`.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: The launch.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UiLaunch'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/ui/launches/{id}/actions:
    post:
      operationId: post-apx-v1-ui-launches-id-actions
      security:
        - apxOAuth:
            - apx.ui:record
      tags:
        - UI launch
      summary: Record an action done in the screen (loopback fallback)
      description: |-
        The surface, or the service behind it, records what the agent did
        when the implementation could not express it as the module's own
        resource or Command (Part 25 §25.4). The record carries the
        launch's `correlationId` and is published as
        `apx.ui.action.recorded.v1`. A launch that was never opened and
        has expired refuses with `ui-launch-expired`; a closed one with
        `ui-launch-closed`.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UiActionRecord'
      responses:
        '201':
          description: Recorded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UiActionRecord'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: The launch is `expired` (`ui-launch-expired`) or `closed` (`ui-launch-closed`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/ui/launches/{id}/close:
    post:
      operationId: post-apx-v1-ui-launches-id-close
      security:
        - apxOAuth:
            - apx.ui:record
      tags:
        - UI launch
      summary: Close a launch
      description: |-
        The screen reports it is done: `opened` (or `issued`) → `closed`
        (Part 25 §25.3). No body. Publishes `apx.ui.launch.changed.v1`.
        Already closed is 409 `ui-launch-closed`.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: The closed launch.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UiLaunch'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: Already closed (`ui-launch-closed`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/equipment:
    get:
      operationId: get-apx-v1-equipment
      security:
        - apxOAuth:
            - apx.siteconfig:read
      tags:
        - Site configuration
      summary: List a place's equipment with its roles, makes, versions and areas
      description: |-
        Every SupplementalEquipment at the place, each with its
        `apds-ext:apx:equipment-detail@1.0` decoration, so a reader learns
        what the site has from APX alone (Part 26 §26.1). Distinct from
        `GET /v1/devices`, which serves live state; this serves the
        description. `mode=change&cursor=` serves the Part 5 §5.2 feed,
        so an edge or call-centre system keeps a local copy current.
        Naming a `place` outside the grant is 403 `insufficient-grant`.
      parameters:
        - $ref: '#/components/parameters/ModeParam'
        - $ref: '#/components/parameters/CursorParam'
        - name: place
          in: query
          required: true
          schema:
            type: string
            format: uuid
          description: The HierarchyElement subtree root.
        - name: role
          in: query
          schema:
            type: string
          description: An apx-equipment-roles value.
        - name: area
          in: query
          schema:
            type: string
          description: An apx-area-types value.
        - name: lane
          in: query
          schema:
            type: string
            format: uuid
          description: Equipment serving this VehicularAccess.
        - name: level
          in: query
          schema:
            type: string
        - $ref: '#/components/parameters/page'
      responses:
        '200':
          description: Paginated equipment; with `mode=change`, the changes after `cursor` in the same envelope (Part 5 §5.2 rule 8).
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/EquipmentRecord'
                  updateMode:
                    $ref: '#/components/schemas/ChangeFeedUpdateMode'
                  cursor:
                    $ref: '#/components/schemas/ChangeFeedCursor'
                  deleted:
                    $ref: '#/components/schemas/ChangeFeedTombstones'
                  grantAdditions:
                    $ref: '#/components/schemas/ChangeFeedGrantAdditions'
                  next:
                    $ref: '#/components/schemas/ChangeFeedNext'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/CursorRefused'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/equipment/{id}:
    get:
      operationId: get-apx-v1-equipment-id
      security:
        - apxOAuth:
            - apx.siteconfig:read
      tags:
        - Site configuration
      summary: Read one piece of equipment
      description: The SupplementalEquipment with its APX decorations (Part 26 §26.1).
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: The equipment record.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EquipmentRecord'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/comms-points:
    get:
      operationId: get-apx-v1-comms-points
      security:
        - apxOAuth:
            - apx.siteconfig:read
      tags:
        - Site configuration
      summary: List or look up comms points
      description: |-
        The ways a parker reaches help at the caller's places (Part 26
        §26.4). A call platform finds the comms point of an inbound
        contact with `callerId`, `dialedNumber` or `commsDeviceId`; the
        answer carries the lane, or the place only. `mode=change&cursor=`
        serves the Part 5 §5.2 feed.
      parameters:
        - $ref: '#/components/parameters/ModeParam'
        - $ref: '#/components/parameters/CursorParam'
        - name: place
          in: query
          schema:
            type: string
            format: uuid
        - name: lane
          in: query
          schema:
            type: string
            format: uuid
        - name: type
          in: query
          schema:
            type: string
          description: An apx-comms-point-types value.
        - name: callerId
          in: query
          schema:
            type: string
          description: E.164; matches `callerId`.
        - name: dialedNumber
          in: query
          schema:
            type: string
          description: E.164; matches `phoneNumber`.
        - name: commsDeviceId
          in: query
          schema:
            type: string
        - $ref: '#/components/parameters/page'
      responses:
        '200':
          description: Paginated comms points; with `mode=change`, the changes after `cursor` in the same envelope.
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/CommsPoint'
                  updateMode:
                    $ref: '#/components/schemas/ChangeFeedUpdateMode'
                  cursor:
                    $ref: '#/components/schemas/ChangeFeedCursor'
                  deleted:
                    $ref: '#/components/schemas/ChangeFeedTombstones'
                  grantAdditions:
                    $ref: '#/components/schemas/ChangeFeedGrantAdditions'
                  next:
                    $ref: '#/components/schemas/ChangeFeedNext'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/CursorRefused'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    post:
      operationId: post-apx-v1-comms-points
      security:
        - apxOAuth:
            - apx.siteconfig:manage
      tags:
        - Site configuration
      summary: Add a comms point
      description: |-
        Whoever runs the calls adds the comms point, the call centre or
        the call platform (Part 26 §26.4). `place` must lie inside the
        grant (403 `insufficient-grant`); `lane`, `equipment` and `serves`
        must exist (422 `reference-unknown`). `Idempotency-Key` optional.
        Publishes `apx.commspoints.changed.v1`.
      parameters:
        - $ref: '#/components/parameters/IdempotencyKeyOptional'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CommsPoint'
      responses:
        '200':
          description: Idempotent replay.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CommsPoint'
        '201':
          description: Created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CommsPoint'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: '`Idempotency-Key` replayed with a different body (`idempotency-conflict`).'
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: A `type` outside the registry, or a `place`, `lane`, `equipment` or `serves` that does not exist (`reference-unknown`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/comms-points/{id}:
    get:
      operationId: get-apx-v1-comms-points-id
      security:
        - apxOAuth:
            - apx.siteconfig:read
      tags:
        - Site configuration
      summary: Read a comms point
      description: The comms point with the lane or place it serves and the barrier an agent opens for it (Part 26 §26.4).
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: The comms point.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CommsPoint'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    put:
      operationId: put-apx-v1-comms-points-id
      security:
        - apxOAuth:
            - apx.siteconfig:manage
      tags:
        - Site configuration
      summary: Replace a comms point
      description: |-
        Full replacement with the version last read as `If-Match` or body
        `version` (409 `version-conflict`, Part 4 §4.2a). Publishes
        `apx.commspoints.changed.v1`.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - $ref: '#/components/parameters/IfMatch'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CommsPoint'
      responses:
        '200':
          description: Replaced.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CommsPoint'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: Stale version (`version-conflict`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: A `type` outside the registry, or a reference that does not exist (`reference-unknown`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    delete:
      operationId: delete-apx-v1-comms-points-id
      security:
        - apxOAuth:
            - apx.siteconfig:manage
      tags:
        - Site configuration
      summary: Remove a comms point
      description: The feed emits a tombstone (Part 5 §5.2); publishes `apx.commspoints.changed.v1`.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '204':
          description: Removed.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/identifiers:resolve:
    post:
      operationId: post-apx-v1-identifiers-resolve
      security:
        - apxOAuth:
            - apx.siteconfig:read
      tags:
        - Site configuration
      summary: Find the APX record behind another system's id
      description: |-
        Looks up a `{system, id}` pair from any
        `apds-ext:apx:external-ids@1.0` decoration the caller may see
        (Part 26 §26.6), so a PARCS, a call platform or an aggregator goes
        from its own id to the place, lane, equipment or comms point
        without a table of its own. A read, as a POST so the id never sits
        in a URL. No match is 404 `target-not-found`.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/IdentifierResolveRequest'
      responses:
        '200':
          description: The record the id names.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IdentifierResolution'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No visible record carries this id (`target-not-found`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/cameras/{id}/views:
    post:
      operationId: post-apx-v1-cameras-id-views
      security:
        - apxOAuth:
            - apx.cameras:view
      tags:
        - Site configuration
      summary: Get a short-lived link to see a camera
      description: |-
        A live stream, a still, or a recording of the camera (the
        SupplementalEquipment with role `camera`), as a single-use link
        bound to the agent and valid for at most 5 minutes (Part 26
        §26.3). Whoever holds the camera answers; its password never
        leaves the site. Every view is logged against the agent and
        `correlationId`. Offered under the `cameraViews` feature;
        `playback` also needs `cameraPlayback`.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The camera's SupplementalEquipment id.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CameraViewRequest'
      responses:
        '201':
          description: The link.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CameraView'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: The camera is offline, has no recorder for `playback`, or the implementation cannot issue a view now (`camera-view-unavailable`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: '`playback` with a `from`/`to` outside the camera''s retention or missing (`playback-range-unavailable`), or a `kind` the camera''s `streams` cannot serve (`request-unprocessable`).'
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/display-records:
    get:
      operationId: get-apx-v1-display-records
      security:
        - apxOAuth:
            - apx.siteconfig:read
      tags:
        - Site configuration
      summary: List the messages signs showed
      description: |-
        The records that a sign showed a message, newest first (Part 26
        §26.9): which sign, which kind of message, when, and for which read
        or stay. An operator measures the signs with them; an appeal finds
        the proof of display. `mode=change&cursor=` serves the Part 5 §5.2
        feed. A `place` outside the grant is 403 `insufficient-grant`.
      parameters:
        - $ref: '#/components/parameters/ModeParam'
        - $ref: '#/components/parameters/CursorParam'
        - name: place
          in: query
          schema:
            type: string
            format: uuid
          description: The HierarchyElement subtree root.
        - name: display
          in: query
          schema:
            type: string
            format: uuid
          description: The sign's SupplementalEquipment id.
        - name: messageKind
          in: query
          schema:
            type: string
          description: An apx-display-message-kinds value or implementer code.
        - name: session
          in: query
          schema:
            type: string
            format: uuid
          description: Records for this stay.
        - name: observation
          in: query
          schema:
            type: string
            format: uuid
          description: Records triggered by this read.
        - name: since
          in: query
          description: Inclusive lower bound on `shownTime`.
          schema:
            type: string
            format: date-time
        - name: until
          in: query
          description: Exclusive upper bound on `shownTime`.
          schema:
            type: string
            format: date-time
        - $ref: '#/components/parameters/page'
      responses:
        '200':
          description: Paginated display records; with `mode=change`, the changes after `cursor` in the same envelope (Part 5 §5.2 rule 8).
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/DisplayRecord'
                  updateMode:
                    $ref: '#/components/schemas/ChangeFeedUpdateMode'
                  cursor:
                    $ref: '#/components/schemas/ChangeFeedCursor'
                  deleted:
                    $ref: '#/components/schemas/ChangeFeedTombstones'
                  grantAdditions:
                    $ref: '#/components/schemas/ChangeFeedGrantAdditions'
                  next:
                    $ref: '#/components/schemas/ChangeFeedNext'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/CursorRefused'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    post:
      operationId: post-apx-v1-display-records
      security:
        - apxOAuth:
            - apx.displays:record
      tags:
        - Site configuration
      summary: Record that a sign showed a message
      description: |-
        Written by whichever system drove the display, the edge
        controller, the PARCS or the sign's player, usually with no APX
        command involved (Part 26 §26.9). `display` must be a
        SupplementalEquipment (422 `reference-unknown`); the server derives
        `place` from it. No message text and no plate are stored. With
        `command`, `shownTime` and `contentHash` must agree with that
        command's `CommandResult.display`. Immutable once written.
        `Idempotency-Key` optional. Publishes `apx.displays.shown.v1`.
      parameters:
        - $ref: '#/components/parameters/IdempotencyKeyOptional'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DisplayRecord'
      responses:
        '200':
          description: Idempotent replay.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DisplayRecord'
        '201':
          description: Recorded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DisplayRecord'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: '`Idempotency-Key` replayed with a different body (`idempotency-conflict`).'
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: A `display`, `observation`, `session` or `command` that names nothing visible (`reference-unknown`); a body `place` that disagrees with the display's, or a record that disagrees with its command's result (`request-unprocessable`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/display-records/{id}:
    get:
      operationId: get-apx-v1-display-records-id
      security:
        - apxOAuth:
            - apx.siteconfig:read
      tags:
        - Site configuration
      summary: Read a display record
      description: What a sign showed, when, and for which read or stay (Part 26 §26.9).
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: The display record.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DisplayRecord'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/approvals:
    get:
      operationId: get-apx-v1-approvals
      security:
        - apxOAuth:
            - apx.resolution:read
      tags:
        - Resolution
      summary: List approval requests
      description: Approval requests at the caller's places, newest first (Part 17 §17.3a); an approver's queue is `status=pending&role=…`.
      parameters:
        - name: place
          in: query
          schema:
            type: string
            format: uuid
        - name: status
          in: query
          schema:
            type: string
            enum:
              - pending
              - approved
              - denied
              - expired
        - name: role
          in: query
          schema:
            type: string
        - $ref: '#/components/parameters/page'
      responses:
        '200':
          description: Paginated approval requests.
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    $ref: '#/components/schemas/PaginatedListMeta'
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/ApprovalRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    post:
      operationId: post-apx-v1-approvals
      security:
        - apxOAuth:
            - apx.support:manage
      tags:
        - Resolution
      summary: Ask for approval of an action
      description: |-
        An agent whose AllowedAction said `requiresApproval` asks the
        named role to decide (Part 17 §17.3a). `place` must lie inside the
        grant. `Idempotency-Key` optional. Publishes
        `apx.approvals.changed.v1`; the approver's system subscribes to it
        or reads the queue.
      parameters:
        - $ref: '#/components/parameters/IdempotencyKeyOptional'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ApprovalRequest'
      responses:
        '200':
          description: Idempotent replay.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApprovalRequest'
        '201':
          description: Created, `status` = `pending`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApprovalRequest'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: '`Idempotency-Key` replayed with a different body (`idempotency-conflict`).'
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: A `place` or `target` that does not exist (`reference-unknown`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/approvals/{id}:
    get:
      operationId: get-apx-v1-approvals-id
      security:
        - apxOAuth:
            - apx.resolution:read
      tags:
        - Resolution
      summary: Read an approval request
      description: The request with its `decision` once made, or its `expired` status once `expiresAt` has passed (Part 17 §17.3a).
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: The request with its decision, if made.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApprovalRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/approvals/{id}/decide:
    post:
      operationId: post-apx-v1-approvals-id-decide
      security:
        - apxOAuth:
            - apx.support:manage
      tags:
        - Resolution
      summary: Approve or deny
      description: |-
        The approver decides: `pending` → `approved` or `denied` (Part 17
        §17.3a). The agent then executes the action with `Approval`
        evidence citing the request. A request already decided or expired
        is 409 `approval-closed`. Publishes `apx.approvals.changed.v1`.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ApprovalDecision'
      responses:
        '200':
          description: The decided request.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApprovalRequest'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: Already decided or expired (`approval-closed`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/payments/{id}/receipt:
    post:
      operationId: post-apx-v1-payments-id-receipt
      security:
        - apxOAuth:
            - apx.payments:write
      tags:
        - Accounts
      summary: Send the receipt again
      description: |-
        Re-sends the receipt of a settled payment by e-mail, SMS, a
        re-print at the device, or a short-lived link (Part 13 §13.1a).
        The destination travels in the body, never in a URL. Accepted for
        delivery (202); the outcome is in the returned ReceiptDelivery.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReceiptRequest'
      responses:
        '202':
          description: Queued or sent.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReceiptDelivery'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: The payment is not settled (`payment-state-illegal`, Part 13 §13.1a).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '422':
          description: A `channel` this implementation or device cannot serve (`receipt-channel-unsupported`), or a `destination` missing for `email`/`sms` (`request-unprocessable`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/TooManyRequests'
webhooks:
  apx-event:
    post:
      operationId: receive-apx-event
      summary: Signed APX event delivery
      description: |-
        Every webhook delivery POSTs one EventEnvelope with headers
        `APX-Signature` (v1=HMAC-SHA256(secret, timestamp + "." + body)),
        `APX-Timestamp` (RFC 3339, ±5 min replay window),
        `APX-Delivery-Id` (unique per attempt; envelope `id` is stable
        across retries), and `APX-Key-Id` (REQUIRED during secret-rotation
        overlap windows — Part 9 §9.4). Respond 2xx to acknowledge;
        anything else triggers the normative retry schedule (Part 8).

        **Every attempt is signed afresh (normative, Part 8 §8.3):**
        `APX-Timestamp` is the time of that attempt and `APX-Signature` is
        computed over it and the unchanged body, so a retry an hour later
        still falls inside the receiver's ±5-minute window. The body — and
        with it the envelope `id` and `time` — is byte-identical across
        attempts.

        The typed entries below (`apx-native-event` and one per APX topic
        whose data schema lives outside its own domain) name the `data`
        schema each topic carries (Part 8 §8.7); they are the same POST.
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EventEnvelope'
      responses:
        '200':
          description: Acknowledged.
  apx-native-event:
    post:
      operationId: receive-apx-native-event
      summary: APDS EventTypeEnum topic delivery
      description: |-
        A delivery on an APDS 4.1 topic (`SessionCreated`, `PlaceUpdated`,
        …): `type` is an APDS `EventTypeEnum` value, `data` the APDS
        `EventData` shape (the created/updated entity; for a `*Deleted`
        topic the last state), and `subject` references the entity
        (Part 5 §5.4, Part 8 §8.2). Signed and retried like every delivery.
      parameters:
        - name: APX-Signature
          in: header
          required: true
          description: '`v1=` + hex HMAC-SHA256(secret, APX-Timestamp + "." + raw body), computed per attempt.'
          schema:
            type: string
            pattern: ^v1=[0-9a-f]{64}$
        - name: APX-Timestamp
          in: header
          required: true
          description: RFC 3339 time of THIS attempt (not of the event or of the first attempt).
          schema:
            type: string
            format: date-time
        - name: APX-Delivery-Id
          in: header
          required: true
          description: UUID unique per attempt; the envelope `id` is the dedup key.
          schema:
            type: string
            format: uuid
        - name: APX-Key-Id
          in: header
          required: false
          description: The signing key's id — REQUIRED during a rotation overlap (Part 9 §9.4).
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/EventEnvelope'
                - type: object
                  properties:
                    type:
                      $ref: '#/components/schemas/EventTypeEnum'
                    data:
                      $ref: '#/components/schemas/EventData'
      responses:
        '200':
          description: Acknowledged.
  apx.subscription.failed.v1:
    post:
      operationId: receive-apx-subscription-failed
      summary: A subscription exhausted its retry schedule
      description: |-
        Published when a subscription enters `failed` (Part 8 §8.3).
        `subject` references the subscription (`className`
        `ApxEventSubscription`); `data` is a SubscriptionFailure. Delivered
        to other subscriptions of the same `apx_org` that list the topic,
        never to the failed one.
      parameters:
        - name: APX-Signature
          in: header
          required: true
          description: '`v1=` + hex HMAC-SHA256(secret, APX-Timestamp + "." + raw body), computed per attempt.'
          schema:
            type: string
            pattern: ^v1=[0-9a-f]{64}$
        - name: APX-Timestamp
          in: header
          required: true
          description: RFC 3339 time of THIS attempt (not of the event or of the first attempt).
          schema:
            type: string
            format: date-time
        - name: APX-Delivery-Id
          in: header
          required: true
          description: UUID unique per attempt; the envelope `id` is the dedup key.
          schema:
            type: string
            format: uuid
        - name: APX-Key-Id
          in: header
          required: false
          description: The signing key's id — REQUIRED during a rotation overlap (Part 9 §9.4).
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/EventEnvelope'
                - type: object
                  properties:
                    type:
                      const: apx.subscription.failed.v1
                    data:
                      $ref: '#/components/schemas/SubscriptionFailure'
      responses:
        '200':
          description: Acknowledged.
  apx.data.observation.created.v1:
    post:
      operationId: receive-apx-data-observation-created
      summary: An Observation was ingested
      description: |-
        One event per ingested read. `data` is the APDS
        `ObservationElement` (an ingested ObservationSet yields one event
        per element); `subject` references it with `className`
        `ObservationElement`; publishers MUST populate `elementIds` with
        the observing lane or place, which is the event's place binding
        (Part 8 §8.5). Plate values are subject to Part 9 §9.6.
      parameters:
        - name: APX-Signature
          in: header
          required: true
          description: '`v1=` + hex HMAC-SHA256(secret, APX-Timestamp + "." + raw body), computed per attempt.'
          schema:
            type: string
            pattern: ^v1=[0-9a-f]{64}$
        - name: APX-Timestamp
          in: header
          required: true
          description: RFC 3339 time of THIS attempt (not of the event or of the first attempt).
          schema:
            type: string
            format: date-time
        - name: APX-Delivery-Id
          in: header
          required: true
          description: UUID unique per attempt; the envelope `id` is the dedup key.
          schema:
            type: string
            format: uuid
        - name: APX-Key-Id
          in: header
          required: false
          description: The signing key's id — REQUIRED during a rotation overlap (Part 9 §9.4).
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/EventEnvelope'
                - type: object
                  properties:
                    type:
                      const: apx.data.observation.created.v1
                    data:
                      $ref: '#/components/schemas/ObservationElement'
      responses:
        '200':
          description: Acknowledged.
  apx.data.observation.updated.v1:
    post:
      operationId: receive-apx-data-observation-updated
      summary: An ingested Observation was replaced
      description: |-
        Published whenever an ingested Observation changes — for example
        the LPR system revising `accessEvent` through
        `PUT /v1/lpr/reads/{observation}/access-event` (Part 13 §13.3a(4),
        §13.4), or a reviewer's plate decision through
        `PUT /v1/lpr/reads/{observation}/plate` (§13.3a(4a)). `data` is the
        APDS `ObservationElement` as it now stands; `subject` and the place
        binding (`elementIds`) are as for `apx.data.observation.created.v1`.
        Consumers key on the Observation id and keep the highest `version`.
        Plate values are subject to Part 9 §9.6.
      parameters:
        - name: APX-Signature
          in: header
          required: true
          description: '`v1=` + hex HMAC-SHA256(secret, APX-Timestamp + "." + raw body), computed per attempt.'
          schema:
            type: string
            pattern: ^v1=[0-9a-f]{64}$
        - name: APX-Timestamp
          in: header
          required: true
          description: RFC 3339 time of THIS attempt (not of the event or of the first attempt).
          schema:
            type: string
            format: date-time
        - name: APX-Delivery-Id
          in: header
          required: true
          description: UUID unique per attempt; the envelope `id` is the dedup key.
          schema:
            type: string
            format: uuid
        - name: APX-Key-Id
          in: header
          required: false
          description: The signing key's id — REQUIRED during a rotation overlap (Part 9 §9.4).
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/EventEnvelope'
                - type: object
                  properties:
                    type:
                      const: apx.data.observation.updated.v1
                    data:
                      $ref: '#/components/schemas/ObservationElement'
      responses:
        '200':
          description: Acknowledged.
  apx.reservation.noshow.v1:
    post:
      operationId: receive-apx-reservation-noshow
      summary: A reservation reached its no-show condition
      description: |-
        `data` is a ReservationSummary (`reservation`, `reservationState`
        `noShow`, `plannedStart`); `subject` references the AssignedRight
        (Part 14 §14.1, Part 8 §8.7).
      parameters:
        - name: APX-Signature
          in: header
          required: true
          description: '`v1=` + hex HMAC-SHA256(secret, APX-Timestamp + "." + raw body), computed per attempt.'
          schema:
            type: string
            pattern: ^v1=[0-9a-f]{64}$
        - name: APX-Timestamp
          in: header
          required: true
          description: RFC 3339 time of THIS attempt (not of the event or of the first attempt).
          schema:
            type: string
            format: date-time
        - name: APX-Delivery-Id
          in: header
          required: true
          description: UUID unique per attempt; the envelope `id` is the dedup key.
          schema:
            type: string
            format: uuid
        - name: APX-Key-Id
          in: header
          required: false
          description: The signing key's id — REQUIRED during a rotation overlap (Part 9 §9.4).
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/EventEnvelope'
                - type: object
                  properties:
                    type:
                      const: apx.reservation.noshow.v1
                    data:
                      $ref: '#/components/schemas/ReservationSummary'
      responses:
        '200':
          description: Acknowledged.
components:
  parameters:
    ModeParam:
      name: mode
      in: query
      required: false
      description: |-
        APX change feed (Part 5 §5.2): `full` (default — the route's ordinary
        list; on a native APDS route, exactly stock APDS 4.1) or `change` (the
        changes after `cursor`: a ChangeFeedPage on a native route, the route's
        own list envelope with the change-page members on an APX list route,
        rule 8; on an APX list route without a cursor, an empty page holding the
        current head cursor).
      schema:
        type: string
        enum:
          - full
          - change
        default: full
    CursorParam:
      name: cursor
      in: query
      required: false
      description: Opaque change-feed cursor from a previous change page. Only meaningful with `mode=change`; a refused cursor is 404 `target-not-found` (Part 5 §5.2 rules 2 and 5).
      schema:
        type: string
    IfMatch:
      name: If-Match
      in: header
      required: false
      description: |-
        The `version` the client last read, as an entity tag (`"7"`). A
        stale value is 409 `version-conflict`; nothing is written (Part 4
        §4.2a). Equivalent to sending `version` in the body.
      schema:
        type: string
        examples:
          - '"7"'
    IdempotencyKeyOptional:
      name: Idempotency-Key
      in: header
      required: false
      description: |-
        When given, the operation is idempotent per Part 4 §4.2a: a replay
        with the same body returns the current representation (200), a
        different body is 409 `idempotency-conflict`. Clients that retry
        SHOULD send it.
      schema:
        type: string
    latitude:
      schema:
        type: number
        format: float
      in: query
      name: latitude
      description: Location latitude to use as filter (mandatory if __longitude__ and __radius__ are defined)
    longitude:
      schema:
        type: number
        format: float
      in: query
      name: longitude
      description: Location longitude to use as filter (mandatory if __latitude__ and __radius__ are defined)
    radius:
      schema:
        type: integer
        minimum: 0
      in: query
      name: radius
      description: Number of metres to use as search filter from given position (mandatory if __latitude__ and __longitude__ are defined)
    place_types:
      schema:
        type: array
        items:
          $ref: '#/components/schemas/HierarchyElementTypeEnum'
      name: type
      in: query
      description: Comma-separated list of place types to consider. All will be assumed if parameter is not used or left blank.
      style: form
      explode: false
    right_spec_types:
      schema:
        type: array
        items:
          $ref: '#/components/schemas/RightSpecificationTypeEnum'
      name: right_type
      in: query
      description: Comma-separated list of right specification types to consider. All will be assumed if parameter is not used or left blank.
      style: form
      explode: false
    structure_type:
      schema:
        type: array
        items:
          $ref: '#/components/schemas/StructureTypeEnum'
      name: structure_type
      in: query
      description: Comma-separated list of types of structure in the hierarchy to consider (all will be assumed if parameter is not used or left blank)
      style: form
      explode: false
    structure_grade:
      schema:
        type: array
        items:
          $ref: '#/components/schemas/StructureGradeEnum'
      name: structure_grade
      in: query
      description: Comma-separated list of Structure grades in the hierarchy to consider (all will be assumed if parameter is not used or left blank)
      style: form
      explode: false
    place_name:
      schema:
        type: string
      name: name
      in: query
      description: Name of place hierarchy element (in any of its supported languages)
    place_layer:
      schema:
        type: integer
      name: layer
      in: query
      description: Most detailed (lower-level) layer of data desired. 0 (zero) being the first level (and higher numbers correspond to lower-levels of information). If left empty, the entire place hierarchy that matches the remaining parameters will be returned.
    operator:
      schema:
        type: string
      in: query
      name: operator
      description: id of the parking operator in charge of the location(s)
    modified_since:
      schema:
        type: integer
        minimum: 0
      in: query
      name: modified_since
      description: Unix epoch __instant__ to filter results that have changed or have been deleted after the given instant. If __expand__ attributes are requested, then this parameter will also apply to those objects. When this attribute is used, the result set will also include a list of deleted references to avoid storing stale data.
    places_expand:
      schema:
        type: array
        items:
          type: string
          enum:
            - all
            - none
            - rightSpecifications
            - occupancy
            - areaLocation
            - pointLocation
            - contacts
            - operatingRestrictions
            - characteristics
            - paymentMethods
            - openingTimes
            - streetAddress
      description: Comma-separated list of optional object attributes associated to a place hierarchy element that should be included in the result set.
      name: expand
      in: query
      style: form
      explode: false
    page:
      schema:
        type: integer
        minimum: 1
      in: query
      name: page
      description: The page number for paginated responses.
    version:
      schema:
        type: integer
        minimum: 1
      in: query
      name: version
      description: Previous version number. Useful when a reference to a resource version is found in another dataset, and that version is no longer the latest one. Latest version is assumed when this parameter is not used.
    place_ids:
      schema:
        type: array
        items:
          type: string
      description: Comma-separated list of unique place ids according to the requested types.
      name: place
      in: query
      explode: false
      style: form
    start_before:
      schema:
        type: integer
        minimum: 0
      in: query
      name: start_before
      description: Unix epoch __instant__ to filter results starting before the given instant.
    end_before:
      schema:
        type: integer
        minimum: 0
      in: query
      name: end_before
      description: Unix epoch __instant__ to filter results ending before the given instant.
    start_after:
      schema:
        type: integer
        minimum: 0
      in: query
      name: start_after
      description: Unix epoch __instant__ to filter results starting after the given instant.
    end_after:
      schema:
        type: integer
        minimum: 0
      in: query
      name: end_after
      description: Unix epoch __instant__ to filter results ending after the given instant.
    issuer:
      schema:
        type: string
      in: query
      name: issuer
      description: id of the entity that issued the returned records
    right_specs_expand:
      schema:
        type: array
        items:
          type: string
          enum:
            - all
            - none
            - rateEligibility
            - validity
            - credentials
            - rightPools
      description: Comma-separated list of optional object attributes associated to a right specification that should be included in the result set.
      name: expand
      in: query
      style: form
      explode: false
    right_spec_ids:
      schema:
        type: array
        items:
          type: string
      description: Comma-separated list of unique right specification ids according to the requested types.
      name: right_spec
      in: query
      explode: false
      style: form
    rates_expand:
      schema:
        type: array
        items:
          type: string
          enum:
            - all
            - none
            - rateLineCollections
            - rateLineCollections.rateLines
      description: Comma-separated list of optional attributes associated to a rate that should be included in the result set.
      name: expand
      in: query
      style: form
      explode: false
    credential_ids:
      schema:
        type: array
        items:
          type: string
      in: query
      name: credential_id
      description: Comma-separated list of unique credential ids according to the requested types.
      style: form
      explode: false
    credential_types:
      schema:
        type: array
        items:
          $ref: '#/components/schemas/CredentialTypeEnum'
      name: credential_type
      in: query
      description: Comma-separated list of credential types to consider. All will be assumed if parameter is not used or left blank.
      style: form
      explode: false
    sessions_expand:
      schema:
        type: array
        items:
          type: string
          enum:
            - all
            - none
            - credentials
            - vehicleAncillaryIdentification
            - segments
            - segments.space
            - segments.assignedRight
      description: Comma-separated list of optional attributes associated to a session or its segment.s that should be included in the result set.
      name: expand
      in: query
      style: form
      explode: false
    assigned_expand:
      schema:
        type: array
        items:
          type: string
          enum:
            - all
            - none
            - plannedUses
            - assignedRightIssuer
      description: Comma-separated list of optional object attributes associated to an assigned right that should be included in the result set.
      name: expand
      in: query
      style: form
      explode: false
    quote_type:
      name: quote_type
      in: query
      schema:
        type: string
        description: type of quote element requested
        enum:
          - QuoteRightRequest
          - QuoteRightResponse
          - QuoteSessionExtensionRequest
          - QuoteSessionExtensionResponse
  responses:
    BadRequest:
      description: |-
        The request is malformed: the body or a parameter fails the
        operation's schema or a normative field rule (problem type
        `invalid-request`, with an `errors[]` member naming each offending
        JSON Pointer), or a REQUIRED Idempotency-Key is absent
        (`idempotency-key-required`). Part 12.
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    Unauthorized:
      description: |-
        Missing, malformed, expired, or revoked access token (problem type
        `unauthenticated`, Part 12).
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    CursorRefused:
      description: |-
        `mode=change` only (Part 5 §5.2): the cursor is unknown, older
        than the retention window, or was issued for another (class,
        credential, filter set). Problem type `target-not-found`; re-sync
        with `mode=full`. The cursor is an APX parameter, so this refusal
        is always a Problem (Part 5 §5.2 rules 2 and 5).
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    NotFound:
      description: |-
        The addressed resource does not exist (problem type
        `target-not-found`). A resource at a place outside the caller's
        `apx_places` grant is 403 `insufficient-grant` instead (Part 9 §9.3).
        A resource that exists but lies outside a narrower ownership scope
        (a merchant's own programs, a valet customer's own ticket) is
        reported as 404, so the answer never confirms another party's
        record exists (Part 9 §9.3a).
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    Forbidden:
      description: |-
        Insufficient scope (problem type `insufficient-scope`) or place
        grant (`insufficient-grant`) for this operation (Part 9).
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    TooManyRequests:
      description: Rate limited (problem type `rate-limited`, Part 12).
      headers:
        Retry-After:
          description: Seconds to wait before retrying (RFC 9110).
          schema:
            type: integer
            minimum: 0
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
  securitySchemes:
    oAuth:
      type: oauth2
      flows:
        clientCredentials:
          tokenUrl: https://api.parking-data-standards.org
          scopes:
            po: Parking Operator
            sp: Service Provider
            ep: Enforcement Provider
            ad: Administrator
    apxOAuth:
      type: oauth2
      description: |-
        OAuth 2.0 client-credentials (aligned with APDS 4.1's `oAuth` scheme).
        APX scopes follow `apx.<domain>:<verb>`. Grants are carried in the
        normative token claims `apx_org` (Organisation reference) and
        `apx_places` (HierarchyElement subtree grants — FAIL-CLOSED: absent
        or empty = no places; the explicit wildcard "*" = all places,
        Part 9 §9.3).
      flows:
        clientCredentials:
          tokenUrl: https://auth.example.com/oauth2/token
          scopes:
            apx.data:read: Read parking data via APDS-native routes
            apx.data:write: Create/update parking data via APDS-native routes
            apx.control:read: Read commands, lanes, and device status
            apx.control:execute: Execute commands (vend gate, lost ticket, push rate, apply validation…)
            apx.alerts:read: Read alerts
            apx.alerts:write: Raise, acknowledge, and resolve alerts
            apx.subscriptions:manage: Create and manage event subscriptions
            apx.accounts:read: Look up accounts and balances
            apx.payments:write: Take payments and post accounting write-backs
            apx.lpr:read: LPR plate/ticket cross-lookup
            apx.reservations:manage: Quote, book, amend, cancel reservations
            apx.permits:manage: Issue and manage permits
            apx.tolling:manage: Create and manage toll transactions
            apx.resolution:read: Resolve and read customer-service resolution contexts and allowed actions
            apx.support:manage: Record and read support-interaction history
            apx.violations:read: Read violations and run the enforcement eligibility check
            apx.violations:manage: Create, review, issue, settle, appeal, and void violations
            apx.validations:read: Read validation programs, issuances, redemptions, and statements
            apx.validations:manage: Enrol and update programs, issue stock, reverse redemptions, close statements
            apx.validations:redeem: Merchant scope — check codes, issue own stock, record redemptions, read own programs and statements (limited to the token's apx_org)
            apx.credentials:read: Read credentials and their access-event history
            apx.credentials:manage: Issue, activate, suspend, resume, report lost, revoke, and replace credentials
            apx.valet:read: Read valet tickets and the retrieval queue
            apx.valet:manage: Take custody, park, stage, hand back, and manage retrievals
            apx.valet:request: Customer scope — request or cancel retrieval and read status/ETA for the caller's own ticket (text, app, web, voice bot)
            apx.platelists:read: Read plate lists and their entries, plate values included (Part 24)
            apx.platelists:manage: Create and maintain plate lists and entries (Part 24)
            apx.ui:launch: Open a vendor screen for an agent and read the launches it issued (Part 25)
            apx.ui:read: Read UI launches and the actions recorded in them (Part 25)
            apx.ui:record: The surface's own scope; record actions done in a launched screen and close it (Part 25)
            apx.siteconfig:read: Read a place's equipment, cameras, comms points, display records and external ids; resolve another system's id (Part 26)
            apx.siteconfig:manage: Add, replace and remove comms points (Part 26)
            apx.cameras:view: Obtain short-lived camera view links, logged against the agent (Part 26)
            apx.displays:record: The scope of the system that drives a sign; record that a message was shown (Part 26 §26.9)
            apx.compliance:read: Read the stay-compliance status on Sessions; without it the decoration is left out (Part 5 §5.9)
            apx.compliance:write: Write the stay-compliance status on Sessions, beside the Session write scope (Part 5 §5.9)
            apx.digest:use: Receive the credential digest keys (Part 9 §9.6 rule 6)
            apx.replication:write: Replay another implementation's records with their original provenance and lifecycle times (Part 18 §18.6)
            apx.charging:read: read charging-point status (with bay presence) and charging sessions
            apx.charging:manage: bridge scope; push point availability, bay observations, open sessions, report timeline events, attach settlement
            apx.charging:status: customer scope; minimized read of the caller's own charging session and the place's charger availability (app, text, voice bot)
  schemas:
    RecordInfo:
      title: RecordInfo
      description: |-
        Provenance metadata for an APX resource, aligned to the APDS Information
        Model's RecordType (creationTime/creator/lastUpdate). All timestamps are
        RFC 3339 (APDS DateTime).
      type: object
      properties:
        creationTime:
          $ref: '#/components/schemas/DateTime'
        creator:
          description: Reference to the creating Organisation or Contact.
          $ref: '#/components/schemas/Reference'
        creationUser:
          type: string
          description: Human or system principal that created the record.
        lastUpdate:
          $ref: '#/components/schemas/DateTime'
        lastUpdateUser:
          type: string
          description: Human or system principal that last updated the record.
        origin:
          type: string
          description: |-
            The implementation that first created the record, when it differs
            from the one serving it (Part 18 §18.6 replication): the origin's
            `EventEnvelope.source` value. Absent on records the serving
            implementation created itself.
          examples:
            - https://edge.lakeside-garage.example/v1
    Extensions:
      title: Extensions
      description: |-
        The official APDS extension container (Use Case Document §C.2.5).
        Keys MUST follow `apds-ext:<namespace>:<class>@<major>.<minor>`.
        Implementations MUST preserve unknown extension keys on round-trip
        (tolerant reader, faithful writer). An APX decoration key, wherever
        the container appears, MUST carry a value valid against that
        decoration's schema (Part 4 §4.3); other keys are any object.
      type: object
      propertyNames:
        pattern: ^apds-ext:[a-z0-9-]+:[a-z0-9-]+@[0-9]+\.[0-9]+$
      properties:
        apds-ext:apx:devicestatus@1.0:
          $ref: '#/components/schemas/DeviceStatus'
        apds-ext:apx:ratepolicy@1.0:
          $ref: '#/components/schemas/RatePolicy'
        apds-ext:apx:lpr-read@1.0:
          $ref: '#/components/schemas/LprReadDetail'
        apds-ext:apx:lane-cameras@1.0:
          $ref: '#/components/schemas/LaneCameras'
        apds-ext:apx:reservation@1.0:
          $ref: '#/components/schemas/ReservationExtension'
        apds-ext:apx:permit@1.0:
          $ref: '#/components/schemas/PermitExtension'
        apds-ext:apx:permit@1.1:
          $ref: '#/components/schemas/PermitExtension'
        apds-ext:apx:session-detail@1.0:
          $ref: '#/components/schemas/SessionDetail'
        apds-ext:apx:match-evidence@1.0:
          $ref: '#/components/schemas/MatchEvidence'
        apds-ext:apx:stay-compliance@1.0:
          $ref: '#/components/schemas/StayCompliance'
        apds-ext:apx:violation-source@1.0:
          $ref: '#/components/schemas/ViolationSource'
        apds-ext:apx:payment-detail@1.0:
          $ref: '#/components/schemas/PaymentDetail'
        apds-ext:apx:credential-digest@1.0:
          $ref: '#/components/schemas/CredentialDigest'
        apds-ext:apx:equipment-detail@1.0:
          $ref: '#/components/schemas/EquipmentDetail'
        apds-ext:apx:camera@1.0:
          $ref: '#/components/schemas/CameraDetail'
        apds-ext:apx:external-ids@1.0:
          $ref: '#/components/schemas/ExternalIdentifiers'
        apds-ext:apx:place-operations@1.0:
          $ref: '#/components/schemas/PlaceOperations'
      additionalProperties:
        type: object
    ApxResourceCore:
      title: ApxResourceCore
      description: |-
        Identity core shared by every APX-defined resource. Shaped so any APX
        resource can itself be the target of an APDS Reference or
        VersionedReference (RFC 4122 UUID identifier + integer version).
      type: object
      required:
        - id
        - version
      properties:
        id:
          type: string
          format: uuid
          description: RFC 4122 UUID, unique within the resource class.
        version:
          type: integer
          minimum: 1
          description: Monotonically increasing object version.
        recordInfo:
          $ref: '#/components/schemas/RecordInfo'
        extensions:
          $ref: '#/components/schemas/Extensions'
    Problem:
      title: Problem
      description: |-
        RFC 9457 problem details. APX problem `type` URIs are registered in the
        APX problem-type registry. Used for all APX error responses; APDS-native
        routes may alternatively use the APDS ResponseStatus shape.
      type: object
      required:
        - type
        - title
        - status
      properties:
        type:
          type: string
          format: uri
          description: Problem type URI from the APX problem registry.
          examples:
            - https://apx-standard.org/problems/insufficient-grant
        title:
          type: string
          description: Short human-readable summary of the problem type.
        status:
          type: integer
          minimum: 100
          maximum: 599
          description: HTTP status code.
        detail:
          type: string
          description: Human-readable explanation specific to this occurrence.
        instance:
          type: string
          format: uri-reference
          description: URI reference identifying this specific occurrence.
      additionalProperties: true
      examples:
        - type: https://apx-standard.org/problems/target-not-found
          title: Target not found
          status: 404
          detail: No lane b2000000-0000-4000-8000-00000000dead at this place.
          instance: /v1/lanes/b2000000-0000-4000-8000-00000000dead/current
    EventEnvelope:
      title: EventEnvelope
      description: |-
        The single envelope for all APX asynchronous delivery (webhooks and SSE).
        Attribute names are aligned with CloudEvents 1.0 (informative mapping in
        the standard's annex); `subject` carries an APDS Reference so events bind
        to APDS/APX entities natively.
      type: object
      required:
        - id
        - type
        - source
        - time
        - data
      properties:
        id:
          type: string
          format: uuid
          description: Unique event id (delivery-stable; retries reuse it).
        type:
          type: string
          description: |-
            Event topic. Either an APX topic (`apx.<domain>.<event>.vN`) or an
            APDS EventTypeEnum value (e.g. `SessionCreated`).
          examples:
            - apx.alert.raised.v1
            - SessionCreated
        source:
          type: string
          format: uri-reference
          description: Identifies the publishing implementation/site.
        time:
          $ref: '#/components/schemas/DateTime'
        subject:
          description: The entity this event is about.
          $ref: '#/components/schemas/Reference'
        dataschema:
          type: string
          format: uri
          description: Optional URI of the schema that `data` validates against.
        data:
          description: Event payload. For APDS EventTypeEnum topics this is the APDS EventData shape.
          type: object
        extensions:
          $ref: '#/components/schemas/Extensions'
      examples:
        - id: 3b4c5d6e-7f8a-4b9c-8d0e-1f2a3b4c5d6e
          type: apx.reservation.noshow.v1
          source: https://api.lakeside-garage.example/v1
          subject:
            id: e2000000-0000-4000-8000-000000000003
            className: AssignedRight
          time: '2026-08-14T19:30:00Z'
          data:
            reservation:
              id: e2000000-0000-4000-8000-000000000003
              className: AssignedRight
            reservationState: noShow
            plannedStart: '2026-08-14T18:00:00Z'
    CodeListValue:
      title: CodeListValue
      description: |-
        A value drawn from an APX or implementer UserDefinedCodeList — carries the
        defined value plus an optional ReferencedCodeListEntry-style pointer to
        the list that defines it.
      type: object
      required:
        - value
      properties:
        value:
          type: string
          description: The definedValue from the code list entry.
          examples:
            - vendGate
        codeListId:
          description: VersionedReference to the defining UserDefinedCodeList.
          $ref: '#/components/schemas/VersionedReference'
    ChangeFeedPage:
      title: ChangeFeedPage
      description: |-
        Response of a native APDS list route when called with `mode=change`.
        Items are VERBATIM APDS entities carrying only changed fields plus
        identity (change semantics per Part 5: explicit null = clear the field,
        absent = unchanged — generalizing APDS Use Case C.1.1.6). Deletions are
        APDS DeletedReferences (tombstones).
      type: object
      required:
        - publicationTime
        - updateMode
        - items
        - cursor
      properties:
        publicationTime:
          $ref: '#/components/schemas/DateTime'
        publisher:
          description: The publishing Organisation.
          $ref: '#/components/schemas/Reference'
        updateMode:
          type: string
          const: change
        items:
          type: array
          description: |-
            Changed APDS entities of the route's class, each a change payload
            (identity plus only the changed members; Part 5 §5.1).
          items:
            $ref: '#/components/schemas/ChangePayload'
        deleted:
          type: array
          description: Tombstones for deleted entities.
          items:
            $ref: '#/components/schemas/DeletedReference'
        cursor:
          type: string
          description: Opaque cursor to resume AFTER the last change in this page.
        grantAdditions:
          type: array
          description: |-
            Present on the first page served after the credential's apx_places
            grant gained subtrees (Part 5 §5.2 rule 7): the new subtree roots.
            The client MUST full-sync these subtrees before relying on the
            feed for them — the cursor does not retroactively cover their
            history.
          items:
            type: string
            format: uuid
        next:
          type:
            - string
            - 'null'
          format: uri-reference
          description: Link to the next page when more changes are immediately available; null otherwise.
      examples:
        - publicationTime: '2026-08-06T18:20:00Z'
          publisher:
            id: a1000000-0000-4000-8000-000000000001
            className: Organisation
          updateMode: change
          items:
            - id: f1000000-0000-4000-8000-000000000001
              version: 4
              className: Session
              segments:
                - actualEnd: '2026-08-06T18:14:34Z'
          deleted:
            - id: f1000000-0000-4000-8000-000000000099
              className: Session
              deleteTimestamp: '2026-08-06T17:58:12Z'
          cursor: c:00042
    ChangeFeedUpdateMode:
      title: ChangeFeedUpdateMode
      type: string
      const: change
      description: |-
        Present, with the value `change`, exactly when the page answers
        `mode=change` (Part 5 §5.2 rule 8); absent on an ordinary list page.
    ChangeFeedCursor:
      title: ChangeFeedCursor
      type: string
      description: |-
        `mode=change` only. Opaque cursor resuming strictly after the last
        change in this page (Part 5 §5.2 rules 1, 2, 5).
    ChangeFeedTombstones:
      title: ChangeFeedTombstones
      type: array
      description: |-
        `mode=change` only. Resources removed since the cursor (retention
        purge, Part 9 §9.6; release of a moved place, Part 18 §18.4), as APDS
        DeletedReferences carrying the APX resource's schema name as
        `className`. Retained for the cursor window (Part 5 §5.2 rule 4).
      items:
        $ref: '#/components/schemas/DeletedReference'
    ChangeFeedGrantAdditions:
      title: ChangeFeedGrantAdditions
      type: array
      description: |-
        `mode=change` only. Present on the first page served after the
        credential's `apx_places` grant gained subtrees: the new subtree roots,
        which the client full-syncs with the route's `place` filter before
        relying on the feed for them (Part 5 §5.2 rule 7).
      items:
        type: string
        format: uuid
    ChangeFeedNext:
      title: ChangeFeedNext
      type:
        - string
        - 'null'
      format: uri-reference
      description: |-
        `mode=change` only. Link to the next page when more changes are
        immediately available (the same request with this page's `cursor`);
        null otherwise.
    OccupancySnapshot:
      title: OccupancySnapshot
      description: |-
        Current occupancy for one HierarchyElement, computed from the APDS
        occupancy model (Supply + DemandTable) that natively lives in the Place
        hierarchy. A convenience READ (Part 5 §5.5): the Place payload remains
        the source of truth; this answers "how full is it right now" without
        pulling the hierarchy. Composed entirely of verbatim APDS occupancy
        classes — APX adds no parallel occupancy datatypes.
      type: object
      required:
        - place
        - computedAt
      properties:
        place:
          description: The HierarchyElement (Place, Level, Area, …) this snapshot describes.
          $ref: '#/components/schemas/Reference'
        computedAt:
          description: When this snapshot was computed.
          $ref: '#/components/schemas/DateTime'
        supply:
          description: The element's supply (verbatim APDS Supply).
          $ref: '#/components/schemas/Supply'
        demand:
          description: |-
            The latest area demand record (verbatim APDS DemandType — count,
            percentage, occupancyCalculation, recordDateTime).
          $ref: '#/components/schemas/DemandType'
        available:
          type:
            - integer
            - 'null'
          minimum: 0
          description: |-
            Convenience derivation: supply.supplyQuantity − demand.count when
            both are known; null when either side is unknown. Never negative —
            overfull facilities clamp to 0 (the demand record still shows the
            true count).
          examples:
            - 59
        evCharging:
          type: object
          description: |-
            Part 23 §23.7 — charging availability under this
            element, derived from ChargingPointStatus. Optional; present only
            when the implementation claims `apx-charging`.
            Counts are of charging points (APDS ElectricChargingEquipment),
            not connectors. Absent counts are unknown, never guessed.
          properties:
            pointsTotal:
              type: integer
              minimum: 0
            available:
              type: integer
              minimum: 0
              description: 'Points with `availability: available`.'
            charging:
              type: integer
              minimum: 0
            occupiedNotCharging:
              type: integer
              minimum: 0
              description: Points `occupied` (cable connected, no energy) — includes complete and idle sessions.
            blocked:
              type: integer
              minimum: 0
              description: Points whose bay holds a vehicle that is not plugged in, or is obstructed.
            inoperative:
              type: integer
              minimum: 0
              description: Points `inoperative` or `outOfOrder`.
        extensions:
          $ref: '#/components/schemas/Extensions'
      examples:
        - place:
            id: b1000000-0000-4000-8000-000000000001
            className: Place
          computedAt: '2026-08-25T17:45:00Z'
          supply:
            supplyViewType: spaceView
            supplyQuantity: 420
          demand:
            count: 361
            percentage: 85.9
            occupancyCalculation: counted
            recordDateTime: '2026-08-25T17:44:30Z'
          available: 59
    ApxEventSubscription:
      title: ApxEventSubscription
      description: |-
        Superset of the APDS 4.1 EventSubscription. A stock APDS client sending
        only `{endpoint, topics}` (EventTypeEnum values) gets stock behavior;
        the APX fields are additive and optional.
      type: object
      required:
        - topics
      properties:
        id:
          type: string
          format: uuid
          description: Assigned at creation; used with DELETE/PATCH /webhooks/{id}.
        version:
          type: integer
          minimum: 1
        endpoint:
          description: Client endpoint URL for webhook deliveries (required for transport=webhook).
          $ref: '#/components/schemas/Url'
        topics:
          type: array
          minItems: 1
          description: |-
            APDS EventTypeEnum values (e.g. SessionCreated) and/or APX topics
            (apx.<domain>.<event>.vN) — freely mixed.
          items:
            type: string
        transport:
          type: string
          enum:
            - webhook
            - sse
          default: webhook
        filters:
          $ref: '#/components/schemas/SubscriptionFilters'
        secret:
          type: string
          description: |-
            HMAC signing secret (≥32 bytes of entropy, used as raw UTF-8 key
            material; shorter is 400 `invalid-request`). For `transport:
            webhook` only: server-generated when absent and returned EXACTLY
            ONCE — in the Prefer=representation creation response. Never
            present in GET/PATCH responses. An SSE subscription has nothing to
            sign and gets no secret (Part 8 §8.1).
        secretRef:
          type: string
          writeOnly: true
          description: |-
            Identifier of an out-of-band-exchanged secret (Part 9 §9.4) —
            supply INSTEAD of `secret` when key material must never transit
            the API. Never a secret value itself.
        keyId:
          type: string
          writeOnly: true
          description: |-
            Identifier the client chooses for the key it supplies with `secret`
            or `secretRef`; deliveries signed with that key carry it in
            `APX-Key-Id`. Server-assigned when absent (Part 8 §8.1).
        retireKeyIds:
          type: array
          writeOnly: true
          description: |-
            PATCH only: key ids to retire now, ending a rotation overlap early.
            Retiring the last active key is 400 `invalid-request`. Without it,
            the server retires the superseded key 24 hours after the rotation
            (Part 8 §8.1).
          items:
            type: string
        activeKeyIds:
          type: array
          readOnly: true
          description: |-
            Identifiers of the currently valid signing keys — two entries
            during a rotation overlap window, matching deliveries' APX-Key-Id
            header (Part 9 §9.4).
          items:
            type: string
        status:
          type: string
          enum:
            - active
            - paused
            - failed
          description: |-
            `active` delivers; `paused` holds matching events for up to 24 hours
            and delivers them in order on resume (Part 8 §8.1); `failed` is
            server-assigned when the retry schedule is exhausted (a client
            setting it is 400 `invalid-request`). PATCH `status: active` to
            resume a paused or failed subscription.
        recordInfo:
          $ref: '#/components/schemas/RecordInfo'
        extensions:
          $ref: '#/components/schemas/Extensions'
    DeliveryRecord:
      title: DeliveryRecord
      description: One entry in a subscription's delivery ledger.
      type: object
      required:
        - deliveryId
        - eventId
        - attempts
        - status
        - time
      properties:
        deliveryId:
          type: string
          format: uuid
        eventId:
          type: string
          format: uuid
          description: EventEnvelope.id delivered (stable across retries).
        attempts:
          type: integer
          minimum: 1
        status:
          type: string
          enum:
            - delivered
            - retrying
            - failed
        lastCode:
          type: integer
          description: Last HTTP status code received from the endpoint (0 = network error).
        time:
          $ref: '#/components/schemas/DateTime'
        attemptHistory:
          type: array
          description: |-
            Every attempt so far, oldest first (Part 8 §8.3). `deliveryId` and
            `lastCode` above are those of the latest entry. The normative
            schedule makes at most 27 attempts per event.
          items:
            $ref: '#/components/schemas/DeliveryAttempt'
      examples:
        - deliveryId: 4d5e6f7a-8b9c-4d0e-9f1a-2b3c4d5e6f7a
          eventId: 2a3b4c5d-6e7f-4890-9a0b-1c2d3e4f5a6b
          attempts: 1
          status: delivered
          lastCode: 200
          time: '2026-08-06T18:17:42Z'
    Alert:
      title: Alert
      description: |-
        An operational condition requiring attention. Alert types are OPEN
        (UserDefinedCodeList `apx-alert-types`, seeded from APDS Use Case C.2.2
        transaction exceptions and space statuses); severity is CLOSED.
      type: object
      required:
        - id
        - version
        - alertType
        - severity
        - status
        - detectionTime
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
          description: |-
            Server-assigned when the raise carries none. A client MAY supply its
            own UUID on raise (Part 4 §4.1, Part 7 §7.1); an id that already
            exists is 409 `id-collision`.
        version:
          type: integer
          minimum: 1
          readOnly: true
        alertType:
          type: string
          description: definedValue from apx-alert-types or an implementer code list.
          examples:
            - deviceFault
        severity:
          type: string
          enum:
            - info
            - warning
            - minor
            - major
            - critical
        status:
          type: string
          enum:
            - raised
            - acknowledged
            - resolved
            - expired
          readOnly: true
          description: 'Lifecycle: raised → acknowledged → resolved | expired.'
        source:
          type: object
          description: Where the condition was detected.
          properties:
            device:
              description: Reference to a SupplementalEquipment.
              $ref: '#/components/schemas/Reference'
            place:
              type: string
              format: uuid
              description: HierarchyElement UUID (subtree semantics for filtering).
        relatedEntity:
          description: The APDS/APX entity this alert concerns (Session, AssignedRight, Command…).
          $ref: '#/components/schemas/Reference'
        supportInteraction:
          description: The Part 17 SupportInteraction the alert was raised from, when a call produced it (a receipt request, a refund request, a damage report; Part 7 §7.6).
          $ref: '#/components/schemas/Reference'
        occurrenceTime:
          description: When the condition actually occurred (may precede detection).
          $ref: '#/components/schemas/DateTime'
        detectionTime:
          $ref: '#/components/schemas/DateTime'
        expiryTime:
          description: |-
            The end of the alert's validity window (Part 7 §7.3). Settable on
            raise; when absent the server MAY default it by policy per
            `alertType`, and returns the value it applies. If the alert is still
            `raised` or `acknowledged` at this instant the server transitions it
            to `expired` and publishes `apx.alert.status.v1`. Absent means the
            alert never expires on its own.
          $ref: '#/components/schemas/DateTime'
        description:
          description: Human-readable detail.
          $ref: '#/components/schemas/MultilingualString'
        statusHistory:
          type: array
          description: Immutable, append-only lifecycle audit (Part 4 §4.2).
          items:
            type: object
            required:
              - state
              - time
              - actor
            properties:
              state:
                type: string
              time:
                $ref: '#/components/schemas/DateTime'
              actor:
                type: string
                description: Client/agent principal that caused the transition.
              detail:
                type: string
        recordInfo:
          $ref: '#/components/schemas/RecordInfo'
        extensions:
          $ref: '#/components/schemas/Extensions'
      examples:
        - id: 7b8c9d0e-1f2a-4b3c-8d4e-5f6a7b8c9d0e
          version: 2
          alertType: deviceFault
          severity: major
          status: acknowledged
          source:
            device:
              id: c1000000-0000-4000-8000-000000000003
              className: SupplementalEquipment
            place: b1000000-0000-4000-8000-000000000001
          occurrenceTime: '2026-08-06T18:17:40Z'
          detectionTime: '2026-08-06T18:17:41Z'
          description:
            - language: en
              string: Pay station 3 not responding
          statusHistory:
            - state: raised
              time: '2026-08-06T18:17:41Z'
              actor: lakeside-parcs
            - state: acknowledged
              time: '2026-08-06T18:19:05Z'
              actor: apx-operator
              detail: field tech dispatched
    Command:
      title: Command
      description: |-
        A request for an operational action against a lane/device/place.
        Perishable (expiryTime), idempotent (Idempotency-Key), fully audited
        (immutable statusHistory).
      type: object
      required:
        - id
        - version
        - commandType
        - target
        - status
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
        version:
          type: integer
          minimum: 1
          readOnly: true
        commandType:
          type: string
          description: definedValue from apx-command-types (vendGate, lostTicket, pushRate, applyValidation, pushNegotiatedRate, matchTicket, …).
          examples:
            - vendGate
        target:
          description: |-
            Reference to the target — SupplementalEquipment (device) or a
            VehicularAccess/Place HierarchyElement (lane/place scope).
          $ref: '#/components/schemas/Reference'
        parameters:
          type: object
          description: |-
            Command-type-specific parameters. Normative parameter schemas per
            commandType are given in Part 6 (e.g. lostTicket.method,
            pushRate.rateTable VersionedReference, applyValidation.ticket +
            provider, displayMessage.message, setDeviceState.state,
            pushNegotiatedRate.rateTable VersionedReference to a RateTable
            flagged negotiable, or pushNegotiatedRate.amount AmountInCurrency
            (any amount the agent states, where the host offers the
            negotiatedAmounts feature), matchTicket.session + evidence,
            resetPassback/forceIn/forceOut.credential, courtesyExit.holder).
        requestedBy:
          description: The organisation requesting the action (defaults to the token's apx_org).
          $ref: '#/components/schemas/Reference'
        agent:
          type: string
          description: |-
            Opaque principal of the human or AI agent who initiated the command
            (mirrors SupportInteraction.agent, Part 17 §17.6). Distinct from
            requestedBy (the organisation) and from approval.approvedBy (the
            approver). REQUIRED for pushNegotiatedRate and matchTicket (Part 6
            §6.6–6.7): who selected the rate, who made the match.
          examples:
            - agent:j.okafor
        agentType:
          type: string
          enum:
            - human
            - ai
          description: Whether `agent` is a person or an AI agent (mirrors SupportInteraction.agentType).
        reason:
          type: string
          description: Free-text or code-list reason for the action (audit).
        resolutionContext:
          description: The ResolutionContext this command resolves (Part 17) — links the action into the interaction's audit chain.
          $ref: '#/components/schemas/Reference'
        resolutionContextVersion:
          type: integer
          minimum: 1
          readOnly: true
          description: |-
            The `version` of the ResolutionContext whose allowed actions this
            write was checked against, recorded by the server so the decision stays
            reconstructible after the context is recomputed or expires (Part 17 §17.2).
        correlationId:
          type: string
          format: uuid
          description: Correlation chain id (Part 17 §17.7) — one id connects call → context → command → events → support interaction.
        approval:
          $ref: '#/components/schemas/Approval'
        expiryTime:
          description: Commands are perishable — MUST NOT be dispatched after this instant.
          $ref: '#/components/schemas/DateTime'
        priority:
          type: string
          enum:
            - normal
            - high
          default: normal
        status:
          type: string
          enum:
            - received
            - accepted
            - rejected
            - dispatched
            - executing
            - succeeded
            - failed
            - expired
            - cancelled
          readOnly: true
        confirmationLevel:
          type: string
          enum:
            - accepted
            - deviceAcknowledged
            - physicallyConfirmed
          readOnly: true
          description: |-
            How far success is actually confirmed (Part 6 §6.1): the command was
            accepted; the device acknowledged it; or the physical outcome was
            verified (e.g. gate-state sensor). Consumers — AI agents especially —
            MUST NOT claim a physical outcome ("the gate is open") beyond this
            level ("the open command was accepted").
        statusHistory:
          type: array
          description: Immutable, append-only lifecycle audit — THE audit trail (Part 4 §4.2).
          items:
            type: object
            required:
              - state
              - time
              - actor
            properties:
              state:
                type: string
              time:
                $ref: '#/components/schemas/DateTime'
              actor:
                type: string
              detail:
                type: string
        result:
          $ref: '#/components/schemas/CommandResult'
        recordInfo:
          $ref: '#/components/schemas/RecordInfo'
        extensions:
          $ref: '#/components/schemas/Extensions'
      examples:
        - id: 5e8d7c6b-4a39-4281-b0f1-2e3d4c5b6a70
          version: 5
          commandType: vendGate
          target:
            id: b2000000-0000-4000-8000-000000000002
            className: VehicularAccess
          requestedBy:
            id: a1000000-0000-4000-8000-000000000001
            className: Organisation
          reason: customer assistance — cinema validation applied, remainder waived per policy
          expiryTime: '2026-08-06T18:16:00Z'
          status: succeeded
          statusHistory:
            - state: received
              time: '2026-08-06T18:14:31Z'
              actor: apx-operator
            - state: accepted
              time: '2026-08-06T18:14:31Z'
              actor: lakeside-parcs
            - state: dispatched
              time: '2026-08-06T18:14:32Z'
              actor: lakeside-parcs
            - state: executing
              time: '2026-08-06T18:14:32Z'
              actor: gate-c1000000-0002
            - state: succeeded
              time: '2026-08-06T18:14:34Z'
              actor: gate-c1000000-0002
              detail: barrier raised
    Approval:
      title: Approval
      description: |-
        Approval evidence, REQUIRED on a write whose AllowedAction said
        requiresApproval (Part 17 §17.3). Servers MUST reject a
        requires-approval action without it (403 approval-required). One shared
        shape for control commands and domain actions (e.g. refunds).
      type: object
      required:
        - approvedBy
      properties:
        approvedBy:
          type: string
          description: The approving principal (role per AllowedAction.approvalRole).
        approvedAt:
          $ref: '#/components/schemas/DateTime'
        note:
          type: string
        approvalRequest:
          description: The Part 17 §17.3a ApprovalRequest whose decision this evidence cites, when the approval was asked for through APX.
          $ref: '#/components/schemas/Reference'
    DeviceStatus:
      title: DeviceStatus
      description: |-
        Live state overlay keyed by Reference to an APDS SupplementalEquipment —
        never duplicates its descriptive fields. APDS 4.1 has no general
        equipment status list: its RefillPointStatusEnum (Data Dictionary
        A.3.53) covers refill points only and is absent from apds-api-4.1.yaml.
        deviceState values come from the APX registry apx-device-states, which
        follows that enumeration's style and shares its available, occupied,
        inoperative and unknown values. Attachable to
        APDS payloads as apds-ext:apx:devicestatus@1.0.
      type: object
      required:
        - device
        - deviceState
      properties:
        device:
          $ref: '#/components/schemas/Reference'
        deviceState:
          type: string
          description: definedValue from apx-device-states.
          examples:
            - available
        lastCommunication:
          description: When the device last reported; an agent reads "offline since" from it (Part 6 §6.4).
          $ref: '#/components/schemas/DateTime'
        stateChangedTime:
          $ref: '#/components/schemas/DateTime'
        fault:
          type: object
          description: The current fault, when `deviceState` is `fault` or `inoperative` and the device reports one (Part 6 §6.4).
          required:
            - code
          properties:
            code:
              type: string
              description: The implementation's fault code, as the device reports it.
              examples:
                - E42
            displayText:
              type: string
              description: What the device shows or what the technician reads for the code.
              examples:
                - Ticket transport jammed
            since:
              $ref: '#/components/schemas/DateTime'
        consumables:
          type: array
          description: Supply levels the device reports (Part 6 §6.4). `low` or `empty` raises the Part 7 `consumableLow` alert.
          items:
            type: object
            required:
              - kind
              - level
            properties:
              kind:
                type: string
                enum:
                  - tickets
                  - receiptPaper
                  - cash
                  - coins
              level:
                type: string
                enum:
                  - ok
                  - low
                  - empty
                  - unknown
        maintenanceMode:
          type: boolean
          description: The device is under test or maintenance; calls and events from it are excluded from service figures (Part 6 §6.4).
        extensions:
          $ref: '#/components/schemas/Extensions'
      examples:
        - device:
            id: c1000000-0000-4000-8000-000000000003
            className: SupplementalEquipment
          deviceState: fault
          lastCommunication: '2026-08-06T18:16:55Z'
          stateChangedTime: '2026-08-06T18:17:40Z'
    LaneStatus:
      title: LaneStatus
      description: |-
        The transaction context at a lane right now (the call-center
        screen-pop). Composes APDS references and data; adds no
        parallel entities.
      type: object
      required:
        - lane
      properties:
        lane:
          $ref: '#/components/schemas/Reference'
        currentTicket:
          type: object
          description: The ticket/credential currently in the machine, if any.
          properties:
            ticketNumber:
              type: string
            session:
              $ref: '#/components/schemas/Reference'
            issuedTime:
              $ref: '#/components/schemas/DateTime'
            amountDue:
              $ref: '#/components/schemas/AmountInCurrency'
            paidInFull:
              type: boolean
            validations:
              type: array
              items:
                type: object
                properties:
                  provider:
                    $ref: '#/components/schemas/Reference'
                  providerName:
                    type: string
                    description: Human-readable vendor name (from the place's ValidationProvider list).
                  validationType:
                    type: string
                    description: The provider's validation type at time of application.
                  validationId:
                    type: string
                    description: Unique id of this applied validation — maps to APDS Segment.validationId.
                  amountReduced:
                    description: The ACTUAL value this validation removed from the amount due (dispute evidence).
                    $ref: '#/components/schemas/AmountInCurrency'
                  appliedTime:
                    $ref: '#/components/schemas/DateTime'
            lpr:
              type: object
              description: Latest plate read at this lane (APDS Observation-derived).
              properties:
                plate:
                  type: string
                confidence:
                  type: number
                observation:
                  $ref: '#/components/schemas/Reference'
                imageLink:
                  $ref: '#/components/schemas/Url'
            negotiatedRate:
              type: object
              description: |-
                The negotiated rate in effect on this ticket, if a
                pushNegotiatedRate command that selected a RateTable succeeded
                for it (Part 6 §6.6). Absent when the ticket prices from the
                lane's normal rate deck, and absent when the agent stated an
                amount instead (see `negotiatedAmount`). At most one of
                `negotiatedRate` and `negotiatedAmount` is present: the latest
                succeeded pushNegotiatedRate for the ticket decides which.
              required:
                - rateTable
                - command
              properties:
                rateTable:
                  description: The RateTable selected (VersionedReference — the exact version applied).
                  $ref: '#/components/schemas/VersionedReference'
                command:
                  description: The pushNegotiatedRate Command that applied it — carries `agent`, `reason`, and the audit trail.
                  $ref: '#/components/schemas/Reference'
                agent:
                  type: string
                  description: The principal who selected the rate (copied from the command for the screen-pop).
                policy:
                  description: The table's `apds-ext:apx:ratepolicy@1.0` decoration as it stood when applied (its displayName is what the agent saw).
                  $ref: '#/components/schemas/RatePolicy'
            negotiatedAmount:
              type: object
              description: |-
                The amount an agent stated for this ticket, if a
                pushNegotiatedRate command carrying `parameters.amount` succeeded
                for it (the negotiatedAmounts feature, Part 6 §6.3, §6.6). Absent
                otherwise. It is what the ticket owes, not a discount. At most one
                of `negotiatedRate` and `negotiatedAmount` is present: the latest
                succeeded pushNegotiatedRate for the ticket decides which.
              required:
                - amount
                - reason
                - agent
                - command
              properties:
                amount:
                  description: The amount stated, as the command's `parameters.amount`.
                  $ref: '#/components/schemas/AmountInCurrency'
                reason:
                  type: string
                  minLength: 1
                  description: The command's `reason`, copied for the screen-pop.
                agent:
                  type: string
                  minLength: 1
                  description: The principal who stated the amount (the command's `agent`), copied for the screen-pop.
                command:
                  description: The pushNegotiatedRate Command that applied it — the audit trail.
                  $ref: '#/components/schemas/Reference'
            matchedCommand:
              description: |-
                When this ticket was bound to an open session by a matchTicket
                command (Part 6 §6.7), the Command that made the match — carries
                `agent`, `parameters.evidence`, and the audit trail. Absent for a
                ticket physically inserted at the lane.
              $ref: '#/components/schemas/Reference'
        matchCandidates:
          type: array
          description: |-
            Open sessions at this lane's place that plausibly belong to the
            vehicle in the lane, best first (Part 6 §6.7). Computed when the lane
            has no ticket in the machine, or whenever the caller passes a
            `plate`, `phone`, or `credential` lookup parameter. ADVISORY: the
            agent confirms with the driver; the server never binds a candidate
            without a matchTicket command.
          items:
            $ref: '#/components/schemas/MatchCandidate'
        monthlyCredential:
          type: object
          description: Monthly-parker credential context at the lane, if presented.
          properties:
            credential:
              $ref: '#/components/schemas/Reference'
            cardNumber:
              type: string
            accessGranted:
              type: boolean
            denialReason:
              type: string
              description: When access is denied — definedValue from `apx-access-denial-reasons` or an implementer code list (Part 11), the same vocabulary as Part 21 access events.
              examples:
                - accountBalance
            lastActivity:
              $ref: '#/components/schemas/DateTime'
            recentEvents:
              type: array
              maxItems: 10
              description: The last 10 activity events on this credential (trend view).
              items:
                type: object
                properties:
                  time:
                    $ref: '#/components/schemas/DateTime'
                  event:
                    type: string
                  lane:
                    $ref: '#/components/schemas/Reference'
      examples:
        - lane:
            id: b2000000-0000-4000-8000-000000000002
            className: VehicularAccess
          currentTicket:
            ticketNumber: T-1001
            session:
              id: f1000000-0000-4000-8000-000000000001
              className: Session
            issuedTime: '2026-08-06T08:02:11Z'
            amountDue:
              currencyType: USD
              currencyValue: 9
            paidInFull: false
            validations: []
            lpr:
              plate: SYN-1234
              confidence: 0.97
              observation:
                id: f2000000-0000-4000-8000-000000000001
                className: Observation
              imageLink: https://api.lakeside-garage.example/lpr/f2000000.jpg
          monthlyCredential:
            credential:
              id: e3000000-0000-4000-8000-000000000001
              className: Credential
            cardNumber: MC-0777
            accessGranted: false
            denialReason: account past due
            lastActivity: '2026-08-05T18:22:00Z'
            recentEvents:
              - time: '2026-08-05T18:22:00Z'
                event: exit
                lane:
                  id: b2000000-0000-4000-8000-000000000002
                  className: VehicularAccess
              - time: '2026-08-05T08:04:31Z'
                event: entry
                lane:
                  id: b2000000-0000-4000-8000-000000000001
                  className: VehicularAccess
    ValidationProvider:
      title: ValidationProvider
      description: A venue/organisation allowed to validate tickets at a place.
      type: object
      required:
        - provider
      properties:
        provider:
          $ref: '#/components/schemas/Reference'
        name:
          type: string
        program:
          description: |-
            The ValidationProgram this row is derived from, when the server
            claims `apx-validations` (Part 20) — additive; absent otherwise.
          $ref: '#/components/schemas/Reference'
        validationType:
          type: string
          description: e.g. flat discount, hours comped — implementer code list.
        benefit:
          type: object
          description: |-
            What the validation is WORTH — disclosed in the lookup so agents can
            answer disputes. Exactly one of amount (money off), duration
            (comped time, priced at the applicable rate), or percentage
            (proportionate discount) applies.
          required:
            - description
          properties:
            description:
              type: string
              description: Human-readable statement of the benefit.
              examples:
                - $3.00 off
                - First two hours comped
            amount:
              description: Fixed money off.
              $ref: '#/components/schemas/AmountInCurrency'
            duration:
              description: Comped parking time (ISO 8601), valued at the applicable rate.
              $ref: '#/components/schemas/Duration'
            percentage:
              type: number
              minimum: 0
              maximum: 100
              description: Proportionate discount on the amount due, mirrored from a percentage ValidationProgram (Part 20 §20.1).
      examples:
        - provider:
            id: a2000000-0000-4000-8000-000000000011
            className: Organisation
          name: Lakeside Cinema
          validationType: twoHoursComped
          benefit:
            description: First two hours comped
            duration: PT2H
    RatePolicy:
      title: RatePolicy
      description: |-
        Level B decoration on an APDS RateTable, carried in its `extensions`
        container as `apds-ext:apx:ratepolicy@1.0` (Part 6 §6.6). APDS models
        the rate deck completely; it has no way to say which tables an agent
        may offer as a negotiated rate. This is that flag — and because it
        rides inside the RateTable, every consumer mirroring the deck through
        the native `/rates` route (Part 5 §5.2) receives it with the table, no
        second query. APX deliberately defines NO selection rules here (length
        of stay, time of day, caller type): the system presenting the deck to
        an agent or a third party applies its own guardrails. The server's only
        rule is enforcement — a pushNegotiatedRate naming a table that is not
        flagged negotiable is refused (422 rate-not-negotiable).
      type: object
      required:
        - negotiable
      properties:
        negotiable:
          type: boolean
          description: Whether this RateTable MAY be selected by a pushNegotiatedRate command.
        displayName:
          type: string
          description: Short agent-facing label for the table when offered as a negotiated rate (e.g. "Customer-service flat $20").
        note:
          type: string
          description: Free-text guidance for the presenting system or agent. Informative — never evaluated by the server.
      examples:
        - negotiable: true
          displayName: Customer-service flat $20
          note: Offer for rate complaints referred by on-site tenants. Log the tenant in reason.
    MatchCandidate:
      title: MatchCandidate
      description: |-
        An open session at the place that plausibly belongs to the vehicle in
        the lane (Part 6 §6.7). Produced by the lane inquiry from the lane's
        own LPR read, a presented credential, the account registry (by plate
        or phone), or a checked-in reservation. Composes APDS references; adds
        no parallel session store. Advisory until a matchTicket command binds
        one.
      type: object
      required:
        - session
        - matchedBy
        - confidence
      properties:
        session:
          description: The open APDS Session this candidate proposes.
          $ref: '#/components/schemas/Reference'
        ticketNumber:
          type: string
          description: The entry ticket number, if a ticket was issued at entry.
        entryTime:
          $ref: '#/components/schemas/DateTime'
        entryLane:
          description: The VehicularAccess the session entered through.
          $ref: '#/components/schemas/Reference'
        plate:
          type: string
          description: The plate recorded on the session at entry, if any.
        matchedBy:
          type: string
          enum:
            - plateRead
            - credential
            - account
            - reservation
          description: |-
            How this candidate was found: the lane's LPR read against the entry
            read (plateRead); a credential presented at the lane (credential);
            the account registry by plate or phone (account); a checked-in
            reservation carrying the plate (reservation).
        evidence:
          description: |-
            The record that produced the match — the entry Observation, the
            Credential, the RightHolder account, or the AssignedRight — so the
            agent can show it and the matchTicket command can cite it.
          $ref: '#/components/schemas/Reference'
        confidence:
          type: number
          minimum: 0
          maximum: 1
          description: Server's confidence that this is the vehicle in the lane (a plate-read match projects APDS Confidence.overallConfidence).
        amountDueIfMatched:
          description: What the exit would price at from this session's true entry time — so the agent can tell the driver before matching.
          $ref: '#/components/schemas/AmountInCurrency'
        imageLink:
          description: The entry image, for visual confirmation (access-controlled per Part 9 §9.6).
          $ref: '#/components/schemas/Url'
      examples:
        - session:
            id: c4000000-0000-4000-8000-000000000051
            className: Session
          ticketNumber: T-4502
          entryTime: '2026-09-24T08:02:17Z'
          entryLane:
            id: b2000000-0000-4000-8000-000000000001
            className: VehicularAccess
          plate: KLM4410
          matchedBy: plateRead
          evidence:
            id: f2000000-0000-4000-8000-000000000911
            className: Observation
          confidence: 0.94
          amountDueIfMatched:
            currencyType: USD
            currencyValue: 14
          imageLink: https://api.lakeside-garage.example/lpr/f2000000-0911.jpg
    Account:
      title: Account
      description: A billable parking account (monthly parker, fleet…), anchored on an APDS RightHolder.
      type: object
      required:
        - id
        - version
        - accountStatus
      properties:
        id:
          type: string
          format: uuid
        version:
          type: integer
          minimum: 1
        holder:
          description: Reference to the APDS RightHolder.
          $ref: '#/components/schemas/Reference'
        name:
          type: string
        phone:
          type: string
        email:
          type: string
          description: |-
            Contact e-mail on file. Personal data under the same Part 9 §9.6
            minimization rule as `phone`: returned only under
            `apx.accounts:read` (Part 13 §13.1).
        cardNumber:
          type: string
          description: Access credential number (NOT a payment card PAN).
        plates:
          type: array
          items:
            type: string
        credentials:
          type: array
          description: |-
            The account's CredentialRecords (Part 21), when the server claims
            `apx-credentials` — additive; `cardNumber` and `plates` remain
            the APDS-only summary.
          items:
            $ref: '#/components/schemas/Reference'
        balance:
          description: Current balance due.
          $ref: '#/components/schemas/AmountInCurrency'
        accountStatus:
          type: string
          enum:
            - enabled
            - disabled
        places:
          type: array
          description: |-
            HierarchyElement subtree roots this account is valid at. On
            aggregating implementations (one endpoint fronting many locations)
            this is how consumers attribute the account to its site(s); results
            of place-less account lookups MUST stay within the caller's
            `apx_places` grant (Part 13 §13.5).
          items:
            $ref: '#/components/schemas/Reference'
        recordInfo:
          $ref: '#/components/schemas/RecordInfo'
        extensions:
          $ref: '#/components/schemas/Extensions'
    PaymentRecord:
      title: PaymentRecord
      description: A payment taken through APX (maps to the APDS Payment concept; card capture stays in the implementer's PCI scope).
      type: object
      required:
        - id
        - transactionID
        - dateCollected
        - amount
        - paymentStatus
        - place
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
        transactionID:
          type: string
          readOnly: true
        place:
          description: |-
            The HierarchyElement (site) this payment is bound to. REQUIRED so
            every payment — in API responses and in
            `apx.accounts.payment.recorded.v1` events — is attributable to its
            location on implementations fronting many places (Part 13 §13.5).
          $ref: '#/components/schemas/Reference'
        dateCollected:
          $ref: '#/components/schemas/DateTime'
          readOnly: true
        amount:
          $ref: '#/components/schemas/AmountInCurrency'
        meansOfPayment:
          description: |-
            How the customer paid, in APDS's own vocabulary (`MeansOfPaymentEnum`,
            which APDS uses for the means a place accepts). A card whose credit or
            debit type the payment layer does not report is `unknown`.
          $ref: '#/components/schemas/MeansOfPaymentEnum'
        channel:
          type: string
          description: |-
            Where the payment was captured. `lane` = a lane device; `payStation` =
            a pay-on-foot or pay station; `agent` = a person on the implementer's
            own PCI-scoped terminal; `autoAttendant` = a PCI-compliant IVR that
            captures the card out of band; `online` = web or mobile app. APX
            never carries PANs, whichever channel is used.
          enum:
            - lane
            - payStation
            - agent
            - autoAttendant
            - online
            - other
        paymentStatus:
          type: string
          description: |-
            The payment layer's answer. `approved` = approved (for a hold, see
            `captureStatus`); `declined` = refused by the payment layer;
            `reversed` = a hold voided, or a payment refunded in full.
            Transitions per Part 13 §13.1a.
          enum:
            - approved
            - declined
            - reversed
          readOnly: true
        captureStatus:
          type: string
          readOnly: true
          description: |-
            Whether an approved payment's funds have been collected (Part 13
            §13.1a). `authorized` = a hold: the payment layer approved an
            authorization-only request (`captureLater: true`), funds are held,
            nothing is collected yet; settled by
            `POST /v1/payments/{id}/capture` or released by `…/void`.
            `captured` = collected. Absent = `captured` (a sale). A hold is
            returned to the caller that created it, but is not listed by
            `GET /v1/payments` unless asked for, is not published on
            `apx.accounts.payment.recorded.v1`, and is not materialized as an
            APDS Payment until captured.
          enum:
            - authorized
            - captured
        captureLater:
          type: boolean
          default: false
          description: |-
            Create-time intent: `true` asks for authorization only (the record
            is created `paymentStatus: approved`, `captureStatus: authorized`
            and is settled later by `POST /v1/payments/{id}/capture` or
            released by `…/void`). Absent or `false` = sale (authorize and
            capture at once). A server that does not model an authorization
            lifecycle refuses `true` with 422 `request-unprocessable` (Part 13
            §13.1a).
        refundedAmount:
          description: |-
            Cumulative amount refunded so far (Part 13 §13.1a). Absent or zero
            = nothing refunded. When it reaches `amount` the record is
            `reversed`; a partial refund leaves it `approved` with this member
            showing what was given back.
          readOnly: true
          $ref: '#/components/schemas/AmountInCurrency'
        account:
          $ref: '#/components/schemas/Reference'
        ticketNumber:
          type: string
        cardLast4:
          type: string
          pattern: ^[0-9]{2,4}$
          description: |-
            Truncated payment-card digits (PCI-permitted). For transient parkers
            with no LPR and no readable ticket, this is often the ONLY key a
            caller can provide — the lookup of last resort.
        postings:
          type: array
          description: Accounting write-backs (PARIS-style) applied for this payment.
          items:
            $ref: '#/components/schemas/Posting'
        extensions:
          $ref: '#/components/schemas/Extensions'
      examples:
        - id: 9c0d1e2f-3a4b-4c5d-8e6f-7a8b9c0d1e2f
          transactionID: PARIS-20260806-00347
          place:
            id: b1000000-0000-4000-8000-000000000001
            className: Place
          dateCollected: '2026-08-06T18:26:40Z'
          amount:
            currencyType: USD
            currencyValue: 4.5
          meansOfPayment: paymentCreditCard
          paymentStatus: approved
          ticketNumber: T-1001
          cardLast4: '0777'
          postings:
            - confirmationNumber: CONF-88214
              accountUpdated: false
              postedTo: PARIS
              time: '2026-08-06T18:26:41Z'
    Posting:
      title: Posting
      description: An accounting write-back of a payment to a monthly-parking/AR system.
      type: object
      required:
        - confirmationNumber
        - accountUpdated
      properties:
        confirmationNumber:
          type: string
        accountUpdated:
          type: boolean
        newBalance:
          $ref: '#/components/schemas/AmountInCurrency'
        postedTo:
          type: string
          description: Target accounting system identifier (e.g. "paris").
        time:
          $ref: '#/components/schemas/DateTime'
      examples:
        - confirmationNumber: CONF-88214
          accountUpdated: false
          postedTo: PARIS
          time: '2026-08-06T18:26:41Z'
    PaymentLink:
      title: PaymentLink
      description: |-
        A hosted payment link sent to a customer (Part 13 §13.1a) — the
        customer-service payment action of first resort. APX carries the link's
        lifecycle, never card data; the hosted page is the implementer's PCI
        scope.
      type: object
      required:
        - id
        - version
        - place
        - channel
        - status
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
        version:
          type: integer
          minimum: 1
          readOnly: true
        place:
          description: Site binding (Part 13 §13.5).
          $ref: '#/components/schemas/Reference'
        account:
          description: The account the payment settles (or omit and use ticketNumber).
          $ref: '#/components/schemas/Reference'
        ticketNumber:
          type: string
        session:
          $ref: '#/components/schemas/Reference'
        amount:
          description: Requested amount; omit to charge the current amount due.
          $ref: '#/components/schemas/AmountInCurrency'
        channel:
          type: string
          description: Delivery channel (sms | email | other implementer code list).
          examples:
            - sms
        sentTo:
          type: string
          description: Masked destination (e.g. "+1•••••••4567"). PII-minimized.
        status:
          type: string
          enum:
            - sent
            - opened
            - paid
            - expired
            - cancelled
          readOnly: true
        payment:
          description: The resulting PaymentRecord once paid.
          $ref: '#/components/schemas/Reference'
        expiresAt:
          $ref: '#/components/schemas/DateTime'
        correlationId:
          type: string
          format: uuid
        resolutionContext:
          $ref: '#/components/schemas/Reference'
        resolutionContextVersion:
          type: integer
          minimum: 1
          readOnly: true
          description: |-
            The `version` of the ResolutionContext whose allowed actions this
            write was checked against, recorded by the server so the decision stays
            reconstructible after the context is recomputed or expires (Part 17 §17.2).
        approval:
          description: Approval evidence, when the context's AllowedAction for the link said requiresApproval (Part 17 §17.3).
          $ref: '#/components/schemas/Approval'
        recordInfo:
          $ref: '#/components/schemas/RecordInfo'
        extensions:
          $ref: '#/components/schemas/Extensions'
      examples:
        - id: e6000000-0000-4000-8000-000000000002
          version: 1
          place:
            id: b1000000-0000-4000-8000-000000000001
            className: Place
          account:
            id: c2000000-0000-4000-8000-000000000004
            className: Account
          amount:
            currencyType: USD
            currencyValue: 185
          channel: sms
          sentTo: +1•••••••4567
          status: sent
          expiresAt: '2026-09-02T22:15:41Z'
          resolutionContext:
            id: e5000000-0000-4000-8000-000000000001
            className: ResolutionContext
          correlationId: 7c9e6679-7425-40de-944b-e07fc1f90ae7
    PostingRequest:
      title: PostingRequest
      description: Request body for the accounting write-back of a payment.
      type: object
      properties:
        postedTo:
          type: string
          description: Target accounting system identifier; server default applies when omitted.
          examples:
            - paris
        account:
          description: Account to post against when the payment isn't already account-bound.
          $ref: '#/components/schemas/Reference'
        note:
          type: string
    LprRead:
      title: LprRead
      description: One plate read joined with its ticket/session context.
      type: object
      required:
        - plate
        - place
      properties:
        plate:
          type: string
        place:
          description: |-
            The HierarchyElement (site) where the read occurred. REQUIRED so
            cross-lookups and `apx.data.observation.created.v1` consumers can
            always attribute the read to its location (Part 13 §13.5).
          $ref: '#/components/schemas/Reference'
        confidence:
          type: number
          minimum: 0
          maximum: 1
          description: Overall read accuracy (APDS 4.1 Confidence.overallConfidence). Per-attribute confidences are in `detail`.
        detail:
          $ref: '#/components/schemas/LprReadDetail'
        laneTravel:
          type: string
          enum:
            - withLane
            - againstLane
            - unknown
          readOnly: true
          deprecated: true
          description: |-
            DEPRECATED since 0.12.0, removed at 1.0. APX no longer derives
            direction; use `detail.accessEvent` (entry | exit), which the LPR
            system reports (Part 13 §13.3a(4)). Servers SHOULD return `unknown`.
        observation:
          description: The underlying APDS Observation.
          $ref: '#/components/schemas/Reference'
        observationDateTime:
          $ref: '#/components/schemas/DateTime'
        ticketNumber:
          type: string
        session:
          $ref: '#/components/schemas/Reference'
        imageLink:
          description: |-
            Screenshot/still of the read (APDS Image). Absent when no image was
            taken or the imagery has been purged (see `purgedImagery`). The
            preferred still; every unpurged image is in `images[]`.
          $ref: '#/components/schemas/Url'
        images:
          type: array
          description: |-
            Every unpurged image of the read (Part 13 §13.3c), by kind:
            the APDS `ImageTypeEnum` values plus `plateExtended` (a wider crop
            around the plate) and `context` (the scene around the vehicle,
            wider than the overview), carried as `imageType` strings until
            APDS adds them. Same access and purge rules as `imageLink`.
          items:
            type: object
            required:
              - id
            properties:
              id:
                type: string
                description: The APDS Image id.
              imageType:
                type: string
                description: '`overview`, `plate` (APDS ImageTypeEnum), `plateExtended`, `context`, or an implementer kind.'
                examples:
                  - plateExtended
              imageLink:
                $ref: '#/components/schemas/Url'
              cameraId:
                type: string
        lane:
          description: |-
            The VehicularAccess (lane) the read was taken at, when the
            Observation's `elementIds` reference one. Whether the read was an
            entry or an exit is `detail.accessEvent` (Part 13 §13.3a(4)); the
            lane used does not decide it.
          $ref: '#/components/schemas/Reference'
        cameraId:
          type: string
          description: The capturing camera (APDS Image.cameraID), opaque.
        purgedImagery:
          type: boolean
          readOnly: true
          description: |-
            True when imagery for this read existed and was purged under the
            published retention schedule (Part 13 §13.3b), so a consumer can
            tell "picture purged" from "no picture taken". Absent or false
            otherwise.
        recentReservations:
          type: array
          maxItems: 10
          description: |-
            The same customer's last 10 reservations (newest first) — customer
            resolved from the plate via the account registry or the
            reservation's own vehicle credentials.
          items:
            $ref: '#/components/schemas/ReservationSummary'
        extensions:
          description: |-
            The underlying Observation's `extensions`, projected minus the
            `apds-ext:apx:lpr-read@1.0` block (which is `detail`), so vendor
            keys preserved on ingest are visible here (Part 13 §13.3a,
            Part 4 §4.3).
          $ref: '#/components/schemas/Extensions'
      examples:
        - plate: RVR-8821
          place:
            id: b1000000-0000-4000-8000-000000000006
            className: Place
          confidence: 0.91
          detail:
            plate:
              value: RVR-8821
              confidence: 0.91
            stateProvince:
              value: IL
              confidence: 0.88
            make:
              value: Ford
              confidence: 0.94
            model:
              value: F-150
              confidence: 0.71
            color:
              value: grey
              confidence: 0.83
            bodyType:
              value: pickup
              confidence: 0.96
            frameReads: 4
            platesRead: 2
            plateFace: front
            plateBox:
              top: 0.52
              left: 0.29
              bottom: 0.59
              right: 0.36
            movement: toward
            accessEvent: entry
            captureGroup: riverside/20261214T074108/0417
            engine: vendor-x/7.2
          observation:
            id: f2000000-0000-4000-8000-000000000741
            className: Observation
          observationDateTime: '2026-12-14T07:41:08Z'
          session:
            id: f1000000-0000-4000-8000-000000000741
            className: Session
          lane:
            id: b2000000-0000-4000-8000-000000000061
            className: VehicularAccess
          cameraId: riverside/cam-exit-1
          imageLink: https://api.riverside-lot.example/lpr/f2000000-741-plate.jpg
          recentReservations: []
    AttributeRead:
      title: AttributeRead
      description: One recognized attribute with its own confidence (0–1, APDS Confidence scale).
      type: object
      required:
        - value
      properties:
        value:
          type: string
        confidence:
          type: number
          minimum: 0
          maximum: 1
    LprReadDetail:
      title: LprReadDetail
      description: |-
        What a modern LPR camera knows beyond the plate string and one overall
        score (Part 13 §13.3a). Carried on the ingested APDS Observation as the
        Level B decoration `apds-ext:apx:lpr-read@1.0` in its `extensions`
        container (Part 4 §4.3 — plain APDS consumers ignore it), and projected
        on `LprRead.detail` and `PlateCandidate.detail`. Every field optional;
        each recognized attribute carries its own confidence. APDS's
        `vehicleAncillaryIdentification` (country, stateProvince, make, model,
        color) remains the APDS-visible copy of the winning values; this block
        adds the per-attribute confidence, the candidates that lost, and the
        passage geometry APDS has no fields for.
      type: object
      properties:
        plate:
          $ref: '#/components/schemas/AttributeRead'
        country:
          description: Plate issuing country (APDS VehicleAncillaryIdentification.country vocabulary).
          $ref: '#/components/schemas/AttributeRead'
        stateProvince:
          description: Plate issuing state/province (APDS VehicleAncillaryIdentification.stateProvince vocabulary).
          $ref: '#/components/schemas/AttributeRead'
        plateCategory:
          description: The plate's category where the issuing country uses one (e.g. the prefix on some Gulf-state plates). Absent where the country has none.
          $ref: '#/components/schemas/AttributeRead'
        make:
          $ref: '#/components/schemas/AttributeRead'
        model:
          $ref: '#/components/schemas/AttributeRead'
        color:
          $ref: '#/components/schemas/AttributeRead'
        bodyType:
          description: The engine's own vehicle class label (SUV, sedan, pickup, bus, truck…), carried as the engine reports it and not mapped to a standard list.
          $ref: '#/components/schemas/AttributeRead'
        alternateReads:
          type: array
          description: The other candidate plate strings the engine considered for this capture, best first — kept so a correction (Part 17 §17.5) can pick a loser.
          items:
            type: object
            required:
              - plate
            properties:
              plate:
                type: string
              stateProvince:
                type: string
              confidence:
                type: number
                minimum: 0
                maximum: 1
        frameReads:
          type: integer
          minimum: 0
          description: |-
            How many frames read this plate as the vehicle passed. Engines need
            at least two to call `movement`, so a camera that sees only one of
            the vehicle's plates still reports it (Part 13 §13.3a(3)).
        platesRead:
          type: integer
          minimum: 0
          description: |-
            How many distinct plates of the vehicle were read in the passage
            (1 = one plate; 2 = front and rear).
        plateFace:
          type: string
          enum:
            - front
            - rear
            - unknown
          description: Which plate of the vehicle was read, for engines that can tell.
        plateBox:
          type: object
          description: |-
            The plate's position in the camera frame, as fractions 0–1 of the
            frame's height (`top`, `bottom`) and width (`left`, `right`), so it
            survives image resizing.
          required:
            - top
            - left
            - bottom
            - right
          properties:
            top:
              type: number
              minimum: 0
              maximum: 1
            left:
              type: number
              minimum: 0
              maximum: 1
            bottom:
              type: number
              minimum: 0
              maximum: 1
            right:
              type: number
              minimum: 0
              maximum: 1
        movement:
          type: string
          enum:
            - toward
            - away
            - stopped
            - unknown
            - approaching
            - receding
          description: |-
            The vehicle's motion relative to the camera: toward it, away from
            it, or stopped. A camera fact, not a statement about the facility.
            `approaching` and `receding` are deprecated synonyms of `toward`
            and `away` — accepted until 1.0; writers SHOULD send the new values
            (Part 13 §13.3a(3)).
        speed:
          type: number
          minimum: 0
          description: Vehicle speed in km/h when the engine measures it; absent otherwise, never a sentinel such as -1.
        accessEvent:
          type: string
          enum:
            - entry
            - exit
            - unknown
          description: |-
            Whether this read was a vehicle entering or leaving the facility, as
            reported by the LPR system — not the lane's configured purpose (the
            lane's APDS `accessType`), and never inferred by the APX server.
            Absent means `unknown`. The LPR system MAY revise it through
            `PUT /v1/lpr/reads/{observation}/access-event` (Part 13 §13.3a(4)).
        captureGroup:
          type: string
          description: |-
            Opaque id linking the reads of one vehicle's passage — several
            frames, and one camera or several (e.g. front plate and rear
            plate) — so consumers can treat them as one event. Reads of one
            group SHOULD carry the same `accessEvent` (Part 13 §13.3a(6)).
        engine:
          type: string
          description: Recognition engine/vendor identifier, opaque (for confidence calibration downstream).
        review:
          type: object
          description: |-
            The human-review state of the read (Part 13 §13.3a(4a)): a
            low-confidence read, or any read in a jurisdiction that requires
            review, is `pending` until a reviewer confirms, corrects, or
            rejects it through `PUT /v1/lpr/reads/{observation}/plate`.
            `notRequired` is a read no rule sent to review. Absent means the
            implementation does not review reads.
          properties:
            state:
              type: string
              enum:
                - pending
                - confirmed
                - corrected
                - rejected
                - notRequired
            reasons:
              type: array
              description: Why the read was sent to review — definedValues from `apx-read-review-reasons` (Part 11) or implementer values.
              items:
                type: string
            decidedTime:
              $ref: '#/components/schemas/DateTime'
            decidedBy:
              type: string
              description: Opaque reviewer principal.
            original:
              type: object
              description: |-
                The engine's values before the first correction, with their
                confidences, kept so the correction is auditable. Set by the
                server on the first `corrected` decision and never changed
                afterwards (Part 13 §13.3a(4a)).
              properties:
                plate:
                  $ref: '#/components/schemas/AttributeRead'
                country:
                  $ref: '#/components/schemas/AttributeRead'
                stateProvince:
                  $ref: '#/components/schemas/AttributeRead'
      examples:
        - plate:
            value: RVR-8821
            confidence: 0.91
          stateProvince:
            value: IL
            confidence: 0.88
          make:
            value: Ford
            confidence: 0.94
          model:
            value: F-150
            confidence: 0.71
          color:
            value: grey
            confidence: 0.83
          bodyType:
            value: pickup
            confidence: 0.96
          frameReads: 4
          platesRead: 2
          plateFace: front
          plateBox:
            top: 0.52
            left: 0.29
            bottom: 0.59
            right: 0.36
          movement: toward
          accessEvent: entry
          captureGroup: riverside/20261214T074108/0417
          engine: vendor-x/7.2
    LaneCameras:
      title: LaneCameras
      description: |-
        The LPR cameras on a lane and which way each one faces (Part 13
        §13.3a(5)). Carried on an APDS VehicularAccess as the Level B
        decoration `apds-ext:apx:lane-cameras@1.0` in its `extensions`
        container (Part 4 §4.3). Facing is relative to the facility, not to
        the lane's mode, so it holds on `reversible` lanes. Describes the
        setup only; APX derives nothing from it.
      type: object
      required:
        - cameras
      properties:
        cameras:
          type: array
          minItems: 1
          items:
            type: object
            required:
              - cameraId
              - faces
            properties:
              cameraId:
                type: string
                description: |-
                  The camera, as `Image.cameraID` names it on its reads. MUST
                  be unique within the Place.
              faces:
                type: string
                enum:
                  - inward
                  - outward
                description: |-
                  `inward` — looking into the facility, the way entering
                  traffic travels (reads the rear plates of entering
                  vehicles); `outward` — looking out of it, the way exiting
                  traffic travels (reads the rear plates of exiting vehicles).
      examples:
        - cameras:
            - cameraId: harbor/cam-centre-in
              faces: inward
            - cameraId: harbor/cam-centre-out
              faces: outward
    ReservationExtension:
      title: ReservationExtension
      description: |-
        The apds-ext:apx:reservation@1.0 extension object attached to a native
        AssignedRight. Presence of this extension marks the AssignedRight as a
        reservation; state transitions follow Part 14 §14.1 (transition
        table). `plannedStart`/`plannedEnd` MUST mirror the AssignedRight's
        `plannedUses[0].startTime`/`endTime`, which is authoritative.
      type: object
      required:
        - reservationState
      properties:
        reservationState:
          type: string
          enum:
            - confirmed
            - amended
            - cancelled
            - checkedIn
            - noShow
        plannedStart:
          description: Mirror of `plannedUses[0].startTime` (Part 14 §14.1).
          $ref: '#/components/schemas/DateTime'
        plannedEnd:
          description: Mirror of `plannedUses[0].endTime` (Part 14 §14.1).
          $ref: '#/components/schemas/DateTime'
        checkInSession:
          description: Set when a Session referencing this AssignedRight is created.
          $ref: '#/components/schemas/Reference'
        noShowAfter:
          description: |-
            SERVER-SET: the instant after which a reservation still without a
            check-in transitions to `noShow` (`plannedStart` plus the
            operator's grace period, Part 14 §14.1 step 6), so a platform can
            tell a customer when the booking lapses. Clients do not send it.
          readOnly: true
          $ref: '#/components/schemas/DateTime'
      examples:
        - reservationState: checkedIn
          plannedStart: '2026-08-14T18:00:00Z'
          plannedEnd: '2026-08-15T01:00:00Z'
          checkInSession:
            id: f1000000-0000-4000-8000-000000000014
            className: Session
    ReservationSummary:
      title: ReservationSummary
      description: |-
        Compact view of one past/current reservation, for customer-history
        lookups. Also the `data` of `apx.reservation.noshow.v1` (Part 14
        §14.1 step 6).
      type: object
      required:
        - reservation
      properties:
        reservation:
          $ref: '#/components/schemas/Reference'
        reservationState:
          type: string
          enum:
            - confirmed
            - amended
            - cancelled
            - checkedIn
            - noShow
        plannedStart:
          $ref: '#/components/schemas/DateTime'
        plannedEnd:
          $ref: '#/components/schemas/DateTime'
        noShowAfter:
          description: When a reservation not yet checked in lapses to `noShow` (see ReservationExtension.noShowAfter).
          $ref: '#/components/schemas/DateTime'
        issuer:
          type: string
          description: Who sold the reservation, so a code that several sellers could have issued is read against the right one (Part 14 §14.1, Part 17 §17.2). An operator code or the seller's domain.
          examples:
            - spothero.example
        amountPaid:
          description: What the customer prepaid, so an agent at the lane sees it without a payment lookup.
          $ref: '#/components/schemas/AmountInCurrency'
      examples:
        - reservation:
            id: e2000000-0000-4000-8000-000000000002
            className: AssignedRight
          reservationState: checkedIn
          plannedStart: '2026-08-14T18:00:00Z'
          plannedEnd: '2026-08-15T01:00:00Z'
    PoolAvailability:
      title: PoolAvailability
      description: |-
        Availability of one RightPool of a pooled RightSpecification (APDS
        RightPool profile, Part 14 §14.2). `issued` =
        `RightPool.distributedAssignedRights`, `available` =
        `RightPool.availableAssignedRights`, `capacity` = their sum.
      type: object
      required:
        - rightSpecification
        - capacity
        - issued
        - available
      properties:
        rightSpecification:
          $ref: '#/components/schemas/VersionedReference'
        pool:
          description: The RightPool these counts are for (selected per Part 14 §14.2).
          $ref: '#/components/schemas/VersionedReference'
        validity:
          description: The selected pool's validity window (APDS `RightPool.validity`), when it has one.
          $ref: '#/components/schemas/Validity'
        capacity:
          type: integer
          minimum: 0
          description: Permits the pool can issue in total (`issued` + `available`); may exceed `spaces` when the operator oversells.
        issued:
          type: integer
          minimum: 0
        available:
          type: integer
          minimum: 0
        spaces:
          type: integer
          minimum: 0
          description: Physical spaces behind the pool, when the operator sells above that count. Informative.
    PermitIssueRequest:
      title: PermitIssueRequest
      description: |-
        Issue a permit from a pooled RightSpecification — creates a native
        AssignedRight with (possibly multiple) vehicle credentials, per the APDS
        annual-permit use case (one right, multiple vehicles).
      type: object
      required:
        - rightSpecification
        - holder
      properties:
        rightSpecification:
          $ref: '#/components/schemas/VersionedReference'
        holder:
          description: |-
            The RightHolder the permit is issued to; materialized as a
            `CustomerCredential` on the AssignedRight (Part 14 §14.2).
          $ref: '#/components/schemas/Reference'
        credentials:
          type: array
          description: |-
            Vehicle credentials (e.g. plates) usable under this one permit; each
            is materialized as a `VehicleCredential` (Part 14 §14.2).
          items:
            type: object
            properties:
              credentialType:
                type: string
                description: |-
                  An APDS `CredentialTypeEnum` value, which MUST also be in the
                  RightSpecification's `credentials` allow-list (Part 14 §14.2).
                examples:
                  - licensePlate
              credentialIdentification:
                type: string
                description: What the lane reads — the plate string, tag id, or card number.
        validity:
          type: object
          description: |-
            The permit's validity window; materialized as one `PlannedUse`
            (`startTime`/`endTime`) and `expiry` = `end` (Part 14 §14.2).
          properties:
            start:
              $ref: '#/components/schemas/DateTime'
            end:
              $ref: '#/components/schemas/DateTime'
        extensions:
          description: |-
            Extension container (Part 4 §4.3). `apds-ext:apx:permit@1.0` links
            a renewal to the permit it renews (Part 14 §14.2).
          allOf:
            - $ref: '#/components/schemas/Extensions'
            - type: object
              properties:
                apds-ext:apx:permit@1.0:
                  $ref: '#/components/schemas/PermitExtension'
    TollTransaction:
      title: TollTransaction
      description: |-
        A toll charge assembled from plate/transponder reads: Observation refs →
        pricing → Payment ref, with a dispute lifecycle.
      type: object
      required:
        - id
        - version
        - tollPoint
        - transactionStatus
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
        version:
          type: integer
          minimum: 1
          readOnly: true
        tollPoint:
          description: Reference to the toll point (SupplementalEquipment).
          $ref: '#/components/schemas/Reference'
        observations:
          type: array
          description: The underlying APDS Observations (plate/transponder reads).
          items:
            $ref: '#/components/schemas/Reference'
        credential:
          type: object
          description: The credential observed (licensePlate, rfid transponder…).
          properties:
            credentialType:
              type: string
              description: |-
                Read technology. Senders SHOULD use an APDS `CredentialTypeEnum`
                value (`licensePlate`, `rfid`, …); Part 15 §15.1.
              examples:
                - licensePlate
                - rfid
            credentialIdentification:
              type: string
              description: What was read — the plate string or the transponder/tag id, as read.
        pricing:
          $ref: '#/components/schemas/AmountInCurrency'
        payment:
          description: Reference to the settling PaymentRecord/APDS Payment.
          $ref: '#/components/schemas/Reference'
        transactionStatus:
          type: string
          enum:
            - created
            - priced
            - paid
            - disputed
            - resolved
            - voided
          readOnly: true
        dispute:
          type: object
          properties:
            reason:
              type: string
              description: definedValue from `apx-toll-dispute-reasons` or an implementer code list (Part 11).
            openedTime:
              $ref: '#/components/schemas/DateTime'
            resolvedTime:
              $ref: '#/components/schemas/DateTime'
            resolution:
              type: string
              description: |-
                definedValue from `apx-toll-dispute-resolutions` (upheld |
                refunded | adjusted | withdrawn, Part 15 §15.1) or an implementer
                code list (Part 11).
            disputedBy:
              description: |-
                The party on whose behalf the dispute was raised (RightHolder,
                Organisation, or Contact); absent for an operator-initiated
                dispute (Part 15 §15.1).
              readOnly: true
              $ref: '#/components/schemas/Reference'
            originalPricing:
              description: |-
                Set by the server when an `adjusted` resolution rewrites
                `pricing`: the amount before the adjustment (Part 15 §15.1).
              readOnly: true
              $ref: '#/components/schemas/AmountInCurrency'
        statusHistory:
          type: array
          description: Immutable lifecycle audit (Part 4 §4.2).
          items:
            type: object
            required:
              - state
              - time
              - actor
            properties:
              state:
                type: string
              time:
                $ref: '#/components/schemas/DateTime'
              actor:
                type: string
              detail:
                type: string
        recordInfo:
          $ref: '#/components/schemas/RecordInfo'
        extensions:
          $ref: '#/components/schemas/Extensions'
      examples:
        - id: e9000000-0000-4000-8000-000000000802
          version: 5
          tollPoint:
            id: b4000000-0000-4000-8000-000000000001
            className: SupplementalEquipment
          credential:
            credentialType: licensePlate
            credentialIdentification: SYN-9930
          pricing:
            currencyType: USD
            currencyValue: 2.75
          payment:
            id: 9c0d1e2f-3a4b-4c5d-8e6f-7a8b9c0d1902
            className: PaymentRecord
          transactionStatus: resolved
          dispute:
            reason: wrongVehicle
            openedTime: '2026-10-02T15:20:11Z'
            resolvedTime: '2026-10-03T09:41:02Z'
            resolution: refunded
          statusHistory:
            - state: created
              time: '2026-09-22T07:52:31Z'
              actor: gantry-hc-01
              detail: plate fallback, confidence 0.71
            - state: priced
              time: '2026-09-22T07:52:31Z'
              actor: toll-pricing
            - state: paid
              time: '2026-09-23T02:11:41Z'
              actor: billing-batch
            - state: disputed
              time: '2026-10-02T15:20:11Z'
              actor: agent-0219
            - state: resolved
              time: '2026-10-03T09:41:02Z'
              actor: backoffice-jlee
              detail: refunded; gantry hc-01 flagged for recalibration
    TollPaymentAttachment:
      title: TollPaymentAttachment
      description: Request body attaching the settling Payment to a toll transaction.
      type: object
      required:
        - payment
      properties:
        payment:
          description: Reference to the settling APDS Payment (or APX PaymentRecord).
          $ref: '#/components/schemas/Reference'
        note:
          type: string
    TollDisputeOpen:
      title: TollDisputeOpen
      description: Request body opening a dispute on a toll transaction.
      type: object
      required:
        - reason
      properties:
        reason:
          type: string
          description: |-
            Dispute reason — definedValue from `apx-toll-dispute-reasons`
            (wrongVehicle | duplicateCharge | wrongClass | notLiable | other,
            Part 15 §15.1) or an implementer code list (Part 11).
          examples:
            - wrongVehicle
            - duplicateCharge
        detail:
          type: string
        disputedBy:
          description: |-
            The party on whose behalf the operator raises the dispute
            (RightHolder, Organisation, or Contact). MAY be absent for an
            operator-initiated dispute (Part 15 §15.1).
          $ref: '#/components/schemas/Reference'
    TollDisputeResolution:
      title: TollDisputeResolution
      description: Request body resolving an open dispute.
      type: object
      required:
        - resolution
      properties:
        resolution:
          type: string
          description: |-
            Resolution — definedValue from `apx-toll-dispute-resolutions`
            (upheld | refunded | adjusted | withdrawn, Part 15 §15.1) or an
            implementer code list (Part 11).
          examples:
            - refunded
        adjustedPricing:
          description: |-
            The new amount owed. REQUIRED when `resolution` is `adjusted`
            (otherwise 400 `invalid-request`) and ignored for any other value;
            the server moves the old `pricing` to `dispute.originalPricing`
            (Part 15 §15.1).
          $ref: '#/components/schemas/AmountInCurrency'
        note:
          type: string
    Violation:
      title: Violation
      description: |-
        An enforcement finding against a vehicle at a place: the detection
        (automated, guided, or manual), the eligibility check that justified
        it, the evidence, the issued notice/citation, settlement, and any
        appeal — with the immutable lifecycle audit (Part 4 §4.2).

        Lifecycle (Part 19 §19.1): `detected → confirmed | dismissed`,
        `confirmed → issued`, `issued → paid | appealed`,
        `paid → appealed` (pay-then-appeal, within the policy's
        `appealWindowDays`), `appealed → issued | paid (upheld, or reduced
        with amount replaced by adjustedAmount; back to the state the appeal
        was opened from) | closed (dismissed)`, `paid → closed` (server-side
        administrative transition, no API operation). The terminal states
        are `dismissed`, `closed`, and `voided`; `void` is valid from every
        other state (`detected`, `confirmed`, `issued`, `appealed`, `paid`).
        Automated detection MAY skip review (`detected → issued`) where the
        policy in force permits (`EnforcementPolicy.unreviewedIssuance`);
        guided detection MUST pass through review.
      type: object
      required:
        - id
        - version
        - violationType
        - violationStatus
        - place
        - detection
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
        version:
          type: integer
          minimum: 1
          readOnly: true
        violationType:
          type: string
          description: definedValue from `apx-violation-types` or an implementer code list.
          examples:
            - noValidRight
        violationStatus:
          type: string
          enum:
            - detected
            - confirmed
            - dismissed
            - issued
            - paid
            - appealed
            - closed
            - voided
          readOnly: true
          description: Current lifecycle state (see schema description for transitions).
        place:
          description: The HierarchyElement (Place, Area, Space…) where the violation was observed.
          $ref: '#/components/schemas/Reference'
        space:
          description: The specific APDS Space, when the detection is space-resolved (sensor, bay camera).
          $ref: '#/components/schemas/Reference'
        detection:
          $ref: '#/components/schemas/ViolationDetection'
        vehicle:
          $ref: '#/components/schemas/ViolationVehicle'
        observations:
          type: array
          description: The underlying APDS Observations (plate reads, sensor events) the finding is built from.
          items:
            $ref: '#/components/schemas/Reference'
        evidence:
          $ref: '#/components/schemas/ViolationEvidence'
        eligibilityCheck:
          description: The entitlement check performed at detection time (the same shape `GET /v1/enforcement/eligibility` returns).
          $ref: '#/components/schemas/EligibilityResult'
        relatedSession:
          description: The APDS Session the vehicle was in, when one exists.
          $ref: '#/components/schemas/Reference'
        relatedRight:
          description: The AssignedRight that was closest to covering the stay (expired permit, wrong-zone reservation…).
          $ref: '#/components/schemas/Reference'
        location:
          $ref: '#/components/schemas/ViolationLocation'
        policy:
          description: The EnforcementPolicy resolved for `place` at `issue` (Part 19 §19.10), frozen with its version.
          $ref: '#/components/schemas/VersionedReference'
          readOnly: true
        signage:
          type: array
          readOnly: true
          description: |-
            The Signage records in force at `place` (and ancestors) at
            `detectedTime`, frozen at `issue` with their versions — the
            evidence of what was posted (Part 19 §19.11).
          items:
            $ref: '#/components/schemas/VersionedReference'
        unpaidAmount:
          description: |-
            The unpaid parking fee this violation relates to — the basis for
            the policy's relative penalty caps (`maximumMultipleOfUnpaid`,
            `maximumPercentOverUnpaid`). Computed by the server at `issue`
            from the rate deck in force for the stay and frozen with the
            policy (Part 19 §19.10). Absent when the policy in force has no
            relative cap or no fee could be derived.
          readOnly: true
          $ref: '#/components/schemas/AmountInCurrency'
        capAmount:
          description: |-
            The effective penalty cap at `issue` (the lowest of the policy's
            `penaltyCap` bounds, relative ones applied to `unpaidAmount`),
            frozen so an appeal can check `penalty-exceeds-cap` without
            recomputing it. Absent when no cap applied.
          readOnly: true
          $ref: '#/components/schemas/AmountInCurrency'
        amountHistory:
          type: array
          readOnly: true
          description: |-
            Every change to `amount`, in order: the issued amount, each
            server-applied escalation step, and each appeal reduction
            (Part 19 §19.10). `amount` always equals the last entry. The
            first entry is written at `issue`: `reason: issued`, or, when the
            requested amount was clamped to the cap, a single entry with
            `reason: cap`, the clamped `amount`, and the amount asked for in
            `requestedAmount`.
          items:
            type: object
            required:
              - amount
              - time
              - reason
            properties:
              amount:
                $ref: '#/components/schemas/AmountInCurrency'
              time:
                $ref: '#/components/schemas/DateTime'
              reason:
                type: string
                enum:
                  - issued
                  - escalation
                  - appealReduced
                  - cap
              step:
                type: string
                description: The policy escalation step id that fired, when `reason` is `escalation`.
              requestedAmount:
                description: The amount the `issue` call asked for, when `reason` is `cap` (the entry's `amount` is the clamped figure).
                $ref: '#/components/schemas/AmountInCurrency'
              detail:
                type: string
        notice:
          type: object
          description: The notice, warning, or citation issued for this violation. Absent until `issued`.
          readOnly: true
          properties:
            noticeKind:
              type: string
              description: What was issued — warning, notice, citation (implementer code list; jurisdictional vocabulary).
              examples:
                - citation
            noticeNumber:
              type: string
              description: The operator's/jurisdiction's printed or mailed notice number.
              examples:
                - LG-2026-018342
            issuedTime:
              $ref: '#/components/schemas/DateTime'
            issuedBy:
              description: The issuing Organisation or officer Contact.
              $ref: '#/components/schemas/Reference'
            deliveryMethod:
              type: string
              description: How the notice reached the driver — windshield, handed, mail, electronic (implementer code list).
              examples:
                - mail
        amount:
          description: The amount payable on the issued notice (after any appeal reduction).
          $ref: '#/components/schemas/AmountInCurrency'
        dueTime:
          description: When payment falls due.
          $ref: '#/components/schemas/DateTime'
        payment:
          description: Reference to the settling APDS Payment or APX PaymentRecord (Part 13).
          $ref: '#/components/schemas/Reference'
        payments:
          type: array
          readOnly: true
          description: |-
            Every payment applied to the notice, in order (Part 19 §19.6a).
            `payment` remains the settling one; a partial payment appears
            here, raises `amountPaid`, and leaves the state `issued` until
            `amountPaid` reaches `amount`. For an imported violation (§19.13)
            an item may carry only the source's own payment `reference`, when
            the money never moved through this server's Part 13 records.
          items:
            $ref: '#/components/schemas/ViolationAppliedPayment'
        amountPaid:
          readOnly: true
          description: |-
            The sum received so far against `amount` (Part 19 §19.6a). `paid`
            means `amountPaid` ≥ `amount`. Absent means nothing received.
          $ref: '#/components/schemas/AmountInCurrency'
        appeal:
          type: object
          description: The appeal on this violation, if one was opened. One appeal per violation.
          readOnly: true
          properties:
            reason:
              type: string
              description: Appeal reason (implementer code list).
              examples:
                - notTheVehicle
            detail:
              type: string
            appellant:
              description: The appealing party (Contact), when identified.
              $ref: '#/components/schemas/Reference'
            openedTime:
              $ref: '#/components/schemas/DateTime'
            openedFrom:
              type: string
              enum:
                - issued
                - paid
              description: |-
                The state the appeal was opened from; `paid` is a
                pay-then-appeal (Part 19 §19.6). `upheld` and `reduced` return
                the violation to this state.
            resolvedTime:
              $ref: '#/components/schemas/DateTime'
            resolution:
              type: string
              description: upheld | reduced | dismissed (implementer code list).
              examples:
                - dismissed
            resolutionNote:
              type: string
            refund:
              description: |-
                The Part 13 refund (APX PaymentRecord or APDS Payment) that
                returned money on a pay-then-appeal resolved `reduced`
                (partial) or `dismissed` (full).
              $ref: '#/components/schemas/Reference'
        statusHistory:
          type: array
          description: Immutable, append-only lifecycle audit (Part 4 §4.2).
          items:
            type: object
            required:
              - state
              - time
              - actor
            properties:
              state:
                type: string
              time:
                $ref: '#/components/schemas/DateTime'
              actor:
                type: string
                description: Client/agent principal that caused the transition.
              detail:
                type: string
        recordInfo:
          $ref: '#/components/schemas/RecordInfo'
        extensions:
          $ref: '#/components/schemas/Extensions'
      examples:
        - id: d3000000-0000-4000-8000-000000000001
          version: 2
          violationType: expiredRight
          violationStatus: issued
          place:
            id: b1000000-0000-4000-8000-000000000004
            className: Place
          detection:
            mode: automated
            detectedTime: '2026-09-18T09:31:04Z'
            detector:
              id: b2000000-0000-4000-8000-000000000031
              className: SupplementalEquipment
            principal: lpr-pipeline-lot-c
            confidence: 0.94
            rule: paybyplate-expiry-15m
          vehicle:
            credentialType: licensePlate
            credentialIdentification: SYN-4471
            jurisdiction: US-IL
          observations:
            - id: f2000000-0000-4000-8000-000000000041
              className: Observation
          relatedSession:
            id: f1000000-0000-4000-8000-000000000044
            className: Session
          notice:
            noticeKind: notice
            noticeNumber: LG-2026-018301
            issuedTime: '2026-09-18T09:31:09Z'
            issuedBy:
              id: a1000000-0000-4000-8000-000000000001
              className: Organisation
            deliveryMethod: mail
          amount:
            currencyType: USD
            currencyValue: 35
          dueTime: '2026-10-18T23:59:59Z'
          statusHistory:
            - state: detected
              time: '2026-09-18T09:31:05Z'
              actor: lpr-pipeline-lot-c
              detail: rule paybyplate-expiry-15m; grace to 09:20 elapsed
            - state: issued
              time: '2026-09-18T09:31:09Z'
              actor: lpr-pipeline-lot-c
              detail: policy lot-c-auto-issue (confidence 0.94 ≥ 0.9); notice LG-2026-018301 queued for mail
    EligibilityResult:
      title: EligibilityResult
      description: |-
        "Is this vehicle entitled to be here right now?" — the guided-enforcement
        screen-pop (Part 19 §19.3). A convenience READ composed from the APDS
        entities that natively answer the question: AssignedRights (APDS's own
        enforcement source of truth), Sessions, and reservation/permit profiles.
        Adds no parallel entitlement entity; the AssignedRight remains
        authoritative.
      type: object
      required:
        - place
        - credential
        - checkedTime
        - entitled
      properties:
        place:
          description: The HierarchyElement the question was asked for.
          $ref: '#/components/schemas/Reference'
        credential:
          type: object
          required:
            - credentialType
            - credentialIdentification
          properties:
            credentialType:
              $ref: '#/components/schemas/CredentialTypeEnum'
            credentialIdentification:
              type: string
              examples:
                - SYN-4471
        checkedTime:
          description: The instant the answer applies to (the `at` parameter, or now).
          $ref: '#/components/schemas/DateTime'
        entitled:
          type: boolean
          description: True when at least one basis entry is `valid` for the place at `checkedTime`.
        basis:
          type: array
          description: Every right or session considered, newest first, with why it does or does not cover the stay.
          items:
            type: object
            required:
              - status
            properties:
              right:
                description: The AssignedRight considered.
                $ref: '#/components/schemas/Reference'
              session:
                description: The Session considered (pay-by-plate, transient).
                $ref: '#/components/schemas/Reference'
              rightType:
                type: string
                description: Human-readable product (from the RightSpecification) — monthly permit, reservation, pay-by-plate.
                examples:
                  - monthlyPermit
              validFrom:
                $ref: '#/components/schemas/DateTime'
              validTo:
                $ref: '#/components/schemas/DateTime'
              status:
                type: string
                enum:
                  - valid
                  - expired
                  - notYetValid
                  - wrongPlace
                  - consumed
                  - suspended
                description: Why this basis does or does not entitle the vehicle here, now.
        suggestedViolationType:
          type: string
          description: When not entitled — the `apx-violation-types` value the server's rules suggest (never binding on the officer).
          examples:
            - expiredRight
        graceUntil:
          description: |-
            When the grace on the stay ends, derived from the `stayGrace` of the
            EnforcementPolicy in force at `checkedTime` (Part 19 §19.3 rule 5):
            the stay's start plus `entryMinutes` while no right covers it, or
            the end of its last covering right plus `exitMinutes` once its
            rights have ended. Absent when that side has no grace, no policy is
            in force, or a right covers the stay.
          $ref: '#/components/schemas/DateTime'
        lastRead:
          type: object
          description: The most recent plate read of this credential at the place (APDS Observation-derived).
          properties:
            observation:
              $ref: '#/components/schemas/Reference'
            observationDateTime:
              $ref: '#/components/schemas/DateTime'
            confidence:
              type: number
              minimum: 0
              maximum: 1
            imageLink:
              $ref: '#/components/schemas/Url'
        extensions:
          $ref: '#/components/schemas/Extensions'
      examples:
        - place:
            id: b1000000-0000-4000-8000-000000000003
            className: Place
          credential:
            credentialType: licensePlate
            credentialIdentification: SYN-8820
          checkedTime: '2026-09-18T10:14:05Z'
          entitled: false
          basis:
            - right:
                id: e1000000-0000-4000-8000-000000000027
                className: AssignedRight
              rightType: monthlyPermit
              validFrom: '2026-09-01T00:00:00Z'
              validTo: '2026-09-30T23:59:59Z'
              status: wrongPlace
          suggestedViolationType: wrongPlace
          lastRead:
            observation:
              id: f2000000-0000-4000-8000-000000000052
              className: Observation
            observationDateTime: '2026-09-18T08:31:47Z'
            confidence: 0.96
            imageLink: https://api.lakeside-garage.example/lpr/f2000000-0052.jpg
    ViolationReview:
      title: ViolationReview
      description: Request body for guided-enforcement review — confirm or dismiss a detected candidate.
      type: object
      required:
        - decision
      properties:
        decision:
          type: string
          enum:
            - confirm
            - dismiss
        reason:
          type: string
          description: |-
            Required when `decision` is `dismiss` (implementer code list —
            permitDisplayed, plateMisread, gracePeriod…); a dismissal without
            it is 400 `invalid-request` with `errors[].pointer` `/reason`
            (Part 19 §19.1 rule 1).
          examples:
            - plateMisread
        note:
          type: string
        reviewer:
          description: The reviewing officer's Contact, when the token is a system credential.
          $ref: '#/components/schemas/Reference'
        violationType:
          type: string
          description: Corrects the violation type on confirmation, when the officer's finding differs from the detector's.
          examples:
            - wrongZone
    ViolationIssue:
      title: ViolationIssue
      description: Request body issuing the notice/citation for a confirmed (or, under automated policy, detected) violation.
      type: object
      required:
        - amount
      properties:
        noticeKind:
          type: string
          description: warning | notice | citation (implementer code list). Default is implementation policy.
          examples:
            - citation
        noticeNumber:
          type: string
          description: Client-supplied notice number (pre-printed handheld stock). Server-assigned when absent.
        amount:
          $ref: '#/components/schemas/AmountInCurrency'
        dueTime:
          $ref: '#/components/schemas/DateTime'
        deliveryMethod:
          type: string
          description: windshield | handed | mail | electronic (implementer code list).
          examples:
            - windshield
        issuedBy:
          description: The issuing Organisation or officer Contact, when different from the token's organisation.
          $ref: '#/components/schemas/Reference'
        note:
          type: string
    ViolationPaymentAttachment:
      title: ViolationPaymentAttachment
      description: |-
        Request body attaching a Payment to an issued violation. The full
        amount (or the remainder) settles it (`paid`); a smaller `amount` is
        a partial payment (Part 19 §19.6a) that stays `issued`.
      type: object
      required:
        - payment
      properties:
        payment:
          description: Reference to the settling APDS Payment (or APX PaymentRecord taken via `POST /v1/payments`).
          $ref: '#/components/schemas/Reference'
        amount:
          description: The amount this payment contributes; absent means the full outstanding amount.
          $ref: '#/components/schemas/AmountInCurrency'
        note:
          type: string
    ViolationAppealOpen:
      title: ViolationAppealOpen
      description: Request body opening an appeal on an issued violation, or on a paid one within the policy's appeal window (pay-then-appeal).
      type: object
      required:
        - reason
      properties:
        reason:
          type: string
          description: Appeal reason (implementer code list).
          examples:
            - notTheVehicle
        detail:
          type: string
        appellant:
          description: The appealing party (Contact), when identified.
          $ref: '#/components/schemas/Reference'
        evidenceLinks:
          type: array
          description: Appellant-supplied evidence, as access-controlled links.
          items:
            $ref: '#/components/schemas/Url'
    ViolationAppealResolution:
      title: ViolationAppealResolution
      description: Request body resolving an open appeal.
      type: object
      required:
        - resolution
      properties:
        resolution:
          type: string
          description: |-
            upheld | reduced | dismissed (implementer code list). `upheld` returns
            the violation to the state the appeal was opened from (`issued`, or
            `paid` for a pay-then-appeal); `reduced` does the same with `amount`
            replaced by `adjustedAmount`; `dismissed` closes it.
          examples:
            - reduced
        adjustedAmount:
          description: |-
            The new amount payable. Required when `resolution` is `reduced`; a
            `reduced` resolution without it is 400 `invalid-request` with
            `errors[].pointer` `/adjustedAmount` (Part 19 §19.1 rule 3).
          $ref: '#/components/schemas/AmountInCurrency'
        refund:
          description: |-
            For a pay-then-appeal resolved `reduced` or `dismissed`: the Part 13
            refund returning the difference or the whole payment
            (`POST /v1/payments/{id}/refund`). Recorded on `appeal.refund`.
          $ref: '#/components/schemas/Reference'
        note:
          type: string
      if:
        required:
          - resolution
        properties:
          resolution:
            const: reduced
      then:
        required:
          - adjustedAmount
    ViolationVoid:
      title: ViolationVoid
      description: Request body voiding a violation (terminal; never deletes the audit).
      type: object
      required:
        - reason
      properties:
        reason:
          type: string
          description: Void reason (implementer code list — issuedInError, duplicate, policyException…).
          examples:
            - duplicate
        refund:
          description: |-
            When voiding a `paid` violation: the Part 13 refund that returned
            the payment (SHOULD be given; Part 19 §19.1 rule 4).
          $ref: '#/components/schemas/Reference'
        note:
          type: string
    EnforcementPolicy:
      title: EnforcementPolicy
      description: |-
        The jurisdictional rules that govern issuing and escalating violations
        at a place (Part 19 §19.10): lawful notice delivery per detection
        mode, the initial penalty cap, the escalation schedule, windows, and
        whether posted signage is required. Bound to a HierarchyElement with
        subtree inheritance — the nearest ancestor's policy applies unless a
        descendant overrides it. A machine-readable summary an operator
        configures from the governing statute; never the statute itself.
        Edits use versioned `PUT` with the version last read as `If-Match`
        or body `version` (Part 4 §4.2a; 409 `version-conflict` when stale).
      type: object
      required:
        - id
        - version
        - place
        - policyStatus
        - effectiveFrom
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
        version:
          type: integer
          minimum: 1
          readOnly: true
        place:
          description: The HierarchyElement this policy binds to (a state- or city-wide root, a lot, a level).
          $ref: '#/components/schemas/Reference'
        name:
          type: string
          examples:
            - Illinois private-lot notice rules 2026
        policyStatus:
          type: string
          enum:
            - active
            - superseded
            - retired
        effectiveFrom:
          $ref: '#/components/schemas/DateTime'
        effectiveTo:
          $ref: '#/components/schemas/DateTime'
        authority:
          type: object
          description: Provenance — where the rules come from.
          properties:
            jurisdiction:
              type: string
              description: ISO 3166-2 or implementer code for the legal jurisdiction.
              examples:
                - US-IL
            citation:
              type: string
              description: Statute, ordinance, or regulation citation.
              examples:
                - 625 ILCS 5/11-1305
            url:
              $ref: '#/components/schemas/Url'
        deliveryRules:
          type: array
          description: Which notice delivery methods are lawful for which detection modes, and by when.
          items:
            type: object
            required:
              - detectionModes
              - deliveryMethods
            properties:
              detectionModes:
                type: array
                items:
                  type: string
                  enum:
                    - automated
                    - guided
                    - manual
              deliveryMethods:
                type: array
                description: Lawful `notice.deliveryMethod` values for these modes (implementer code list — windshield, handed, mail, electronic).
                items:
                  type: string
              noticeDeadline:
                description: Latest lawful `issue` after `detectedTime` for these methods (ISO 8601).
                $ref: '#/components/schemas/Duration'
              minimumEvidence:
                type: object
                description: What the violation MUST carry before a notice by these methods is lawful.
                properties:
                  observations:
                    type: integer
                    minimum: 0
                  images:
                    type: integer
                    minimum: 0
                  locationRequired:
                    type: boolean
        unreviewedIssuance:
          type: object
          description: |-
            Whether an `automated` detection may go `detected → issued`
            without a human `review` (Part 19 §19.4 rule 1). When present the
            server MUST apply it at `issue` (409 `violation-not-issuable`
            otherwise); when absent the operator's published documentation
            governs, as before. `guided` and `manual` detections are always
            reviewed, whatever this says.
          properties:
            permitted:
              type: boolean
              default: false
              description: True when unreviewed automated issuance is lawful and permitted at this place.
            minimumConfidence:
              type: number
              minimum: 0
              maximum: 1
              description: Lowest `detection.confidence` that may be issued unreviewed; a detection below it, or with no confidence, needs review.
            violationTypes:
              type: array
              description: The `violationType` values that may be issued unreviewed; absent = every type.
              items:
                type: string
        penaltyCap:
          type: object
          description: |-
            Ceiling on the amount at `issue`. When more than one bound is
            present the lowest applies. Relative bounds apply to the
            violation's `unpaidAmount`, which the server computes and freezes
            at `issue` together with the resulting `capAmount`.
          properties:
            maximumAmount:
              $ref: '#/components/schemas/AmountInCurrency'
            maximumMultipleOfUnpaid:
              type: number
              minimum: 0
              description: Cap as a multiple of the unpaid parking fee the violation relates to (e.g. 2 = twice the unpaid fee).
            maximumPercentOverUnpaid:
              type: number
              minimum: 0
              description: Cap as unpaid fee plus this percentage of it.
            onExceed:
              type: string
              enum:
                - refuse
                - clamp
              description: '`refuse` → 422 `penalty-exceeds-cap`; `clamp` → issue at the cap and record `reason: cap` in amountHistory.'
        escalation:
          type: array
          description: |-
            Ordered, server-applied steps (Part 19 §19.10). Each fires once
            when `afterDays` have elapsed since `notice.issuedTime` with the
            violation still `issued`; days spent `appealed` do not count
            (the clock pauses during an appeal). The result is appended to
            `amountHistory` and never exceeds `overallCeiling`. A step whose
            fixed `addAmount` alone exceeds `overallCeiling.maximumAmount` is
            refused at create/update (422 `request-unprocessable`).
          items:
            type: object
            required:
              - step
              - afterDays
            properties:
              step:
                type: string
                description: Stable step id recorded in `amountHistory[].step`.
                examples:
                  - late-30
              afterDays:
                type: integer
                minimum: 1
              addAmount:
                $ref: '#/components/schemas/AmountInCurrency'
              addPercent:
                type: number
                minimum: 0
                description: Percentage of the CURRENT amount to add.
              description:
                type: string
        overallCeiling:
          type: object
          description: Hard ceiling on `amount` after any escalation.
          properties:
            maximumAmount:
              $ref: '#/components/schemas/AmountInCurrency'
            maximumMultipleOfIssued:
              type: number
              minimum: 1
              description: e.g. 3 = never more than three times the issued amount.
        appealWindowDays:
          type: integer
          minimum: 0
          description: |-
            Days after `notice.issuedTime` during which an appeal MUST be
            accepted — from `issued`, or from `paid` (pay-then-appeal). After
            it, servers MAY refuse with 409 `appeal-closed`.
        paymentGraceDays:
          type: integer
          minimum: 0
          description: Days after `notice.issuedTime` before the first escalation step MAY fire, regardless of `afterDays` (days spent `appealed` do not count).
        signageRequired:
          type: boolean
          description: When true, `issue` is refused (422 `signage-required`) unless Signage was in force at the place at `detectedTime`.
        stayGrace:
          type: object
          description: |-
            How long a stay may go uncovered at each end before it needs a
            right (Part 19 §19.10 rule 7). Both members are optional and
            independent: absent means no grace on that side, `0` states
            explicitly that there is none. The policy states the minutes only;
            how they combine with the rights into a stay's outcome is the
            evaluating system's rule. The source of
            `EligibilityResult.graceUntil` (§19.3 rule 5).
          properties:
            entryMinutes:
              type: integer
              minimum: 0
              description: Minutes after entry before a right (a payment, a permit, a reservation) must cover the stay.
              examples:
                - 15
            exitMinutes:
              type: integer
              minimum: 0
              description: Minutes after the end of the last covering right before the stay must be over.
              examples:
                - 15
        statusHistory:
          type: array
          description: Immutable, append-only lifecycle audit (Part 4 §4.2).
          items:
            type: object
            required:
              - state
              - time
              - actor
            properties:
              state:
                type: string
              time:
                $ref: '#/components/schemas/DateTime'
              actor:
                type: string
              detail:
                type: string
        recordInfo:
          $ref: '#/components/schemas/RecordInfo'
        extensions:
          $ref: '#/components/schemas/Extensions'
      examples:
        - id: d4000000-0000-4000-8000-000000000001
          version: 1
          place:
            id: b1000000-0000-4000-8000-000000000004
            className: Place
          name: State private-lot notice rules — Lot C
          policyStatus: active
          effectiveFrom: '2026-07-01T00:00:00Z'
          authority:
            jurisdiction: US-IL
            citation: Synthetic Stat. §12-405 (private lot notices)
          deliveryRules:
            - detectionModes:
                - automated
              deliveryMethods:
                - mail
                - electronic
              noticeDeadline: P14D
              minimumEvidence:
                observations: 1
                images: 1
                locationRequired: true
            - detectionModes:
                - guided
                - manual
              deliveryMethods:
                - windshield
                - handed
              noticeDeadline: PT1H
          penaltyCap:
            maximumMultipleOfUnpaid: 2
            onExceed: refuse
          escalation:
            - step: late-30
              afterDays: 30
              addPercent: 25
              description: 25% late penalty
            - step: late-60
              afterDays: 60
              addAmount:
                currencyType: USD
                currencyValue: 15
              description: Collection referral fee
          overallCeiling:
            maximumMultipleOfIssued: 3
          appealWindowDays: 21
          paymentGraceDays: 14
          signageRequired: true
          statusHistory:
            - state: active
              time: '2026-06-20T14:00:00Z'
              actor: backoffice-jlee
              detail: loaded from counsel's summary of §12-405
    Signage:
      title: Signage
      description: |-
        A record of what is posted at a place — the text, a photo, the
        sign's position, and when it was in force (Part 19 §19.11). Bound to
        a HierarchyElement with subtree inheritance. Versioned so an appeal
        can show the sign as it stood on the day: superseding a sign is a
        new version or a new record with `effectiveTo` set, never an edit in
        place of historical text. Edits use versioned `PUT` (Part 4 §4.2a).
      type: object
      required:
        - id
        - version
        - place
        - text
        - signageStatus
        - effectiveFrom
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
        version:
          type: integer
          minimum: 1
          readOnly: true
        place:
          description: The HierarchyElement the sign governs (the lot, a level, a zone).
          $ref: '#/components/schemas/Reference'
        text:
          description: The posted text, verbatim, per language.
          $ref: '#/components/schemas/MultilingualString'
        signageStatus:
          type: string
          enum:
            - active
            - superseded
            - removed
        effectiveFrom:
          $ref: '#/components/schemas/DateTime'
        effectiveTo:
          $ref: '#/components/schemas/DateTime'
        location:
          description: Where the sign stands (GeoJSON Point).
          $ref: '#/components/schemas/GeoJsonObject'
        imageLink:
          description: Access-controlled photo of the physical sign (Part 9 §9.6).
          $ref: '#/components/schemas/Url'
        signType:
          type: string
          description: Implementer code list — entrance, payStation, perSpace, towAway, ratesBoard.
          examples:
            - entrance
        policy:
          description: The EnforcementPolicy whose disclosure requirements this sign satisfies, when applicable.
          $ref: '#/components/schemas/Reference'
        statusHistory:
          type: array
          description: Immutable, append-only lifecycle audit (Part 4 §4.2).
          items:
            type: object
            required:
              - state
              - time
              - actor
            properties:
              state:
                type: string
              time:
                $ref: '#/components/schemas/DateTime'
              actor:
                type: string
              detail:
                type: string
        recordInfo:
          $ref: '#/components/schemas/RecordInfo'
        extensions:
          $ref: '#/components/schemas/Extensions'
      examples:
        - id: d5000000-0000-4000-8000-000000000001
          version: 1
          place:
            id: b1000000-0000-4000-8000-000000000004
            className: Place
          text:
            - language: en
              string: 'PAY BY PLATE. Unpaid or expired parking is subject to a $35 notice; unpaid notices increase 25% after 30 days. Appeals: lakeside-garage.example/appeals within 21 days.'
            - language: es
              string: 'PAGUE POR PLACA. El estacionamiento sin pagar o vencido está sujeto a un aviso de $35; los avisos impagos aumentan 25% después de 30 días. Apelaciones: lakeside-garage.example/appeals dentro de 21 días.'
          signageStatus: active
          effectiveFrom: '2026-07-01T00:00:00Z'
          location:
            type: Point
            coordinates:
              - -87.6214
              - 41.8827
          imageLink: https://api.lakeside-garage.example/signage/lot-c-entrance-2026-07.jpg
          signType: entrance
          policy:
            id: d4000000-0000-4000-8000-000000000001
            className: EnforcementPolicy
          statusHistory:
            - state: active
              time: '2026-06-28T10:12:00Z'
              actor: backoffice-jlee
              detail: installed 2026-06-28, photographed
    ValidationBenefit:
      title: ValidationBenefit
      description: |-
        What a validation is worth. Exactly one of `amount` (money off),
        `duration` (comped time, valued at the applicable rate), or
        `percentage` (proportionate discount — the APDS RateDiscount
        `discountRate` semantics) applies; `description` is always present so
        agents can answer disputes in plain language. A program body whose
        benefit carries none or more than one of the three is refused with
        422 `request-unprocessable` (Part 20 §20.1); the rule is stated here
        rather than as a schema `oneOf` so that existing request bodies keep
        validating.
      type: object
      required:
        - description
      properties:
        description:
          type: string
          examples:
            - First two hours comped
        amount:
          description: Fixed money off.
          $ref: '#/components/schemas/AmountInCurrency'
        duration:
          description: Comped parking time (ISO 8601), valued at the applicable rate.
          $ref: '#/components/schemas/Duration'
        percentage:
          type: number
          minimum: 0
          maximum: 100
          description: Proportionate discount on the amount due (APDS RateDiscount.discountRate semantics).
    ValidationProgram:
      title: ValidationProgram
      description: |-
        A merchant's enrolment to validate parking at a place: who the
        provider is, what the validation is worth, the rules that bound it,
        how the merchant is billed, and how instruments are issued. Active
        programs ARE the source of the Part 6 `GET /v1/validations/providers`
        list when `apx-validations` is claimed.

        Lifecycle (Part 20 §20.1): `active ⇄ suspended`, either → `ended`
        (terminal). Status changes go through `PUT` with the version last
        read as `If-Match` or body `version` (Part 4 §4.2a; 409
        `version-conflict` when stale).
      type: object
      required:
        - id
        - version
        - place
        - provider
        - programStatus
        - benefit
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
        version:
          type: integer
          minimum: 1
          readOnly: true
        place:
          description: The HierarchyElement (Place or subtree root) the program validates parking at.
          $ref: '#/components/schemas/Reference'
        provider:
          description: The merchant — an APDS Contact or Organisation.
          $ref: '#/components/schemas/Reference'
        name:
          type: string
          description: Display name shown to agents and on receipts.
          examples:
            - Harbor Bistro
        validationType:
          type: string
          description: Implementer code list naming the validation product (matches `ValidationProvider.validationType`).
          examples:
            - twoHourComp
        programStatus:
          type: string
          enum:
            - active
            - suspended
            - ended
        benefit:
          $ref: '#/components/schemas/ValidationBenefit'
        rules:
          type: object
          description: |-
            The closed rule set every implementation evaluates at redemption
            (Part 20 §20.3). Anything beyond it rides in `extensions`.
          properties:
            maxPerTicket:
              type: integer
              minimum: 1
              description: Redemptions of THIS program allowed on one ticket/session.
            maxPerDay:
              type: integer
              minimum: 1
              description: Redemptions of this program allowed per calendar day at the place.
            validityWindow:
              description: How long after issuance an instrument stays redeemable (ISO 8601).
              $ref: '#/components/schemas/Duration'
            stackable:
              type: boolean
              description: |-
                Whether this program may combine with other programs on the
                same ticket. Evaluated both ways (Part 20 §20.3 rule 3): a
                redemption is refused when the incoming program is not
                stackable and another program is already applied, or when any
                program already applied is not stackable.
            applicableRateTables:
              type: array
              description: Restrict to these APDS RateTables; absent = all tables at the place that accept validations.
              items:
                $ref: '#/components/schemas/Reference'
        billing:
          type: object
          description: How the operator charges the merchant for redemptions.
          required:
            - model
          properties:
            model:
              type: string
              enum:
                - merchantPays
                - operatorAbsorbs
                - split
            unitPrice:
              description: What the merchant pays per redemption (merchantPays), or the base for `merchantShare` (split). Absent = billed at the actual amount reduced.
              $ref: '#/components/schemas/AmountInCurrency'
            merchantShare:
              type: number
              minimum: 0
              maximum: 100
              description: Percentage of the amount reduced the merchant pays under `split`.
            billingCycle:
              type: string
              enum:
                - monthly
                - weekly
                - perRedemption
        issuanceMethods:
          type: array
          description: Instrument forms this program may issue.
          items:
            type: string
            enum:
              - code
              - qrCode
              - stamp
              - digital
              - api
        statusHistory:
          type: array
          description: Immutable, append-only lifecycle audit (Part 4 §4.2).
          items:
            type: object
            required:
              - state
              - time
              - actor
            properties:
              state:
                type: string
              time:
                $ref: '#/components/schemas/DateTime'
              actor:
                type: string
              detail:
                type: string
        recordInfo:
          $ref: '#/components/schemas/RecordInfo'
        extensions:
          $ref: '#/components/schemas/Extensions'
      examples:
        - id: e5000000-0000-4000-8000-000000000001
          version: 1
          place:
            id: b1000000-0000-4000-8000-000000000001
            className: Place
          provider:
            id: a2000000-0000-4000-8000-000000000077
            className: Organisation
          name: Harbor Bistro
          validationType: twoHourComp
          programStatus: active
          benefit:
            description: First two hours comped
            duration: PT2H
          rules:
            maxPerTicket: 1
            maxPerDay: 200
            validityWindow: P1D
            stackable: false
          billing:
            model: merchantPays
            unitPrice:
              currencyType: USD
              currencyValue: 4
            billingCycle: monthly
          issuanceMethods:
            - qrCode
          statusHistory:
            - state: active
              time: '2026-09-01T15:02:11Z'
              actor: backoffice-jlee
              detail: enrolled
    ValidationIssuance:
      title: ValidationIssuance
      description: |-
        A batch of validation instruments issued to a program — printed codes,
        QR codes, stamp stock, digital tokens. `codes[]` is returned EXACTLY
        ONCE, in the creation response (the webhook-secret convention, Part 8
        §8.1); later reads omit it. `stamp` and `api` batches carry no codes.
      type: object
      required:
        - id
        - version
        - program
        - quantity
        - method
        - issuanceStatus
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
        version:
          type: integer
          minimum: 1
          readOnly: true
        program:
          $ref: '#/components/schemas/Reference'
        quantity:
          type: integer
          minimum: 1
        method:
          type: string
          enum:
            - code
            - qrCode
            - stamp
            - digital
            - api
        validFrom:
          $ref: '#/components/schemas/DateTime'
        validTo:
          description: Expiry of every instrument in the batch; defaults from the program's `rules.validityWindow`.
          $ref: '#/components/schemas/DateTime'
        issuedTo:
          type: string
          description: Opaque principal or merchant contact the stock was handed to.
        codes:
          type: array
          readOnly: true
          description: The instrument codes — present ONLY in the creation response.
          items:
            type: string
        issuanceStatus:
          type: string
          enum:
            - issued
            - void
          readOnly: true
          description: '`void` after `POST …/issuances/{issuanceId}/void` (Part 20 §20.2 rule 5).'
        voidDetail:
          $ref: '#/components/schemas/ValidationVoidDetail'
        note:
          type: string
        recordInfo:
          $ref: '#/components/schemas/RecordInfo'
        extensions:
          $ref: '#/components/schemas/Extensions'
      examples:
        - id: e6000000-0000-4000-8000-000000000003
          version: 1
          program:
            id: e5000000-0000-4000-8000-000000000001
            className: ValidationProgram
          quantity: 50
          method: qrCode
          validFrom: '2026-09-12T17:00:00Z'
          validTo: '2026-09-13T17:00:00Z'
          issuedTo: front-of-house
          codes:
            - HB-7Q2M-K9X4-3TPD
            - HB-A1C8-ZR5N-W6LJ
            - HB-P0V3-E7HS-M2QY
          issuanceStatus: issued
    ValidationInstrument:
      title: ValidationInstrument
      description: The current state of one validation code — the pay-station / merchant-app "is this code good?" read.
      type: object
      required:
        - code
        - program
        - instrumentStatus
      properties:
        code:
          type: string
        program:
          $ref: '#/components/schemas/Reference'
        issuance:
          $ref: '#/components/schemas/Reference'
        instrumentStatus:
          type: string
          enum:
            - valid
            - redeemed
            - void
            - expired
        validFrom:
          $ref: '#/components/schemas/DateTime'
        validTo:
          $ref: '#/components/schemas/DateTime'
        benefit:
          description: What redeeming this code is worth (from the program), so a pay station can show it before applying.
          $ref: '#/components/schemas/ValidationBenefit'
        redemption:
          description: The ValidationRedemption that consumed the code, when `redeemed`.
          $ref: '#/components/schemas/Reference'
        voidDetail:
          $ref: '#/components/schemas/ValidationVoidDetail'
        extensions:
          $ref: '#/components/schemas/Extensions'
      examples:
        - code: HB-7Q2M-K9X4-3TPD
          program:
            id: e5000000-0000-4000-8000-000000000001
            className: ValidationProgram
          issuance:
            id: e6000000-0000-4000-8000-000000000003
            className: ValidationIssuance
          instrumentStatus: valid
          validFrom: '2026-09-12T17:00:00Z'
          validTo: '2026-09-13T17:00:00Z'
          benefit:
            description: First two hours comped
            duration: PT2H
    ValidationRedemption:
      title: ValidationRedemption
      description: |-
        One validation applied to one ticket/session — the ledger entry every
        channel writes: a pay station scanning a code, a merchant app, an
        agent's `applyValidation` command (Part 6), or a lane device. `validationId`
        is the APDS `Segment.validationId`, so APDS consumers see the same
        redemption without speaking APX. `amountReduced` is the ACTUAL value
        removed from the amount due (dispute evidence), never the nominal benefit.
      type: object
      required:
        - id
        - version
        - program
        - place
        - appliedTime
        - channel
        - redemptionStatus
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
        version:
          type: integer
          minimum: 1
          readOnly: true
        program:
          $ref: '#/components/schemas/Reference'
        place:
          $ref: '#/components/schemas/Reference'
        instrumentCode:
          type: string
          description: The code redeemed, when the channel used one.
        ticketNumber:
          type: string
        session:
          $ref: '#/components/schemas/Reference'
        appliedTime:
          $ref: '#/components/schemas/DateTime'
        channel:
          type: string
          enum:
            - lane
            - payStation
            - merchantApp
            - callCenter
            - api
        appliedBy:
          type: string
          description: Opaque principal (device id, merchant user, agent id).
        command:
          description: The Part 6 Command that applied it, when the channel was `callCenter`/`api` via `applyValidation`.
          $ref: '#/components/schemas/Reference'
        validationId:
          type: string
          readOnly: true
          description: The APDS Segment.validationId materialized on the session.
        amountReduced:
          description: Actual reduction of the amount due.
          $ref: '#/components/schemas/AmountInCurrency'
        durationComped:
          $ref: '#/components/schemas/Duration'
        redemptionStatus:
          type: string
          enum:
            - applied
            - reversed
          readOnly: true
        reversal:
          type: object
          readOnly: true
          properties:
            reason:
              type: string
            note:
              type: string
            time:
              $ref: '#/components/schemas/DateTime'
            actor:
              type: string
            closedStatement:
              description: |-
                When the redemption was already billed on a closed statement:
                that statement. It is not edited; the correction is a credit
                line on the next closed statement (Part 20 §20.4).
              $ref: '#/components/schemas/Reference'
            creditedOn:
              description: The closed statement carrying the credit line for this reversal; absent until that period closes.
              $ref: '#/components/schemas/Reference'
        statusHistory:
          type: array
          description: Immutable, append-only lifecycle audit (Part 4 §4.2).
          items:
            type: object
            required:
              - state
              - time
              - actor
            properties:
              state:
                type: string
              time:
                $ref: '#/components/schemas/DateTime'
              actor:
                type: string
              detail:
                type: string
        recordInfo:
          $ref: '#/components/schemas/RecordInfo'
        extensions:
          $ref: '#/components/schemas/Extensions'
      examples:
        - id: e7000000-0000-4000-8000-000000000041
          version: 1
          program:
            id: e5000000-0000-4000-8000-000000000001
            className: ValidationProgram
          place:
            id: b1000000-0000-4000-8000-000000000001
            className: Place
          instrumentCode: HB-7Q2M-K9X4-3TPD
          ticketNumber: T-2210
          session:
            id: f1000000-0000-4000-8000-000000000210
            className: Session
          appliedTime: '2026-09-12T21:33:05Z'
          channel: payStation
          appliedBy: paystation-b2000000-0007
          validationId: VAL-20260912-000318
          amountReduced:
            currencyType: USD
            currencyValue: 6
          durationComped: PT2H
          redemptionStatus: applied
          statusHistory:
            - state: applied
              time: '2026-09-12T21:33:05Z'
              actor: paystation-b2000000-0007
              detail: T-2210 amount due 9.00 → 3.00
    ValidationRedemptionReversal:
      title: ValidationRedemptionReversal
      description: Request body reversing a redemption (wrong ticket, merchant dispute, fraud).
      type: object
      required:
        - reason
      properties:
        reason:
          type: string
          description: Implementer code list.
          examples:
            - wrongTicket
        note:
          type: string
    ValidationStatementClose:
      title: ValidationStatementClose
      description: Request body closing a billing period for a program.
      type: object
      required:
        - periodStart
        - periodEnd
      properties:
        periodStart:
          $ref: '#/components/schemas/DateTime'
        periodEnd:
          $ref: '#/components/schemas/DateTime'
        note:
          type: string
    ValidationStatement:
      title: ValidationStatement
      description: |-
        A program's redemptions and billable total for a period. Returned
        as a computed preview by `GET …/statement`, and as an IMMUTABLE
        record once a period is closed by `POST …/statements` (`statementStatus:
        closed`; the operator's accounting system invoices from it). Closed
        periods MUST NOT overlap (409 `statement-overlap`).
      type: object
      required:
        - program
        - periodStart
        - periodEnd
        - redemptionCount
        - billableAmount
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
          description: Present only on closed statements.
        version:
          type: integer
          minimum: 1
          readOnly: true
        program:
          $ref: '#/components/schemas/Reference'
        place:
          $ref: '#/components/schemas/Reference'
        periodStart:
          $ref: '#/components/schemas/DateTime'
        periodEnd:
          $ref: '#/components/schemas/DateTime'
        statementStatus:
          type: string
          enum:
            - preview
            - closed
          readOnly: true
        billingModel:
          type: string
          enum:
            - merchantPays
            - operatorAbsorbs
            - split
        redemptionCount:
          type: integer
          minimum: 0
          description: Applied redemptions in the period (reversed ones excluded).
        reversedCount:
          type: integer
          minimum: 0
        totalReduced:
          description: Sum of `amountReduced` over applied redemptions.
          $ref: '#/components/schemas/AmountInCurrency'
        billableAmount:
          description: |-
            What the merchant owes for the period under the program's billing
            model, net of any `credit` lines (reversals of redemptions billed
            on an earlier closed statement, Part 20 §20.6).
          $ref: '#/components/schemas/AmountInCurrency'
        creditCount:
          type: integer
          minimum: 0
          description: Number of `credit` lines — post-closure reversals credited in this period.
        lines:
          type: array
          description: Per-redemption detail; MAY be omitted from list responses.
          items:
            type: object
            required:
              - redemption
              - appliedTime
            properties:
              lineKind:
                type: string
                enum:
                  - redemption
                  - credit
                description: |-
                  `redemption` (default when absent) — a redemption applied in
                  the period. `credit` — a redemption billed on an earlier
                  closed statement and reversed since; `billable` is negative.
              redemption:
                $ref: '#/components/schemas/Reference'
              appliedTime:
                $ref: '#/components/schemas/DateTime'
              originalStatement:
                description: For a `credit` line, the closed statement that billed the redemption.
                $ref: '#/components/schemas/Reference'
              ticketNumber:
                type: string
              amountReduced:
                $ref: '#/components/schemas/AmountInCurrency'
              billable:
                $ref: '#/components/schemas/AmountInCurrency'
        closedTime:
          $ref: '#/components/schemas/DateTime'
        closedBy:
          type: string
        note:
          type: string
        recordInfo:
          $ref: '#/components/schemas/RecordInfo'
        extensions:
          $ref: '#/components/schemas/Extensions'
      examples:
        - id: e8000000-0000-4000-8000-000000000009
          version: 1
          program:
            id: e5000000-0000-4000-8000-000000000001
            className: ValidationProgram
          place:
            id: b1000000-0000-4000-8000-000000000001
            className: Place
          periodStart: '2026-09-01T00:00:00Z'
          periodEnd: '2026-10-01T00:00:00Z'
          statementStatus: closed
          billingModel: merchantPays
          redemptionCount: 412
          reversedCount: 3
          totalReduced:
            currencyType: USD
            currencyValue: 2418
          billableAmount:
            currencyType: USD
            currencyValue: 1648
          lines:
            - redemption:
                id: e7000000-0000-4000-8000-000000000041
                className: ValidationRedemption
              appliedTime: '2026-09-12T21:33:05Z'
              ticketNumber: T-2210
              amountReduced:
                currencyType: USD
                currencyValue: 6
              billable:
                currencyType: USD
                currencyValue: 4
          closedTime: '2026-10-01T09:00:12Z'
          closedBy: backoffice-jlee
    CredentialRecord:
      title: CredentialRecord
      description: |-
        One access credential — keycard, fob, RFID tag or transponder, mobile
        credential, hangtag, or a plate used as the credential — with its
        holder, validity, physical media, and lifecycle. `credentialType` is
        the APDS read technology; `media.form` is the physical form.

        Lifecycle (Part 21 §21.1): `issued → active`, `active ⇄ suspended`,
        `active | suspended → lost | revoked | expired`, and `replace`
        creates a successor while this record becomes `replaced`.
        `revoked`, `expired`, and `replaced` are terminal; `lost` may still be
        `replace`d or `revoke`d.
      type: object
      required:
        - id
        - version
        - credentialType
        - credentialIdentification
        - credentialStatus
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
        version:
          type: integer
          minimum: 1
          readOnly: true
        credentialType:
          description: The APDS read technology (rfid, bluetooth, electronicID, hangtag, licensePlate…).
          $ref: '#/components/schemas/CredentialTypeEnum'
        credentialIdentification:
          type: string
          description: |-
            The value the lane reads — card number, tag id, plate. Unique per
            (credentialType) within the implementation among non-terminal
            records; a collision is 409 `credential-identification-in-use`
            whose `detail` MUST NOT identify the holding record, its holder, or
            its place (Part 21 §21.1 rule 2, §21.5).
          examples:
            - C-0048812
        credentialAssignedType:
          type: string
          enum:
            - vehicle
            - customer
            - other
          description: APDS CredentialAssignedTypeEnum — what the credential identifies.
        holder:
          description: The APDS RightHolder (or Contact) the credential is issued to.
          $ref: '#/components/schemas/Reference'
        account:
          description: The APX Account (Part 13) this credential belongs to, when the holder is a billable account.
          $ref: '#/components/schemas/Reference'
        assignedRights:
          type: array
          description: The APDS AssignedRights this credential is materialized on (Part 21 §21.2).
          items:
            $ref: '#/components/schemas/Reference'
        places:
          type: array
          description: HierarchyElement subtree roots this credential is valid at.
          items:
            $ref: '#/components/schemas/Reference'
        validity:
          type: object
          description: |-
            When the credential may be used. `end`, when given, MUST be in the
            future at issue and after `start`; otherwise the issue is 422
            `request-unprocessable` (Part 21 §21.1 rule 7).
          properties:
            start:
              $ref: '#/components/schemas/DateTime'
            end:
              $ref: '#/components/schemas/DateTime'
        activateOnStart:
          type: boolean
          default: false
          description: |-
            When true, the server moves the record `issued → active` by itself
            at `validity.start` (or at issue, when `validity.start` is absent or
            already past), with actor `system`, and publishes
            `apx.credentials.status.v1` (Part 21 §21.1 rule 6). When false or
            absent the record stays `issued` until `activate` is called — the
            card handed over at the desk.
        media:
          type: object
          description: The physical (or virtual) form the credential was issued on.
          properties:
            form:
              type: string
              enum:
                - physicalCard
                - fob
                - transponder
                - hangtag
                - mobile
                - plate
                - ticket
                - virtual
            serialNumber:
              type: string
              description: Manufacturer or stock serial of the physical item (distinct from `credentialIdentification`).
            batch:
              type: string
              description: Stock batch or print run.
            issuedTime:
              $ref: '#/components/schemas/DateTime'
            deposit:
              description: Deposit taken for the physical item.
              $ref: '#/components/schemas/AmountInCurrency'
            depositStatus:
              type: string
              enum:
                - held
                - refunded
                - forfeited
        credentialStatus:
          type: string
          enum:
            - issued
            - active
            - suspended
            - lost
            - revoked
            - expired
            - replaced
          readOnly: true
        suspension:
          type: object
          readOnly: true
          description: Present while `suspended`.
          properties:
            reason:
              type: string
            until:
              $ref: '#/components/schemas/DateTime'
        replaces:
          description: The CredentialRecord this one succeeded.
          $ref: '#/components/schemas/Reference'
        replacedBy:
          description: The successor, when `replaced`.
          readOnly: true
          $ref: '#/components/schemas/Reference'
        statusHistory:
          type: array
          description: Immutable, append-only lifecycle audit (Part 4 §4.2).
          items:
            type: object
            required:
              - state
              - time
              - actor
            properties:
              state:
                type: string
              time:
                $ref: '#/components/schemas/DateTime'
              actor:
                type: string
              detail:
                type: string
        recordInfo:
          $ref: '#/components/schemas/RecordInfo'
        extensions:
          $ref: '#/components/schemas/Extensions'
      examples:
        - id: d6000000-0000-4000-8000-000000000102
          version: 1
          credentialType: rfid
          credentialIdentification: C-0051207
          credentialAssignedType: customer
          holder:
            id: c1000000-0000-4000-8000-000000000102
            className: RightHolder
          account:
            id: 7a8b9c0d-1e2f-4a3b-8c4d-5e6f7a8b9c0d
            className: Account
          assignedRights:
            - id: e1000000-0000-4000-8000-000000000102
              className: AssignedRight
          places:
            - id: b1000000-0000-4000-8000-000000000001
              className: Place
          validity:
            start: '2026-01-01T00:00:00Z'
            end: '2026-12-31T23:59:59Z'
          media:
            form: physicalCard
            serialNumber: HID-77A3-006903
            batch: 2026-Q3-A
            issuedTime: '2026-09-19T12:04:20Z'
            deposit:
              currencyType: USD
              currencyValue: 25
            depositStatus: held
          credentialStatus: active
          replaces:
            id: d6000000-0000-4000-8000-000000000101
            className: CredentialRecord
          statusHistory:
            - state: issued
              time: '2026-09-19T12:04:20Z'
              actor: agent-0212
              detail: replacement for d6000000-…-0101 (lost)
            - state: active
              time: '2026-09-19T12:04:20Z'
              actor: agent-0212
    CredentialTransition:
      title: CredentialTransition
      description: Request body for activate / suspend / resume / report-lost / revoke.
      type: object
      required:
        - reason
      properties:
        reason:
          type: string
          description: Implementer code list (nonPayment, holderRequest, securityIncident, stolen…).
          examples:
            - holderRequest
        note:
          type: string
        until:
          description: For `suspend` — automatic resume time; absent = until resumed. MUST be in the future; a past `until` is 422 `request-unprocessable` (Part 21 §21.1 rule 7).
          $ref: '#/components/schemas/DateTime'
    CredentialReplaceRequest:
      title: CredentialReplaceRequest
      description: |-
        Request body issuing a successor credential. The new record inherits
        holder, account, assigned rights, places, and validity unless
        overridden; the old record becomes `replaced` and is removed from the
        APDS AssignedRights at the same instant the successor is materialized.
      type: object
      required:
        - reason
      properties:
        reason:
          type: string
          description: Implementer code list (lost, stolen, damaged, upgrade, reissue).
          examples:
            - lost
        credentialType:
          description: Successor read technology; defaults to the old record's.
          $ref: '#/components/schemas/CredentialTypeEnum'
        credentialIdentification:
          type: string
          description: Successor identification; server-assigned when absent (pre-encoded stock).
        media:
          type: object
          description: Successor media; same shape as `CredentialRecord.media`.
          properties:
            form:
              type: string
              enum:
                - physicalCard
                - fob
                - transponder
                - hangtag
                - mobile
                - plate
                - ticket
                - virtual
            serialNumber:
              type: string
            batch:
              type: string
            deposit:
              $ref: '#/components/schemas/AmountInCurrency'
        oldDepositStatus:
          type: string
          enum:
            - held
            - refunded
            - forfeited
          description: What happens to the old record's deposit.
        note:
          type: string
    CredentialAccessEvent:
      title: CredentialAccessEvent
      description: |-
        One access attempt with a credential at a lane — granted or denied,
        and why. Fills the gap that APDS EventTypeEnum has no access events
        (published as `apx.credentials.access.v1`).
      type: object
      required:
        - credential
        - occurredAt
        - direction
        - outcome
      properties:
        id:
          type: string
          format: uuid
        credential:
          $ref: '#/components/schemas/Reference'
        occurredAt:
          $ref: '#/components/schemas/DateTime'
        place:
          $ref: '#/components/schemas/Reference'
        lane:
          description: The VehicularAccess where the attempt occurred.
          $ref: '#/components/schemas/Reference'
        device:
          description: The reader (SupplementalEquipment).
          $ref: '#/components/schemas/Reference'
        direction:
          type: string
          enum:
            - entry
            - exit
        outcome:
          type: string
          enum:
            - granted
            - denied
        denialReason:
          type: string
          description: When denied — definedValue from `apx-access-denial-reasons` or an implementer code list (Part 11). The `credential*` values mirror the non-active lifecycle states.
          examples:
            - credentialReplaced
        session:
          description: The APDS Session opened or closed by a granted access.
          $ref: '#/components/schemas/Reference'
        presented:
          $ref: '#/components/schemas/PresentedCredential'
        extensions:
          $ref: '#/components/schemas/Extensions'
      examples:
        - id: d7000000-0000-4000-8000-000000000410
          credential:
            id: d6000000-0000-4000-8000-000000000101
            className: CredentialRecord
          occurredAt: '2026-09-19T18:02:17Z'
          place:
            id: b1000000-0000-4000-8000-000000000001
            className: Place
          lane:
            id: b2000000-0000-4000-8000-000000000001
            className: VehicularAccess
          device:
            id: b2000000-0000-4000-8000-000000000011
            className: SupplementalEquipment
          direction: entry
          outcome: denied
          denialReason: credentialReplaced
    ConditionReport:
      title: ConditionReport
      description: |-
        The vehicle's condition as recorded by an attendant (or a scanning
        device) at drop-off or handback: free-text notes, per-area damage
        entries, and access-controlled image links (Part 9 §9.6). The
        drop-off report is the evidence a damage claim is answered with.
      type: object
      properties:
        notes:
          type: string
          description: Free-text observations.
          examples:
            - Scuff on rear bumper, driver side; interior clean.
        damage:
          type: array
          description: Structured damage entries, one per finding.
          items:
            type: object
            required:
              - area
            properties:
              area:
                type: string
                description: Implementer code list — frontBumper, rearBumper, driverDoor, passengerDoor, hood, roof, trunk, wheelFL/FR/RL/RR, windshield, interior…
                examples:
                  - rearBumper
              description:
                type: string
              severity:
                type: string
                enum:
                  - minor
                  - moderate
                  - major
              imageLink:
                $ref: '#/components/schemas/Url'
              recordedTime:
                description: Set by the server on an entry appended after drop-off (`POST …/condition`, Part 22 §22.2 rule 3); absent on the original entries, which share the report's `recordedTime`.
                $ref: '#/components/schemas/DateTime'
              recordedBy:
                type: string
                description: Opaque principal that recorded an appended entry.
        imageLinks:
          type: array
          description: Walk-around photos or scan captures, as access-controlled links.
          items:
            $ref: '#/components/schemas/Url'
        recordedTime:
          $ref: '#/components/schemas/DateTime'
        recordedBy:
          type: string
          description: Opaque principal (attendant id, scanning device id).
        customerAcknowledged:
          type: boolean
          description: Whether the customer acknowledged the report (signature, tap, spoken confirmation).
      examples:
        - notes: Scuff on rear bumper, driver side, approx 6 cm. Interior clean.
          damage:
            - area: rearBumper
              description: 6 cm scuff, driver side
              severity: minor
              imageLink: https://api.lakeside-garage.example/valet/v-20419/in-rear-bumper.jpg
          imageLinks:
            - https://api.lakeside-garage.example/valet/v-20419/in-front.jpg
            - https://api.lakeside-garage.example/valet/v-20419/in-driver.jpg
            - https://api.lakeside-garage.example/valet/v-20419/in-rear.jpg
            - https://api.lakeside-garage.example/valet/v-20419/in-passenger.jpg
          recordedTime: '2026-09-20T18:30:02Z'
          recordedBy: scanner-0031
          customerAcknowledged: true
    ValetTicket:
      title: ValetTicket
      description: |-
        The custody record for one valeted vehicle: drop-off (with condition
        evidence), where it is parked and where the keys are, the retrieval
        request and its ETA, staging, and handback — with the immutable
        lifecycle audit. The APDS Session remains the stay and the money;
        this record is what the attendant board, the customer's phone, and a
        damage claim look at.

        Lifecycle (Part 22 §22.1): `dropped → parked → requested → retrieving
        (pickup) → staged → handedBack → closed`; `cancel-retrieval` returns
        `requested | retrieving` to `parked`; `park` re-parks a `staged` car;
        `dropped → handedBack` is allowed before the car moves; `closed` is
        server-side when the stay settles. `cancel` moves a `dropped` ticket
        to the terminal `cancelled` (custody never taken).

        As a create body: `storage`, `retrieval`, `handback`, `statusHistory`,
        and `recordInfo` are server-written — a server MUST ignore values a
        client sends for them (Part 22 §22.1 rule 5). `session` and
        `assignedRight` MAY be sent when the operator opened them first.
      type: object
      required:
        - id
        - version
        - place
        - valetStatus
        - dropOff
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
        version:
          type: integer
          minimum: 1
          readOnly: true
        place:
          description: The HierarchyElement (the facility or valet stand).
          $ref: '#/components/schemas/Reference'
        session:
          description: The APDS Session for the stay (opened at drop-off).
          $ref: '#/components/schemas/Reference'
        assignedRight:
          description: The APDS AssignedRight (the valet ticket as a right), when the operator issues one.
          $ref: '#/components/schemas/Reference'
        ticketNumber:
          type: string
          description: The number printed on the claim ticket / shown in the app.
          examples:
            - V-20419
        vehicle:
          type: object
          properties:
            credentialType:
              $ref: '#/components/schemas/CredentialTypeEnum'
            credentialIdentification:
              type: string
              description: The plate (or other credential) read at drop-off.
              examples:
                - SYN-7734
            jurisdiction:
              type: string
            make:
              type: string
            model:
              type: string
            colour:
              type: string
            description:
              type: string
        customer:
          type: object
          description: Who the car belongs to — minimized (Part 9 §9.6); enough to verify at handback and reach them for ETA.
          properties:
            contact:
              $ref: '#/components/schemas/Reference'
            account:
              description: The APX Account (Part 13), for members and hotel guests on file.
              $ref: '#/components/schemas/Reference'
            displayName:
              type: string
            contactChannel:
              type: object
              description: How to reach the customer about retrieval; the handle is opaque/masked — no telephony in the contract.
              properties:
                type:
                  type: string
                  enum:
                    - sms
                    - app
                    - web
                    - voice
                    - email
                    - none
                handle:
                  type: string
                  description: Opaque or masked handle (push token id, masked number).
        dropOff:
          type: object
          required:
            - time
          properties:
            time:
              $ref: '#/components/schemas/DateTime'
            lane:
              description: The VehicularAccess or valet stand where custody was taken.
              $ref: '#/components/schemas/Reference'
            attendant:
              type: string
              description: Opaque principal.
            mileage:
              type: integer
              minimum: 0
            fuelLevelPercent:
              type: number
              minimum: 0
              maximum: 100
            keyTag:
              type: string
              description: The key hook / tag identifier.
            itemsLeft:
              type: string
              description: Declared items left in the vehicle.
            conditionReport:
              $ref: '#/components/schemas/ConditionReport'
        storage:
          type: object
          description: Where the vehicle and its keys are.
          properties:
            space:
              description: The APDS Space, when the facility is space-mapped.
              $ref: '#/components/schemas/Reference'
            zone:
              type: string
              description: Zone/row/level text for facilities that are not space-mapped.
              examples:
                - P3 row D
            keyLocation:
              type: string
              examples:
                - board-2 hook 17
            parkedTime:
              $ref: '#/components/schemas/DateTime'
            parkedBy:
              type: string
        retrieval:
          type: object
          description: The current (or last) retrieval request.
          properties:
            requestedTime:
              $ref: '#/components/schemas/DateTime'
            requestedFor:
              description: A scheduled pickup time; absent = as soon as possible.
              $ref: '#/components/schemas/DateTime'
            channel:
              type: string
              enum:
                - sms
                - app
                - web
                - voiceBot
                - kiosk
                - attendant
                - callCenter
            requestedBy:
              type: string
              description: Opaque principal (customer handle, attendant, bot id).
            interaction:
              type: string
              description: Opaque interaction id (Part 17 §17.6 convention) linking to the support interaction that raised it, if any.
            etaMinutes:
              type: integer
              minimum: 0
              description: Whole minutes from now until `promisedTime`, never negative — `max(0, floor(promisedTime − now))` — recomputed on every read and event (Part 22 §22.3 rule 1). For a scheduled pickup it counts down to `requestedFor`.
            promisedTime:
              description: When the car is promised at the staging lane — `requestedFor` when scheduled, else `requestedTime` plus the operator's estimate.
              $ref: '#/components/schemas/DateTime'
            retrievingBy:
              type: string
              description: Opaque principal of the runner fetching the car (set by `pickup`).
            stagingLane:
              $ref: '#/components/schemas/Reference'
            stagedTime:
              $ref: '#/components/schemas/DateTime'
            cancelledTime:
              $ref: '#/components/schemas/DateTime'
            cancelReason:
              type: string
        handback:
          type: object
          readOnly: true
          properties:
            time:
              $ref: '#/components/schemas/DateTime'
            handedTo:
              type: string
              description: Opaque description of the recipient as verified.
            verificationMethod:
              type: string
              enum:
                - ticket
                - phone
                - code
                - id
                - attendant
            attendant:
              type: string
            mileage:
              type: integer
              minimum: 0
            conditionReport:
              $ref: '#/components/schemas/ConditionReport'
            notes:
              type: string
        charging:
          type: object
          description: |-
            Part 23 §23.8 — the guest asked the valet to charge
            the car. Additive and optional; the charge itself is a Part 23
            ChargingSession referenced here once the valet plugs in.
          properties:
            requested:
              type: boolean
              description: The customer asked for the vehicle to be charged during the stay.
            targetStateOfChargePercent:
              type: number
              minimum: 0
              maximum: 100
            instructions:
              type: string
              description: Free text from the customer (charge port side, adapter in trunk…).
            session:
              description: The Part 23 ChargingSession the valet opened.
              $ref: '#/components/schemas/Reference'
        valetStatus:
          type: string
          enum:
            - dropped
            - parked
            - requested
            - retrieving
            - staged
            - handedBack
            - closed
            - cancelled
          readOnly: true
        statusHistory:
          type: array
          description: Immutable, append-only lifecycle audit (Part 4 §4.2).
          items:
            type: object
            required:
              - state
              - time
              - actor
            properties:
              state:
                type: string
              time:
                $ref: '#/components/schemas/DateTime'
              actor:
                type: string
              detail:
                type: string
        recordInfo:
          $ref: '#/components/schemas/RecordInfo'
        extensions:
          $ref: '#/components/schemas/Extensions'
      examples:
        - id: d8000000-0000-4000-8000-000000000419
          version: 3
          place:
            id: b1000000-0000-4000-8000-000000000005
            className: Place
          ticketNumber: V-20419
          vehicle:
            credentialType: licensePlate
            credentialIdentification: SYN-7734
            make: Audi
            colour: grey
          dropOff:
            time: '2026-09-20T18:30:14Z'
          retrieval:
            requestedTime: '2026-09-20T20:41:03Z'
            channel: sms
            requestedBy: customer
            etaMinutes: 8
            promisedTime: '2026-09-20T20:49:03Z'
          valetStatus: requested
          statusHistory:
            - state: dropped
              time: '2026-09-20T18:30:14Z'
              actor: attendant-0031
            - state: parked
              time: '2026-09-20T18:36:40Z'
              actor: runner-0107
            - state: requested
              time: '2026-09-20T20:41:03Z'
              actor: customer
              detail: channel sms; eta 8 min
    ValetParkRequest:
      title: ValetParkRequest
      description: Request body recording where the vehicle was parked and where its keys are.
      type: object
      properties:
        space:
          $ref: '#/components/schemas/Reference'
        zone:
          type: string
        keyLocation:
          type: string
        note:
          type: string
    ValetRetrievalRequest:
      title: ValetRetrievalRequest
      description: Request body asking for the car — from the customer (text, app, web, voice bot) or an attendant.
      type: object
      required:
        - channel
      properties:
        channel:
          type: string
          enum:
            - sms
            - app
            - web
            - voiceBot
            - kiosk
            - attendant
            - callCenter
        requestedFor:
          description: Scheduled pickup; absent = as soon as possible.
          $ref: '#/components/schemas/DateTime'
        interaction:
          type: string
          description: Opaque interaction id (Part 17 §17.6) when raised through a support channel or bot.
        note:
          type: string
    ValetCancelRetrievalRequest:
      title: ValetCancelRetrievalRequest
      description: Request body cancelling an open retrieval request; the vehicle returns to `parked`.
      type: object
      required:
        - reason
      properties:
        reason:
          type: string
          examples:
            - customerDelayed
        note:
          type: string
    ValetStageRequest:
      title: ValetStageRequest
      description: Request body recording the vehicle at the staging lane, ready for handback.
      type: object
      required:
        - stagingLane
      properties:
        stagingLane:
          $ref: '#/components/schemas/Reference'
        note:
          type: string
    ValetHandbackRequest:
      title: ValetHandbackRequest
      description: Request body handing the vehicle to a verified customer, with the handback condition report.
      type: object
      required:
        - verificationMethod
      properties:
        verificationMethod:
          type: string
          enum:
            - ticket
            - phone
            - code
            - id
            - attendant
        verificationValue:
          type: string
          description: What was presented (ticket number, one-time code…); never stored beyond the check.
        handedTo:
          type: string
        mileage:
          type: integer
          minimum: 0
        conditionReport:
          $ref: '#/components/schemas/ConditionReport'
        notes:
          type: string
    ChargingBayPresence:
      title: ChargingBayPresence
      description: |-
        Part 23 — what the bay in front of a charging point physically contains, as
        observed by an overhead camera, a ground sensor, the charger's own
        connector state, or an attendant — fused by the server (Part 23 §23.3).
        Distinguishes the cases the charger alone cannot: a vehicle parked in
        the bay but not plugged in (an ICE vehicle, or an EV not charging), and
        a bay blocked by something that is not a vehicle. Also the request body
        a camera analytics system POSTs to `…/points/{id}/bay`.
      type: object
      required:
        - presence
      properties:
        presence:
          type: string
          enum:
            - empty
            - vehiclePluggedIn
            - vehicleNotPluggedIn
            - blocked
            - unknown
          description: |-
            `empty` — nothing in the bay; `vehiclePluggedIn` — a vehicle is
            present and the charger reports a connected cable;
            `vehicleNotPluggedIn` — a vehicle is present and no cable is
            connected (ICE-ing, or an EV not charging); `blocked` — the bay is
            obstructed by something other than a parked vehicle (cones,
            debris, a vehicle straddling); `unknown`.
        source:
          type: string
          enum:
            - overheadCamera
            - groundSensor
            - charger
            - attendant
            - inferred
          description: The evidence source this presence state was derived from (the strongest one, when fused).
        observation:
          description: The APDS Observation carrying the camera/sensor evidence (Part 13 §13.3 conventions).
          $ref: '#/components/schemas/Reference'
        observedTime:
          $ref: '#/components/schemas/DateTime'
        sinceTime:
          description: When the current presence state began — the dwell clock for not-plugged-in and idle handling.
          $ref: '#/components/schemas/DateTime'
        vehicle:
          type: object
          description: The vehicle seen in the bay, minimized (Part 9 §9.6). Omitted on the customer scope.
          properties:
            credentialType:
              $ref: '#/components/schemas/CredentialTypeEnum'
            credentialIdentification:
              type: string
              description: The plate read, when the camera has LPR.
              examples:
                - SYN-7734
            jurisdiction:
              type: string
            evCapable:
              type:
                - boolean
                - 'null'
              description: |-
                Whether the vehicle appears able to charge (make/model or badge
                recognition) — `false` is the ICE-in-EV-bay signal; `null` when
                unknown.
        confidence:
          type: number
          minimum: 0
          maximum: 1
          description: The analytics system's confidence in `presence`.
        imageLink:
          description: Access-controlled evidence image (Part 9 §9.6), never inline.
          $ref: '#/components/schemas/Url'
        detail:
          type: string
    ChargingPointStatus:
      title: ChargingPointStatus
      description: |-
        Part 23 — live state overlay keyed by Reference to an APDS ElectricChargingEquipment
        — the dynamic counterpart of the static ElectricChargingPoint (APDS
        `refillPointIndex` exists precisely "to link static and dynamic
        publications"). Never duplicates the static descriptive fields
        (connector types, power ratings live in APDS). Carries availability per
        point and per connector, the current session, a reservation, and what
        the bay camera sees. Same pattern as Part 6 DeviceStatus. Also the
        request body the charging-network bridge PUTs to `…/points/{id}/status`.
      type: object
      required:
        - chargingPoint
        - availability
      properties:
        chargingPoint:
          description: The APDS ElectricChargingEquipment (HierarchyElement).
          $ref: '#/components/schemas/Reference'
        place:
          description: The containing Place (event binding and place filters).
          $ref: '#/components/schemas/Reference'
        space:
          description: The APDS Space (bay) this point serves, when the facility is space-mapped.
          $ref: '#/components/schemas/Reference'
        refillPointIndex:
          type: integer
          description: The APDS RefillPoint index of the static publication this status describes.
        evseId:
          type: string
          description: The EVSE identifier as the charging network knows it (ISO 15118 / eMI3 form) — opaque bridge to OCPP/OCPI.
          examples:
            - US*LSG*E20419*1
        availability:
          type: string
          enum:
            - available
            - occupied
            - charging
            - reserved
            - blocked
            - inoperative
            - outOfOrder
            - unknown
          description: |-
            Point-level availability (the busiest connector wins): `available`;
            `occupied` — a cable is connected but no energy is flowing
            (plugged in, suspended, complete, or idle); `charging`; `reserved`
            (Part 14 AssignedRight in force); `blocked` — the bay is occupied
            or obstructed without a connected cable (from `bay.presence`);
            `inoperative` (planned: maintenance, closed hours); `outOfOrder`
            (fault); `unknown`. Aligned with the OCPI EVSE status vocabulary.
        connectors:
          type: array
          description: Per-connector availability; `connectorIndex` is the 1-based position in the static APDS `connectors[]`.
          items:
            type: object
            required:
              - connectorIndex
              - availability
            properties:
              connectorIndex:
                type: integer
                minimum: 1
              connectorType:
                description: Echo of the static APDS connector type, for consumers that do not hold the hierarchy.
                $ref: '#/components/schemas/ConnectorTypeEnum'
              availability:
                type: string
                enum:
                  - available
                  - occupied
                  - charging
                  - reserved
                  - blocked
                  - inoperative
                  - outOfOrder
                  - unknown
              currentPowerKw:
                type: number
                minimum: 0
              currentSession:
                $ref: '#/components/schemas/Reference'
        currentSession:
          description: The ChargingSession in progress at this point, if any.
          $ref: '#/components/schemas/Reference'
        reservedFor:
          description: The APDS AssignedRight (Part 14 reservation) holding this point, if any.
          $ref: '#/components/schemas/Reference'
        bay:
          $ref: '#/components/schemas/ChargingBayPresence'
        lastCommunication:
          $ref: '#/components/schemas/DateTime'
        stateChangedTime:
          $ref: '#/components/schemas/DateTime'
        extensions:
          $ref: '#/components/schemas/Extensions'
    ChargingSession:
      title: ChargingSession
      description: |-
        Part 23 — one charge of one vehicle at one charging point, as the parking system
        sees it: who was authorized and how, the timeline from plug-in to
        unplug, energy delivered, the idle period after charging completed,
        cost, and how it settles — while the APDS Session remains the parking
        stay and is only referenced. The charging network's own identifiers
        (OCPP transaction, OCPI session/CDR) ride along opaquely so the two
        records can be reconciled without APX redefining either protocol.

        Lifecycle (Part 23 §23.2 transition table): `authorized → pluggedIn →
        charging ⇄ suspended → complete → idle → unplugged → closed`;
        `unplugged` also directly from `pluggedIn` (no energy) and `complete`
        (left inside the grace); `cancelled` for an authorization never used;
        `fault` from any state before `unplugged`, exiting via `unplugged` (or
        `cancelled` if never plugged in). `idle` is server-side when
        `idlePolicy.graceMinutes` elapses after `complete`; `closed` is
        server-side on settlement.
      type: object
      required:
        - id
        - version
        - place
        - chargingPoint
        - chargingStatus
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
        version:
          type: integer
          minimum: 1
          readOnly: true
        place:
          description: The Place (facility) — event binding and grant check.
          $ref: '#/components/schemas/Reference'
        chargingPoint:
          description: The APDS ElectricChargingEquipment.
          $ref: '#/components/schemas/Reference'
        connectorIndex:
          type: integer
          minimum: 1
          description: 1-based position in the point's static APDS `connectors[]`.
        evseId:
          type: string
          description: Opaque EVSE identifier (ISO 15118 / eMI3 form).
        space:
          description: The APDS Space (bay), when space-mapped.
          $ref: '#/components/schemas/Reference'
        parkingSession:
          description: The APDS Session for the parking stay this charge happened inside. REQUIRED when `settlement.mode` is `parkingSession`.
          $ref: '#/components/schemas/Reference'
        assignedRight:
          description: The APDS AssignedRight used — a charging reservation (Part 14) or the permit that entitles charging.
          $ref: '#/components/schemas/Reference'
        valetTicket:
          description: The Part 22 ValetTicket when the valet plugged the car in.
          $ref: '#/components/schemas/Reference'
        vehicle:
          type: object
          description: Minimized (Part 9 §9.6); plate values only under `apx.charging:read`/`:manage`.
          properties:
            credentialType:
              $ref: '#/components/schemas/CredentialTypeEnum'
            credentialIdentification:
              type: string
              examples:
                - SYN-7734
            jurisdiction:
              type: string
            make:
              type: string
            model:
              type: string
        authorization:
          type: object
          description: How the charge was authorized and who is on the hook for it.
          properties:
            method:
              description: The APDS authentication/identification method (`rfid`, `apps`, `overTheAir` for ISO 15118 Plug & Charge, `creditCard`, `unlimitedAccess` for free-vend inside a controlled garage…).
              $ref: '#/components/schemas/AuthenticationAndIdentificationEnum'
            methodDetail:
              type: string
              description: Free text for methods the APDS list does not name (e.g. plate linked by LPR at entry).
              examples:
                - plate linked to parking session at entry LPR
            credential:
              description: The Part 21 CredentialRecord (or APDS CredentialAssigned) presented.
              $ref: '#/components/schemas/Reference'
            account:
              description: The Part 13 Account charged, when settlement is on account.
              $ref: '#/components/schemas/Reference'
            contractId:
              type: string
              description: The e-mobility contract id (EMAID) or roaming token, masked/opaque — never a raw payment credential.
              examples:
                - US-LSG-C****4471
            authorizedTime:
              $ref: '#/components/schemas/DateTime'
            authorizedBy:
              type: string
              description: Opaque principal (bridge id, attendant, customer).
        chargingStatus:
          type: string
          enum:
            - authorized
            - pluggedIn
            - charging
            - suspended
            - complete
            - idle
            - unplugged
            - closed
            - cancelled
            - faulted
          readOnly: true
          description: |-
            Mapping to OCPP 2.0.1 `chargingState`: `pluggedIn` = EVConnected;
            `charging` = Charging; `suspended` = SuspendedEV | SuspendedEVSE
            (see `suspendedBy`); `complete` and `idle` = EVConnected after
            energy delivery ended; `unplugged` = Idle (no EV).
        suspendedBy:
          type: string
          enum:
            - ev
            - evse
          description: 'While `suspended`: whether the vehicle or the charger paused delivery.'
        timeline:
          type: object
          readOnly: true
          properties:
            authorizedTime:
              $ref: '#/components/schemas/DateTime'
            pluggedInTime:
              $ref: '#/components/schemas/DateTime'
            chargingStartedTime:
              $ref: '#/components/schemas/DateTime'
            chargingEndedTime:
              $ref: '#/components/schemas/DateTime'
            idleStartedTime:
              description: When the grace period elapsed and idle began (server-set).
              $ref: '#/components/schemas/DateTime'
            unpluggedTime:
              $ref: '#/components/schemas/DateTime'
            closedTime:
              $ref: '#/components/schemas/DateTime'
        energy:
          type: object
          description: Energy in kilowatt-hours (APDS DeliveryUnitEnum `kWh`); meter readings in watt-hours as chargers report them.
          properties:
            meterStartWh:
              type: number
              minimum: 0
            meterStopWh:
              type: number
              minimum: 0
            deliveredKwh:
              type: number
              minimum: 0
              description: Energy delivered so far (final after `chargingEndedTime`).
            currentPowerKw:
              type: number
              minimum: 0
            peakPowerKw:
              type: number
              minimum: 0
            stateOfChargePercent:
              type: number
              minimum: 0
              maximum: 100
              description: Vehicle state of charge when the vehicle reports it (ISO 15118).
            targetStateOfChargePercent:
              type: number
              minimum: 0
              maximum: 100
              description: The customer's or valet's requested target; delivery ends when reached where the charger supports it.
            lastMeterTime:
              $ref: '#/components/schemas/DateTime'
        stopReason:
          type: string
          enum:
            - evDisconnected
            - evFull
            - targetReached
            - energyLimitReached
            - timeLimitReached
            - remote
            - local
            - deauthorized
            - emergencyStop
            - powerLoss
            - other
          description: Why energy delivery ended (OCPP 2.0.1 stopped-reason subset plus `targetReached`).
        idlePolicy:
          type: object
          description: |-
            The idle rule applied to THIS session, snapshotted at authorization
            so the customer read can say "10 minutes grace, then $0.40/min" and
            so a later policy change never re-prices a past session.
          properties:
            graceMinutes:
              type: integer
              minimum: 0
              description: Minutes after `complete` before `idle` begins.
            idleRate:
              $ref: '#/components/schemas/AmountInCurrency'
            idleRatePer:
              type: string
              enum:
                - minute
                - hour
            maxIdleMinutes:
              type: integer
              minimum: 0
              description: After this much idle the session is eligible for enforcement (Part 19) — `apx.charging.idle.started.v1` consumers act on it.
            appliesToSettlement:
              type: boolean
              description: Whether idle charges are billed by this operator (true) or by the charging network (false).
        cost:
          type: object
          description: Cost as the parking system knows it; absent components are unknown, not zero. Money is APDS AmountInCurrency.
          properties:
            energy:
              $ref: '#/components/schemas/AmountInCurrency'
            time:
              $ref: '#/components/schemas/AmountInCurrency'
            idle:
              $ref: '#/components/schemas/AmountInCurrency'
            fees:
              $ref: '#/components/schemas/AmountInCurrency'
            total:
              $ref: '#/components/schemas/AmountInCurrency'
            tariffReference:
              type: string
              description: Opaque id of the charging network's tariff in force.
            pricedAt:
              $ref: '#/components/schemas/DateTime'
        settlement:
          type: object
          description: How the cost is collected (Part 23 §23.5).
          properties:
            mode:
              type: string
              enum:
                - parkingSession
                - directPayment
                - chargingNetwork
              description: |-
                `parkingSession` — the cost becomes a line on the APDS Session
                and is paid with the parking (one bill at exit);
                `directPayment` — settled by a Part 13 payment referenced in
                `payment`; `chargingNetwork` — billed by the charging network
                or roaming partner; the parking side records energy and idle
                but not money.
            payment:
              description: The settling APDS Payment / APX PaymentRecord (`directPayment`).
              $ref: '#/components/schemas/Reference'
            settledTime:
              $ref: '#/components/schemas/DateTime'
            externalReference:
              type: string
              description: The charging network's charge detail record id (OCPI CDR) once issued — opaque.
        network:
          type: object
          description: The charging network behind the point, and its identifiers for this charge — opaque bridge fields, never interpreted by APX.
          properties:
            operator:
              description: The charge point operator — a Reference to the operator's contact/organisation record, as Part 20 references a merchant.
              $ref: '#/components/schemas/Reference'
            partyId:
              type: string
              description: Roaming party id (country code + party id form).
              examples:
                - US-LSG
            ocppTransactionId:
              type: string
            ocpiSessionId:
              type: string
        statusHistory:
          type: array
          description: Immutable, append-only lifecycle audit (Part 4 §4.2).
          items:
            type: object
            required:
              - state
              - time
              - actor
            properties:
              state:
                type: string
              time:
                $ref: '#/components/schemas/DateTime'
              actor:
                type: string
              detail:
                type: string
        recordInfo:
          $ref: '#/components/schemas/RecordInfo'
        extensions:
          $ref: '#/components/schemas/Extensions'
    ChargingEvent:
      title: ChargingEvent
      description: |-
        Part 23 — one physical-timeline event the charging-network bridge reports for a
        session — the APX counterpart of an OCPP 2.0.1 TransactionEvent. The
        server applies the lifecycle transition (Part 23 §23.2) and appends
        `statusHistory`. `meterValue` events update `energy` without a state
        change. Idempotent by `Idempotency-Key` (bridges retry).
      type: object
      required:
        - eventType
        - time
      properties:
        eventType:
          type: string
          enum:
            - pluggedIn
            - chargingStarted
            - meterValue
            - suspended
            - resumed
            - chargingEnded
            - unplugged
            - fault
            - cancelled
        time:
          $ref: '#/components/schemas/DateTime'
        connectorIndex:
          type: integer
          minimum: 1
        meterWh:
          type: number
          minimum: 0
          description: Cumulative meter reading at `time`.
        powerKw:
          type: number
          minimum: 0
        stateOfChargePercent:
          type: number
          minimum: 0
          maximum: 100
        suspendedBy:
          type: string
          enum:
            - ev
            - evse
          description: With `suspended`.
        stopReason:
          type: string
          enum:
            - evDisconnected
            - evFull
            - targetReached
            - energyLimitReached
            - timeLimitReached
            - remote
            - local
            - deauthorized
            - emergencyStop
            - powerLoss
            - other
          description: With `chargingEnded`.
        faultCode:
          type: string
          description: With `fault` — the charger's error code, opaque.
        externalEventId:
          type: string
          description: The bridge's own id for this event (OCPP seqNo, message id) for reconciliation.
        detail:
          type: string
    ChargingPaymentAttachment:
      title: ChargingPaymentAttachment
      description: Part 23 — request body attaching the settling payment to an `unplugged` `directPayment` session, or recording the network's charge detail record for a `chargingNetwork` one.
      type: object
      properties:
        payment:
          description: The settling APDS Payment / APX PaymentRecord.
          $ref: '#/components/schemas/Reference'
        externalReference:
          type: string
          description: The charging network's CDR id.
        note:
          type: string
    SessionDetail:
      title: SessionDetail
      description: |-
        The `apds-ext:apx:session-detail@1.0` decoration on an APDS Session
        (Part 5 §5.8): what the pairing of reads decided and APDS has no
        members for — the reads behind the visit, why and how it ended, the
        matches it rests on, and the parent visit of an area Session. Written
        with the native Session POST/PUT by an external pairing engine; a
        server that pairs reads itself SHOULD write the same block on its own
        Sessions. A plain APDS client ignores it. It adds no event topic and
        carries no plate characters. A write that breaks a consistency rule
        of §5.8 is 422 and nothing is written.
      type: object
      properties:
        reads:
          type: array
          description: |-
            The reads attached to this Session. A read already bound as
            `entry` or `exit` to another Session of the same place is refused
            with 409 `read-already-bound` unless `supersedes` names that Session.
            A read naming no Observation visible to the caller is 422
            `reference-unknown`.
          items:
            $ref: '#/components/schemas/SessionReadBinding'
        supersedes:
          description: The Session whose reads this write takes over (a re-pairing).
          $ref: '#/components/schemas/Reference'
        lifecycle:
          type: string
          enum:
            - open
            - ended
            - final
            - disputed
          description: |-
            `open` — a vehicle is in the facility, no `actualEnd` yet; `ended` —
            closed, may still be revised; `final` — no further revision
            expected; `disputed` — under review. Every state but `open` requires
            `actualEnd`, and `open` forbids it (422 `request-unprocessable`
            otherwise). `final` is the writer's statement, never a lock: a
            server MUST NOT refuse a later revision on that ground.
        closure:
          $ref: '#/components/schemas/SessionClosure'
        flags:
          type: array
          description: Open flags — `entryUnknown`, `orphanExit`, `reentry`, `passThrough`, or implementer values.
          items:
            type: string
        matches:
          type: array
          items:
            $ref: '#/components/schemas/MatchEvidence'
        parent:
          description: |-
            The visit this area Session is part of (className `Session`). The
            parent's `hierarchyElement` MUST be an ancestor of this Session's
            (422 `request-unprocessable` otherwise). Consumers count visits by
            Sessions without `parent`; children still open when the parent
            ends SHOULD be closed no later than its `actualEnd` with `endReason`
            `parentExit`.
          $ref: '#/components/schemas/Reference'
        passThrough:
          type: boolean
          description: An area stay shorter than the area's minimum dwell — never scored or billed.
    SessionReadBinding:
      title: SessionReadBinding
      description: |-
        One LPR read attached to a Session by the pairing engine (Part 5
        §5.8, member `reads[]` of `apds-ext:apx:session-detail@1.0`).
      type: object
      required:
        - observation
        - role
      properties:
        observation:
          description: The APDS ObservationElement (className `ObservationElement`).
          $ref: '#/components/schemas/Reference'
        role:
          type: string
          enum:
            - entry
            - exit
            - duplicate
            - activity
          description: |-
            `entry` and `exit` are the passages that opened and closed the
            visit; `duplicate` is the same passage seen by another camera or
            frame; `activity` is the vehicle seen inside (a sweep, a bay camera).
        representative:
          type: boolean
          description: |-
            The read that stands for the visit in lists and screen-pops. At
            most one per Session; two are 422 `request-unprocessable` (Part 5
            §5.8 rule 1).
    SessionClosure:
      title: SessionClosure
      description: Why and how a Session ended (Part 5 §5.8).
      type: object
      properties:
        endReason:
          type: string
          description: definedValue from `apx-session-end-reasons` (Part 11) or an implementer code list.
          examples:
            - exitRead
        endInferred:
          type: boolean
          description: True when `actualEnd` was set by a rule rather than observed.
        startObserved:
          type: boolean
          description: |-
            False declares `actualStart` synthetic — an exit-only Session whose
            entry was never observed; the writer SHOULD then set `actualStart`
            equal to `actualEnd`. Consumers MUST exclude such Sessions from
            dwell statistics and from occupancy (Part 5 §5.8 rule 4). Absent
            means true.
        rule:
          type:
            - string
            - 'null'
          description: The implementer rule that closed a `stale` Session (e.g. `transient-48h`); null when none applied.
    MatchEvidence:
      title: MatchEvidence
      description: |-
        How a link to a Session was established and how sure it is (Part 5
        §5.8; shared by the `matches[]` member of
        `apds-ext:apx:session-detail@1.0` and the decoration
        `apds-ext:apx:match-evidence@1.0` on a Violation or ValetTicket).
        Carries no plate characters and no vehicle attribute values
        (Part 9 §9.6). Where both ends of one link carry evidence (the
        Session's `matches[]` entry and the decoration on the Violation or
        ValetTicket), the two MUST agree. Evidence with `plate.method:
        lenient` or `applied: false` may excuse a stay but never accuse one:
        `issue` on a Violation resting on it is 409 `violation-not-issuable`
        (Part 19 §19.4 rule 5).
      type: object
      required:
        - target
        - matchType
        - applied
      properties:
        target:
          description: |-
            The record at the other end of the link. In `matches[]`: an
            AssignedRight, a ValetTicket, a Violation, a PlateListEntry, or an
            Observation. In the decoration on a Violation or ValetTicket: the
            Session.
          $ref: '#/components/schemas/Reference'
        matchType:
          type: string
          enum:
            - right
            - valet
            - violation
            - list
            - exitPairing
            - sweep
            - other
          description: |-
            The kind of link: `right` — an AssignedRight covers the stay;
            `valet` — a ValetTicket's stay; `violation` — a Violation's stay;
            `list` — a plate-list entry matched the vehicle (Part 24);
            `exitPairing` — an exit read paired to the Session's entry;
            `sweep` — the vehicle seen during an inventory or patrol sweep tied
            to the Session; `other` — anything else.
          examples:
            - right
        plate:
          type: object
          description: How the plate strings agreed, when the link rests on a plate.
          required:
            - method
          properties:
            method:
              type: string
              enum:
                - exact
                - alias
                - fold
                - fuzzy
                - lenient
                - reviewer
              description: |-
                `exact` — the same characters; `alias` — a plate the right or
                account lists for the same vehicle; `fold` — equal after
                folding look-alike characters (O/0, I/1, B/8); `fuzzy` — within
                the implementation's edit-cost threshold; `lenient` — accepted
                under a relaxed rule that may excuse a stay but never accuse
                one; `reviewer` — a person judged the plates to match where no
                automatic method did.
            editCost:
              type:
                - number
                - 'null'
              minimum: 0
              description: The weighted edit cost of a `fuzzy` or `lenient` match; null otherwise.
            jurisdiction:
              type: string
              enum:
                - agrees
                - differs
                - unknown
        vehicle:
          type: object
          description: The vehicle-attribute evidence (make, model, colour) behind the match, as a level and a score — never the values.
          required:
            - level
          properties:
            level:
              type: string
              enum:
                - unknown
                - mismatch
                - inconclusive
                - weak
                - good
                - strong
              description: |-
                `unknown` — not compared; `mismatch` — the attributes contradict
                the match; `inconclusive` — compared, no signal; `weak`, `good`,
                `strong` — increasing support.
            llr:
              type: number
              description: Log-likelihood ratio of the vehicle evidence.
            model:
              type: string
              description: The evidence model and version that scored it, opaque.
        applied:
          type: boolean
          description: |-
            False is a shadow match — recorded for evaluation, not acted on. A
            link the record actually carries has `applied: true`.
        decidedBy:
          type: string
          enum:
            - system
            - person
          description: |-
            Whether software or a person made the link. A `matchTicket` that
            binds a lane-inquiry candidate SHOULD be recorded as `person`
            (Part 5 §5.8 rule 5).
        decidedTime:
          description: When the link was made.
          $ref: '#/components/schemas/DateTime'
    StayCompliance:
      title: StayCompliance
      description: |-
        The `apds-ext:apx:stay-compliance@1.0` decoration on an APDS Session
        (Part 5 §5.9): the outcome a compliance engine scored for the stay,
        and the policy it measured against. Written with the native Session
        POST/PUT by the engine; a server that scores stays itself SHOULD write
        the same block. The rules that produce the outcome stay in the engine.

        A status is not a Violation: a `violation`-family status issues
        nothing (Part 19 issues violations). Served only to tokens with
        `apx.compliance:read`, and written only with `apx.compliance:write`
        (403 `insufficient-scope`); a write that omits it keeps the stored
        block. It carries no plate characters.
      type: object
      required:
        - status
        - family
        - evaluatedTime
        - sequence
      properties:
        status:
          type: string
          description: definedValue of apx-stay-compliance-statuses, or an implementer code.
          examples:
            - overstay
        family:
          type: string
          enum:
            - compliant
            - violation
            - withheld
            - other
          description: |-
            The family of the status. For a registry status it MUST be the
            family the registry gives (422 `request-unprocessable`).
            `compliant` — rights or an exemption covered the stay
            `violation` — the stay was not covered as the policy requires
            `withheld` — not scored, or held back for review
            `other` — an outcome none of the other families fits, for example paid after exit
        pendingStatus:
          type: string
          description: The status the stay would have once a person confirms it; present only with `status` `reviewRequired` (422 `request-unprocessable` otherwise).
          examples:
            - overstay
        flags:
          type: array
          description: Facts behind the status — definedValues of apx-stay-compliance-flags, or implementer codes.
          items:
            type: string
          examples:
            - - paidAfterExit
        evaluatedTime:
          description: When the evaluation ran.
          $ref: '#/components/schemas/DateTime'
        sequence:
          type: integer
          minimum: 1
          description: Orders the evaluations of one Session. A write with a lower `sequence` than the one held is 409 `evaluation-out-of-order`; an equal one replaces it.
        final:
          type: boolean
          description: The writer's statement that no further evaluation is expected; never a lock.
        policy:
          description: The EnforcementPolicy, at its version, the evaluation used (Part 19 §19.10), whose `stayGrace` explains the result. Naming no policy visible to the caller is 422 `reference-unknown`.
          $ref: '#/components/schemas/VersionedReference'
      examples:
        - status: overstay
          family: violation
          flags:
            - paidAfterExit
          evaluatedTime: '2026-10-21T14:05:00Z'
          sequence: 3
          final: false
          policy:
            id: d1900000-0000-4000-8000-000000000010
            className: EnforcementPolicy
            version: 4
    OccupancyHistoryPage:
      title: OccupancyHistoryPage
      description: |-
        Occupancy per clock interval for one HierarchyElement (Part 5 §5.5a):
        the history behind the §5.5 snapshot, derived from the APDS
        DemandTable records the implementation holds. Buckets are aligned to
        the interval boundary in the place's time zone; a bucket with no
        demand record carries no counts, never a guess.
      type: object
      required:
        - place
        - interval
        - from
        - to
        - buckets
      properties:
        place:
          $ref: '#/components/schemas/Reference'
        interval:
          description: The bucket length as requested (ISO 8601 duration, e.g. `PT1H`).
          $ref: '#/components/schemas/Duration'
        from:
          $ref: '#/components/schemas/DateTime'
        to:
          $ref: '#/components/schemas/DateTime'
        buckets:
          type: array
          items:
            type: object
            required:
              - start
            properties:
              start:
                $ref: '#/components/schemas/DateTime'
              maxCount:
                type: integer
                minimum: 0
                description: The highest demand count recorded in the bucket.
              avgCount:
                type: number
                minimum: 0
                description: The time-weighted mean demand count over the bucket.
              supplyQuantity:
                type: integer
                minimum: 0
                description: The supply in force during the bucket (APDS Supply.supplyQuantity).
              samples:
                type: integer
                minimum: 0
                description: How many demand records the bucket is computed from.
        extensions:
          $ref: '#/components/schemas/Extensions'
    CredentialDigest:
      title: CredentialDigest
      description: |-
        The `apds-ext:apx:credential-digest@1.0` decoration (Part 9 §9.6 rule
        6): a keyed digest of a normalized credential identification (a plate),
        so a consumer that only needs "same plate?" can match without the
        plate itself. `value` is base64url(HMAC-SHA-256(key, normalized
        identification)); the key is named by `keyId` and distributed through
        `GET /v1/digest-keys`. Visible under `apx.data:read`.
      type: object
      required:
        - alg
        - keyId
        - value
      properties:
        alg:
          type: string
          enum:
            - HS256
        keyId:
          type: string
          description: The digest key the value was computed under (rotation by keyId).
        value:
          type: string
          description: base64url, no padding.
        credentialType:
          $ref: '#/components/schemas/CredentialTypeEnum'
    PlateCorrection:
      title: PlateCorrection
      description: |-
        Request body of `PUT /v1/lpr/reads/{observation}/plate` (Part 13
        §13.3a(4a)): a reviewer's decision on one read. `confirmed` keeps the
        engine's values; `corrected` replaces them with the ones given;
        `rejected` marks the read unusable for pairing and enforcement.
        `plate`, `country`, and `stateProvince` belong to `corrected` only:
        sent with another decision they are 422 `request-unprocessable`.
      type: object
      required:
        - decision
      properties:
        decision:
          type: string
          enum:
            - confirmed
            - corrected
            - rejected
        plate:
          type: string
          description: The corrected plate. Required when `decision` is `corrected`; not allowed otherwise.
        country:
          type: string
          description: APDS VehicleAncillaryIdentification.country vocabulary. Only with `corrected`.
        stateProvince:
          type: string
          description: APDS VehicleAncillaryIdentification.stateProvince vocabulary. Only with `corrected`.
        reason:
          type: string
        reviewer:
          type: string
          description: Opaque reviewer principal (recorded as `review.decidedBy`).
        extensions:
          $ref: '#/components/schemas/Extensions'
    LprReadSearch:
      title: LprReadSearch
      description: |-
        Request body of `POST /v1/lpr/reads:search` (Part 13 §13.3): the same
        keys as the `GET` lookup, carried in a body so a plate never enters a
        URL that proxies and access logs keep (Part 9 §9.6). At least one of
        `plate`, `ticket`, `observation`, or `session` is REQUIRED.
      type: object
      properties:
        plate:
          type: string
        ticket:
          type: string
        observation:
          type: string
          format: uuid
        session:
          type: string
          format: uuid
        place:
          type: string
          format: uuid
          description: Narrow results below the grant to one HierarchyElement and its subtree.
        page:
          type: integer
          minimum: 1
    AccountSearch:
      title: AccountSearch
      description: |-
        Request body of `POST /v1/accounts:search` (Part 13 §13.1): the same
        keys as the `GET` lookup, carried in a body so personal data never
        enters a URL (Part 9 §9.6).
      type: object
      properties:
        name:
          type: string
        phone:
          type: string
        email:
          type: string
        card:
          type: string
          description: Truncated card digits only (two to four); more is 422 `personal-data-not-permitted`.
        plate:
          type: string
        place:
          type: array
          items:
            type: string
            format: uuid
        page:
          type: integer
          minimum: 1
    PaymentSearch:
      title: PaymentSearch
      description: |-
        Request body of `POST /v1/payments:search` (Part 13 §13.2): the same
        keys and rules as the `GET` lookup, in a body (Part 9 §9.6).
      type: object
      properties:
        ticketLast4:
          type: string
        cardLast4:
          type: string
          pattern: ^[0-9]{2,4}$
        ticketNumber:
          type: string
        account:
          type: string
          format: uuid
        date:
          type: string
          format: date
        place:
          type: array
          items:
            type: string
            format: uuid
        captureStatus:
          type: string
          enum:
            - authorized
            - captured
        page:
          type: integer
          minimum: 1
    PaymentDetail:
      title: PaymentDetail
      description: |-
        The `apds-ext:apx:payment-detail@1.0` decoration (Part 13 §13.6a) on a
        `PaymentRecord` or an APDS `Payment`: the rate sold and the lines that
        sum to the total, so revenue reports and the deck price check have
        the base amount, the fee, and the product without a bilateral code.
        On a `PaymentRecord` it carries `rateSold` and `lines`; on a native
        APDS `Payment` it carries `rateSold` only, because the Payment's own
        `paymentLines` are the itemization there.
      type: object
      minProperties: 1
      properties:
        rateSold:
          type: object
          description: The rate the vendor sold, as the vendor names it.
          properties:
            id:
              type: string
              description: The vendor's rate id, or the APDS RateTable id when the deck is the source.
            name:
              type: string
            rateTable:
              description: The APDS RateTable at the version applied, when known.
              $ref: '#/components/schemas/VersionedReference'
            product:
              type: string
              enum:
                - standard
                - pass
                - other
            class:
              type: string
              enum:
                - standard
                - validation
                - discount
                - zeroed
                - other
        lines:
          type: array
          minItems: 1
          description: |-
            The itemization, as APDS `PaymentLine`s (by `$ref`, never
            re-shaped). Each line's code is its `idCode`: a definedValue of
            `apx-payment-line-codes` (Part 11) or an implementer code. A line
            coded `validation` has `paymentType: validation` and its `value` is
            the value the validation offset (not money collected); every other
            line has `paymentType: payment`, and a reduction (`discount`) is a
            negative `value`. The `currencyValue`s of the `paymentType:
            payment` lines MUST sum to the record's `amount`, in its
            `currencyType`; otherwise 422 `request-unprocessable` and nothing
            is charged. Only on a `PaymentRecord`: on a native APDS `Payment`
            the itemization is that Payment's own `paymentLines` and this
            member is absent (one store, Part 13 §13.6a).
          items:
            $ref: '#/components/schemas/PaymentLine'
    ViolationDetection:
      title: ViolationDetection
      type: object
      description: How and when the candidate was found.
      required:
        - mode
        - detectedTime
      properties:
        mode:
          type: string
          enum:
            - automated
            - guided
            - manual
          description: |-
            `automated` — a camera/sensor pipeline created the violation with
            no human in the loop. `guided` — the system surfaced a candidate
            (typically to a handheld) and an officer confirms on site.
            `manual` — an officer created the violation directly.
        detectedTime:
          $ref: '#/components/schemas/DateTime'
        detector:
          description: The detecting device (SupplementalEquipment) or, for guided/manual, the officer's Contact.
          $ref: '#/components/schemas/Reference'
        principal:
          type: string
          description: Opaque principal of the human or system that detected (officer badge id, pipeline name).
          examples:
            - officer-0417
        confidence:
          type: number
          minimum: 0
          maximum: 1
          description: Detection confidence (plate read × rule certainty), when the detector reports one.
        rule:
          type: string
          description: Implementer identifier of the enforcement rule that fired (automated mode).
          examples:
            - overstay-2h-zone-b
    ViolationVehicle:
      title: ViolationVehicle
      type: object
      description: The credential observed on the vehicle (an APDS CredentialTypeEnum credential).
      required:
        - credentialType
        - credentialIdentification
      properties:
        credentialType:
          $ref: '#/components/schemas/CredentialTypeEnum'
        credentialIdentification:
          type: string
          description: The credential value — plate string, permit number, transponder id.
          examples:
            - SYN-4471
        jurisdiction:
          type: string
          description: Issuing jurisdiction of the plate/credential (state, province, country code).
          examples:
            - US-IL
        description:
          type: string
          description: Free-text vehicle description captured by the officer (make, colour).
    ViolationEvidence:
      title: ViolationEvidence
      type: array
      description: |-
        Evidence media, as access-controlled LINKS (Part 9 §9.6 — never
        inline). Each item points at an APDS Image reachable under the same
        authentication and place grant as this resource.
      items:
        type: object
        required:
          - imageLink
        properties:
          imageLink:
            $ref: '#/components/schemas/Url'
          imageType:
            $ref: '#/components/schemas/ImageTypeEnum'
          capturedTime:
            $ref: '#/components/schemas/DateTime'
          device:
            description: The capturing SupplementalEquipment (camera, handheld).
            $ref: '#/components/schemas/Reference'
          description:
            type: string
    ViolationLocation:
      title: ViolationLocation
      type: object
      description: |-
        Where the violation was observed and from where — modelled on the
        APDS Observation `Location` shape (Part 19 §19.9), with two
        differences: `observerLocation` is optional here (APDS requires
        it; an automated finding copied from a fixed sensor may have
        none), and `accuracyMetres` is added. The member names and the
        `PointLocation` types are APDS's own. GeoJSON positions are
        [longitude, latitude] in that order; enforcement tools that store
        latitude first MUST swap on the wire. Automated detections SHOULD
        copy this from the underlying Observation.
      properties:
        observedLocation:
          description: The vehicle's position (GeoJSON Point).
          $ref: '#/components/schemas/GeoJsonObject'
        observerLocation:
          description: The officer's or camera's position when the finding was made (GeoJSON Point).
          $ref: '#/components/schemas/GeoJsonObject'
        observedLocationTextual:
          description: Human-readable address or description of the observed location.
          $ref: '#/components/schemas/MultilingualString'
        accuracyMetres:
          type: number
          minimum: 0
          description: Horizontal accuracy reported by the capturing device.
    ViolationAppliedPayment:
      title: ViolationAppliedPayment
      description: |-
        One payment applied to a violation (Part 19 §19.6a): a partial
        payment or the settling one. `payment` references the Part 13 record
        (APDS Payment or APX PaymentRecord) when the money moved through this
        server; a payment an import source took itself (§19.13) may carry
        only the source's own `reference`.
      type: object
      required:
        - amount
      properties:
        amount:
          description: The amount applied to this violation.
          $ref: '#/components/schemas/AmountInCurrency'
        paidTime:
          description: When the payment was made (for an import, as the source reported it).
          $ref: '#/components/schemas/DateTime'
        payment:
          description: The APDS Payment or APX PaymentRecord (Part 13), when one exists on this server.
          $ref: '#/components/schemas/Reference'
        reference:
          type: string
          description: The import source's own identifier for the payment, when it reported one.
          examples:
            - PMT-77120
    ViolationSource:
      title: ViolationSource
      description: |-
        The `apds-ext:apx:violation-source@1.0` decoration (Part 19 §19.13): a
        violation issued by an external enforcement system and imported
        through `POST /v1/enforcement/violation-imports`, keyed on `system` +
        `recordId`. `sourceRevision`, or without one `sourceUpdatedTime`,
        orders the source's revisions.
      type: object
      required:
        - system
        - recordId
      properties:
        system:
          type: string
          description: The issuing system, opaque (`passport`, `aims`…).
        recordId:
          type: string
          description: The source's own citation or record id.
        sourceStatus:
          type: string
          description: The source's own status vocabulary, carried as reported (`issued`, `warned`, `voided`, `dismissed`, `partiallyPaid`…).
        sourceRevision:
          type: integer
          minimum: 0
          description: The source's revision counter; a re-import with a higher value updates the record.
        sourceUpdatedTime:
          description: When the source last changed the record. Orders revisions when the source keeps no `sourceRevision`.
          $ref: '#/components/schemas/DateTime'
        receivedTime:
          description: When this server applied the revision it now holds. Server-set.
          readOnly: true
          $ref: '#/components/schemas/DateTime'
        officer:
          type: string
          description: The source's officer identifier, opaque.
        violationCode:
          type: string
          description: The source's own violation code, when it has no `apx-violation-types` equivalent.
    ViolationImport:
      title: ViolationImport
      description: |-
        Request body of `POST /v1/enforcement/violation-imports` (Part 19
        §19.13): a violation as an external enforcement system reports it —
        in any state, with the `statusHistory[]` times the source recorded,
        the notice, the amounts and payments, and the
        `apds-ext:apx:violation-source@1.0` decoration that keys it. The
        members mean what they mean on `Violation`; the difference is that
        `violationStatus`, `notice`, `amountPaid`, `payments`, and
        `statusHistory` are written by the caller here, because the source,
        not this server, decided them. A state at or past issuance
        (`issued`, `paid`, `appealed`, `closed`) REQUIRES `notice` (with
        `noticeNumber` and `issuedTime`) and `amount` (400 `invalid-request`
        otherwise); `paid` with `amountPaid` below `amount` is 422
        `request-unprocessable`. A warning with no fine is `issued` (or
        `closed`) with `notice.noticeKind` `warning` and a zero `amount`.
      type: object
      required:
        - violationType
        - violationStatus
        - place
        - detection
        - statusHistory
        - extensions
      properties:
        id:
          type: string
          format: uuid
          description: The source's id for the violation, when it is a UUID the server may keep; the server MAY mint its own.
        violationType:
          type: string
          description: definedValue from `apx-violation-types` or an implementer code list.
          examples:
            - noValidRight
        violationStatus:
          type: string
          enum:
            - detected
            - confirmed
            - dismissed
            - issued
            - paid
            - appealed
            - closed
            - voided
          description: |-
            The APX state the source's status maps to. `paid` requires
            `amountPaid` at least `amount`; a part-paid violation is `issued`
            (Part 19 §19.6a). The source's own wording goes in the decoration's
            `sourceStatus`.
        place:
          description: The HierarchyElement where the violation was observed.
          $ref: '#/components/schemas/Reference'
        space:
          description: The specific APDS Space, when space-resolved.
          $ref: '#/components/schemas/Reference'
        detection:
          $ref: '#/components/schemas/ViolationDetection'
        vehicle:
          $ref: '#/components/schemas/ViolationVehicle'
        observations:
          type: array
          description: The underlying APDS Observations, when the source shared them.
          items:
            $ref: '#/components/schemas/Reference'
        evidence:
          $ref: '#/components/schemas/ViolationEvidence'
        relatedSession:
          description: The APDS Session the vehicle was in, when known (or set later through `POST /v1/violations/{id}/session`).
          $ref: '#/components/schemas/Reference'
        relatedRight:
          description: The AssignedRight closest to covering the stay, when known.
          $ref: '#/components/schemas/Reference'
        location:
          $ref: '#/components/schemas/ViolationLocation'
        notice:
          type: object
          description: The notice, warning, or citation as the source issued it.
          required:
            - noticeNumber
            - issuedTime
          properties:
            noticeKind:
              type: string
              description: warning | notice | citation (implementer code list).
              examples:
                - citation
            noticeNumber:
              type: string
              description: The number printed on the notice — the lookup a driver can make (`?noticeNumber=`).
              examples:
                - EX-2026-018342
            issuedTime:
              description: When the source issued it, as the source reported it.
              $ref: '#/components/schemas/DateTime'
            issuedBy:
              description: The issuing Organisation or officer Contact, when it is known here.
              $ref: '#/components/schemas/Reference'
            deliveryMethod:
              type: string
              description: windshield | handed | mail | electronic (implementer code list).
              examples:
                - windshield
        amount:
          description: The amount payable now, as the source reports it.
          $ref: '#/components/schemas/AmountInCurrency'
        dueTime:
          $ref: '#/components/schemas/DateTime'
        amountPaid:
          description: The total paid toward `amount`, as the source reports it.
          $ref: '#/components/schemas/AmountInCurrency'
        payments:
          type: array
          description: The payments the source applied, in order.
          items:
            $ref: '#/components/schemas/ViolationAppliedPayment'
        statusHistory:
          type: array
          minItems: 1
          description: |-
            The lifecycle as the source recorded it, oldest first, with the
            source's own times (`actor` is the source's principal — an officer
            badge, the system name). Append-only: the server keeps the entries
            it already holds and appends only those later than its last one
            (Part 4 §4.2).
          items:
            type: object
            required:
              - state
              - time
              - actor
            properties:
              state:
                type: string
              time:
                $ref: '#/components/schemas/DateTime'
              actor:
                type: string
              detail:
                type: string
        extensions:
          description: The extension container; MUST carry `apds-ext:apx:violation-source@1.0`.
          allOf:
            - $ref: '#/components/schemas/Extensions'
            - required:
                - apds-ext:apx:violation-source@1.0
      allOf:
        - if:
            required:
              - violationStatus
            properties:
              violationStatus:
                enum:
                  - issued
                  - paid
                  - appealed
                  - closed
          then:
            required:
              - notice
              - amount
    ViolationSessionLink:
      title: ViolationSessionLink
      description: |-
        Request body of `POST /v1/violations/{id}/session` (Part 19 §19.13):
        sets, corrects, or clears `relatedSession` after creation, carrying the
        match evidence. `session: null` clears the link. `If-Match` carries the
        Violation version last read.
      type: object
      required:
        - session
      properties:
        session:
          description: The APDS Session (className `Session`), or null to clear the link.
          oneOf:
            - $ref: '#/components/schemas/Reference'
            - type: 'null'
        evidence:
          description: How the match was made; written onto the violation as `apds-ext:apx:match-evidence@1.0`, with the Session as `target`.
          $ref: '#/components/schemas/MatchEvidence'
        reason:
          type: string
          description: Why the link was set or changed (implementer code list — lateMatch, reviewerCorrection, mismatch…).
          examples:
            - lateMatch
    PlateList:
      title: PlateList
      description: |-
        A list of credentials with a category and per-place behaviour
        (Part 24). Entries are kept separately (`PlateListEntry`); the list
        carries the policy.
      type: object
      required:
        - id
        - version
        - name
        - category
        - status
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
        version:
          type: integer
          minimum: 1
          readOnly: true
        name:
          type: string
        category:
          type: string
          description: definedValue from `apx-plate-list-categories` (Part 11) — `allow`, `watch`, `scofflaw`, `enforcementVehicle` — or an implementer category.
          examples:
            - scofflaw
        owner:
          description: The Organisation that maintains the list (a city, an operator).
          $ref: '#/components/schemas/Reference'
        places:
          type: array
          description: Where the list applies, with per-place flags; a list with no `places` applies nowhere.
          items:
            $ref: '#/components/schemas/PlateListPlaceFlags'
        status:
          type: string
          enum:
            - active
            - suspended
            - retired
        description:
          type: string
        entryCount:
          type: integer
          minimum: 0
          readOnly: true
        recordInfo:
          $ref: '#/components/schemas/RecordInfo'
        extensions:
          $ref: '#/components/schemas/Extensions'
    PlateListEntry:
      title: PlateListEntry
      description: |-
        One credential on a list (Part 24 §24.2). The plate value appears
        only under `apx.platelists:read`/`:manage`; a consumer that only
        screens may hold the `apds-ext:apx:credential-digest@1.0` decoration
        instead (Part 9 §9.6 rule 6).
      type: object
      required:
        - id
        - version
        - credential
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
        version:
          type: integer
          minimum: 1
          readOnly: true
        list:
          description: The PlateList this entry belongs to.
          readOnly: true
          $ref: '#/components/schemas/Reference'
        credential:
          type: object
          required:
            - credentialType
            - credentialIdentification
          properties:
            credentialType:
              $ref: '#/components/schemas/CredentialTypeEnum'
            credentialIdentification:
              type: string
              description: The plate or credential value.
            jurisdiction:
              type: string
              description: Issuing jurisdiction of the plate (state, province, country code).
        validity:
          type: object
          description: When the entry is in force; absent bounds are open.
          properties:
            start:
              $ref: '#/components/schemas/DateTime'
            end:
              $ref: '#/components/schemas/DateTime'
        details:
          type: object
          description: Why the credential is on the list, as the list owner records it.
          properties:
            amountOwed:
              $ref: '#/components/schemas/AmountInCurrency'
            noticeCount:
              type: integer
              minimum: 0
            reference:
              type: string
              description: The owner's case or file reference, opaque.
            note:
              type: string
        vehicle:
          type: object
          description: A description that helps an officer confirm the match; never a registry.
          properties:
            description:
              type: string
        recordInfo:
          $ref: '#/components/schemas/RecordInfo'
        extensions:
          $ref: '#/components/schemas/Extensions'
    PlateListPlaceFlags:
      title: PlateListPlaceFlags
      description: What the list does at one place (Part 24 §24.1).
      type: object
      required:
        - place
      properties:
        place:
          description: The HierarchyElement subtree the flags apply to.
          $ref: '#/components/schemas/Reference'
        enforced:
          type: boolean
          description: A match counts for compliance (`allow`) or enforcement (`scofflaw`, `watch`) at this place.
        alertOnArrival:
          type: boolean
          description: A match raises the Part 7 arrival alert of the list's category.
        refuseService:
          type: boolean
          description: A match refuses service at the lane (the refused-service sign, Part 6 `displayMessage`).
    DiscoveryDocument:
      title: DiscoveryDocument
      description: |-
        What THIS credential can do: exactly the endpoints, commands, topics,
        and places reachable with the presented token's scopes and grants.
        Two clients with different grants receive different documents; a client
        can call everything its document lists and nothing more.
      type: object
      required:
        - client
        - conformanceClasses
        - scopes
        - endpoints
      properties:
        client:
          type: string
          description: The OAuth client id this document was computed for.
        organisation:
          description: The client's Organisation (token claim apx_org).
          $ref: '#/components/schemas/Reference'
        conformanceClasses:
          type: array
          description: |-
            Server classes usable by this client (intersection with its
            scopes). Always a subset of the bootstrap document's
            `conformanceClasses` (Part 16 §16.2).
          items:
            type: string
        scopes:
          type: array
          items:
            type: string
        places:
          type: array
          description: |-
            Granted HierarchyElement subtree roots (token claim apx_places),
            reflected exactly. Fail-closed semantics (Part 9 §9.3): an empty
            array means NO places; the explicit wildcard entry "*" means all
            places. A token with no `apx_places` claim is reflected as `[]`,
            never by omitting the member (Part 16 §16.2).
          items:
            type: string
        endpoints:
          type: array
          description: |-
            Callable endpoints (APDS-native, APX, and vendor routes under
            `/apx/x/<vendor-ns>/`), each callable for at least one target inside
            the granted places (Part 16 §16.2).
          items:
            type: object
            required:
              - path
              - methods
            properties:
              path:
                type: string
                description: |-
                  The OpenAPI path template exactly as it appears in the bundle
                  (`/v1/commands/{id}`; APDS-native routes unchanged), relative
                  to the bootstrap document's `apiBase`.
                examples:
                  - /v1/commands/{id}
              methods:
                type: array
                description: Upper-case HTTP method names.
                items:
                  type: string
                  examples:
                    - GET
        commandTypes:
          type: array
          description: |-
            Command types this client may execute (empty without
            apx.control:execute). A permission list; what the host offers is
            `features` (Part 16 §16.2).
          items:
            type: string
        features:
          type: array
          description: |-
            Optional features of claimed classes that this client may use
            (definedValues from `apx-features`, Part 11; Part 6 §6.5). Listed whenever
            the host offers the feature and the client holds a read or execute
            scope of the class, so a read-only client can see it too.
          items:
            type: string
          examples:
            - - negotiatedRates
              - ticketMatching
        uiSurfaces:
          type: array
          description: |-
            The vendor screens this client may launch (Part 25 §25.1), each
            with its display and launch modes and the actions it reports back.
            Present only when the host implements `apx-ui-launch` and the
            client holds `apx.ui:launch`.
          items:
            $ref: '#/components/schemas/UiSurface'
        placeCapabilities:
          type: array
          description: |-
            What each granted place can do, before a call (Part 16 §16.2):
            the command types the site executes, the surfaces offered there,
            and the optional features it supports. A site with no revenue
            control link lists no command types, so an agent knows to use the
            vendor's screen instead. Absent when every place offers the same
            as the document-level `commandTypes`, `uiSurfaces` and `features`.
          items:
            type: object
            required:
              - place
            properties:
              place:
                type: string
                format: uuid
                description: The HierarchyElement subtree root the row applies to.
              commandTypes:
                type: array
                items:
                  type: string
              uiSurfaces:
                type: array
                description: apx-ui-surfaces values offered at this place.
                items:
                  type: string
              features:
                type: array
                items:
                  type: string
        topics:
          type: array
          description: |-
            Topics this client may subscribe to: APX registry topics, APDS
            `EventTypeEnum` values (Part 8), and vendor topics (`<vendor-ns>.`).
          items:
            type: string
        rateLimits:
          type: object
          description: |-
            Advisory per-credential limits (Part 16 §16.2). Defined keys:
            `requestsPerMinute`, `commandsPerMinute`, `burst` (most requests in
            any one second), `subscriptionsMax`, `streamConnectionsMax`. Every
            value is a per-credential integer; other keys are advisory vendor
            additions.
          additionalProperties:
            type: integer
          examples:
            - requestsPerMinute: 600
              commandsPerMinute: 60
        replication:
          type: array
          description: |-
            Part 18 §18.6 — for a place this implementation shares with a
            replicated site or aggregator implementation, which side is
            authoritative for each entity class. A write to a class from the
            non-authoritative side is 409 `not-authoritative`. Absent when
            the implementation replicates nothing.
          items:
            type: object
            required:
              - place
              - class
              - authority
            properties:
              place:
                type: string
                format: uuid
                description: The HierarchyElement subtree root the row applies to.
              class:
                type: string
                description: An APDS class (`Session`, `RateTable`…) or APX resource class (`Violation`, `Alert`…).
              authority:
                type: string
                enum:
                  - site
                  - aggregator
              peer:
                type: string
                format: uri-reference
                description: The other implementation's `EventEnvelope.source`.
        extensions:
          $ref: '#/components/schemas/Extensions'
    ResolutionContext:
      title: ResolutionContext
      description: |-
        The aggregated customer-service context (Part 17): everything the
        server could resolve about one interaction, plus the policy-decided
        allowed actions. Every section beyond the required core is OPTIONAL —
        implementations include what they know and omit what they don't
        (graceful degradation), and MUST NOT include sections the caller's
        scopes/grants could not read directly.
      type: object
      required:
        - id
        - version
        - computedAt
        - status
        - place
        - allowedActions
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
        version:
          type: integer
          minimum: 1
          readOnly: true
          description: Increments each time the context is recomputed.
        computedAt:
          $ref: '#/components/schemas/DateTime'
        status:
          type: string
          enum:
            - full
            - partial
          description: partial = at least one source has not answered yet; re-read to refresh.
        pendingSources:
          type: array
          description: Names of sources still resolving when status=partial (implementer-defined identifiers).
          items:
            type: string
        interactionId:
          type: string
          description: Echo of the caller's opaque interaction identifier.
          examples:
            - interaction-938383
        correlationId:
          type: string
          format: uuid
        issue:
          $ref: '#/components/schemas/ResolutionIssue'
        place:
          description: The facility this interaction is anchored to.
          $ref: '#/components/schemas/Reference'
        placeDisplay:
          type: string
          examples:
            - Lakeside Garage
        lane:
          description: The VehicularAccess (lane) if resolved.
          $ref: '#/components/schemas/Reference'
        laneStatus:
          description: The live lane inquiry result (Part 6 §6.2).
          $ref: '#/components/schemas/LaneStatus'
        vehicle:
          type: object
          description: The vehicle as best resolved (usually via LPR). Plate vocabulary follows APDS VehicleAncillaryIdentification (country/stateProvince).
          properties:
            plate:
              type: string
            country:
              type: string
              examples:
                - US
            stateProvince:
              type: string
              examples:
                - FL
            confidence:
              type: number
              minimum: 0
              maximum: 1
              description: Projection of APDS Confidence.overallConfidence (0–1).
            plateImage:
              $ref: '#/components/schemas/Url'
        session:
          $ref: '#/components/schemas/Reference'
        holder:
          description: The RightHolder (parker) if identified.
          $ref: '#/components/schemas/Reference'
        holderDisplay:
          type: string
          description: Display name only — contact details require the account read (PII minimization).
        account:
          $ref: '#/components/schemas/Account'
        assignedRight:
          description: The permit/reservation AssignedRight if resolved.
          $ref: '#/components/schemas/Reference'
        reservation:
          $ref: '#/components/schemas/ReservationSummary'
        credential:
          $ref: '#/components/schemas/Reference'
        passback:
          $ref: '#/components/schemas/PassbackStatus'
        accessDecision:
          type: object
          description: The most recent access decision at the lane.
          properties:
            status:
              type: string
              enum:
                - granted
                - denied
                - pending
                - unknown
            reasonCode:
              type: string
              description: Operator code-list value.
              examples:
                - outstandingBalance
            reasonDisplay:
              type: string
            occurredAt:
              $ref: '#/components/schemas/DateTime'
        payments:
          type: array
          description: Recent relevant payments (most recent first).
          items:
            $ref: '#/components/schemas/PaymentRecord'
        devices:
          type: array
          description: Live status of the lane's devices — surfaces equipment faults before the agent asks the customer to retry.
          items:
            $ref: '#/components/schemas/DeviceStatus'
        recentOverrides:
          type: array
          items:
            $ref: '#/components/schemas/OverrideRecord'
        supportHistory:
          type: array
          description: Recent SupportInteractions for the same subjects.
          items:
            $ref: '#/components/schemas/SupportInteraction'
        allowedActions:
          type: array
          description: The policy layer's decisions — see AllowedAction. May be empty.
          items:
            $ref: '#/components/schemas/AllowedAction'
        recommendedAction:
          type: object
          description: The server's suggested next step (advisory, never binding). MUST be one of allowedActions.
          required:
            - action
          properties:
            action:
              type: string
              description: The AllowedAction.action value being recommended.
              examples:
                - post-apx-v1-payment-links
            reason:
              type: string
        recordInfo:
          $ref: '#/components/schemas/RecordInfo'
        extensions:
          $ref: '#/components/schemas/Extensions'
      examples:
        - id: e5000000-0000-4000-8000-000000000013
          version: 1
          computedAt: '2026-09-05T20:12:44Z'
          status: full
          issue:
            code: validationMissing
            display: Customer reports a merchant validation that is not applied to the ticket
          place:
            id: b1000000-0000-4000-8000-000000000001
            className: Place
          laneStatus:
            lane:
              id: b2000000-0000-4000-8000-000000000002
              className: VehicularAccess
            currentTicket:
              ticketNumber: T-70443
              session:
                id: c4000000-0000-4000-8000-000000000023
                className: Session
              amountDue:
                currencyType: USD
                currencyValue: 14
              paidInFull: false
              validations: []
          allowedActions:
            - action: applyValidation
              display: Apply merchant validation
              target:
                id: b2000000-0000-4000-8000-000000000002
                className: VehicularAccess
              allowed: true
              requiresApproval: false
              execution:
                type: control
                command: applyValidation
            - action: vendGate
              display: Vend gate
              target:
                id: b2000000-0000-4000-8000-000000000002
                className: VehicularAccess
              allowed: false
              execution:
                type: control
                command: vendGate
              reason:
                code: sessionUnpaid
                display: A validation adjusts the amount due; it does not waive the remainder.
                policy: no-vend-while-unpaid
          recommendedAction:
            action: applyValidation
            reason: The ticket carries no validation; if the claimed provider is on the place's list, apply it and requote.
    ResolutionResolveRequest:
      title: ResolutionResolveRequest
      description: |-
        Whatever PARKING-DOMAIN identifiers are currently known — the server
        resolves every relationship it can (Part 17 §17.2). At least one
        IDENTIFYING member is required — `device`, `place`, `lane`,
        `session`, `holder`, `credential`, `plate`, `ticketNumber`,
        `reservationCode`, `guestReference`, `commsPoint`, `callerId`,
        `dialedNumber`, or `commsDeviceId`; all are optional individually.
        `interactionId`, `correlationId`, `channel`, and `reservationIssuer`
        are metadata and do not count: a body without an identifying member
        is 400 `invalid-request` (Part 17 §17.1). Unknown members are ignored
        (tolerant reader) and never used for resolution. (`minProperties: 1`
        is the only part of this rule the schema states; the full rule is
        enforced by the server.)

        Telephony values appear in exactly two places in APX: on a Part 26
        CommsPoint, and in the `callerId`, `dialedNumber` and `commsDeviceId`
        members here, which the call platform supplies to find the comms
        point. A PARCS implementation never has to hold, return or understand
        them; one that holds no comms points answers these members with 422
        `comms-point-unknown` (Part 17 §17.1). No SIP identifiers, anywhere.
      type: object
      minProperties: 1
      properties:
        interactionId:
          type: string
          description: |-
            OPAQUE identifier of the calling application's customer interaction
            (a call, chat, SMS session…). APX never interprets it — it only
            echoes it for correlation (Part 17 §17.7). Not an identifier for
            resolution.
          examples:
            - interaction-938383
        correlationId:
          type: string
          format: uuid
          description: Caller-minted correlation id; echoed on the context and reusable on Commands.
        channel:
          type: string
          description: How the interaction arrived, for context/history display (voice | intercom | chat | web | other).
          examples:
            - intercom
        device:
          description: A SupplementalEquipment the interaction is anchored to (only meaningful if inventoried in the Place hierarchy).
          $ref: '#/components/schemas/Reference'
        place:
          $ref: '#/components/schemas/Reference'
        lane:
          $ref: '#/components/schemas/Reference'
        session:
          $ref: '#/components/schemas/Reference'
        holder:
          $ref: '#/components/schemas/Reference'
        credential:
          $ref: '#/components/schemas/Reference'
        plate:
          type: string
        ticketNumber:
          type: string
        reservationCode:
          type: string
        reservationIssuer:
          type: string
          description: Who sold the reservation, when the code alone is ambiguous across sellers (Part 17 §17.2, ReservationSummary.issuer). Metadata, not an identifier.
          examples:
            - spothero.example
        guestReference:
          type: object
          description: A guest without a plate or ticket — a hotel room, a company, a tenant's employee, an event (Part 17 §17.2). The server resolves it through the place's guest arrangements.
          required:
            - kind
            - value
          properties:
            kind:
              type: string
              enum:
                - hotelRoom
                - company
                - tenant
                - event
                - other
            value:
              type: string
              examples:
                - '1412'
        commsPoint:
          description: The Part 26 CommsPoint the contact came from, when the call platform already knows it.
          $ref: '#/components/schemas/Reference'
        callerId:
          type: string
          pattern: ^\+[1-9][0-9]{1,14}$
          description: E.164. The number the contact came from; matched against `CommsPoint.callerId` (Part 26 §26.4). A parker's own mobile number resolves to nothing and is not stored.
          examples:
            - '+15555550199'
        dialedNumber:
          type: string
          pattern: ^\+[1-9][0-9]{1,14}$
          description: E.164. The number the contact called; matched against `CommsPoint.phoneNumber`. A posted number shared by many lanes resolves to the place only.
          examples:
            - '+15555550142'
        commsDeviceId:
          type: string
          description: The call platform's device id; matched against `CommsPoint.commsDeviceId`.
          examples:
            - dev-51cc-ae16
    ResolutionIssue:
      title: ResolutionIssue
      description: |-
        The machine-classified issue this context describes. `code` is a
        definedValue from the apx-issue-types registry (open, per Part 11);
        `display` is the human-readable summary shown to agents.
      type: object
      required:
        - code
      properties:
        code:
          type: string
          description: definedValue from apx-issue-types.
          examples:
            - accountBalanceDenied
        display:
          type: string
          examples:
            - Monthly parker denied because of outstanding balance
    AllowedAction:
      title: AllowedAction
      description: |-
        One policy decision about one action, evaluated for THIS context, THIS
        credential, and THIS moment (Part 17 §17.3). The server — never the
        consuming agent, human or AI — decides permissibility. Approval
        requirements are policy-dependent, which is why they live here at
        runtime and not in a registry.

        The `execution` descriptor abstracts HOW the action runs — a Part 6
        control command or a domain API operation — so the agent sees one
        unified action list and never needs to know which APX module executes
        it. Servers MUST NOT list an action the implementation does not
        support (Part 17 §17.3).
      type: object
      required:
        - action
        - allowed
      allOf:
        - if:
            required:
              - allowed
            properties:
              allowed:
                const: false
          then:
            required:
              - reason
        - if:
            required:
              - requiresApproval
            properties:
              requiresApproval:
                const: true
          then:
            required:
              - reason
      properties:
        action:
          type: string
          description: |-
            Logical action identifier: the apx-command-types value for control
            actions, or the effective-spec operationId for domain actions.
          examples:
            - courtesyExit
        display:
          type: string
          description: Agent-facing label.
          examples:
            - Courtesy exit
        target:
          description: The Reference the action should be executed against.
          $ref: '#/components/schemas/Reference'
        allowed:
          type: boolean
        requiresApproval:
          type: boolean
          default: false
          description: When true, the executing request MUST carry approval evidence (Part 17 §17.3).
        approvalRole:
          type: string
          description: Role that can approve (implementer/operator code list).
          examples:
            - supervisor
        execution:
          type: object
          description: |-
            How to execute (RECOMMENDED). Exactly one of command/operationId/
            surface per type. `ui` says the action is done in the vendor's own
            screen (Part 25): the agent launches `surface` on `subject` and
            the implementation reports what was done as the module's native
            resource or a UiActionRecord carrying the launch's correlation id.
            The value set grows additively: a client MUST skip an action whose
            `type` it does not recognise rather than fail (Part 17 §17.3).
          required:
            - type
          allOf:
            - if:
                required:
                  - type
                properties:
                  type:
                    const: control
              then:
                required:
                  - command
            - if:
                required:
                  - type
                properties:
                  type:
                    const: domain
              then:
                required:
                  - operationId
            - if:
                required:
                  - type
                properties:
                  type:
                    const: ui
              then:
                required:
                  - surface
          properties:
            type:
              type: string
              enum:
                - control
                - domain
                - ui
            command:
              type: string
              description: For type=control — the apx-command-types value for POST /v1/commands.
              examples:
                - courtesyExit
            operationId:
              type: string
              description: For type=domain — the operationId of the executing operation in the effective OpenAPI description.
              examples:
                - post-apx-v1-payment-links
            surface:
              type: string
              description: For type=ui — the apx-ui-surfaces value to launch (Part 25 §25.5).
              examples:
                - lane.console
            subject:
              description: For type=ui — the entity to open the surface on; defaults to the action's `target`.
              $ref: '#/components/schemas/Reference'
        reason:
          type: object
          description: Why the action is denied or gated. REQUIRED when allowed=false or requiresApproval=true.
          required:
            - code
          properties:
            code:
              type: string
              description: Machine-readable policy reason code (operator code list).
              examples:
                - courtesyLimitReached
            display:
              type: string
              examples:
                - Two courtesy exits have already been provided within the previous 48 hours.
            policy:
              type: string
              description: Identifier of the matched operator policy (opaque to APX).
    PassbackStatus:
      title: PassbackStatus
      description: Anti-passback state overlay for one APDS Credential.
      type: object
      required:
        - credential
        - state
      properties:
        credential:
          $ref: '#/components/schemas/Reference'
        state:
          type: string
          enum:
            - normal
            - violation
            - unknown
        expectedPresence:
          type: string
          enum:
            - inside
            - outside
            - unknown
        recordedPresence:
          type: string
          enum:
            - inside
            - outside
            - unknown
        lastAccess:
          type: object
          description: The most recent access event for this credential.
          required:
            - direction
            - occurredAt
          properties:
            direction:
              type: string
              enum:
                - entry
                - exit
            occurredAt:
              $ref: '#/components/schemas/DateTime'
            place:
              $ref: '#/components/schemas/Reference'
            lane:
              description: The VehicularAccess where the access occurred.
              $ref: '#/components/schemas/Reference'
        extensions:
          $ref: '#/components/schemas/Extensions'
      examples:
        - credential:
            id: c3000000-0000-4000-8000-000000000013
            className: Credential
          state: violation
          expectedPresence: outside
          recordedPresence: inside
          lastAccess:
            direction: entry
            occurredAt: '2026-09-01T08:03:47Z'
            place:
              id: b1000000-0000-4000-8000-000000000001
              className: Place
            lane:
              id: b2000000-0000-4000-8000-000000000001
              className: VehicularAccess
    PlateCandidate:
      title: PlateCandidate
      description: |-
        One candidate plate read for correction workflows (Part 17 §17.5) —
        a projection over APDS Observations, imagery as access-controlled
        links (Part 9 §9.6).
      type: object
      required:
        - plate
        - confidence
        - observationDateTime
      properties:
        plate:
          type: string
        country:
          type: string
          description: Plate issuing country (APDS VehicleAncillaryIdentification.country vocabulary).
          examples:
            - US
        stateProvince:
          type: string
          description: Plate issuing state/province (APDS VehicleAncillaryIdentification.stateProvince vocabulary).
          examples:
            - FL
        confidence:
          type: number
          minimum: 0
          maximum: 1
          description: Projection of APDS Confidence.overallConfidence (0–1) for the read.
        observationDateTime:
          description: When the read was captured (aligned with LprRead.observationDateTime; APDS ObservationElement.observationStartTime).
          $ref: '#/components/schemas/DateTime'
        detail:
          description: Per-attribute confidences, alternate reads, and passage geometry (Part 13 §13.3a), when the read carried them.
          $ref: '#/components/schemas/LprReadDetail'
        lane:
          $ref: '#/components/schemas/Reference'
        observation:
          description: The underlying APDS Observation.
          $ref: '#/components/schemas/Reference'
        plateImage:
          $ref: '#/components/schemas/Url'
        vehicleImage:
          $ref: '#/components/schemas/Url'
        purgedImagery:
          type: boolean
          readOnly: true
          description: True when imagery for this read existed and was purged under the retention schedule (Part 13 §13.3b); `plateImage`/`vehicleImage` are then absent.
        extensions:
          description: The underlying Observation's `extensions`, minus the `apds-ext:apx:lpr-read@1.0` block (which is `detail`) — Part 13 §13.3a.
          $ref: '#/components/schemas/Extensions'
      examples:
        - plate: SVN-4821
          country: US
          stateProvince: FL
          confidence: 0.97
          observationDateTime: '2026-09-02T22:39:04Z'
          lane:
            id: b2000000-0000-4000-8000-000000000002
            className: VehicularAccess
          observation:
            id: f2000000-0000-4000-8000-000000000014
            className: Observation
          plateImage: https://api.lakeside-garage.example/v1/media/f2000000-0014/plate.jpg
    OverrideRecord:
      title: OverrideRecord
      description: A recent manual override relevant to this context (courtesy exits, gate opens, passback resets…). Summarizes a Part 6 Command.
      type: object
      required:
        - commandType
        - occurredAt
      properties:
        commandType:
          type: string
          description: definedValue from apx-command-types.
          examples:
            - courtesyExit
        command:
          description: Reference to the full Command (audit trail).
          $ref: '#/components/schemas/Reference'
        occurredAt:
          $ref: '#/components/schemas/DateTime'
        requestedBy:
          $ref: '#/components/schemas/Reference'
        place:
          $ref: '#/components/schemas/Reference'
        agent:
          type: string
          description: The human or AI principal who initiated the override, copied from the summarized Command's `agent`.
          examples:
            - agent:j.okafor
        agentType:
          type: string
          enum:
            - human
            - ai
          description: Copied from the summarized Command's `agentType`.
        reason:
          type: string
          description: The override's recorded reason, copied from the summarized Command's `reason`.
    SupportInteraction:
      title: SupportInteraction
      description: |-
        One customer-service interaction (human or AI agent), recorded so
        future resolution contexts can surface "they called twice yesterday".
      type: object
      required:
        - id
        - version
        - channel
        - agentType
        - startedAt
        - place
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
        version:
          type: integer
          minimum: 1
          readOnly: true
        channel:
          type: string
          description: voice | chat | email | sms | other (implementer code list).
          examples:
            - voice
        agentType:
          type: string
          enum:
            - human
            - ai
        agent:
          type: string
          description: Agent identifier (human or system principal).
        startedAt:
          $ref: '#/components/schemas/DateTime'
        endedAt:
          $ref: '#/components/schemas/DateTime'
        place:
          $ref: '#/components/schemas/Reference'
        issue:
          $ref: '#/components/schemas/ResolutionIssue'
        summary:
          type: string
          description: Short outcome summary. NOT a transcript — PII minimization (Part 9 §9.6).
        subjects:
          type: object
          description: What/who the interaction was about (all optional).
          properties:
            session:
              $ref: '#/components/schemas/Reference'
            holder:
              $ref: '#/components/schemas/Reference'
            account:
              $ref: '#/components/schemas/Reference'
            credential:
              $ref: '#/components/schemas/Reference'
            reservation:
              $ref: '#/components/schemas/Reference'
            plate:
              type: string
        actions:
          type: array
          description: References to actions executed during the interaction (Commands, PaymentLinks, domain mutations).
          items:
            $ref: '#/components/schemas/Reference'
        interactionId:
          type: string
          description: The calling application's opaque interaction identifier.
          examples:
            - interaction-938383
        resolution:
          type: object
          description: How the interaction ended.
          properties:
            code:
              type: string
              description: A definedValue of apx-interaction-outcomes (Part 11) or an implementer code (Part 17 §17.5).
              examples:
                - resolved
            display:
              type: string
        correlationId:
          type: string
          format: uuid
          description: Correlation chain id (Part 17 §17.7).
        recordInfo:
          $ref: '#/components/schemas/RecordInfo'
        extensions:
          $ref: '#/components/schemas/Extensions'
      examples:
        - id: e7000000-0000-4000-8000-000000000003
          version: 1
          channel: voice
          agentType: ai
          agent: callcenter-ai-agent-07
          startedAt: '2026-09-02T21:14:02Z'
          endedAt: '2026-09-02T21:18:30Z'
          place:
            id: b1000000-0000-4000-8000-000000000001
            className: Place
          issue:
            code: accountBalanceDenied
            display: Monthly parker denied because of outstanding balance
          summary: Balance hold at Exit 3; customer paid $185.00 via payment link; exited normally.
          subjects:
            holder:
              id: c1000000-0000-4000-8000-000000000003
              className: RightHolder
            account:
              id: c2000000-0000-4000-8000-000000000004
              className: Account
            plate: SYN-1234
          actions:
            - id: e6000000-0000-4000-8000-000000000002
              className: PaymentLink
          interactionId: interaction-938383
          resolution:
            code: resolved
            display: Paid and exited
          correlationId: 7c9e6679-7425-40de-944b-e07fc1f90ae7
    ApprovalRequest:
      title: ApprovalRequest
      description: |-
        Asking someone with authority to approve an action before it runs
        (Part 17 §17.3a). An agent whose AllowedAction said `requiresApproval`
        creates one, addressed to a `role` (an escalation role of the place,
        Part 26 §26.5, or the AllowedAction's `approvalRole`); the approver
        decides through `POST /v1/approvals/{id}/decide`; the resulting
        `Approval` evidence on the write cites the request. Every change is
        published as `apx.approvals.changed.v1`.
      allOf:
        - $ref: '#/components/schemas/ApxResourceCore'
        - type: object
          required:
            - place
            - action
            - requestedBy
            - role
            - correlationId
            - status
          properties:
            id:
              type: string
              format: uuid
              readOnly: true
            version:
              type: integer
              minimum: 1
              readOnly: true
              description: Server-managed; bodies carry it only for a versioned replace (Part 4 §4.2a).
            place:
              $ref: '#/components/schemas/Reference'
            action:
              type: string
              description: The apx-command-types value or effective-spec operationId to be approved (the AllowedAction.action).
              examples:
                - post-apx-v1-payments-id-refund
            target:
              description: What the action is to be executed against.
              $ref: '#/components/schemas/Reference'
            requestedBy:
              type: string
              description: The agent asking.
              examples:
                - agent-4471
            agentType:
              type: string
              enum:
                - human
                - ai
            role:
              type: string
              description: The role asked to decide (apx-escalation-roles value or the AllowedAction's approvalRole).
              examples:
                - siteManager
            interactionId:
              type: string
              examples:
                - interaction-938383
            correlationId:
              type: string
              format: uuid
              description: The interaction's correlation id (Part 17 §17.7).
            reason:
              type: string
              description: Why the agent is asking, in one line.
              examples:
                - Customer double charged at the exit; refund of 12.00 USD
            status:
              type: string
              enum:
                - pending
                - approved
                - denied
                - expired
              readOnly: true
            expiresAt:
              description: When a pending request lapses to `expired`. Settable on create; the server MAY default it by policy.
              $ref: '#/components/schemas/DateTime'
            decision:
              readOnly: true
              $ref: '#/components/schemas/ApprovalDecision'
      examples:
        - id: d7000000-0000-4000-8000-000000000001
          version: 2
          place:
            id: b1000000-0000-4000-8000-000000000001
            className: Place
          action: post-apx-v1-payments-id-refund
          target:
            id: e6000000-0000-4000-8000-000000000002
            className: PaymentRecord
          requestedBy: agent-4471
          agentType: human
          role: siteManager
          interactionId: interaction-938383
          correlationId: 6a1f3c2e-7b4d-4e8f-9a0b-1c2d3e4f5a6b
          reason: Customer double charged at the exit; refund of 12.00 USD
          status: approved
          expiresAt: '2026-10-18T14:30:00Z'
          decision:
            outcome: approved
            decidedBy: mgr-lakeside-02
            decidedAt: '2026-10-18T14:09:12Z'
            note: Confirmed on the payment history
    ApprovalDecision:
      title: ApprovalDecision
      description: The decision on an ApprovalRequest (Part 17 §17.3a), also the body of `POST /v1/approvals/{id}/decide`.
      type: object
      required:
        - outcome
        - decidedBy
      properties:
        outcome:
          type: string
          enum:
            - approved
            - denied
        decidedBy:
          type: string
          description: The approving principal, in the role the request named.
          examples:
            - mgr-lakeside-02
        decidedAt:
          readOnly: true
          $ref: '#/components/schemas/DateTime'
        note:
          type: string
    ReceiptRequest:
      title: ReceiptRequest
      description: |-
        Asks the implementation to send the receipt for a settled payment
        again (Part 13 §13.1a). The `destination` travels in the body, never
        in a URL, and is not stored beyond the delivery.
      type: object
      required:
        - channel
      properties:
        channel:
          type: string
          enum:
            - email
            - sms
            - print
            - link
          description: '`print` re-prints at the device the payment was taken on; `link` returns a short-lived URL for the agent to read out or forward.'
        destination:
          type: string
          description: The e-mail address or E.164 number for `email` and `sms`; ignored for `print` and `link`.
          examples:
            - parker@example.com
        agent:
          type: string
          examples:
            - agent-4471
        correlationId:
          type: string
          format: uuid
    ReceiptDelivery:
      title: ReceiptDelivery
      description: The outcome of a receipt request (Part 13 §13.1a).
      type: object
      required:
        - payment
        - channel
        - status
        - requestedAt
      properties:
        payment:
          $ref: '#/components/schemas/Reference'
        channel:
          type: string
          enum:
            - email
            - sms
            - print
            - link
        status:
          type: string
          enum:
            - queued
            - sent
            - failed
        link:
          type: string
          format: uri
          description: For `channel` = `link`, the receipt's short-lived URL.
          examples:
            - https://pay.example/r/8c1d…
        requestedAt:
          $ref: '#/components/schemas/DateTime'
    UiSurface:
      title: UiSurface
      description: |-
        One screen an implementation offers for launch (Part 25 §25.1). Listed
        in the discovery document's `uiSurfaces[]`, so a host learns which
        screens exist, how each may be shown, which launch modes it accepts,
        and which actions it reports back. The `surface` name is a
        definedValue of `apx-ui-surfaces` (`<module>.<view>`, Part 11); its
        registry entry names the subject class the surface opens.
      type: object
      required:
        - surface
        - displayModes
        - launchModes
      properties:
        surface:
          type: string
          description: definedValue from apx-ui-surfaces.
          examples:
            - lane.console
        subjectClass:
          type: string
          description: |-
            The APDS or APX class a launch of this surface opens
            (`VehicularAccess`, `Session`, `Violation`…). Absent for a general
            surface such as `place.console` or `module.home`.
          examples:
            - VehicularAccess
        displayModes:
          type: array
          minItems: 1
          description: |-
            How the host may show the surface. `embed` needs the host's origin
            registered with the implementation (Part 25 §25.6); `popup` is the
            fallback every surface MUST support.
          items:
            type: string
            enum:
              - embed
              - popup
              - tab
        launchModes:
          type: array
          minItems: 1
          description: |-
            `handshake` — the host calls `POST /v1/ui/launches` and opens the
            returned single-use `url`. `signedToken` — the host signs a
            UiLaunchToken and sends it to `launchUrl` (Part 25 §25.3).
          items:
            type: string
            enum:
              - handshake
              - signedToken
        launchUrl:
          type: string
          format: uri
          description: Where a signed launch token is sent (signedToken mode only). HTTPS only.
          examples:
            - https://parcs.example/apx/launch
        actions:
          type: array
          description: |-
            What the surface can report back (Part 25 §25.4): apx-command-types
            values and effective-spec operationIds. A host uses it to decide
            which `returnFields` to ask for.
          items:
            type: string
          examples:
            - - lostTicket
              - applyValidation
              - vendGate
        places:
          type: array
          description: The HierarchyElement subtrees where the surface is offered. Absent means everywhere the credential is granted.
          items:
            $ref: '#/components/schemas/Reference'
    UiLaunchRequest:
      title: UiLaunchRequest
      description: |-
        What the host sends to open a surface for one agent (Part 25 §25.2).
        The same members are the claims of a signed launch token
        (UiLaunchToken). `correlationId` ties everything the agent does in
        the screen back to the host's record; `returnFields` lists the APX
        paths the host wants back when the implementation has to answer with
        a UiActionRecord instead of a native resource.
      type: object
      required:
        - surface
        - place
        - agent
        - agentType
        - correlationId
        - displayMode
      properties:
        surface:
          type: string
          description: definedValue from apx-ui-surfaces.
          examples:
            - lane.console
        subject:
          description: The entity the surface opens on (its class per the surface's registry entry). Required unless the surface is general.
          $ref: '#/components/schemas/Reference'
        place:
          description: The facility the launch concerns; MUST lie inside the caller's grant.
          $ref: '#/components/schemas/Reference'
        lane:
          description: The VehicularAccess, when the launch concerns one lane.
          $ref: '#/components/schemas/Reference'
        agent:
          type: string
          description: The staff member the screen is opened for; the implementation logs them in as this agent.
          examples:
            - agent-4471
        agentType:
          type: string
          enum:
            - human
            - ai
        interactionId:
          type: string
          description: The host's opaque interaction identifier (Part 17 §17.7), echoed on every record the launch produces.
          examples:
            - interaction-938383
        correlationId:
          type: string
          format: uuid
          description: Host-minted correlation id, carried by every native resource, Command, or UiActionRecord that results from the screen (Part 25 §25.4).
        displayMode:
          type: string
          enum:
            - embed
            - popup
            - tab
        returnFields:
          type: array
          description: |-
            JSON-pointer paths, relative to the module resource the surface's
            actions produce, that the host wants back in `UiActionRecord.fields`
            (`/amount`, `/session/id`). A value the implementation cannot
            supply is listed in `unavailable[]` with a reason.
          items:
            type: string
          examples:
            - - /amount
              - /session/id
              - /validation/provider
        expiresIn:
          type: integer
          minimum: 1
          maximum: 60
          default: 60
          description: Seconds the launch `url` stays usable. Never more than 60 (Part 25 §25.6).
    UiLaunch:
      title: UiLaunch
      description: |-
        One opening of a surface for one agent (Part 25 §25.3). Created by the
        handshake (`POST /v1/ui/launches`) or minted by the implementation when
        a signed token is presented. `url` is single-use and expires at
        `expiresAt`; the record itself stays readable for audit and carries
        the `actions[]` the screen reported.
      allOf:
        - $ref: '#/components/schemas/ApxResourceCore'
        - $ref: '#/components/schemas/UiLaunchRequest'
        - type: object
          required:
            - status
            - expiresAt
          properties:
            id:
              type: string
              format: uuid
              readOnly: true
            version:
              type: integer
              minimum: 1
              readOnly: true
              description: Server-managed; bodies carry it only for a versioned replace (Part 4 §4.2a).
            url:
              type: string
              format: uri
              readOnly: true
              description: |-
                The single-use HTTPS address the host opens for the agent.
                Present only on the create response and the first read within
                `expiresAt`; never carries personal data or secrets in its
                query string (Part 25 §25.6).
              examples:
                - https://parcs.example/apx/launch/7f0c…?l=4a1e…
            expiresAt:
              description: When `url` (or the signed token) stops working. At most 60 s after issue.
              $ref: '#/components/schemas/DateTime'
            status:
              type: string
              enum:
                - issued
                - opened
                - closed
                - expired
              description: |-
                `issued` → `opened` on first use of the url or token (single
                use) → `closed` when the screen reports it is done, or
                `expired` when `expiresAt` passes unused. An opened launch not
                closed within the implementation's limit (RECOMMENDED 1 h)
                also becomes `expired` (Part 25 §25.3).
            openedAt:
              $ref: '#/components/schemas/DateTime'
            closedAt:
              $ref: '#/components/schemas/DateTime'
            actions:
              type: array
              readOnly: true
              description: Every UiActionRecord reported for this launch, oldest first (Part 25 §25.4).
              items:
                $ref: '#/components/schemas/UiActionRecord'
    UiActionRecord:
      title: UiActionRecord
      description: |-
        What an agent did in a launched screen when the implementation could
        not express it as the module's own resource or Command (Part 25 §25.4).
        The native resource is always preferred: a lost ticket issued in the
        vendor's screen MUST appear as a `lostTicket` Command carrying the
        launch's `correlationId`. Only an action with no APX operation on this
        implementation is recorded here, with the `fields` the host asked for
        in `returnFields`, and `unavailable[]` for the ones it could not
        supply. Published as `apx.ui.action.recorded.v1`.
      type: object
      required:
        - action
        - outcome
        - occurredAt
        - summary
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
        launch:
          readOnly: true
          description: The UiLaunch this record belongs to.
          $ref: '#/components/schemas/Reference'
        action:
          type: string
          description: |-
            The apx-command-types value or effective-spec operationId the
            action corresponds to, or `other` when none does (Part 25 §25.4).
          examples:
            - lostTicket
        outcome:
          type: string
          enum:
            - completed
            - failed
            - noAction
        occurredAt:
          $ref: '#/components/schemas/DateTime'
        agent:
          type: string
          description: The agent who acted; defaults to the launch's `agent`.
          examples:
            - agent-4471
        summary:
          type: string
          description: One line a host can show in the call record. Carries no personal data beyond what the host already holds.
          examples:
            - Lost ticket issued at the exit lane, fee collected
        result:
          description: The native resource or Command the action produced, when one exists (then `fields` MAY be omitted).
          $ref: '#/components/schemas/Reference'
        fields:
          type: object
          description: The values the host asked for, keyed by the `returnFields` path.
          additionalProperties: {}
          examples:
            - /amount:
                amount: 25
                currency: USD
              /session/id: e5000000-0000-4000-8000-000000000001
        unavailable:
          type: array
          description: Requested paths the implementation could not fill, and why.
          items:
            type: object
            required:
              - field
              - reason
            properties:
              field:
                type: string
                examples:
                  - /validation/provider
              reason:
                type: string
                enum:
                  - notSupported
                  - notApplicable
        correlationId:
          type: string
          format: uuid
          description: The launch's correlation id, echoed.
      examples:
        - id: d9000000-0000-4000-8000-000000000011
          launch:
            id: d9000000-0000-4000-8000-000000000001
            className: UiLaunch
          action: lostTicket
          outcome: completed
          occurredAt: '2026-10-18T14:07:40Z'
          agent: agent-4471
          summary: Lost ticket issued at the exit lane, fee collected
          fields:
            /amount:
              amount: 25
              currency: USD
            /session/id: e5000000-0000-4000-8000-000000000001
          unavailable:
            - field: /validation/provider
              reason: notApplicable
          correlationId: 6a1f3c2e-7b4d-4e8f-9a0b-1c2d3e4f5a6b
    UiLaunchToken:
      title: UiLaunchToken
      description: |-
        INFORMATIVE. The claims of a signed launch token (JWS, ES256 or RS256)
        in the `signedToken` launch mode (Part 25 §25.3). `aud` is the
        implementation, `exp` is at most 60 s after `iat`, `jti` is unique and
        single-use. The remaining claims are the UiLaunchRequest members. The
        token travels by form POST or in the URL fragment, never in the query
        string, and the implementation checks it against the host's keys
        registered at onboarding (Part 25 §25.6).
      allOf:
        - $ref: '#/components/schemas/UiLaunchRequest'
        - type: object
          required:
            - iss
            - aud
            - exp
            - iat
            - jti
          properties:
            iss:
              type: string
              description: The host's issuer identifier, as registered.
              examples:
                - https://callcenter.example
            aud:
              type: string
              description: The implementation the token is for.
              examples:
                - https://parcs.example
            exp:
              type: integer
              description: Expiry, seconds since the epoch; at most `iat` + 60.
            iat:
              type: integer
              description: Issued at, seconds since the epoch.
            jti:
              type: string
              description: Unique token id; the implementation refuses a replay.
    EquipmentDetail:
      title: EquipmentDetail
      description: |-
        What a piece of hardware is, where it is, and what it does (Part 26
        §26.1). Carried on an APDS SupplementalEquipment as the Level B
        decoration `apds-ext:apx:equipment-detail@1.0` in its `extensions`
        container (Part 4 §4.3). The equipment TYPE stays the APDS
        `EquipmentTypeEnum` (often `paymentMachine` or `other`); `role` says
        what the item does on the site, from the fixed code list
        `apx-equipment-roles`.

        `firmwareVersion` and `softwareVersion` are optional but RECOMMENDED,
        and readable by every client of the place, because knowing what runs
        on each device is what makes integration at scale possible. IP
        addresses are deliberately left out in the interest of security:
        together with model and firmware they map a site's network for an
        attacker, and no APX flow connects to a device directly. They could
        be added later, as an optional member behind a restricted scope, if a
        real need arises. MAC addresses stay, as the hardware identity when
        the serial label is gone or when the MAC is the serial.
      type: object
      required:
        - role
      properties:
        role:
          type: string
          description: definedValue from apx-equipment-roles (a fixed list; `other` is a code, not free text).
          examples:
            - exitVerifier
        manufacturer:
          type: string
          examples:
            - Amano McGann
        model:
          type: string
          examples:
            - AGP-1500
        firmwareVersion:
          type: string
          examples:
            - 4.2.1
        softwareVersion:
          type: string
          description: The application software on the device, when distinct from its firmware.
          examples:
            - '2026.3'
        serialNumber:
          type: string
          examples:
            - AMG-55-20318
        macAddresses:
          type: array
          description: One per network interface, lower-case hex without separators.
          items:
            type: string
            pattern: ^[0-9a-f]{12}$
          examples:
            - - 001a2b3c4d5e
        installedAt:
          type: string
          format: date
          examples:
            - '2024-03-18'
        area:
          type: string
          description: Where on the site the item is, a definedValue from apx-area-types (Part 26 §26.2).
          examples:
            - lane
        level:
          type: string
          description: The floor label as signed on site.
          examples:
            - P1
        lane:
          description: The VehicularAccess the item serves. Absent for place-level equipment (an access door, a pay-on-foot station, a server).
          $ref: '#/components/schemas/Reference'
        builtInto:
          description: The host equipment this item is part of (an intercom in a door's call box, a camera in a pay station).
          $ref: '#/components/schemas/Reference'
        controls:
          type: array
          description: The barriers this device opens (an exit verifier that controls gate 2, a card reader that controls an access door).
          items:
            $ref: '#/components/schemas/Reference'
        serviceProvider:
          type: object
          description: Who services the item. An organisation and a support reference, never a person.
          properties:
            organisation:
              $ref: '#/components/schemas/Reference'
            supportReference:
              type: string
              description: The provider's own reference for this unit or contract (an asset tag, a contract number).
              examples:
                - SVC-2024-0918
      examples:
        - role: exitVerifier
          manufacturer: Amano McGann
          model: AGP-1500
          firmwareVersion: 4.2.1
          softwareVersion: '2026.3'
          serialNumber: AMG-55-20318
          macAddresses:
            - 001a2b3c4d5e
          installedAt: '2024-03-18'
          area: lane
          level: P1
          lane:
            id: b2000000-0000-4000-8000-000000000002
            className: VehicularAccess
          controls:
            - id: c2000000-0000-4000-8000-000000000021
              className: SupplementalEquipment
          serviceProvider:
            organisation:
              id: a1000000-0000-4000-8000-000000000009
              className: Organisation
            supportReference: SVC-2024-0918
    CameraDetail:
      title: CameraDetail
      description: |-
        A camera anywhere on the site, not only on a lane (Part 26 §26.3).
        Carried on a SupplementalEquipment whose EquipmentDetail `role` is
        `camera`, as the Level B decoration `apds-ext:apx:camera@1.0`. Where
        the camera is (`area`, `level`, `lane`) and what it is built into
        (`builtInto`) are EquipmentDetail members, shared with every other
        piece of hardware; this decoration adds how it is mounted, what it
        looks at, and how it can be viewed. It holds no addresses, usernames
        or passwords: a view is obtained through `POST /v1/cameras/{id}/views`
        and the password never leaves the site (Part 26 §26.3). Camera models
        and stream profiles follow ONVIF (Profile S, Profile T) and are not
        redefined. `apds-ext:apx:lane-cameras@1.0` (Part 13) is unchanged.
      type: object
      required:
        - view
      properties:
        mounting:
          type: string
          enum:
            - builtIn
            - overhead
            - pole
            - wall
            - ceiling
            - other
          description: When `builtIn`, EquipmentDetail `builtInto` names the host, for example a pay station's driver camera.
        view:
          type: array
          minItems: 1
          description: What the camera looks at; one camera may cover several.
          items:
            type: string
            enum:
              - plate
              - vehicle
              - driver
              - equipmentInteraction
              - pedestrians
              - areaOverview
              - other
        faces:
          type: string
          enum:
            - inward
            - outward
          description: For lanes, plazas and ramps, relative to the facility (Part 13 §13.3a).
        primary:
          type: boolean
          description: Show this camera first for its lane or area.
        ptz:
          type: boolean
          description: Can pan, tilt and zoom.
        recorder:
          type: object
          description: The DVR or NVR that records it (an equipment item with role `videoRecorder`) and the channel.
          properties:
            equipment:
              $ref: '#/components/schemas/Reference'
            channel:
              type: string
              examples:
                - '7'
        streams:
          type: array
          description: What the camera can deliver, so a host knows what kind of view to ask for.
          items:
            type: object
            required:
              - protocol
            properties:
              protocol:
                type: string
                enum:
                  - webrtc
                  - hls
                  - rtsp
                  - mjpeg
                  - snapshot
              transport:
                type: string
                examples:
                  - tcp
              resolution:
                type: string
                examples:
                  - 1920x1080
        retentionDays:
          type: integer
          minimum: 0
          description: How long recordings are kept; stated per camera because `driver` and `pedestrians` views capture faces (Part 26 §26.3).
          examples:
            - 30
        credentialRef:
          type: string
          description: |-
            For a camera that cannot sit behind a gateway, the label of the
            credential the receiving system looks up in its own vault. NEVER
            the secret itself; the secret is exchanged once, outside APX, at
            onboarding (Part 9 §9.7).
          examples:
            - site-0042/cam-door-1
      examples:
        - mounting: wall
          view:
            - pedestrians
          primary: true
          ptz: false
          recorder:
            equipment:
              id: c2000000-0000-4000-8000-000000000090
              className: SupplementalEquipment
            channel: '7'
          streams:
            - protocol: webrtc
            - protocol: snapshot
          retentionDays: 30
    ExternalIdentifiers:
      title: ExternalIdentifiers
      description: |-
        The ids other systems use for the same place, lane or equipment
        (Part 26 §26.6). Carried on any HierarchyElement as the Level B
        decoration `apds-ext:apx:external-ids@1.0`. APDS
        `SupplementalFacility.externalIdentifiers` holds untyped strings; here
        each id says which system issued it. `system` is a URI the issuer
        owns, usually its own domain, so APX names no products or platforms.
        `POST /v1/identifiers:resolve` finds the APX record from such an id.
      type: object
      required:
        - identifiers
      properties:
        identifiers:
          type: array
          minItems: 1
          items:
            type: object
            required:
              - system
              - id
            properties:
              system:
                type: string
                format: uri
                description: A URI owned by the system that issued the id.
                examples:
                  - https://parcs.example
              id:
                type: string
                examples:
                  - LOT-0042
      examples:
        - identifiers:
            - system: https://parcs.example
              id: LOT-0042
            - system: https://calls.example
              id: acct-7f31
    PlaceOperations:
      title: PlaceOperations
      description: |-
        Operational facts about a place that a call centre needs before a
        call (Part 26 §26.5). Carried on a place HierarchyElement as the
        Level B decoration `apds-ext:apx:place-operations@1.0`.
        `escalationContacts` lists roles in calling order, never names or
        phone numbers: the call platform holds those, so APX carries no
        personal contact data. A Part 17 approval request is addressed to a
        role from this list.
      type: object
      properties:
        commsAccountId:
          type: string
          description: The id the call platform uses for the whole site (its account), the site-level pair of `CommsPoint.commsDeviceId`.
          examples:
            - acct-7f31
        escalationContacts:
          type: array
          description: Who to escalate to, by role, in order.
          items:
            type: object
            required:
              - role
              - order
            properties:
              role:
                type: string
                description: definedValue from apx-escalation-roles.
                examples:
                  - siteManager
              order:
                type: integer
                minimum: 1
                description: Calling order; 1 is tried first.
              hours:
                description: When this role is reachable. Absent means always.
                $ref: '#/components/schemas/Period'
      examples:
        - commsAccountId: acct-7f31
          escalationContacts:
            - role: attendant
              order: 1
            - role: siteManager
              order: 2
            - role: operatorOnCall
              order: 3
    CommsPoint:
      title: CommsPoint
      description: |-
        Any way a parker reaches help from a lane or a location (Part 26
        §26.4): an intercom, an analog dialler, a posted phone number, a
        kiosk, a QR code, an app. A call platform matches an inbound contact
        to a comms point by the number it calls out as (`callerId`), the
        number it called (`phoneNumber`), or its own device id
        (`commsDeviceId`), and APX then answers with the lane, or with the
        location only when the comms point serves no single lane (a posted
        number shared by many lanes can never name the lane by itself).

        These are the only members of APX that carry telephony values, and
        the call platform supplies them; a PARCS implementation never has to
        hold, return or understand them (Part 17 §17.1). SIP usernames,
        realms and passwords are deliberately left out: a username with its
        realm is half of a line's login, they exist only for SIP devices, and
        the call platform already maps its own SIP data to these ids. A SIP
        password or any other credential MUST never appear in any member.
      allOf:
        - $ref: '#/components/schemas/ApxResourceCore'
        - type: object
          required:
            - type
            - place
          anyOf:
            - required:
                - phoneNumber
            - required:
                - callerId
            - required:
                - commsDeviceId
          properties:
            id:
              type: string
              format: uuid
              readOnly: true
            version:
              type: integer
              minimum: 1
              readOnly: true
              description: Server-managed; bodies carry it only for a versioned replace (Part 4 §4.2a).
            type:
              type: string
              description: definedValue from apx-comms-point-types.
              examples:
                - intercom
            place:
              description: The location it serves.
              $ref: '#/components/schemas/Reference'
            lane:
              description: The VehicularAccess it serves, when it serves exactly one.
              $ref: '#/components/schemas/Reference'
            equipment:
              description: The SupplementalEquipment it is, when it is inventoried hardware (role `intercom`, `analogDialer`, `emergencyPhone`).
              $ref: '#/components/schemas/Reference'
            serves:
              description: The barrier an agent opens for this comms point, a gate or an access door, when there is one.
              $ref: '#/components/schemas/Reference'
            phoneNumber:
              type: string
              pattern: ^\+[1-9][0-9]{1,14}$
              description: E.164. The number that is called when help is requested, dialled by the parker for a posted number, or by the intercom or dialler when its button is pushed.
              examples:
                - '+15555550142'
            callerId:
              type: string
              pattern: ^\+[1-9][0-9]{1,14}$
              description: E.164. The number the device calls out as.
              examples:
                - '+15555550199'
            commsDeviceId:
              type: string
              description: The id the call platform uses for this comms point when it identifies it by neither caller id nor dialled number.
              examples:
                - dev-51cc-ae16
            coverage:
              type: array
              description: When the comms point is answered and in which languages. The answering call centre itself is not named.
              items:
                type: object
                properties:
                  period:
                    $ref: '#/components/schemas/Period'
                  languages:
                    type: array
                    description: BCP 47 language tags.
                    items:
                      type: string
                    examples:
                      - - en
                        - es
      examples:
        - id: c3000000-0000-4000-8000-000000000001
          version: 1
          type: intercom
          place:
            id: b1000000-0000-4000-8000-000000000001
            className: Place
          lane:
            id: b2000000-0000-4000-8000-000000000002
            className: VehicularAccess
          equipment:
            id: c2000000-0000-4000-8000-000000000023
            className: SupplementalEquipment
          serves:
            id: c2000000-0000-4000-8000-000000000021
            className: SupplementalEquipment
          callerId: '+15555550199'
          commsDeviceId: dev-51cc-ae16
          coverage:
            - languages:
                - en
                - es
    EquipmentRecord:
      title: EquipmentRecord
      description: |-
        An APDS SupplementalEquipment as APX serves it (Part 26 §26.1): the
        stock APDS record plus its `extensions` container, which carries the
        `apds-ext:apx:equipment-detail@1.0` decoration (REQUIRED on every
        record this class serves), `apds-ext:apx:camera@1.0` on a camera, and
        `apds-ext:apx:external-ids@1.0` where other systems have ids for it.
        The APDS record itself is never reshaped.
      allOf:
        - $ref: '#/components/schemas/SupplementalEquipment'
        - type: object
          properties:
            extensions:
              $ref: '#/components/schemas/Extensions'
    IdentifierResolveRequest:
      title: IdentifierResolveRequest
      description: An external id to look up (Part 26 §26.6), as it appears in an ExternalIdentifiers entry.
      type: object
      required:
        - system
        - id
      properties:
        system:
          type: string
          format: uri
          examples:
            - https://parcs.example
        id:
          type: string
          examples:
            - LOT-0042
    IdentifierResolution:
      title: IdentifierResolution
      description: The APX record an external id names (Part 26 §26.6).
      type: object
      required:
        - target
        - className
      properties:
        target:
          description: The place, lane, equipment or comms point found.
          $ref: '#/components/schemas/Reference'
        className:
          type: string
          description: The target's class, repeated for convenience.
          examples:
            - VehicularAccess
        place:
          description: The place the target belongs to (the target itself when it is a place).
          $ref: '#/components/schemas/Reference'
    CameraViewRequest:
      title: CameraViewRequest
      description: |-
        Asks for a short-lived link to see a camera (Part 26 §26.3). Whoever
        holds the camera answers, the PARCS, the video system or an on-site
        gateway, and the camera's password never leaves the site. `playback`
        needs `from` and `to` and the `cameraPlayback` feature.
      type: object
      required:
        - kind
        - agent
        - correlationId
      properties:
        kind:
          type: string
          enum:
            - live
            - snapshot
            - playback
        from:
          $ref: '#/components/schemas/DateTime'
        to:
          $ref: '#/components/schemas/DateTime'
        agent:
          type: string
          description: The staff member the view is issued to; every view is logged against them.
          examples:
            - agent-4471
        agentType:
          type: string
          enum:
            - human
            - ai
        correlationId:
          type: string
          format: uuid
          description: The interaction the view belongs to; a view link MUST NOT be reused outside it.
        interactionId:
          type: string
          examples:
            - interaction-938383
    CameraView:
      title: CameraView
      description: |-
        A single-use, short-lived link to a camera's live stream, a still, or
        a recording (Part 26 §26.3). Bound to the agent it was issued to and
        logged against the `correlationId`; it expires at `expiresAt`, never
        more than 5 minutes after issue, and it never contains a camera
        credential.
      type: object
      required:
        - id
        - camera
        - kind
        - url
        - expiresAt
      properties:
        id:
          type: string
          format: uuid
        camera:
          $ref: '#/components/schemas/Reference'
        kind:
          type: string
          enum:
            - live
            - snapshot
            - playback
        url:
          type: string
          format: uri
          examples:
            - https://video.example/v/9c2f…
        protocol:
          type: string
          enum:
            - webrtc
            - hls
            - rtsp
            - mjpeg
            - snapshot
          description: What the link serves (`snapshot` is an image).
        expiresAt:
          $ref: '#/components/schemas/DateTime'
        issuedTo:
          type: string
          description: The agent, echoed.
          examples:
            - agent-4471
        from:
          $ref: '#/components/schemas/DateTime'
        to:
          $ref: '#/components/schemas/DateTime'
      examples:
        - id: c4000000-0000-4000-8000-000000000001
          camera:
            id: c2000000-0000-4000-8000-000000000031
            className: SupplementalEquipment
          kind: live
          url: https://video.example/v/9c2f0e1a
          protocol: webrtc
          expiresAt: '2026-10-18T14:12:00Z'
          issuedTo: agent-4471
    DisplayRecord:
      title: DisplayRecord
      description: |-
        The record that a sign showed a message (Part 26 §26.9): which sign,
        which kind of message, when, and for which read or stay. Written by
        whichever system drove the display, the edge controller, the PARCS or
        the sign's own player, often with no APX command involved; immutable
        once written. It is the proof of display a refused-service message
        needs (Part 24 §24.4), and the data an operator measures the signs by.

        The proof members are the Part 6 §6.1a `CommandResult.display` shape,
        unchanged. The message text is never stored, only its hash and wording
        version, and the plate is never stored even when the sign shows it
        (Part 9 §9.6 rule 8). When a `displayMessage` command drove the sign,
        `command` names it and the record MUST agree with its result.
      allOf:
        - $ref: '#/components/schemas/ApxResourceCore'
        - $ref: '#/components/schemas/DisplayProof'
        - type: object
          required:
            - display
            - messageKind
            - shownTime
          properties:
            id:
              type: string
              format: uuid
              readOnly: true
            version:
              type: integer
              minimum: 1
              readOnly: true
            display:
              description: The sign, a SupplementalEquipment of §26.1 (role `laneDisplay` or `countSign`).
              $ref: '#/components/schemas/Reference'
            place:
              description: The place of the display; the server derives it from the device, and a body value that disagrees is 422 `request-unprocessable`.
              $ref: '#/components/schemas/Reference'
            messageKind:
              type: string
              description: definedValue of apx-display-message-kinds, or an implementer code for a location's own messages.
              examples:
                - transientExitUnpaid
            observation:
              description: The read that triggered the message (className `ObservationElement`), when there was one.
              $ref: '#/components/schemas/Reference'
            session:
              description: The stay the message was for (className `Session`), when there was one.
              $ref: '#/components/schemas/Reference'
            command:
              description: The Part 6 `displayMessage` command that drove the sign, when one did; `shownTime` and `contentHash` then agree with its `CommandResult.display`.
              $ref: '#/components/schemas/Reference'
      examples:
        - id: c5000000-0000-4000-8000-000000000001
          version: 1
          display:
            id: c2000000-0000-4000-8000-000000000041
            className: SupplementalEquipment
          place:
            id: b1000000-0000-4000-8000-000000000001
            className: Place
          messageKind: transientExitUnpaid
          observation:
            id: f3000000-0000-4000-8000-000000000140
            className: ObservationElement
          session:
            id: c4000000-0000-4000-8000-000000000077
            className: Session
          shownTime: '2026-10-21T14:03:12Z'
          contentHash: sha256:9f2c1e0b7a4d
          wordingVersion: exit-2026-10
          acknowledgedBy: player
    DisplayProof:
      title: DisplayProof
      description: |-
        What a sign or display confirmed it showed, and when (Part 6 §6.1a):
        `CommandResult.display` for a commanded message, and the proof members
        of a Part 26 §26.9 DisplayRecord for any message. Carries a hash and
        the wording version, never the message text.
      type: object
      properties:
        shownTime:
          $ref: '#/components/schemas/DateTime'
        contentHash:
          type: string
          description: Hash of the rendered content, so a dispute can prove what was shown.
        wordingVersion:
          type: string
          description: The wording version the template was rendered under.
        screenshot:
          description: Access-controlled link to a capture of the display (Part 9 §9.6).
          $ref: '#/components/schemas/Url'
        acknowledgedBy:
          type: string
          enum:
            - player
            - operator
            - none
    ApxConfiguration:
      type: object
      description: Unauthenticated bootstrap configuration document.
      required:
        - apxVersion
        - apdsVersion
        - tokenEndpoint
        - conformanceClasses
      properties:
        apxVersion:
          type: string
          description: |-
            APX standard version implemented (semver). This is the edition
            (Part 3 §3.4) whose Parts and registries the implementation
            follows; when `edition` is also present the two are equal.
          examples:
            - 0.1.0
        edition:
          type: string
          description: The APX edition implemented (Part 3 §3.4), as named in its `spec/edition.json`.
          examples:
            - 0.16.0
        apdsVersion:
          type: string
          description: APDS version this implementation extends.
          examples:
            - '4.1'
        tokenEndpoint:
          type: string
          format: uri
          description: OAuth2 token endpoint (client-credentials grant).
        apiBase:
          type: string
          format: uri
          description: |-
            The URL every path in the bundle is relative to (APX `/v1/…` and
            APDS-native routes alike). Absent means the origin root that serves
            this document. REQUIRED when the API is mounted elsewhere (Part 16
            §16.1).
          examples:
            - https://api.citypark.example/parking
        conformanceClasses:
          type: array
          description: |-
            APX conformance classes this implementation supports, closed under
            the Part 3 §3.1 dependency table, plus any vendor classes
            (`<vendor-ns>-<class>`). Clients ignore classes they do not
            recognise.
          items:
            type: string
          examples:
            - - apx-data
              - apx-events
              - apx-control
              - apx-alerts
              - apx-discovery
        features:
          type: array
          description: Optional features the implementation offers — definedValues from `apx-features` or vendor features (Part 6 §6.5, Part 11, Part 16 §16.1).
          items:
            type: string
          examples:
            - - negotiatedRates
              - ticketMatching
        registries:
          type: object
          description: |-
            Locations of the published UserDefinedCodeList registries, keyed by
            the registry `name` from Part 11 (vendor lists by their own name).
          additionalProperties:
            type: string
            format: uri
        registryVersions:
          type: object
          description: The version of each registry the implementation validates against, keyed as `registries`.
          additionalProperties:
            type: integer
            minimum: 1
          examples:
            - apx-command-types: 3
        extensions:
          $ref: '#/components/schemas/Extensions'
    HierarchyElementTypeEnum:
      title: HierarchyElementTypeEnum
      description: |-
        Defines the supported lists of types of parking hierarchy elements permissible
        * campus : a data structure holding information about a large, often ill-defined area, which may contain many parking structures.
        * identifiedArea : a data structure holding information about a coherent feature, such as a set of parking spaces that all share the same characteristics.
        * place : a data structure holding information about a single identifiable parking place.
        * space : a data structure holding information about a single space for parking, usually designed for one vehicle, which may be denoted by painted or other road surface markers.
        * subplaceElement : a sub-division of a place for the convenience of the operator that may be used for parking related or other purposes.
        * specificArea : a specialisation of an identified area that denotes a specific geographic area in a place that has a common physical infrastructure purpose and common characteristics.
        * vehicularAccess : a specialisation of an identified area defining vehicular access areas.
        * electricChargingEquipment : a specialisation of a supplemental facility for electric charging areas.
        * supplementalEquipment : a specialisation of a supplemental facility which is available on some site, for example on a rest area.
        * supplementalServiceFacility : a specialisation of a supplemental facility to specify the type and number of available sub-facilities, for example 20 restaurants.
      type: string
      x-package: place.enums
      enum:
        - campus
        - identifiedArea
        - place
        - space
        - subplaceElement
        - specificArea
        - vehicularAccess
        - electricChargingEquipment
        - supplementalEquipment
        - supplementalServiceFacility
    RightSpecificationTypeEnum:
      title: RightTypeEnum
      description: |-
        Defines the type of RightSpecification
        * accessPermission : intended grant access permission
        * loadingUnloading : intended granting permissions to load and unload vehicles.
        * oneTimeUseParking : intended for one time or limited parking usage
        * permitParking : intended for multi-use parking usage
        * setDownPickup : intended for passenger set down and pick up
        * waiting : intended to grant permission for an accompanied vehicle to wait
      type: string
      x-package: right_specification.enums
      enum:
        - accessPermission
        - loadingUnloading
        - oneTimeUseParking
        - permitParking
        - setdownPickup
        - waiting
    StructureTypeEnum:
      title: StructureTypeEnum
      description: |-
        A list of types of parking structure.
        * offStreetStructure : Off-street multi-tier parking structure.
        * offStreetSurface : Off-street ground-level at grade parking.
        * onStreet : On-street parking.
      type: string
      x-package: place.enums
      enum:
        - offStreetStructure
        - offStreetSurface
        - onStreet
    StructureGradeEnum:
      title: StructureGradeEnum
      description: |-
        Types of layout of the parking site.
        * aboveGround : Parking is above ground level (this may include ground level parking)
        * groundLevel : Parking is at ground level
        * underground : Parking is on one or more floors below ground level
      type: string
      x-package: place.enums
      enum:
        - aboveGround
        - groundLevel
        - underground
    PaginatedListMeta:
      title: PaginatedListMeta
      description: Metadata for paginated list of results for listing API endpoints.
      type: object
      x-package: api
      properties:
        referenceInstant:
          type: integer
          description: Unix epoch time to be used as reference which should be the same for all pages. Allows a consistent view of data across multiple paged requests.
          minimum: 0
          examples:
            - 1709840615
        offset:
          type: integer
          minimum: 0
          description: Index of the first item returned in the page.
          examples:
            - 0
        pageSize:
          type: integer
          description: Maximum number of items that can be returned per page.
          minimum: 0
          examples:
            - 100
        total:
          type: integer
          description: Total number of items contained in all pages.
          minimum: 0
          examples:
            - 1
      required:
        - referenceInstant
        - offset
        - pageSize
        - total
    DateTime:
      title: DateTime
      description: ISO-8601 format definition of a date and time - format YYYY-MM-DDTHH:MM:SSZ.
      type: string
      x-package: common
      format: date-time
      examples:
        - '2024-03-09T15:35:08Z'
    DeletedReference:
      title: DeletedReference
      description: A reference to a deleted identifiable managed object where the identifier is unique. It is described by a string identifying the class of the referenced object (key name) with a unique string identifier as its value, and the deletion instant.
      type: object
      x-package: api
      properties:
        id:
          type: string
          description: The unique id of the deleted object.
        className:
          type: string
          description: The class name of the deleted object.
          pattern: ^([A-Z][a-z0-9]+)+
        deleteTimestamp:
          description: The instant when the reference was deleted.
          $ref: '#/components/schemas/DateTime'
      required:
        - id
        - className
        - deleteTimestamp
    PaginatedList:
      title: PaginatedList
      description: Paginated list of results for listing API endpoints.
      type: object
      x-package: api
      properties:
        meta:
          $ref: '#/components/schemas/PaginatedListMeta'
        deletedReferences:
          type: array
          description: This attribute will returned when the `modified_since` query parameter is used. It will contain references to deleted resources since the provided instant, that would have otherwise been included in the dataset (either at the top-level or as associated objects).
          items:
            $ref: '#/components/schemas/DeletedReference'
      required:
        - meta
    HierarchyElement:
      title: HierarchyElement
      description: A generalised component of a place hierarchy, that forms one element in the tree-like hierarchy. This forms a reusable block of the hierarchy, with relations to its parent element (if one exists) and any child elements. Each Place element in the hierarchy shall have a name, and may support a free-text description and an operator/property owner defined reference (e.g. location number/identifier)'
      type: object
      x-package: place
      discriminator:
        propertyName: type
        mapping:
          campus: '#/components/schemas/Campus'
          place: '#/components/schemas/Place'
          space: '#/components/schemas/Space'
      allOf:
        - $ref: '#/components/schemas/VersionedIdentity'
        - type: object
          properties:
            type:
              $ref: '#/components/schemas/HierarchyElementTypeEnum'
            name:
              $ref: '#/components/schemas/MultilingualString'
            description:
              $ref: '#/components/schemas/MultilingualString'
            aliases:
              type: array
              description: Alternative names for the hierarchy element.
              items:
                $ref: '#/components/schemas/MultilingualString'
            operatorDefinedReference:
              $ref: '#/components/schemas/VersionedReference'
            parentId:
              $ref: '#/components/schemas/VersionedReference'
            childIds:
              type: array
              readOnly: true
              description: The identity of one or several child nodes directly related to this hierarchy element.
              items:
                $ref: '#/components/schemas/VersionedReference'
            layer:
              type: integer
              minimum: 0
              description: Indicator of the position of this hierarchy element in the specific hierarchy, with the top of the hierarchy numbered layer 0.
            rightSpecifications:
              type: array
              readOnly: true
              description: RightSpecifications associated to the element
              items:
                $ref: '#/components/schemas/VersionedReference'
            hierarchyElementRecord:
              readOnly: true
              $ref: '#/components/schemas/HierarchyElementRecord'
            hierarchyElementReference:
              $ref: '#/components/schemas/HierarchyElementReference'
            occupancyLevel:
              $ref: '#/components/schemas/OccupancyLevel'
            responsibilityRoleAssignments:
              description: roles and responsibilities
              type: array
              items:
                $ref: '#/components/schemas/ResponsibilityRoleAssignment'
            extensions:
              description: The APDS extension container (Use Case Document §C.2.5; Part 4 §4.3). Undeclared on APDS 4.1 entities (APX erratum 010).
              $ref: '#/components/schemas/Extensions'
      required:
        - type
        - name
        - layer
        - hierarchyElementRecord
    Campus:
      title: Campus
      description: The highest level in the hierarchy, it typically defines a large facility (such as a university campus, or an airport), or a large geographic zone (such as a city or a town), which may contain numerous Places. A Campus combines and encompasses a number of Places that can be logically reported together.
      type: object
      x-package: place
      allOf:
        - $ref: '#/components/schemas/HierarchyElement'
    CoveredTypeEnum:
      title: CoveredTypeEnum
      description: |-
        Defines the supported lists of different types describing roof coverage of the facility or entity
        * covered: Indicates that the facility or specific entity has a roof to provide protection from direct overhead sun or adverse weather
        * notCovered: Indicates that the facility or specific entity has no roof to provide protection from direct overhead sun or adverse weather
        * partiallyCovered: Indicates that the facility or specific entity has a roof offering partial coverage to provide protection from direct overhead sun or adverse weather
        * topLevelNotCovered: Indicates that in a multi-level facility or specific entity the top level(s) have no roof to provide protection from direct overhead sun or adverse weather
      type: string
      x-package: place.characteristics.enums
      enum:
        - covered
        - notCovered
        - partiallyCovered
        - topLevelNotCovered
    AccessibilityTypeEnum:
      title: AccessibilityTypeEnum
      description: |-
        Special forms of accessibility, easements and marking for disabled people.
        * barrierFreeAccessible: Accessible without any steps or other barriers. Does not ensure the same access as disabledAccessible.
        * disabledAccessible: Accessible for disabled people. wheelChairAccessible is a special form of it.
        * disabledEasements: There are special easements for disabled people, like handrails or disabled-friendly furniture.
        * disabledMarkedThere: is a visible mark to support access by disabled people (e.g. a wheelchair symbol).
        * none: No form of special accessibility, i.e. usually not convenient for disabled people, e.g. because of steps or barriers.
        * orientationSystemForBlindPeople: There is some orientation system, which helps blind or visually impaired people. Examples might be some acoustic system or tactile paving.
        * other: Other.
        * unknown: It is unknown, whether there is a special form of accessibility.
        * wheelChairAccessible: Accessible by people in a wheelchair.
      type: string
      x-package: place.characteristics.enums
      enum:
        - barrierFreeAccessible
        - disabledAccessible
        - disabledEasements
        - disabledMarkedThere
        - none
        - orientationSystemForBlindPeople
        - other
        - unknown
        - wheelChairAccessible
    OperatingModeTypeEnum:
      title: OperatingModeTypeEnum
      description: |-
        A list of supported parking operation modes
        * app : App â€“ payment is collected via an app that may also control access to the facility.
        * payAndDisplay : PND â€“ pay and display. Vehicle displays a credential to show it is paid. Typically prepaid and short term.
        * payByPlate : PBP - pay by plate - vehicle registration or license plate is used for recording and enforcement either on street or off street. Payment is collected on a prepaid basis or at the exit.
        * payBySpace : PBS â€“ pay by space. Vehicle makes a payment based on occupying a specific space. Typically prepaid.
        * permit : Similar to PND but for long term parking (e.g. monthly pass, quarterly, semester).
        * ticket : Payment is done with a ticket (e.g. with magnetic strip, barcode). Payment is collected at the exit.
      type: string
      x-package: place.characteristics.enums
      enum:
        - app
        - payAndDisplay
        - payByPlate
        - payBySpace
        - permit
        - ticket
    StaffEnum:
      title: StaffEnum
      description: |-
        A list of supported values for staffing characteristics
        * staffed : Normally staffed during operating hours
        * temporary : Staffed on a temporary or part time basis.
        * unstaffed : Not normally staffed during operating hours
      type: string
      x-package: place.characteristics.enums
      enum:
        - staffed
        - temporary
        - unstaffed
    PlaceCharacteristics:
      title: PlaceCharacteristics
      description: Defines information concerning characteristics related to a parking facility.
      type: object
      x-package: place.characteristics
      properties:
        openToPublic:
          description: Identifies if this facility is accessible to public use (TRUE) or private use only (FALSE).
          type: boolean
        accessControlled:
          type: boolean
          description: Indicates facility has physical access control (e.g. barriers, gates) (TRUE) or no access control (FALSE).
        robotic:
          type: boolean
          description: Indicates existence of a robotic parking system (a parking structure where customer leaves vehicle at drop off area and robots move the vehicle to parking location within the structure). Default is (FALSE).
        coveredType:
          $ref: '#/components/schemas/CoveredTypeEnum'
        disabledAccess:
          type: boolean
          description: Specifies if there is provision of facilities for disable access (TRUE) or not (FALSE).
        disabledAccessTypes:
          type: array
          description: Defines the type of provision of facilities for disable access available.
          items:
            $ref: '#/components/schemas/AccessibilityTypeEnum'
        operatingModes:
          type: array
          description: Defines the mode of parking operation in use.
          items:
            $ref: '#/components/schemas/OperatingModeTypeEnum'
        spacesNonDedicated:
          type: integer
          description: Number of parking spaces that are not assigned for a particular purpose.
          minimum: 0
        spacesTotal:
          type: integer
          description: Total number of parking spaces
          minimum: 0
        staffed:
          $ref: '#/components/schemas/StaffEnum'
        structureGrade:
          $ref: '#/components/schemas/StructureGradeEnum'
        structureType:
          $ref: '#/components/schemas/StructureTypeEnum'
        evChargingPoints:
          type: integer
          description: Total number of electric vehicle charging points.
          minimum: 0
    Contact:
      title: Contact
      description: Address and contact information about some person, service or the parking site, provided in detail or via reference.
      type: object
      x-package: contact
      discriminator:
        propertyName: contactType
        mapping:
          contactPoint: '#/components/schemas/ContactPoint'
          contactByReference: '#/components/schemas/ContactByReference'
      properties:
        contactType:
          $ref: '#/components/schemas/ContactTypeEnum'
        contactNotDefined:
          type: boolean
          description: When true, there is currently no contact defined for the selected role and/or timeframe. Don't use the specialisations in this case.
        contactUnknown:
          type: boolean
          description: When true, the contact for the selected role and/or timeframe is unknown. Don't use the specialisations in this case.
        shareWithPublic:
          type: boolean
          description: When true, the details of this contact may be shared with the public. If false these contacts details are for internal purposes only.
        validityOfContact:
          $ref: '#/components/schemas/OverallPeriod'
      required:
        - contactType
    VersionedIdentity:
      title: VersionedIdentity
      description: Represents an object unique identifier associated with a version that can evolve over time.
      type: object
      x-package: common
      properties:
        id:
          type: string
          description: Unique identifier for the object.
          minLength: 1
          examples:
            - 98bccb9c-2ffe-4ca4-8e7f-eb1ae4439c29
        version:
          type: integer
          description: Positive integer representing the object version.
          minimum: 1
          examples:
            - 1
      required:
        - id
        - version
    LanguageCode:
      title: LanguageCode
      description: ISO 639-1:2002 language code.
      type: string
      x-package: common
      pattern: ^[a-z]{2}$
      examples:
        - en
    SpecificLanguageString:
      title: SpecificLanguageString
      description: Object containing a language code (using ISO 639-1:2002) and the translated string.
      type: object
      x-package: common
      properties:
        language:
          $ref: '#/components/schemas/LanguageCode'
        string:
          type: string
          description: Translated string
          examples:
            - This is a translated string
      required:
        - language
        - string
    MultilingualString:
      title: MultilingualString
      description: Array of SpecificLanguageString objects representing multi language text.
      type: array
      minItems: 1
      x-package: common
      items:
        $ref: '#/components/schemas/SpecificLanguageString'
    ContactPointTypeEnum:
      title: ContactPointTypeEnum
      description: |-
        Defines the supported lists of types of contact.
        * customerService : Contact details for parking customer support for a facility or specific entity
        * emergencyContact : Contact details for emergency assistance or support for a facility or specific entity specifically related to parking operations
        * enforcementSystemProvider : Contact details for the provider of the enforcement system
        * operator : Contact details for the parking operator for a facility or specific entity
        * owner : Contact details for the owner of a facility or specific entity.
        * propertyManager : Contact details for the property manager of a facility or related facility.
        * securityService : Contact details for security services for a facility or specific entity
        * serviceProvider : Contact details for a parking service provider (e.g. pay-by-mobile provider)
      type: string
      x-package: contact.enums
      enum:
        - customerService
        - emergencyContact
        - enforcementSystemProvider
        - operator
        - owner
        - propertyManager
        - securityService
        - serviceProvider
    CountryCode:
      title: CountryCode
      description: EN ISO 3166-1 two-character country code.
      type: string
      x-package: common
      pattern: ^[A-Z]{2}$
      examples:
        - GB
    AddressLineTypeEnum:
      title: AddressLineTypeEnum
      description: |-
        A table of types of address lines
         * apartment: Element indicating a discrete element of a building forming the address
         * building: Element identifying the number or name and type of the edifice or construction relevant for the address [derived from ISO19160-4]
         * districtTerritory: Element specifying the geographic or administrative area of the country for the address [Source: 19160-4]
         * floor: Element indicating the floor or level on which a delivery point is located in a multi-storey building [Source:ISO19160-4]
         * poBox: A postal delivery location identifier, not necessarily a physical location.
         * region: Element indicating the name of the area within or adjacent to the town in which delivery address is.
         * street: Element indicating road or street identifier or name 
         * town: Element indicating the name of the populated place in which a delivery point is located, or near to or via which the delivery point is accessed. [Source: ISO19160-4]
         * unit: An element representing a section of a building or organisation.Free-text description of the condition that leads to a surcharge being applied.
      type: string
      x-package: place.enums
      enum:
        - apartment
        - building
        - districtTerritory
        - floor
        - poBox
        - region
        - street
        - town
        - unit
    AddressLine:
      title: AddressLine
      description: A class defining information concerning one line of a postal address.
      type: object
      x-package: place.characteristics
      properties:
        order:
          type: integer
          minimum: 0
          description: The sequence order that the address line element should be displayed in
        text:
          $ref: '#/components/schemas/MultilingualString'
        type:
          $ref: '#/components/schemas/AddressLineTypeEnum'
      required:
        - order
        - text
        - type
    Address:
      title: Address
      description: A street oriented addressing structure supporting delivery
      type: object
      x-package: place.characteristics
      properties:
        countryCode:
          $ref: '#/components/schemas/CountryCode'
        city:
          $ref: '#/components/schemas/MultilingualString'
        postCode:
          type: string
          description: Postcode or postal code for the address.
        addressLines:
          type: array
          description: Address lines
          items:
            $ref: '#/components/schemas/AddressLine'
    Url:
      title: Url
      description: Represents a Url for an internet accessible resource.
      type: string
      x-package: common
      examples:
        - https://api.parking-data-standards.org
    ContactDetails:
      title: ContactDetails
      description: Details for some person, service or the parking site itself, especially address information.
      type: object
      x-package: contact
      properties:
        available24hours:
          type: boolean
          description: Specifies if the availability is 24 hours a day. If true available 24 hours. If omitted, this information is unknown or heterogeneous.
        contactDetailsFax:
          type: string
          description: Fax of the contact.
        contactDetailsLanguage:
          type: array
          description: Language(s) this contact is able to speak resp. understand.
          items:
            $ref: '#/components/schemas/LanguageCode'
        contactDetailsLogoUrl:
          $ref: '#/components/schemas/Url'
        contactDetailsMoreInfo:
          $ref: '#/components/schemas/MultilingualString'
        contactDetailsResponsibility:
          $ref: '#/components/schemas/MultilingualString'
        contactPersonFirstName:
          type: string
          description: First name of the contact person.
        contactPersonName:
          type: string
          description: Name of the contact person.
        contactPersonPosition:
          $ref: '#/components/schemas/MultilingualString'
        publishingAgreement:
          type: boolean
          description: Indication, whether the contact accepted publishing its contact information [TRUE] = accepted.
        urlLinkAddress:
          $ref: '#/components/schemas/Url'
    EmailTypeEnum:
      title: EmailTypeEnum
      description: |-
        Defines the supported lists of different email contact types
        * customerService: The email contact is for customer service.
        * general: The email contact is general in nature.
        * helpdesk: The email contact is a helpdesk.
        * individual: The email contact is for a specified individual.
      type: string
      x-package: contact.enums
      enum:
        - customerService
        - general
        - helpdesk
        - individual
    EMail:
      title: EMail
      description: Represents an eMail address.
      type: string
      x-package: common
      format: email
      examples:
        - john.doe@npp.com
    EMailCommonData:
      title: EMailCommonData
      description: Defines information concerning an email point of contact.
      type: object
      x-package: contact
      properties:
        primaryFlag:
          description: If true, this indicates that this is the primary point of contact
          type: boolean
        typeCode:
          description: The type of contact that can be reached with this email
          $ref: '#/components/schemas/EmailTypeEnum'
        emailAddress:
          description: The email address
          $ref: '#/components/schemas/EMail'
    TelephoneContact:
      title: TelephoneContact
      description: A class defining information relating to a specific telephone point of contact.
      type: object
      x-package: contact
      properties:
        areaCode:
          type: string
          description: The area code element of a telephone number.
        extensionNumbers:
          type: array
          description: Any extension number typically within a larger organisation's telephone exchange system.
          items:
            type: string
        ituCountryCode:
          type: string
          description: Country calling codes or country dial in codes are telephone dialing prefixes for the member countries or regions of the International Telecommunication Union (ITU). They are defined by the ITU-T in standards E.123 and E.164.
        localNumbers:
          type: array
          description: The local code element of a telephone number.
          items:
            type: string
    GeoJsonObject:
      title: GeoJsonObject
      description: |-
        GeoJSon object

        The coordinate reference system for all GeoJSON coordinates is a
        geographic coordinate reference system, using the World Geodetic System
        1984 (WGS 84) datum, with longitude and latitude units of decimal
        degrees.
        This is equivalent to the coordinate reference system identified by the
        Open Geospatial Consortium (OGC) URN
        An OPTIONAL third-position element SHALL be the height in meters above
        or below the WGS 84 reference ellipsoid.
        In the absence of elevation values, applications sensitive to height or
        depth SHOULD interpret positions as being at local ground or sea level.
      type: object
      properties:
        type:
          type: string
          enum:
            - Feature
            - FeatureCollection
            - Point
            - MultiPoint
            - LineString
            - MultiLineString
            - Polygon
            - MultiPolygon
            - GeometryCollection
        bbox:
          description: |-
            A GeoJSON object MAY have a member named "bbox" to include
            information on the coordinate range for its Geometries, Features, or
            FeatureCollections. The value of the bbox member MUST be an array of
            length 2*n where n is the number of dimensions represented in the
            contained geometries, with all axes of the most southwesterly point
            followed by all axes of the more northeasterly point. The axes order
            of a bbox follows the axes order of geometries.
          type: array
          items:
            type: number
        coordinates:
          type: array
          items:
            description: A position member (number) or a nested position array, by geometry type.
          description: RFC 7946 §3.1 coordinates of a geometry object — for a Point, [longitude, latitude] or [longitude, latitude, elevation] in WGS 84 decimal degrees. Undeclared in APDS 4.1 (APX erratum 011).
      required:
        - type
      discriminator:
        propertyName: type
    ContactPoint:
      title: ContactPoint
      description: Defines contact details for specified role. Organisation name attribute should not be used in combination with role parkingSiteAddress.
      type: object
      x-package: contact
      allOf:
        - $ref: '#/components/schemas/Contact'
        - $ref: '#/components/schemas/VersionedIdentity'
        - type: object
          properties:
            organisationName:
              $ref: '#/components/schemas/MultilingualString'
            type:
              $ref: '#/components/schemas/ContactPointTypeEnum'
            address:
              type: array
              description: Addresses.
              items:
                $ref: '#/components/schemas/Address'
            contactDetails:
              type: array
              description: Contact details.
              items:
                $ref: '#/components/schemas/ContactDetails'
            eMailCommonData:
              type: array
              description: Email common data.
              items:
                $ref: '#/components/schemas/EMailCommonData'
            telephoneContacts:
              type: array
              description: Telephone contact.
              items:
                $ref: '#/components/schemas/TelephoneContact'
            pointLocations:
              type: array
              description: Contact point location.
              items:
                $ref: '#/components/schemas/GeoJsonObject'
            extensions:
              description: The APDS extension container (Use Case Document §C.2.5; Part 4 §4.3). Undeclared on APDS 4.1 entities (APX erratum 010).
              $ref: '#/components/schemas/Extensions'
          required:
            - type
    VersionedReference:
      title: VersionedReference
      description: Represents a reference to an identifiable object where the combination of the identifier and version is unique. It is composed of an unique identifier, a version and potentially a string identifying the class of the referenced object.
      type: object
      x-package: common
      properties:
        id:
          type: string
          description: Unique identifier for the object.
          minLength: 1
          examples:
            - 98bccb9c-2ffe-4ca4-8e7f-eb1ae4439c29
        version:
          type: integer
          description: Positive integer representing the object version.
          minimum: 1
          examples:
            - 1
        className:
          type: string
          description: Class name of the referenced object.
          pattern: ^[A-Z]+[A-Za-z0-9]+
          examples:
            - UKNumberPlate
      required:
        - id
        - version
    ContactByReference:
      title: ContactByReference
      description: Contact information that is addressed via a reference.
      type: object
      x-package: contact
      allOf:
        - $ref: '#/components/schemas/Contact'
        - type: object
          properties:
            contactReference:
              $ref: '#/components/schemas/VersionedReference'
          required:
            - contactReference
    ContactTypeEnum:
      title: ContactTypeEnum
      description: |-
        Defined the type of contact object.
        * ContactPoint: Contact detailed information.
        * ContactByReference: Reference to an exiting contact.
      type: string
      x-package: contact.enums
      enum:
        - contactPoint
        - contactByReference
    DayEnum:
      title: DayEnum
      description: Defines permissible enumerations of identification of days within a week.
      type: string
      x-package: time.enums
      enum:
        - monday
        - tuesday
        - wednesday
        - thursday
        - friday
        - saturday
        - sunday
    MonthEnum:
      title: MonthEnum
      description: Defines permissible enumerations of identification of calendar months within a year.
      type: string
      x-package: time.enums
      enum:
        - january
        - february
        - march
        - april
        - may
        - june
        - july
        - august
        - september
        - october
        - november
        - december
    WeekOfMonthEnum:
      title: WeekOfMonthEnum
      description: |-
        Weeks of the month

        * `firstWeekOfMonth`: First week of the month
        * `secondWeekOfMonth`: Second week of the month
        * `thirdWeekOfMonth`: Third week of the month
        * `fourthWeekOfMonth`: Fourth week of the month
        * `fifthWeekOfMonth`: Fifth week of the month (at most only 3 days and non in February when not a leap year)
      type: string
      x-package: time.enums
      enum:
        - firstWeekOfMonth
        - secondWeekOfMonth
        - thirdWeekOfMonth
        - fourthWeekOfMonth
        - fifthWeekOfMonth
    DayWeekMonth:
      title: DayWeekMonth
      description: Specification of periods defined by the intersection of days, weeks and months.
      type: object
      x-package: time
      properties:
        applicableDay:
          type: array
          uniqueItems: true
          maxItems: 7
          description: Applicable day of the week (1 to 7). All days of the week is expressed by non-inclusion of this attribute.
          items:
            $ref: '#/components/schemas/DayEnum'
        applicableMonth:
          type: array
          description: Applicable month of the year (1 to 12). All months of the year is expressed by non-inclusion of this attribute.
          uniqueItems: true
          maxItems: 12
          items:
            $ref: '#/components/schemas/MonthEnum'
        applicableWeek:
          type: array
          description: Applicable week of the month (1 to 5). All weeks of the month is expressed by non-inclusion of this attribute.
          uniqueItems: true
          maxItems: 5
          items:
            $ref: '#/components/schemas/WeekOfMonthEnum'
    SpecialDay:
      title: SpecialDay
      description: Specification of a special type of day, possibly also a public holiday. Can be country or region specific.
      type: object
      x-package: time
      discriminator:
        propertyName: specialDayType
        mapping:
          dayBeforePublicHoliday: '#/components/schemas/OtherSpecialDay'
          dayFollowingPublicHoliday: '#/components/schemas/OtherSpecialDay'
          inLieuOfPublicHoliday: '#/components/schemas/OtherSpecialDay'
          longWeekendDay: '#/components/schemas/OtherSpecialDay'
          other: '#/components/schemas/OtherSpecialDay'
          publicEventDay: '#/components/schemas/OtherSpecialDay'
          publicHoliday: '#/components/schemas/PublicHoliday'
          schoolDay: '#/components/schemas/OtherSpecialDay'
          schoolHolidays: '#/components/schemas/OtherSpecialDay'
      properties:
        specialDayType:
          $ref: '#/components/schemas/SpecialDayTypeEnum'
        intersectWithApplicableDays:
          type: boolean
          description: Indicates if the period is the intersection of applicable days and this special day (TRUE) or if it is the union of applicable days and this special day.
      required:
        - specialDayType
        - intersectWithApplicableDays
    OtherSpecialDay:
      title: OtherSpecialDay
      description: Specification of a other type of special day.
      type: object
      x-package: time
      allOf:
        - $ref: '#/components/schemas/SpecialDay'
    PublicHoliday:
      title: PublicHoliday
      description: Specification of a specific public holiday in case `specialDayType` is set to `publicHoliday`.
      type: object
      x-package: time
      allOf:
        - $ref: '#/components/schemas/SpecialDay'
        - type: object
          properties:
            publicHolidayName:
              $ref: '#/components/schemas/MultilingualString'
          required:
            - publicHolidayName
    SpecialDayTypeEnum:
      title: SpecialDayTypeEnum
      description: |-
        Collection of special types of days
        * dayBeforePublicHoliday: The day preceding a public holiday
        * dayFollowingPublicHoliday: A day following a public holiday
        * inLieuOfPublicHoliday: A holiday in lieu of a public holiday that falls on a weekend
        * longWeekendDay: A day between a public holiday and the weekend
        * other: Some other special day
        * publicEventDay: A day of a public event. You may use the publicEvent attribute to specify the corresponding event
        * publicHoliday: Public holiday A public holiday in general. You may use the PublicHoliday class to refer on a specific public holiday
        * schoolDay: A school day
        * schoolHolidays: A day within the school holidays
      type: string
      x-package: time.enums
      enum:
        - dayBeforePublicHoliday
        - dayFollowingPublicHoliday
        - inLieuOfPublicHoliday
        - longWeekendDay
        - other
        - publicEventDay
        - publicHoliday
        - schoolDay
        - schoolHolidays
    Time:
      title: Time
      description: ISO-8601 format definition of a time - format HH:MM.
      type: string
      x-package: common
      pattern: ^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$
      examples:
        - '12:15'
    TimePeriodOfDay:
      title: TimePeriodOfDay
      description: Specification of a continuous period of time within the same day.
      type: object
      x-package: time
      properties:
        startTimeOfPeriod:
          description: Start of time period.
          $ref: '#/components/schemas/Time'
        endTimeOfPeriod:
          description: End time of period.
          $ref: '#/components/schemas/Time'
      required:
        - startTimeOfPeriod
        - endTimeOfPeriod
    Period:
      title: Period
      description: Defines a continuous time period or a set of discontinuous time periods defined by the intersection of a set of criteria all within an overall delimiting interval.
      type: object
      x-package: time
      properties:
        periodName:
          $ref: '#/components/schemas/MultilingualString'
        startOfPeriod:
          description: Start of the period.
          $ref: '#/components/schemas/DateTime'
        endOfPeriod:
          description: End of the period.
          $ref: '#/components/schemas/DateTime'
        recurringDayWeekMonthPeriod:
          type: array
          description: The list of days each month for the period. If empty, all year (7d/7).
          items:
            $ref: '#/components/schemas/DayWeekMonth'
        recurringSpecialDay:
          type: array
          description: The list of special days for the period.
          items:
            $ref: '#/components/schemas/SpecialDay'
        recurringTimePeriodOfDay:
          type: array
          description: The list of start and end time for each day. If empty, all day (24h/24).
          items:
            $ref: '#/components/schemas/TimePeriodOfDay'
    OverallPeriod:
      title: OverallPeriod
      description: A continuous or discontinuous period of validity defined by overall bounding start and end times and the possible intersection of valid periods (potentially recurring) with the complement of exception periods (also potentially recurring).
      type: object
      x-package: time
      properties:
        overallStartTime:
          description: Start of bounding period of validity defined by date and time.
          $ref: '#/components/schemas/DateTime'
        overallEndTime:
          description: End of bounding period of validity defined by date and time.
          $ref: '#/components/schemas/DateTime'
        validPeriods:
          type: array
          description: A single time period, a recurring time `Period` period or a set of different recurring time periods during which validity is true.
          items:
            $ref: '#/components/schemas/Period'
        exceptionPeriods:
          type: array
          description: A single time period, a recurring time Period period or a set of different recurring time periods during which validity is false.
          items:
            $ref: '#/components/schemas/Period'
      required:
        - overallStartTime
    ImageAlbum:
      title: ImageAlbum
      description: A class defining information relating to images for a parking facility.
      type: object
      x-package: contact
      properties:
        photo:
          $ref: '#/components/schemas/Url'
        caption:
          $ref: '#/components/schemas/MultilingualString'
        logoImage:
          type: array
          description: URL to location of logo(s) the parking operator wishes to associate with this parking facility (e.g. their logo, schemes [ParkMark])
          items:
            $ref: '#/components/schemas/Url'
    Marketing:
      title: Marketing
      description: Universal resource locator (URI) that points towards a web site carrying marketing material supplied.
      type: object
      x-package: contact
      properties:
        imageAlbums:
          type: array
          description: Image albums associated
          items:
            $ref: '#/components/schemas/ImageAlbum'
        webURLs:
          type: array
          items:
            $ref: '#/components/schemas/Url'
    OperatingRestrictionTypeEnum:
      title: OperatingRestrictionTypeEnum
      description: |-
        Defines operating restrictions to use the of a facility.
        * busOnly : Only buses are permitted.
        * busStop : This is a stopping place of bus pick-up or drop-off; not to be used for parking.
        * carpoolOnly : Only carpool vehicles are permitted.
        * commercialVehicleOnly : Only commercial vehicles are permitted.
        * disabledPersonPermitOnly : Only vehicles of registered disabled person permit holders permitted.
        * electricVehicleOnly : Only electric vehicles permitted.
        * freeParking : No fee for parking
        * governmentVehicleOnly : Only government vehicles permitted.
        * loadingZone : This is a loading zone; not to be used for parking.
        * loadingZoneCommercial : Only government vehicles permitted.
        * media : Only for use by the media
        * noParking : No parking permitted
        * noWaiting : No waiting or parking of vehicles is permitted
        * parkingTimeLimit : Time limited parking.
        * residentialPermitOnly : Only for use by residential permit holders only
        * snow : Snow clearing zone; no parking
        * streetCleaning : Street cleansing zone; no parking
        * taxiOnly : Only taxis are permitted.
        * valetOnly : Only valet service vehicles are permitted.
      type: string
      x-package: place.characteristics.enums
      enum:
        - busOnly
        - busStop
        - carpoolOnly
        - commercialVehicleOnly
        - disabledPersonPermitOnly
        - electricVehicleOnly
        - freeParking
        - governmentVehicleOnly
        - loadingZone
        - loadingZoneCommercial
        - media
        - noParking
        - noWaiting
        - parkingTimeLimit
        - residentialPermitOnly
        - snow
        - streetCleaning
        - taxiOnly
        - valetOnly
    OperatingRestrictions:
      title: OperatingRestrictions
      description: A class defining operating restrictions.
      type: object
      x-package: place.characteristics
      properties:
        operatingRestriction:
          $ref: '#/components/schemas/OperatingRestrictionTypeEnum'
        operatingRestrictionContext:
          $ref: '#/components/schemas/MultilingualString'
        times:
          $ref: '#/components/schemas/OverallPeriod'
      required:
        - operatingRestriction
    RGBColour:
      title: RGBColour
      description: A RGB colour described by values for red, green and blue (0..255) as well as an optional name.
      type: object
      x-package: common
      properties:
        colourName:
          $ref: '#/components/schemas/MultilingualString'
        rgbBlueValue:
          type: integer
          description: The blue value of the RGB colour (0..255).
          minimum: 0
          maximum: 255
        rgbGreenValue:
          type: integer
          description: The green value of the RGB colour (0..255).
          minimum: 0
          maximum: 255
        rgbRedValue:
          type: integer
          description: The red value of the RGB colour (0..255).
          minimum: 0
          maximum: 255
      required:
        - rgbBlueValue
        - rgbGreenValue
        - rgbRedValue
    AccessAndEgress:
      title: AccessAndEgress
      description: Time periods specified for access to or from a parking facility.
      type: object
      x-package: time
      discriminator:
        propertyName: accessAndEgressType
        mapping:
          accessAndEgressValidity: '#/components/schemas/AccessAndEgressValidity'
          accessAndEgressPeriods: '#/components/schemas/AccessAndEgressPeriods'
      properties:
        accessAndEgressType:
          $ref: '#/components/schemas/AccessAndEgressTypeEnum'
        exitPossibleAtAnyTime:
          type: boolean
          description: If true, specifies that the specified access is available for exit at all times.
        entranceOpenTimeArea:
          type: array
          description: Entrance open time area
          items:
            $ref: '#/components/schemas/EntranceOpenTime'
        exitOpenTimeArea:
          type: array
          description: Exit open time area
          items:
            $ref: '#/components/schemas/ExitOpenTime'
      required:
        - accessAndEgressType
    ValidityStatusEnum:
      title: ValidityStatusEnum
      description: |-
        Values of validity status that can be assigned to a described event, action or item.
        * active : The described event, action or item is currently active regardless of the definition of the validity time specification.
        * definedByValidityTimeSpec : The validity status of the described event, action or item is in accordance with the definition of the validity time specification.
        * planned : The described event, action or item is currently planned regardless of the definition of the validity time specification.
        * suspended : The described event, action or item is currently suspended, that is inactive, regardless of the definition of the validity time specification.
      type: string
      x-package: time.enums
      enum:
        - active
        - definedByValidityTimeSpec
        - planned
        - suspended
    Validity:
      title: Validity
      description: Specification of validity, either explicitly or by a validity time period specification which may be discontinuous.
      type: object
      x-package: time
      properties:
        validityStatus:
          $ref: '#/components/schemas/ValidityStatusEnum'
        validityTimeSpecification:
          $ref: '#/components/schemas/OverallPeriod'
      required:
        - validityTimeSpecification
    AccessAndEgressValidity:
      title: AccessAndEgressValidity
      description: Defines an AccessAndEgress variant with validity.
      type: object
      x-package: time
      allOf:
        - $ref: '#/components/schemas/AccessAndEgress'
        - type: object
          properties:
            validity:
              description: Specific validity information.
              $ref: '#/components/schemas/Validity'
    AccessAndEgressPeriods:
      title: AccessAndEgressPeriods
      description: Defines an AccessAndEgress variant with periods.
      type: object
      x-package: time
      allOf:
        - $ref: '#/components/schemas/AccessAndEgress'
        - type: object
          properties:
            periods:
              type: array
              minItems: 1
              description: list of periods
              items:
                $ref: '#/components/schemas/Period'
    AccessAndEgressTypeEnum:
      title: AccessAndEgressTypeEnum
      description: Defines the type of access and egress for places.
      type: string
      x-package: time.enums
      enum:
        - accessAndEgressValidity
        - accessAndEgressPeriods
    PeriodsOrValidity:
      title: PeriodsOrValidity
      description: Describes the mutually exclusive use of one Validity or one or more Periods.
      type: object
      x-package: time
      discriminator:
        propertyName: type
        mapping:
          validity: '#/components/schemas/ValidityAlias'
          periods: '#/components/schemas/PeriodsAlias'
      properties:
        type:
          $ref: '#/components/schemas/PeriodsOrValidityTypeEnum'
      required:
        - type
    ValidityAlias:
      title: ValidityAlias
      description: Represents a validity.
      type: object
      x-package: time
      allOf:
        - $ref: '#/components/schemas/PeriodsOrValidity'
        - type: object
          properties:
            validity:
              $ref: '#/components/schemas/Validity'
    PeriodsAlias:
      title: PeriodsAlias
      description: Represents an array of periods.
      type: object
      x-package: time
      allOf:
        - $ref: '#/components/schemas/PeriodsOrValidity'
        - type: object
          properties:
            periods:
              type: array
              minItems: 1
              items:
                $ref: '#/components/schemas/Period'
    PeriodsOrValidityTypeEnum:
      title: PeriodsOrValidityTypeEnum
      description: |-
        Collection of types for PeriodsOrValidity.
        * validity: using validity
        * periods: using periods
      type: string
      x-package: time.enums
      enum:
        - validity
        - periods
    EntranceOpenTime:
      title: EntranceOpenTime
      description: Specification of periods of times when parking entrance(s) are open for vehicle movements.
      type: object
      allOf:
        - $ref: '#/components/schemas/PeriodsOrValidity'
      x-package: time
    ExitOpenTime:
      title: ExitOpenTime
      description: Specification of periods of times when parking exit(s) are open for vehicle movements.
      type: object
      allOf:
        - $ref: '#/components/schemas/PeriodsOrValidity'
      x-package: time
    OperatingTime:
      title: OperatingTime
      description: Specification of periods or time when the parking operates, do not represents times of accessibility.
      type: object
      allOf:
        - $ref: '#/components/schemas/PeriodsOrValidity'
      x-package: time
    Times:
      title: Times
      description: |-
        Defines forms of time period for specific purposes. 
        There are four distinct time domain concepts: 
        * Hours of operation (times at which the facility may be used)
        * Access and egress (times it is possible to enter and leave the facility)
        * Entrance open time
        * Exit open time
      type: object
      x-package: time
      properties:
        available24hours:
          type: boolean
          description: If [TRUE], the identified parking hierarchy entities is available 24 hours per day.
        openAllYear:
          type: boolean
          description: If [TRUE], the identified parking hierarchy entities is available every day each year.
        openingTimesNotSpecified:
          type: boolean
          description: If [TRUE], the time periods are not specified.
        openingTimesUnknown:
          type: boolean
          description: If [TRUE], the time periods are not known.
        accessAndEgress:
          type: array
          items:
            $ref: '#/components/schemas/AccessAndEgress'
        operatingTime:
          $ref: '#/components/schemas/OperatingTime'
      required:
        - available24hours
        - openAllYear
        - openingTimesNotSpecified
        - openingTimesUnknown
    MeansOfPaymentEnum:
      title: MeansOfPaymentEnum
      description: |-
        Means of payment
        * cashBillsOnly : Cash payment using bills only.
        * cashCoinsAndBills : Cash payment using bills and/or coins only.
        * cashCoinsOnly : Cash payment with coins only.
        * mobileAccount : Payment method using an app or other functions typically via a smartphone, to a linked bank or card account.
        * paymentCreditCard : Payment by electronic payment credit card which is a small plastic card issued by a bank, building society, or  other financial institution (ISO/IEC 7813 and other related standards), allowing the holder to purchase goods or services on credit.
        * paymentDebitCard : Payment by electronic payment debit card which is a small plastic card (ISO/IEC 7813 and other related standards), allowing the holder to transfer money electronically from their bank account when making a purchase.
        * paymentValueCard : Payment by electronic payment debit card which is a small plastic card (ISO/IEC 7813 and other related standards)  with a monetary value stored on the card itself, not that may not be linked to an external account maintained by a financial institution.
        * prepay : Advanced payment for parking right.
        * tollTag : Toll tag (RFID) or similar, with associated account.
        * unknown : Unknown.
      type: string
      x-package: rate.payment.enums
      enum:
        - cashBillsOnly
        - cashCoinsAndBills
        - cashCoinsOnly
        - mobileAccount
        - paymentCreditCard
        - paymentDebitCard
        - paymentValueCard
        - prepay
        - tollTag
        - unknown
    PaymentTimingEnum:
      title: PaymentTimingEnum
      description: |-
        Details of when payment is required.
        * other : Other.
        * payAfterExit : Payment on account
        * payAndExit : Pay directly at the exit with a payment card or other means of payment (usually, this payment card must have been used when entering as well).
        * payOnEntry : Pay at start of the parking session (e.g. for pay and display)
        * payPriorToExit : Pay at machine on foot prior to returning to vehicle and use payment ticket to exit.
        * prepay : Pay before entry
      type: string
      x-package: rate.payment.enums
      enum:
        - other
        - payAfterExit
        - payAndExit
        - payOnEntry
        - payPriorToExit
        - prepay
    Reference:
      title: Reference
      description: Represents a reference to an identifiable object where the identifier is unique. It is composed of an unique identifier and a string identifying the class of the referenced object. If multiple versions exists for the object, the latest version is considered.
      type: object
      x-package: common
      minProperties: 1
      maxProperties: 1
      properties:
        id:
          type: string
          description: The unique identifier within the given class.
          examples:
            - 98bccb9c-2ffe-4ca4-8e7f-eb1ae4439c29
        className:
          type: string
          description: The class name of the referenced object in PascalCase.
          minLength: 1
          examples:
            - UKNumberPlate
      required:
        - id
        - className
    ReferencedCodeListEntry:
      title: ReferencedCodeListEntry
      description: Provides a structure to support reference to an entry in a previously defined user-defined code list.
      type: object
      x-package: common
      properties:
        codeListEntryId:
          $ref: '#/components/schemas/Reference'
        codeListId:
          $ref: '#/components/schemas/VersionedReference'
        entryDefinedValue:
          type: string
          description: Free-text defined text (name) for the code list entry being referenced.
      required:
        - entryDefinedValue
    BrandsAcceptedCodeList:
      title: BrandsAcceptedCodeList
      description: Use this class to describe details of the brands that are accepted.
      type: object
      x-package: rate.payment
      properties:
        brandsAcceptedList:
          $ref: '#/components/schemas/ReferencedCodeListEntry'
      required:
        - brandsAcceptedList
    BrandsAcceptedText:
      title: BrandsAcceptedText
      description: Use this class to describe details of the brands that are accepted.
      type: object
      x-package: rate.payment
      properties:
        brandsAccepted:
          $ref: '#/components/schemas/MultilingualString'
    PaymentMethod:
      title: PaymentMethod
      description: Provides information on the means of payment available
      type: object
      x-package: rate.payment
      properties:
        paymentMeans:
          type: array
          description: The means of payment available
          items:
            $ref: '#/components/schemas/MeansOfPaymentEnum'
        paymentMode:
          type: array
          description: Defines the timing of the parking or other mobility related payment
          items:
            $ref: '#/components/schemas/PaymentTimingEnum'
        brandsAcceptedCodeList:
          type: array
          description: List of accepted brands for payment cards (by code)
          items:
            $ref: '#/components/schemas/BrandsAcceptedCodeList'
        brandsAcceptedText:
          type: array
          description: List of accepted brands for payment cards (by name)
          items:
            $ref: '#/components/schemas/BrandsAcceptedText'
    SafetyStandardClassification:
      title: SafetyStandardClassification
      description: Use this class to classification type/level for security schemes for a place
      type: object
      x-package: place.characteristics
      properties:
        securityFeature:
          $ref: '#/components/schemas/ReferencedCodeListEntry'
        securityLevel:
          $ref: '#/components/schemas/ReferencedCodeListEntry'
    PlaceInformation:
      title: PlaceInformation
      description: Defines information concerning multiple features relating to parking hierarchy elements.
      type: object
      x-package: place.characteristics
      properties:
        characteristics:
          $ref: '#/components/schemas/PlaceCharacteristics'
        contacts:
          type: array
          description: Contact info for hierarchy element.
          items:
            $ref: '#/components/schemas/Contact'
        marketing:
          $ref: '#/components/schemas/Marketing'
        operatingRestrictions:
          type: array
          description: Operating restrictions for hierarchy element.
          items:
            $ref: '#/components/schemas/OperatingRestrictions'
        rgbColours:
          type: array
          description: Colours associated with hierarchy element.
          items:
            $ref: '#/components/schemas/RGBColour'
        times:
          $ref: '#/components/schemas/Times'
        paymentMethods:
          type: array
          description: Accepted payment methods at hierarchy element.
          items:
            $ref: '#/components/schemas/PaymentMethod'
        safetyStandardClassifications:
          type: array
          description: Safety standard classifications.
          items:
            $ref: '#/components/schemas/SafetyStandardClassification'
    Place:
      title: Place
      description: A place or location used for parking, loading, unloading, standing, or some other mobility or transport related activity. Place typically identifies a parking structure, surface lot or on street parking zone
      type: object
      x-package: place
      allOf:
        - $ref: '#/components/schemas/HierarchyElement'
        - $ref: '#/components/schemas/PlaceInformation'
        - type: object
          properties:
            timeZone:
              type: string
              description: IANA time-zone (see https://www.iana.org/time-zones)
            placeStreetAddress:
              $ref: '#/components/schemas/Address'
            placeBoundedZone:
              type: array
              description: Place bounded zone
              items:
                $ref: '#/components/schemas/GeoJsonObject'
            indicativePointLocation:
              type: array
              description: Indicative place point location
              items:
                $ref: '#/components/schemas/GeoJsonObject'
          required:
            - timeZone
    ParkingSpaceOccupancyDetectionEnum:
      title: ParkingSpaceOccupancyDetectionEnum
      description: |-
        A list of supported methods for detection of occupancy by a vehicle in a parking space.
        * anpr : Automated License Plate Recognition information is tracked for inbound and outbound traffic. The difference between in and out counts enables an occupancy count.
        * imageAnalytics : Image analytics are used to evaluate a picture with known parking space geography and computer vision is used to determine occupancy at a point in time.
        * spaceSensor : A sensor in each space detects the presence of a vehicle.
        * userDeclaration : User self-declared, where the user enters a space identifier and/or vehicle registration number, typically at the start of a parking session.
        * videoAnalytics : Video analytics are used to evaluate a video stream to identify objects (vehicles) and direction of travel. The difference between the inbound objects and outbound objects determines occupancy.
        * videoSpace : Video analytics or ANPR technologies are used to evaluate a video stream with known space geometry to identify objects (vehicles or license plates) occupying specific spaces.
        * visual : Operator/owner makes periodic visual counts of the facility.
      type: string
      x-package: place.occupancy.enums
      enum:
        - anpr
        - imageAnalytics
        - spaceSensor
        - userDeclaration
        - videoAnalytics
        - videoSpace
        - visual
    UnitOfMeasureDistanceEnum:
      title: UnitOfMeasureDistanceEnum
      description: |-
        Unit used for length/distance elements.
        * foot: Imperial foot = 12 inches
        * metres: SI - metre
      type: string
      x-package: place.enums
      enum:
        - foot
        - metres
    LinearDimension:
      title: LinearDimension
      description: A class defining information concerning a linear measure (distance) with unit.
      type: object
      x-package: place.characteristics
      properties:
        measure:
          type: number
          format: float
          description: Quantity in the defined unit of measure.
        unitOfMeasure:
          $ref: '#/components/schemas/UnitOfMeasureDistanceEnum'
      required:
        - measure
        - unitOfMeasure
    UnitOfMeasureAreaEnum:
      title: UnitOfMeasureAreaEnum
      description: |-
        Unit used for area/surface elements.
        * squareFeet: Unit of Square feet.
        * squareMetres: Unit of Metres Square.
        * squareYards: Unit of Square yards.
      type: string
      x-package: place.enums
      enum:
        - squareFeet
        - squareMetres
        - squareYards
    AreaDimension:
      title: AreaDimension
      type: object
      description: A class defining information concerning an area measurement with unit.
      x-package: place.characteristics
      properties:
        measure:
          type: number
          format: float
          description: Quantity in the defined unit of measure.
        unitOfMeasure:
          $ref: '#/components/schemas/UnitOfMeasureAreaEnum'
      required:
        - measure
        - unitOfMeasure
    UnitOfMeasureWeightEnum:
      title: UnitOfMeasureWeightEnum
      description: |-
        Unit used for weight elements.
        * poundsWeight: 1 lb
        * tonnesMetric: 1000 kilogrammes
      type: string
      x-package: place.enums
      enum:
        - poundsWeight
        - tonnesMetric
    WeightDimension:
      title: WeightDimension
      description: A class defining information concerning a weight quantity with unit.
      type: object
      x-package: place.characteristics
      properties:
        measure:
          type: number
          description: Quantity in the defined unit of measure.
          format: float
        unitOfMeasure:
          $ref: '#/components/schemas/UnitOfMeasureWeightEnum'
      required:
        - measure
        - unitOfMeasure
    SpaceDimension:
      title: SpaceDimension
      description: |-
        A component that provides dimension information. 
        The product of width and height must not be necessarily be the square footage (e.g. in multi-storey buildings or when some zones are not part of the square footage).
      type: object
      x-package: place.characteristics
      properties:
        dimensionHeight:
          $ref: '#/components/schemas/LinearDimension'
        dimensionLength:
          $ref: '#/components/schemas/LinearDimension'
        dimensionWidth:
          $ref: '#/components/schemas/LinearDimension'
        dimensionUsableArea:
          $ref: '#/components/schemas/AreaDimension'
        weightLimit:
          $ref: '#/components/schemas/WeightDimension'
    MaximumDimensions:
      title: MaximumDimensions
      description: A class defining information relating to the maximum physical dimensions for the defined purpose
      type: object
      x-package: place.characteristics
      properties:
        maximumHeight:
          $ref: '#/components/schemas/LinearDimension'
        maximumLength:
          $ref: '#/components/schemas/LinearDimension'
        maximumWidth:
          $ref: '#/components/schemas/LinearDimension'
    Space:
      title: Space
      description: A single space for parking, usually designed for one vehicle, which may, but not necessarily, be denoted by painted or other road surface marker.
      type: object
      x-package: place
      allOf:
        - $ref: '#/components/schemas/HierarchyElement'
        - type: object
          properties:
            spaceId:
              $ref: '#/components/schemas/Reference'
            detection:
              $ref: '#/components/schemas/ParkingSpaceOccupancyDetectionEnum'
            indicativePointLocation:
              $ref: '#/components/schemas/GeoJsonObject'
            spaceBoundedZone:
              $ref: '#/components/schemas/GeoJsonObject'
            spaceDimension:
              $ref: '#/components/schemas/SpaceDimension'
            spaceMaximumDims:
              $ref: '#/components/schemas/MaximumDimensions'
            operatingRestrictions:
              type: array
              description: Operating restrictions for space
              items:
                $ref: '#/components/schemas/OperatingRestrictions'
          required:
            - spaceId
    HierarchyElementRecord:
      title: HierarchyElementRecord
      description: A collection of information concerning the creation of a hierarchy element
      type: object
      x-package: place
      properties:
        creationTime:
          description: Date/time that this version of the place facility record was created.
          $ref: '#/components/schemas/DateTime'
        creator:
          $ref: '#/components/schemas/VersionedReference'
        creatorEmail:
          $ref: '#/components/schemas/EMail'
      required:
        - creationTime
    Duration:
      title: Duration
      description: ISO8601 format definition of an interval of time in format [PnnYnnMnnDTnnHnnMnnS].
      type: string
      x-package: common
      pattern: ^P(?!$)(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+S)?)?$
      examples:
        - P1Y2M3DT4H5M6S
    CalculationTypeEnum:
      title: CalculationTypeEnum
      description: |-
        A list of the supported calculation types for demand.
        * counted : Physical determination if a space is occupied
        * derived : Space occupancy is estimated by using related data such as active payments or sold permits.
        * expected : Future prediction of occupancy levels.
        * verified : Defines an occupancy report that is considered a verified report.
      type: string
      x-package: place.occupancy.enums
      enum:
        - counted
        - derived
        - expected
        - verified
    DemandType:
      title: DemandType
      description: This table is dedicated to reporting on actual occupancy in an area.
      type: object
      x-package: place.occupancy
      properties:
        count:
          type: integer
          description: Number of occupied spaces.
          minimum: 0
        occupancyCalculation:
          $ref: '#/components/schemas/CalculationTypeEnum'
        percentage:
          type: number
          description: Percent of spaces occupied.
          format: float
          minimum: 0
          maximum: 100
        recordDateTime:
          description: When data in the record was compiled.
          $ref: '#/components/schemas/DateTime'
      required:
        - recordDateTime
    OccupancyLevel:
      title: OccupancyLevel
      description: Defines an occupancy level as specified by the data supplier.
      type: object
      x-package: place.occupancy
      properties:
        occupancyIndicator:
          $ref: '#/components/schemas/ReferencedCodeListEntry'
      required:
        - occupancyIndicator
    DemandSpaceType:
      title: DemandSpaceType
      description: Identifies when a space was occupied and for how long.
      type: object
      x-package: place.occupancy
      properties:
        detectionUpdateTime:
          description: Time of update, from detector.
          $ref: '#/components/schemas/DateTime'
        occupancyEstimatedStartTime:
          description: The estimated time a space is expected to be occupied.
          $ref: '#/components/schemas/DateTime'
        occupancyEstimatedEndTime:
          description: The estimated time a space is expected to be vacated.
          $ref: '#/components/schemas/DateTime'
        occupancyStartTime:
          description: The actual time space is occupied.
          $ref: '#/components/schemas/DateTime'
        occupancyEndTime:
          description: The actual time space is vacated.
          $ref: '#/components/schemas/DateTime'
        spaceId:
          $ref: '#/components/schemas/Reference'
        occupancyLevel:
          $ref: '#/components/schemas/OccupancyLevel'
      required:
        - detectionUpdateTime
    DemandTable:
      title: DemandTable
      description: Defines the parameters of reporting actual usage of parking in a Hierarchy Element
      type: object
      x-package: place.occupancy
      properties:
        frequency:
          $ref: '#/components/schemas/Duration'
        timestamp:
          description: Timestamp when the demand table data was compiled.
          $ref: '#/components/schemas/DateTime'
        demandType:
          type: array
          description: Occupancy for area
          items:
            $ref: '#/components/schemas/DemandType'
        demandSpaceType:
          type: array
          description: Occupancy for single spaces
          items:
            $ref: '#/components/schemas/DemandSpaceType'
    SupplyViewTypeEnum:
      title: SupplyViewTypeEnum
      description: |-
        Define if space quantity is demarcated or estimated.
        * spaceView : Each space is physically marked and identifiable.
        * vehicleView :  The vehicle capacity in an area is estimated based on calculating a capacity (i.e. curb length divided by a length of vehicle). The
        distributing party decides on the appropriate length of vehicle to use.
      type: string
      x-package: place.occupancy.enums
      enum:
        - spaceView
        - vehicleView
    Supply:
      title: Supply
      description: |-
        A class defining concepts relating the parameters of the supply of parking. 
        This is the total number of spaces usable for parking or other mobility operations. 
        It can be defined as demarcated spaces or non-demarcated.
      type: object
      x-package: place.occupancy
      properties:
        supplyViewType:
          $ref: '#/components/schemas/SupplyViewTypeEnum'
        supplyQuantity:
          type: integer
          description: Indicates the numeric value of available parking or other space uses.
        supplyValidityStart:
          description: Valid start date/time for the supply
          $ref: '#/components/schemas/DateTime'
        supplyValidityEnd:
          description: Valid end date/time for the supply
          $ref: '#/components/schemas/DateTime'
      required:
        - supplyQuantity
        - supplyViewType
    HierarchyElementReference:
      title: HierarchyElementReference
      description: A class providing a unique reference identifier for a discrete part of the parking place hierarchy. This can indicate a campus, parking place, hierarchy element, identifiable area or space.
      type: object
      x-package: place
      properties:
        elementId:
          $ref: '#/components/schemas/VersionedReference'
        demandTable:
          type: array
          items:
            $ref: '#/components/schemas/DemandTable'
        supply:
          type: array
          items:
            $ref: '#/components/schemas/Supply'
      required:
        - elementId
    ResponsibilityRoleAssignment:
      title: ResponsibilityRoleAssignment
      description: describes roles and responsibilites for a particular location (e.g. operator)
      type: object
      x-package: contact
      properties:
        type:
          description: the type of contact/organisation (e.g. operator)
          $ref: '#/components/schemas/ContactPointTypeEnum'
        contactPoints:
          description: list with contact details
          type: array
          items:
            $ref: '#/components/schemas/ContactPoint'
    HierarchyElementList:
      title: HierarchyElementList
      description: Paginated list of HierarchyElements
      type: object
      x-package: place
      allOf:
        - $ref: '#/components/schemas/PaginatedList'
        - type: object
          properties:
            data:
              type: array
              description: List of HierarchyElements
              items:
                $ref: '#/components/schemas/HierarchyElement'
    ResponseStatusEnum:
      title: ResponseStatusEnum
      description: |-
        Type of status for a Response.
        * ok : OK
        * error : An error occurred
      type: string
      x-package: api.enums
      enum:
        - ok
        - error
    ResponseStatus:
      title: ResponseStatus
      description: Codifies responses following some creation, update or delete operation.
      type: object
      x-package: api
      properties:
        status:
          description: The status code of the response.
          $ref: '#/components/schemas/ResponseStatusEnum'
        code:
          type: integer
          description: Same numbering and semantics as HTTP status codes.
        message:
          type: string
          description: Descriptive message for error statuses.
        ids:
          description: list of conflicting/missing ids (if applicable)
          type: array
          items:
            type: string
      required:
        - status
    ObservationTypeEnum:
      type: string
      title: ObservationTypeEnum
      description: |-
        A list of the supported observation types.

        * `anpr`: Automatic vehicle license plate recognition
        * `chalk`: Chalk-mark observation or similar
        * `rfTransponder`: Rf transponder radio frequency transponder device, for toll tag or similar radio based devices
        * `scanner`: Handheld or fixed scanning device (optical)
        * `visual`: Visual (human) observation
      enum:
        - anpr
        - chalk
        - rfTransponder
        - scanner
        - visual
      x-tags:
        - enumeration
    CredentialTypeEnum:
      title: CredentialTypeEnum
      description: |-
        * barcode : barcode or QR digital print pattern, held on any physical media.
        * bluetooth : specific bluetooth or BLE identification chip used to associate a BLE receiver to a specific user.  Used for both one time and permit uses.
        * eticket : digital equivalent of a paper ticket, often presentable via smartphone or similar device for control.
        * hangtag : visible, often removable, credential indicator, with visible markings
        * licensePlate : fixed plate, in a defined format, used to identify a specific vehicle- Normally a permanent fixture.
        * permit : issued credential, often in the form of an adhesive label, often placed on the windscreen, credential indicator, with visible markings
        * qrCode : quick Reference (QR) code
        * rfid : specific RF identification associated to an RFID-related account.  Used for permit uses.
        * ticket : typically issued paper with printed details, often with magnetic strips; typically single use disposable.
        * electronicID : an identifier transmitted by electronic means
        * ticketcoupon : a visible printed or written paper-based ticket or coupon carrying an identifiable credential.
        * vehicleplate : a fixed identifier (registration plate) visible and fixed to a vehicle.
      type: string
      x-package: right_specification.enums
      enum:
        - barcode
        - bluetooth
        - eticket
        - hangtag
        - licensePlate
        - permit
        - qrCode
        - rfid
        - ticket
        - electronicID
        - ticketcoupon
        - vehicleplate
    Location:
      title: Location
      type: object
      description: Positional information relating to an observation for both the observation target ('observed') and the source ('observer').
      properties:
        observedLocation:
          $ref: '#/components/schemas/GeoJsonObject'
        observedLocationTextual:
          $ref: '#/components/schemas/MultilingualString'
        observerLocation:
          $ref: '#/components/schemas/GeoJsonObject'
      required:
        - observerLocation
      x-tags:
        - observation
    ImageTypeEnum:
      title: ImageTypeEnum
      description: the nature of the captured image
      type: string
      enum:
        - overview
        - plate
      x-tags:
        - enumeration
    Image:
      title: Image
      description: Class containing information relating to still or moving image observation evidence or a reference (link) to such observation evidence.
      properties:
        id:
          type: string
          description: Reference identifier to a specific image.
        image:
          type: string
          description: Base64 File or binary object containing a still or moving image.
        imageLink:
          $ref: '#/components/schemas/Url'
        imageType:
          $ref: '#/components/schemas/ImageTypeEnum'
        cameraID:
          type: string
          description: identification code for the camera device
        cameraDistance:
          type: number
          format: float
          description: recorded distance in metres between the camera and observation
      required:
        - id
      x-tags:
        - observation
    VehicleAncillaryIdentification:
      title: VehicleAncillaryIdentification
      description: Information relating to a specific vehicle.
      type: object
      x-package: common
      properties:
        country:
          $ref: '#/components/schemas/CountryCode'
        color:
          type: string
          description: The predominant colour of the vehicle.
        description:
          type: string
          description: Free-text description of other distinguishing features of the vehicle.
        make:
          type: string
          description: The branded manufacturer's name for the vehicle (e.g. Ford, Audi, BMW, Mazda).
        model:
          type: string
          description: The model name for the vehicle type (e.g. Ford Mondeo, Citroen C-Zero).
        stateProvince:
          type: string
          description: State, province or other administrative subdivision where a nation state permits registration of vehicles on a lower administrative level basis.
      required:
        - country
    Confidence:
      title: Confidence
      description: overall confidence of the observation measurement
      type: object
      properties:
        overallConfidence:
          description: overall confidence of the observation measurement - can be vendor-specific but rescaled to a value between 0 and 1, with 1 being greatest confidence
          type: number
          format: float
          minimum: 0
          maximum: 1
    CharacterConfidence:
      title: CharacterConfidence
      description: confidence of observation measurement
      type: object
      properties:
        confidence:
          description: confidence of the observation measurement for a specific indexed character - can be vendor-specific but rescaled to a value between 0 and 1, with 1 being greatest confidence
          type: number
          format: float
          minimum: 0
          maximum: 1
        index:
          description: index reference to a specific character within an observed sequence
          type: integer
          minimum: 0
      required:
        - confidence
        - index
    ObservationElement:
      title: ObservationElement
      allOf:
        - $ref: '#/components/schemas/VersionedIdentity'
        - type: object
          properties:
            method:
              $ref: '#/components/schemas/ObservationTypeEnum'
            observer:
              type: string
              description: The individual person making the observation recorded in this observation element.
            type:
              $ref: '#/components/schemas/CredentialTypeEnum'
            observedCredentialId:
              type: string
              description: Specific identifier to the referenced observed credential.
            observationStartTime:
              type: string
              format: date-time
              description: The initial date and time of the observation.
            observationEndTime:
              type: string
              format: date-time
              description: The ending date and time of the observation, when it was continous since `observationStartTime`.
            description:
              $ref: '#/components/schemas/MultilingualString'
            creationDateTime:
              type: string
              format: date-time
              description: The date and time stamp for the creation of the observation element.
            location:
              $ref: '#/components/schemas/Location'
            images:
              type: array
              description: still or moving images observation evidence or a reference to such observation evidence
              items:
                $ref: '#/components/schemas/Image'
            elementIds:
              $ref: '#/components/schemas/VersionedReference'
            vehicleAncillaryIdentification:
              $ref: '#/components/schemas/VehicleAncillaryIdentification'
            observerOrganisation:
              $ref: '#/components/schemas/VersionedReference'
            confidence:
              $ref: '#/components/schemas/Confidence'
            characterConfidence:
              $ref: '#/components/schemas/CharacterConfidence'
            extensions:
              description: The APDS extension container (Use Case Document §C.2.5; Part 4 §4.3). Undeclared on APDS 4.1 entities (APX erratum 010).
              $ref: '#/components/schemas/Extensions'
          required:
            - method
            - observationStartTime
            - creationDateTime
            - location
            - observerOrganisation
      description: A specific collection of observation details intended to be used for one specific observation instance.
      x-tags:
        - observation
    ObservationDataType:
      title: ObservationDataType
      description: used as discriminator between a single observation element and an observation set
      type: string
      enum:
        - ObservationElement
        - ObservationSet
    ObservationSet:
      title: ObservationSet
      description: Details of the collection of a set of related recorded observations.
      allOf:
        - $ref: '#/components/schemas/VersionedIdentity'
        - type: object
          properties:
            creationDateTime:
              type: string
              description: |-
                The date and time of the creation of the
                observation set.
              format: date-time
            creator:
              $ref: '#/components/schemas/VersionedReference'
            observationElements:
              type: array
              description: Individual observations in the set
              items:
                $ref: '#/components/schemas/ObservationElement'
            extensions:
              description: The APDS extension container (Use Case Document §C.2.5; Part 4 §4.3). Undeclared on APDS 4.1 entities (APX erratum 010).
              $ref: '#/components/schemas/Extensions'
          required:
            - creationDateTime
            - creator
      x-tags:
        - observation
    RightPoolRelativeValidity:
      title: RightPoolRelativeValidity
      type: object
      x-package: right_specification
      description: A specific calendar can be defined to represent the number of AssignedRights available for distribution in a specific recurring time period via RelativeValidity.
      properties:
        period:
          $ref: '#/components/schemas/Period'
    RightPool:
      title: RightPool
      type: object
      x-package: right_specification
      allOf:
        - $ref: '#/components/schemas/VersionedIdentity'
        - type: object
          properties:
            assignedRightsIssuer:
              readOnly: true
              $ref: '#/components/schemas/VersionedReference'
            distributedAssignedRights:
              type: integer
              description: Defines the number of AssignedRights that have been issued by the issuer.
            availableAssignedRights:
              type: integer
              description: Defines the number of AssignedRights that have been issued by the issuer that are still available to be assigned.
            qtyRelation:
              type: integer
              description: Defines the number of actions or parking included in a RightSpecification.
            relativeValidity:
              $ref: '#/components/schemas/RightPoolRelativeValidity'
            validity:
              $ref: '#/components/schemas/Validity'
          required:
            - assignedRightsIssuer
            - availableAssignedRights
            - distributedAssignedRights
    FuelTypeEnum:
      title: FuelTypeEnum
      description: |-
        Type of fuel used by a vehicle : 
        * all : All sort of fuel is accepted
        * battery : Battery
        * biodiesel : Biodiesel
        * diesel : Fuel used for compression - ignition (CI) engines
        * dieselBatteryHybrid : Diesel and battery hybrid
        * ethanol : Ethanol\n* hydrogen: Hydrogen
        * liquidGas : Liquid gas of any type including LPG
        * lpg : Liquid petroleum gas\n* methane: Methane gas
        * other : Other
        * petrol: Fuel used for positive-ignition (PI) engines
        * petrol95Octane : Petrol with 95 octane\n* petrol98Octane: Petrol with 98 octane
        * petrolBatteryHybrid : Petrol and battery hybrid
        * petrolLeaded : Leaded petrol
        * petrolUnleaded : Unleaded petrol
        * unknown : The sort of fuel is not known"
      type: string
      x-package: rate.eligibility.enums
      enum:
        - all
        - battery
        - biodiesel
        - diesel
        - dieselBatteryHybrid
        - ethanol
        - hydrogen
        - liquidGas
        - lpg
        - methane
        - other
        - petrol
        - petrol95Octane
        - petrol98Octane
        - petrolBatteryHybrid
        - petrolLeaded
        - petrolUnleaded
        - unknown
    LowEmissionLevelEnum:
      title: LowEmissionLevelEnum
      description: |-
        The emission level of a vehicle
        * freeOfEmission : Only vehicles that do not produce emissions (e.g. electric driven). Hybrid driven cars are allowed, when they switch to emission free mode within the considered situation
        * lowLevelEmission : Vehicles with low level emission
      type: string
      x-package: rate.eligibility.enums
      enum:
        - freeOfEmission
        - lowLevelEmission
    ValueRangeClassEnum:
      title: ValueRangeClassEnum
      description: class of value range specification
      x-package: rate.eligibility.enums
      type: string
      enum:
        - batteryCapacity
        - engineCapacityPetrol
        - emissionStandard
        - engineCapacityDiesel
        - manufactureDate
        - emissionValue
    UnitOfMeasureEnum:
      title: UnitOfMeasureEnum
      description: emission-related units of measure
      x-package: rate.eligibility.enums
      type: string
      enum:
        - cubicCentimetres
        - cubicInches
        - year
        - gkm
        - gpm
        - kWh
        - eurolevel
    ComparisonOperatorEnum:
      title: ComparisonOperatorEnum
      description: |-
        Logical comparison operations
        * equalTo : Logical comparison operator of "equal to".
        * greaterThan : Logical comparison operator of "greater than".
        * greaterThanOrEqualTo : Logical comparison operator of "greater than or equal to".
        * lessThan : Logical comparison operator of "less than".
        * lessThanOrEqualTo : Logical comparison operator of "less than or equal to".
      type: string
      x-package: common.enums
      enum:
        - equalTo
        - greaterThan
        - greaterThanOrEqualTo
        - lessThan
        - lessThanOrEqualTo
    ValueRangeBoundary:
      title: ValueRangeBoundary
      description: boundary within a value range
      x-package: common
      type: object
      properties:
        value:
          type: number
        comparisonOperator:
          $ref: '#/components/schemas/ComparisonOperatorEnum'
    ValueRange:
      title: ValueRange
      description: value range for emission criteria
      x-package: common
      type: object
      properties:
        class:
          $ref: '#/components/schemas/ValueRangeClassEnum'
        unit:
          $ref: '#/components/schemas/UnitOfMeasureEnum'
        boundaries:
          type: array
          items:
            $ref: '#/components/schemas/ValueRangeBoundary'
          minItems: 1
          maxItems: 2
    Emissions:
      title: Emissions
      description: Emission characteristics of vehicles.
      type: object
      x-package: rate.eligibility
      properties:
        emissionClassification:
          $ref: '#/components/schemas/ReferencedCodeListEntry'
        emissionClassificationOther:
          type: array
          description: Some other (probably locally defined) value(s) for emission classification.
          items:
            type: string
        emissionLevel:
          $ref: '#/components/schemas/LowEmissionLevelEnum'
        vehicleCharacteristics:
          description: emission characteristics of vehicle
          type: array
          items:
            $ref: '#/components/schemas/ValueRange'
          examples:
            - class: manufactureDate
              unit: year
              boundaries:
                - value: 2000
                  comparisonOperator: lessThanOrEqualTo
    WeightTypeEnum:
      title: WeightTypeEnum
      description: |-
        Type of weight - describing the meaning of a vehicle weight value
        * actual : The weight is the actual weight of a specific vehicle
        * maximumPermitted : The weight is the maximum permitted weight for a vehicle
      type: string
      x-package: rate.eligibility.enums
      enum:
        - actual
        - maximumPermitted
    GrossWeightCharacteristic:
      title: GrossWeightCharacteristic
      description: Gross weight characteristic of a vehicle.
      type: object
      x-package: rate.eligibility
      properties:
        comparisonOperator:
          $ref: '#/components/schemas/ComparisonOperatorEnum'
        grossVehicleWeight:
          type: number
          description: The gross weight of the vehicle and its load, including any trailers (in Tonnes).
          format: float
          exclusiveMinimum: 0
        typeOfWeight:
          $ref: '#/components/schemas/WeightTypeEnum'
      required:
        - comparisonOperator
        - grossVehicleWeight
        - typeOfWeight
    HeightCharacteristic:
      title: HeightCharacteristic
      description: Height characteristic of a vehicle.
      type: object
      x-package: rate.eligibility
      properties:
        comparisonOperator:
          $ref: '#/components/schemas/ComparisonOperatorEnum'
        vehicleHeight:
          type: number
          description: The height (in metres) of the highest part, excluding antennae, of an individual vehicle above the road surface.
          format: float
          exclusiveMinimum: 0
      required:
        - comparisonOperator
        - vehicleHeight
    LengthCharacteristic:
      title: LengthCharacteristic
      description: Length characteristic of a vehicle.
      type: object
      x-package: rate.eligibility
      properties:
        comparisonOperator:
          $ref: '#/components/schemas/ComparisonOperatorEnum'
        vehicleLength:
          type: number
          description: The overall distance (in metres) between the front and back of an individual vehicle, including the length of any trailers, couplings or embedded features.
          format: float
          exclusiveMinimum: 0
      required:
        - comparisonOperator
        - vehicleLength
    WidthCharacteristic:
      title: WidthCharacteristic
      type: object
      x-package: rate.eligibility
      description: Width characteristic of a vehicle
      properties:
        comparisonOperator:
          $ref: '#/components/schemas/ComparisonOperatorEnum'
        vehicleWidth:
          type: number
          format: float
          exclusiveMinimum: 0
          description: The maximum width of an individual vehicle, including any features embedded or fixed on it, in metres
      required:
        - comparisonOperator
        - vehicleWidth
    VehicleTypeEnum:
      title: VehicleTypeEnum
      description: |-
        * agriculturalVehicle : Vehicle normally used for agricultural purposes (e.g. tractor, combined harvester).
        * anyVehicle : Vehicle of any type.
        * articulatedBus : Articulated bus
        * articulatedTrolleyBus : Articulated trolley bus
        * articulatedVehicle : Articulated vehicle.
        * bicycle : Bicycle.
        * bus : Bus.
        * car : Vehicles designed and constructed for the carriage of passengers and comprising no more than eight seats (in addition to the driver seat), and having a maximum mass (technically permissible maximum laden mass) not exceeding 3.5 tons (M1).
        * caravan : Caravan.
        * carOrLightVehicle : Car or light vehicle.
        * carWithCaravan : Car towing a caravan.
        * carWithTrailer : Car towing a trailer.
        * constructionOrMaintenanceVehicle : Vehicle normally used for construction or maintenance purposes (e.g. digger, excavator, bulldozer, lorry mounted crane)
        * fourWheelDrive : Four wheel drive vehicle.
        * heavyDutyTransporter : A transporter for heavy duty (usually with abnormal dimensions).
        * heavyGoodsVehicle : Vehicles with a total weight above 3,500 kg (vehicle and load).
        * heavyGoodsVehicleWithTrailer : Heavy goods vehicle with trailer
        * heavyVehicle : Vehicle whose weight means it should be classed as a heavy vehicle
        * highSidedVehicle : High sided vehicle.
        * largeCar : Large car
        * largeGoodsVehicle : Vehicles for the carriage of goods and having a maximum mass exceeding 3.5 tonnes (belonging to class N2 when not exceeding 12 tonnes, otherwise class N3).
        * lightCommercialVehicle : Vehicles for the carriage of goods and having a maximum mass not exceeding 3.5 tonnes (class N1).
        * lightCommercialVehicleWithTrailer : Light goods vehicle with trailer
        * longHeavyLorry : A heavy lorry that is longer than normal.
        * lorry : Lorry of any type.
        * metro : Metro
        * minibus : Vehicles designed and constructed for the carriage of passengers, comprising more than eight seats (in addition to the driver seat), and having a maximum mass not exceeding 5 tonnes (class M2).
        * moped : Moped (a two wheeled motor vehicle characterized by a small engine typically less than 50cc and by normally having pedals).
        * motorcycle : Motorcycle.
        * motorcycleWithSideCar : Three wheeled vehicle comprising a motorcycle with an attached side car.
        * motorhome : motorhome
        * motorScooter : MotorScooter (a two wheeled motor vehicle characterized by a step-through frame and small diameter wheels).
        * other : Other than as defined in this enumeration.
        * passengerCar : Passenger car
        * smallCar : Small car
        * tanker : Vehicle with large tank for carrying bulk liquids.
        * threeWheeledVehicle : Three wheeled vehicle of unspecified type.
        * trailer : Trailer.
        * tram : Tram.
        * trolleyBus : Trolley bus
        * twoWheeledVehicle : Two wheeled vehicle of unspecified type.
        * unknown : Unknown.
        * van : Van.
        * vehicleWithCaravan : Vehicle (of unspecified type) towing a caravan.
        * vehicleWithCatalyticConverter : Vehicle with catalytic converter.
        * vehicleWithoutCatalyticConverter : Vehicle without catalytic converter.
        * vehicleWithTrailer : Vehicle (of unspecified type) towing a trailer.
        * withEvenNumberedRegistrationPlates : Vehicle with even numbered registration plate.
        * withOddNumberedRegistrationPlates : Vehicle with odd numbered registration plate.
      type: string
      x-package: rate.eligibility.enums
      enum:
        - agriculturalVehicle
        - anyVehicle
        - articulatedBus
        - articulatedTrolleyBus
        - articulatedVehicle
        - bicycle
        - bus
        - car
        - caravan
        - carOrLightVehicle
        - carWithCaravan
        - carWithTrailer
        - constructionOrMaintenanceVehicle
        - fourWheelDrive
        - heavyDutyTransporter
        - heavyGoodsVehicle
        - heavyGoodsVehicleWithTrailer
        - heavyVehicle
        - highSidedVehicle
        - largeCar
        - largeGoodsVehicle
        - lightCommercialVehicle
        - lightCommercialVehicleWithTrailer
        - longHeavyLorry
        - lorry
        - metro
        - minibus
        - moped
        - motorcycle
        - motorcycleWithSideCar
        - motorhome
        - motorScooter
        - other
        - passengerCar
        - smallCar
        - tanker
        - threeWheeledVehicle
        - trailer
        - tram
        - trolleyBus
        - twoWheeledVehicle
        - unknown
        - van
        - vehicleWithCaravan
        - vehicleWithCatalyticConverter
        - vehicleWithoutCatalyticConverter
        - vehicleWithTrailer
        - withEvenNumberedRegistrationPlates
        - withOddNumberedRegistrationPlates
    VehicleLoadTypeEnum:
      title: VehicleLoadTypeEnum
      description: |-
        * abnormalLoad : A load that exceeds normal vehicle dimensions in terms of height, length, width, gross vehicle weight or axle weight or any combination of these. Generally termed an "abnormal load".
        * ammunition : Ammunition.
        * chemicals : Chemicals of unspecified type.
        * combustibleMaterials : Combustible materials of unspecified type.
        * corrosiveMaterials : Corrosive materials of unspecified type.
        * debris : Debris of unspecified type.
        * empty : No load.
        * explosiveMaterials : Explosive materials of unspecified type.
        * extraHighLoad : A load of exceptional height.
        * extraLongLoad : A load of exceptional length.
        * extraWideLoad : A load of exceptional width.
        * fuel : Fuel of unspecified type.
        * glass : Glass.
        * goods : Any goods of a commercial nature.
        * hazardousMaterials : Materials classed as being of a hazardous nature.
        * liquid : Liquid of an unspecified nature.
        * livestock : Livestock.
        * materials : General materials of unspecified type.
        * materialsDangerousForPeople : Materials classed as being of a danger to people or animals.
        * materialsDangerousForTheEnvironment : Materials classed as being potentially dangerous to the environment.
        * materialsDangerousForWater : Materials classed as being dangerous when exposed to water (e.g. materials which may react exothermically with water).
        * oil : Oil.
        * ordinary : Materials that present limited environmental or health risk. Non-combustible, non-toxic, non-corrosive.
        * other : Other than as defined in this enumeration.
        * perishableProducts : Products or produce that will significantly degrade in quality or freshness over a short period of time.
        * petrol : Petrol or petroleum.
        * pharmaceuticalMaterials : Pharmaceutical materials.
        * radioactiveMaterials : Materials that emit significant quantities of electro-magnetic radiation that may present a risk to people, animals or the environment.
        * refrigeratedGoods : Refrigerated goods.
        * refuse : Refuse.
        * toxicMaterials : Materials of a toxic nature which may damage the environment or endanger public health.
        * vehicles : Vehicles of any type which are being transported.
      type: string
      x-package: rate.eligibility.enums
      enum:
        - abnormalLoad
        - ammunition
        - chemicals
        - combustibleMaterials
        - corrosiveMaterials
        - debris
        - empty
        - explosiveMaterials
        - extraHighLoad
        - extraLongLoad
        - extraWideLoad
        - fuel
        - glass
        - goods
        - hazardousMaterials
        - liquid
        - livestock
        - materials
        - materialsDangerousForPeople
        - materialsDangerousForTheEnvironment
        - materialsDangerousForWater
        - oil
        - ordinary
        - other
        - perishableProducts
        - petrol
        - pharmaceuticalMaterials
        - radioactiveMaterials
        - refrigeratedGoods
        - refuse
        - toxicMaterials
        - vehicles
    UserQualification:
      title: UserQualification
      description: Defines user group characteristics
      type: object
      x-package: rate.eligibility
      properties:
        userGroup:
          $ref: '#/components/schemas/ReferencedCodeListEntry'
      required:
        - userGroup
    RelativeOffsets:
      title: RelativeOffsets
      description: Relative offsets definition used in a time-based constrained
      type: object
      x-package: time
      properties:
        earliestStartRelative:
          $ref: '#/components/schemas/Duration'
        earliestEndRelative:
          $ref: '#/components/schemas/Duration'
        latestStartRelative:
          $ref: '#/components/schemas/Duration'
        latestEndRelative:
          $ref: '#/components/schemas/Duration'
    UnitOfTimeEnum:
      title: UnitOfTimeEnum
      description: The list of the supported units of measures of time.
      type: string
      x-package: time.enums
      enum:
        - year
        - month
        - week
        - day
        - hour
        - minute
        - second
    TimeUnitRelativeEnum:
      title: TimeUnitRelativeEnum
      description: |-
        A list of relativity operators for time units
        * `previous`
        * `current`
        * `next`
      type: string
      x-package: time.enums
      enum:
        - previous
        - current
        - next
    RelativeTimes:
      title: RelativeTimes
      description: Relative times definition used in a time-based constrained
      type: object
      x-package: time
      properties:
        unit:
          $ref: '#/components/schemas/UnitOfTimeEnum'
        earliestStartRelative:
          $ref: '#/components/schemas/TimeUnitRelativeEnum'
        earliestEndRelative:
          $ref: '#/components/schemas/TimeUnitRelativeEnum'
        latestStartRelative:
          $ref: '#/components/schemas/TimeUnitRelativeEnum'
        latestEndRelative:
          $ref: '#/components/schemas/TimeUnitRelativeEnum'
    TimesOfDay:
      title: TimesOfDay
      description: Definition of times used in a time-based constrained.
      type: object
      x-package: time
      properties:
        earliestStart:
          $ref: '#/components/schemas/Time'
        earliestEnd:
          $ref: '#/components/schemas/Time'
        latestStart:
          $ref: '#/components/schemas/Time'
        latestEnd:
          $ref: '#/components/schemas/Time'
    AssignedRightTimeRelative:
      title: AssignedRightTimeRelative
      description: Time based constrained for a Qualification (either specific times or relative offsets)
      type: object
      x-package: rate.eligibility
      discriminator:
        propertyName: metaType
        mapping:
          RelativeOffsets: '#/components/schemas/RelativeOffsets'
          RelativeTimes: '#/components/schemas/RelativeTimes'
          TimesOfDay: '#/components/schemas/TimesOfDay'
      properties:
        metaType:
          type: string
          enum:
            - RelativeOffsets
            - RelativeTimes
            - TimesOfDay
    LinkedRightSpecification:
      title: LinkedRightSpecification
      description: Time based constrained for a Qualification
      type: object
      x-package: rate.eligibility
      properties:
        assignedRightTimeRelative:
          description: earliest/latest start/end relative (via offsets) or specific (via times)
          $ref: '#/components/schemas/AssignedRightTimeRelative'
        qualifyingRightSpecification:
          description: held right specification to which this constraint relates
          $ref: '#/components/schemas/VersionedReference'
      required:
        - assignedRightTimeRelative
        - qualifyingRightSpecification
    AssignRightTime:
      title: AssignRightTime
      description: Qualification criteria for eligibility based on the duration of time relative to a defined time based qualification related to an assigned right.
      type: object
      x-package: rate.eligibility
      properties:
        assignedRightTime:
          type: string
          description: Assigned right time
          format: date-time
        comparisonOperator:
          $ref: '#/components/schemas/ComparisonOperatorEnum'
        unitOfTime:
          $ref: '#/components/schemas/UnitOfTimeEnum'
      required:
        - assignedRightTime
        - comparisonOperator
        - unitOfTime
    Qualification:
      title: Qualification
      description: Defines a set of criteria used to test eligibility for using a specific RateTable.
      type: object
      x-package: rate.eligibility
      properties:
        freeToPark:
          type: boolean
          description: Indicates that a parking is free (TRUE) or not (FALSE).
        withReservation:
          type: boolean
          description: Indicates whether a reservation is required (TRUE) or not (FALSE).
        withMembership:
          type: boolean
          description: Indicates that a membership is required (TRUE) or not (FALSE).
        membershipNames:
          type: array
          description: Free-text description of the membership names.
          items:
            $ref: '#/components/schemas/MultilingualString'
        propulsionEnergyType:
          type: array
          description: Indicates fuel/energy types of eligible vehicles.
          items:
            $ref: '#/components/schemas/FuelTypeEnum'
        emissions:
          $ref: '#/components/schemas/Emissions'
        grossWeightCharacteristics:
          type: array
          description: Qualify based on the vehicle's min/max gross weight characteristics
          uniqueItems: true
          maxItems: 2
          items:
            $ref: '#/components/schemas/GrossWeightCharacteristic'
        heightCharacteristics:
          type: array
          description: Qualify based on the vehicle's min/max height characteristics
          uniqueItems: true
          maxItems: 2
          items:
            $ref: '#/components/schemas/HeightCharacteristic'
        lengthCharacteristics:
          type: array
          description: Qualify based on the vehicle's min/max gross length characteristics
          uniqueItems: true
          maxItems: 2
          items:
            $ref: '#/components/schemas/LengthCharacteristic'
        widthCharacteristics:
          type: array
          description: Qualify based on the vehicle's min/max gross width characteristics
          uniqueItems: true
          maxItems: 2
          items:
            $ref: '#/components/schemas/WidthCharacteristic'
        vehicleTypes:
          type: array
          description: Qualify based on the type of vehicle.
          items:
            $ref: '#/components/schemas/VehicleTypeEnum'
        vehicleLoads:
          type: array
          description: Qualify based on the type of load carried by the vehicle.
          items:
            $ref: '#/components/schemas/VehicleLoadTypeEnum'
        userQualifications:
          type: array
          description: User-defined user groups qualification
          items:
            $ref: '#/components/schemas/UserQualification'
        activeAssignedRight:
          $ref: '#/components/schemas/VersionedReference'
        linkedRightSpecification:
          $ref: '#/components/schemas/LinkedRightSpecification'
        paymentMethod:
          type: array
          description: Qualifying payment methods
          items:
            $ref: '#/components/schemas/PaymentMethod'
        memberOfOtherRateTable:
          type: boolean
          description: Indicates if this qualification can be used in with another RateTable (TRUE) or not (FALSE).
        rateTableMember:
          type: array
          description: Free-text description of other rate table membership
          items:
            type: string
        assignRightTimes:
          type: array
          description: Qualify based on min/max time duration from a right being assigned
          uniqueItems: true
          maxItems: 2
          items:
            $ref: '#/components/schemas/AssignRightTime'
    CredentialAssigned:
      title: CredentialAssigned
      description: Defines a credential that is used for verification for one AssignedRight.
      type: object
      x-package: assigned_right.credential
      discriminator:
        propertyName: credentialAssignedType
        x-discriminator-default: VehicleCredential
        mapping:
          customer: '#/components/schemas/CustomerCredential'
          vehicle: '#/components/schemas/VehicleCredential'
          other: '#/components/schemas/OtherCredential'
      allOf:
        - $ref: '#/components/schemas/Credential'
        - type: object
          properties:
            credentialAssignedType:
              $ref: '#/components/schemas/CredentialAssignedTypeEnum'
            identifier:
              $ref: '#/components/schemas/Reference'
            issuer:
              $ref: '#/components/schemas/MultilingualString'
          required:
            - identifier
            - type
    CustomerCredential:
      title: CustomerCredential
      description: Details of a credential identifying a customer, like an individual or an organisation.
      type: object
      x-package: assigned_right.credential
      allOf:
        - $ref: '#/components/schemas/CredentialAssigned'
    VehicleCredential:
      title: VehicleCredential
      description: Details of a credential identifying a specific vehicle.
      type: object
      x-package: assigned_right.credential
      allOf:
        - $ref: '#/components/schemas/CredentialAssigned'
    OtherCredential:
      title: OtherCredential
      description: Details of a credential for identifying an entity other than a specific vehicle or customer.
      type: object
      x-package: assigned_right.credential
      allOf:
        - $ref: '#/components/schemas/CredentialAssigned'
    Credential:
      title: Credential
      description: Defines a form of credential that is applicable for a specific RightSpecification.
      type: object
      x-package: assigned_right.credential
      properties:
        type:
          $ref: '#/components/schemas/CredentialTypeEnum'
      required:
        - type
    CredentialAssignedTypeEnum:
      title: CredentialAssignedTypeEnum
      description: Defines the type of Credential for one AssignedRight.
      type: string
      x-package: assigned_right.credential
      enum:
        - customer
        - vehicle
        - other
    AssignedRightHolder:
      title: AssignedRightHolder
      description: Information concerning a specific holder of a granted right, corresponding to a defined __RightSpecification__.
      type: object
      x-package: assigned_right
      properties:
        credentials:
          type: array
          items:
            $ref: '#/components/schemas/CredentialAssigned'
    Eligibility:
      title: Eligibility
      description: Defines one or several qualifications to be eligible to a specific RateTable.
      type: object
      x-package: rate.eligibility
      allOf:
        - $ref: '#/components/schemas/VersionedIdentity'
        - type: object
          properties:
            description:
              $ref: '#/components/schemas/MultilingualString'
            eligibilityName:
              $ref: '#/components/schemas/MultilingualString'
            qualifications:
              type: array
              description: Describes the criteria to be eligible.
              items:
                $ref: '#/components/schemas/Qualification'
            rightHolders:
              type: array
              description: Represents a list of RightHolders that are automatically eligible for the specific RateTable.
              items:
                $ref: '#/components/schemas/AssignedRightHolder'
    CurrencyCode:
      title: CurrencyCode
      description: Code for the specified currency as defined in ISO 4217.
      type: string
      x-package: common
      pattern: ^[A-Z]{3}$
      examples:
        - GBP
        - EUR
    AmountInCurrency:
      title: AmountInCurrency
      description: A class supporting the definition of a unit of currency in a defined currency.
      type: object
      x-package: rate.payment
      properties:
        currencyType:
          description: The currency code.
          $ref: '#/components/schemas/CurrencyCode'
        currencyValue:
          type: number
          description: The amount of currency specified in the given currency code type.
          format: float
      required:
        - currencyType
        - currencyValue
    RateDiscount:
      title: RateDiscount
      description: Defines discount rates to be applied to a RateTable
      type: object
      x-package: rate
      properties:
        fixedValue:
          $ref: '#/components/schemas/AmountInCurrency'
        discountRate:
          type: number
          description: Proportionate discount (-) or surcharge (+) to be applied to all values in the referenced RateTable.
          minimum: 0
          maximum: 100
          format: float
    RateEligibility:
      title: RateEligibility
      description: Defines the combination of Eligibility requirements and RateTables to associate this combination to a RightSpecification.
      type: object
      x-package: rate.eligibility
      allOf:
        - $ref: '#/components/schemas/VersionedIdentity'
        - type: object
          properties:
            priority:
              type: integer
              description: An integer value, starting at 1, indicating the order in which multiple relevant RateTables shall be considered, with 1 being the highest priority.
              minimum: 1
            combinable:
              type: boolean
              description: Indicates if all RateTables associated to a RightSpecification with a common Eligibility can be combined to establish a lowest cost tariff (TRUE) or they cannot be combined (FALSE).
            eligibility:
              $ref: '#/components/schemas/Eligibility'
            rateTable:
              $ref: '#/components/schemas/VersionedReference'
            rateDiscount:
              $ref: '#/components/schemas/RateDiscount'
    OverpaymentPolicyTypeEnum:
      title: OverpaymentPolicyTypeEnum
      description: list of overpayment policy types
      x-package: right_specification
      type: string
      enum:
        - rateEndCutOff
        - fullTimePurchased
        - creditCarryOver
    RateTransition:
      title: RateTransition
      description: describes rate transition rules
      type: object
      x-package: right_specification
      properties:
        overpaymentPolicy:
          $ref: '#/components/schemas/OverpaymentPolicyTypeEnum'
        followThroughAllowed:
          type: boolean
        prepaymentAllowed:
          type: boolean
        reservationAvailable:
          type: boolean
    RightSpecification:
      title: RightSpecification
      description: Defines what the owner/manager of a place is granting the ability to do (e.g. park, delivery, pick up) to specific users or vehicles.
      type: object
      x-package: right_specification
      allOf:
        - $ref: '#/components/schemas/VersionedIdentity'
        - type: object
          properties:
            description:
              $ref: '#/components/schemas/MultilingualString'
            type:
              $ref: '#/components/schemas/RightSpecificationTypeEnum'
            financialReference:
              type: string
              description: Creator defined free-text reference to financial transactions associated to the specific Right Specification.
            transferable:
              type: boolean
            transferableConditions:
              type: boolean
            credentials:
              type: array
              description: The allowed credential types for this RightSpecification
              items:
                $ref: '#/components/schemas/CredentialTypeEnum'
            validity:
              $ref: '#/components/schemas/Validity'
            expiry:
              type: string
              description: Date/time showing the timestamp for when a RightSpecification ceases to be valid.
              format: date-time
            rightPools:
              type: array
              description: Shares the number of AssignedRights that are available for use, are currently in use, or intended for use within a specific RightSpecification in specific date/time periods by a specific AssignedRightIssuer'
              items:
                $ref: '#/components/schemas/RightPool'
            issuer:
              readOnly: true
              $ref: '#/components/schemas/VersionedReference'
            hierarchyElements:
              type: array
              description: Reference to Places where this RightSpecification is available.
              minItems: 1
              items:
                $ref: '#/components/schemas/VersionedReference'
            rateEligibility:
              type: array
              description: |-
                Defines the combination of Eligibility requirements with RateTables and associates this combination to a RightSpecification. 
                RateEligibility enables a RightSpecification to have association to multiple RateTable(s) for a
                specific Eligibility ( or set of Qualifications). 
                RateEligibility also defines if RateTables are Combinable. 
                This is a Yes / No (Boolean) definition. 
                Either all RateTables associated to a RightSpecification with a common Eligibility can be combined or they cannot.
              items:
                $ref: '#/components/schemas/RateEligibility'
            rateTransition:
              $ref: '#/components/schemas/RateTransition'
            extensions:
              description: The APDS extension container (Use Case Document §C.2.5; Part 4 §4.3). Undeclared on APDS 4.1 entities (APX erratum 010).
              $ref: '#/components/schemas/Extensions'
          required:
            - issuer
            - transferable
            - hierarchyElements
            - validity
    RightSpecificationList:
      title: RightSpecificationList
      description: Paginated list of RightSpecifications
      type: object
      x-package: right_specification
      allOf:
        - $ref: '#/components/schemas/PaginatedList'
        - type: object
          properties:
            data:
              type: array
              description: List of RightSpecifications
              items:
                $ref: '#/components/schemas/RightSpecification'
    RateAvailabilityTypeEnum:
      title: RateAvailabilityTypeEnum
      description: |-
        * private : Parking access is limited to known and authorized individuals.
        * public : Open to the public. 
        * restricted : Open to the public but requires a direct purpose or permission to use from owner (e.g. Doctor's surgery, storefront...)"
      type: string
      x-package: rate.enums
      enum:
        - private
        - public
        - restricted
    RateTypeEnum:
      title: RateTypeEnum
      description: |-
        Describes the type of rates for a RateTable.
        * contract : Rate provided to contract holders only.
        * daily : Rate provided on a daily rate, per calendar day.
        * event : Rate provided in combination with a specific event.
        * hourly : Rate provided on an hourly basis.
      type: string
      x-package: rate.enums
      enum:
        - contract
        - daily
        - event
        - hourly
    RateLineTypeEnum:
      title: RateLineTypeEnum
      description: |-
        Describes the type of rates of a RateLine.
        * flatRate : A rate applied to the rate line which is not time/duration dependent. i.e. a single fixed payment.
        * flatRateTier : A flat rate charge rate associated with a specific time-based tier. This is a special case of an incrementing rate.
        * incrementingRate : A charge rate that increases by a defined amount in a defined time.
      type: string
      x-package: rate.enums
      enum:
        - flatRate
        - flatRateTier
        - incrementingRate
    RateUsageConditionsTypeEnum:
      title: RateUsageConditionsTypeEnum
      description: |
        A list of supported rate usage condition types.
        * fixedDuration : Fixed duration - check Rate Usage Duration Limitation field
        * fixedNumber : check Rate Usage Count Limitation field
        * once : Permit can be used once
        * unlimited : Unlimited usage.
      type: string
      x-package: rate.enums
      enum:
        - fixedDuration
        - fixedNumber
        - once
        - unlimited
    TriggerTypeEnum:
      title: TriggerTypeEnum
      description: |-
        * firstUse : Trigger is applied on first use of the facility.
        * withTransaction : Trigger condition is met when the transaction is completed.
      type: string
      x-package: rate.enums
      enum:
        - firstUse
        - withTransaction
    RateLineTax:
      title: RateLineTax
      description: Contains details of the tax to be applied to a RateLine.
      type: object
      x-package: rate
      properties:
        triggerDescription:
          $ref: '#/components/schemas/MultilingualString'
        triggerType:
          $ref: '#/components/schemas/TriggerTypeEnum'
        taxIncluded:
          type: boolean
          description: Indicates if the tax to be applied is included within the total rate associated with this rate line (TRUE) or if the tax is to be added additionally to the total (FALSE).
        labelForDisplay:
          $ref: '#/components/schemas/MultilingualString'
        taxRate:
          type: number
          description: The percentage rate of tax to be applied.
          format: float
          maximum: 100
          minimum: 0
        taxValue:
          $ref: '#/components/schemas/AmountInCurrency'
      required:
        - taxIncluded
    RateLine:
      title: RateLine
      description: |-
        Describes a specific line in a __RateTable__. __incrementPeriod__ represents the time period for incrementing the __RateLine__ charge. 
        If set to the same as the duration of the period between the __durationStart__ and __durationEnd__, the increment will occur once per period, i.e. a flat rate time-based tier charge rate.
      type: object
      x-package: rate
      allOf:
        - $ref: '#/components/schemas/VersionedIdentity'
        - type: object
          properties:
            sequence:
              type: integer
              description: The position of this rate line within a __RateLineCollection__
              minimum: 1
            rateLineType:
              $ref: '#/components/schemas/RateLineTypeEnum'
            description:
              $ref: '#/components/schemas/MultilingualString'
            durationStart:
              type: string
              description: If used, indicates the start time for the applicability of the specific RateLine, generally with respect to the start of the parking Session, e.g. the start of a time-based tier charge rate. The format can be either of _hh:mm_ (hours and minutes) or _dd:hh:mm_ (days, hours and minutes).
            durationEnd:
              type: string
              description: If used, indicates the end time for the applicability of the specific RateLine, generally with respect to the end of the parking or other mobility Session, e.g. the end of a time-based tier charge rate.The format can be either of _hh:mm_ (hours and minutes) or _dd:hh:mm_ (days, hours and minutes).
            incrementPeriod:
              $ref: '#/components/schemas/Duration'
            value:
              type: number
              format: float
            minValue:
              type: number
              format: float
            maxValue:
              type: number
              format: float
            usageCondition:
              $ref: '#/components/schemas/RateUsageConditionsTypeEnum'
            rateLineTax:
              $ref: '#/components/schemas/RateLineTax'
          required:
            - sequence
            - rateLineType
            - value
    RateLineCollection:
      title: RateLineCollection
      description: Describes a group of __RateLine__ elements that logically group together within one __RateTable__.
      type: object
      x-package: rate
      allOf:
        - $ref: '#/components/schemas/VersionedIdentity'
        - type: object
          properties:
            collectionSequence:
              type: integer
              description: An indicator giving the place in sequence of this RateLineCollection.
              minimum: 1
            applicableCurrency:
              $ref: '#/components/schemas/CurrencyCode'
            minTime:
              $ref: '#/components/schemas/Duration'
            maxTime:
              $ref: '#/components/schemas/Duration'
            resetTime:
              $ref: '#/components/schemas/Time'
            minValueCollection:
              $ref: '#/components/schemas/AmountInCurrency'
            maxValueCollection:
              $ref: '#/components/schemas/AmountInCurrency'
            validStart:
              type: string
              description: The start time for the validity of this RateLineCollection.
              format: date-time
            validEnd:
              type: string
              description: The end time for the validity of this RateLineCollection.
              format: date-time
            relativeTimes:
              type: boolean
              description: Indicates whether or not times that are relative to the start of an event are used as the basis for rate calculation (TRUE), or if parking rate calculation definitions are done with respect to the parking sessions and defined as local or UTC times (FALSE).
            referenceTimeStart:
              type: string
              format: date-time
              description: Event-related reference start time
            referenceTimeEnd:
              type: string
              format: date-time
              description: Event-related reference end time
            taxIncluded:
              type: boolean
              description: Indication that tax to be applied is included within the total rate associated with this rate line collection (true) or indicates that the tax is added additionally to the total.
            taxRate:
              type: number
              description: The percentage rate of tax to be applied.
              format: float
              minimum: 0
              maximum: 100
            taxValue:
              type: number
              description: The monetary amount of tax to be applied.
              format: float
            rateLines:
              type: array
              minItems: 1
              items:
                $ref: '#/components/schemas/RateLine'
          required:
            - collectionSequence
            - applicableCurrency
            - resetTime
            - validStart
            - relativeTimes
            - taxIncluded
            - rateLines
    RateTable:
      title: RateTable
      description: Contains a specific set of rate line collection relating to one or more locations and optionally one set of eligibility criteria. rate table id refers to the internal identifier provided by the data supplier, and not the rate table unique identifier.
      type: object
      x-package: rate
      allOf:
        - $ref: '#/components/schemas/VersionedIdentity'
        - type: object
          properties:
            rateTableName:
              $ref: '#/components/schemas/MultilingualString'
            rateTableID:
              $ref: '#/components/schemas/MultilingualString'
            availability:
              $ref: '#/components/schemas/RateAvailabilityTypeEnum'
            rateResponsibleParty:
              readOnly: true
              $ref: '#/components/schemas/VersionedReference'
            rateSupersedeLink:
              $ref: '#/components/schemas/VersionedReference'
            validation:
              type: boolean
              description: Indicates if validations are accepted when using this RateTable.
            rateType:
              $ref: '#/components/schemas/RateTypeEnum'
            additionalInformation:
              $ref: '#/components/schemas/Url'
            validity:
              $ref: '#/components/schemas/Validity'
            rateLineCollections:
              type: array
              description: List of RateLineCollection that defines this RateTable.
              minItems: 1
              items:
                $ref: '#/components/schemas/RateLineCollection'
            extensions:
              description: The APDS extension container (Use Case Document §C.2.5; Part 4 §4.3). Undeclared on APDS 4.1 entities (APX erratum 010).
              $ref: '#/components/schemas/Extensions'
          required:
            - rateTableName
            - availability
            - rateLineCollections
    RateTableList:
      title: RateList
      description: Paginated list of Rates
      type: object
      x-package: rate
      allOf:
        - $ref: '#/components/schemas/PaginatedList'
        - type: object
          properties:
            data:
              type: array
              description: List of Rates
              items:
                $ref: '#/components/schemas/RateTable'
    Segment:
      title: Segment
      description: |-
        Segments enables a single __session__ to capture and report changes in __rates__ and __assigned rights__ during a its validity. A segment can only have one __assigned right__ and __rate__ associated to it and must always :
        * be associated to a __session__.
        * be associated to an __assigned right__ and to a specific __rate__ and __credential__ via the __assigned right__.
        * keep track of the version of the __assigned right__ (i.e. when a segment starts with one __assigned right__ and then is updated to a new __assigned right__ replacing the original at the end of the __segment__).
        * be associated with a __place__.
        * be associated to a __financial transaction__ data.
        * have a start and end time.
      type: object
      x-package: session
      allOf:
        - $ref: '#/components/schemas/VersionedIdentity'
        - type: object
          properties:
            actualStart:
              type: string
              format: date-time
            actualEnd:
              type: string
              format: date-time
            assignedRight:
              $ref: '#/components/schemas/VersionedReference'
            spaceId:
              $ref: '#/components/schemas/VersionedReference'
            validationType:
              type: array
              description: The form of validation (the nature of credential) that is used in conjunction with the specific segment.
              minItems: 1
              items:
                $ref: '#/components/schemas/CredentialTypeEnum'
            validationId:
              type: string
              description: Specific validation identification associated to the segment.
            credentialId:
              $ref: '#/components/schemas/Reference'
            notes:
              $ref: '#/components/schemas/MultilingualString'
          required:
            - actualStart
            - assignedRight
            - validationType
    Session:
      title: Session
      description: A session captures the actual use of an assigned right and includes start time, end time, credential, and other relevant data related to an operational transaction. A __session__ is not used for future activities, and is broken into one or multiple __segments__.
      type: object
      x-package: session
      allOf:
        - $ref: '#/components/schemas/VersionedIdentity'
        - type: object
          properties:
            actualStart:
              type: string
              format: date-time
              description: The date/time of the start of the session.
            actualEnd:
              type: string
              format: date-time
              description: The date/time of the end of the session.
            initiator:
              readOnly: true
              $ref: '#/components/schemas/VersionedReference'
            hierarchyElement:
              $ref: '#/components/schemas/VersionedReference'
            identifiedCredentials:
              type: array
              minItems: 1
              items:
                $ref: '#/components/schemas/CredentialAssigned'
            segments:
              type: array
              minItems: 1
              items:
                $ref: '#/components/schemas/Segment'
            identifiedVehicle:
              $ref: '#/components/schemas/VehicleAncillaryIdentification'
            extensions:
              description: The APDS extension container (Use Case Document §C.2.5; Part 4 §4.3). Undeclared on APDS 4.1 entities (APX erratum 010).
              $ref: '#/components/schemas/Extensions'
          required:
            - actualStart
            - initiator
            - identifiedCredentials
            - segments
    SessionList:
      title: SessionList
      description: Paginated list of Sessions
      type: object
      x-package: session
      allOf:
        - $ref: '#/components/schemas/PaginatedList'
        - type: object
          properties:
            data:
              type: array
              description: List of Sessions
              items:
                $ref: '#/components/schemas/Session'
    IssueMethodTypeEnum:
      title: IssueMethodTypeEnum
      description: |-
        A list of the supported methods for issuing credentials.
        * electronic : electronically issued, traceable
        * permit : physical identifier, typically visibly mounted within vehicle
        * ticket : typically single use, paper based
      type: string
      x-package: assigned_right.enums
      enum:
        - electronic
        - ticket
        - permit
    PlannedUse:
      title: PlannedUse
      description: Represents a specific future instance of an AssignedRight.
      type: object
      x-package: assigned_right
      properties:
        startTime:
          type: string
          description: Datetime instance when a PlannedUse is considered to start, and be available for use.
          format: date-time
        endTime:
          type: string
          description: Datetime instance when a PlannedUse is considered to end, and no longer be available for use.
          format: date-time
        cancelTime:
          type: string
          description: Datetime instance when a specific PlannedUse has been cancelled by the RightHolder.
          format: date-time
        expiryTime:
          type: string
          description: Datetime instance when a PlannedUse expires, and is no longer available for use.
          format: date-time
        issuer:
          readOnly: true
          $ref: '#/components/schemas/VersionedReference'
        issuanceTime:
          type: string
          description: Date/time at which a specific PlannedUse instance was issued.
          format: date-time
        issueMethod:
          $ref: '#/components/schemas/IssueMethodTypeEnum'
        credentialsAssigned:
          type: array
          description: Credentials that might be used for the future AssignedRight.
          minItems: 1
          items:
            $ref: '#/components/schemas/CredentialAssigned'
      required:
        - startTime
    PaymentTypeEnum:
      title: PaymentTypeEnum
      description: |-
        Indicates the nature of the payment made against an AssignedRight.
        * payment : Indicates financial payment made
        * validation : Indicates financial value offset through use of validation coupon or similar
      type: string
      x-package: rate.payment.enums
      enum:
        - payment
        - validation
    PaymentLine:
      title: PaymentLine
      description: Enables transaction details to be accumulated based on the type of payment (ie, base fee, taxes, surcharges, etc)
      type: object
      x-package: rate.payment
      allOf:
        - $ref: '#/components/schemas/VersionedIdentity'
        - type: object
          properties:
            identifierId:
              type: string
              description: Identifier for the transaction (e.g. reservation number, credit card transaction reference).
            idCode:
              type: string
              description: Unique cost code identifier, potentially agreed bi-laterally between data supplier and data receiver.
            paymentType:
              $ref: '#/components/schemas/PaymentTypeEnum'
            value:
              $ref: '#/components/schemas/AmountInCurrency'
          required:
            - paymentType
            - value
    Payment:
      title: Payment
      description: Represents the record of payments for associated AssignedRight.
      type: object
      x-package: rate.payment
      allOf:
        - $ref: '#/components/schemas/VersionedIdentity'
        - type: object
          properties:
            dateCollected:
              description: Datetime that the payment related to this financial transaction is recorded as being paid and collected.
              $ref: '#/components/schemas/DateTime'
            dateAuthorised:
              description: Datetime that the payment related to this financial transaction is authorised.
              $ref: '#/components/schemas/DateTime'
            serviceProvider:
              readOnly: true
              $ref: '#/components/schemas/VersionedReference'
            transactionID:
              type: string
              description: Identifier for the transaction (e.g. reservation number, credit card transaction reference) as agreed upon by the two entities sharing data.
            idCode:
              type: string
              description: User defined field to identity additional details such as customer account number or G/L account number.
            startPeriodCovered:
              type: string
              description: Note field to describe the start of the period a payment covers.
              format: date-time
            endPeriodCovered:
              type: string
              description: Note field to describe the end of the period a payment covers.
              format: date-time
            paymentLines:
              type: array
              description: A data class that enables transaction details to be accumulated.
              items:
                $ref: '#/components/schemas/PaymentLine'
            extensions:
              description: The APDS extension container (Use Case Document §C.2.5; Part 4 §4.3). Undeclared on APDS 4.1 entities (APX erratum 010). Carries apds-ext:apx:payment-detail@1.0 with rateSold only; the Payment's own paymentLines are the itemization (Part 13 §13.6a).
              $ref: '#/components/schemas/Extensions'
          required:
            - serviceProvider
            - paymentLines
    MonetaryValue:
      title: MonetaryValue
      type: object
      description: Lightweight record of the monetary financial value of the associated AssignedRight (temporary). Service provider is entity responsible for selling/collecting fees associated to the AR.
      x-package: rate.payment
      properties:
        taxIncluded:
          type: boolean
          description: Whether tax included in monetary value, if yes (TRUE), if not (FALSE).
        serviceProvider:
          $ref: '#/components/schemas/VersionedReference'
          readOnly: true
        value:
          $ref: '#/components/schemas/AmountInCurrency'
      required:
        - taxIncluded
        - serviceProvider
        - value
    AssignedRight:
      title: AssignedRight
      description: AssignedRight indicates the granting of a specific right specification to a specific right holder, and indicates one instance of a planned use of the right.
      type: object
      x-package: assigned_right
      allOf:
        - $ref: '#/components/schemas/VersionedIdentity'
        - type: object
          properties:
            rightSpecification:
              $ref: '#/components/schemas/VersionedReference'
            rightHolder:
              $ref: '#/components/schemas/AssignedRightHolder'
            assignedRightIssuer:
              readOnly: true
              $ref: '#/components/schemas/VersionedReference'
            issueMethod:
              $ref: '#/components/schemas/IssueMethodTypeEnum'
            issuanceTime:
              type: string
              description: The datetime this AssignedRight was issued.
              format: date-time
            minutesAvailable:
              type: number
              description: Number of decimal minutes that are remaining for use under a specified AssignedRight.
              format: float
            minutesUsed:
              type: number
              description: Number of decimal minutes that have been used under a specified AssignedRight.
              format: float
            totalMinutes:
              type: number
              description: Number of decimal minutes that have been issued under a specified AssignedRight.
              format: float
            remainingValue:
              $ref: '#/components/schemas/AmountInCurrency'
            totalRightValue:
              $ref: '#/components/schemas/AmountInCurrency'
            instancesUsed:
              type: integer
              description: The total number of instances that have been used under a specified RightSpecification.
            instancesAvailable:
              type: integer
              description: The total number of instances that are available for use under a specified RightSpecification.
            totalInstances:
              type: integer
              description: The total number of instances that have been issued under a specified AssignedRight.
            expiry:
              type: string
              description: The datetime when the specific AssignedRight expires, and is not longer available for use.
              format: date-time
            plannedUses:
              type: array
              description: Planned future uses of this AssignedRight.
              items:
                $ref: '#/components/schemas/PlannedUse'
            payments:
              type: array
              description: Payments made for this AssignedRight.
              items:
                $ref: '#/components/schemas/Payment'
            monetaryValue:
              $ref: '#/components/schemas/MonetaryValue'
            extensions:
              description: The APDS extension container (Use Case Document §C.2.5; Part 4 §4.3). Undeclared on APDS 4.1 entities (APX erratum 010).
              $ref: '#/components/schemas/Extensions'
          required:
            - rightSpecification
            - rightHolder
    AssignedRightList:
      title: AssignedRightList
      description: Paginated list of AssignedRights
      type: object
      x-package: assigned_right
      allOf:
        - $ref: '#/components/schemas/PaginatedList'
        - type: object
          properties:
            data:
              type: array
              description: List of AssignedRights
              items:
                $ref: '#/components/schemas/AssignedRight'
    ReferenceQuoteExtension:
      title: ReferenceQuoteExtension
      type: object
      description: Class providing a versioned reference to a quote for a session extension
      properties:
        quoteResponseId:
          $ref: '#/components/schemas/VersionedReference'
        optionId:
          $ref: '#/components/schemas/VersionedReference'
      x-package: Quotes
      x-tags: Quotes
    ReferenceQuoteNew:
      title: ReferenceQuoteNew
      type: object
      description: Class providing a versioned reference to a new quote
      properties:
        quoteResponseId:
          $ref: '#/components/schemas/VersionedReference'
        optionId:
          $ref: '#/components/schemas/VersionedReference'
      x-package: Quotes
      x-tags: Quotes
    ReferenceToQuote:
      title: ReferenceToQuote
      description: Class defining a reference to a specific Quote
      oneOf:
        - $ref: '#/components/schemas/ReferenceQuoteExtension'
        - $ref: '#/components/schemas/ReferenceQuoteNew'
      x-package: Quotes
      x-tags: Quotes
    ReferencedRightSpecification:
      title: ReferencedRightSpecification
      type: object
      description: class to support referencing a RightSpecification
      properties:
        elementId:
          $ref: '#/components/schemas/VersionedReference'
        rightSpecificationId:
          $ref: '#/components/schemas/VersionedReference'
      required:
        - rightSpecificationId
      x-package: Quotes
      x-tags: Quotes
    QuoteRightRequest:
      title: QuoteRightRequest
      description: class containing data elements required to request a quote for a new transaction
      allOf:
        - $ref: '#/components/schemas/VersionedIdentity'
        - type: object
          properties:
            eligibility:
              $ref: '#/components/schemas/Eligibility'
            referencedRightSpecifications:
              type: array
              items:
                $ref: '#/components/schemas/ReferencedRightSpecification'
            periodStart:
              type: string
              format: date-time
              description: request date/time for the start of a proposed new transactions
            periodEnd:
              type: string
              format: date-time
              description: request date/time for the end of a proposed new transactions
            requestTime:
              type: string
              format: date-time
              description: date/time at which the request was made
            timePeriods:
              type: array
              items:
                $ref: '#/components/schemas/Duration'
              description: requested duration for the proposed new transaction
          required:
            - periodStart
            - requestTime
      x-package: Quotes
      x-tags: Quotes
    ResponseReasonEnum:
      title: ResponseReasonEnum
      description: |
        A list of supported reasons if a requested quote response is not provided

        * `eligibilityRequirementNotMet`: a stated eligibility requirement is not considered to be met
        * `noAvailability`: No availability for request
        * `noMatchingSpecification`: No matching rights specification found
        * `other`: other reason (reason not given)
        * `rightSpecificationNotAvailableAtRequestedTimes`: the requested specification is not available at the requested time
      type: string
      enum:
        - eligibilityRequirementNotMet
        - noAvailability
        - noMatchingSpecification
        - other
        - rightSpecificationNotAvailableAtRequestedTimes
      x-package: Quotes
      x-tags: Quotes
    QuoteExpiration:
      title: QuoteExpiration
      description: class defining conditions indicating the end of the validity of a quote
      properties:
        expiresDateTime:
          type: string
          format: date-time
        firstComeFirstServe:
          type: boolean
          description: a Boolean value shows that the availability of an Option and thus FinancialQuote are available to the requester on a first come first served basis, with no assurance that the advertised RightSpecification will be available based on actual demand
      required:
        - firstComeFirstServe
      x-package: Quotes
      x-tags: Quotes
    Identifiers:
      title: Identifiers
      description: compound reference for rate table and right specification
      properties:
        rateTableID:
          $ref: '#/components/schemas/VersionedReference'
        rightSpecificationId:
          $ref: '#/components/schemas/VersionedReference'
        rateTableId:
          description: The quoted RateTable (the spelling Identifiers.required names). Publishers send this member; rateTableID is the APDS 4.1 declared spelling of the same reference and MAY accompany it (APX erratum 009).
          $ref: '#/components/schemas/VersionedReference'
      required:
        - rateTableId
        - rightSpecificationId
      x-package: Quotes
      x-tags: Quotes
    FinancialQuote:
      title: FinancialQuote
      type: object
      description: class containing information on financila value of a quote
      properties:
        serviceProvider:
          $ref: '#/components/schemas/VersionedReference'
        taxIncluded:
          type: boolean
          description: whether tax is included in the specified monetary value or not
        transactionId:
          type: string
          description: identifier for the transaction (e.g. reservation number) as agreed upon by the two entities sharing data
        value:
          $ref: '#/components/schemas/AmountInCurrency'
      required:
        - taxIncluded
        - value
      x-package: Quotes
      x-tags: Quotes
    Option:
      title: Option
      description: Class providing one option to a quote request
      allOf:
        - $ref: '#/components/schemas/VersionedIdentity'
        - type: object
          properties:
            elementId:
              $ref: '#/components/schemas/VersionedReference'
            exact:
              type: boolean
              description: indicates the supplied Option fully covers the time period requested
            quoteExpiration:
              $ref: '#/components/schemas/QuoteExpiration'
            identifiers:
              type: array
              minItems: 1
              items:
                $ref: '#/components/schemas/Identifiers'
            financialQuote:
              $ref: '#/components/schemas/FinancialQuote'
          required:
            - quoteExpiration
            - financialQuote
      x-package: Quotes
      x-tags: Quotes
    QuoteRightResponse:
      title: QuoteRightResponse
      description: class containing data to support response to request for quote for a new transaction
      allOf:
        - $ref: '#/components/schemas/VersionedIdentity'
        - type: object
          properties:
            start:
              type: string
              description: date/time for the start of the proposed new transaction
              format: date-time
            end:
              type: string
              description: date/time for the end of the proposed new transaction
              format: date-time
            requestTime:
              type: string
              description: date/time at which the request for a quote was recorded/registered by the supplier
              format: date-time
            reason:
              $ref: '#/components/schemas/ResponseReasonEnum'
            quoteRequestId:
              $ref: '#/components/schemas/VersionedReference'
            responseTime:
              description: date/time at which the response is made by the supplier
              format: date-time
              type: string
            options:
              type: array
              items:
                $ref: '#/components/schemas/Option'
          required:
            - start
            - end
            - requestTime
            - quoteRequestId
            - responseTime
      x-package: Quotes
      x-tags: Quotes
    QuoteSessionExtensionRequest:
      title: QuoteSessionExtensionRequest
      description: class containing detail required to initiate a request for a quote to extend an existing session
      allOf:
        - $ref: '#/components/schemas/VersionedIdentity'
        - type: object
          properties:
            requestedEndTime:
              type: string
              description: proposed date/time at which the proposed extended Session would end
              format: date-time
            requestTime:
              type: string
              description: reference date/time at which the request for a quote for a session extension is made
              format: date-time
            sessionId:
              $ref: '#/components/schemas/VersionedReference'
            suppliedCredential:
              $ref: '#/components/schemas/VersionedReference'
          required:
            - requestedEndTime
            - requestTime
            - sessionId
            - suppliedCredential
      x-package: Quotes
      x-tags: Quotes
    QuoteRightResponseExtensionReasonEnum:
      title: QuoteRightResponseExtensionReasonEnum
      description: |
        A list of supported reasons if a requested session extension request is not provided

        * `existingSessionNotFound`: Error – the existing session referenced is not found
        * `incorrectCredentialsSupplied`: Error – credential details supplied are incorrect
        * `noExtensionPossible`: Error – the requested extension is not possible
      type: string
      enum:
        - existingSessionNotFound
        - incorrectCredentialsSupplied
        - noExtensionPossible
      x-package: Quotes
      x-tags: Quotes
    QuoteSessionExtensionResponse:
      title: QuoteSessionExtensionResponse
      description: class containing data to support response to request for quote to extend an existing Session
      allOf:
        - $ref: '#/components/schemas/VersionedIdentity'
        - type: object
          properties:
            requestSessionExtensionId:
              $ref: '#/components/schemas/VersionedReference'
            sessionId:
              $ref: '#/components/schemas/VersionedReference'
            requestTime:
              type: string
              format: date-time
              description: date/time at which the request for a quote was recorded/registered by the supplier
            responseTime:
              type: string
              format: date-time
              description: date/time at which the response is made by the supplier
            revisedEndTime:
              type: string
              format: date-time
              description: Date/time of the revised session end time
            reason:
              $ref: '#/components/schemas/QuoteRightResponseExtensionReasonEnum'
          required:
            - requestSessionExtensionId
            - sessionId
            - requestTime
            - responseTime
            - revisedEndTime
      x-package: Quotes
      x-tags: Quotes
    PermitExtension:
      title: PermitExtension
      description: |-
        The `apds-ext:apx:permit@1.1` extension object (Part 14 §14.2; `@1.0`
        remains valid and carries the first two members only): links a renewal
        permit to the one it renews, so a portal can follow the chain, and
        caps how many of a multi-vehicle permit's vehicles may be parked at
        once (§14.2d).
      type: object
      properties:
        renews:
          description: The AssignedRight this permit renews.
          $ref: '#/components/schemas/Reference'
        renewedBy:
          description: Set by the server on the renewed permit when a renewal is issued.
          readOnly: true
          $ref: '#/components/schemas/Reference'
        maxConcurrentVehicles:
          type: integer
          minimum: 1
          description: |-
            How many of the permit's registered vehicles may be parked at the
            place at once (Part 14 §14.2d). Absent means every registered
            vehicle may. A vehicle beyond the limit is an overage.
        overageBilling:
          type: object
          description: What an overage costs (Part 14 §14.2d).
          required:
            - mode
          properties:
            mode:
              type: string
              enum:
                - rack
                - dayRate
                - none
              description: '`rack` — the place''s transient rate deck; `dayRate` — the flat `dayRate`; `none` — recorded, not billed.'
            dayRate:
              $ref: '#/components/schemas/AmountInCurrency'
    SubscriptionFilters:
      title: SubscriptionFilters
      type: object
      description: Server-side delivery filtering.
      properties:
        places:
          type: array
          description: |-
            Only events bound to these HierarchyElement subtrees are delivered
            (Part 8 §8.5). Every entry must lie inside the token's `apx_places`
            grant, else 403 `insufficient-grant`.
          items:
            type: string
            format: uuid
        severityFloor:
          type: string
          description: For alert topics — minimum severity delivered.
          enum:
            - info
            - warning
            - minor
            - major
            - critical
        alertTypes:
          type: array
          description: |-
            For alert topics — only alerts whose `alertType` is listed are
            delivered (Part 8 §8.5a). Values are `apx-alert-types` entries or
            implementer types; combines with `severityFloor` (both must hold).
          items:
            type: string
          examples:
            - - scofflawArrival
              - refusedServiceArrival
    ApxEventSubscriptionPatch:
      title: ApxEventSubscriptionPatch
      description: |-
        Body of `PATCH /webhooks/{id}`: a JSON Merge Patch (RFC 7396) over
        ApxEventSubscription. Members present replace the stored value, an
        explicit `null` clears an optional member, and absent members are
        unchanged — so `{"status": "active"}` alone resumes a subscription.
        `version`, when given, is the precondition (Part 4 §4.2a); a stale one
        is 409 `version-conflict`. `id`, `activeKeyIds`, and `recordInfo` are
        server-managed and cannot be patched.
      type: object
      properties:
        version:
          type: integer
          minimum: 1
          description: The version the client last read.
        endpoint:
          $ref: '#/components/schemas/Url'
        topics:
          type: array
          minItems: 1
          items:
            type: string
        transport:
          type: string
          enum:
            - webhook
            - sse
        filters:
          description: Replaces the stored filters; `{}` removes every filter.
          $ref: '#/components/schemas/SubscriptionFilters'
        secret:
          type: string
          description: A new signing secret; starts a rotation overlap (Part 8 §8.1).
        secretRef:
          type: string
          writeOnly: true
        keyId:
          type: string
          writeOnly: true
        retireKeyIds:
          type: array
          writeOnly: true
          items:
            type: string
        status:
          type: string
          enum:
            - active
            - paused
            - failed
          description: |-
            `active` or `paused` — the client-settable states. `failed` is
            server-assigned; a PATCH setting it is 400 `invalid-request`.
        extensions:
          $ref: '#/components/schemas/Extensions'
    DeliveryAttempt:
      title: DeliveryAttempt
      description: One delivery attempt of one event to one subscription.
      type: object
      required:
        - deliveryId
        - time
        - code
      properties:
        deliveryId:
          type: string
          format: uuid
          description: The attempt's `APX-Delivery-Id` (unique per attempt).
        time:
          description: When the attempt was sent — also its `APX-Timestamp` (each attempt is signed afresh, Part 8 §8.3).
          $ref: '#/components/schemas/DateTime'
        code:
          type: integer
          description: HTTP status code received (0 = network error or timeout).
    CommandResult:
      title: CommandResult
      description: |-
        The structured outcome of a command, populated by the server when the
        command reaches `succeeded` (Part 6 §6.1a) and absent before then. Members
        are normative per command type: `lostTicket` → `ticketNumber`, `session`,
        `amountDue`; `matchTicket` → `session`, `amountDue`;
        `pushNegotiatedRate` → `amountDue`, and `rateTable` when a table was
        selected (absent for a stated amount, which the lane inquiry reports
        as `currentTicket.negotiatedAmount`). Other command types
        leave it absent unless a registry entry says otherwise. It restates what
        the lane inquiry shows, so a console can continue (print, take payment)
        without parsing `statusHistory[].detail` or making a second call.
      type: object
      readOnly: true
      properties:
        ticketNumber:
          type: string
          description: The ticket the command issued or bound (lostTicket).
        session:
          description: The APDS Session the ticket belongs to (lostTicket, matchTicket).
          $ref: '#/components/schemas/Reference'
        amountDue:
          description: The amount due on the ticket immediately after the command.
          $ref: '#/components/schemas/AmountInCurrency'
        rateTable:
          description: The RateTable at the exact version applied (pushNegotiatedRate with a table; absent for a stated amount).
          $ref: '#/components/schemas/VersionedReference'
        display:
          description: |-
            Proof of display for `displayMessage` (Part 6 §6.1a): what the
            device confirmed it showed, when, and whether the player or an
            operator acknowledged it. A Part 26 §26.9 DisplayRecord that names
            this command MUST agree with it.
          $ref: '#/components/schemas/DisplayProof'
        extensions:
          $ref: '#/components/schemas/Extensions'
    TollPricing:
      title: TollPricing
      description: |-
        Request body pricing a `created` toll transaction (Part 15 §15.1), for
        operators whose pricing engine runs outside the APX server.
      type: object
      required:
        - pricing
      properties:
        pricing:
          $ref: '#/components/schemas/AmountInCurrency'
        detail:
          type: string
          description: Pricing basis recorded in `statusHistory` (e.g. vehicle class, rate id).
    TollVoid:
      title: TollVoid
      description: Request body voiding a toll transaction that should never have been charged (Part 15 §15.1).
      type: object
      required:
        - reason
      properties:
        reason:
          type: string
          description: Why the transaction is void (implementer code list, e.g. duplicate, exemptVehicle, misread).
          examples:
            - duplicate
        note:
          type: string
    ValidationVoidDetail:
      title: ValidationVoidDetail
      description: Who voided an issuance or instrument, when, and why. Present once `void`.
      type: object
      readOnly: true
      properties:
        reason:
          type: string
        note:
          type: string
        time:
          $ref: '#/components/schemas/DateTime'
        actor:
          type: string
        voidedCount:
          type: integer
          minimum: 0
          description: On an issuance, how many un-redeemed instruments the void moved to `void` (redeemed ones are unaffected).
    ValidationIssuanceRequest:
      title: ValidationIssuanceRequest
      description: |-
        Request body for `POST /v1/validations/programs/{id}/issuances`: the
        writable members of `ValidationIssuance`. The program is the one the
        path names; `program` MAY be repeated in the body, and a value that
        differs from the path is 422 `request-unprocessable` (Part 20 §20.2).
        Server-assigned members (`id`, `version`, `codes`, `issuanceStatus`)
        are ignored if sent.
      type: object
      required:
        - quantity
        - method
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
        version:
          type: integer
          minimum: 1
          readOnly: true
        program:
          description: Optional; defaults to, and MUST equal, the program in the path.
          $ref: '#/components/schemas/Reference'
        quantity:
          type: integer
          minimum: 1
        method:
          type: string
          enum:
            - code
            - qrCode
            - stamp
            - digital
            - api
        validFrom:
          $ref: '#/components/schemas/DateTime'
        validTo:
          description: Expiry of every instrument in the batch; defaults from the program's `rules.validityWindow`.
          $ref: '#/components/schemas/DateTime'
        issuedTo:
          type: string
          description: Opaque principal or merchant contact the stock was handed to.
        codes:
          type: array
          readOnly: true
          items:
            type: string
        issuanceStatus:
          type: string
          enum:
            - issued
            - void
          readOnly: true
        note:
          type: string
        recordInfo:
          $ref: '#/components/schemas/RecordInfo'
        extensions:
          $ref: '#/components/schemas/Extensions'
    ValidationVoid:
      title: ValidationVoid
      description: |-
        Request body voiding an issuance batch or a single instrument code
        (Part 20 §20.2 rule 5) — a stolen sheet, a leaked code, a misprint.
      type: object
      required:
        - reason
      properties:
        reason:
          type: string
          description: Implementer code list — lost, stolen, leaked, misprint, programEnded.
          examples:
            - stolen
        note:
          type: string
    PresentedCredential:
      title: PresentedCredential
      description: |-
        What the reader actually read at the lane. Carried on an access event
        when no CredentialRecord matched (`denialReason: unknownCredential`),
        and MAY be carried otherwise. Personal data under Part 21 §21.5:
        returned only under `apx.credentials:*` scopes.
      type: object
      required:
        - credentialType
        - credentialIdentification
      properties:
        credentialType:
          $ref: '#/components/schemas/CredentialTypeEnum'
        credentialIdentification:
          type: string
          description: The value read (card number, tag id, plate).
          examples:
            - C-0099999
    AccessEvent:
      title: AccessEvent
      description: |-
        One access attempt at a lane, whether or not the presented credential
        matched a CredentialRecord — the item of `GET /v1/access-events` and
        the data of `apx.credentials.access.v1`. `credential` is REQUIRED
        whenever a record matched; it is absent only for `denialReason:
        unknownCredential`, where `presented` is REQUIRED instead (Part 21
        §21.4). Every `CredentialAccessEvent` is a valid `AccessEvent`; this
        schema exists because `CredentialAccessEvent.credential` is required
        and relaxing it would break clients of the per-credential history.
      type: object
      required:
        - occurredAt
        - direction
        - outcome
      properties:
        id:
          type: string
          format: uuid
        credential:
          description: The matched CredentialRecord; absent only when nothing matched.
          $ref: '#/components/schemas/Reference'
        presented:
          $ref: '#/components/schemas/PresentedCredential'
        occurredAt:
          $ref: '#/components/schemas/DateTime'
        place:
          $ref: '#/components/schemas/Reference'
        lane:
          description: The VehicularAccess where the attempt occurred.
          $ref: '#/components/schemas/Reference'
        device:
          description: The reader (SupplementalEquipment).
          $ref: '#/components/schemas/Reference'
        direction:
          type: string
          enum:
            - entry
            - exit
        outcome:
          type: string
          enum:
            - granted
            - denied
        denialReason:
          type: string
          description: When denied — definedValue from `apx-access-denial-reasons` or an implementer code list (Part 11).
          examples:
            - unknownCredential
        session:
          description: The APDS Session opened or closed by a granted access.
          $ref: '#/components/schemas/Reference'
        extensions:
          $ref: '#/components/schemas/Extensions'
    ValetPickupRequest:
      title: ValetPickupRequest
      description: Request body recording that a runner has gone to fetch the car (`requested → retrieving`).
      type: object
      properties:
        retrievingBy:
          type: string
          description: Opaque principal of the runner; absent = the calling principal.
          examples:
            - runner-0107
        note:
          type: string
    ValetCancelRequest:
      title: ValetCancelRequest
      description: Request body abandoning a drop-off before custody was taken; the ticket becomes `cancelled` (terminal).
      type: object
      required:
        - reason
      properties:
        reason:
          type: string
          description: Implementer code list (customerLeft, selfParked, duplicateTicket, refused…).
          examples:
            - customerLeft
        note:
          type: string
    ConnectorTypeEnum:
      title: ConnectorTypeEnum
      description: |-
        A table of commonly used connectors / charging interfaces
        * cee3: CEE3, 230 V, 16 A
        * cee5: CEE5, 400 V, 16-63 A
        * chademo: CHAdeMO, 600 V DC. Used mostly in Japan.
        * domestic: A domestic socket of unspecified type. Applicable countries should be specified in seperate attribute.
        * domesticA: Domestic socket type A (mainly used in the USA, Canada, Mexico & Japan)
        * domesticB: Domestic socket type B (mainly used in the USA, Canada & Mexico)
        * domesticC: Domestic socket type C (commonly used in Europe, South America & Asia)
        * domesticD: Domestic socket type D (mainly used in India)
        * domesticE: Domestic socket type E (primarily used in France, Belgium, Poland, Slovakia & Czechia)
        * domesticF: Domestic socket type F (used almost everywhere in Europe & Russia, except for the UK & Ireland)
        * domesticG: Domestic socket type G (mainly used in the United Kingdom, Ireland, Malta, Malaysia, Singapore & the Arabian Peninsula)
        * domesticH: Domestic socket type H (used exclusively in Israel, the West Bank & the Gaza Strip)
        * domesticI: Domestic socket type I (mainly used in Australia, New Zealand, China & Argentina)
        * domesticJ: Domestic socket type J (used almost exclusively in Switzerland & Liechtenstein)
        * domesticK: Domestic socket type K (used almost exclusively in Denmark & Greenland)
        * domesticL: Domestic socket type L (used almost exclusively in Italy & Chile)
        * domesticM: Domestic socket type M (mainly used in South Africa)
        * domesticN: Domestic socket type N (used in Brazil and South Africa)
        * domesticO: Domestic socket type O (used exclusively in Thailand)
        * iec60309x2single16:  IEC 60309-2 Industrial Connector single phase 16 amperes (usually blue)
        * iec60309x2three16: IEC 60309-2 Industrial Connector three phase 16 amperes (usually red)
        * iec60309x2three32: IEC 60309-2 Industrial Connector three phase 32 amperes (usually red)
        * iec60309x2three64: IEC 60309-2 Industrial Connector three phase 64 amperes (usually red)
        * iec62196T1: IEC 62196 Type 1 "SAE J1772".  Mostly used in USA and Asia.
        * iec62196T1COMBO: Combo Type 1 based, DC
        * iec62196T2: IEC 62196 Type 2 "Mennekes" - 400 V, 16-63 A. Mandatory in Europe
        * iec62196T2COMBO: Combo Type 2 based, DC, Type 2 connector with extension for simultaneous DC-charging
        * iec62196T3A: IEC 62196 Type 3A
        * iec62196T3C: " IEC 62196 Type 3C ""Scame""  "
        * other: Other charging interface.
        * pantographBottomUp: On-board Bottom-up-Pantograph typically for bus charging
        * pantographTopDown: Off-board Top-down-Pantograph typically for bus charging
        * teslaConnectorAmerica: Tesla connector used in America (Tesla specific)
        * teslaConnectorEurope: Tesla Connector EU (modification of the Type 2 connector)
        * teslaR: Tesla Connector "Roadster"-type (round, 4 pin)
        * teslaS: Tesla Connector "Model-S"-type (oval, 5 pin)
        * yazaki: Yazaki, 400 VDC, 125 A, Asian standard.
      type: string
      x-package: place.service.enums
      enum:
        - cee3
        - cee5
        - chademo
        - domestic
        - domesticA
        - domesticB
        - domesticC
        - domesticD
        - domesticE
        - domesticF
        - domesticG
        - domesticH
        - domesticI
        - domesticJ
        - domesticK
        - domesticL
        - domesticM
        - domesticN
        - domesticO
        - iec60309x2single16
        - iec60309x2three16
        - iec60309x2three32
        - iec60309x2three64
        - iec62196T1
        - iec62196T1COMBO
        - iec62196T2
        - iec62196T2COMBO
        - iec62196T3A
        - iec62196T3C
        - other
        - pantographBottomUp
        - pantographTopDown
        - teslaConnectorAmerica
        - teslaConnectorEurope
        - teslaR
        - teslaS
        - yazaki
    AuthenticationAndIdentificationEnum:
      title: AuthenticationAndIdentificationEnum
      description: |-
        A table of authentication and/or identification methods: 
        * activeRFIDChip: Phone (active RFID chip)
        * apps: Apps
        * calypso: RFID Calypso
        * cashPayment: No specific authentication by using cash
        * creditCard: Credit card
        * debitCard: Debit card
        * mifareClassic: RFID Card / Phone NFC - Mifare Classic
        * mifareDesfire: RFID Card / Phone NFC - Mifare Desfire
        * nfc: Nearfield communication
        * noAccess: No access granted
        * overTheAir: Over the air according to ISO 15118
        * phoneDialog: phone (dialog with platform)
        * phoneSMS: Phone (SMS)
        * pinpad: PINPAD
        * plc: PLC according to ISO 15118
        * prepaidCard: Pre-Paid card
        * rfid: RFID
        * unlimitedAccess: No authentication/identification required.
        * website: Using a website
      type: string
      x-package: place.service.enums
      enum:
        - activeRFIDChip
        - apps
        - calypso
        - cashPayment
        - creditCard
        - debitCard
        - mifareClassic
        - mifareDesfire
        - nfc
        - noAccess
        - overTheAir
        - phoneDialog
        - phoneSMS
        - pinpad
        - plc
        - prepaidCard
        - rfid
        - unlimitedAccess
        - website
    PaymentLinkCancel:
      title: PaymentLinkCancel
      description: |-
        Request body cancelling a payment link before the customer pays
        (Part 13 §13.1a). The body is optional; `reason` is recorded on the
        link's audit trail.
      type: object
      properties:
        reason:
          type: string
          description: Why the link was cancelled (implementer code list, e.g. wrongRecipient, paidOtherwise).
          examples:
            - wrongRecipient
        note:
          type: string
    AlertTransition:
      title: AlertTransition
      description: |-
        Optional body of `POST /v1/alerts/{id}/acknowledge` and `/resolve`
        (Part 7 §7.2). Annotates the `statusHistory[]` entry the transition
        appends. Sending no body is equivalent to sending `{}`.
      type: object
      properties:
        detail:
          type: string
          description: Copied verbatim into the appended history entry's `detail`.
          examples:
            - field tech dispatched, ETA 40 min
        agent:
          type: string
          description: |-
            The human or AI principal acting through the calling client (as
            `Command.agent`, Part 6 §6.1). When given it is recorded as the
            appended entry's `actor`; otherwise `actor` is the principal
            derived from the token. Attribution only: authorization is always
            the token's.
          examples:
            - agent:j.okafor
        extensions:
          $ref: '#/components/schemas/Extensions'
    IdentifiedArea:
      title: IdentifiedArea
      description: |-
        An identifiable discrete bounded geographic zone that shares common characteristics and that may be used for 
        parking related or other purposes. 
        Identified Areas are segmented into two types : Vehicular Access class and Specific Area class.
      type: object
      x-package: place
      allOf:
        - $ref: '#/components/schemas/HierarchyElement'
        - type: object
          properties:
            streetAddress:
              type: array
              description: Identified area street address.
              items:
                $ref: '#/components/schemas/Address'
            areaBoundedZone:
              type: array
              description: Identified area bounded zone.
              items:
                $ref: '#/components/schemas/GeoJsonObject'
            indicativePointLocation:
              type: array
              description: Indicative identified area point location.
              items:
                $ref: '#/components/schemas/GeoJsonObject'
            times:
              $ref: '#/components/schemas/Times'
            operatingRestrictions:
              type: array
              description: Operating restrictions
              items:
                $ref: '#/components/schemas/OperatingRestrictions'
    UserTypeEnum:
      title: UserTypeEnum
      description: |-
        Types of different users,for example used in the context of parking.
        * allUsers: All users.
        * commuters: Commuters.
        * customers: Customers.
        * disabled: Physically impaired people.
        * elderlyUsers: Elderly users.
        * employees: Employees.
        * families: Families.
        * handicapped: Persons with deficiencies in their daily life.
        * hearingImpaired: People with difficulties to hear.
        * hotelGuests: Hotel guests.
        * longTermParkers: Long-term parker.
        * members: Members.
        * men: Men.
        * other: Other.
        * overnightParkers: Overnight parker.
        * parkAndCycleUser: Park and cycle user.
        * parkAndRideUsers: Users that are exchanging into public transport at a park and ride station.
        * parkAndWalkUser: Park and walk user.
        * pensioners: Pensioners.
        * pregnantWomen: Pregnant women.
        * registeredDisabledUsers: Registered disabled persons.
        * reservationHolders: Those who have a valid reservation, e.g. for the duration of parking.
        * residents: Local residents.
        * seasonTicketHolders: Season ticket holders.
        * shoppers: Shoppers.
        * shortTermParkers: Short-term parker.
        * sportEventAwaySupporters: Sport event away supporters.
        * sportEventHomeSupporters: Sport event home supporters.
        * staff: Staff.
        * students: Students.
        * subscribers: Subscribers.
        * unknown: Unknown.
        * visitors: Visitors.
        * visuallyImpaired: People with difficulties to see.
        * wheelchairUsers: Wheelchair users.
        * women: Women.
      type: string
      x-package: place.enums
      enum:
        - allUsers
        - commuters
        - customers
        - disabled
        - elderlyUsers
        - employees
        - families
        - handicapped
        - hearingImpaired
        - hotelGuests
        - longTermParkers
        - members
        - men
        - other
        - overnightParkers
        - parkAndCycleUser
        - parkAndRideUsers
        - parkAndWalkUser
        - pensioners
        - pregnantWomen
        - registeredDisabledUsers
        - reservationHolders
        - residents
        - seasonTicketHolders
        - shoppers
        - shortTermParkers
        - sportEventAwaySupporters
        - sportEventHomeSupporters
        - staff
        - students
        - subscribers
        - unknown
        - visitors
        - visuallyImpaired
        - wheelchairUsers
        - women
    SupplementalFacility:
      title: SupplementalFacility
      description: One type of supplemental facility which can be supplemental equipment or a supplemental service facility.
      type: object
      x-package: place
      allOf:
        - $ref: '#/components/schemas/IdentifiedArea'
        - type: object
          properties:
            accessibilities:
              type: array
              description: Information on accessibility, easements and marking for handicapped people.
              items:
                $ref: '#/components/schemas/AccessibilityTypeEnum'
            additionalDescription:
              $ref: '#/components/schemas/MultilingualString'
            applicableForUsers:
              type: array
              description: Limitation to a set of special users.
              items:
                $ref: '#/components/schemas/UserTypeEnum'
            comment:
              $ref: '#/components/schemas/MultilingualString'
            externalIdentifiers:
              type: array
              description: An external identifier for the supplemental facility, e.g. an inventory number. This attribute has an unbounded multiplicity to support identifiers for multiple occurrences of this element.'
              items:
                type: string
            nameOrBrand:
              $ref: '#/components/schemas/MultilingualString'
            otherSupplementalFacility:
              type: array
              items:
                $ref: '#/components/schemas/MultilingualString'
            photoUrl:
              $ref: '#/components/schemas/Url'
            quantity:
              type: integer
              minimum: 0
              description: Number of the supplemental facility (e.g. number of toilets, restaurants, park & ride places, etc.) with respect to given restrictions. Dynamic overridable.
            regularlyCleaned:
              type: boolean
              description: Indication, if the supplemental facility is cleaned on a regular basis.
            rightSpecificationIds:
              type: array
              description: List of applicable right specifications
              items:
                $ref: '#/components/schemas/VersionedReference'
            supplementalFacilityIndex:
              type: integer
              description: An index to link this supplemental facility between the static and dynamic publications.
          required:
            - supplementalFacilityIndex
    EquipmentTypeEnum:
      title: EquipmentTypeEnum
      description: |-
        Types of equipment.
        * bikeParking: Bike parking.
        * cashMachine: Cash machine.
        * copyMachineOrService: A possibility to create copies of documents.
        * defibrillator: Medical equipment to provide first aid after heart attacks.
        * dsrcReceiver: A system to manage digital short range communication (radio beacon transceivers), e.g. for tolling roadside equipment.
        * dumpingStation: Possibility to get rid of sewerage (especially for motorhomes).
        * electricChargingStation: For charging vehicles, motorhome supply etc. The 'numberOf...' attribute specifies the number of charging stations.
        * elevator: Indication of the availability of elevators.
        * faxMachineOrService: A possibility to send and/or receive faxes.
        * fireExtinguisher: Fire extinguisher
        * fireHose: A hose for water transport in case of fire.
        * fireHydrant: Fire hydrant
        * firstAidEquipment: Equipment to support first aid on injured people. Note that 'defibrillator' is a separate literal.
        * iceFreeScaffold: A technical equipment to remove ice and snow from the roof of lorries.
        * informationPoint: An information point with employees.
        * informationStele: An unmanned information point.
        * internetTerminal: Public internet terminal. Charges may be specified using the TariffsAndPayment section.
        * internetWireless: Public wireless internet. Specifying an amount would be the number of hotspots/access points. Charges may be specified using the TariffsAndPayment section.
        * luggageLocker: Possibility to deposit luggage in a safe way.
        * none: None.
        * other: Some other equipment. Use 'otherSupplementalFacility' to specify it.
        * paymentMachine: A payment machine, for example a parking ticket machine.
        * picnicFacilities: Indication of whether any picnicking facilities, such as tables, chairs and shaded areas, are available.
        * playground: A playground for children.
        * publicCardPhone: Indicates, whether there's a public telephone available that can be used with a card.
        * publicCoinPhone: Indicates, whether there's a public telephone available that can be used with coins.
        * publicPhone: Indicates, whether there's a public telephone available.
        * refuseBin: Refuse bins for small amounts of garbage (see also 'wasteDisposal').
        * safeDeposit: A possibility to store valuable possession in a safe way. 
        * shelter: A shelter (against wind, sun, ....).
        * shower: Indicates, whether there are shower facilities available.
        * snowAndIceRemovalEquipment: Equipment to remove snow and ice.nt
        * toilet: Indicates, whether there are toilets available.
        * tollTerminal: A terminal, where toll charges can be paid manually (this does not mean a toll gate on the road)
        * tyreAirPressureEquipment: Equipment to measure and refill tyre air pressure.
        * unknown: Unknown.
        * vendingMachine: A vending machine for snacks, coffee etc. (without manpower).
        * wasteDisposal: Possibility to get rid of waste in a legal way (e.g. for truckers or motorhomes). Normal refuse bins are not intended here.
        * waterBasin: A water basin to wash hands, clothes or dishes.
        * waterSupply: Supply of fresh water, e.g. for motorhomes.
        * waterTap: Fresh water out of a tap.
      type: string
      x-package: place.service.enums
      enum:
        - bikeParking
        - cashMachine
        - copyMachineOrService
        - defibrillator
        - dsrcReceiver
        - dumpingStation
        - electricChargingStation
        - elevator
        - faxMachineOrService
        - fireExtinguisher
        - fireHose
        - fireHydrant
        - firstAidEquipment
        - iceFreeScaffold
        - informationPoint
        - informationStele
        - internetTerminal
        - internetWireless
        - luggageLocker
        - none
        - other
        - paymentMachine
        - picnicFacilities
        - playground
        - publicCardPhone
        - publicCoinPhone
        - publicPhone
        - refuseBin
        - safeDeposit
        - shelter
        - shower
        - snowAndIceRemovalEquipment
        - toilet
        - tollTerminal
        - tyreAirPressureEquipment
        - unknown
        - vendingMachine
        - wasteDisposal
        - waterBasin
        - waterSupply
        - waterTap
    DeliveryUnitEnum:
      title: DeliveryUnitEnum
      description: |-
        Table with different units in which the delivery is measured.
        * gasGallonEquivalent: The amount of alternative fuel it takes to equal the energy content of one liquid gallon of gasoline. Used mostly in the US.
        * imperialGallon: Imperial Gallon (4.54609 litres)
        * kg: kilogram
        * kWh: kilowatt hour
        * litre: Litre
        * m3: cubic meter
        * usGallon: US-Gallon (3.785411784 litres)
      type: string
      x-package: place.service.enums
      enum:
        - gasGallonEquivalent
        - imperialGallon
        - kg
        - kWh
        - litre
        - m3
        - usGallon
    Units:
      title: Units
      description: Amount in units, which are specified by unitTypeEnum.
      type: number
      x-package: common.units
    ReservationTypeEnum:
      title: ReservationTypeEnum
      description: |-
        Different types of reservation.
        * mandatory: Reservation is mandatory.
        * notAvailable: Reservation is not possible.
        * optional: Reservation is optional.
        * partly: There is a specific contingent, that can be reserved.
        * unknown: Possibility of reservation is unknown,
        * unspecified: Possibility of reservation is not specified.
      type: string
      x-package: place.service.enums
      enum:
        - mandatory
        - notAvailable
        - optional
        - partly
        - unknown
        - unspecified
    ServiceTypeEnum:
      title: ServiceTypeEnum
      description: |-
        A table of different service levels to be expected for fuelling/charging and payment.
        * fullService: Full fuelling service carried out by an employee.
        * selfService: Self Service for fuelling
        * unattended: Unattended station, fuelling and payment to be done without assistance.
      type: string
      x-package: place.service.enums
      enum:
        - fullService
        - selfService
        - unattended
    RefillPoint:
      title: RefillPoint
      description: Technical infrastructure at a specific location that facilitates an energy refilling process being connected to maximum one vehicle at a time.
      type: object
      x-package: place.service
      properties:
        authenticationAndIdentificationMethods:
          type: array
          description: Information on what methods of identification and/or authentication are accepted
          items:
            $ref: '#/components/schemas/AuthenticationAndIdentificationEnum'
        currencyOverride:
          type: array
          description: Information on which currency/currencies can be used to pay
          items:
            $ref: '#/components/schemas/CurrencyCode'
        deliveryUnit:
          $ref: '#/components/schemas/DeliveryUnitEnum'
        minimumDeliveryAmount:
          $ref: '#/components/schemas/Units'
        maximumDeliveryAmount:
          $ref: '#/components/schemas/Units'
        modelType:
          $ref: '#/components/schemas/MultilingualString'
        refillPointIndex:
          type: integer
          description: An index to link this element between the static and dynamic publications.
        reservability:
          $ref: '#/components/schemas/ReservationTypeEnum'
        serviceType:
          type: array
          description: Information on different service types for the fuelling/charging and payment process.
          items:
            $ref: '#/components/schemas/ServiceTypeEnum'
        userInterfaceLanguage:
          type: array
          description: Languages, in which a user interface is available, if any
          items:
            $ref: '#/components/schemas/LanguageCode'
      required:
        - refillPointIndex
    SupplementalEquipment:
      title: SupplementalEquipment
      description: One type of supplemental equipment, which is available on some site, for example on a rest area.
      type: object
      x-package: place
      allOf:
        - $ref: '#/components/schemas/SupplementalFacility'
        - type: object
          properties:
            equipmentType:
              $ref: '#/components/schemas/EquipmentTypeEnum'
            refillPoints:
              type: array
              items:
                $ref: '#/components/schemas/RefillPoint'
          required:
            - equipmentType
    EventTypeEnum:
      title: EventTypeEnum
      type: string
      enum:
        - AssignedRightCreated
        - AssignedRightUpdated
        - AssignedRightDeleted
        - SessionCreated
        - SessionUpdated
        - SessionDeleted
        - PlaceCreated
        - PlaceUpdated
        - PlaceDeleted
        - RightSpecificationCreated
        - RightSpecificationUpdated
        - RightSpecificationDeleted
        - RateCreated
        - RateUpdated
        - RateDeleted
        - OrganisationCreated
        - OrganisationUpdated
        - OrganisationDeleted
    EventData:
      title: EventData
      description: data of created / updated / deleted record
      type: object
      oneOf:
        - $ref: '#/components/schemas/HierarchyElement'
        - $ref: '#/components/schemas/RightSpecification'
        - $ref: '#/components/schemas/RateTable'
        - $ref: '#/components/schemas/AssignedRight'
        - $ref: '#/components/schemas/Session'
        - $ref: '#/components/schemas/Contact'
    SubscriptionFailure:
      title: SubscriptionFailure
      description: |-
        Data of `apx.subscription.failed.v1` (Part 8 §8.3): which subscription
        stopped, where it was delivering, and the attempt that exhausted the
        schedule. The envelope `subject` references the same subscription.
      type: object
      required:
        - subscription
        - failedTime
      properties:
        subscription:
          description: The subscription (`className` `ApxEventSubscription`).
          $ref: '#/components/schemas/Reference'
        endpoint:
          description: The endpoint that stopped answering (webhook transport).
          $ref: '#/components/schemas/Url'
        failedTime:
          description: When the subscription entered `failed`.
          $ref: '#/components/schemas/DateTime'
        firstFailedEventId:
          type: string
          format: uuid
          description: EventEnvelope.id of the first event that could not be delivered.
        attempts:
          type: integer
          minimum: 1
          description: Attempts made for that event before the schedule was exhausted.
        lastCode:
          type: integer
          description: The last HTTP status code received (0 = network error).
    ChangePayload:
      title: ChangePayload
      description: |-
        A change-mode payload for any native APDS entity class (Part 5 §5.1):
        the entity's identity plus only the members that changed. An absent
        member is unchanged; an explicit `null` clears it. Nested objects that
        carry their own `id` (a Session segment, say) follow the same rule.

        This schema checks the envelope only (identity present, any member may
        be null). Each member present is still validated by the server against
        the class's native property schema, and a member the class does not
        define is refused with 400 (Part 5 §5.1a). It is the request schema of
        a native `PUT` sent with `APX-Update-Mode: change`, and the shape of
        every `ChangeFeedPage` item.
      type: object
      required:
        - id
      properties:
        id:
          type: string
          minLength: 1
          description: The entity's identifier (APDS VersionedIdentity.id).
        version:
          type: integer
          minimum: 1
          description: |-
            On a write, the version the client last read (the precondition,
            Part 4 §4.2a); on a feed item, the version after the change.
      additionalProperties: true
    HierarchyElementChangePayload:
      title: HierarchyElementChangePayload
      description: 'A change-mode body for native `PUT /places/{id}` (Part 5 §5.1a): `id` plus only the HierarchyElement members that changed; an absent member is unchanged and an explicit `null` clears it. Every member present is checked against the class, and a member the class does not define is refused. Generated at build time (tools/change-payloads.mjs); the generic ChangePayload remains the shape of change-feed items.'
      type: object
      required:
        - id
      properties:
        id:
          type: string
          minLength: 1
          description: The entity identifier (APDS VersionedIdentity.id).
        version:
          anyOf:
            - type: integer
              description: Positive integer representing the object version.
              minimum: 1
              examples:
                - 1
            - type: 'null'
        type:
          anyOf:
            - $ref: '#/components/schemas/HierarchyElementTypeEnum'
            - type: 'null'
        name:
          type:
            - array
            - 'null'
          minItems: 1
          items:
            type: object
        description:
          type:
            - array
            - 'null'
          minItems: 1
          items:
            type: object
        aliases:
          type:
            - array
            - 'null'
          items:
            $ref: '#/components/schemas/MultilingualString'
        operatorDefinedReference:
          type:
            - object
            - 'null'
        parentId:
          type:
            - object
            - 'null'
        childIds:
          type:
            - array
            - 'null'
          items:
            type: object
        layer:
          anyOf:
            - type: integer
              minimum: 0
              description: Indicator of the position of this hierarchy element in the specific hierarchy, with the top of the hierarchy numbered layer 0.
            - type: 'null'
        rightSpecifications:
          type:
            - array
            - 'null'
          items:
            type: object
        hierarchyElementRecord:
          type:
            - object
            - 'null'
        hierarchyElementReference:
          type:
            - object
            - 'null'
        occupancyLevel:
          type:
            - object
            - 'null'
        responsibilityRoleAssignments:
          type:
            - array
            - 'null'
          items:
            type: object
        extensions:
          anyOf:
            - $ref: '#/components/schemas/Extensions'
            - type: 'null'
        characteristics:
          type:
            - object
            - 'null'
        contacts:
          type:
            - array
            - 'null'
          items:
            type: object
        marketing:
          type:
            - object
            - 'null'
        operatingRestrictions:
          type:
            - array
            - 'null'
          items:
            type: object
        rgbColours:
          type:
            - array
            - 'null'
          items:
            type: object
        times:
          type:
            - object
            - 'null'
        paymentMethods:
          type:
            - array
            - 'null'
          items:
            type: object
        safetyStandardClassifications:
          type:
            - array
            - 'null'
          items:
            type: object
        timeZone:
          anyOf:
            - type: string
              description: IANA time-zone (see https://www.iana.org/time-zones)
            - type: 'null'
        placeStreetAddress:
          type:
            - object
            - 'null'
        placeBoundedZone:
          type:
            - array
            - 'null'
          items:
            type: object
        indicativePointLocation:
          type:
            - array
            - 'null'
          items:
            type: object
        spaceId:
          type:
            - object
            - 'null'
        detection:
          anyOf:
            - $ref: '#/components/schemas/ParkingSpaceOccupancyDetectionEnum'
            - type: 'null'
        spaceBoundedZone:
          type:
            - object
            - 'null'
        spaceDimension:
          type:
            - object
            - 'null'
        spaceMaximumDims:
          type:
            - object
            - 'null'
      additionalProperties: false
    ContactPointChangePayload:
      title: ContactPointChangePayload
      description: 'A change-mode body for native `PUT /contacts/{contactId}` (Part 5 §5.1a): `id` plus only the ContactPoint members that changed; an absent member is unchanged and an explicit `null` clears it. Every member present is checked against the class, and a member the class does not define is refused. Generated at build time (tools/change-payloads.mjs); the generic ChangePayload remains the shape of change-feed items.'
      type: object
      required:
        - id
      properties:
        contactType:
          anyOf:
            - $ref: '#/components/schemas/ContactTypeEnum'
            - type: 'null'
        contactNotDefined:
          anyOf:
            - type: boolean
              description: When true, there is currently no contact defined for the selected role and/or timeframe. Don't use the specialisations in this case.
            - type: 'null'
        contactUnknown:
          anyOf:
            - type: boolean
              description: When true, the contact for the selected role and/or timeframe is unknown. Don't use the specialisations in this case.
            - type: 'null'
        shareWithPublic:
          anyOf:
            - type: boolean
              description: When true, the details of this contact may be shared with the public. If false these contacts details are for internal purposes only.
            - type: 'null'
        validityOfContact:
          type:
            - object
            - 'null'
        id:
          type: string
          minLength: 1
          description: The entity identifier (APDS VersionedIdentity.id).
        version:
          anyOf:
            - type: integer
              description: Positive integer representing the object version.
              minimum: 1
              examples:
                - 1
            - type: 'null'
        organisationName:
          type:
            - array
            - 'null'
          minItems: 1
          items:
            type: object
        type:
          anyOf:
            - $ref: '#/components/schemas/ContactPointTypeEnum'
            - type: 'null'
        address:
          type:
            - array
            - 'null'
          items:
            type: object
        contactDetails:
          type:
            - array
            - 'null'
          items:
            type: object
        eMailCommonData:
          type:
            - array
            - 'null'
          items:
            type: object
        telephoneContacts:
          type:
            - array
            - 'null'
          items:
            type: object
        pointLocations:
          type:
            - array
            - 'null'
          items:
            type: object
        extensions:
          anyOf:
            - $ref: '#/components/schemas/Extensions'
            - type: 'null'
      additionalProperties: false
    RightSpecificationChangePayload:
      title: RightSpecificationChangePayload
      description: 'A change-mode body for native `PUT /rights/specs/{id}` (Part 5 §5.1a): `id` plus only the RightSpecification members that changed; an absent member is unchanged and an explicit `null` clears it. Every member present is checked against the class, and a member the class does not define is refused. Generated at build time (tools/change-payloads.mjs); the generic ChangePayload remains the shape of change-feed items.'
      type: object
      required:
        - id
      properties:
        id:
          type: string
          minLength: 1
          description: The entity identifier (APDS VersionedIdentity.id).
        version:
          anyOf:
            - type: integer
              description: Positive integer representing the object version.
              minimum: 1
              examples:
                - 1
            - type: 'null'
        description:
          type:
            - array
            - 'null'
          minItems: 1
          items:
            type: object
        type:
          anyOf:
            - $ref: '#/components/schemas/RightSpecificationTypeEnum'
            - type: 'null'
        financialReference:
          anyOf:
            - type: string
              description: Creator defined free-text reference to financial transactions associated to the specific Right Specification.
            - type: 'null'
        transferable:
          anyOf:
            - type: boolean
            - type: 'null'
        transferableConditions:
          anyOf:
            - type: boolean
            - type: 'null'
        credentials:
          type:
            - array
            - 'null'
          items:
            $ref: '#/components/schemas/CredentialTypeEnum'
        validity:
          type:
            - object
            - 'null'
        expiry:
          anyOf:
            - type: string
              description: Date/time showing the timestamp for when a RightSpecification ceases to be valid.
              format: date-time
            - type: 'null'
        rightPools:
          type:
            - array
            - 'null'
          items:
            type: object
        issuer:
          type:
            - object
            - 'null'
        hierarchyElements:
          type:
            - array
            - 'null'
          minItems: 1
          items:
            type: object
        rateEligibility:
          type:
            - array
            - 'null'
          items:
            type: object
        rateTransition:
          type:
            - object
            - 'null'
        extensions:
          anyOf:
            - $ref: '#/components/schemas/Extensions'
            - type: 'null'
      additionalProperties: false
    RateTableChangePayload:
      title: RateTableChangePayload
      description: 'A change-mode body for native `PUT /rates/{id}` (Part 5 §5.1a): `id` plus only the RateTable members that changed; an absent member is unchanged and an explicit `null` clears it. Every member present is checked against the class, and a member the class does not define is refused. Generated at build time (tools/change-payloads.mjs); the generic ChangePayload remains the shape of change-feed items.'
      type: object
      required:
        - id
      properties:
        id:
          type: string
          minLength: 1
          description: The entity identifier (APDS VersionedIdentity.id).
        version:
          anyOf:
            - type: integer
              description: Positive integer representing the object version.
              minimum: 1
              examples:
                - 1
            - type: 'null'
        rateTableName:
          type:
            - array
            - 'null'
          minItems: 1
          items:
            type: object
        rateTableID:
          type:
            - array
            - 'null'
          minItems: 1
          items:
            type: object
        availability:
          anyOf:
            - $ref: '#/components/schemas/RateAvailabilityTypeEnum'
            - type: 'null'
        rateResponsibleParty:
          type:
            - object
            - 'null'
        rateSupersedeLink:
          type:
            - object
            - 'null'
        validation:
          anyOf:
            - type: boolean
              description: Indicates if validations are accepted when using this RateTable.
            - type: 'null'
        rateType:
          anyOf:
            - $ref: '#/components/schemas/RateTypeEnum'
            - type: 'null'
        additionalInformation:
          anyOf:
            - $ref: '#/components/schemas/Url'
            - type: 'null'
        validity:
          type:
            - object
            - 'null'
        rateLineCollections:
          type:
            - array
            - 'null'
          minItems: 1
          items:
            type: object
        extensions:
          anyOf:
            - $ref: '#/components/schemas/Extensions'
            - type: 'null'
      additionalProperties: false
    SessionChangePayload:
      title: SessionChangePayload
      description: 'A change-mode body for native `PUT /sessions/{id}` (Part 5 §5.1a): `id` plus only the Session members that changed; an absent member is unchanged and an explicit `null` clears it. Every member present is checked against the class, and a member the class does not define is refused. Generated at build time (tools/change-payloads.mjs); the generic ChangePayload remains the shape of change-feed items.'
      type: object
      required:
        - id
      properties:
        id:
          type: string
          minLength: 1
          description: The entity identifier (APDS VersionedIdentity.id).
        version:
          anyOf:
            - type: integer
              description: Positive integer representing the object version.
              minimum: 1
              examples:
                - 1
            - type: 'null'
        actualStart:
          anyOf:
            - type: string
              format: date-time
              description: The date/time of the start of the session.
            - type: 'null'
        actualEnd:
          anyOf:
            - type: string
              format: date-time
              description: The date/time of the end of the session.
            - type: 'null'
        initiator:
          type:
            - object
            - 'null'
        hierarchyElement:
          type:
            - object
            - 'null'
        identifiedCredentials:
          type:
            - array
            - 'null'
          minItems: 1
          items:
            type: object
        segments:
          type:
            - array
            - 'null'
          minItems: 1
          items:
            type: object
        identifiedVehicle:
          type:
            - object
            - 'null'
        extensions:
          anyOf:
            - $ref: '#/components/schemas/Extensions'
            - type: 'null'
      additionalProperties: false
    AssignedRightChangePayload:
      title: AssignedRightChangePayload
      description: 'A change-mode body for native `PUT /rights/assigned/{id}` (Part 5 §5.1a): `id` plus only the AssignedRight members that changed; an absent member is unchanged and an explicit `null` clears it. Every member present is checked against the class, and a member the class does not define is refused. Generated at build time (tools/change-payloads.mjs); the generic ChangePayload remains the shape of change-feed items.'
      type: object
      required:
        - id
      properties:
        id:
          type: string
          minLength: 1
          description: The entity identifier (APDS VersionedIdentity.id).
        version:
          anyOf:
            - type: integer
              description: Positive integer representing the object version.
              minimum: 1
              examples:
                - 1
            - type: 'null'
        rightSpecification:
          type:
            - object
            - 'null'
        rightHolder:
          type:
            - object
            - 'null'
        assignedRightIssuer:
          type:
            - object
            - 'null'
        issueMethod:
          anyOf:
            - $ref: '#/components/schemas/IssueMethodTypeEnum'
            - type: 'null'
        issuanceTime:
          anyOf:
            - type: string
              description: The datetime this AssignedRight was issued.
              format: date-time
            - type: 'null'
        minutesAvailable:
          anyOf:
            - type: number
              description: Number of decimal minutes that are remaining for use under a specified AssignedRight.
              format: float
            - type: 'null'
        minutesUsed:
          anyOf:
            - type: number
              description: Number of decimal minutes that have been used under a specified AssignedRight.
              format: float
            - type: 'null'
        totalMinutes:
          anyOf:
            - type: number
              description: Number of decimal minutes that have been issued under a specified AssignedRight.
              format: float
            - type: 'null'
        remainingValue:
          type:
            - object
            - 'null'
        totalRightValue:
          type:
            - object
            - 'null'
        instancesUsed:
          anyOf:
            - type: integer
              description: The total number of instances that have been used under a specified RightSpecification.
            - type: 'null'
        instancesAvailable:
          anyOf:
            - type: integer
              description: The total number of instances that are available for use under a specified RightSpecification.
            - type: 'null'
        totalInstances:
          anyOf:
            - type: integer
              description: The total number of instances that have been issued under a specified AssignedRight.
            - type: 'null'
        expiry:
          anyOf:
            - type: string
              description: The datetime when the specific AssignedRight expires, and is not longer available for use.
              format: date-time
            - type: 'null'
        plannedUses:
          type:
            - array
            - 'null'
          items:
            type: object
        payments:
          type:
            - array
            - 'null'
          items:
            type: object
        monetaryValue:
          type:
            - object
            - 'null'
        extensions:
          anyOf:
            - $ref: '#/components/schemas/Extensions'
            - type: 'null'
      additionalProperties: false
    ObservationElementChangePayload:
      title: ObservationElementChangePayload
      description: 'A change-mode body for native `PUT /observations/{id}` (Part 5 §5.1a): `id` plus only the ObservationElement members that changed; an absent member is unchanged and an explicit `null` clears it. Every member present is checked against the class, and a member the class does not define is refused. Generated at build time (tools/change-payloads.mjs); the generic ChangePayload remains the shape of change-feed items.'
      type: object
      required:
        - id
      properties:
        id:
          type: string
          minLength: 1
          description: The entity identifier (APDS VersionedIdentity.id).
        version:
          anyOf:
            - type: integer
              description: Positive integer representing the object version.
              minimum: 1
              examples:
                - 1
            - type: 'null'
        method:
          anyOf:
            - $ref: '#/components/schemas/ObservationTypeEnum'
            - type: 'null'
        observer:
          anyOf:
            - type: string
              description: The individual person making the observation recorded in this observation element.
            - type: 'null'
        type:
          anyOf:
            - $ref: '#/components/schemas/CredentialTypeEnum'
            - type: 'null'
        observedCredentialId:
          anyOf:
            - type: string
              description: Specific identifier to the referenced observed credential.
            - type: 'null'
        observationStartTime:
          anyOf:
            - type: string
              format: date-time
              description: The initial date and time of the observation.
            - type: 'null'
        observationEndTime:
          anyOf:
            - type: string
              format: date-time
              description: The ending date and time of the observation, when it was continous since `observationStartTime`.
            - type: 'null'
        description:
          type:
            - array
            - 'null'
          minItems: 1
          items:
            type: object
        creationDateTime:
          anyOf:
            - type: string
              format: date-time
              description: The date and time stamp for the creation of the observation element.
            - type: 'null'
        location:
          type:
            - object
            - 'null'
        images:
          type:
            - array
            - 'null'
          items:
            type: object
        elementIds:
          type:
            - object
            - 'null'
        vehicleAncillaryIdentification:
          type:
            - object
            - 'null'
        observerOrganisation:
          type:
            - object
            - 'null'
        confidence:
          type:
            - object
            - 'null'
        characterConfidence:
          type:
            - object
            - 'null'
        extensions:
          anyOf:
            - $ref: '#/components/schemas/Extensions'
            - type: 'null'
      additionalProperties: false
tags:
  - name: Discovery
    description: |-
      **Where every integration starts.** A partner needs exactly one thing
      to begin: a hostname.

      `GET /.well-known/apx-configuration` is unauthenticated and served at
      the host root. It answers where to get a token, which optional
      conformance classes this server implements, and where its code-list
      registries are published. `GET /v1/discovery` then answers the
      narrower and more useful question: what can *this credential* do? The
      document it returns is the intersection of the server's classes with
      the caller's scopes and place grants.

      Discovery is **contractual, not advertising**: everything the document
      lists will work for the caller, and anything it omits will refuse with
      a clean 403. That is what makes onboarding a new vendor a matter of
      issuing a credential rather than exchanging PDFs.

      Written standard:
      [Part 16](https://github.com/rneubauer/apx/blob/main/docs/standard/16-discovery.md).
  - name: Data
    description: |-
      **Reading and writing parking data, and staying in sync.**

      The data routes themselves are APDS 4.1's own, mounted verbatim:
      `/places`, `/sessions`, `/rates`, `/rights/specs`, `/rights/assigned`,
      `/observations`, `/contacts`, `/quotes`. APX invents nothing here on
      purpose, because data exchange is the part the industry already
      agreed on.

      What APX adds is a **profile** over those routes, all of it additive
      and invisible to a client that ignores it: full versus change update
      semantics, tombstones for deletions, and a cursor-based change feed
      that is ordered, gapless, and exactly-once, so a partner that goes
      offline for an hour replays precisely what it missed. Partial writes
      make `null` mean *clear this field* and omission mean *leave it
      alone*, which retires the oldest bug in data integration.

      The one net-new read here is the occupancy snapshot: how full a
      garage, level, or zone is right now, without walking the whole Place
      hierarchy.

      Two decorations on the APDS Session carry what other systems
      decided about a stay: the pairing of reads behind it
      (`session-detail`), and the compliance outcome an engine scored for
      it (`stay-compliance`), which is served only under its own scope.

      Written standard:
      [Part 5](https://github.com/rneubauer/apx/blob/main/docs/standard/05-data.md).
  - name: Subscription
    description: |-
      **Push instead of poll.** A superset-compatible profile of the APDS
      4.1 `/webhooks` endpoint: stock APDS subscription bodies work here
      unmodified.

      Webhooks without rules are where integrations go to die, so the
      delivery contract is normative rather than best-effort. Every delivery
      is one uniform envelope, HMAC-signed so the receiver can prove it is
      genuine, carrying a stable event id so duplicates are detectable.
      Failed deliveries follow a published retry schedule before the
      subscription is marked failed, which itself raises an alert. The
      delivery ledger records every attempt and its result.

      Subscriptions filter by place and by severity, so a partner receives
      only its own world, and an event whose place cannot be resolved is
      dropped rather than leaked. Server-sent events carry the same
      envelopes for consumers that cannot host a public endpoint.

      Written standard:
      [Part 8](https://github.com/rneubauer/apx/blob/main/docs/standard/08-events.md).
  - name: Alerts
    description: |-
      **Knowing something is wrong.** A net-new domain: APDS has no alert,
      event, or notification class.

      One `Alert` resource covers the operational conditions an attendant or
      a monitoring system acts on: a device fault, a blocked lane, a vehicle
      in a space it should not be, an occupancy threshold crossed, a payment
      exception. Alert *types* are an open vocabulary, seeded from the APDS
      use-case exception list and extensible by any implementer through
      their own code list. Severity, by contrast, is a closed five-level
      scale, because filtering on it has to mean the same thing everywhere.

      The lifecycle is raised, acknowledged, resolved, with an immutable
      audit of every transition.

      Written standard:
      [Part 7](https://github.com/rneubauer/apx/blob/main/docs/standard/07-alerts.md).
  - name: Control
    description: |-
      **Doing things in the real world.** APDS inventories devices and marks
      access-controlled places but defines no actuation. This is it.

      Everything physical goes through one audited command plane rather than
      scattered verbs: vend a gate, hold it open, close a lane, issue a lost
      ticket, push a rate table, apply a validation, set a device state,
      display a message, restart a device. Commands are **idempotent** (a
      retry must not vend the gate twice), **perishable** (a vend requested
      ten minutes ago must not fire now), and audited end to end.

      Two optional features close open tickets at the exit lane without
      touching the deck. **Negotiated rates:** a RateTable flagged
      `negotiable` (the `apds-ext:apx:ratepolicy@1.0` decoration, which
      rides with the table on every `/rates` sync) may be pushed to the
      one car in the lane, and the command names the agent who chose it.
      **Ticket matching:** when no ticket is in the machine the lane
      inquiry offers the open sessions that plausibly belong to the
      vehicle — by plate read, credential, account phone, or reservation
      — and `matchTicket` binds the exit to the real entry, priced from
      the real entry time, with the agent on the record. The lost-ticket
      fee becomes the fallback, not the default.

      The response is deliberately not a success boolean. It is a command
      resource whose `confirmationLevel` distinguishes *accepted* from *the
      device acknowledged it* from *the outcome was physically verified*. A
      consumer, an AI agent especially, must not claim a stronger outcome
      than that level supports.

      Also here: the lane inquiry that populates a call-center screen-pop,
      the validation-provider list for a place, and live device status.

      Written standard:
      [Part 6](https://github.com/rneubauer/apx/blob/main/docs/standard/06-control.md).
  - name: Accounts
    description: |-
      **Money.** Account and balance lookup, taking a payment, refunds,
      voids and captures, accounting write-back, and payment history.

      APDS models a `Payment` but not the *act* of taking one. The APX
      `PaymentRecord` is that action record: addressable, idempotent, and
      reconcilable, and every approved one is materialized as an APDS
      Payment so downstream APDS consumers see it without speaking APX.

      Two rules shape this domain. Full card numbers never appear anywhere.
      And because one endpoint often fronts many facilities, every payment
      names the place it belongs to, so revenue stays attributable and a
      grant cannot leak across sites.

      APDS publishes no payment events, which leaves financial analytics
      blind; APX closes that with a payment-recorded topic.

      Written standard:
      [Part 13](https://github.com/rneubauer/apx/blob/main/docs/standard/13-accounts-payments-lpr.md).
  - name: LPR
    description: |-
      **Plates.** A camera read *is* an APDS `Observation`, so ingest is the
      standard data route every integration already uses. No bespoke
      ingestion API.

      The genuinely new need is the **join**: which ticket goes with this
      plate, and which plate with this ticket. That is the one endpoint this
      domain adds, answering with the session, the confidence score, and an
      access-controlled image link.

      Modern engines know more than a plate string, so a read may also carry
      per-attribute confidence for plate, state, make, model, colour and
      class, the runner-up plate strings the engine rejected, how many
      frames and plates it read, which face of the vehicle it saw, and
      whether the vehicle was moving toward the camera, away from it, or
      stopped. The LPR system then says what the read *was*: an **entry**
      or an **exit**. APX derives nothing — each lane's cameras, and which
      way each faces, are described on the lane, and a Session is simply
      the entry and exit reads of one visit.

      Written standard:
      [Part 13](https://github.com/rneubauer/apx/blob/main/docs/standard/13-accounts-payments-lpr.md).
  - name: Reservations
    description: |-
      **Booking ahead**, expressed as conventions over native APDS routes
      rather than a parallel booking system.

      Quote through the APDS quote route, book by creating an
      `AssignedRight` carrying the APX reservation extension, amend and
      cancel through the same surface, and check in by linking the arrival
      to the right. The reservation is therefore a first-class APDS object
      any APDS consumer can read, not an APX-only record that has to be
      synchronized.

      The hard parts this domain pins down are the ones integrations usually
      get wrong: how a prepaid booking binds to the session the vehicle
      actually starts, what happens when the plate is misread, and when a
      no-show is declared.

      Written standard:
      [Part 14](https://github.com/rneubauer/apx/blob/main/docs/standard/14-reservations-permits.md).
  - name: Permits
    description: |-
      **Pooled permits**: issuing from a finite allocation, over the APDS
      right-specification and right-pool model.

      The cases that matter are the ones a naive implementation breaks on: a
      pool that runs out, a household or company credential valid for
      several vehicles, and issuance that must stay attributable when
      allocations are audited later.

      Written standard:
      [Part 14](https://github.com/rneubauer/apx/blob/main/docs/standard/14-reservations-permits.md).
  - name: Tolling
    description: |-
      **Toll transactions**, a net-new domain: APDS has no toll entity.

      Everything is still built to APDS conventions. A toll point is
      equipment in the place hierarchy, the reads are native `Observation`s,
      money is the APDS amount shape, and settlement links a Payment
      reference. A transaction runs created, priced, paid, and a dispute can
      move any non-voided transaction aside for resolution.

      Creation is idempotent, because gantries retry in storms.

      Written standard:
      [Part 15](https://github.com/rneubauer/apx/blob/main/docs/standard/15-tolling.md).
  - name: Resolution
    description: |-
      **When a customer presses the intercom.** The agent, human or AI,
      should not have to log into another system, find the facility, find
      the lane, find the transaction, and reconstruct what happened.

      One call assembles the context from whatever identifiers the caller
      has: a phone number, a lane, a plate, a ticket, a credential, a
      reservation code. The server resolves every relationship it can and
      does not fail because some identifiers are missing.

      The important design decision is that **the server, not the agent,
      decides what may be done**. The context returns the allowed actions,
      already evaluated against policy, including which ones require
      supervisor approval. Writes then go through the existing command plane
      rather than a second one. A refund an agent should not offer is simply
      not in the list.

      Written standard:
      [Part 17](https://github.com/rneubauer/apx/blob/main/docs/standard/17-resolution.md).
  - name: Support
    description: |-
      **What happened on the last call.** Support-interaction history for a
      resolution context: who spoke to the customer, through which channel,
      about what, and what was done.

      It exists so the second call is not the first call again, and so an
      action taken during an interaction can be traced back to the
      conversation that prompted it.

      Written standard:
      [Part 17](https://github.com/rneubauer/apx/blob/main/docs/standard/17-resolution.md).
  - name: Violations
    description: |-
      **Enforcement, from camera to citation to appeal.** A net-new domain,
      and the one with the most legal exposure.

      One `Violation` resource covers tickets, notices, and citations alike,
      through detection (automated, guided, or manual), review, issuance,
      settlement by Payment reference, appeal, and void. Guided enforcement
      is supported by an eligibility check a handheld calls before an
      officer writes anything, composed from the rights and sessions that
      remain authoritative.

      What makes this domain unusual is that **the law at the location is
      data**. A per-place enforcement policy records which notice methods
      are lawful, the penalty cap, and the escalation schedule, and the
      server enforces it: an issuance by a method the jurisdiction does not
      permit, past the notice deadline, above the cap, or at a place whose
      required signage was not posted, is refused. The posted signage itself
      is on file, with its text and photograph, as it stood at the moment of
      the finding.

      Written standard:
      [Part 19](https://github.com/rneubauer/apx/blob/main/docs/standard/19-violations.md).
  - name: Validations
    description: |-
      **The merchant side**, from enrolment to invoice.

      The lane-side act of applying a validation is a command in the control
      plane. This domain is everything around it: enrolling a merchant at a
      place with a benefit and its rules, issuing instrument stock (codes,
      QR, stamps), the redemption ledger every channel writes to, and
      closable billing statements.

      The ledger is the point. A validation applied at a pay station, by an
      agent console, or through a merchant's own app lands in one place, so
      the month-end statement is a query rather than a reconciliation.
      Closed statements are immutable, and a reversal after closing appears
      as a credit on the next one.

      A merchant-confined scope lets a venue check codes, issue its own
      stock, and read its own statements without seeing anyone else's.

      Written standard:
      [Part 20](https://github.com/rneubauer/apx/blob/main/docs/standard/20-validations.md).
  - name: Credentials
    description: |-
      **The card, the fob, the tag, the phone.** The lifecycle of anything
      presented at a lane: issue, activate, suspend, resume, report lost,
      revoke, replace, plus access-event history.

      The rule that makes this domain worth having is **materialization**:
      an active credential record MUST appear on the holder's APDS assigned
      right, and MUST be removed when it is suspended, lost, revoked, or
      expired. A lane that speaks only APDS therefore refuses the lost card
      at six o'clock because the office replaced it at noon. There is no
      second list to keep in sync.

      APDS has no access events, so granted and denied presentations with
      their reasons are recorded here and published as a topic.

      Written standard:
      [Part 21](https://github.com/rneubauer/apx/blob/main/docs/standard/21-credentials.md).
  - name: Valet
    description: |-
      **Custody.** A net-new domain: APDS has no valet entity, only a
      restriction flag.

      The stay and the money remain the APDS session. What APDS has no words
      for is who has the keys, where the car is, when it was asked for, who
      it was handed to, and what condition it was in. A ticket records
      drop-off with a condition report (notes, per-panel damage entries,
      walk-around photographs, and the customer's acknowledgement), the
      parked position and key location, the retrieval request and its ETA,
      staging, and a verified handback.

      Retrieval works from a text, an app, a web page, a voice bot, a kiosk,
      or the stand, through one customer-facing scope confined to the
      caller's own ticket and minimized so it exposes status and ETA but
      never where the car or the keys are.

      The acknowledged drop-off report is what answers "that scratch wasn't
      there" a week later.

      Written standard:
      [Part 22](https://github.com/rneubauer/apx/blob/main/docs/standard/22-valet.md).
  - name: UI launch
    description: |-
      **The vendor's own screen, without breaking the record.** Most
      actions in a call centre still happen in a vendor's portal in
      another window, and the two systems never agree afterwards. A
      vendor will take years to implement every APX module, but it
      already has good screens.

      A host opens one of those screens for an agent in two ways. In the
      **handshake**, it posts a launch with its normal APX token and gets
      back a single-use URL that logs the agent in, valid for sixty
      seconds, which also serves vendors who want header-based
      authentication, since a browser cannot add headers to a page it
      opens. In the **signed-token** mode, the host signs a short-lived
      token and sends it to the vendor's launch address by form post or
      URL fragment.

      The rule that makes this worth having is the **loopback**: whatever
      the agent does in the screen MUST come back as the module's own
      resource or Command, carrying the launch's correlation id. Only when
      the implementation has no APX operation for the action does it
      record a `UiActionRecord` instead, with the fields the host asked
      for. Defined once; every module adds screens through the
      `apx-ui-surfaces` registry.

      Written standard:
      [Part 25](https://github.com/rneubauer/apx/blob/main/docs/standard/25-ui-launch.md).
  - name: Site configuration
    description: |-
      **A location, described by APX alone.** Before a call, an agent or
      a system should be able to learn what a site has without data from
      any other system: which hardware is on each lane and what each
      piece does, what it is, what runs on it, where the cameras are and
      what they see, how a parker reaches help from each lane or door,
      and who to escalate to.

      APDS already models the place, its lanes and its equipment. This
      domain adds what APDS leaves open: a fixed list of **equipment
      roles** (gate, exit verifier, access door, camera, intercom…), the
      make, model, firmware, serial and MAC of every unit, where it is by
      **area** and level, what it is built into and what it controls; a
      **camera** description for any camera on the site, with views
      issued as short-lived links so a password never leaves the site; a
      **comms point** for every way help is reached, whether an intercom,
      an analog dialer, a posted number or a QR code; typed **external
      ids** so other systems' identifiers resolve to APX records;
      **display records**, the proof that a sign showed a message for a
      read or a stay, written by whichever system drove the sign; and
      change topics so a copy of the setup stays current. IP addresses
      and SIP details are deliberately left out.

      Written standard:
      [Part 26](https://github.com/rneubauer/apx/blob/main/docs/standard/26-site-configuration.md).
x-tagGroups:
  - name: Start here
    tags:
      - Discovery
  - name: Platform
    tags:
      - Data
      - Subscription
      - Control
      - Alerts
      - Site configuration
      - UI launch
  - name: Commerce
    tags:
      - Accounts
      - Reservations
      - Permits
      - Validations
      - Tolling
  - name: Vehicles and access
    tags:
      - LPR
      - Credentials
      - Valet
      - Charging
  - name: Enforcement and service
    tags:
      - Violations
      - Plate lists
      - Resolution
      - Support
