Skip to content

AccessControl 2.2.1-rc.1

Property and building access control to distribute keys for visitors and guests.

Supports different key types like key cards, pin codes and more to come.

Supports multiple hardware vendors.

How to get started:

  • Create an "Access Control Provider" configuration with the Configuration API. A provider reflects the upstream service provided by the hardware manufacturer.

  • Create a "Controller" configuration for key distribution, also on the Configuration API. A controller acts as a physical or logical device used to issue keys, such as a card encoder.

  • Create a key (createKey). Issue a key card, pin code or any other supported key type.

Servers: http://localhost:8081/api/v2

Extensions

Extensions to the base API. These extensions are intended for internal use, may change and are not officially supported.

Get AccessControl Capabilities

GET /access/providers/{configurationId}/capabilities

Returns the capabilities the configured AccessControl provider supports and the subset invokable as extensions. The set is derived from the configured provider; callers use it to decide which actions to surface without hard-coding provider knowledge.

Parameters

  • configurationId (path, string, required)

    Uuid of the AccessControl provider configuration

Responses

  • 200

    OK

  • 404

    Provider configuration not found.

Invoke AccessControl Extension

GET /access/providers/{configurationId}/extensions/{extensionName}

Generic dispatcher for a provider extension. The response is the provider's native shape, returned verbatim. Returns 404 when the extension is not registered or the configured provider does not support it.

Parameters

  • configurationId (path, string, required)

    Uuid of the AccessControl provider configuration

  • extensionName (path, string, required)

    Name of the extension to invoke (e.g. unit-list, unit-sync, encoder-list). The supported set is owned by the configured provider — see the capabilities endpoint.

Responses

  • 200

    OK — provider-specific extension payload.

  • 404

    Extension not registered, provider not found, or not supported by the provider.

  • 502

    The upstream access-control system could not carry out the request.

    The request itself was well-formed and accepted — this is the locking system, its gateway or its vendor API failing, being unreachable, or refusing because it is busy. errorCode says which.

    Retrying is usually worthwhile, but not immediately: a gateway that answered "busy" is still busy a second later. Where outcomeUnknown is true the write may have landed despite the failure, so re-run the idempotent form of the operation rather than assuming nothing happened.

CardDispenser

Card Dispensers are devices used to dispense keycards or other access media. They can be used to issue keycards to guests or staff members.

Get Dispenser Status

GET /access/dispensers/{dispenserId}/status

Parameters

  • dispenserId (path, string (uuid), required)

    Uuid of the card dispenser

Responses

  • 200

    Dispenser status

  • 404

    The requested resource could not be found.

  • 500

    An unexpected error occurred on the server.

Set Dispenser State

PUT /access/dispensers/{dispenserId}/status/{state}

Set a state on a card dispenser.

Parameters

  • dispenserId (path, string (uuid), required)

    Uuid of the card dispenser

  • state (path, CardDispenserState, required)

Responses

  • 204

    No Content

Place card

PUT /access/dispensers/{dispenserId}/place-card/{cardPosition}

Place the card on the card dispenser to the designated position.

Parameters

  • dispenserId (path, string (uuid), required)

    Uuid of the card dispenser

  • cardPosition (path, PlaceCard, required)

Responses

  • 204

    No Content

Reset Dispenser Cache

POST /access/dispensers/{dispenserId}/reset-cache

Drops the service's cached handle for one card dispenser, so the next call to it reconnects and re-reads its configuration. Use after changing a dispenser configuration, or to recover a dispenser the service still believes is in a state it has since left.

Answers 404 when the dispenser holds no cache entry — nothing was reset, which is not the same as the dispenser being unknown.

Parameters

  • dispenserId (path, string (uuid), required)

    Uuid of the card dispenser

Responses

  • 200

    Cache entry dropped

  • 404

    The dispenser held no cache entry

Reset All Dispenser Caches

POST /access/dispensers/reset-all-cache

Drops every cached dispenser handle at once. The message reports how many entries were cleared; clearing none is a success, not an error.

Responses

  • 200

    Cache entries dropped

Key

Creating keys (keycards, pin codes, etc.) for access control systems.
After creating a key its information are hold in the system. Before a key can be created one needs to setup a provider and a controller first. Controllers define the keyType (such as keycard or pin code) and the provider defines the keyProvider (such as Tesa or Salto).

Some keys such as keycards can only be created if a medium is present (like a keycard encoder), and often times that is also true if you want to delete it.

Read Key

GET /access/controllers/{controllerId}/key

Reads key of specified controller including data read from keycard.

Intended to be used for physical keycards.

Parameters

  • controllerId (path, string (uuid), required)

    Uuid of the controller

Responses

  • 200

    OK

  • 404

    The requested resource could not be found.

  • 500

    An unexpected error occurred on the server.

  • 502

    The upstream access-control system could not carry out the request.

    The request itself was well-formed and accepted — this is the locking system, its gateway or its vendor API failing, being unreachable, or refusing because it is busy. errorCode says which.

    Retrying is usually worthwhile, but not immediately: a gateway that answered "busy" is still busy a second later. Where outcomeUnknown is true the write may have landed despite the failure, so re-run the idempotent form of the operation rather than assuming nothing happened.

Create a Key

POST /access/controllers/{controllerId}/key

Creates a new key on the controller. A key can be a keycard, pin code or other key type according to the controller. Note that the response contains some additional information about the key such as a keycard uuid or a pin code number.

unitName is required for any key that reaches the locking system. The unit is what names the lock, so a key without one has nothing to be written to and is rejected with 422. The single exception is a key held virtually (see below), where the unit is expected to arrive before the pin is written.

externalId is required for a key that will be held virtually. On a controller configured with virtualBefore, a key whose start lies further out than the window is not written to the locking system yet. Such a key is materialised only through replaceKeyByReservation, which resolves it by the stay's external id — so without one the guest would be handed a pin that nothing could ever activate. Creating it is refused with 400.

This applies only while the key would be held for its start date. Once the window has opened the key goes to the locking system on this call, and no external id is needed to get it there.

Parameters

  • controllerId (path, string (uuid), required)

    Uuid of the controller

Request body

application/vnd.api+json · KeyTypes

  • unitName (string, required) – name of the lock or door
  • original (boolean, required) – create and replace key if true, copy otherwise
  • startDate (string (date), required) – Date after which the key is valid
  • startTime (string (time)) – Time after which the key is valid, seconds must be 00
  • endDate (string (date), required) – Date after which the key is invalid
  • endTime (string (time)) – Time after which the key is invalid, seconds must be 00
  • authorizations (string[]) – Add/assign authorization to system default
  • deAuthorizations (string[]) – Remove/deny authorization zone from system default
  • extraUnits (string[]) – Additional units to grant access to
  • type (string enum, required)
  • providerId (string (uuid), required) – The provider configuration the key was created with.
  • id (string (uuid), required) – The generated UUID
  • createdAt (string (date-time), required) – Time of creation
  • updatedAt (string (date-time), required) – Time of last update
  • keyType (string, required) – The type of the key

Responses

  • 201

    Created

  • 400

    The server could not understand the request due to invalid syntax.

  • 422

    The request body failed validation.

  • 500

    An unexpected error occurred on the server.

  • 502

    The upstream access-control system could not carry out the request.

    The request itself was well-formed and accepted — this is the locking system, its gateway or its vendor API failing, being unreachable, or refusing because it is busy. errorCode says which.

    Retrying is usually worthwhile, but not immediately: a gateway that answered "busy" is still busy a second later. Where outcomeUnknown is true the write may have landed despite the failure, so re-run the idempotent form of the operation rather than assuming nothing happened.

Erase Key

DELETE /access/controllers/{controllerId}/key

Deletes a key on a "Controller". Typically used for deleting a key-card on a card encoder.

Also consider invalidating a key with deleteKey or replaceKey.

Parameters

  • controllerId (path, string (uuid), required)

    Uuid of the controller

Responses

  • 204

    OK

Create Keys in a batch

POST /access/controllers/{controllerId}/keys

Creates several keys of the same kind on the controller in one call — typically a run of key cards encoded back to back from a dispenser. The key itself is described exactly as for createKey; quantity says how many to produce.

Encoding is sequential and stops at the first card that fails, so a batch can end partially done: succeeded reports how many keys were actually created and error describes the card that stopped the run. Read keys rather than assuming requested were made.

This response is not the JSON:API resource document the rest of this API returns. There is no type/id envelope around data, since a batch is not one resource.

Parameters

  • controllerId (path, string (uuid), required)

    Uuid of the controller

Request body

application/vnd.api+json

  • quantity (integer) – How many keys to create

Responses

  • 201

    Created

  • 400

    The server could not understand the request due to invalid syntax.

  • 422

    The request body failed validation.

  • 500

    An unexpected error occurred on the server.

Create or Reconcile a Key for a Stay

PUT /access/controllers/{controllerId}/keys/by-reservation/{stayExternalId}

Brings the key for a stay into line with the reservation as it stands right now, creating it if it does not exist yet. Safe to call repeatedly with the same body.

This is the operation to use when a caller is driving keys from reservation data and cannot easily track whether it has already created one — a workflow retrying after a failure, a connector replaying an event, a scheduled reconciliation. Rather than asking the caller to check first and branch, the key is resolved from stayExternalId and either created or updated in place.

The pin is never regenerated. Once a pin has been issued for a stay it stays the same for the life of that key, however many times this operation runs. A guest who has been told their pin will not find it changed underneath them.

Each call re-evaluates the request against the controller's current configuration — unit mapping, the unit matrix, timezone handling. Dates that moved, a unit assigned late, or a changed configuration are therefore picked up simply by calling again; there is nothing to replay and no separate reconciliation verb.

externalId in the body must agree with the path. stayExternalId says which stay is being addressed and the body describes it; if the body carries a different externalId the request contradicts itself and is refused with 400. Omitting it is not a disagreement — the path value is used. Send it only if it matches.

Virtual pins. On a controller configured with virtualBefore, a key whose start is far enough out is created virtual — the pin is returned immediately but is not written to the locking system yet. Calling this operation once the window has opened and a unit is assigned writes it to the locking system and flips isVirtual to false. That is the only way a virtual pin is materialised: there is deliberately no separate endpoint for it, because materialisation needs the current reservation data that this request already carries.

Both conditions are needed, so the request that materialises a key must carry unitName. A virtual key minted before a room was assigned stays virtual until a call supplies one; a call made after the window has opened but still without a unit is refused with 422, and the held key is left untouched rather than half-written. Call again with the unit once the reservation has one.

Interpreting the outcome. Every successful call returns 200 with the key as it now stands — whether it was created, materialised, or already correct and left untouched. Do not branch on the status code; read isVirtual to find out whether the pin is live in the locking system. A 404 means the controller or the stay's key is gone (a cancelled reservation, for instance) and the caller should stop rather than retry; 5xx is worth retrying.

Parameters

  • controllerId (path, string (uuid), required)

    Uuid of the controller

  • stayExternalId (path, string, required)

    Identifier of the stay in the system the reservation originates from, as sent in externalId when the key was created. It identifies the key across repeated calls and is what makes this operation idempotent.

Request body

application/vnd.api+json · KeyTypes

  • unitName (string, required) – name of the lock or door
  • original (boolean, required) – create and replace key if true, copy otherwise
  • startDate (string (date), required) – Date after which the key is valid
  • startTime (string (time)) – Time after which the key is valid, seconds must be 00
  • endDate (string (date), required) – Date after which the key is invalid
  • endTime (string (time)) – Time after which the key is invalid, seconds must be 00
  • authorizations (string[]) – Add/assign authorization to system default
  • deAuthorizations (string[]) – Remove/deny authorization zone from system default
  • extraUnits (string[]) – Additional units to grant access to
  • type (string enum, required)
  • providerId (string (uuid), required) – The provider configuration the key was created with.
  • id (string (uuid), required) – The generated UUID
  • createdAt (string (date-time), required) – Time of creation
  • updatedAt (string (date-time), required) – Time of last update
  • keyType (string, required) – The type of the key

Responses

  • 200

    The key as it now stands. Read isVirtual to tell a pin that is live in the locking system from one that is still only held here.

  • 400

    The server could not understand the request due to invalid syntax.

  • 404

    The requested resource could not be found.

  • 422

    The request body failed validation.

  • 500

    An unexpected error occurred on the server.

  • 502

    The upstream access-control system could not carry out the request.

    The request itself was well-formed and accepted — this is the locking system, its gateway or its vendor API failing, being unreachable, or refusing because it is busy. errorCode says which.

    Retrying is usually worthwhile, but not immediately: a gateway that answered "busy" is still busy a second later. Where outcomeUnknown is true the write may have landed despite the failure, so re-run the idempotent form of the operation rather than assuming nothing happened.

List Keys

GET /access/keys

Lists all (guest) keys created for all providers.

Any attribute of the key resource can be filtered, and the value is interpreted as the type of the field it is compared against. controllerId is filterable too, although it is not part of the returned resource:

Field Form Example
startDate, endDate date filter[startDate][gte]=2026-07-01
startTime, endTime time filter[startTime][gte]=14:30:00
createdAt, updatedAt timestamp, UTC filter[createdAt][gt]=2026-07-01T12:00:00Z
controllerId id filter[controllerId][eq]=4d42cfa2-…
original, isVirtual true / false filter[isVirtual][eq]=true
unitName, keyType, externalId, pin, uid text filter[keyType][eq]=pinCode

A date field may also be given a full timestamp, which is read as that day. A value that cannot be interpreted as the field's type is answered with 400 naming the field and the form it expects, rather than being ignored or failing as a server error.

Parameters

  • filter (query, object)

    Filter results using field/operator pairs. The format is filter[field][operator]=value.

    Supported operators: eq, ne, gt, gte, lt, lte, like.

    Multiple filters are combined with AND.

  • page (query, object)

    Cursor-based pagination. Use page[after] or page[before] with a resource id to navigate pages.

Responses

  • 200

    OK

  • 400

    The server could not understand the request due to invalid syntax.

  • 500

    An unexpected error occurred on the server.

Get Key

GET /access/keys/{keyId}

Get detailed information about one specific key.

Parameters

  • keyId (path, string (uuid), required)

Responses

  • 200

    OK

  • 404

    The requested resource could not be found.

  • 500

    An unexpected error occurred on the server.

Update Key

PUT /access/keys/{keyId}

Modify a created key.

Important: Access Control System must support key modification. For physical keys (keycards). This can be accomplished through an updater or by updating the locks (online or by other means). Consider creating a new key instead.

The property providerIdis immutable and cannot be changed.

Physical keycards

If you are trying to modify a key from one access unit to another consider creating a new key instead and also create a new key for the "old" unit to invalidate the previously created key. The same is true if you are modifying the startDate, endDate, authorization or deAuthorization parameter. You should not modify the original nor the extraUnits parameter in most cases.

Set endDate or endTime parameter to the past to invalidate the key.

Other keys

None physical keys such as pin codes should have lesser restrictions. You should still consider some limitations. Refer to the access control provider implementation documentation.

Parameters

  • keyId (path, string (uuid), required)

Request body

application/vnd.api+json · KeyTypes

  • unitName (string, required) – name of the lock or door
  • original (boolean, required) – create and replace key if true, copy otherwise
  • startDate (string (date), required) – Date after which the key is valid
  • startTime (string (time)) – Time after which the key is valid, seconds must be 00
  • endDate (string (date), required) – Date after which the key is invalid
  • endTime (string (time)) – Time after which the key is invalid, seconds must be 00
  • authorizations (string[]) – Add/assign authorization to system default
  • deAuthorizations (string[]) – Remove/deny authorization zone from system default
  • extraUnits (string[]) – Additional units to grant access to
  • type (string enum, required)
  • providerId (string (uuid), required) – The provider configuration the key was created with.
  • id (string (uuid), required) – The generated UUID
  • createdAt (string (date-time), required) – Time of creation
  • updatedAt (string (date-time), required) – Time of last update
  • keyType (string, required) – The type of the key

Responses

  • 204

    No Content

Delete Key

DELETE /access/keys/{keyId}

Deletes a key.

This endpoint is intended for keys not requiring a physical key being present. An example for such a key is a pin code. Check the documentation of your access control provider implementation whether or not this can invalidate a physical key (keycard).

To delete a physical key, check eraseKey operation instead.

To invalidate a key, consider using PUT instead and set the end to the past.

Parameters

  • keyId (path, string (uuid), required)

Responses

  • 204

    No Content

AccessUnit

AccessUnits are the physical locks or access control devices. A unit can be a door, a gate, a locker or any other device that can be controlled by an access control system.

List Access Units

GET /access/units

List all access units (locks) of one access-control provider.

Parameters

  • filter (query, object)

    Filter results using field/operator pairs. The format is filter[field][operator]=value.

    Supported operators: eq, ne, gt, gte, lt, lte, like.

    Multiple filters are combined with AND.

  • page (query, object)

    Cursor-based pagination. Use page[after] or page[before] with a resource id to navigate pages.

Responses

  • 200

    OK

  • 400

    The server could not understand the request due to invalid syntax.

  • 500

    An unexpected error occurred on the server.

Create Access Unit

POST /access/units

Adds a new access-control unit to the list. The unit must correspond to an existing unit in the access-control system. Use this method only if the list cannot be populated automatically.

Request body

application/vnd.api+json · Unit

Access Control Unit

  • name (string, required) – common name of the unit or lock.
  • code (string) – Unit id or external code/id as seen in the access-control system. This is useful if the unit has a name and id in the access-control system and is only use in the api implementation of specific access-control provider.
  • config (object) – Access-control provider specific configuration options, such as the locks possibilities.
  • providerId (string (uuid), required) – The id of the access-control provider that manages this unit.

Responses

  • 201

    Created

  • 400

    The server could not understand the request due to invalid syntax.

  • 422

    The request body failed validation.

  • 500

    An unexpected error occurred on the server.

Get Access Unit

GET /access/units/{unitId}

Get a Unit of the access control system

Parameters

  • unitId (path, string (uuid), required)

Responses

  • 200

    OK

  • 404

    The requested resource could not be found.

  • 500

    An unexpected error occurred on the server.

Update Access Unit

PUT /access/units/{unitId}

Update a unit in the access control system

Parameters

  • unitId (path, string (uuid), required)

Request body

application/vnd.api+json · Unit

Access Control Unit

  • name (string, required) – common name of the unit or lock.
  • code (string) – Unit id or external code/id as seen in the access-control system. This is useful if the unit has a name and id in the access-control system and is only use in the api implementation of specific access-control provider.
  • config (object) – Access-control provider specific configuration options, such as the locks possibilities.
  • providerId (string (uuid), required) – The id of the access-control provider that manages this unit.

Responses

  • 204

    No Content

Delete an access unit

DELETE /access/units/{unitId}

Delete a unit from the access control system

Parameters

  • unitId (path, string (uuid), required)

Responses

  • 204

    No Content