{
  "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\n[APDS 4.1 API](https://github.com/parkingdata/spec) (Alliance for Parking\nData Standards, core model published as ISO/TS 5206-1).\n\n## The prime directive\n\nWherever APDS 4.1 already defines a route, schema, or convention, APX uses\nit **verbatim**, by `$ref` into the vendored, unmodified `apds-api-4.1.yaml`.\nAPX never redefines, subsets, or re-shapes an APDS entity, and a plain\nAPDS 4.1 client works against an APX implementation without modification.\nEverything here is what APDS deliberately leaves out.\n\n## Five ideas, used everywhere\n\n| Concept | Plain meaning |\n|---|---|\n| **Place** | Anywhere a vehicle can park, broken into levels, lanes, and spaces |\n| **Right** | Permission to park. A *specification* is the product; an *assigned right* is that product granted to someone |\n| **Session** | An actual stay: a vehicle using a right, with a start and an end |\n| **Rate** | Pricing: hourly tables, flat fees, event rates |\n| **Observation** | Something a sensor saw, with a timestamp, a confidence score, and imagery |\n\nSupporting players: an **Organisation** or **Contact**, a **Credential**\n(the thing presented at the lane), and a **Device** (gate, pay station,\ncamera). All of them are APDS classes; none is redefined here.\n\n## Conventions\n\n- Every APX resource carries an `id` (UUID) and an integer `version`.\n  Objects reference each other as `{\"id\": \"…\", \"className\": \"Session\"}`.\n- Timestamps are RFC 3339 UTC. Money is the APDS shape\n  `{\"currencyType\": \"USD\", \"currencyValue\": 9.00}`.\n- Errors are RFC 9457 `application/problem+json` with a registered\n  `type` URI you can program against, never a bare string.\n- Mutating operations a device may retry require an `Idempotency-Key`.\n  Replaying a key with the same body returns the resource as it stands\n  now (Part 4 §4.2a), never a second copy; with a\n  different body it is a conflict.\n- Lifecycles are audited: resources with states carry an immutable,\n  append-only `statusHistory[]`.\n\n## Access\n\nOAuth 2.0 client credentials. Two independent bounds apply to every call:\n**scopes** (`apx.<domain>:<verb>`, what kinds of thing you may do) and\n**grants** (the token claims `apx_org` and `apx_places`, which facilities\nyou may do them at). Grants are fail-closed: absent or empty means no\nplaces. A vendor hired for one garage cannot act on another.\n\n## Not everything is mandatory\n\nAPX is partitioned into named **conformance classes**. `apx-data` and\n`apx-events` are the base; every other class is optional and\nindependently claimable, with objective per-requirement criteria in\nAnnex A of the written standard. An implementation advertises the classes\nit satisfies at `/.well-known/apx-configuration`.\n\n## How to read this document\n\nOperations are grouped by domain in the navigation, and each group opens\nwith what APDS already provides, what APX adds on top, and a link to the\ngoverning Part of the **written standard** in\n[docs/standard/](https://github.com/rneubauer/apx/tree/main/docs/standard).\nWhere prose and this description disagree for an APX-defined path, this\ndocument prevails and the prose is a defect to be corrected; for\nAPDS-native paths the vendored APDS document prevails.\n\nEnd-to-end worked examples, every payload machine-validated against this\nbundle, are in\n[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\npaths (/places, /sessions, /webhooks, …) and APX routes under the\nexplicit /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 :\n* __latitude__, __longitude__ and __radius__ : retrieve all places within a geographic area,\n* __types__ : retrieve all places of the given type,\n* __right_type__ : retrieve all places associated with the right specification type,\n* __structure_type__ : retrieve all places associated with the specified structure type,\n* __structure_grade__ : retrieve all places associated with the specified structure grade,\n* __name__ : retrieve all places which match the name of the facilities,\n* __layer__ : specify the maximum hierarchy element layer desired,\n* __operator__ : the id of the operator of this location\n* __modified_since__ : retrieve all places that have changed from that given instant onwards,\n* __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:\n\n* latitude, longitude, radius: to check for `Observations` within a geographic area\n* a list of `Places`, to retrieve all Observations within a set of parking locations\n* start_before: to get observations starting before a given instant\n* end_before: to get observations ending before a given instant\n* start_after: to get observations starting after a given instant\n* end_after: to get observations ending after a given instant\n* a modification instant: to only display changed resources from that point onwards\n\nAdditionally, 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 :\n* __latitude__, __longitude__ and __radius__ : retrieve all right specifications used in a geographic area (via their associated place),\n* a list of __Places__ : retrieve all right specifications connected to any of the given places,\n* __issuer__ : the id of the entity that issued the right specification\n* __modified_since__ : retrieve all right specifications that have changed from that given instant onwards, \n* __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 : \n* __latitude__, __longitude__ and __radius__ : retrieve all rates used in a geographic area (via their associated assigned rights and place), \n* a list of __places__ : retrieve all rates connected to assigned rights that belong to any of the given places, \n* a list of __right specifications__ : retrieve all rates connected to any of the given right specifications, \n* __issuer__ : the id of the rate responsible party (i.e. the issuer of the rate table)\n* __modified_since__ : retrieve all rates that have changed from that given instant onwards, \n* __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 : \n* __latitude__, __longitude__ and __radius__ : retrieve all sessions occurring in a geographic area (via their associated place), \n* a list of __Places__ : retrieve all sessions connected to any of the given places, \n* a list of __RightSpecifications__ : retrieve all sessions with segments using any of the given right specifications, \n* a list of __Credentials__ : retrieve all sessions linked to the given credentials, \n* __start_before__ : retrieve all sessions starting before that given instant, \n* __end_before__ : retrieve all sessions ending before that given instant, \n* __start_after__ : retrieve all sessions starting after that given instant, \n* __end_after__ : retrieve all sessions ending after that given instant, \n* __modified_since__ : retrieve all sessions that have changed from that given instant onwards, \n* __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 :\n* __latitude__, __longitude__ and __radius__ : retrieve all assigned rights occurring in a geographic area (via their associated place)\n* a list of __places__ : retrieve all assigned rights connected to any of the given places,\n* a list of __right specifications__ : retrieve all assigned rights with segments using any of the given right specifications, \n* a list of __credentials__ : retrieve all assigned rights linked to the given credentials,\n* __start_before__ : retrieve all assigned rights starting before that given instant, \n* __end_before__ : retrieve all assigned rights ending before that given instant, \n* __start_after__ : retrieve all assigned rights starting after that given instant, \n* __end_after__ : retrieve all assigned rights ending after that given instant, \n* __modified_since__ : retrieve all assigned rights that have changed from that given instant onwards, \n* __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\nthe Place hierarchy. A pure convenience READ over the APDS occupancy\nmodel (Supply + DemandTable) — the Place payload remains the source\nof truth. Fields the implementation does not know are simply absent.\nThreshold crossings publish apx.data.occupancy.v1 and SHOULD raise\nan occupancyThresholdExceeded alert (Part 7). Scope apx.data:read;\nthe 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`\n(`{endpoint, topics[]}` with EventTypeEnum values) is a valid body;\nAPX fields (transport, filters, secret) are additive.\n\n**Response negotiation (normative, Part 8 §8.1):** the stock APDS\n4.1 response contract is preserved — a request WITHOUT\n`Prefer: return=representation` receives the native APDS `200`/`202`\nwith `ResponseStatus`, exactly as APDS documents. An APX client\nsends `Prefer: return=representation` and receives `201` with the\nfull subscription INCLUDING the signing secret (returned exactly\nonce, in that response only; webhook transport only).\n\nRefusals at creation (Part 8 §8.1): a topic the credential could\nnot read synchronously is 403 `insufficient-scope` (Part 9 §9.6(4));\na `filters.places` entry outside the token's `apx_places` grant is\n403 `insufficient-grant`. Send `Idempotency-Key` to make a retried\ncreate safe.",
        "parameters": [
          {
            "name": "Prefer",
            "in": "header",
            "required": false,
            "description": "RFC 7240. `return=representation` selects the APX-rich 201\nresponse (subscription + one-time secret). Absent, the server\nanswers 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\n(request did not ask for the APX representation). `ids[]`\ncarries the new subscription's id as its single entry, so a\nstock 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\ncreated; includes the signing secret, exactly once.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApxEventSubscription"
                }
              }
            }
          },
          "202": {
            "description": "Stock APDS contract — subscription request received; will be\nprocessed and then approved/declined. `ids[]` carries the new\nsubscription'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\nschema or a field rule (`invalid-request`, with `errors[]`): a\nwebhook-transport subscription without `endpoint`, an empty\n`topics[]`, a secret under 32 bytes of entropy, or an\n`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\n(`idempotency-conflict`). A replay with the same body returns\nthe subscription as it now stands (Part 4 §4.2a) — never the\nsecret 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,\n`activeKeyIds`, and filters — without paging through `GET\n/webhooks`. Secrets are never returned. Readable in every state,\nincluding `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\nor failed subscription), or rotate the secret. The body is a JSON\nMerge Patch over the subscription: send only what changes\n(Part 8 §8.1). The precondition is `If-Match` or the body\n`version`; a stale one is 409 `version-conflict` (Part 4 §4.2a).\nWhile the subscription is `failed`, the only PATCH accepted is one\nthat sets `status: active`; any other is 410\n`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\n`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,\nsubscription), with the attempt count, status, last HTTP code, and\nthe per-attempt history (`attemptHistory`: each attempt's\n`APX-Delivery-Id`, time, and code — Part 8 §8.3). Newest first.\nReadable in every subscription state. An event held while the\nsubscription 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`.\nFrame grammar (normative, Part 8 §8.4): one event per frame, an\n`id:` line carrying the per-subscription sequence (a decimal\ninteger), a single `data:` line carrying the envelope JSON, and a\nblank line; `retry:` and comment lines MAY appear. Reconnect with\n`Last-Event-ID` to resume strictly after that sequence.\n\nChecks run in this order: the subscription exists and is visible\n(else 404), its transport is `sse` (else 404 `target-not-found` —\nthere is no stream for it), it is not `failed` (else 410\n`subscription-failed`), and `Last-Event-ID` is still buffered (else\n410 `stream-position-expired`; re-sync through the Part 5 change\nfeed, 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\n(`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\n`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\n(`subscription-failed`), or `Last-Event-ID` is older than the\nserver'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,\napplyValidation, …). Idempotency-Key REQUIRED. Returns 202 with the\nCommand; poll GET /v1/commands/{id} or subscribe to\napx.control.command.status.v1. Requires scope apx.control:execute\nAND 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\nit currently stands, not a snapshot of the first response (Part 4\n§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\n`commandType`, a missing `target`, or a parameter that fails its\n§6.1 definition (`invalid-request`, with `errors[]`); or a command\nthat 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\nresolution context evaluated the action as not allowed\n(`action-not-allowed`), or approval evidence is missing\n(`approval-required`) — Part 17 §17.3.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency-Key replayed with a different body\n(`idempotency-conflict`), or `pushNegotiatedRate` / `matchTicket`\nat a lane with no transaction in progress\n(`lane-no-current-transaction`) — Part 12.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Refused synchronously, nothing dispatched: command expired before\ndispatch (`command-expired`); unknown validation provider\n(`validation-provider-unknown`); `lostTicket` at a place whose\napplicable rate deck has no `lostTicketFee` line\n(`lost-ticket-fee-undefined`, Part 6 §6.1); a RateTable not\nflagged negotiable (`rate-not-negotiable`); a session that is not\nopen (`session-not-open`); or a parameter Reference that names\nnothing (`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\ncommand was received, each with its full `statusHistory` (Part 6\n§6.1b). Only commands whose target lies inside the token's\n`apx_places` grant are returned; naming a `place` outside the grant\nis 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\nsee, optionally narrowed by place and state (Part 6 §6.4). Naming a\n`place` outside the token's `apx_places` grant is 403\n`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\ndue, applied validations, latest LPR read, and monthly-credential\ncontext including the last 10 activity events. When no ticket is in\nthe machine — or when a lookup parameter is given — also\n`matchCandidates[]`: the open sessions at the place that plausibly\nbelong to the vehicle in the lane (Part 6 §6.7), for a driver who\nhas 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\nREQUIRED. Created `priced` when `pricing` is given, otherwise\n`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\nthe key created, in its current representation (`version` and\n`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\nthat fails the schema, e.g. no `tollPoint` (`invalid-request`,\nPart 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\nwindow; all filters combine with AND (Part 15 §15.2). Results are\nconstrained 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\n`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\noutside 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\n`resolved` with resolution `upheld` or `adjusted` on an unpaid\ntransaction; anything else is 409 `toll-transition-illegal` (Part 15\n§15.1). Re-attaching the payment already attached returns 200\nunchanged, so a replayed billing batch is harmless.\nIdempotency-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`,\n`disputed`, `voided`, `resolved` as `refunded` or already paid,\nor `paid` with a different payment — `toll-transition-illegal`),\nor Idempotency-Key replayed with a different body\n(`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\n`created` transaction and moves it to `priced` (Part 15 §15.1).\nFrom any other state 409 `toll-transition-illegal`; a later price\nchange 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\nreplayed 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\nexempt service vehicle, a misread). Allowed from `created` and\n`priced` only; a paid charge is corrected by a dispute resolved\n`refunded`, so `paid`, `disputed`, `resolved`, and `voided` are 409\n`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\nIdempotency-Key replayed with a different body\n(`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\ninitiative (Part 15 §15.1). Allowed from `priced` and `paid`.\nRe-disputing a `resolved` transaction is 409 `dispute-closed`; a\n`created`, `voided`, or already `disputed` transaction is 409\n`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\ntransaction's state does not allow a dispute\n(`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 |\nrefunded | adjusted | withdrawn (Part 15 §15.1); `adjusted` carries\n`adjustedPricing`, which replaces `pricing` (the old amount moves to\n`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\n(`dispute-closed`), or the transaction was never disputed\n(`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\npipeline, a guided-enforcement handheld, or an officer directly\n(`detection.mode`). The `Idempotency-Key` header is REQUIRED:\ncameras and handhelds retry, and a retry must not create a second\nviolation. Same key + same body returns the violation's current\nrepresentation (200, Part 4 §4.2a); same key + different body is\n409 idempotency-conflict. The server\nperforms the eligibility check at creation and records it in\n`eligibilityCheck`; a vehicle found entitled is still recorded (as\n`dismissed`, with the basis) so the audit trail is complete.\nPublishes `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\nthat fails the schema or a §19.9 field rule — e.g. no\n`detection`, or a position whose first element is outside\n−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\nReference names nothing visible to the caller, or\n`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,\ntype, place (subtree-inclusive), detection mode, the\n`since`..`until` window on detectedTime, and — for violations\nimported from another enforcement system (Part 19 §19.13) — the\nsource system and the source's record id. Results are constrained\nto the caller's place grant; a lookup that names no place (by\nplate or notice number) returns only violations at granted places\n(Part 9 §9.3a). Plate values appear only under `apx.violations:*`\nscopes (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\nofficer's decision is recorded with reason and reviewer; a\n`violationType` in the body corrects the detector's classification.\n`dismiss` without `reason` is 400 `invalid-request`. Any other\nstarting 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\n`automated` detections where the policy in force permits\nunreviewed issuance (`EnforcementPolicy.unreviewedIssuance`, or\nthe operator's published documentation where the policy is\nsilent); a `guided` or `manual` detection still in `detected`, or\nan automated one the policy does not permit, is 409\n`violation-not-issuable`. Whatever the detection mode, `issue` is\nalso 409 `violation-not-issuable` while any LPR read in\n`observations[]` has plate review `pending` or `rejected` (Part 13\n§13.3a(4a), Part 19 §19.4 rule 6), and when the `relatedSession`\nlink rests on match evidence with `plate.method: lenient` or\n`applied: false` (Part 5 §5.8, Part 19 §19.4 rule 5). Sets\n`notice`, `amount`, and `dueTime`.\n\nThe server resolves the EnforcementPolicy in force at `place`\n(Part 19 §19.10) and refuses with 422 when the request breaks it:\n`delivery-method-not-permitted`, `notice-deadline-passed`,\n`penalty-exceeds-cap` (or clamps, per the policy), or\n`signage-required`. On success `policy`, `signage[]`,\n`unpaidAmount`, `capAmount`, and the first `amountHistory` entry\n(`reason: issued`, or `reason: cap` with `requestedAmount` when\nclamped) are frozen onto the violation. Publishes\n`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\nevidence read's plate review is `pending` or `rejected`, or on\nlenient or unapplied match evidence (`violation-not-issuable`,\nPart 19 §19.4); or an illegal transition\n(`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\nPart 13 surface (`POST /v1/payments`, a payment link, or an APDS\nPayment ingested from a pay station); this attaches its reference.\nNot in `issued` is 409 `violation-transition-illegal`. A body\n`amount` below what is outstanding is a partial payment (Part 19\n§19.6a): it is appended to `payments[]`, `amountPaid` grows, and\nthe violation stays `issued`; it moves to `paid` when `amountPaid`\nreaches `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\npolicy's `appealWindowDays` (pay-then-appeal, Part 19 §19.6); the\nstate it came from is recorded as `appeal.openedFrom`. One appeal\nper violation: a second appeal, an appeal on a closed or voided\nviolation, or one outside the appeal window is 409\n`appeal-closed`. From a state that was never issued (`detected`,\n`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\npay-then-appeal); `reduced` → the same, with `amount` replaced by\n`adjustedAmount` (400 `invalid-request` when it is absent);\n`dismissed` → `closed`. A pay-then-appeal resolved `reduced` or\n`dismissed` carries the Part 13 `refund` reference. No open\nappeal, 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`,\n`issued`, `appealed`, `paid`); the record and its statusHistory\nremain readable. Voiding a `paid` violation SHOULD carry the Part\n13 `refund` reference. From a terminal state (`dismissed`,\n`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\nwhether a credential is covered at a place at an instant, and by\nwhat — composing the APDS AssignedRights (APDS's own enforcement\nsource of truth), Sessions, and the reservation/permit profiles the\nserver holds. A convenience READ in the spirit of lane inquiry and\nthe occupancy snapshot: the AssignedRight remains authoritative and\na client MAY derive the same answer from the native routes. Lives\nunder `/v1/enforcement` (not `/v1/violations/…`) because no\nviolation 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`\nREQUIRED. The policy applies to the element and its subtree from\n`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\ncaller; or `request-unprocessable` — an inconsistent policy,\ne.g. `effectiveTo` before `effectiveFrom`, or an escalation step\nwhose fixed `addAmount` alone exceeds\n`overallCeiling.maximumAmount`. (Steps that only might reach\nthe 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\nwhose effective window covers `at` (default now). This is exactly\nwhat the server applies at `issue` and for escalation, so\nhandhelds, 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\nread, sent as `If-Match: \"<version>\"` or as the body's `version`\n(Part 4 §4.2a); a stale one is 409 `version-conflict` and nothing\nis written. Changes apply to issuance and escalation from the\nupdate onward; violations already issued keep the `policy`\nversion 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.\n`Idempotency-Key` REQUIRED. To change the wording later, create a\nnew record (or new version) with the new `effectiveFrom` and set\nthe 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\neffective window covers `at` (default now) — what the server\nfreezes 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\nread, sent as `If-Match: \"<version>\"` or as the body's `version`\n(Part 4 §4.2a); a stale one is 409 `version-conflict`. Changing\n`text` on a record that any issued violation references is\nrefused (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`\nREQUIRED. The program becomes a row in the Part 6 provider lookup\nfor that place while `active`. Publishes\n`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\n`applicableRateTables` entry names nothing visible to the\ncaller; or `request-unprocessable` — a benefit carrying none or\nmore 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\n`apx.validations:redeem` token sees only programs whose provider is\nits 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\nstatusHistory. A `redeem` token reading another provider's program\nreceives 404, exactly as for a program that does not exist (Part 9\n§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\nprogram. The precondition is the `version` last read, sent as\n`If-Match: \"<version>\"` or as the body's `version` (Part 4 §4.2a);\na stale one is 409 `version-conflict`. Status transitions:\n`active ⇄ suspended`, either → `ended` (terminal; 422\n`program-not-active` for any transition out of `ended`). Benefit\nand rule changes apply to redemptions from the update onward;\nexisting 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`;\n`request-unprocessable` — a benefit carrying none or more than\none of amount/duration/percentage; `reference-unknown` — a body\nReference 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\nnames; the body need not repeat `program` (a value that differs\nfrom the path is 422 `request-unprocessable`). `Idempotency-Key`\nREQUIRED — a retried print job must not double the stock. For\n`code`/`qrCode`/`digital`, the generated `codes[]` are returned in\nTHIS response only. Program must be `active` (422\n`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`;\n`request-unprocessable` — `method` is not in the program's\n`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\napplying. Returns status, program, validity window, and the\nbenefit. A code the caller's grant cannot see is 404, never 403\n(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\nit that is `valid` or `expired` → `void` (Part 20 §20.2 rule 5) —\nthe stolen sheet of QR codes. Instruments already `redeemed` are\nunaffected; their redemptions stand until reversed. The result's\n`voidDetail.voidedCount` says how many codes were voided. A `redeem`\ntoken may void only its own provider's batches (another\nprovider's is 404, §20.5). Voiding a batch already `void` returns\nit unchanged (200). No event is published; the instrument read is\nthe 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\n§20.2 rule 5) — a single leaked code. A `redeemed` code cannot be\nvoided (422 `instrument-invalid`; reverse the redemption first).\nVoiding a code already `void` returns it unchanged (200). As on\nthe read, a code outside the caller's grant or provider is 404,\nnever 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,\nmerchant app, or lane device — the data-plane counterpart of the\nPart 6 `applyValidation` command (which agents use to act on a\nlane; it materializes the same resource). `Idempotency-Key`\nREQUIRED. The server evaluates the program rules (Part 20 §20.3):\n422 `program-not-active`, `request-unprocessable` (the body's\n`place` is not the program's place or within its subtree),\n`instrument-invalid`, `redemption-limit-exceeded`. On success the session gains the APDS\n`Segment.validationId` and `amountReduced` reflects the ACTUAL\nreduction. 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`);\n`request-unprocessable` (place mismatch — `detail` names the\nprogram's place); `instrument-invalid` (unknown, void, expired,\nor used code, or a required instrument absent);\n`redemption-limit-exceeded` (a program rule refuses it);\n`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\napplied it, channel, status, and `since` (appliedTime). A `redeem`\ntoken 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\nstatusHistory. Another provider's redemption under a `redeem`\ntoken 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\nrestored while the session is still open (Part 20 §20.4), and the\ninstrument (if any) returns to `valid` while still within its\nwindow. Already reversed is 409 `redemption-reversed`. A\nredemption already billed on a CLOSED statement is reversed too:\nthe closed statement is never edited; `reversal.closedStatement`\nnames it, and the next statement closed for the program carries a\nnegative `credit` line (`reversal.creditedOn` is set when it\ncloses, §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\n`from`..`to` under its billing model — a preview\n(`statementStatus: preview`, no `id`), including the `credit`\nlines the period would carry. Closing the period is\n`POST …/statements`. `from` not before `to` is 400\n`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\naccounting invoices from. `Idempotency-Key` REQUIRED. Periods MUST\nNOT overlap an existing closed statement (409 `statement-overlap`).\nThe statement carries a negative `credit` line for every\nredemption reversed since an earlier statement billed it, and\nsets `reversal.creditedOn` on each (Part 20 §20.6). Publishes\n`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\nstatement 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\nby a later `activate` call or, when the body sets\n`activateOnStart: true`, by the server itself at `validity.start`\n(at once when that is absent or past), with actor `system` (Part 21\n§21.1 rule 6). `Idempotency-Key` REQUIRED.\n`credentialIdentification` MUST be unique per `credentialType`\namong non-terminal records (409 `credential-identification-in-use`,\nwhose `detail` MUST NOT identify the holding record, holder, or\nplace — §21.5). Server-assigned members in the body (`id`,\n`version`, `credentialStatus`, `suspension`, `replacedBy`,\n`statusHistory`, `recordInfo`) are ignored. Publishes\n`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\n(`reference-unknown`); or a validity window that is already over\nor inverted — `validity.end` not in the future, or before\n`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\n(subtree-inclusive). Results are constrained to the caller's place\ngrant; identification values are personal data under Part 9 §9.6.\nA lookup by `identification` that matches only records outside the\ngrant 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,\nassigned rights, places, and validity; links `replaces`/`replacedBy`;\nmoves THIS record to `replaced` and swaps the APDS CredentialAssigned\natomically. The predecessor keeps every other field it had (§21.3).\nAllowed from `active`, `suspended`, or `lost`. From `issued` it is\n409 `credential-transition-illegal` (revoke it and issue anew);\n`credential-not-replaceable` is reserved for the terminal states\n`revoked`, `expired`, `replaced`. `Idempotency-Key` REQUIRED.\nReturns 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\n`issued` (`credential-transition-illegal`), successor\nidentification in use (`credential-identification-in-use`), or\nkey 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\nor denied, where, and why. The same events are published as\n`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 —\nincluding presentations that matched no CredentialRecord\n(`denialReason: unknownCredential`, carrying `presented`). \"Every\ndenial at lane 1 tonight\" is `?lane=…&outcome=denied&since=…`.\nResults are constrained to the caller's place grant; naming a\nplace, lane, or device outside it is 403 `insufficient-grant`\n(Part 9 §9.3a). Retention per Part 9 §9.6. The same events are\npublished 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\nreport. `Idempotency-Key` REQUIRED (handhelds and scanning devices\nretry). The server SHOULD open the APDS Session for the stay and\nreference it, unless the body already references one. `storage`,\n`retrieval`, `handback`, `statusHistory`, and `recordInfo` in the\nbody are ignored — the server writes them (Part 22 §22.1 rule 5).\nA `customer.contactChannel.handle` that carries a raw phone number\nor e-mail address SHOULD be refused with 422\n`personal-data-not-permitted` rather than stored or silently\nmasked (§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\n(`reference-unknown`), or a raw phone number or e-mail address\nwhere an opaque handle is required (`personal-data-not-permitted`,\n§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,\nordered by `retrieval.promisedTime` ascending — what the runners\nand the stand see. Scheduled pickups (`requestedFor`) appear when\nthey 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\nonly its own ticket, as the minimized projection of Part 22 §22.5\n— `id`, `version`, `place`, `ticketNumber`, `vehicle`,\n`customer.displayName`, `dropOff.time`, `retrieval.{requestedTime,\nrequestedFor, channel, etaMinutes, promisedTime, stagingLane,\nstagedTime, cancelledTime}`, `handback.time`, `valetStatus`, and\n`extensions`; everything else, including `statusHistory`, is\nomitted. The same projection applies to the ticket a\n`apx.valet:request` token gets back from `retrieve` and\n`cancel-retrieval`. An operator token gets 403 `insufficient-grant` for a\nticket 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\nre-park a `staged` car the customer is not collecting yet\n(`staged → parked`: records the new `storage`, clears\n`retrieval.stagingLane`/`stagedTime`, and sets\n`retrieval.cancelledTime` and `cancelReason: re-parked`). Any\nother state is 409 `valet-transition-illegal`. Send `If-Match`\nwith the version last read so two runners cannot overwrite each\nother's `storage`: a stale value is 409 `version-conflict` (Part 4\n§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\npage, or voice bot calls this on `apx.valet:request` for its own\nticket; attendants and the call center on `apx.valet:manage`. The\nserver sets `retrieval.etaMinutes` and `promisedTime` and\npublishes `apx.valet.retrieval.requested.v1`. A repeat while\n`requested` or `retrieving` (\"CAR\" texted twice) is not an error:\n200 with the current ticket and ETA, nothing appended or\nrepublished, and the body's `requestedFor` ignored (to reschedule,\n`cancel-retrieval` then `retrieve`). From `dropped` (not yet\nparked) it is 409 `valet-vehicle-not-located`; from `staged`,\n`handedBack`, `closed`, or `cancelled` it is 409\n`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\nthe car moved). The attendant verifies the claimant\n(`verificationMethod`) — a mismatch is 403\n`valet-verification-failed` and MUST be recorded in\n`statusHistory`. Records the handback condition report. The APDS\nSession closes per the operator's flow; `closed` follows\nserver-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\n`retrieval.retrievingBy` (the body's value, else the calling\nprincipal) — what the runner board shows as \"on its way\". Optional:\n`stage` from `requested` remains valid, and a server MAY infer\n`retrieving` from its own runner assignment instead (Part 22 §22.1\nrule 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\nmoved, or the ticket was opened in error. Appends\n`statusHistory[]` and publishes `apx.valet.ticket.status.v1`; the\nserver SHOULD close the APDS Session it opened at drop-off at no\ncharge. A customer who changes their mind *after* the walk-around\nbut takes the car back is `handback` from `dropped` instead. Any\nother 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\nat P3 — without editing the drop-off report (Part 22 §22.2 rule 3).\nEach `damage[]` entry is appended to\n`dropOff.conditionReport.damage[]` stamped with a server-set\n`recordedTime` and `recordedBy` (the body's `recordedBy`, else the\ncalling principal); `imageLinks[]` are appended to the report's\n`imageLinks[]`; `notes` becomes the `detail` of a new\n`statusHistory[]` entry whose `state` is the unchanged\n`valetStatus`. The report's original `notes`, `recordedTime`,\n`recordedBy`, and `customerAcknowledged` never change, and\n`customerAcknowledged` in the body is ignored. Legal in any state\nexcept `closed` and `cancelled` (409 `valet-transition-illegal`).\nSend `Idempotency-Key` when retrying: an append retried without\none 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\nplace (subtree-inclusive), optionally filtered by `availability`\n— \"is there a free charger\". A `apx.charging:status` token\nreceives the minimized form (no `bay.vehicle`, no `bay.imageLink`,\nno `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)\nreplaces the point-level and per-connector `availability`,\n`currentSession`, `reservedFor`, and `lastCommunication`. The `bay`\nblock is NOT written here — it comes from `…/bay` and is fused by\nthe server (Part 23 §23.3); a `bay` in this body is ignored.\nPublishes `apx.charging.point.status.v1` when availability\nchanges.",
        "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\nreports the bay's physical presence: empty, vehicle plugged in,\nvehicle NOT plugged in, blocked. The server fuses it with the\ncharger's connector state (Part 23 §23.3 table) into\n`ChargingPointStatus.bay` and derives `availability: blocked` when\nno cable is connected (a connected cable wins). A vehicle not\nplugged in past the place's grace SHOULD raise the proposed\n`evBayNotCharging` alert — or the seeded `iceInEvSpace` when\n`vehicle.evCapable` is false; an obstructed bay SHOULD raise the\nproposed `evBayBlocked` alert (Part 7; Part 23 §23.3).\n`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,\nthe point and connector, the parking Session it belongs to, the\nsettlement mode, and the idle policy snapshot; the plug-in itself\narrives as a `pluggedIn` event (Part 23 §23.2). `Idempotency-Key`\nREQUIRED. 409 `charging-point-unavailable` when the point or\nconnector is inoperative, out of order, reserved for someone else,\nor already serving an active session. Publishes\n`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\nonly its own session(s), minimized (Part 23 §23.6): status, energy\nand state of charge, timeline, idle policy and idle clock, cost\ntotals, the point and connector — no plate, no credential or\ncontract id, no network identifiers. Enough for \"your car is at\n62%, charging ends in about 40 minutes; 10 minutes grace, then\n$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\ntransition for `eventType` per Part 23 §23.2 — `pluggedIn`,\n`chargingStarted`, `suspended`/`resumed`, `chargingEnded`,\n`unplugged`, `fault`, `cancelled` — or, for `meterValue`, updates\n`energy` in place. Events MUST be applied in `time` order; one that\nis illegal from the current state is 409\n`charging-transition-illegal` (a `meterValue` after `unplugged`, a\n`pluggedIn` after `charging`). `Idempotency-Key` REQUIRED. Every\nstate change appends `statusHistory` and publishes\n`apx.charging.session.status.v1`; `complete → idle` is server-side\nafter `idlePolicy.graceMinutes` and additionally publishes\n`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\nPayment reference and moves an `unplugged` session to `closed`;\nbefore `unplugged` the final cost is unknown and it is 409\n`charging-settlement-conflict`. For `chargingNetwork`, records the\ncharge detail record id. For `parkingSession` it is 409\n`charging-settlement-conflict` — that session closes when the APDS\nSession 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\nprojection as `GET /v1/lpr/reads?observation=`, addressed by path\nlike the revision routes. A read at a place outside the caller's\n`apx_places` grant is 403 `insufficient-grant`; an unknown or purged\nread 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\nthe access-event revision: a reviewer's decision on one read,\nbefore any Session exists and however many Sessions the read\nfeeds. `corrected` writes the winning values into the\nObservation's `observedCredentialId` and\n`vehicleAncillaryIdentification` and into `detail.plate`,\n`.country`, `.stateProvince`, keeping the engine's values, with\ntheir confidences, in `detail.review.original` — set on the first\ncorrection and never changed afterwards. Every decision that\nchanges the read sets `detail.review`, increments the Observation\n`version`, and publishes `apx.data.observation.updated.v1`.\nResending the decision and values the read already has is a\nno-op: 200 with the current `version`, no new version, no event.\n`If-Match` carries the Observation `version` last read (409\n`version-conflict` when stale; nothing is written). `corrected`\nwithout `plate`, or `plate`, `country`, or `stateProvince` with\nany other decision, is 422 `request-unprocessable`. A `pending` or\n`rejected` read is not issuable evidence (Part 19 §19.4 rule 6).\nThe write changes no Session.\n\nThe 200 is the read as it now stands when the caller also holds\n`apx.lpr:read`; otherwise (scope `apx.data:write` alone suffices\nfor the write) it is the access-event-style minimal echo, which\ncarries only the plate values the caller itself supplied and\ndiscloses 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\nso a plate never enters a URL that proxies, gateways, and access\nlogs keep (Part 9 §9.6; Part 13 §13.3). Same rules, grant\nbehaviour, and response. The `GET` keeps working; a deployment\nthat 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\nin the body (Part 9 §9.6). Same rules, grant behaviour, and\nresponse; a card number pasted into `card` is 422\n`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\nin the body (Part 9 §9.6). Same keys rule (at least one), 8-hour\nwindow 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\nkeys 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\n§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\ndetected and issued, in whatever state the source reports it,\nwith the `statusHistory[]` times the source recorded (Part 19\n§19.13). The path is under `/v1/enforcement`, like the eligibility\ncheck, so it cannot be mistaken for `/v1/violations/{id}` (§19.2).\n\n`Idempotency-Key` is REQUIRED and the record is also keyed on the\ndecoration's `system` + `recordId`: a later import with a higher\n`sourceRevision` — or, when the source keeps no counter, a later\n`sourceUpdatedTime` — updates the record (200, version + 1,\n`apx.violations.status.v1`); the same revision is a no-op 200; an\nolder one is 409 `version-conflict`. `statusHistory[]` is\nappend-only: the server keeps the entries it holds and appends only\nthe source's later ones, never rewriting history.\n\nA state at or past issuance (`issued`, `paid`, `appealed`,\n`closed`) without `notice` (with `noticeNumber` and `issuedTime`)\nor `amount` is 400 `invalid-request`; `paid` with `amountPaid`\nbelow `amount` is 422 `request-unprocessable`. The server performs\nno eligibility check and applies no policy clamp to an imported\namount: the source decided. Publishes `apx.violations.detected.v1`\non first import, and `.issued.v1` when the imported state is at or\nbeyond `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\nthat fails the schema — no `apds-ext:apx:violation-source@1.0`,\nor a state at or past issuance without `notice` or `amount`\n(`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\nregistries (`reference-unknown`); `violationStatus: paid` with\n`amountPaid` below `amount`, or a payment in another currency\nthan `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\ncreation, with the match evidence (Part 19 §19.13;\n`apds-ext:apx:match-evidence@1.0` is written onto the violation).\nThe link is not a lifecycle transition: it is valid in every\nstate, terminal ones included, and appends nothing to\n`statusHistory[]`. `If-Match` carries the Violation `version` last\nread (409 `version-conflict` when stale; nothing is written). On a\nchange `version` increments and `apx.violations.status.v1` is\npublished; resending what the violation already holds is a no-op\n(200, no new version, no event). A Session that does not exist or\nis not visible to the caller is 422 `reference-unknown`; one at a\nplace outside the hierarchy of the violation's `place` (neither\nthe same element, an ancestor, nor a descendant) is 422\n`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\ncaller; `request-unprocessable` — the Session is at a place\noutside 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\nthe APDS DemandTable records the implementation holds for the\nelement. Buckets align to `interval` boundaries in the place's time\nzone; an element the implementation holds no occupancy for is 404\n`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\ninside the grant, and those owned by the caller's `apx_org`.\n`mode=change&cursor=` serves the Part 5 §5.2 feed of lists\n(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).\nEvery `places[].place` must lie inside the grant (403\n`insufficient-grant`). `Idempotency-Key` optional (Part 4 §4.2a).\nPublishes `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\n`version` (409 `version-conflict`, Part 4 §4.2a). Entries are not\npart 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;\n`mode=change&cursor=` serves the Part 5 §5.2 feed of entries so a\nscreening module keeps a local copy current. Plate values appear\nonly under `apx.platelists:*` (Part 9 §9.6); a consumer holding\nonly `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\ncredential is already on the list with an overlapping validity is\nupdated in place (200) rather than duplicated. `Idempotency-Key`\noptional. 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\ndigests with, so an authorised consumer can compute the digest of\na plate it holds and match it to decorated records without ever\nreceiving plates (Part 9 §9.6 rule 6). Rotation is by `keyId`;\nboth keys are served during an overlap. The normalization the\nimplementation 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\nholder's most recent reservations (newest planned start first),\nresolved from a plate or an explicit RightHolder id. At least one\nof `plate` or `holder` is REQUIRED (400 `invalid-request`\notherwise); when both are given the result is their intersection\n(reservations of that holder carrying that plate). `from`/`to`,\n`state`, `country`, and `stateProvince` narrow further (Part 14\n§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\nvocabulary). Qualifies `plate`; absent, the plate string alone\nis 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\ninstant. `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\nmultiple places). Holder ids are LOCAL to each implementation —\nthere is no central user catalog; cross-system correlation is\nby 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`\nwindow (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\n`target-not-found`). A place that exists outside the caller's\ngrant 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\nplate cannot be the link (barcode-only reservations, unreadable\nplates). Mirrors plate correction (Part 17 §17.5): a transactional\ndomain action, naturally idempotent (PUT).\n\nNORMATIVE (Part 14 §14.1b): the link MUST materialize in the\nunderlying APDS Session (`segments[].assignedRight`), MUST publish\nSessionUpdated, and MUST be visible to plain APDS clients reading\n/sessions/{id} — a façade over APDS-modeled state, never a\nparallel store. Pricing consequences (the prepaid rate replacing\nthe drive-up rate) follow from the link per the implementation's\nnormal rating.\n\nRe-sending the same link is a no-op 200. A link naming a DIFFERENT\nright on a session already linked to one is 409\n`right-not-linkable` (\"session already linked\"); undo the first\nlink with POST /v1/sessions/{id}/assigned-right/unlink. `If-Match`\ncarries the APDS Session `version` the client read (Part 4 §4.2a).\nWhere the resolution context gated this action, the approval\nevidence rides `approval`; a policy refusal is 403\n`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\nconsumed elsewhere, outside its validity, wrong place, in\nreservationState `cancelled` or `noShow`, or the session is\nalready linked to a different right), or `If-Match` names a\nstale 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\n§14.1b): removes the linked AssignedRight from the session's\ncurrent segment, reverts the segment to the implementation's\ndrive-up right, and returns the reservation to its pre-check-in\n`reservationState` (`confirmed` or `amended`, clearing\n`checkInSession`). MUST materialize in the underlying APDS Session\nand MUST publish SessionUpdated, like the link. `reason` is\nREQUIRED. Unlinking a session that carries no linked right is a\nno-op 200 without `unlinkedRight`. A closed Session is 422\n`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\npool of the RightSpecification. With neither `pool` nor `at`, the\npool whose validity contains now, else the earliest future pool\n(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\nright, many vehicles), materialized per Part 14 §14.2. Pool\nexhaustion is 409 pool-exhausted. A client that may retry SHOULD\nsend `Idempotency-Key`: a retried issue without one consumes a\nsecond 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\nthe key issued, in its current representation; no second slot is\nconsumed (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\ndifferent body (`idempotency-conflict`); a stale\n`rightSpecification.version` (`version-conflict`); or a credential\nidentification already active on another permit at the place\n(`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\nor is visible (`reference-unknown`); or the RightSpecification has\nno `rightPools`, or a `credentialType` is not in its\n`credentials` allow-list (`request-unprocessable`, `detail` names\nthe 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\nstatus. Results are constrained to the caller's `apx_places` grant\n(Part 13 §13.5); under an absent or empty grant the answer is an\nempty 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\nHierarchyElement ids, subtree-inclusive. A place outside the\ncaller's grant is 403 `insufficient-grant`. Servers that do not\nimplement 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\nREQUIRED. `channel: autoAttendant` = a PCI-compliant IVR captures the\ncard out of band; APX never carries PANs. Declines are 422. With\n`captureLater: true` the payment is authorized only: a hold,\ncreated `paymentStatus: approved` with `captureStatus: authorized`,\nreturned to this caller but not published or listed by default\nuntil 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\nkey 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\nthat fails the schema or names neither `account` nor\n`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\n`payment` member referencing the recorded declined PaymentRecord,\nPart 13 §13.1); a body carrying card data beyond the truncated\nlast four (`personal-data-not-permitted`, refused before it is\npersisted or logged); `captureLater` on a server without an\nauthorization lifecycle, or `apds-ext:apx:payment-detail@1.0`\nlines whose `paymentType: payment` values do not sum to\n`amount` or whose `paymentType` contradicts the `validation`\ncode (`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\none key — `ticketLast4`, `cardLast4`, `ticketNumber`, or `account` —\nis REQUIRED; `date` and `place` only narrow, and a query with no key\nis 400 `invalid-request`. Privacy rule: a truncated-key lookup\nwithout a `date` is constrained to the last 8 hours; `ticketNumber`\nand `account` are exempt. Results are constrained to the caller's\ngrant (§13.5). Holds (`captureStatus: authorized`) are omitted\nunless `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\nlast resort (no LPR, no readable ticket). Same recent-window\nprivacy rule as ticketLast4. At most four digits: a value\ncarrying more is refused with 422 `personal-data-not-permitted`\nbefore 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\nHierarchyElement ids, subtree-inclusive. A place outside the\ncaller'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\nyet captured), which are otherwise never returned; `captured`\nlists only collected payments (the default behaviour made\nexplicit). Absent = holds excluded (Part 13 §13.2). Never a key\non 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\nlast four (`personal-data-not-permitted`, Part 13 §13.2). The\nserver 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\nconfirmation and new balance. Only an `approved` payment can be\nposted; any other state is 409 `payment-state-illegal` (Part 13\n§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\naction per Part 17 §17.4 — never a control command. Idempotency-Key\nREQUIRED; approval evidence required when the resolution context's\nAllowedAction 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\ncumulative refund reaches `amount`, otherwise still `approved`\n(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\n(`payment-state-illegal`, Part 13 §13.1a) — or Idempotency-Key\nreplayed 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`\nminus `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\n(`captureStatus: authorized`): `paymentStatus` becomes `reversed`,\nnothing was collected, and no event is published (Part 13 §13.1a).\nIdempotency-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\n(`payment-state-illegal`) — or Idempotency-Key replayed with a\ndifferent 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:\n`captureStatus` `authorized → captured` (`paymentStatus` stays\n`approved`), optionally for a lower `amount` than was authorized.\nThe capture is when the payment is published and materialized\n(Part 13 §13.1a). Idempotency-Key REQUIRED. Scope\napx.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\n(`payment-state-illegal`, Part 13 §13.1a) — or Idempotency-Key\nreplayed 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\n§13.1a): sends a hosted payment link via the given channel for an\naccount, ticket, or session. APX never carries PANs. Idempotency-Key\nREQUIRED. Scope apx.payments:write. Payment completion arrives as\napx.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\ncreated, in its current representation (`status` may have\nadvanced; 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\nthat fails the schema or names no account, ticket, or session to\nsettle (`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\n(`request-unprocessable`), or a body carrying card data\n(`personal-data-not-permitted`, refused before it is persisted or\nlogged; 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\n| cancelled`, Part 13 §13.1a) and, once paid, the resulting\nPaymentRecord. 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,\npaid another way): `sent | opened → cancelled`. The hosted page MUST\nstop accepting payment from that instant. A link that is `paid`,\n`expired`, or already `cancelled` is 409 `payment-state-illegal`\n(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`\n(`payment-state-illegal`), or Idempotency-Key replayed with a\ndifferent 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\nsession's plate, optionally citing the chosen Observation candidate\n(GET /v1/lpr/candidates). A transactional domain action — not a\ncontrol command. Naturally idempotent (PUT). Scope apx.data:write.\n\nNORMATIVE (Part 17 §17.5): the correction MUST materialize in the\nunderlying APDS Session (identifiedCredentials /\nidentifiedVehicle), MUST publish SessionUpdated, and MUST be\nvisible to plain APDS clients reading /sessions/{id} — this route\nis a business-action façade over APDS-modeled state, never a\nparallel store.\n\n`If-Match` carries the APDS Session `version` the client read; a\nstale one is 409 `version-conflict` (Part 4 §4.2a). A closed\nSession may be corrected only inside the operator's dispute\nwindow and only with `reason`; otherwise 422 `session-not-open`\n(Part 17 §17.5). The 200 echoes only the plate values the caller\nsupplied and discloses no other plate-bearing data; candidate\nreads stay under apx.lpr:read (Part 9 §9.6). Where the resolution\ncontext gated this action, the approval evidence rides `approval`;\na policy refusal is 403 `action-not-allowed` or\n`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\nwindow, or closed and the correction carries no `reason`\n(`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;\nSession → the reads behind it. A pure profile over APDS\nObservations (ingest = native POST /observations). Where the\ningested Observation carried the `apds-ext:apx:lpr-read@1.0`\ndecoration, each read returns `detail` (per-attribute confidences\nfor plate, state, make, model, color, class; alternate reads;\npassage geometry; and `accessEvent` — entry or exit — as the LPR\nsystem reported it; Part 13 §13.3a).\n\nAt least one of `plate`, `ticket`, `observation`, or `session` is\nREQUIRED;\na call with none is 400 `invalid-request`, never a bulk export\n(Part 9 §9.6). Keys given together intersect. Results are bounded\nby the caller's `apx_places` grant (Part 13 §13.5); a value-keyed\nlookup 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\nLprRead projection of one ingested read; the stored\nObservationElement 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\nand every read of their passages (Part 13 §13.3a(6)). A Session\nat a place outside the caller's `apx_places` grant is 403\n`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\nsubtree (Part 13 §13.5(3)). A place outside the caller's\n`apx_places` grant is 403 `insufficient-grant`. Servers that do\nnot 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\n(Part 13 §13.3a(4)) — for example after pairing the reads of one\n`captureGroup`, or an entry read with an exit read. APDS 4.1 has no\nroute that replaces one Observation, so this is the revision route.\n\nThe server writes the value into the Observation's\n`apds-ext:apx:lpr-read@1.0` decoration, increments the Observation\n`version`, and publishes `apx.data.observation.updated.v1` with the\nObservation as it now stands (Part 13 §13.4). Sending the value\nthe read already has is a no-op: 200 with the current `version`,\nno new version, no event. `If-Match` carries the Observation\n`version` the caller last saw; a stale one is 409\n`version-conflict` and nothing is written (Part 4 §4.2a). A read\nat a place outside the caller's `apx_places` grant is 403\n`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\nthe same key with the same body returns the alert as it currently\nstands (200, Part 4 §4.2a); the same key with a different body is\n409 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\ncurrently stands (e.g. already acknowledged), not a snapshot of the\nfirst 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\nfails the Alert schema, e.g. an unknown `severity` or no\n`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\n(`idempotency-conflict`), or a client-supplied `id` that already\nexists (`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),\ndevice, relatedEntity, since. Alerts with no place binding (e.g.\n`webhookDeliveryFailed`) are visible to tokens of the owning\norganisation and are excluded whenever `place` is given (Part 7\n§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\n`alert-transition-illegal`. The optional body annotates the history\nentry this transition appends (Part 7 §7.2); a request with no body\nis 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\n`alert-transition-illegal`. The optional body annotates the history\nentry this transition appends (Part 7 §7.2); a request with no body\nis 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\nparking-domain identifiers are known (lane, device, plate, ticket,\ncredential, reservation code…) — telephony mapping stays on the\ncall platform's side (§17.1) — and returns everything the server\ncan resolve —\nissue classification, lane status, vehicle, session, account,\npassback, device status, recent overrides, support history — plus\nthe policy-decided allowedActions. Sections the caller's scopes and\n`apx_places` grant could not read directly are omitted. May return\n`status: partial` with `pendingSources` rather than waiting on a\nslow 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\nidentifying members (device, place, lane, session, holder,\ncredential, plate, ticketNumber, reservationCode) — problem type\n`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`\nincrements when anything material changed. Use after events arrive\nor 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\na full context recompute; call before executing when time has\npassed. The consuming agent (human or AI) MUST NOT decide\npermissibility 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\nsession or lane — the read side of plate correction (Part 17\n§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\npresence, last access. The write side is the `resetPassback` /\n`forceIn` / `forceOut` commands (Part 17 §17.4). Scope\napx.control:read; the place grant must cover the credential's\nlast-access place.\n\nA credential the server knows but does not track for passback (a\ntransient ticket at a site without anti-passback) is 200 with\n`state: unknown`, not 404; 404 means the credential does not\nexist (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\nresolution contexts can surface it. Summaries, not transcripts\n(Part 9 §9.6). Scope apx.support:manage.\n\nA console MAY record the interaction when the call is answered and\ncomplete it later with PUT /v1/support/interactions/{id}. Clients\nthat retry SHOULD send `Idempotency-Key`: a replay returns the\ncurrent record with 200, a different body under the same key is\n409 `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\nfilter is required; none is 400 `invalid-request`. `correlationId`, `interactionId`, and\n`credential` each suffice on their own, so one correlation id\nreconstructs the episode (Part 17 §17.7). Scope\napx.support:manage (or apx.resolution:read for read-only\nconsumers).",
        "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\napx.support:manage, or apx.resolution:read for read-only\nconsumers; the interaction's `place` must be inside the caller's\ngrant.",
        "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\nwhen the call was answered with `endedAt`, `resolution`, `summary`,\nand `actions` (Part 17 §17.6). Optimistic concurrency per Part 4\n§4.2a: send the `version` last read as `If-Match` (or in the\nbody); a stale one is 409 `version-conflict`. The server\nincrements `version` and publishes\n`apx.support.interaction.recorded.v1` again; consumers tell a\ncreate from an update by `version`. `id` in the body, when\npresent, 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\nendpoints, command types, topics, and place subtrees THIS client can\nuse. Soundness rule: everything listed is callable; APX endpoints\nnot 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,\nthe APDS version this implementation extends, supported APX\nconformance classes, and code-list registry locations.\n\nServed 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\n§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\n`url` that logs the named agent into the surface, valid for at\nmost 60 seconds (Part 25 §25.2). This is the launch mode for\nvendors who want header-based authentication, since a browser\ncannot add headers when it opens a page. `place` must lie inside\nthe grant (403 `insufficient-grant`). `Idempotency-Key` optional\n(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\nplace (`ui-surface-unknown`); a `displayMode` the surface does\nnot support (`ui-display-mode-unsupported`); or a `subject`,\n`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\nonly 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\nwhen the implementation could not express it as the module's own\nresource or Command (Part 25 §25.4). The record carries the\nlaunch's `correlationId` and is published as\n`apx.ui.action.recorded.v1`. A launch that was never opened and\nhas expired refuses with `ui-launch-expired`; a closed one with\n`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`\n(Part 25 §25.3). No body. Publishes `apx.ui.launch.changed.v1`.\nAlready 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\n`apds-ext:apx:equipment-detail@1.0` decoration, so a reader learns\nwhat the site has from APX alone (Part 26 §26.1). Distinct from\n`GET /v1/devices`, which serves live state; this serves the\ndescription. `mode=change&cursor=` serves the Part 5 §5.2 feed,\nso an edge or call-centre system keeps a local copy current.\nNaming 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\n§26.4). A call platform finds the comms point of an inbound\ncontact with `callerId`, `dialedNumber` or `commsDeviceId`; the\nanswer carries the lane, or the place only. `mode=change&cursor=`\nserves 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\nthe call platform (Part 26 §26.4). `place` must lie inside the\ngrant (403 `insufficient-grant`); `lane`, `equipment` and `serves`\nmust exist (422 `reference-unknown`). `Idempotency-Key` optional.\nPublishes `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\n`version` (409 `version-conflict`, Part 4 §4.2a). Publishes\n`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\n`apds-ext:apx:external-ids@1.0` decoration the caller may see\n(Part 26 §26.6), so a PARCS, a call platform or an aggregator goes\nfrom its own id to the place, lane, equipment or comms point\nwithout a table of its own. A read, as a POST so the id never sits\nin 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\nSupplementalEquipment with role `camera`), as a single-use link\nbound to the agent and valid for at most 5 minutes (Part 26\n§26.3). Whoever holds the camera answers; its password never\nleaves the site. Every view is logged against the agent and\n`correlationId`. Offered under the `cameraViews` feature;\n`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\n§26.9): which sign, which kind of message, when, and for which read\nor stay. An operator measures the signs with them; an appeal finds\nthe proof of display. `mode=change&cursor=` serves the Part 5 §5.2\nfeed. 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\ncontroller, the PARCS or the sign's player, usually with no APX\ncommand involved (Part 26 §26.9). `display` must be a\nSupplementalEquipment (422 `reference-unknown`); the server derives\n`place` from it. No message text and no plate are stored. With\n`command`, `shownTime` and `contentHash` must agree with that\ncommand's `CommandResult.display`. Immutable once written.\n`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\nnamed role to decide (Part 17 §17.3a). `place` must lie inside the\ngrant. `Idempotency-Key` optional. Publishes\n`apx.approvals.changed.v1`; the approver's system subscribes to it\nor 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\n§17.3a). The agent then executes the action with `Approval`\nevidence citing the request. A request already decided or expired\nis 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\nre-print at the device, or a short-lived link (Part 13 §13.1a).\nThe destination travels in the body, never in a URL. Accepted for\ndelivery (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\n`APX-Signature` (v1=HMAC-SHA256(secret, timestamp + \".\" + body)),\n`APX-Timestamp` (RFC 3339, ±5 min replay window),\n`APX-Delivery-Id` (unique per attempt; envelope `id` is stable\nacross retries), and `APX-Key-Id` (REQUIRED during secret-rotation\noverlap windows — Part 9 §9.4). Respond 2xx to acknowledge;\nanything else triggers the normative retry schedule (Part 8).\n\n**Every attempt is signed afresh (normative, Part 8 §8.3):**\n`APX-Timestamp` is the time of that attempt and `APX-Signature` is\ncomputed over it and the unchanged body, so a retry an hour later\nstill falls inside the receiver's ±5-minute window. The body — and\nwith it the envelope `id` and `time` — is byte-identical across\nattempts.\n\nThe typed entries below (`apx-native-event` and one per APX topic\nwhose data schema lives outside its own domain) name the `data`\nschema 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`,\n…): `type` is an APDS `EventTypeEnum` value, `data` the APDS\n`EventData` shape (the created/updated entity; for a `*Deleted`\ntopic the last state), and `subject` references the entity\n(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).\n`subject` references the subscription (`className`\n`ApxEventSubscription`); `data` is a SubscriptionFailure. Delivered\nto other subscriptions of the same `apx_org` that list the topic,\nnever 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\n`ObservationElement` (an ingested ObservationSet yields one event\nper element); `subject` references it with `className`\n`ObservationElement`; publishers MUST populate `elementIds` with\nthe observing lane or place, which is the event's place binding\n(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\nthe LPR system revising `accessEvent` through\n`PUT /v1/lpr/reads/{observation}/access-event` (Part 13 §13.3a(4),\n§13.4), or a reviewer's plate decision through\n`PUT /v1/lpr/reads/{observation}/plate` (§13.3a(4a)). `data` is the\nAPDS `ObservationElement` as it now stands; `subject` and the place\nbinding (`elementIds`) are as for `apx.data.observation.created.v1`.\nConsumers key on the Observation id and keep the highest `version`.\nPlate 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`\n`noShow`, `plannedStart`); `subject` references the AssignedRight\n(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\nlist; on a native APDS route, exactly stock APDS 4.1) or `change` (the\nchanges after `cursor`: a ChangeFeedPage on a native route, the route's\nown list envelope with the change-page members on an APX list route,\nrule 8; on an APX list route without a cursor, an empty page holding the\ncurrent 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\nstale value is 409 `version-conflict`; nothing is written (Part 4\n§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\nwith the same body returns the current representation (200), a\ndifferent body is 409 `idempotency-conflict`. Clients that retry\nSHOULD 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\noperation's schema or a normative field rule (problem type\n`invalid-request`, with an `errors[]` member naming each offending\nJSON Pointer), or a REQUIRED Idempotency-Key is absent\n(`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\n`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\nthan the retention window, or was issued for another (class,\ncredential, filter set). Problem type `target-not-found`; re-sync\nwith `mode=full`. The cursor is an APX parameter, so this refusal\nis 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\n`target-not-found`). A resource at a place outside the caller's\n`apx_places` grant is 403 `insufficient-grant` instead (Part 9 §9.3).\nA resource that exists but lies outside a narrower ownership scope\n(a merchant's own programs, a valet customer's own ticket) is\nreported as 404, so the answer never confirms another party's\nrecord exists (Part 9 §9.3a).",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "Forbidden": {
        "description": "Insufficient scope (problem type `insufficient-scope`) or place\ngrant (`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).\nAPX scopes follow `apx.<domain>:<verb>`. Grants are carried in the\nnormative token claims `apx_org` (Organisation reference) and\n`apx_places` (HierarchyElement subtree grants — FAIL-CLOSED: absent\nor empty = no places; the explicit wildcard \"*\" = all places,\nPart 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\nModel's RecordType (creationTime/creator/lastUpdate). All timestamps are\nRFC 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\nfrom the one serving it (Part 18 §18.6 replication): the origin's\n`EventEnvelope.source` value. Absent on records the serving\nimplementation created itself.",
            "examples": [
              "https://edge.lakeside-garage.example/v1"
            ]
          }
        }
      },
      "Extensions": {
        "title": "Extensions",
        "description": "The official APDS extension container (Use Case Document §C.2.5).\nKeys MUST follow `apds-ext:<namespace>:<class>@<major>.<minor>`.\nImplementations MUST preserve unknown extension keys on round-trip\n(tolerant reader, faithful writer). An APX decoration key, wherever\nthe container appears, MUST carry a value valid against that\ndecoration'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\nresource can itself be the target of an APDS Reference or\nVersionedReference (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\nAPX problem-type registry. Used for all APX error responses; APDS-native\nroutes 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).\nAttribute names are aligned with CloudEvents 1.0 (informative mapping in\nthe standard's annex); `subject` carries an APDS Reference so events bind\nto 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\nAPDS 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\ndefined value plus an optional ReferencedCodeListEntry-style pointer to\nthe 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`.\nItems are VERBATIM APDS entities carrying only changed fields plus\nidentity (change semantics per Part 5: explicit null = clear the field,\nabsent = unchanged — generalizing APDS Use Case C.1.1.6). Deletions are\nAPDS 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\n(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\ngrant gained subtrees (Part 5 §5.2 rule 7): the new subtree roots.\nThe client MUST full-sync these subtrees before relying on the\nfeed for them — the cursor does not retroactively cover their\nhistory.",
            "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\n`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\nchange 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\npurge, Part 9 §9.6; release of a moved place, Part 18 §18.4), as APDS\nDeletedReferences carrying the APX resource's schema name as\n`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\ncredential's `apx_places` grant gained subtrees: the new subtree roots,\nwhich the client full-syncs with the route's `place` filter before\nrelying 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\nimmediately available (the same request with this page's `cursor`);\nnull otherwise."
      },
      "OccupancySnapshot": {
        "title": "OccupancySnapshot",
        "description": "Current occupancy for one HierarchyElement, computed from the APDS\noccupancy model (Supply + DemandTable) that natively lives in the Place\nhierarchy. A convenience READ (Part 5 §5.5): the Place payload remains\nthe source of truth; this answers \"how full is it right now\" without\npulling the hierarchy. Composed entirely of verbatim APDS occupancy\nclasses — 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,\npercentage, occupancyCalculation, recordDateTime).",
            "$ref": "#/components/schemas/DemandType"
          },
          "available": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Convenience derivation: supply.supplyQuantity − demand.count when\nboth are known; null when either side is unknown. Never negative —\noverfull facilities clamp to 0 (the demand record still shows the\ntrue count).",
            "examples": [
              59
            ]
          },
          "evCharging": {
            "type": "object",
            "description": "Part 23 §23.7 — charging availability under this\nelement, derived from ChargingPointStatus. Optional; present only\nwhen the implementation claims `apx-charging`.\nCounts are of charging points (APDS ElectricChargingEquipment),\nnot 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\nonly `{endpoint, topics}` (EventTypeEnum values) gets stock behavior;\nthe 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\n(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\nmaterial; shorter is 400 `invalid-request`). For `transport:\nwebhook` only: server-generated when absent and returned EXACTLY\nONCE — in the Prefer=representation creation response. Never\npresent in GET/PATCH responses. An SSE subscription has nothing to\nsign 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) —\nsupply INSTEAD of `secret` when key material must never transit\nthe API. Never a secret value itself."
          },
          "keyId": {
            "type": "string",
            "writeOnly": true,
            "description": "Identifier the client chooses for the key it supplies with `secret`\nor `secretRef`; deliveries signed with that key carry it in\n`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.\nRetiring the last active key is 400 `invalid-request`. Without it,\nthe server retires the superseded key 24 hours after the rotation\n(Part 8 §8.1).",
            "items": {
              "type": "string"
            }
          },
          "activeKeyIds": {
            "type": "array",
            "readOnly": true,
            "description": "Identifiers of the currently valid signing keys — two entries\nduring a rotation overlap window, matching deliveries' APX-Key-Id\nheader (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\nand delivers them in order on resume (Part 8 §8.1); `failed` is\nserver-assigned when the retry schedule is exhausted (a client\nsetting it is 400 `invalid-request`). PATCH `status: active` to\nresume 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\n`lastCode` above are those of the latest entry. The normative\nschedule 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\n(UserDefinedCodeList `apx-alert-types`, seeded from APDS Use Case C.2.2\ntransaction 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\nown UUID on raise (Part 4 §4.1, Part 7 §7.1); an id that already\nexists 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\nraise; when absent the server MAY default it by policy per\n`alertType`, and returns the value it applies. If the alert is still\n`raised` or `acknowledged` at this instant the server transitions it\nto `expired` and publishes `apx.alert.status.v1`. Absent means the\nalert 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.\nPerishable (expiryTime), idempotent (Idempotency-Key), fully audited\n(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\nVehicularAccess/Place HierarchyElement (lane/place scope).",
            "$ref": "#/components/schemas/Reference"
          },
          "parameters": {
            "type": "object",
            "description": "Command-type-specific parameters. Normative parameter schemas per\ncommandType are given in Part 6 (e.g. lostTicket.method,\npushRate.rateTable VersionedReference, applyValidation.ticket +\nprovider, displayMessage.message, setDeviceState.state,\npushNegotiatedRate.rateTable VersionedReference to a RateTable\nflagged negotiable, or pushNegotiatedRate.amount AmountInCurrency\n(any amount the agent states, where the host offers the\nnegotiatedAmounts feature), matchTicket.session + evidence,\nresetPassback/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\n(mirrors SupportInteraction.agent, Part 17 §17.6). Distinct from\nrequestedBy (the organisation) and from approval.approvedBy (the\napprover). REQUIRED for pushNegotiatedRate and matchTicket (Part 6\n§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\nwrite was checked against, recorded by the server so the decision stays\nreconstructible 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\naccepted; the device acknowledged it; or the physical outcome was\nverified (e.g. gate-state sensor). Consumers — AI agents especially —\nMUST NOT claim a physical outcome (\"the gate is open\") beyond this\nlevel (\"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\nrequiresApproval (Part 17 §17.3). Servers MUST reject a\nrequires-approval action without it (403 approval-required). One shared\nshape 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 —\nnever duplicates its descriptive fields. APDS 4.1 has no general\nequipment status list: its RefillPointStatusEnum (Data Dictionary\nA.3.53) covers refill points only and is absent from apds-api-4.1.yaml.\ndeviceState values come from the APX registry apx-device-states, which\nfollows that enumeration's style and shares its available, occupied,\ninoperative and unknown values. Attachable to\nAPDS 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\nscreen-pop). Composes APDS references and data; adds no\nparallel 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\npushNegotiatedRate command that selected a RateTable succeeded\nfor it (Part 6 §6.6). Absent when the ticket prices from the\nlane's normal rate deck, and absent when the agent stated an\namount instead (see `negotiatedAmount`). At most one of\n`negotiatedRate` and `negotiatedAmount` is present: the latest\nsucceeded 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\npushNegotiatedRate command carrying `parameters.amount` succeeded\nfor it (the negotiatedAmounts feature, Part 6 §6.3, §6.6). Absent\notherwise. It is what the ticket owes, not a discount. At most one\nof `negotiatedRate` and `negotiatedAmount` is present: the latest\nsucceeded 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\ncommand (Part 6 §6.7), the Command that made the match — carries\n`agent`, `parameters.evidence`, and the audit trail. Absent for a\nticket 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\nvehicle in the lane, best first (Part 6 §6.7). Computed when the lane\nhas no ticket in the machine, or whenever the caller passes a\n`plate`, `phone`, or `credential` lookup parameter. ADVISORY: the\nagent confirms with the driver; the server never binds a candidate\nwithout 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\nclaims `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\nanswer disputes. Exactly one of amount (money off), duration\n(comped time, priced at the applicable rate), or percentage\n(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`\ncontainer as `apds-ext:apx:ratepolicy@1.0` (Part 6 §6.6). APDS models\nthe rate deck completely; it has no way to say which tables an agent\nmay offer as a negotiated rate. This is that flag — and because it\nrides inside the RateTable, every consumer mirroring the deck through\nthe native `/rates` route (Part 5 §5.2) receives it with the table, no\nsecond query. APX deliberately defines NO selection rules here (length\nof stay, time of day, caller type): the system presenting the deck to\nan agent or a third party applies its own guardrails. The server's only\nrule is enforcement — a pushNegotiatedRate naming a table that is not\nflagged 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\nthe lane (Part 6 §6.7). Produced by the lane inquiry from the lane's\nown LPR read, a presented credential, the account registry (by plate\nor phone), or a checked-in reservation. Composes APDS references; adds\nno parallel session store. Advisory until a matchTicket command binds\none.",
        "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\nread (plateRead); a credential presented at the lane (credential);\nthe account registry by plate or phone (account); a checked-in\nreservation carrying the plate (reservation)."
          },
          "evidence": {
            "description": "The record that produced the match — the entry Observation, the\nCredential, the RightHolder account, or the AssignedRight — so the\nagent 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\nminimization rule as `phone`: returned only under\n`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\n`apx-credentials` — additive; `cardNumber` and `plates` remain\nthe 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\naggregating implementations (one endpoint fronting many locations)\nthis is how consumers attribute the account to its site(s); results\nof place-less account lookups MUST stay within the caller's\n`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\nevery payment — in API responses and in\n`apx.accounts.payment.recorded.v1` events — is attributable to its\nlocation 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`,\nwhich APDS uses for the means a place accepts). A card whose credit or\ndebit 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` =\na pay-on-foot or pay station; `agent` = a person on the implementer's\nown PCI-scoped terminal; `autoAttendant` = a PCI-compliant IVR that\ncaptures the card out of band; `online` = web or mobile app. APX\nnever 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\n`captureStatus`); `declined` = refused by the payment layer;\n`reversed` = a hold voided, or a payment refunded in full.\nTransitions 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\n§13.1a). `authorized` = a hold: the payment layer approved an\nauthorization-only request (`captureLater: true`), funds are held,\nnothing is collected yet; settled by\n`POST /v1/payments/{id}/capture` or released by `…/void`.\n`captured` = collected. Absent = `captured` (a sale). A hold is\nreturned to the caller that created it, but is not listed by\n`GET /v1/payments` unless asked for, is not published on\n`apx.accounts.payment.recorded.v1`, and is not materialized as an\nAPDS Payment until captured.",
            "enum": [
              "authorized",
              "captured"
            ]
          },
          "captureLater": {
            "type": "boolean",
            "default": false,
            "description": "Create-time intent: `true` asks for authorization only (the record\nis created `paymentStatus: approved`, `captureStatus: authorized`\nand is settled later by `POST /v1/payments/{id}/capture` or\nreleased by `…/void`). Absent or `false` = sale (authorize and\ncapture at once). A server that does not model an authorization\nlifecycle refuses `true` with 422 `request-unprocessable` (Part 13\n§13.1a)."
          },
          "refundedAmount": {
            "description": "Cumulative amount refunded so far (Part 13 §13.1a). Absent or zero\n= nothing refunded. When it reaches `amount` the record is\n`reversed`; a partial refund leaves it `approved` with this member\nshowing 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\nwith no LPR and no readable ticket, this is often the ONLY key a\ncaller 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\ncustomer-service payment action of first resort. APX carries the link's\nlifecycle, never card data; the hosted page is the implementer's PCI\nscope.",
        "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\nwrite was checked against, recorded by the server so the decision stays\nreconstructible 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\ncross-lookups and `apx.data.observation.created.v1` consumers can\nalways 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\ndirection; use `detail.accessEvent` (entry | exit), which the LPR\nsystem 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\ntaken or the imagery has been purged (see `purgedImagery`). The\npreferred 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:\nthe APDS `ImageTypeEnum` values plus `plateExtended` (a wider crop\naround the plate) and `context` (the scene around the vehicle,\nwider than the overview), carried as `imageType` strings until\nAPDS 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\nObservation's `elementIds` reference one. Whether the read was an\nentry or an exit is `detail.accessEvent` (Part 13 §13.3a(4)); the\nlane 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\npublished retention schedule (Part 13 §13.3b), so a consumer can\ntell \"picture purged\" from \"no picture taken\". Absent or false\notherwise."
          },
          "recentReservations": {
            "type": "array",
            "maxItems": 10,
            "description": "The same customer's last 10 reservations (newest first) — customer\nresolved from the plate via the account registry or the\nreservation's own vehicle credentials.",
            "items": {
              "$ref": "#/components/schemas/ReservationSummary"
            }
          },
          "extensions": {
            "description": "The underlying Observation's `extensions`, projected minus the\n`apds-ext:apx:lpr-read@1.0` block (which is `detail`), so vendor\nkeys preserved on ingest are visible here (Part 13 §13.3a,\nPart 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\nscore (Part 13 §13.3a). Carried on the ingested APDS Observation as the\nLevel B decoration `apds-ext:apx:lpr-read@1.0` in its `extensions`\ncontainer (Part 4 §4.3 — plain APDS consumers ignore it), and projected\non `LprRead.detail` and `PlateCandidate.detail`. Every field optional;\neach recognized attribute carries its own confidence. APDS's\n`vehicleAncillaryIdentification` (country, stateProvince, make, model,\ncolor) remains the APDS-visible copy of the winning values; this block\nadds the per-attribute confidence, the candidates that lost, and the\npassage 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\nat least two to call `movement`, so a camera that sees only one of\nthe 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\n(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\nframe's height (`top`, `bottom`) and width (`left`, `right`), so it\nsurvives 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\nit, or stopped. A camera fact, not a statement about the facility.\n`approaching` and `receding` are deprecated synonyms of `toward`\nand `away` — accepted until 1.0; writers SHOULD send the new values\n(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\nreported by the LPR system — not the lane's configured purpose (the\nlane's APDS `accessType`), and never inferred by the APX server.\nAbsent means `unknown`. The LPR system MAY revise it through\n`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\nframes, and one camera or several (e.g. front plate and rear\nplate) — so consumers can treat them as one event. Reads of one\ngroup 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\nlow-confidence read, or any read in a jurisdiction that requires\nreview, is `pending` until a reviewer confirms, corrects, or\nrejects it through `PUT /v1/lpr/reads/{observation}/plate`.\n`notRequired` is a read no rule sent to review. Absent means the\nimplementation 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\nconfidences, kept so the correction is auditable. Set by the\nserver on the first `corrected` decision and never changed\nafterwards (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\n§13.3a(5)). Carried on an APDS VehicularAccess as the Level B\ndecoration `apds-ext:apx:lane-cameras@1.0` in its `extensions`\ncontainer (Part 4 §4.3). Facing is relative to the facility, not to\nthe lane's mode, so it holds on `reversible` lanes. Describes the\nsetup 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\nbe unique within the Place."
                },
                "faces": {
                  "type": "string",
                  "enum": [
                    "inward",
                    "outward"
                  ],
                  "description": "`inward` — looking into the facility, the way entering\ntraffic travels (reads the rear plates of entering\nvehicles); `outward` — looking out of it, the way exiting\ntraffic 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\nAssignedRight. Presence of this extension marks the AssignedRight as a\nreservation; state transitions follow Part 14 §14.1 (transition\ntable). `plannedStart`/`plannedEnd` MUST mirror the AssignedRight's\n`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\ncheck-in transitions to `noShow` (`plannedStart` plus the\noperator's grace period, Part 14 §14.1 step 6), so a platform can\ntell 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\nlookups. Also the `data` of `apx.reservation.noshow.v1` (Part 14\n§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\nRightPool profile, Part 14 §14.2). `issued` =\n`RightPool.distributedAssignedRights`, `available` =\n`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\nAssignedRight with (possibly multiple) vehicle credentials, per the APDS\nannual-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\n`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\nis 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\nRightSpecification'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`\n(`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\na 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 →\npricing → 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`\nvalue (`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 |\nrefunded | adjusted | withdrawn, Part 15 §15.1) or an implementer\ncode list (Part 11)."
              },
              "disputedBy": {
                "description": "The party on whose behalf the dispute was raised (RightHolder,\nOrganisation, or Contact); absent for an operator-initiated\ndispute (Part 15 §15.1).",
                "readOnly": true,
                "$ref": "#/components/schemas/Reference"
              },
              "originalPricing": {
                "description": "Set by the server when an `adjusted` resolution rewrites\n`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`\n(wrongVehicle | duplicateCharge | wrongClass | notLiable | other,\nPart 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\n(RightHolder, Organisation, or Contact). MAY be absent for an\noperator-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`\n(upheld | refunded | adjusted | withdrawn, Part 15 §15.1) or an\nimplementer code list (Part 11).",
            "examples": [
              "refunded"
            ]
          },
          "adjustedPricing": {
            "description": "The new amount owed. REQUIRED when `resolution` is `adjusted`\n(otherwise 400 `invalid-request`) and ignored for any other value;\nthe server moves the old `pricing` to `dispute.originalPricing`\n(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\n(automated, guided, or manual), the eligibility check that justified\nit, the evidence, the issued notice/citation, settlement, and any\nappeal — with the immutable lifecycle audit (Part 4 §4.2).\n\nLifecycle (Part 19 §19.1): `detected → confirmed | dismissed`,\n`confirmed → issued`, `issued → paid | appealed`,\n`paid → appealed` (pay-then-appeal, within the policy's\n`appealWindowDays`), `appealed → issued | paid (upheld, or reduced\nwith amount replaced by adjustedAmount; back to the state the appeal\nwas opened from) | closed (dismissed)`, `paid → closed` (server-side\nadministrative transition, no API operation). The terminal states\nare `dismissed`, `closed`, and `voided`; `void` is valid from every\nother state (`detected`, `confirmed`, `issued`, `appealed`, `paid`).\nAutomated detection MAY skip review (`detected → issued`) where the\npolicy in force permits (`EnforcementPolicy.unreviewedIssuance`);\nguided 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\n`detectedTime`, frozen at `issue` with their versions — the\nevidence 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\nthe policy's relative penalty caps (`maximumMultipleOfUnpaid`,\n`maximumPercentOverUnpaid`). Computed by the server at `issue`\nfrom the rate deck in force for the stay and frozen with the\npolicy (Part 19 §19.10). Absent when the policy in force has no\nrelative 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\n`penaltyCap` bounds, relative ones applied to `unpaidAmount`),\nfrozen so an appeal can check `penalty-exceeds-cap` without\nrecomputing 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\nserver-applied escalation step, and each appeal reduction\n(Part 19 §19.10). `amount` always equals the last entry. The\nfirst entry is written at `issue`: `reason: issued`, or, when the\nrequested amount was clamped to the cap, a single entry with\n`reason: cap`, the clamped `amount`, and the amount asked for in\n`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).\n`payment` remains the settling one; a partial payment appears\nhere, raises `amountPaid`, and leaves the state `issued` until\n`amountPaid` reaches `amount`. For an imported violation (§19.13)\nan item may carry only the source's own payment `reference`, when\nthe 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`\nmeans `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\npay-then-appeal (Part 19 §19.6). `upheld` and `reduced` return\nthe 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\nreturned money on a pay-then-appeal resolved `reduced`\n(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\nscreen-pop (Part 19 §19.3). A convenience READ composed from the APDS\nentities that natively answer the question: AssignedRights (APDS's own\nenforcement source of truth), Sessions, and reservation/permit profiles.\nAdds no parallel entitlement entity; the AssignedRight remains\nauthoritative.",
        "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\nEnforcementPolicy in force at `checkedTime` (Part 19 §19.3 rule 5):\nthe stay's start plus `entryMinutes` while no right covers it, or\nthe end of its last covering right plus `exitMinutes` once its\nrights have ended. Absent when that side has no grace, no policy is\nin 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 —\npermitDisplayed, plateMisread, gracePeriod…); a dismissal without\nit is 400 `invalid-request` with `errors[].pointer` `/reason`\n(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\namount (or the remainder) settles it (`paid`); a smaller `amount` is\na 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\nthe violation to the state the appeal was opened from (`issued`, or\n`paid` for a pay-then-appeal); `reduced` does the same with `amount`\nreplaced by `adjustedAmount`; `dismissed` closes it.",
            "examples": [
              "reduced"
            ]
          },
          "adjustedAmount": {
            "description": "The new amount payable. Required when `resolution` is `reduced`; a\n`reduced` resolution without it is 400 `invalid-request` with\n`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\nrefund returning the difference or the whole payment\n(`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\nthe 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\nat a place (Part 19 §19.10): lawful notice delivery per detection\nmode, the initial penalty cap, the escalation schedule, windows, and\nwhether posted signage is required. Bound to a HierarchyElement with\nsubtree inheritance — the nearest ancestor's policy applies unless a\ndescendant overrides it. A machine-readable summary an operator\nconfigures from the governing statute; never the statute itself.\nEdits use versioned `PUT` with the version last read as `If-Match`\nor 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`\nwithout a human `review` (Part 19 §19.4 rule 1). When present the\nserver MUST apply it at `issue` (409 `violation-not-issuable`\notherwise); when absent the operator's published documentation\ngoverns, as before. `guided` and `manual` detections are always\nreviewed, 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\npresent the lowest applies. Relative bounds apply to the\nviolation's `unpaidAmount`, which the server computes and freezes\nat `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\nwhen `afterDays` have elapsed since `notice.issuedTime` with the\nviolation still `issued`; days spent `appealed` do not count\n(the clock pauses during an appeal). The result is appended to\n`amountHistory` and never exceeds `overallCeiling`. A step whose\nfixed `addAmount` alone exceeds `overallCeiling.maximumAmount` is\nrefused 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\naccepted — from `issued`, or from `paid` (pay-then-appeal). After\nit, 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\nright (Part 19 §19.10 rule 7). Both members are optional and\nindependent: absent means no grace on that side, `0` states\nexplicitly that there is none. The policy states the minutes only;\nhow they combine with the rights into a stay's outcome is the\nevaluating system's rule. The source of\n`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\nsign's position, and when it was in force (Part 19 §19.11). Bound to\na HierarchyElement with subtree inheritance. Versioned so an appeal\ncan show the sign as it stood on the day: superseding a sign is a\nnew version or a new record with `effectiveTo` set, never an edit in\nplace 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),\n`duration` (comped time, valued at the applicable rate), or\n`percentage` (proportionate discount — the APDS RateDiscount\n`discountRate` semantics) applies; `description` is always present so\nagents can answer disputes in plain language. A program body whose\nbenefit carries none or more than one of the three is refused with\n422 `request-unprocessable` (Part 20 §20.1); the rule is stated here\nrather than as a schema `oneOf` so that existing request bodies keep\nvalidating.",
        "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\nprovider is, what the validation is worth, the rules that bound it,\nhow the merchant is billed, and how instruments are issued. Active\nprograms ARE the source of the Part 6 `GET /v1/validations/providers`\nlist when `apx-validations` is claimed.\n\nLifecycle (Part 20 §20.1): `active ⇄ suspended`, either → `ended`\n(terminal). Status changes go through `PUT` with the version last\nread as `If-Match` or body `version` (Part 4 §4.2a; 409\n`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\n(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\nsame ticket. Evaluated both ways (Part 20 §20.3 rule 3): a\nredemption is refused when the incoming program is not\nstackable and another program is already applied, or when any\nprogram 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,\nQR codes, stamp stock, digital tokens. `codes[]` is returned EXACTLY\nONCE, in the creation response (the webhook-secret convention, Part 8\n§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\nchannel writes: a pay station scanning a code, a merchant app, an\nagent's `applyValidation` command (Part 6), or a lane device. `validationId`\nis the APDS `Segment.validationId`, so APDS consumers see the same\nredemption without speaking APX. `amountReduced` is the ACTUAL value\nremoved 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:\nthat statement. It is not edited; the correction is a credit\nline 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\nas a computed preview by `GET …/statement`, and as an IMMUTABLE\nrecord once a period is closed by `POST …/statements` (`statementStatus:\nclosed`; the operator's accounting system invoices from it). Closed\nperiods 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\nmodel, net of any `credit` lines (reversals of redemptions billed\non 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\nthe period. `credit` — a redemption billed on an earlier\nclosed 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\ncredential, hangtag, or a plate used as the credential — with its\nholder, validity, physical media, and lifecycle. `credentialType` is\nthe APDS read technology; `media.form` is the physical form.\n\nLifecycle (Part 21 §21.1): `issued → active`, `active ⇄ suspended`,\n`active | suspended → lost | revoked | expired`, and `replace`\ncreates a successor while this record becomes `replaced`.\n`revoked`, `expired`, and `replaced` are terminal; `lost` may still be\n`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\n(credentialType) within the implementation among non-terminal\nrecords; a collision is 409 `credential-identification-in-use`\nwhose `detail` MUST NOT identify the holding record, its holder, or\nits 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\nfuture at issue and after `start`; otherwise the issue is 422\n`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\nat `validity.start` (or at issue, when `validity.start` is absent or\nalready past), with actor `system`, and publishes\n`apx.credentials.status.v1` (Part 21 §21.1 rule 6). When false or\nabsent the record stays `issued` until `activate` is called — the\ncard 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\nholder, account, assigned rights, places, and validity unless\noverridden; the old record becomes `replaced` and is removed from the\nAPDS 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,\nand why. Fills the gap that APDS EventTypeEnum has no access events\n(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\ndevice) at drop-off or handback: free-text notes, per-area damage\nentries, and access-controlled image links (Part 9 §9.6). The\ndrop-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\nevidence), where it is parked and where the keys are, the retrieval\nrequest and its ETA, staging, and handback — with the immutable\nlifecycle audit. The APDS Session remains the stay and the money;\nthis record is what the attendant board, the customer's phone, and a\ndamage claim look at.\n\nLifecycle (Part 22 §22.1): `dropped → parked → requested → retrieving\n(pickup) → staged → handedBack → closed`; `cancel-retrieval` returns\n`requested | retrieving` to `parked`; `park` re-parks a `staged` car;\n`dropped → handedBack` is allowed before the car moves; `closed` is\nserver-side when the stay settles. `cancel` moves a `dropped` ticket\nto the terminal `cancelled` (custody never taken).\n\nAs a create body: `storage`, `retrieval`, `handback`, `statusHistory`,\nand `recordInfo` are server-written — a server MUST ignore values a\nclient sends for them (Part 22 §22.1 rule 5). `session` and\n`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\nthe car. Additive and optional; the charge itself is a Part 23\nChargingSession 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\nobserved by an overhead camera, a ground sensor, the charger's own\nconnector state, or an attendant — fused by the server (Part 23 §23.3).\nDistinguishes the cases the charger alone cannot: a vehicle parked in\nthe bay but not plugged in (an ICE vehicle, or an EV not charging), and\na bay blocked by something that is not a vehicle. Also the request body\na 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\npresent and the charger reports a connected cable;\n`vehicleNotPluggedIn` — a vehicle is present and no cable is\nconnected (ICE-ing, or an EV not charging); `blocked` — the bay is\nobstructed by something other than a parked vehicle (cones,\ndebris, 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\nrecognition) — `false` is the ICE-in-EV-bay signal; `null` when\nunknown."
              }
            }
          },
          "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\n— the dynamic counterpart of the static ElectricChargingPoint (APDS\n`refillPointIndex` exists precisely \"to link static and dynamic\npublications\"). Never duplicates the static descriptive fields\n(connector types, power ratings live in APDS). Carries availability per\npoint and per connector, the current session, a reservation, and what\nthe bay camera sees. Same pattern as Part 6 DeviceStatus. Also the\nrequest 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`;\n`occupied` — a cable is connected but no energy is flowing\n(plugged in, suspended, complete, or idle); `charging`; `reserved`\n(Part 14 AssignedRight in force); `blocked` — the bay is occupied\nor obstructed without a connected cable (from `bay.presence`);\n`inoperative` (planned: maintenance, closed hours); `outOfOrder`\n(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\nsees it: who was authorized and how, the timeline from plug-in to\nunplug, energy delivered, the idle period after charging completed,\ncost, and how it settles — while the APDS Session remains the parking\nstay and is only referenced. The charging network's own identifiers\n(OCPP transaction, OCPI session/CDR) ride along opaquely so the two\nrecords can be reconciled without APX redefining either protocol.\n\nLifecycle (Part 23 §23.2 transition table): `authorized → pluggedIn →\ncharging ⇄ suspended → complete → idle → unplugged → closed`;\n`unplugged` also directly from `pluggedIn` (no energy) and `complete`\n(left inside the grace); `cancelled` for an authorization never used;\n`fault` from any state before `unplugged`, exiting via `unplugged` (or\n`cancelled` if never plugged in). `idle` is server-side when\n`idlePolicy.graceMinutes` elapses after `complete`; `closed` is\nserver-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;\n`charging` = Charging; `suspended` = SuspendedEV | SuspendedEVSE\n(see `suspendedBy`); `complete` and `idle` = EVConnected after\nenergy 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\nso the customer read can say \"10 minutes grace, then $0.40/min\" and\nso 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\nand is paid with the parking (one bill at exit);\n`directPayment` — settled by a Part 13 payment referenced in\n`payment`; `chargingNetwork` — billed by the charging network\nor roaming partner; the parking side records energy and idle\nbut 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\nsession — the APX counterpart of an OCPP 2.0.1 TransactionEvent. The\nserver applies the lifecycle transition (Part 23 §23.2) and appends\n`statusHistory`. `meterValue` events update `energy` without a state\nchange. 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\n(Part 5 §5.8): what the pairing of reads decided and APDS has no\nmembers for — the reads behind the visit, why and how it ended, the\nmatches it rests on, and the parent visit of an area Session. Written\nwith the native Session POST/PUT by an external pairing engine; a\nserver that pairs reads itself SHOULD write the same block on its own\nSessions. A plain APDS client ignores it. It adds no event topic and\ncarries no plate characters. A write that breaks a consistency rule\nof §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\n`entry` or `exit` to another Session of the same place is refused\nwith 409 `read-already-bound` unless `supersedes` names that Session.\nA read naming no Observation visible to the caller is 422\n`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` —\nclosed, may still be revised; `final` — no further revision\nexpected; `disputed` — under review. Every state but `open` requires\n`actualEnd`, and `open` forbids it (422 `request-unprocessable`\notherwise). `final` is the writer's statement, never a lock: a\nserver 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\nparent's `hierarchyElement` MUST be an ancestor of this Session's\n(422 `request-unprocessable` otherwise). Consumers count visits by\nSessions without `parent`; children still open when the parent\nends SHOULD be closed no later than its `actualEnd` with `endReason`\n`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\n§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\nvisit; `duplicate` is the same passage seen by another camera or\nframe; `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\nmost one per Session; two are 422 `request-unprocessable` (Part 5\n§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\nentry was never observed; the writer SHOULD then set `actualStart`\nequal to `actualEnd`. Consumers MUST exclude such Sessions from\ndwell statistics and from occupancy (Part 5 §5.8 rule 4). Absent\nmeans 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\n§5.8; shared by the `matches[]` member of\n`apds-ext:apx:session-detail@1.0` and the decoration\n`apds-ext:apx:match-evidence@1.0` on a Violation or ValetTicket).\nCarries no plate characters and no vehicle attribute values\n(Part 9 §9.6). Where both ends of one link carry evidence (the\nSession's `matches[]` entry and the decoration on the Violation or\nValetTicket), the two MUST agree. Evidence with `plate.method:\nlenient` or `applied: false` may excuse a stay but never accuse one:\n`issue` on a Violation resting on it is 409 `violation-not-issuable`\n(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\nAssignedRight, a ValetTicket, a Violation, a PlateListEntry, or an\nObservation. In the decoration on a Violation or ValetTicket: the\nSession.",
            "$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;\n`valet` — a ValetTicket's stay; `violation` — a Violation's stay;\n`list` — a plate-list entry matched the vehicle (Part 24);\n`exitPairing` — an exit read paired to the Session's entry;\n`sweep` — the vehicle seen during an inventory or patrol sweep tied\nto 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\naccount lists for the same vehicle; `fold` — equal after\nfolding look-alike characters (O/0, I/1, B/8); `fuzzy` — within\nthe implementation's edit-cost threshold; `lenient` — accepted\nunder a relaxed rule that may excuse a stay but never accuse\none; `reviewer` — a person judged the plates to match where no\nautomatic 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\nthe match; `inconclusive` — compared, no signal; `weak`, `good`,\n`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\nlink 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\nbinds a lane-inquiry candidate SHOULD be recorded as `person`\n(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\n(Part 5 §5.9): the outcome a compliance engine scored for the stay,\nand the policy it measured against. Written with the native Session\nPOST/PUT by the engine; a server that scores stays itself SHOULD write\nthe same block. The rules that produce the outcome stay in the engine.\n\nA status is not a Violation: a `violation`-family status issues\nnothing (Part 19 issues violations). Served only to tokens with\n`apx.compliance:read`, and written only with `apx.compliance:write`\n(403 `insufficient-scope`); a write that omits it keeps the stored\nblock. 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\nfamily the registry gives (422 `request-unprocessable`).\n`compliant` — rights or an exemption covered the stay\n`violation` — the stay was not covered as the policy requires\n`withheld` — not scored, or held back for review\n`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):\nthe history behind the §5.5 snapshot, derived from the APDS\nDemandTable records the implementation holds. Buckets are aligned to\nthe interval boundary in the place's time zone; a bucket with no\ndemand 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\n6): a keyed digest of a normalized credential identification (a plate),\nso a consumer that only needs \"same plate?\" can match without the\nplate itself. `value` is base64url(HMAC-SHA-256(key, normalized\nidentification)); the key is named by `keyId` and distributed through\n`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\n§13.3a(4a)): a reviewer's decision on one read. `confirmed` keeps the\nengine's values; `corrected` replaces them with the ones given;\n`rejected` marks the read unusable for pairing and enforcement.\n`plate`, `country`, and `stateProvince` belong to `corrected` only:\nsent 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\nkeys as the `GET` lookup, carried in a body so a plate never enters a\nURL that proxies and access logs keep (Part 9 §9.6). At least one of\n`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\nkeys as the `GET` lookup, carried in a body so personal data never\nenters 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\nkeys 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\n`PaymentRecord` or an APDS `Payment`: the rate sold and the lines that\nsum to the total, so revenue reports and the deck price check have\nthe base amount, the fee, and the product without a bilateral code.\nOn a `PaymentRecord` it carries `rateSold` and `lines`; on a native\nAPDS `Payment` it carries `rateSold` only, because the Payment's own\n`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\nre-shaped). Each line's code is its `idCode`: a definedValue of\n`apx-payment-line-codes` (Part 11) or an implementer code. A line\ncoded `validation` has `paymentType: validation` and its `value` is\nthe value the validation offset (not money collected); every other\nline has `paymentType: payment`, and a reduction (`discount`) is a\nnegative `value`. The `currencyValue`s of the `paymentType:\npayment` lines MUST sum to the record's `amount`, in its\n`currencyType`; otherwise 422 `request-unprocessable` and nothing\nis charged. Only on a `PaymentRecord`: on a native APDS `Payment`\nthe itemization is that Payment's own `paymentLines` and this\nmember 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\nno human in the loop. `guided` — the system surfaced a candidate\n(typically to a handheld) and an officer confirms on site.\n`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\ninline). Each item points at an APDS Image reachable under the same\nauthentication 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\nAPDS Observation `Location` shape (Part 19 §19.9), with two\ndifferences: `observerLocation` is optional here (APDS requires\nit; an automated finding copied from a fixed sensor may have\nnone), and `accuracyMetres` is added. The member names and the\n`PointLocation` types are APDS's own. GeoJSON positions are\n[longitude, latitude] in that order; enforcement tools that store\nlatitude first MUST swap on the wire. Automated detections SHOULD\ncopy 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\npayment or the settling one. `payment` references the Part 13 record\n(APDS Payment or APX PaymentRecord) when the money moved through this\nserver; a payment an import source took itself (§19.13) may carry\nonly 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\nviolation issued by an external enforcement system and imported\nthrough `POST /v1/enforcement/violation-imports`, keyed on `system` +\n`recordId`. `sourceRevision`, or without one `sourceUpdatedTime`,\norders 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\n§19.13): a violation as an external enforcement system reports it —\nin any state, with the `statusHistory[]` times the source recorded,\nthe notice, the amounts and payments, and the\n`apds-ext:apx:violation-source@1.0` decoration that keys it. The\nmembers mean what they mean on `Violation`; the difference is that\n`violationStatus`, `notice`, `amountPaid`, `payments`, and\n`statusHistory` are written by the caller here, because the source,\nnot this server, decided them. A state at or past issuance\n(`issued`, `paid`, `appealed`, `closed`) REQUIRES `notice` (with\n`noticeNumber` and `issuedTime`) and `amount` (400 `invalid-request`\notherwise); `paid` with `amountPaid` below `amount` is 422\n`request-unprocessable`. A warning with no fine is `issued` (or\n`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\n`amountPaid` at least `amount`; a part-paid violation is `issued`\n(Part 19 §19.6a). The source's own wording goes in the decoration's\n`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\nsource's own times (`actor` is the source's principal — an officer\nbadge, the system name). Append-only: the server keeps the entries\nit already holds and appends only those later than its last one\n(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):\nsets, corrects, or clears `relatedSession` after creation, carrying the\nmatch evidence. `session: null` clears the link. `If-Match` carries the\nViolation 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\n(Part 24). Entries are kept separately (`PlateListEntry`); the list\ncarries 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\nonly under `apx.platelists:read`/`:manage`; a consumer that only\nscreens may hold the `apds-ext:apx:credential-digest@1.0` decoration\ninstead (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,\nand places reachable with the presented token's scopes and grants.\nTwo clients with different grants receive different documents; a client\ncan 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\nscopes). Always a subset of the bootstrap document's\n`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),\nreflected exactly. Fail-closed semantics (Part 9 §9.3): an empty\narray means NO places; the explicit wildcard entry \"*\" means all\nplaces. A token with no `apx_places` claim is reflected as `[]`,\nnever by omitting the member (Part 16 §16.2).",
            "items": {
              "type": "string"
            }
          },
          "endpoints": {
            "type": "array",
            "description": "Callable endpoints (APDS-native, APX, and vendor routes under\n`/apx/x/<vendor-ns>/`), each callable for at least one target inside\nthe 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\n(`/v1/commands/{id}`; APDS-native routes unchanged), relative\nto 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\napx.control:execute). A permission list; what the host offers is\n`features` (Part 16 §16.2).",
            "items": {
              "type": "string"
            }
          },
          "features": {
            "type": "array",
            "description": "Optional features of claimed classes that this client may use\n(definedValues from `apx-features`, Part 11; Part 6 §6.5). Listed whenever\nthe host offers the feature and the client holds a read or execute\nscope 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\nwith its display and launch modes and the actions it reports back.\nPresent only when the host implements `apx-ui-launch` and the\nclient 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):\nthe command types the site executes, the surfaces offered there,\nand the optional features it supports. A site with no revenue\ncontrol link lists no command types, so an agent knows to use the\nvendor's screen instead. Absent when every place offers the same\nas 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\n`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:\n`requestsPerMinute`, `commandsPerMinute`, `burst` (most requests in\nany one second), `subscriptionsMax`, `streamConnectionsMax`. Every\nvalue is a per-credential integer; other keys are advisory vendor\nadditions.",
            "additionalProperties": {
              "type": "integer"
            },
            "examples": [
              {
                "requestsPerMinute": 600,
                "commandsPerMinute": 60
              }
            ]
          },
          "replication": {
            "type": "array",
            "description": "Part 18 §18.6 — for a place this implementation shares with a\nreplicated site or aggregator implementation, which side is\nauthoritative for each entity class. A write to a class from the\nnon-authoritative side is 409 `not-authoritative`. Absent when\nthe 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\nserver could resolve about one interaction, plus the policy-decided\nallowed actions. Every section beyond the required core is OPTIONAL —\nimplementations include what they know and omit what they don't\n(graceful degradation), and MUST NOT include sections the caller's\nscopes/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\nresolves every relationship it can (Part 17 §17.2). At least one\nIDENTIFYING member is required — `device`, `place`, `lane`,\n`session`, `holder`, `credential`, `plate`, `ticketNumber`,\n`reservationCode`, `guestReference`, `commsPoint`, `callerId`,\n`dialedNumber`, or `commsDeviceId`; all are optional individually.\n`interactionId`, `correlationId`, `channel`, and `reservationIssuer`\nare metadata and do not count: a body without an identifying member\nis 400 `invalid-request` (Part 17 §17.1). Unknown members are ignored\n(tolerant reader) and never used for resolution. (`minProperties: 1`\nis the only part of this rule the schema states; the full rule is\nenforced by the server.)\n\nTelephony values appear in exactly two places in APX: on a Part 26\nCommsPoint, and in the `callerId`, `dialedNumber` and `commsDeviceId`\nmembers here, which the call platform supplies to find the comms\npoint. A PARCS implementation never has to hold, return or understand\nthem; one that holds no comms points answers these members with 422\n`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\n(a call, chat, SMS session…). APX never interprets it — it only\nechoes it for correlation (Part 17 §17.7). Not an identifier for\nresolution.",
            "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\ndefinedValue from the apx-issue-types registry (open, per Part 11);\n`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\ncredential, and THIS moment (Part 17 §17.3). The server — never the\nconsuming agent, human or AI — decides permissibility. Approval\nrequirements are policy-dependent, which is why they live here at\nruntime and not in a registry.\n\nThe `execution` descriptor abstracts HOW the action runs — a Part 6\ncontrol command or a domain API operation — so the agent sees one\nunified action list and never needs to know which APX module executes\nit. Servers MUST NOT list an action the implementation does not\nsupport (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\nactions, 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/\nsurface per type. `ui` says the action is done in the vendor's own\nscreen (Part 25): the agent launches `surface` on `subject` and\nthe implementation reports what was done as the module's native\nresource or a UiActionRecord carrying the launch's correlation id.\nThe value set grows additively: a client MUST skip an action whose\n`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) —\na projection over APDS Observations, imagery as access-controlled\nlinks (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\nfuture 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\n(Part 17 §17.3a). An agent whose AllowedAction said `requiresApproval`\ncreates one, addressed to a `role` (an escalation role of the place,\nPart 26 §26.5, or the AllowedAction's `approvalRole`); the approver\ndecides through `POST /v1/approvals/{id}/decide`; the resulting\n`Approval` evidence on the write cites the request. Every change is\npublished 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\nagain (Part 13 §13.1a). The `destination` travels in the body, never\nin 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\nin the discovery document's `uiSurfaces[]`, so a host learns which\nscreens exist, how each may be shown, which launch modes it accepts,\nand which actions it reports back. The `surface` name is a\ndefinedValue of `apx-ui-surfaces` (`<module>.<view>`, Part 11); its\nregistry 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\n(`VehicularAccess`, `Session`, `Violation`…). Absent for a general\nsurface 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\nregistered with the implementation (Part 25 §25.6); `popup` is the\nfallback 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\nreturned single-use `url`. `signedToken` — the host signs a\nUiLaunchToken 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\nvalues and effective-spec operationIds. A host uses it to decide\nwhich `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).\nThe same members are the claims of a signed launch token\n(UiLaunchToken). `correlationId` ties everything the agent does in\nthe screen back to the host's record; `returnFields` lists the APX\npaths the host wants back when the implementation has to answer with\na 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\nactions produce, that the host wants back in `UiActionRecord.fields`\n(`/amount`, `/session/id`). A value the implementation cannot\nsupply 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\nhandshake (`POST /v1/ui/launches`) or minted by the implementation when\na signed token is presented. `url` is single-use and expires at\n`expiresAt`; the record itself stays readable for audit and carries\nthe `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.\nPresent only on the create response and the first read within\n`expiresAt`; never carries personal data or secrets in its\nquery 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\nuse) → `closed` when the screen reports it is done, or\n`expired` when `expiresAt` passes unused. An opened launch not\nclosed within the implementation's limit (RECOMMENDED 1 h)\nalso 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\nnot express it as the module's own resource or Command (Part 25 §25.4).\nThe native resource is always preferred: a lost ticket issued in the\nvendor's screen MUST appear as a `lostTicket` Command carrying the\nlaunch's `correlationId`. Only an action with no APX operation on this\nimplementation is recorded here, with the `fields` the host asked for\nin `returnFields`, and `unavailable[]` for the ones it could not\nsupply. 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\naction 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)\nin the `signedToken` launch mode (Part 25 §25.3). `aud` is the\nimplementation, `exp` is at most 60 s after `iat`, `jti` is unique and\nsingle-use. The remaining claims are the UiLaunchRequest members. The\ntoken travels by form POST or in the URL fragment, never in the query\nstring, and the implementation checks it against the host's keys\nregistered 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\n§26.1). Carried on an APDS SupplementalEquipment as the Level B\ndecoration `apds-ext:apx:equipment-detail@1.0` in its `extensions`\ncontainer (Part 4 §4.3). The equipment TYPE stays the APDS\n`EquipmentTypeEnum` (often `paymentMachine` or `other`); `role` says\nwhat the item does on the site, from the fixed code list\n`apx-equipment-roles`.\n\n`firmwareVersion` and `softwareVersion` are optional but RECOMMENDED,\nand readable by every client of the place, because knowing what runs\non each device is what makes integration at scale possible. IP\naddresses are deliberately left out in the interest of security:\ntogether with model and firmware they map a site's network for an\nattacker, and no APX flow connects to a device directly. They could\nbe added later, as an optional member behind a restricted scope, if a\nreal need arises. MAC addresses stay, as the hardware identity when\nthe 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).\nCarried on a SupplementalEquipment whose EquipmentDetail `role` is\n`camera`, as the Level B decoration `apds-ext:apx:camera@1.0`. Where\nthe camera is (`area`, `level`, `lane`) and what it is built into\n(`builtInto`) are EquipmentDetail members, shared with every other\npiece of hardware; this decoration adds how it is mounted, what it\nlooks at, and how it can be viewed. It holds no addresses, usernames\nor passwords: a view is obtained through `POST /v1/cameras/{id}/views`\nand the password never leaves the site (Part 26 §26.3). Camera models\nand stream profiles follow ONVIF (Profile S, Profile T) and are not\nredefined. `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\ncredential the receiving system looks up in its own vault. NEVER\nthe secret itself; the secret is exchanged once, outside APX, at\nonboarding (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\n(Part 26 §26.6). Carried on any HierarchyElement as the Level B\ndecoration `apds-ext:apx:external-ids@1.0`. APDS\n`SupplementalFacility.externalIdentifiers` holds untyped strings; here\neach id says which system issued it. `system` is a URI the issuer\nowns, usually its own domain, so APX names no products or platforms.\n`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\ncall (Part 26 §26.5). Carried on a place HierarchyElement as the\nLevel B decoration `apds-ext:apx:place-operations@1.0`.\n`escalationContacts` lists roles in calling order, never names or\nphone numbers: the call platform holds those, so APX carries no\npersonal contact data. A Part 17 approval request is addressed to a\nrole 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\n§26.4): an intercom, an analog dialler, a posted phone number, a\nkiosk, a QR code, an app. A call platform matches an inbound contact\nto a comms point by the number it calls out as (`callerId`), the\nnumber it called (`phoneNumber`), or its own device id\n(`commsDeviceId`), and APX then answers with the lane, or with the\nlocation only when the comms point serves no single lane (a posted\nnumber shared by many lanes can never name the lane by itself).\n\nThese are the only members of APX that carry telephony values, and\nthe call platform supplies them; a PARCS implementation never has to\nhold, return or understand them (Part 17 §17.1). SIP usernames,\nrealms and passwords are deliberately left out: a username with its\nrealm is half of a line's login, they exist only for SIP devices, and\nthe call platform already maps its own SIP data to these ids. A SIP\npassword 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\nstock APDS record plus its `extensions` container, which carries the\n`apds-ext:apx:equipment-detail@1.0` decoration (REQUIRED on every\nrecord this class serves), `apds-ext:apx:camera@1.0` on a camera, and\n`apds-ext:apx:external-ids@1.0` where other systems have ids for it.\nThe 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\nholds the camera answers, the PARCS, the video system or an on-site\ngateway, and the camera's password never leaves the site. `playback`\nneeds `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\na recording (Part 26 §26.3). Bound to the agent it was issued to and\nlogged against the `correlationId`; it expires at `expiresAt`, never\nmore than 5 minutes after issue, and it never contains a camera\ncredential.",
        "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,\nwhich kind of message, when, and for which read or stay. Written by\nwhichever system drove the display, the edge controller, the PARCS or\nthe sign's own player, often with no APX command involved; immutable\nonce written. It is the proof of display a refused-service message\nneeds (Part 24 §24.4), and the data an operator measures the signs by.\n\nThe proof members are the Part 6 §6.1a `CommandResult.display` shape,\nunchanged. The message text is never stored, only its hash and wording\nversion, and the plate is never stored even when the sign shows it\n(Part 9 §9.6 rule 8). When a `displayMessage` command drove the sign,\n`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):\n`CommandResult.display` for a commanded message, and the proof members\nof a Part 26 §26.9 DisplayRecord for any message. Carries a hash and\nthe 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\n(Part 3 §3.4) whose Parts and registries the implementation\nfollows; 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\nAPDS-native routes alike). Absent means the origin root that serves\nthis document. REQUIRED when the API is mounted elsewhere (Part 16\n§16.1).",
            "examples": [
              "https://api.citypark.example/parking"
            ]
          },
          "conformanceClasses": {
            "type": "array",
            "description": "APX conformance classes this implementation supports, closed under\nthe Part 3 §3.1 dependency table, plus any vendor classes\n(`<vendor-ns>-<class>`). Clients ignore classes they do not\nrecognise.",
            "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\nthe 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\n* campus : a data structure holding information about a large, often ill-defined area, which may contain many parking structures.\n* identifiedArea : a data structure holding information about a coherent feature, such as a set of parking spaces that all share the same characteristics.\n* place : a data structure holding information about a single identifiable parking place.\n* 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.\n* subplaceElement : a sub-division of a place for the convenience of the operator that may be used for parking related or other purposes.\n* 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.\n* vehicularAccess : a specialisation of an identified area defining vehicular access areas.\n* electricChargingEquipment : a specialisation of a supplemental facility for electric charging areas.\n* supplementalEquipment : a specialisation of a supplemental facility which is available on some site, for example on a rest area.\n* 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\n* accessPermission : intended grant access permission\n* loadingUnloading : intended granting permissions to load and unload vehicles.\n* oneTimeUseParking : intended for one time or limited parking usage\n* permitParking : intended for multi-use parking usage\n* setDownPickup : intended for passenger set down and pick up\n* 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.\n* offStreetStructure : Off-street multi-tier parking structure.\n* offStreetSurface : Off-street ground-level at grade parking.\n* 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.\n* aboveGround : Parking is above ground level (this may include ground level parking)\n* groundLevel : Parking is at ground level\n* 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\n* covered: Indicates that the facility or specific entity has a roof to provide protection from direct overhead sun or adverse weather\n* notCovered: Indicates that the facility or specific entity has no roof to provide protection from direct overhead sun or adverse weather\n* partiallyCovered: Indicates that the facility or specific entity has a roof offering partial coverage to provide protection from direct overhead sun or adverse weather\n* 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.\n* barrierFreeAccessible: Accessible without any steps or other barriers. Does not ensure the same access as disabledAccessible.\n* disabledAccessible: Accessible for disabled people. wheelChairAccessible is a special form of it.\n* disabledEasements: There are special easements for disabled people, like handrails or disabled-friendly furniture.\n* disabledMarkedThere: is a visible mark to support access by disabled people (e.g. a wheelchair symbol).\n* none: No form of special accessibility, i.e. usually not convenient for disabled people, e.g. because of steps or barriers.\n* orientationSystemForBlindPeople: There is some orientation system, which helps blind or visually impaired people. Examples might be some acoustic system or tactile paving.\n* other: Other.\n* unknown: It is unknown, whether there is a special form of accessibility.\n* 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\n* app : App â€“ payment is collected via an app that may also control access to the facility.\n* payAndDisplay : PND â€“ pay and display. Vehicle displays a credential to show it is paid. Typically prepaid and short term.\n* 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.\n* payBySpace : PBS â€“ pay by space. Vehicle makes a payment based on occupying a specific space. Typically prepaid.\n* permit : Similar to PND but for long term parking (e.g. monthly pass, quarterly, semester).\n* 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\n* staffed : Normally staffed during operating hours\n* temporary : Staffed on a temporary or part time basis.\n* 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.\n* customerService : Contact details for parking customer support for a facility or specific entity\n* emergencyContact : Contact details for emergency assistance or support for a facility or specific entity specifically related to parking operations\n* enforcementSystemProvider : Contact details for the provider of the enforcement system\n* operator : Contact details for the parking operator for a facility or specific entity\n* owner : Contact details for the owner of a facility or specific entity.\n* propertyManager : Contact details for the property manager of a facility or related facility.\n* securityService : Contact details for security services for a facility or specific entity\n* 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\n * apartment: Element indicating a discrete element of a building forming the address\n * building: Element identifying the number or name and type of the edifice or construction relevant for the address [derived from ISO19160-4]\n * districtTerritory: Element specifying the geographic or administrative area of the country for the address [Source: 19160-4]\n * floor: Element indicating the floor or level on which a delivery point is located in a multi-storey building [Source:ISO19160-4]\n * poBox: A postal delivery location identifier, not necessarily a physical location.\n * region: Element indicating the name of the area within or adjacent to the town in which delivery address is.\n * street: Element indicating road or street identifier or name \n * 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]\n * 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\n* customerService: The email contact is for customer service.\n* general: The email contact is general in nature.\n* helpdesk: The email contact is a helpdesk.\n* 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\n\nThe coordinate reference system for all GeoJSON coordinates is a\ngeographic coordinate reference system, using the World Geodetic System\n1984 (WGS 84) datum, with longitude and latitude units of decimal\ndegrees.\nThis is equivalent to the coordinate reference system identified by the\nOpen Geospatial Consortium (OGC) URN\nAn OPTIONAL third-position element SHALL be the height in meters above\nor below the WGS 84 reference ellipsoid.\nIn the absence of elevation values, applications sensitive to height or\ndepth 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\ninformation on the coordinate range for its Geometries, Features, or\nFeatureCollections. The value of the bbox member MUST be an array of\nlength 2*n where n is the number of dimensions represented in the\ncontained geometries, with all axes of the most southwesterly point\nfollowed by all axes of the more northeasterly point. The axes order\nof 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.\n* ContactPoint: Contact detailed information.\n* 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\n\n* `firstWeekOfMonth`: First week of the month\n* `secondWeekOfMonth`: Second week of the month\n* `thirdWeekOfMonth`: Third week of the month\n* `fourthWeekOfMonth`: Fourth week of the month\n* `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\n* dayBeforePublicHoliday: The day preceding a public holiday\n* dayFollowingPublicHoliday: A day following a public holiday\n* inLieuOfPublicHoliday: A holiday in lieu of a public holiday that falls on a weekend\n* longWeekendDay: A day between a public holiday and the weekend\n* other: Some other special day\n* publicEventDay: A day of a public event. You may use the publicEvent attribute to specify the corresponding event\n* publicHoliday: Public holiday A public holiday in general. You may use the PublicHoliday class to refer on a specific public holiday\n* schoolDay: A school day\n* 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.\n* busOnly : Only buses are permitted.\n* busStop : This is a stopping place of bus pick-up or drop-off; not to be used for parking.\n* carpoolOnly : Only carpool vehicles are permitted.\n* commercialVehicleOnly : Only commercial vehicles are permitted.\n* disabledPersonPermitOnly : Only vehicles of registered disabled person permit holders permitted.\n* electricVehicleOnly : Only electric vehicles permitted.\n* freeParking : No fee for parking\n* governmentVehicleOnly : Only government vehicles permitted.\n* loadingZone : This is a loading zone; not to be used for parking.\n* loadingZoneCommercial : Only government vehicles permitted.\n* media : Only for use by the media\n* noParking : No parking permitted\n* noWaiting : No waiting or parking of vehicles is permitted\n* parkingTimeLimit : Time limited parking.\n* residentialPermitOnly : Only for use by residential permit holders only\n* snow : Snow clearing zone; no parking\n* streetCleaning : Street cleansing zone; no parking\n* taxiOnly : Only taxis are permitted.\n* 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.\n* active : The described event, action or item is currently active regardless of the definition of the validity time specification.\n* definedByValidityTimeSpec : The validity status of the described event, action or item is in accordance with the definition of the validity time specification.\n* planned : The described event, action or item is currently planned regardless of the definition of the validity time specification.\n* 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.\n* validity: using validity\n* 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. \nThere are four distinct time domain concepts: \n* Hours of operation (times at which the facility may be used)\n* Access and egress (times it is possible to enter and leave the facility)\n* Entrance open time\n* 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\n* cashBillsOnly : Cash payment using bills only.\n* cashCoinsAndBills : Cash payment using bills and/or coins only.\n* cashCoinsOnly : Cash payment with coins only.\n* mobileAccount : Payment method using an app or other functions typically via a smartphone, to a linked bank or card account.\n* 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.\n* 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.\n* 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.\n* prepay : Advanced payment for parking right.\n* tollTag : Toll tag (RFID) or similar, with associated account.\n* 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.\n* other : Other.\n* payAfterExit : Payment on account\n* 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).\n* payOnEntry : Pay at start of the parking session (e.g. for pay and display)\n* payPriorToExit : Pay at machine on foot prior to returning to vehicle and use payment ticket to exit.\n* 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.\n* anpr : Automated License Plate Recognition information is tracked for inbound and outbound traffic. The difference between in and out counts enables an occupancy count.\n* 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.\n* spaceSensor : A sensor in each space detects the presence of a vehicle.\n* userDeclaration : User self-declared, where the user enters a space identifier and/or vehicle registration number, typically at the start of a parking session.\n* 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.\n* 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.\n* 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.\n* foot: Imperial foot = 12 inches\n* 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.\n* squareFeet: Unit of Square feet.\n* squareMetres: Unit of Metres Square.\n* 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.\n* poundsWeight: 1 lb\n* 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. \nThe 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.\n* counted : Physical determination if a space is occupied\n* derived : Space occupancy is estimated by using related data such as active payments or sold permits.\n* expected : Future prediction of occupancy levels.\n* 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.\n* spaceView : Each space is physically marked and identifiable.\n* 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\ndistributing 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. \nThis is the total number of spaces usable for parking or other mobility operations. \nIt 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.\n* ok : OK\n* 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.\n\n* `anpr`: Automatic vehicle license plate recognition\n* `chalk`: Chalk-mark observation or similar\n* `rfTransponder`: Rf transponder radio frequency transponder device, for toll tag or similar radio based devices\n* `scanner`: Handheld or fixed scanning device (optical)\n* `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.\n* 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.\n* eticket : digital equivalent of a paper ticket, often presentable via smartphone or similar device for control.\n* hangtag : visible, often removable, credential indicator, with visible markings\n* licensePlate : fixed plate, in a defined format, used to identify a specific vehicle- Normally a permanent fixture.\n* permit : issued credential, often in the form of an adhesive label, often placed on the windscreen, credential indicator, with visible markings\n* qrCode : quick Reference (QR) code\n* rfid : specific RF identification associated to an RFID-related account.  Used for permit uses.\n* ticket : typically issued paper with printed details, often with magnetic strips; typically single use disposable.\n* electronicID : an identifier transmitted by electronic means\n* ticketcoupon : a visible printed or written paper-based ticket or coupon carrying an identifiable credential.\n* 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\nobservation 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 : \n* all : All sort of fuel is accepted\n* battery : Battery\n* biodiesel : Biodiesel\n* diesel : Fuel used for compression - ignition (CI) engines\n* dieselBatteryHybrid : Diesel and battery hybrid\n* ethanol : Ethanol\\n* hydrogen: Hydrogen\n* liquidGas : Liquid gas of any type including LPG\n* lpg : Liquid petroleum gas\\n* methane: Methane gas\n* other : Other\n* petrol: Fuel used for positive-ignition (PI) engines\n* petrol95Octane : Petrol with 95 octane\\n* petrol98Octane: Petrol with 98 octane\n* petrolBatteryHybrid : Petrol and battery hybrid\n* petrolLeaded : Leaded petrol\n* petrolUnleaded : Unleaded petrol\n* 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\n* 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\n* 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\n* equalTo : Logical comparison operator of \"equal to\".\n* greaterThan : Logical comparison operator of \"greater than\".\n* greaterThanOrEqualTo : Logical comparison operator of \"greater than or equal to\".\n* lessThan : Logical comparison operator of \"less than\".\n* 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\n* actual : The weight is the actual weight of a specific vehicle\n* 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).\n* anyVehicle : Vehicle of any type.\n* articulatedBus : Articulated bus\n* articulatedTrolleyBus : Articulated trolley bus\n* articulatedVehicle : Articulated vehicle.\n* bicycle : Bicycle.\n* bus : Bus.\n* 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).\n* caravan : Caravan.\n* carOrLightVehicle : Car or light vehicle.\n* carWithCaravan : Car towing a caravan.\n* carWithTrailer : Car towing a trailer.\n* constructionOrMaintenanceVehicle : Vehicle normally used for construction or maintenance purposes (e.g. digger, excavator, bulldozer, lorry mounted crane)\n* fourWheelDrive : Four wheel drive vehicle.\n* heavyDutyTransporter : A transporter for heavy duty (usually with abnormal dimensions).\n* heavyGoodsVehicle : Vehicles with a total weight above 3,500 kg (vehicle and load).\n* heavyGoodsVehicleWithTrailer : Heavy goods vehicle with trailer\n* heavyVehicle : Vehicle whose weight means it should be classed as a heavy vehicle\n* highSidedVehicle : High sided vehicle.\n* largeCar : Large car\n* 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).\n* lightCommercialVehicle : Vehicles for the carriage of goods and having a maximum mass not exceeding 3.5 tonnes (class N1).\n* lightCommercialVehicleWithTrailer : Light goods vehicle with trailer\n* longHeavyLorry : A heavy lorry that is longer than normal.\n* lorry : Lorry of any type.\n* metro : Metro\n* 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).\n* moped : Moped (a two wheeled motor vehicle characterized by a small engine typically less than 50cc and by normally having pedals).\n* motorcycle : Motorcycle.\n* motorcycleWithSideCar : Three wheeled vehicle comprising a motorcycle with an attached side car.\n* motorhome : motorhome\n* motorScooter : MotorScooter (a two wheeled motor vehicle characterized by a step-through frame and small diameter wheels).\n* other : Other than as defined in this enumeration.\n* passengerCar : Passenger car\n* smallCar : Small car\n* tanker : Vehicle with large tank for carrying bulk liquids.\n* threeWheeledVehicle : Three wheeled vehicle of unspecified type.\n* trailer : Trailer.\n* tram : Tram.\n* trolleyBus : Trolley bus\n* twoWheeledVehicle : Two wheeled vehicle of unspecified type.\n* unknown : Unknown.\n* van : Van.\n* vehicleWithCaravan : Vehicle (of unspecified type) towing a caravan.\n* vehicleWithCatalyticConverter : Vehicle with catalytic converter.\n* vehicleWithoutCatalyticConverter : Vehicle without catalytic converter.\n* vehicleWithTrailer : Vehicle (of unspecified type) towing a trailer.\n* withEvenNumberedRegistrationPlates : Vehicle with even numbered registration plate.\n* 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\".\n* ammunition : Ammunition.\n* chemicals : Chemicals of unspecified type.\n* combustibleMaterials : Combustible materials of unspecified type.\n* corrosiveMaterials : Corrosive materials of unspecified type.\n* debris : Debris of unspecified type.\n* empty : No load.\n* explosiveMaterials : Explosive materials of unspecified type.\n* extraHighLoad : A load of exceptional height.\n* extraLongLoad : A load of exceptional length.\n* extraWideLoad : A load of exceptional width.\n* fuel : Fuel of unspecified type.\n* glass : Glass.\n* goods : Any goods of a commercial nature.\n* hazardousMaterials : Materials classed as being of a hazardous nature.\n* liquid : Liquid of an unspecified nature.\n* livestock : Livestock.\n* materials : General materials of unspecified type.\n* materialsDangerousForPeople : Materials classed as being of a danger to people or animals.\n* materialsDangerousForTheEnvironment : Materials classed as being potentially dangerous to the environment.\n* materialsDangerousForWater : Materials classed as being dangerous when exposed to water (e.g. materials which may react exothermically with water).\n* oil : Oil.\n* ordinary : Materials that present limited environmental or health risk. Non-combustible, non-toxic, non-corrosive.\n* other : Other than as defined in this enumeration.\n* perishableProducts : Products or produce that will significantly degrade in quality or freshness over a short period of time.\n* petrol : Petrol or petroleum.\n* pharmaceuticalMaterials : Pharmaceutical materials.\n* radioactiveMaterials : Materials that emit significant quantities of electro-magnetic radiation that may present a risk to people, animals or the environment.\n* refrigeratedGoods : Refrigerated goods.\n* refuse : Refuse.\n* toxicMaterials : Materials of a toxic nature which may damage the environment or endanger public health.\n* 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\n* `previous`\n* `current`\n* `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. \nRateEligibility enables a RightSpecification to have association to multiple RateTable(s) for a\nspecific Eligibility ( or set of Qualifications). \nRateEligibility also defines if RateTables are Combinable. \nThis is a Yes / No (Boolean) definition. \nEither 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.\n* public : Open to the public. \n* 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.\n* contract : Rate provided to contract holders only.\n* daily : Rate provided on a daily rate, per calendar day.\n* event : Rate provided in combination with a specific event.\n* 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.\n* flatRate : A rate applied to the rate line which is not time/duration dependent. i.e. a single fixed payment.\n* flatRateTier : A flat rate charge rate associated with a specific time-based tier. This is a special case of an incrementing rate.\n* 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.\n* fixedDuration : Fixed duration - check Rate Usage Duration Limitation field\n* fixedNumber : check Rate Usage Count Limitation field\n* once : Permit can be used once\n* unlimited : Unlimited usage.\n",
        "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.\n* 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. \nIf 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 :\n* be associated to a __session__.\n* be associated to an __assigned right__ and to a specific __rate__ and __credential__ via the __assigned right__.\n* 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__).\n* be associated with a __place__.\n* be associated to a __financial transaction__ data.\n* 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.\n* electronic : electronically issued, traceable\n* permit : physical identifier, typically visibly mounted within vehicle\n* 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.\n* payment : Indicates financial payment made\n* 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\n\n* `eligibilityRequirementNotMet`: a stated eligibility requirement is not considered to be met\n* `noAvailability`: No availability for request\n* `noMatchingSpecification`: No matching rights specification found\n* `other`: other reason (reason not given)\n* `rightSpecificationNotAvailableAtRequestedTimes`: the requested specification is not available at the requested time\n",
        "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\n\n* `existingSessionNotFound`: Error – the existing session referenced is not found\n* `incorrectCredentialsSupplied`: Error – credential details supplied are incorrect\n* `noExtensionPossible`: Error – the requested extension is not possible\n",
        "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`\nremains valid and carries the first two members only): links a renewal\npermit to the one it renews, so a portal can follow the chain, and\ncaps how many of a multi-vehicle permit's vehicles may be parked at\nonce (§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\nplace at once (Part 14 §14.2d). Absent means every registered\nvehicle 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\n(Part 8 §8.5). Every entry must lie inside the token's `apx_places`\ngrant, 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\ndelivered (Part 8 §8.5a). Values are `apx-alert-types` entries or\nimplementer 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\nApxEventSubscription. Members present replace the stored value, an\nexplicit `null` clears an optional member, and absent members are\nunchanged — so `{\"status\": \"active\"}` alone resumes a subscription.\n`version`, when given, is the precondition (Part 4 §4.2a); a stale one\nis 409 `version-conflict`. `id`, `activeKeyIds`, and `recordInfo` are\nserver-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\nserver-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\ncommand reaches `succeeded` (Part 6 §6.1a) and absent before then. Members\nare normative per command type: `lostTicket` → `ticketNumber`, `session`,\n`amountDue`; `matchTicket` → `session`, `amountDue`;\n`pushNegotiatedRate` → `amountDue`, and `rateTable` when a table was\nselected (absent for a stated amount, which the lane inquiry reports\nas `currentTicket.negotiatedAmount`). Other command types\nleave it absent unless a registry entry says otherwise. It restates what\nthe lane inquiry shows, so a console can continue (print, take payment)\nwithout 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\ndevice confirmed it showed, when, and whether the player or an\noperator acknowledged it. A Part 26 §26.9 DisplayRecord that names\nthis 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\noperators 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\nwritable members of `ValidationIssuance`. The program is the one the\npath names; `program` MAY be repeated in the body, and a value that\ndiffers from the path is 422 `request-unprocessable` (Part 20 §20.2).\nServer-assigned members (`id`, `version`, `codes`, `issuanceStatus`)\nare 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\n(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\nwhen no CredentialRecord matched (`denialReason: unknownCredential`),\nand MAY be carried otherwise. Personal data under Part 21 §21.5:\nreturned 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\nmatched a CredentialRecord — the item of `GET /v1/access-events` and\nthe data of `apx.credentials.access.v1`. `credential` is REQUIRED\nwhenever a record matched; it is absent only for `denialReason:\nunknownCredential`, where `presented` is REQUIRED instead (Part 21\n§21.4). Every `CredentialAccessEvent` is a valid `AccessEvent`; this\nschema exists because `CredentialAccessEvent.credential` is required\nand 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\n* cee3: CEE3, 230 V, 16 A\n* cee5: CEE5, 400 V, 16-63 A\n* chademo: CHAdeMO, 600 V DC. Used mostly in Japan.\n* domestic: A domestic socket of unspecified type. Applicable countries should be specified in seperate attribute.\n* domesticA: Domestic socket type A (mainly used in the USA, Canada, Mexico & Japan)\n* domesticB: Domestic socket type B (mainly used in the USA, Canada & Mexico)\n* domesticC: Domestic socket type C (commonly used in Europe, South America & Asia)\n* domesticD: Domestic socket type D (mainly used in India)\n* domesticE: Domestic socket type E (primarily used in France, Belgium, Poland, Slovakia & Czechia)\n* domesticF: Domestic socket type F (used almost everywhere in Europe & Russia, except for the UK & Ireland)\n* domesticG: Domestic socket type G (mainly used in the United Kingdom, Ireland, Malta, Malaysia, Singapore & the Arabian Peninsula)\n* domesticH: Domestic socket type H (used exclusively in Israel, the West Bank & the Gaza Strip)\n* domesticI: Domestic socket type I (mainly used in Australia, New Zealand, China & Argentina)\n* domesticJ: Domestic socket type J (used almost exclusively in Switzerland & Liechtenstein)\n* domesticK: Domestic socket type K (used almost exclusively in Denmark & Greenland)\n* domesticL: Domestic socket type L (used almost exclusively in Italy & Chile)\n* domesticM: Domestic socket type M (mainly used in South Africa)\n* domesticN: Domestic socket type N (used in Brazil and South Africa)\n* domesticO: Domestic socket type O (used exclusively in Thailand)\n* iec60309x2single16:  IEC 60309-2 Industrial Connector single phase 16 amperes (usually blue)\n* iec60309x2three16: IEC 60309-2 Industrial Connector three phase 16 amperes (usually red)\n* iec60309x2three32: IEC 60309-2 Industrial Connector three phase 32 amperes (usually red)\n* iec60309x2three64: IEC 60309-2 Industrial Connector three phase 64 amperes (usually red)\n* iec62196T1: IEC 62196 Type 1 \"SAE J1772\".  Mostly used in USA and Asia.\n* iec62196T1COMBO: Combo Type 1 based, DC\n* iec62196T2: IEC 62196 Type 2 \"Mennekes\" - 400 V, 16-63 A. Mandatory in Europe\n* iec62196T2COMBO: Combo Type 2 based, DC, Type 2 connector with extension for simultaneous DC-charging\n* iec62196T3A: IEC 62196 Type 3A\n* iec62196T3C: \" IEC 62196 Type 3C \"\"Scame\"\"  \"\n* other: Other charging interface.\n* pantographBottomUp: On-board Bottom-up-Pantograph typically for bus charging\n* pantographTopDown: Off-board Top-down-Pantograph typically for bus charging\n* teslaConnectorAmerica: Tesla connector used in America (Tesla specific)\n* teslaConnectorEurope: Tesla Connector EU (modification of the Type 2 connector)\n* teslaR: Tesla Connector \"Roadster\"-type (round, 4 pin)\n* teslaS: Tesla Connector \"Model-S\"-type (oval, 5 pin)\n* 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: \n* activeRFIDChip: Phone (active RFID chip)\n* apps: Apps\n* calypso: RFID Calypso\n* cashPayment: No specific authentication by using cash\n* creditCard: Credit card\n* debitCard: Debit card\n* mifareClassic: RFID Card / Phone NFC - Mifare Classic\n* mifareDesfire: RFID Card / Phone NFC - Mifare Desfire\n* nfc: Nearfield communication\n* noAccess: No access granted\n* overTheAir: Over the air according to ISO 15118\n* phoneDialog: phone (dialog with platform)\n* phoneSMS: Phone (SMS)\n* pinpad: PINPAD\n* plc: PLC according to ISO 15118\n* prepaidCard: Pre-Paid card\n* rfid: RFID\n* unlimitedAccess: No authentication/identification required.\n* 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\n(Part 13 §13.1a). The body is optional; `reason` is recorded on the\nlink'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`\n(Part 7 §7.2). Annotates the `statusHistory[]` entry the transition\nappends. 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\n`Command.agent`, Part 6 §6.1). When given it is recorded as the\nappended entry's `actor`; otherwise `actor` is the principal\nderived from the token. Attribution only: authorization is always\nthe 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 \nparking related or other purposes. \nIdentified 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.\n* allUsers: All users.\n* commuters: Commuters.\n* customers: Customers.\n* disabled: Physically impaired people.\n* elderlyUsers: Elderly users.\n* employees: Employees.\n* families: Families.\n* handicapped: Persons with deficiencies in their daily life.\n* hearingImpaired: People with difficulties to hear.\n* hotelGuests: Hotel guests.\n* longTermParkers: Long-term parker.\n* members: Members.\n* men: Men.\n* other: Other.\n* overnightParkers: Overnight parker.\n* parkAndCycleUser: Park and cycle user.\n* parkAndRideUsers: Users that are exchanging into public transport at a park and ride station.\n* parkAndWalkUser: Park and walk user.\n* pensioners: Pensioners.\n* pregnantWomen: Pregnant women.\n* registeredDisabledUsers: Registered disabled persons.\n* reservationHolders: Those who have a valid reservation, e.g. for the duration of parking.\n* residents: Local residents.\n* seasonTicketHolders: Season ticket holders.\n* shoppers: Shoppers.\n* shortTermParkers: Short-term parker.\n* sportEventAwaySupporters: Sport event away supporters.\n* sportEventHomeSupporters: Sport event home supporters.\n* staff: Staff.\n* students: Students.\n* subscribers: Subscribers.\n* unknown: Unknown.\n* visitors: Visitors.\n* visuallyImpaired: People with difficulties to see.\n* wheelchairUsers: Wheelchair users.\n* 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.\n* bikeParking: Bike parking.\n* cashMachine: Cash machine.\n* copyMachineOrService: A possibility to create copies of documents.\n* defibrillator: Medical equipment to provide first aid after heart attacks.\n* dsrcReceiver: A system to manage digital short range communication (radio beacon transceivers), e.g. for tolling roadside equipment.\n* dumpingStation: Possibility to get rid of sewerage (especially for motorhomes).\n* electricChargingStation: For charging vehicles, motorhome supply etc. The 'numberOf...' attribute specifies the number of charging stations.\n* elevator: Indication of the availability of elevators.\n* faxMachineOrService: A possibility to send and/or receive faxes.\n* fireExtinguisher: Fire extinguisher\n* fireHose: A hose for water transport in case of fire.\n* fireHydrant: Fire hydrant\n* firstAidEquipment: Equipment to support first aid on injured people. Note that 'defibrillator' is a separate literal.\n* iceFreeScaffold: A technical equipment to remove ice and snow from the roof of lorries.\n* informationPoint: An information point with employees.\n* informationStele: An unmanned information point.\n* internetTerminal: Public internet terminal. Charges may be specified using the TariffsAndPayment section.\n* internetWireless: Public wireless internet. Specifying an amount would be the number of hotspots/access points. Charges may be specified using the TariffsAndPayment section.\n* luggageLocker: Possibility to deposit luggage in a safe way.\n* none: None.\n* other: Some other equipment. Use 'otherSupplementalFacility' to specify it.\n* paymentMachine: A payment machine, for example a parking ticket machine.\n* picnicFacilities: Indication of whether any picnicking facilities, such as tables, chairs and shaded areas, are available.\n* playground: A playground for children.\n* publicCardPhone: Indicates, whether there's a public telephone available that can be used with a card.\n* publicCoinPhone: Indicates, whether there's a public telephone available that can be used with coins.\n* publicPhone: Indicates, whether there's a public telephone available.\n* refuseBin: Refuse bins for small amounts of garbage (see also 'wasteDisposal').\n* safeDeposit: A possibility to store valuable possession in a safe way. \n* shelter: A shelter (against wind, sun, ....).\n* shower: Indicates, whether there are shower facilities available.\n* snowAndIceRemovalEquipment: Equipment to remove snow and ice.nt\n* toilet: Indicates, whether there are toilets available.\n* tollTerminal: A terminal, where toll charges can be paid manually (this does not mean a toll gate on the road)\n* tyreAirPressureEquipment: Equipment to measure and refill tyre air pressure.\n* unknown: Unknown.\n* vendingMachine: A vending machine for snacks, coffee etc. (without manpower).\n* wasteDisposal: Possibility to get rid of waste in a legal way (e.g. for truckers or motorhomes). Normal refuse bins are not intended here.\n* waterBasin: A water basin to wash hands, clothes or dishes.\n* waterSupply: Supply of fresh water, e.g. for motorhomes.\n* 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.\n* gasGallonEquivalent: The amount of alternative fuel it takes to equal the energy content of one liquid gallon of gasoline. Used mostly in the US.\n* imperialGallon: Imperial Gallon (4.54609 litres)\n* kg: kilogram\n* kWh: kilowatt hour\n* litre: Litre\n* m3: cubic meter\n* 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.\n* mandatory: Reservation is mandatory.\n* notAvailable: Reservation is not possible.\n* optional: Reservation is optional.\n* partly: There is a specific contingent, that can be reserved.\n* unknown: Possibility of reservation is unknown,\n* 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.\n* fullService: Full fuelling service carried out by an employee.\n* selfService: Self Service for fuelling\n* 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\nstopped, where it was delivering, and the attempt that exhausted the\nschedule. 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):\nthe entity's identity plus only the members that changed. An absent\nmember is unchanged; an explicit `null` clears it. Nested objects that\ncarry their own `id` (a Session segment, say) follow the same rule.\n\nThis schema checks the envelope only (identity present, any member may\nbe null). Each member present is still validated by the server against\nthe class's native property schema, and a member the class does not\ndefine is refused with 400 (Part 5 §5.1a). It is the request schema of\na native `PUT` sent with `APX-Update-Mode: change`, and the shape of\nevery `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,\nPart 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\nto begin: a hostname.\n\n`GET /.well-known/apx-configuration` is unauthenticated and served at\nthe host root. It answers where to get a token, which optional\nconformance classes this server implements, and where its code-list\nregistries are published. `GET /v1/discovery` then answers the\nnarrower and more useful question: what can *this credential* do? The\ndocument it returns is the intersection of the server's classes with\nthe caller's scopes and place grants.\n\nDiscovery is **contractual, not advertising**: everything the document\nlists will work for the caller, and anything it omits will refuse with\na clean 403. That is what makes onboarding a new vendor a matter of\nissuing a credential rather than exchanging PDFs.\n\nWritten standard:\n[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.**\n\nThe data routes themselves are APDS 4.1's own, mounted verbatim:\n`/places`, `/sessions`, `/rates`, `/rights/specs`, `/rights/assigned`,\n`/observations`, `/contacts`, `/quotes`. APX invents nothing here on\npurpose, because data exchange is the part the industry already\nagreed on.\n\nWhat APX adds is a **profile** over those routes, all of it additive\nand invisible to a client that ignores it: full versus change update\nsemantics, tombstones for deletions, and a cursor-based change feed\nthat is ordered, gapless, and exactly-once, so a partner that goes\noffline for an hour replays precisely what it missed. Partial writes\nmake `null` mean *clear this field* and omission mean *leave it\nalone*, which retires the oldest bug in data integration.\n\nThe one net-new read here is the occupancy snapshot: how full a\ngarage, level, or zone is right now, without walking the whole Place\nhierarchy.\n\nTwo decorations on the APDS Session carry what other systems\ndecided about a stay: the pairing of reads behind it\n(`session-detail`), and the compliance outcome an engine scored for\nit (`stay-compliance`), which is served only under its own scope.\n\nWritten standard:\n[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\n4.1 `/webhooks` endpoint: stock APDS subscription bodies work here\nunmodified.\n\nWebhooks without rules are where integrations go to die, so the\ndelivery contract is normative rather than best-effort. Every delivery\nis one uniform envelope, HMAC-signed so the receiver can prove it is\ngenuine, carrying a stable event id so duplicates are detectable.\nFailed deliveries follow a published retry schedule before the\nsubscription is marked failed, which itself raises an alert. The\ndelivery ledger records every attempt and its result.\n\nSubscriptions filter by place and by severity, so a partner receives\nonly its own world, and an event whose place cannot be resolved is\ndropped rather than leaked. Server-sent events carry the same\nenvelopes for consumers that cannot host a public endpoint.\n\nWritten standard:\n[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,\nevent, or notification class.\n\nOne `Alert` resource covers the operational conditions an attendant or\na monitoring system acts on: a device fault, a blocked lane, a vehicle\nin a space it should not be, an occupancy threshold crossed, a payment\nexception. Alert *types* are an open vocabulary, seeded from the APDS\nuse-case exception list and extensible by any implementer through\ntheir own code list. Severity, by contrast, is a closed five-level\nscale, because filtering on it has to mean the same thing everywhere.\n\nThe lifecycle is raised, acknowledged, resolved, with an immutable\naudit of every transition.\n\nWritten standard:\n[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\naccess-controlled places but defines no actuation. This is it.\n\nEverything physical goes through one audited command plane rather than\nscattered verbs: vend a gate, hold it open, close a lane, issue a lost\nticket, push a rate table, apply a validation, set a device state,\ndisplay a message, restart a device. Commands are **idempotent** (a\nretry must not vend the gate twice), **perishable** (a vend requested\nten minutes ago must not fire now), and audited end to end.\n\nTwo optional features close open tickets at the exit lane without\ntouching the deck. **Negotiated rates:** a RateTable flagged\n`negotiable` (the `apds-ext:apx:ratepolicy@1.0` decoration, which\nrides with the table on every `/rates` sync) may be pushed to the\none car in the lane, and the command names the agent who chose it.\n**Ticket matching:** when no ticket is in the machine the lane\ninquiry offers the open sessions that plausibly belong to the\nvehicle — by plate read, credential, account phone, or reservation\n— and `matchTicket` binds the exit to the real entry, priced from\nthe real entry time, with the agent on the record. The lost-ticket\nfee becomes the fallback, not the default.\n\nThe response is deliberately not a success boolean. It is a command\nresource whose `confirmationLevel` distinguishes *accepted* from *the\ndevice acknowledged it* from *the outcome was physically verified*. A\nconsumer, an AI agent especially, must not claim a stronger outcome\nthan that level supports.\n\nAlso here: the lane inquiry that populates a call-center screen-pop,\nthe validation-provider list for a place, and live device status.\n\nWritten standard:\n[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,\nvoids and captures, accounting write-back, and payment history.\n\nAPDS models a `Payment` but not the *act* of taking one. The APX\n`PaymentRecord` is that action record: addressable, idempotent, and\nreconcilable, and every approved one is materialized as an APDS\nPayment so downstream APDS consumers see it without speaking APX.\n\nTwo rules shape this domain. Full card numbers never appear anywhere.\nAnd because one endpoint often fronts many facilities, every payment\nnames the place it belongs to, so revenue stays attributable and a\ngrant cannot leak across sites.\n\nAPDS publishes no payment events, which leaves financial analytics\nblind; APX closes that with a payment-recorded topic.\n\nWritten standard:\n[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\nstandard data route every integration already uses. No bespoke\ningestion API.\n\nThe genuinely new need is the **join**: which ticket goes with this\nplate, and which plate with this ticket. That is the one endpoint this\ndomain adds, answering with the session, the confidence score, and an\naccess-controlled image link.\n\nModern engines know more than a plate string, so a read may also carry\nper-attribute confidence for plate, state, make, model, colour and\nclass, the runner-up plate strings the engine rejected, how many\nframes and plates it read, which face of the vehicle it saw, and\nwhether the vehicle was moving toward the camera, away from it, or\nstopped. The LPR system then says what the read *was*: an **entry**\nor an **exit**. APX derives nothing — each lane's cameras, and which\nway each faces, are described on the lane, and a Session is simply\nthe entry and exit reads of one visit.\n\nWritten standard:\n[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\nrather than a parallel booking system.\n\nQuote through the APDS quote route, book by creating an\n`AssignedRight` carrying the APX reservation extension, amend and\ncancel through the same surface, and check in by linking the arrival\nto the right. The reservation is therefore a first-class APDS object\nany APDS consumer can read, not an APX-only record that has to be\nsynchronized.\n\nThe hard parts this domain pins down are the ones integrations usually\nget wrong: how a prepaid booking binds to the session the vehicle\nactually starts, what happens when the plate is misread, and when a\nno-show is declared.\n\nWritten standard:\n[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\nright-specification and right-pool model.\n\nThe cases that matter are the ones a naive implementation breaks on: a\npool that runs out, a household or company credential valid for\nseveral vehicles, and issuance that must stay attributable when\nallocations are audited later.\n\nWritten standard:\n[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.\n\nEverything is still built to APDS conventions. A toll point is\nequipment in the place hierarchy, the reads are native `Observation`s,\nmoney is the APDS amount shape, and settlement links a Payment\nreference. A transaction runs created, priced, paid, and a dispute can\nmove any non-voided transaction aside for resolution.\n\nCreation is idempotent, because gantries retry in storms.\n\nWritten standard:\n[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,\nshould not have to log into another system, find the facility, find\nthe lane, find the transaction, and reconstruct what happened.\n\nOne call assembles the context from whatever identifiers the caller\nhas: a phone number, a lane, a plate, a ticket, a credential, a\nreservation code. The server resolves every relationship it can and\ndoes not fail because some identifiers are missing.\n\nThe important design decision is that **the server, not the agent,\ndecides what may be done**. The context returns the allowed actions,\nalready evaluated against policy, including which ones require\nsupervisor approval. Writes then go through the existing command plane\nrather than a second one. A refund an agent should not offer is simply\nnot in the list.\n\nWritten standard:\n[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\nresolution context: who spoke to the customer, through which channel,\nabout what, and what was done.\n\nIt exists so the second call is not the first call again, and so an\naction taken during an interaction can be traced back to the\nconversation that prompted it.\n\nWritten standard:\n[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,\nand the one with the most legal exposure.\n\nOne `Violation` resource covers tickets, notices, and citations alike,\nthrough detection (automated, guided, or manual), review, issuance,\nsettlement by Payment reference, appeal, and void. Guided enforcement\nis supported by an eligibility check a handheld calls before an\nofficer writes anything, composed from the rights and sessions that\nremain authoritative.\n\nWhat makes this domain unusual is that **the law at the location is\ndata**. A per-place enforcement policy records which notice methods\nare lawful, the penalty cap, and the escalation schedule, and the\nserver enforces it: an issuance by a method the jurisdiction does not\npermit, past the notice deadline, above the cap, or at a place whose\nrequired signage was not posted, is refused. The posted signage itself\nis on file, with its text and photograph, as it stood at the moment of\nthe finding.\n\nWritten standard:\n[Part 19](https://github.com/rneubauer/apx/blob/main/docs/standard/19-violations.md)."
    },
    {
      "name": "Validations",
      "description": "**The merchant side**, from enrolment to invoice.\n\nThe lane-side act of applying a validation is a command in the control\nplane. This domain is everything around it: enrolling a merchant at a\nplace with a benefit and its rules, issuing instrument stock (codes,\nQR, stamps), the redemption ledger every channel writes to, and\nclosable billing statements.\n\nThe ledger is the point. A validation applied at a pay station, by an\nagent console, or through a merchant's own app lands in one place, so\nthe month-end statement is a query rather than a reconciliation.\nClosed statements are immutable, and a reversal after closing appears\nas a credit on the next one.\n\nA merchant-confined scope lets a venue check codes, issue its own\nstock, and read its own statements without seeing anyone else's.\n\nWritten standard:\n[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\npresented at a lane: issue, activate, suspend, resume, report lost,\nrevoke, replace, plus access-event history.\n\nThe rule that makes this domain worth having is **materialization**:\nan active credential record MUST appear on the holder's APDS assigned\nright, and MUST be removed when it is suspended, lost, revoked, or\nexpired. A lane that speaks only APDS therefore refuses the lost card\nat six o'clock because the office replaced it at noon. There is no\nsecond list to keep in sync.\n\nAPDS has no access events, so granted and denied presentations with\ntheir reasons are recorded here and published as a topic.\n\nWritten standard:\n[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\nrestriction flag.\n\nThe stay and the money remain the APDS session. What APDS has no words\nfor is who has the keys, where the car is, when it was asked for, who\nit was handed to, and what condition it was in. A ticket records\ndrop-off with a condition report (notes, per-panel damage entries,\nwalk-around photographs, and the customer's acknowledgement), the\nparked position and key location, the retrieval request and its ETA,\nstaging, and a verified handback.\n\nRetrieval works from a text, an app, a web page, a voice bot, a kiosk,\nor the stand, through one customer-facing scope confined to the\ncaller's own ticket and minimized so it exposes status and ETA but\nnever where the car or the keys are.\n\nThe acknowledged drop-off report is what answers \"that scratch wasn't\nthere\" a week later.\n\nWritten standard:\n[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\nactions in a call centre still happen in a vendor's portal in\nanother window, and the two systems never agree afterwards. A\nvendor will take years to implement every APX module, but it\nalready has good screens.\n\nA host opens one of those screens for an agent in two ways. In the\n**handshake**, it posts a launch with its normal APX token and gets\nback a single-use URL that logs the agent in, valid for sixty\nseconds, which also serves vendors who want header-based\nauthentication, since a browser cannot add headers to a page it\nopens. In the **signed-token** mode, the host signs a short-lived\ntoken and sends it to the vendor's launch address by form post or\nURL fragment.\n\nThe rule that makes this worth having is the **loopback**: whatever\nthe agent does in the screen MUST come back as the module's own\nresource or Command, carrying the launch's correlation id. Only when\nthe implementation has no APX operation for the action does it\nrecord a `UiActionRecord` instead, with the fields the host asked\nfor. Defined once; every module adds screens through the\n`apx-ui-surfaces` registry.\n\nWritten standard:\n[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\na system should be able to learn what a site has without data from\nany other system: which hardware is on each lane and what each\npiece does, what it is, what runs on it, where the cameras are and\nwhat they see, how a parker reaches help from each lane or door,\nand who to escalate to.\n\nAPDS already models the place, its lanes and its equipment. This\ndomain adds what APDS leaves open: a fixed list of **equipment\nroles** (gate, exit verifier, access door, camera, intercom…), the\nmake, model, firmware, serial and MAC of every unit, where it is by\n**area** and level, what it is built into and what it controls; a\n**camera** description for any camera on the site, with views\nissued as short-lived links so a password never leaves the site; a\n**comms point** for every way help is reached, whether an intercom,\nan analog dialer, a posted number or a QR code; typed **external\nids** so other systems' identifiers resolve to APX records;\n**display records**, the proof that a sign showed a message for a\nread or a stay, written by whichever system drove the sign; and\nchange topics so a copy of the setup stays current. IP addresses\nand SIP details are deliberately left out.\n\nWritten standard:\n[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"
      ]
    }
  ]
}
