| openapi: 3.0.1 | 
 | info: | 
 |    title: Eclipse Hono™ Device Registry API | 
 |    description: | | 
 |       This API defines how to manage *Tenants*, *Devices*, and *Credentials*. | 
 |       It acts as a common basis which all Hono device registries should | 
 |       implement. | 
 |  | 
 |       ## Required APIs | 
 |  | 
 |       All operations, except the `tenants` resource are required. The tenant | 
 |       management might be outside of the scope of the device registry and | 
 |       managed by a higher level system. In this case all calls should simply | 
 |       return `404`. However, if the `tenants` resource is implemented, then all | 
 |       operations of it must be implemented. | 
 |  | 
 |       ## Security | 
 |  | 
 |       This specification explicitly leaves out the part of authenticating and | 
 |       authorizing users with the device registry. It is assumed that some form | 
 |       of token exchange between the user agent and the backend service will | 
 |       take place. Like for example HTTP basic authentication, or a bearer token. | 
 |  | 
 |       ## Code generation | 
 |  | 
 |       This model is not optimized for generating code from it. Code generators | 
 |       try to understand the model and then translate this into the required | 
 |       programming language. Even if there would be no bugs in the code | 
 |       generators, that process would already only be an approximation. So | 
 |       this model focuses on the description of the API, and does not tweak | 
 |       the specification in a way to please code generators. | 
 |  | 
 |    contact: | 
 |       name: Contact details | 
 |       url: https://www.eclipse.org/hono/community/get-in-touch/ | 
 |    license: | 
 |       name: EPL-2.0 | 
 |       url: https://www.eclipse.org/legal/epl-2.0/ | 
 |    version: 1.9.0 | 
 |  | 
 | externalDocs: | 
 |    description: Eclipse Hono™ web page | 
 |    url: https://eclipse.org/hono | 
 |  | 
 | tags: | 
 |    - name: tenants | 
 |      description: Tenant Management (optional) | 
 |      externalDocs: | 
 |         description: Hono Multi-Tenancy | 
 |         url: https://www.eclipse.org/hono/docs/concepts/tenancy/ | 
 |    - name: devices | 
 |      description: Device registration | 
 |      externalDocs: | 
 |         description: Hono device identity | 
 |         url: https://www.eclipse.org/hono/docs/concepts/device-identity/ | 
 |    - name: credentials | 
 |      description: Device credentials | 
 |      externalDocs: | 
 |         description: Hono device identity | 
 |         url: https://www.eclipse.org/hono/docs/concepts/device-identity/ | 
 |  | 
 | servers: | 
 |    - url: '{server}/v1' | 
 |      variables: | 
 |         server: | 
 |            default: http://hono.eclipseprojects.io:28080 | 
 |            description: Hono Sandbox | 
 |  | 
 | security: | 
 |    - BearerAuth: [] | 
 |    - BasicAuth: [] | 
 |  | 
 | paths: | 
 |  | 
 | # Tenant API | 
 |  | 
 |    /tenants: | 
 |  | 
 |       post: | 
 |          tags: | 
 |             - tenants | 
 |          summary: Create a new tenant with an auto-generated ID | 
 |          description: | | 
 |             Clients use this operation to register a new tenant with an identifier that | 
 |             is generated by the registry. | 
 |          operationId: createTenant | 
 |          requestBody: | 
 |             description: The configuration properties to register for the tenant. | 
 |             content: | 
 |                application/json: | 
 |                   schema: | 
 |                      $ref: '#/components/schemas/Tenant' | 
 |                   examples: | 
 |                      default: | 
 |                         $ref: '#/components/examples/TenantAllAdaptersExample' | 
 |                      mqtt-only: | 
 |                         $ref: '#/components/examples/TenantMqttAdapterOnlyExample' | 
 |             required: false | 
 |          responses: | 
 |             201: | 
 |                $ref: '#/components/responses/Created' | 
 |             400: | 
 |                $ref: '#/components/responses/MalformedRequest' | 
 |             401: | 
 |                $ref: '#/components/responses/Unauthorized' | 
 |             403: | 
 |                $ref: '#/components/responses/NotAllowed' | 
 |             409: | 
 |                description: | | 
 |                   Indicates that an existing tenant uses a certificate authority with the same Subject DN. | 
 |                   If the client has no read access to the conflicting tenant then `403` should be returned instead. | 
 |                content: | 
 |                   application/json: | 
 |                      schema: | 
 |                         $ref: '#/components/schemas/Error' | 
 |                      example: | 
 |                         error: "Root Certificate Authority is already used by other tenant" | 
 |                         subject-dn: "CN=devices,OU=iot,O=ACME" | 
 |             413: | 
 |                $ref: '#/components/responses/RequestEntityTooLarge' | 
 |  | 
 |       get: | 
 |          tags: | 
 |             - tenants | 
 |          summary: Search tenants with optional filters, paging and sorting options. | 
 |          operationId: searchTenants | 
 |          parameters: | 
 |             - $ref: '#/components/parameters/pageSize' | 
 |             - $ref: '#/components/parameters/pageOffset' | 
 |             - $ref: '#/components/parameters/filterJson' | 
 |             - $ref: '#/components/parameters/sortJson' | 
 |          responses: | 
 |             200: | 
 |                description: operation successful | 
 |                content: | 
 |                   application/json: | 
 |                      schema: | 
 |                         $ref: '#/components/schemas/SearchTenantsResult' | 
 |             400: | 
 |                $ref: '#/components/responses/MalformedRequest' | 
 |             401: | 
 |                $ref: '#/components/responses/Unauthorized' | 
 |             404: | 
 |                $ref: '#/components/responses/NotFound' | 
 |  | 
 |    /tenants/{tenantId}: | 
 |  | 
 |       parameters: | 
 |          - $ref: '#/components/parameters/tenantId' | 
 |  | 
 |       post: | 
 |          tags: | 
 |             - tenants | 
 |          summary: Create a new tenant with a given ID | 
 |          description: | | 
 |             Clients use this operation to register a new tenant with a given identifier. | 
 |          operationId: createTenantWithId | 
 |          requestBody: | 
 |             description: The configuration properties to register for the tenant. | 
 |             content: | 
 |                application/json: | 
 |                   schema: | 
 |                      $ref: '#/components/schemas/Tenant' | 
 |                   examples: | 
 |                      default: | 
 |                         $ref: '#/components/examples/TenantAllAdaptersExample' | 
 |                      mqtt-only: | 
 |                         $ref: '#/components/examples/TenantMqttAdapterOnlyExample' | 
 |             required: false | 
 |          responses: | 
 |             201: | 
 |                $ref: '#/components/responses/Created' | 
 |             400: | 
 |                $ref: '#/components/responses/MalformedRequest' | 
 |             401: | 
 |                $ref: '#/components/responses/Unauthorized' | 
 |             403: | 
 |                $ref: '#/components/responses/NotAllowed' | 
 |             409: | 
 |                description: | | 
 |                   Indicates that a tenant with the given identifier already exists or that an existing tenant uses | 
 |                   a certificate authority with the same Subject DN. | 
 |                   If the client has no read access to the conflicting tenant then `403` should be returned instead. | 
 |                content: | 
 |                   application/json: | 
 |                      schema: | 
 |                         $ref: '#/components/schemas/Error' | 
 |                      example: | 
 |                         error: "tenant with given identifier already exists" | 
 |             413: | 
 |                $ref: '#/components/responses/RequestEntityTooLarge' | 
 |  | 
 |       get: | 
 |          tags: | 
 |             - tenants | 
 |          summary: Get tenant information | 
 |          description: | | 
 |             Clients use this operation to retrieve the configuration properties of an existing tenant. | 
 |          operationId: getTenant | 
 |          responses: | 
 |             200: | 
 |                description: operation successful | 
 |                content: | 
 |                   application/json: | 
 |                      schema: | 
 |                         $ref: '#/components/schemas/Tenant' | 
 |                      examples: | 
 |                         mqtt-only: | 
 |                            summary: Constrained tenant | 
 |                            description: | | 
 |                               The body contains the configuration properties of a tenant for which | 
 |                               some resource limits have been defined. | 
 |                            value: | | 
 |                               { | 
 |                                  "enabled": true, | 
 |                                  "resource-limits": { | 
 |                                     "max-connections": 1000, | 
 |                                     "max-ttl": 3600, | 
 |                                     "data-volume": { | 
 |                                        "effective-since": "2019-12-01T00:00:00Z", | 
 |                                        "max-bytes": 10000000, | 
 |                                        "period": { | 
 |                                           "mode": "monthly" | 
 |                                        } | 
 |                                     } | 
 |                                  } | 
 |                               } | 
 |                headers: | 
 |                   ETag: | 
 |                      description: Version of the resource | 
 |                      schema: | 
 |                         type: string | 
 |             400: | 
 |                $ref: '#/components/responses/MalformedRequest' | 
 |             401: | 
 |                $ref: '#/components/responses/Unauthorized' | 
 |             404: | 
 |                $ref: '#/components/responses/NotFound' | 
 |  | 
 |       put: | 
 |          tags: | 
 |             - tenants | 
 |          summary: Update tenant information | 
 |          description: | | 
 |             Clients use this operation to replace an existing tenant's registration information | 
 |             with the information contained in the request body. | 
 |          operationId: updateTenant | 
 |          parameters: | 
 |             - $ref: '#/components/parameters/resourceVersion' | 
 |          requestBody: | 
 |             description: The configuration properties to replace the tenant's existing configuration with. | 
 |             content: | 
 |                application/json: | 
 |                   schema: | 
 |                      $ref: '#/components/schemas/Tenant' | 
 |                   examples: | 
 |                      disable-tenant: | 
 |                         summary: Disable a tenant | 
 |                         description: | | 
 |                            Disabling a tenant effectively prevents any devices of that tenant | 
 |                            to connect to any of the protocol adapters. Devices that are | 
 |                            already connected to an adapter can no longer upload any data | 
 |                            nor receive any commands. Note that the example payload does | 
 |                            not contain any other properties than *enabled* which means | 
 |                            that all other configuration will be removed. | 
 |                         value: | | 
 |                            { | 
 |                               "enabled": false | 
 |                            } | 
 |             required: true | 
 |          responses: | 
 |             204: | 
 |                $ref: '#/components/responses/Updated' | 
 |             400: | 
 |                $ref: '#/components/responses/MalformedRequest' | 
 |             401: | 
 |                $ref: '#/components/responses/Unauthorized' | 
 |             403: | 
 |                $ref: '#/components/responses/NotAllowed' | 
 |             404: | 
 |                $ref: '#/components/responses/NotFound' | 
 |             409: | 
 |                description: | | 
 |                   Indicates that an existing tenant uses a certificate authority with the same Subject DN. | 
 |                   If the client has no read access to the conflicting tenant then `403` should be returned instead. | 
 |                content: | 
 |                   application/json: | 
 |                      schema: | 
 |                         $ref: '#/components/schemas/Error' | 
 |                      example: | 
 |                         error: "Root Certificate Authority is already used by other tenant" | 
 |                         subject-dn: "CN=devices,OU=iot,O=ACME" | 
 |             412: | 
 |                $ref: '#/components/responses/ResourceVersionMismatch' | 
 |             413: | 
 |                $ref: '#/components/responses/RequestEntityTooLarge' | 
 |  | 
 |       delete: | 
 |          tags: | 
 |             - tenants | 
 |          summary: Delete tenant | 
 |          description: | | 
 |             Clients use this operation to remove an existing tenant from the registry. | 
 |  | 
 |             When the operation succeeds, the data owned by this tenant (including devices and their | 
 |             credentials) must no longer be accessible. These entities should be reported as *not found*. | 
 |          operationId: deleteTenant | 
 |          parameters: | 
 |             - $ref: '#/components/parameters/resourceVersion' | 
 |          responses: | 
 |             204: | 
 |                $ref: '#/components/responses/Deleted' | 
 |             401: | 
 |                $ref: '#/components/responses/Unauthorized' | 
 |             403: | 
 |                $ref: '#/components/responses/NotAllowed' | 
 |             404: | 
 |                $ref: '#/components/responses/NotFound' | 
 |             412: | 
 |                $ref: '#/components/responses/ResourceVersionMismatch' | 
 |  | 
 | # Device API | 
 |  | 
 |    /devices/{tenantId}: | 
 |  | 
 |       parameters: | 
 |          - $ref: '#/components/parameters/tenantId' | 
 |  | 
 |       post: | 
 |          tags: | 
 |             - devices | 
 |          summary: Create a new device registration with auto-generated ID | 
 |          description: | | 
 |             Clients use this operation to register a new device for an existing tenant with | 
 |             an identifier that is generated by the registry. | 
 |          operationId: createDeviceRegistration | 
 |          requestBody: | 
 |             description: The configuration properties to register for the device. | 
 |             content: | 
 |                application/json: | 
 |                   schema: | 
 |                      $ref: '#/components/schemas/Device' | 
 |                   examples: | 
 |                      default: | 
 |                         $ref: '#/components/examples/DeviceDefaultExample' | 
 |                      extensions: | 
 |                         $ref: '#/components/examples/DeviceExtExample' | 
 |             required: false | 
 |          responses: | 
 |             201: | 
 |                $ref: '#/components/responses/Created' | 
 |             400: | 
 |                $ref: '#/components/responses/MalformedRequest' | 
 |             401: | 
 |                $ref: '#/components/responses/Unauthorized' | 
 |             403: | 
 |                $ref: '#/components/responses/NotAllowed' | 
 |             404: | 
 |                $ref: '#/components/responses/TenantNotFound' | 
 |             413: | 
 |                $ref: '#/components/responses/RequestEntityTooLarge' | 
 |  | 
 |       get: | 
 |          tags: | 
 |             - devices | 
 |          summary: Search devices for a tenant with optional filters, paging and sorting options. | 
 |          operationId: searchDevicesForTenant | 
 |          parameters: | 
 |             - $ref: '#/components/parameters/pageSize' | 
 |             - $ref: '#/components/parameters/pageOffset' | 
 |             - $ref: '#/components/parameters/filterJson' | 
 |             - $ref: '#/components/parameters/sortJson' | 
 |          responses: | 
 |             200: | 
 |                description: operation successful | 
 |                content: | 
 |                   application/json: | 
 |                      schema: | 
 |                         $ref: '#/components/schemas/SearchDevicesResult' | 
 |             400: | 
 |                $ref: '#/components/responses/MalformedRequest' | 
 |             401: | 
 |                $ref: '#/components/responses/Unauthorized' | 
 |             404: | 
 |                $ref: '#/components/responses/NotFound' | 
 |  | 
 |    /devices/{tenantId}/{deviceId}: | 
 |  | 
 |       parameters: | 
 |          - $ref: '#/components/parameters/tenantId' | 
 |          - $ref: '#/components/parameters/deviceId' | 
 |  | 
 |       post: | 
 |          tags: | 
 |             - devices | 
 |          summary: Create a new device registration | 
 |          description: | | 
 |             Clients use this operation to register a new device for an existing tenant with | 
 |             a given identifier | 
 |          operationId: createDeviceRegistrationWithId | 
 |          requestBody: | 
 |             description: The configuration properties to register for the device. | 
 |             content: | 
 |                application/json: | 
 |                   schema: | 
 |                      $ref: '#/components/schemas/Device' | 
 |                   examples: | 
 |                      default: | 
 |                         $ref: '#/components/examples/DeviceDefaultExample' | 
 |                      extensions: | 
 |                         $ref: '#/components/examples/DeviceExtExample' | 
 |             required: false | 
 |          responses: | 
 |             201: | 
 |                $ref: '#/components/responses/Created' | 
 |             400: | 
 |                $ref: '#/components/responses/MalformedRequest' | 
 |             401: | 
 |                $ref: '#/components/responses/Unauthorized' | 
 |             403: | 
 |                $ref: '#/components/responses/NotAllowed' | 
 |             409: | 
 |                $ref: '#/components/responses/AlreadyExists' | 
 |             404: | 
 |                $ref: '#/components/responses/TenantNotFound' | 
 |             413: | 
 |                $ref: '#/components/responses/RequestEntityTooLarge' | 
 |  | 
 |       get: | 
 |          tags: | 
 |             - devices | 
 |          summary: Get device registration information | 
 |          description: | | 
 |             Clients use this operation to retrieve the configuration properties of an existing device. | 
 |          operationId: getRegistration | 
 |          responses: | 
 |             200: | 
 |                description: operation successful | 
 |                content: | 
 |                   application/json: | 
 |                      schema: | 
 |                         $ref: '#/components/schemas/Device' | 
 |                      examples: | 
 |                         fully-configured: | 
 |                            summary: Fully configured device | 
 |                            description: | | 
 |                               The body contains the configuration properties of a device which | 
 |                               has been configured extensively. | 
 |                            value: | | 
 |                               { | 
 |                                  "enabled": true, | 
 |                                  "defaults": { | 
 |                                     "ttl": 300, | 
 |                                     "content-type": "application/vnd.acme+json" | 
 |                                  }, | 
 |                                  "via": [ | 
 |                                     "gw-1", "gw-4" | 
 |                                  ], | 
 |                                  "status": { | 
 |                                     "created": "2019-10-03T13:45:16Z" | 
 |                                     "updated": "2020-05-04T10:11:12Z" | 
 |                                     "last-user": "Bob", | 
 |                                     "autoProvisioned": false, | 
 |                                     "autoProvisioningNotificationSent": false | 
 |                                  } | 
 |                                  "ext": { | 
 |                                     "manufacturer": "ACME", | 
 |                                     "model-no": "TEMP-SEN", | 
 |                                     "serial-no": "3435A-454" | 
 |                                  } | 
 |                               } | 
 |                headers: | 
 |                   ETag: | 
 |                      description: Version of the resource | 
 |                      schema: | 
 |                         type: string | 
 |             400: | 
 |                $ref: '#/components/responses/MalformedRequest' | 
 |             401: | 
 |                $ref: '#/components/responses/Unauthorized' | 
 |             404: | 
 |                $ref: '#/components/responses/NotFound' | 
 |  | 
 |       put: | 
 |          tags: | 
 |             - devices | 
 |          summary: Update an existing device registration | 
 |          description: | | 
 |             Clients use this operation to replace an existing device's registration information | 
 |             with the information contained in the request body. | 
 |          operationId: updateRegistration | 
 |          parameters: | 
 |             - $ref: '#/components/parameters/resourceVersion' | 
 |          requestBody: | 
 |             description: The configuration properties to replace the device's existing configuration with. | 
 |             content: | 
 |                application/json: | 
 |                   schema: | 
 |                      $ref: '#/components/schemas/Device' | 
 |                   examples: | 
 |                      disable-device: | 
 |                         summary: Disable a device | 
 |                         description: | | 
 |                            Disabling a device effectively prevents the device | 
 |                            to connect to any of the protocol adapters. If the device is | 
 |                            already connected to an adapter then it can no longer upload | 
 |                            any data nor receive any commands. Note that the example payload does | 
 |                            not contain any other properties than *enabled* which means | 
 |                            that all other configuration will be removed. | 
 |                         value: | | 
 |                            { | 
 |                               "enabled": false | 
 |                            } | 
 |             required: true | 
 |          responses: | 
 |             204: | 
 |                $ref: '#/components/responses/Updated' | 
 |             400: | 
 |                $ref: '#/components/responses/MalformedRequest' | 
 |             401: | 
 |                $ref: '#/components/responses/Unauthorized' | 
 |             403: | 
 |                $ref: '#/components/responses/NotAllowed' | 
 |             404: | 
 |                $ref: '#/components/responses/NotFound' | 
 |             412: | 
 |                $ref: '#/components/responses/ResourceVersionMismatch' | 
 |             413: | 
 |                $ref: '#/components/responses/RequestEntityTooLarge' | 
 |  | 
 |       delete: | 
 |          tags: | 
 |             - devices | 
 |          summary: Delete an existing device registration | 
 |          description: | | 
 |             Clients use this operation to remove an existing device from the registry. | 
 |  | 
 |             When the operation succeeds, the data owned by this device (including its credentials) | 
 |             must no longer be accessible. These entities should be reported as *not found*. | 
 |          operationId: deleteRegistration | 
 |          parameters: | 
 |             - $ref: '#/components/parameters/resourceVersion' | 
 |          responses: | 
 |             204: | 
 |                $ref: '#/components/responses/Deleted' | 
 |             401: | 
 |                $ref: '#/components/responses/Unauthorized' | 
 |             403: | 
 |                $ref: '#/components/responses/NotAllowed' | 
 |             404: | 
 |                $ref: '#/components/responses/NotFound' | 
 |             412: | 
 |                $ref: '#/components/responses/ResourceVersionMismatch' | 
 |  | 
 |    /credentials/{tenantId}/{deviceId}: | 
 |  | 
 |       parameters: | 
 |          - $ref: '#/components/parameters/tenantId' | 
 |          - $ref: '#/components/parameters/deviceId' | 
 |  | 
 |       get: | 
 |          tags: | 
 |             - credentials | 
 |          summary: Gets a device's set of credentials. | 
 |          description: | | 
 |             Clients use this operation to retrieve the set of credentials registered for an existing device. | 
 |             Hono's protocol adapters use the credentials registered for a device in order to | 
 |             authenticate the device when it connects to an adapter. | 
 |             Implementors may return all of the credentials' data including all | 
 |             details of its secrets like password hash and/or hash algortihm used. | 
 |             This mode of operation is called *replace mode*. However, this behavior is | 
 |             discouraged because it might disclose confidential information in plain text. | 
 |  | 
 |             Instead, implementors should remove all confidential information from the secrets | 
 |             and include a (unique) identifier with each secret. Clients can then refer to | 
 |             this identifier in order to update particular secrets. This mode of operation | 
 |             is called *patch mode*. | 
 |          operationId: getAllCredentials | 
 |          responses: | 
 |             200: | 
 |                description: Operation successful | 
 |                content: | 
 |                   application/json: | 
 |                      schema: | 
 |                         $ref: '#/components/schemas/CredentialsSet' | 
 |                      examples: | 
 |                         meta-data: | 
 |                            $ref: '#/components/examples/CredentialsMetaDataExample' | 
 |                headers: | 
 |                   ETag: | 
 |                      description: Version of the resource | 
 |                      schema: | 
 |                         type: string | 
 |             400: | 
 |                $ref: '#/components/responses/MalformedRequest' | 
 |             401: | 
 |                $ref: '#/components/responses/Unauthorized' | 
 |             404: | 
 |                $ref: '#/components/responses/DeviceNotFound' | 
 |  | 
 |       put: | 
 |          tags: | 
 |             - credentials | 
 |          summary: Updates a device's credentials. | 
 |          description: | | 
 |             A client uses this operation to update a device's existing set of credentials | 
 |             with the credentials contained in the request body. | 
 |  | 
 |             A registry may run in one of two modes for updating credentials, *replace mode* | 
 |             or *patch mode*. A client can determine the mode of operation by means of inspecting | 
 |             any of the secrets returned by the *getAllCredentials* operation. If the secrets | 
 |             do not contain an `id` property, then the registry uses *replace mode*, otherwise | 
 |             it operates in *patch mode*. | 
 |  | 
 |             In replace mode the registry simply replaces a device's existing set of credentials | 
 |             with the credentials provided in the request body. | 
 |  | 
 |             In patch mode the registry processes the set of updated credentials provided in the | 
 |             request body as follows. | 
 |             1. Start with an empty set `N` of new credentials. | 
 |             1. For each updated credentials object `c-U` contained in the request body, | 
 |                the registry looks up an existing credentials object `c-E` of the same device ID, type | 
 |                and authentication identifier. | 
 |                1. If no matching credentials object exists, `c-U` is added to the set of new | 
 |                   credentials `N`. | 
 |                1. Otherwise, `c-E` is patched over with `c-U` as follows. For each of `c-U`'s | 
 |                   secrets `s-U` the registry does the following | 
 |                   1. If `s-U` has no `id` property, the registry assigns a unique identifier to `s-U`. | 
 |                   1. Otherwise, the registry tries to find a secret `s-E` with the same identifier as `s-U` | 
 |                      among the secrets of `c-E`. | 
 |                      1. If no matching secret exists, updating the credentials has failed and the registry | 
 |                         returns a response with status 400 (Bad Request). | 
 |                      1. Otherwise the confidential properties of `s-E` are merged into `s-U` | 
 |                         with the property values of `s-U` taking precedence. | 
 |                1. `c-U` is added to `N`. | 
 |             1. The registry replaces the device's existing set of credentials with `N` and returns an | 
 |                empty response with status code 204 (No Content) to indicate the successful outcome of the | 
 |                operation. | 
 |  | 
 |                Note that `N` does not contain any of the existing credentials objects `c-E` for which | 
 |                no corresponding credentials object `c-U` with the same device ID, type and authentication | 
 |                identifier exists. This way, existing credentials can be deleted. | 
 |          operationId: setAllCredentials | 
 |          parameters: | 
 |             - $ref: '#/components/parameters/resourceVersion' | 
 |          requestBody: | 
 |             content: | 
 |                application/json: | 
 |                   schema: | 
 |                      $ref: '#/components/schemas/CredentialsSet' | 
 |                   examples: | 
 |                      set-password: | 
 |                         $ref: '#/components/examples/CredentialsSetPasswordExample' | 
 |                      change-password: | 
 |                         $ref: '#/components/examples/CredentialsChangePasswordExample' | 
 |             required: true | 
 |          responses: | 
 |             204: | 
 |                $ref: '#/components/responses/Updated' | 
 |             400: | 
 |                $ref: '#/components/responses/MalformedRequest' | 
 |             401: | 
 |                $ref: '#/components/responses/Unauthorized' | 
 |             403: | 
 |                $ref: '#/components/responses/NotAllowed' | 
 |             404: | 
 |                $ref: '#/components/responses/DeviceNotFound' | 
 |             409: | 
 |                $ref: '#/components/responses/AlreadyExists' | 
 |             412: | 
 |                $ref: '#/components/responses/ResourceVersionMismatch' | 
 |             413: | 
 |                $ref: '#/components/responses/RequestEntityTooLarge' | 
 |  | 
 | components: | 
 |  | 
 |    schemas: | 
 |  | 
 | # Common schema | 
 |  | 
 |       Error: | 
 |          type: object | 
 |          additionalProperties: true | 
 |          required: | 
 |             - error | 
 |          properties: | 
 |             "error": | 
 |                type: string | 
 |                description: A human readable error message of what went wrong. | 
 |  | 
 |       DefaultProperties: | 
 |          type: object | 
 |          additionalProperties: true | 
 |          description: Defaults for properties defined on the tenant and device level. | 
 |  | 
 |       Extensions: | 
 |          type: object | 
 |          additionalProperties: true | 
 |          description: Allows arbitrary properties as extension to the ones | 
 |                       specified by the Hono API. | 
 |  | 
 |       # Tenant schema | 
 |  | 
 |       Tenant: | 
 |          type: object | 
 |          additionalProperties: false | 
 |          properties: | 
 |             "enabled": | 
 |                type: boolean | 
 |                default: true | 
 |             "ext": | 
 |                $ref: '#/components/schemas/Extensions' | 
 |             "adapters": | 
 |                type: array | 
 |                description: | | 
 |                   A list of configuration options for certain types of protocol adapters. | 
 |                   If set then the array must not be empty. | 
 |                   Multiple entries for the same type are considered an error. | 
 |                   If not set, then all adapters are enabled using their respective | 
 |                   default configuration. | 
 |                items: | 
 |                   $ref: '#/components/schemas/Adapter' | 
 |             "defaults": | 
 |                $ref: '#/components/schemas/DefaultProperties' | 
 |             "minimum-message-size": | 
 |                type: integer | 
 |                default: 0 | 
 |                description: | | 
 |                   The minimum message size in bytes. If set, then reported size of | 
 |                   telemetry, event and command messages is calculated as the minimum multiple | 
 |                   of the configured value that is greater than or equal to the messages | 
 |                   payload size. | 
 |             "registration-limits": | 
 |                $ref: '#/components/schemas/RegistrationLimits' | 
 |             "resource-limits": | 
 |                $ref: '#/components/schemas/ResourceLimit' | 
 |             "tracing": | 
 |                $ref: '#/components/schemas/TracingConfig' | 
 |             "trusted-ca": | 
 |                type: array | 
 |                description: | | 
 |                   The set of root certificate authorities which are used for verifying the signature of | 
 |                   client certificates that devices use for authentication. | 
 |                items: | 
 |                   $ref: '#/components/schemas/TrustedCA' | 
 |  | 
 |       TenantWithId: | 
 |          type: object | 
 |          additionalProperties: false | 
 |          allOf: | 
 |             - type: object | 
 |               properties: | 
 |                  "id": | 
 |                     description: The identifier of the tenant. | 
 |                     type: string | 
 |             - $ref: '#/components/schemas/Tenant' | 
 |  | 
 |       TrustedCA: | 
 |          type: object | 
 |          additionalProperties: false | 
 |          properties: | 
 |             "id": | 
 |                type: string | 
 |                required: false | 
 |                description: | | 
 |                   The identifier of the trust anchor. This identifier must be unique | 
 |                   among a tenant's trust anchors. If this property is not provided, | 
 |                   then the device registry assigns a unique identifier. | 
 |                example: A user provided identifier could look like "DEFAULT_TENANT_CA_2021_2022". | 
 |             "subject-dn": | 
 |                type: string | 
 |                description: | | 
 |                   The subject DN of the trusted root certificate in | 
 |                   the format defined by [RFC 2253](https://tools.ietf.org/html/rfc2253#section-2). | 
 |                   CAs of the *same* tenant may share the same subject DN, for example | 
 |                   allowing for the definition of overlapping validity periods. | 
 |                   However, CAs of *different* tenants must not share the same | 
 |                   subject DN in order to allow for the unique look up of a tenant by | 
 |                   the subject DN of one of its trusted CAs. | 
 |                   If the `cert` property is used to provide an X.509 certificate | 
 |                   then the subject DN is determined from the certificate and this | 
 |                   property is ignored. | 
 |                   Otherwise, if the `public-key` property is | 
 |                   used, this property is mandatory. | 
 |             "public-key": | 
 |                type: string | 
 |                format: byte | 
 |                description: | | 
 |                   The Base64 encoded binary DER encoding of the | 
 |                   trusted root certificate’s public key. | 
 |                   If the `cert` property is used to provide an | 
 |                   X.509 certificate then the public key is extracted | 
 |                   from the certificate and this property is ignored. | 
 |                   Either this property or `cert` must be set. | 
 |             "algorithm": | 
 |                type: string | 
 |                description: | | 
 |                   The algorithm used for the public key of the CA. | 
 |                   If the `cert` property is used to provide an | 
 |                   X.509 certificate then the algorithm is determined | 
 |                   from the certificate and this property is ignored. | 
 |                   Otherwise, if the `public-key` property is | 
 |                   used, this property must be set to the algorithm | 
 |                   used, if other than the default. | 
 |                default: RSA | 
 |                example: EC | 
 |             "not-before": | 
 |                type: string | 
 |                format: date-time | 
 |                description: | | 
 |                   The point in time from which on the certificate authority | 
 |                   may be used for authenticating devices. | 
 |                   If the `cert` property is used to provide an | 
 |                   X.509 certificate then the point in time is | 
 |                   determined from the certificate and this property is ignored. | 
 |                   Otherwise, if the `public-key` property is | 
 |                   used, this property is mandatory. | 
 |                   NB: The value MUST be a string that complies with the format defined in | 
 |                   [RFC 3339](https://tools.ietf.org/html/rfc3339#section-5.6) as indicated | 
 |                   by the [date-time](https://spec.openapis.org/oas/v3.0.1#dataTypeFormat) | 
 |                   format in the OpenAPI specification. | 
 |             "not-after": | 
 |                type: string | 
 |                format: date-time | 
 |                description: | | 
 |                   The point in time until which the certificate authority | 
 |                   may be used for authenticating devices. | 
 |                   If the `cert` property is used to provide an | 
 |                   X.509 certificate then the point in time is | 
 |                   determined from the certificate and this property is ignored. | 
 |                   Otherwise, if the `public-key` property is | 
 |                   used, this property is mandatory. | 
 |                   NB: The value MUST be a string that complies with the format defined in | 
 |                   [RFC 3339](https://tools.ietf.org/html/rfc3339#section-5.6) as indicated | 
 |                   by the [date-time](https://spec.openapis.org/oas/v3.0.1#dataTypeFormat) | 
 |                   format in the OpenAPI specification. | 
 |             "cert": | 
 |                type: string | 
 |                format: byte | 
 |                description: | | 
 |                   The Base64 encoded binary DER encoding of the trusted X.509 root certificate. | 
 |                   This property can be used as a convenient alternative to | 
 |                   specifying the `public-key`, `not-before`, `not-after` and | 
 |                   `algorithm` properties explicitly. Implementors of this | 
 |                   API may choose to support this property only for uploading | 
 |                   a certificate but then extract all relevant data and store | 
 |                   it in the properties described above. | 
 |                   Either this property or `public-key` must be set. | 
 |             "auto-provisioning-enabled": | 
 |                type: boolean | 
 |                default: false | 
 |                description: | | 
 |                   Indicates whether this trusted certificate may be used for automatically provisioning devices. | 
 |                   If it is *true* and the feature is supported by the device registry, the device registry | 
 |                   automatically provisions unregistered devices that authenticate with a client certificate | 
 |                   issued by this CA (that is, creates registration and credentials). | 
 |             "auto-provision-as-gateway": | 
 |                type: boolean | 
 |                default: false | 
 |                description: | | 
 |                   Indictates whether this trusted certificate authority may be used for automatically provisioning  | 
 |                   gateways. If it is *true* and the *auto-provisioning-enabled* is also *true*, then the unregistered | 
 |                   devices that authenticate with a client certificate issued by this CA are provisioned as gateways | 
 |                   provided that the device registry implementation being used supports this feature. | 
 |             "auto-provisioning-device-id-template": | 
 |                type: string | 
 |                required: false | 
 |                description: | | 
 |                   Specifies the template to use by the device registry to generate the `device-id` during  | 
 |                   auto-provisioning of devices and gateways. The placeholders `{{subject-dn}}` and `{{subeject-cn}}`  | 
 |                   are currently supported. The template MUST contain at least one of these placeholders. The `device-id` | 
 |                   is generated by the device registry by replacing any placeholders in the template string with their | 
 |                   corresponding *Subject DN* or *Common Name* from the client certificate used for authentication by  | 
 |                   unregistered devices and gateways. The *Subject DN* is formatted according to the rules defined in  | 
 |                   [RFC 2253](https://tools.ietf.org/html/rfc2253#section-2). | 
 |  | 
 |          example: | 
 |             subject-dn: "CN=devices,OU=iot,O=ACME" | 
 |             public-key: "Tk9UIEEgUFVCTElDIEtFWQ==" | 
 |             algorithm: "EC" | 
 |             auto-provisioning-enabled: true | 
 |             auto-provision-as-gateway: false | 
 |             auto-provisioning-device-id-template: "device-{{subject-dn}}" | 
 |             not-before: "2019-10-03T13:45:16+02:00" | 
 |             not-after: "2021-10-03T00:00:00Z" | 
 |  | 
 |       Adapter: | 
 |          type: object | 
 |          additionalProperties: true | 
 |          required: | 
 |             - type | 
 |          properties: | 
 |             "type": | 
 |                type: string | 
 |             "enabled": | 
 |                type: boolean | 
 |                default: false | 
 |             "device-authentication-required": | 
 |                type: boolean | 
 |                default: true | 
 |             "ext": | 
 |                $ref: '#/components/schemas/Extensions' | 
 |  | 
 |       RegistrationLimits: | 
 |          type: object | 
 |          additionalProperties: false | 
 |          properties: | 
 |             "max-devices": | 
 |                type: integer | 
 |                default: -1 | 
 |                description: | | 
 |                   The maximum number of devices that can be registered for a tenant. | 
 |                   A value of `-1` (the default) indicates that no limit is set. | 
 |             "max-credentials-per-device": | 
 |                type: integer | 
 |                default: -1 | 
 |                description: | | 
 |                   The maximum number of credentials that can be registered for a device. | 
 |                   A value of `-1` (the default) indicates that no limit is set. | 
 |  | 
 |       ResourceLimit: | 
 |          type: object | 
 |          additionalProperties: false | 
 |          properties: | 
 |             "max-connections": | 
 |                type: integer | 
 |                default: -1 | 
 |                description: | | 
 |                   The maximum number of concurrent connections allowed from devices of this tenant. | 
 |                   A value of `-1` (the default) indicates that no limit is set. | 
 |             "max-ttl": | 
 |                type: integer | 
 |                default: -1 | 
 |                description: | | 
 |                   The maximum time-to-live (in seconds) to use for events published by | 
 |                   devices of this tenant. Any default TTL value specified | 
 |                   at either the tenant or device level will be limited to | 
 |                   the max value specified here. | 
 |                   If this property is set to a value greater than -1 and no | 
 |                   default TTL is specified for a device, the max value will | 
 |                   be used for events published by the device. | 
 |                   A value of `-1` (the default) indicates that no limit is set. | 
 |                   Note that this property contains the TTL in seconds whereas | 
 |                   the AMQP 1.0 specification defines a message's ttl header | 
 |                   to use milliseconds. | 
 |             "data-volume": | 
 |                $ref: '#/components/schemas/DataVolume' | 
 |             "connection-duration": | 
 |                $ref: '#/components/schemas/ConnectionDuration' | 
 |             "ext": | 
 |                $ref: '#/components/schemas/Extensions' | 
 |  | 
 |       TracingConfig: | 
 |          type: object | 
 |          additionalProperties: false | 
 |          properties: | 
 |             "sampling-mode": | 
 |                type: string | 
 |                description: | | 
 |                   Defines if and how often OpenTracing spans are being | 
 |                   sampled when processing messages for this tenant. | 
 |                   The value `default` indicates that the underyling tracing | 
 |                   system's default sampling mode should be used. | 
 |                   The value `all` indicates that every span created for | 
 |                   messages of the tenant will be sampled. | 
 |                   The value `none` indicates that no spans should be sampled | 
 |                   at all for the tenant. | 
 |                   The mode defined here may be overridden for specific | 
 |                   devices by means of the `sampling-mode-per-auth-id` | 
 |                   property. | 
 |                default: default | 
 |                enum: | 
 |                   - default | 
 |                   - all | 
 |                   - none | 
 |             "sampling-mode-per-auth-id": | 
 |                type: object | 
 |                description: | | 
 |                   Defines if and how often OpenTracing spans are being | 
 |                   sampled when processing messages for specific devices | 
 |                   of this tenant. | 
 |                   This object contains a property for each device for which | 
 |                   specific behavior should be defined, using the device's | 
 |                   authentication identifier as the property name and | 
 |                   the device specific sampling mode as its value. | 
 |                   The value `default` indicates that the underyling tracing | 
 |                   system's default sampling mode should be used. | 
 |                   The value `all` indicates that every span created for | 
 |                   messages of the tenant will be sampled. | 
 |                   The value `none` indicates that no spans should be sampled | 
 |                   at all for the tenant. | 
 |                   The mode defined for a particular device has precedence | 
 |                   over the value defined by the `sampling-mode` property. | 
 |                additionalProperties: | 
 |                   type: string | 
 |                   description: | | 
 |                     The property name is the device's 'authentication identifier. | 
 |                   default: default | 
 |                   enum: | 
 |                      - default | 
 |                      - all | 
 |                      - none | 
 |  | 
 |       DataVolume: | 
 |          type: object | 
 |          additionalProperties: false | 
 |          required: | 
 |             - effective-since | 
 |          properties: | 
 |             "effective-since": | 
 |                type: string | 
 |                format: date-time | 
 |                description: | | 
 |                   The point in time at which the data volume limit came into effect. | 
 |                   NB: The value MUST be a string that complies with the format defined in | 
 |                   [RFC 3339](https://tools.ietf.org/html/rfc3339#section-5.6) as indicated | 
 |                   by the [date-time](https://spec.openapis.org/oas/v3.0.1#dataTypeFormat) | 
 |                   format in the OpenAPI specification. | 
 |             "max-bytes": | 
 |                type: integer | 
 |                default: -1 | 
 |                description: The maximum amount of data (in bytes) that all of the tenant's devices together may | 
 |                             transfer to and/or receive from protocol adapters during each accounting period. | 
 |                             A value of `-1` (the default) indicates that no limit is set. | 
 |             "period": | 
 |                $ref: '#/components/schemas/Period' | 
 |  | 
 |       ConnectionDuration: | 
 |          type: object | 
 |          additionalProperties: false | 
 |          required: | 
 |             - effective-since | 
 |          properties: | 
 |             "effective-since": | 
 |                type: string | 
 |                format: date-time | 
 |                description: | | 
 |                   The point in time at which the connection duration limit came into effect. | 
 |                   NB: The value MUST be a string that complies with the format defined in | 
 |                   [RFC 3339](https://tools.ietf.org/html/rfc3339#section-5.6) as indicated | 
 |                   by the [date-time](https://spec.openapis.org/oas/v3.0.1#dataTypeFormat) | 
 |                   format in the OpenAPI specification. | 
 |             "max-minutes": | 
 |                type: integer | 
 |                default: -1 | 
 |                description: | | 
 |                  The maximum amount of time (in minutes) that all of the tenant's devices together may | 
 |                  be connected to a protocol adapter during each accounting period. | 
 |                  A value of `-1` (the default) indicates that no limit is set. | 
 |             "period": | 
 |                $ref: '#/components/schemas/Period' | 
 |  | 
 |       Period: | 
 |          type: object | 
 |          additionalProperties: false | 
 |          required: | 
 |             - mode | 
 |          properties: | 
 |             "mode": | 
 |                type: string | 
 |                description: | | 
 |                  The accounting period's mode of recurrence. The following modes are defined: | 
 |                  * `monthly`: Accounting periods start at midnight (start of day) UTC on the 1st day of each month. | 
 |                  * `days`: Accounting periods start at the time of the initial accounting period every *N* days where | 
 |                            *N* is the value of the *no-of-days* property. | 
 |  | 
 |                  The initial accounting period always starts at the point in time that the plan was put in effect at. | 
 |                  Implementations MUST support the *monthly* and *days* modes and MAY support additional custom modes. | 
 |             "no-of-days": | 
 |                type: integer | 
 |                minimum: 1 | 
 |                description: The accounting period length in days. This property is only used if *mode* is set to value | 
 |                             `days`. Otherwise, this property is ignored. | 
 |                 | 
 | # Devices schema | 
 |  | 
 |       Device: | 
 |          type: object | 
 |          additionalProperties: false | 
 |          properties: | 
 |             "enabled": | 
 |                type: boolean | 
 |                default: true | 
 |             "defaults": | 
 |                $ref: '#/components/schemas/DefaultProperties' | 
 |             "via": | 
 |                type: array | 
 |                items: | 
 |                   type: string | 
 |                description: | | 
 |                   The device IDs of the gateways that are registered to act on behalf of this device. | 
 |                   Note that "via" and "memberOf" must not be set at the same time. | 
 |             "viaGroups": | 
 |                type: array | 
 |                items: | 
 |                   type: string | 
 |                description: | | 
 |                   The IDs of the gateway groups that are registered to act on behalf of this device. | 
 |                   Note that "viaGroups" and "memberOf" must not be set at the same time. | 
 |             "memberOf": | 
 |                type: array | 
 |                items: | 
 |                   type: string | 
 |                description: | | 
 |                   The IDs of the gateway groups that this device is a member of. | 
 |                   Note that neither "via" nor "viaGroups" must be set if "memberOf" is set. | 
 |             "authorities": | 
 |                type: array | 
 |                items: | 
 |                   type: string | 
 |                description: | | 
 |                   The authorities granted to a device. Applies to gateways only currently: the authority | 
 |                   `auto-provisioning-enabled` entitles a gateway device to perform auto-provisioning for its | 
 |                   edge devices. | 
 |             "downstream-message-mapper": | 
 |                type: string | 
 |                description: | | 
 |                   The name of a service that can be used by protocol adapters to transform downstream messages | 
 |                   uploaded by devices before sending them to downstream consumers. | 
 |                   The protocol adapter needs to map this name to the particular service to invoke. | 
 |                   NB: This is an experimental feature and thus this property is subject to change without | 
 |                   notice. | 
 |             "upstream-message-mapper": | 
 |                type: string | 
 |                description: | | 
 |                   The name of a service that can be used by protocol adapters to transform upstream commands to be sent to devices. | 
 |                   The protocol adapter needs to map this name to the particular service to invoke. | 
 |                   NB: This is an experimental feature and thus this property is subject to change without | 
 |                   notice. | 
 |             "ext": | 
 |                $ref: '#/components/schemas/Extensions' | 
 |             "status": | 
 |                $ref: '#/components/schemas/Status' | 
 |             "command-endpoint": | 
 |                type: object | 
 |                additionalProperties: false | 
 |                description: | | 
 |                   The endpoint of the device that command messages should be sent to. Only relevant for devices | 
 |                   that connect to a type of protocol adapter that actively connects to the device for sending commands, | 
 |                   instead of using a connection initiated by the device. | 
 |                required: | 
 |                   - uri | 
 |                properties: | 
 |                   "uri": | 
 |                      type: string | 
 |                      description: | | 
 |                         Configures the URI to which the command should be sent. The placeholder `{{deviceId}}` is | 
 |                         supported and will be replaced with the id of the device to which the command was initially | 
 |                         sent. | 
 |                   "headers": | 
 |                      type: object | 
 |                      additionalProperties: true | 
 |                      description: Allows arbitrary headers which will be added to the command. | 
 |                   "payload-properties": | 
 |                      type: object | 
 |                      additionalProperties: true | 
 |                      description: Allows arbitrary properties which will be added to the command payload. | 
 |  | 
 |       DeviceWithId: | 
 |          type: object | 
 |          additionalProperties: false | 
 |          allOf: | 
 |             - type: object | 
 |               properties: | 
 |                  "id": | 
 |                     description: The identifier of the device. | 
 |                     type: string | 
 |                     readOnly: true | 
 |             - $ref: '#/components/schemas/Device' | 
 |  | 
 |       Status: | 
 |          type: object | 
 |          additionalProperties: false | 
 |          description: | | 
 |             Additional meta data describing the entity. | 
 |          properties: | 
 |             "created": | 
 |                type: string | 
 |                format: date-time | 
 |                readOnly: true | 
 |                description: The point in time when the entity was originally created. | 
 |             "updated": | 
 |                type: string | 
 |                format: date-time | 
 |                readOnly: true | 
 |                description: The point in time when the entity was last updated. | 
 |             "last-user": | 
 |                type: string | 
 |                readOnly: true | 
 |                description: The user who made the last edit on this entity. | 
 |             "auto-provisioned": | 
 |                type: boolean | 
 |                default: false | 
 |                readOnly: true | 
 |                description: Indicates if the entity was created via auto-provisioning. | 
 |             "auto-provisioning-notification-sent": | 
 |                type: boolean | 
 |                default: false | 
 |                readOnly: true | 
 |                description: Indicates if downstream consumers have been notified about the newly auto-provisioned | 
 |                   entity by means of a corresponding event. | 
 |  | 
 |       SearchTenantsResult: | 
 |          type: object | 
 |          description: The result of a search request for tenants. | 
 |          additionalProperties: false | 
 |          properties: | 
 |             "total": | 
 |                type: integer | 
 |                minimum: 0 | 
 |                description: The total number of objects in the result set, regardless of the *pageSize* set in query. | 
 |             "result": | 
 |                type: array | 
 |                items: | 
 |                   $ref: '#/components/schemas/TenantWithId' | 
 |  | 
 |       SearchDevicesResult: | 
 |          type: object | 
 |          description: The result of a search request for devices. | 
 |          additionalProperties: false | 
 |          properties: | 
 |             "total": | 
 |                type: integer | 
 |                minimum: 0 | 
 |                description: The total number of objects in the result set, regardless of the *pageSize* set in query. | 
 |             "result": | 
 |                type: array | 
 |                items: | 
 |                   $ref: '#/components/schemas/DeviceWithId' | 
 |  | 
 | # Credentials | 
 |  | 
 |       CredentialsSet: | 
 |          type: array | 
 |          description: A set of credentials. The entries in this list must be | 
 |                       unique by the composite key of `auth-id` and `type`. | 
 |          items: | 
 |             $ref: '#/components/schemas/TypedCredentials' | 
 |  | 
 |       TypedCredentials: | 
 |          additionalProperties: false | 
 |          oneOf: | 
 |             - $ref: '#/components/schemas/PasswordCredentials' | 
 |             - $ref: '#/components/schemas/PSKCredentials' | 
 |             - $ref: '#/components/schemas/X509CertificateCredentials' | 
 |          discriminator: | 
 |             propertyName: type | 
 |             mapping: | 
 |                "hashed-password": '#/components/schemas/PasswordCredentials' | 
 |                "psk": '#/components/schemas/PSKCredentials' | 
 |                "x509-cert": '#/components/schemas/X509CertificateCredentials' | 
 |  | 
 |       CommonCredentials: | 
 |          type: object | 
 |          additionalProperties: false | 
 |          properties: | 
 |             "type": | 
 |                type: string | 
 |             "auth-id": | 
 |                type: string | 
 |             "enabled": | 
 |                type: boolean | 
 |                default: true | 
 |             "ext": | 
 |                $ref: '#/components/schemas/Extensions' | 
 |  | 
 |       PasswordCredentials: | 
 |          additionalProperties: false | 
 |          allOf: | 
 |             - $ref: '#/components/schemas/CommonCredentials' | 
 |             - type: object | 
 |               required: | 
 |                  - type | 
 |                  - auth-id | 
 |                  - secrets | 
 |               additionalProperties: false | 
 |               properties: | 
 |                  "type": | 
 |                     type: string | 
 |                     pattern: "hashed-password" | 
 |                  "auth-id": | 
 |                     type: string | 
 |                     description: | | 
 |                        The authentication identifier provided by the device as part of the *user name*. | 
 |                        Example: For user name `sensor1@DEFAULT_TENANT` the authentication identifier to be registered | 
 |                        is `sensor1`. | 
 |                  "secrets": | 
 |                     type: array | 
 |                     items: | 
 |                        $ref: '#/components/schemas/PasswordSecret' | 
 |                     minItems: 1 | 
 |  | 
 |       PSKCredentials: | 
 |          additionalProperties: false | 
 |          allOf: | 
 |             - $ref: '#/components/schemas/CommonCredentials' | 
 |             - type: object | 
 |               required: | 
 |                  - type | 
 |                  - auth-id | 
 |                  - secrets | 
 |               additionalProperties: false | 
 |               properties: | 
 |                  "type": | 
 |                     type: string | 
 |                     pattern: "psk" | 
 |                  "auth-id": | 
 |                     type: string | 
 |                     description: The *PSK identity* provided by the device in the TLS handshake. | 
 |                  "secrets": | 
 |                     type: array | 
 |                     items: | 
 |                        $ref: '#/components/schemas/PSKSecret' | 
 |                     minItems: 1 | 
 |  | 
 |       X509CertificateCredentials: | 
 |          additionalProperties: false | 
 |          allOf: | 
 |             - $ref: '#/components/schemas/CommonCredentials' | 
 |             - type: object | 
 |               required: | 
 |                  - type | 
 |               additionalProperties: false | 
 |               properties: | 
 |                  "type": | 
 |                     type: string | 
 |                     pattern: "x509-cert" | 
 |                  "auth-id": | 
 |                     type: string | 
 |                     description: | | 
 |                        The *subject DN* of the public key contained in the device's X.509 certificate. | 
 |                        The value MUST be formatted according to the rules defined in | 
 |                        [RFC 2253](https://tools.ietf.org/html/rfc2253#section-2). | 
 |                  "secrets": | 
 |                     type: array | 
 |                     items: | 
 |                        $ref: '#/components/schemas/X509CertificateSecret' | 
 |                     description: | | 
 |                        A secret containing the X.509 certificate's validity period. | 
 |                     minItems: 1 | 
 |                     maxItems: 1 | 
 |                  "cert": | 
 |                     type: string | 
 |                     format: byte | 
 |                     writeOnly: true | 
 |                     description: | | 
 |                        The Base64 encoded binary DER encoding of the device's X.509 client certificate. | 
 |                        This property can be used as a convenient alternative to specifying the certificate's | 
 |                        meta data in the *auth-id* and *secrets* explicitly. | 
 |                        When provided in a request body, implementors of this API MUST extract the subject DN | 
 |                        from the certificate's public key and store its value properly formatted to the *auth-id* | 
 |                        property. The certificate's validity period MUST be stored in a single secret. | 
 |                        The certificate itself must then be discarded. | 
 |  | 
 |       CommonSecret: | 
 |          type: object | 
 |          additionalProperties: false | 
 |          properties: | 
 |             "id": | 
 |                type: string | 
 |                description: The device registry can assign an identity to the secret. | 
 |                             This value can be used to update secrets based on their metadata. | 
 |             "enabled": | 
 |                type: boolean | 
 |                default: true | 
 |                description: Indicates if this secret can be used for authentication. | 
 |             "not-before": | 
 |                type: string | 
 |                format: date-time | 
 |                description: | | 
 |                   The point in time from which on this secret will be accepted for authentication. | 
 |                   NB: The value MUST be a string that complies with the format defined in | 
 |                   [RFC 3339](https://tools.ietf.org/html/rfc3339#section-5.6) as indicated | 
 |                   by the [date-time](https://spec.openapis.org/oas/v3.0.1#dataTypeFormat) | 
 |                   format in the OpenAPI specification. | 
 |             "not-after": | 
 |                type: string | 
 |                format: date-time | 
 |                description: | | 
 |                   The point in time after which this secret will no longer be accepted for authentication. | 
 |                   NB: The value MUST be a string that complies with the format defined in | 
 |                   [RFC 3339](https://tools.ietf.org/html/rfc3339#section-5.6) as indicated | 
 |                   by the [date-time](https://spec.openapis.org/oas/v3.0.1#dataTypeFormat) | 
 |                   format in the OpenAPI specification. | 
 |             "comment": | 
 |                type: string | 
 |  | 
 |       X509CertificateSecret: | 
 |          additionalProperties: false | 
 |          allOf: | 
 |             - $ref: '#/components/schemas/CommonSecret' | 
 |  | 
 |       PasswordSecret: | 
 |          additionalProperties: false | 
 |          allOf: | 
 |             - $ref: '#/components/schemas/CommonSecret' | 
 |             - type: object | 
 |               additionalProperties: false | 
 |               properties: | 
 |                  "hash-function": | 
 |                     type: string | 
 |                     example: bcrypt | 
 |                     description: The name of the hash function used to create the password hash (defined in `pwd-hash` property). | 
 |                                  If the password is defined using a `pwd-plain` property, this value will be ignored by the device registry. | 
 |                                  This property should be empty when returning passwords from the device registry using only secret metadata. | 
 |                                  In this case the id field must be set instead. | 
 |                  "pwd-hash": | 
 |                     type: string | 
 |                     description: The password hash as a string, either the output of applying the Bcrypt hash function | 
 |                                  to the clear text password if the `hash-function` is `bcrypt`, or otherwise the Base64 encoding | 
 |                                  of the bytes resulting from applying the hash function to the byte array consisting of the salt bytes | 
 |                                  (if a salt is used) and the UTF-8 encoding of the clear text password. | 
 |                                  For detail regarding different hash functions and the required encoding refer to the | 
 |                                  [Credentials API](https://www.eclipse.org/hono/docs/api/credentials/#hashed-password). | 
 |                                  If the password is defined using a `pwd-plain` property, this value will be ignored by the device registry. | 
 |                                  This property should be empty when returning passwords from the device registry using only secret metadata. | 
 |                                  In this case the id field must be set instead. | 
 |                  "salt": | 
 |                     type: string | 
 |                     format: byte | 
 |                     description: The Base64 encoding of the salt used in the password hash (defined in the `pwd-hash` property). | 
 |                                  If the password is defined using a `pwd-plain` property, this value will be ignored by the device registry. | 
 |                                  This property should be empty when returning passwords from the device registry using only secret metadata. | 
 |                                  In this case the id field must be set instead. | 
 |                  "pwd-plain": | 
 |                     type: string | 
 |                     writeOnly: true | 
 |                     description: The clear text value of the password to be hashed by the device registry. | 
 |                                  If this property is specified, the device registry will ignore user-provided hash properties (`hash-function`, `pwd-hash` and `salt`). | 
 |                                  This property must never be included in a response from the device registry. | 
 |                                  A device registry implementation must never write plain text passwords to a persistent store. | 
 |  | 
 |       PSKSecret: | 
 |          additionalProperties: false | 
 |          allOf: | 
 |             - $ref: '#/components/schemas/CommonSecret' | 
 |             - type: object | 
 |               additionalProperties: false | 
 |               required: | 
 |                  - key | 
 |               properties: | 
 |                  "key": | 
 |                     type: string | 
 |                     format: byte | 
 |                     description: The secret key shared between device and Hono. | 
 |  | 
 |       FilterJson: | 
 |         description: Filters to be applied to bulk queries. | 
 |         additionalProperties: false | 
 |         required: | 
 |            - field | 
 |            - value | 
 |         properties: | 
 |           "field": | 
 |             type: string | 
 |             description: | | 
 |               A [Json Pointer](https://tools.ietf.org/html/rfc6901) identifying the field to use for filtering. | 
 |           "op": | 
 |             type: string | 
 |             description: The operator to use when applying the filter. | 
 |             default: eq | 
 |             enum: | 
 |               - eq | 
 |           "value": | 
 |             oneOf: | 
 |               - type: boolean | 
 |                 description: The value to filter the boolean typed field with. | 
 |               - type: integer | 
 |                 description: The value to filter the integer typed field with. | 
 |               - type: number | 
 |                 description: The value to filter the number typed field with. | 
 |               - type: string | 
 |                 description: | | 
 |                    The value to filter the string typed field with. | 
 |                    Wildcard characters are supported : `*` will match zero or any number of characters | 
 |                    and `?` will match exactly one character. | 
 |  | 
 |    parameters: | 
 |  | 
 |       resourceVersion: | 
 |          name: If-Match | 
 |          in: header | 
 |          description: The expected resource version | 
 |          required: false | 
 |          schema: | 
 |             type: string | 
 |  | 
 |       tenantId: | 
 |          name: tenantId | 
 |          in: path | 
 |          description: The ID of the tenant | 
 |          required: true | 
 |          schema: | 
 |             type: string | 
 |          example: DEFAULT_TENANT | 
 |  | 
 |       deviceId: | 
 |          name: deviceId | 
 |          in: path | 
 |          description: The ID of the device | 
 |          required: true | 
 |          schema: | 
 |             type: string | 
 |          example: 4711 | 
 |  | 
 |       pageSize: | 
 |         name: pageSize | 
 |         in: query | 
 |         description: | | 
 |            The maximum number of objects to include in a response. | 
 |         required: false | 
 |         schema: | 
 |            type: integer | 
 |            minimum: 0 | 
 |            maximum: 200 | 
 |            default: 30 | 
 |  | 
 |       pageOffset: | 
 |         name: pageOffset | 
 |         in: query | 
 |         description: | | 
 |            The offset into the result set from which to include objects in the response. This allows to retrieve the whole result set page by page. | 
 |         required: false | 
 |         schema: | 
 |            type: integer | 
 |            minimum: 0 | 
 |            default: 0 | 
 |  | 
 |       filterJson: | 
 |         name: filterJson | 
 |         in: query | 
 |         description: | | 
 |           A predicate that objects in the result set must match. If this parameter is specified multiple | 
 |           times, objects in the result set must match all predicates. | 
 |           The predicate is specified as a string representing a JSON object complying with the following schema | 
 |           ``` | 
 |           { | 
 |             "type": "object", | 
 |             "additionalProperties": false, | 
 |             "required": ["field", "value"], | 
 |             "properties": { | 
 |               "field": { | 
 |                 "type": "string", | 
 |                 "description": "A Json Pointer (https://tools.ietf.org/html/rfc6901) identifying the field to use for filtering." | 
 |               }, | 
 |               "op": { | 
 |                 "type": "string", | 
 |                 "description": "The operator to apply.", | 
 |                 "default": "eq", | 
 |                 "enum": ["eq"] | 
 |               }, | 
 |               "value": { | 
 |                 "oneOf": [ | 
 |                   { | 
 |                     "type": "boolean", | 
 |                     "description": "The value to filter the boolean typed field with." | 
 |                   },{ | 
 |                     "type": "number", | 
 |                     "description": "The value to filter the number typed field with." | 
 |                   },{ | 
 |                     "type": "string", | 
 |                     "description": "The value to filter the string typed field with. | 
 |                        Wildcard characters are supported : `*` will match zero or any number of characters | 
 |                        and `?` will match exactly one character." | 
 |                   } | 
 |                 ] | 
 |               } | 
 |             } | 
 |           } | 
 |           ``` | 
 |         required: false | 
 |         schema: | 
 |           type: string | 
 |         examples: | 
 |           boolean field: | 
 |             value: "{\"field\": \"/enabled\",\"value\": true}" | 
 |           number field: | 
 |             value: "{\"field\": \"/ext/count\",\"value\": 15}" | 
 |           string field: | 
 |             value: "{\"field\": \"/ext/brand\",\"value\": \"eclipse*\"}" | 
 |  | 
 |       sortJson: | 
 |         name: sortJson | 
 |         in: query | 
 |         description: | | 
 |           Specifies a property to sort the result set by. If this parameter is specified multiple | 
 |           times, the sort options are applied in the order they are specified in the query string. | 
 |           The sort option is specified as a string representing a JSON object complying with the following schema | 
 |           ``` | 
 |           { | 
 |             "type": "object", | 
 |             "additionalProperties": false, | 
 |             "required": ["field"], | 
 |             "properties": { | 
 |               "field": { | 
 |                 "type": "string", | 
 |                 "description": "A Json Pointer (https://tools.ietf.org/html/rfc6901) identifying the field to sort by." | 
 |               }, | 
 |               "direction": { | 
 |                 "type": "string", | 
 |                 "description": "The sort direction.", | 
 |                 "default": "asc", | 
 |                 "enum": ["asc", "desc"] | 
 |               } | 
 |             } | 
 |           } | 
 |           ``` | 
 |         required: false | 
 |         schema: | 
 |           type: string | 
 |         examples: | 
 |           sort ascending: | 
 |             value: "{\"field\":\"/ext/brand\"}" | 
 |           sort descending: | 
 |             value: "{\"field\":\"/status/created\",\"direction\":\"desc\"}" | 
 |  | 
 |    responses: | 
 |  | 
 |       Unauthorized: | 
 |          description: Authentication credentials are required, but missing. | 
 |          headers: | 
 |             "WWW-Authenticate": | 
 |                schema: | 
 |                   type: string | 
 |  | 
 |       Created: | 
 |          description: Object created. | 
 |          headers: | 
 |             Location: | 
 |                description: URL to the resource | 
 |                schema: | 
 |                   type: string | 
 |                   format: uri | 
 |             ETag: | 
 |                description: The new version of the resource | 
 |                schema: | 
 |                   type: string | 
 |          content: | 
 |             application/json: | 
 |                schema: | 
 |                   type: object | 
 |                   additionalProperties: false | 
 |                   required: | 
 |                      - id | 
 |                   properties: | 
 |                      id: | 
 |                         type: string | 
 |                         description: The ID of the created object | 
 |  | 
 |       Updated: | 
 |          description: Object updated. | 
 |          headers: | 
 |             ETag: | 
 |                description: The new version of the resource | 
 |                schema: | 
 |                   type: string | 
 |  | 
 |       Deleted: | 
 |          description: Object deleted. | 
 |  | 
 |       NotFound: | 
 |          description: | | 
 |             Object not found. This may also be returned for some operations | 
 |             if the user lacks authorization to read the subject of the operation. | 
 |          content: | 
 |             application/json: | 
 |                schema: | 
 |                   $ref: '#/components/schemas/Error' | 
 |  | 
 |       TenantNotFound: | 
 |          description: | | 
 |             The referenced tenant could not be found. | 
 |  | 
 |             This may also be returned for some operations | 
 |             if the user lacks authorization to read the tenant. | 
 |          content: | 
 |             application/json: | 
 |                schema: | 
 |                   $ref: '#/components/schemas/Error' | 
 |  | 
 |       DeviceNotFound: | 
 |          description: | | 
 |             The referenced device could not be found. | 
 |  | 
 |             This may also be returned for some operations | 
 |             if the user lacks authorization to read the device. | 
 |          content: | 
 |             application/json: | 
 |                schema: | 
 |                   $ref: '#/components/schemas/Error' | 
 |  | 
 |       NotAllowed: | 
 |          description: | | 
 |             Operation not allowed. If the user does not have read access | 
 |             for this object, then `404` will be returned instead. | 
 |          content: | 
 |             application/json: | 
 |                schema: | 
 |                   $ref: '#/components/schemas/Error' | 
 |  | 
 |       MalformedRequest: | 
 |          description: Malformed request | 
 |          content: | 
 |             application/json: | 
 |                schema: | 
 |                   $ref: '#/components/schemas/Error' | 
 |  | 
 |       AlreadyExists: | 
 |          description: | | 
 |             Object already exists. If the user has no read access for | 
 |             the existing object, then `403` should be returned instead. | 
 |          content: | 
 |             application/json: | 
 |                schema: | 
 |                   $ref: '#/components/schemas/Error' | 
 |  | 
 |       ResourceVersionMismatch: | 
 |          description: | | 
 |             Expected resource version does not match current. | 
 |             This can only happen when the request header `If-Match` | 
 |             was set. | 
 |          content: | 
 |             application/json: | 
 |                schema: | 
 |                   $ref: '#/components/schemas/Error' | 
 |  | 
 |       RequestEntityTooLarge: | 
 |          description: | | 
 |             The size of the payload in the request body exceeds the registry's configured limit. | 
 |          content: | 
 |             application/json: | 
 |                schema: | 
 |                   $ref: '#/components/schemas/Error' | 
 |  | 
 |    securitySchemes: | 
 |  | 
 |       BearerAuth: | 
 |          type: http | 
 |          scheme: bearer | 
 |  | 
 |       BasicAuth: | 
 |          type: http | 
 |          scheme: basic | 
 |  | 
 |    examples: | 
 |  | 
 |       TenantAllAdaptersExample: | 
 |          summary: All adapters | 
 |          description: | | 
 |             An empty request body can be used to create a tenant | 
 |             using default values. This means that the tenant will be | 
 |             enabled and devices of the tenant may connect to all | 
 |             protocol adapters. | 
 |          value: | 
 |  | 
 |       TenantMqttAdapterOnlyExample: | 
 |          summary: MQTT adapter only | 
 |          description: | | 
 |             Creates a tenant with only the MQTT adapter enabled. | 
 |             Devices of the tenant will thus not be able to connect | 
 |             to any adapter other than the MQTT adapter. | 
 |          value: | | 
 |             { | 
 |                "adapters": [{ | 
 |                   "type": "hono-mqtt", | 
 |                   "enabled": true | 
 |                }] | 
 |             } | 
 |  | 
 |       DeviceDefaultExample: | 
 |          summary: Default properties | 
 |          description: | | 
 |             An empty request body can be used to create an enabled device | 
 |             with no additional configuration. | 
 |  | 
 |       DeviceExtExample: | 
 |          summary: Extension properties | 
 |          description: | | 
 |             Creates a device with some (application specific) extension properties. | 
 |          value: | | 
 |             { | 
 |                 "ext": { | 
 |                    "ep": "IMEI4711" | 
 |                 } | 
 |             } | 
 |  | 
 |       CredentialsSetPasswordExample: | 
 |          summary: Set pre-hashed password | 
 |          description: | | 
 |             The secret does not refer to an existing secret (no *id* property). Thus, the | 
 |             existing secrets (if any) will be replaced with the hashed password secret. | 
 |          value: | 
 |             [{ | 
 |                 "auth-id": "sensor1", | 
 |                 "type": "hashed-password", | 
 |                 "secrets": [{ | 
 |                    "pwd-hash": "AQIDBAUGBwg=", | 
 |                    "salt": "Mq7wFw==", | 
 |                    "hash-function": "sha-512", | 
 |                    "not-after": "2027-12-24T19:00:00Z" | 
 |                 }] | 
 |              }] | 
 |  | 
 |       CredentialsChangePasswordExample: | 
 |          summary: Change password | 
 |          description: | | 
 |             The secret refers to an existing hashed password which will be updated | 
 |             with the included values. The plaintext password will be hashed using | 
 |             the registry's default hash algorithm. | 
 |          value: | 
 |            [{ | 
 |                auth-id: sensor1, | 
 |                type: hashed-password, | 
 |                secrets: [{ | 
 |                   "id": "349556ea-4902-47c7-beb0-1009ab693fb4", | 
 |                   "pwd-plain": "newpassword", | 
 |                   "not-after": "2027-12-24T19:00:00Z" | 
 |                }] | 
 |             }] | 
 |  | 
 |       CredentialsMetaDataExample: | 
 |          summary: Meta data only | 
 |          description: | | 
 |             The secrets do not contain the confidential information like password hash | 
 |             or salt. Instead, the secrets contain an identifier which can be | 
 |             used to refer to the secret in a subsequent update operation. | 
 |          value: | 
 |            [{ | 
 |                "enabled": true, | 
 |                "auth-id": "sensor1", | 
 |                "type": "hashed-password", | 
 |                "secrets": [{ | 
 |                   "id": "349556ea-4902-47c7-beb0-1009ab693fb4", | 
 |                   "not-after": "2027-12-24T19:00:00Z" | 
 |                }] | 
 |             }] |