Command Centre REST API (1.0)

Download OpenAPI specification:

This document describes how you can use the Command Centre REST API to view and manage its configuration, user directory, events, and alarms.

Forward compatibility (HATEOAS)

This is a self-referencing REST API that follows the principles of HATEOAS. Other than the initial GET /api when it first connects, your source code should not contain any URLs, as they are subject to change. You should append the query parameters this document describes for operations such as filtering and searching, but everying in the path should come from the results of /api or pages linked from it.

/api only shows the API calls the server is licensed for.

Be prepared to append query parameters to URLs that already have their own: do not assume that you can simply add a question mark and your parameters.

Forward compatibility (undocumented features)

Any behaviour of that is not referenced in this documentation is subject to change. This includes routes (URLs), default values, request parameters, and HTTP verbs, among others.

In particular:

  • If you discover a route or query parameter that is not documented here, a future version may change its behaviour.

  • Take all 2xx responses as success and all 4xx responses as failure. Example: a success could be 200 or 204 depending on whether it has something to tell you, and a negative result will change between the various 400s depending on the environment.

  • Treat items IDs as strings even though they are currently look like small integers. We intend to change them.

  • Treat string identifiers as strings even if they look like GUIDs. If the documentation does not say they will always be a GUID, they may not.

  • Some routes work with a PATCH even though they should only accept a POST. One day, PATCHes to those routes will start to fail.

  • Format all the timestamps you send as specified in the documentation. The parser we currently use is quite flexible so you may find that other formats ( "1/12/2025" ) work today, but they may not tomorrow.

Access control

Clients authenticate by including a pre-shared API key in the Authorization header of each request. Command Centre generates a random API key when you create an endpoint for your clients to connect to. Search the Configuration Client online help for 'REST API' for how do do that.

In current versions of Command Centre, the API key will be in the format XXXX-XXXX-XXXX-XXXX-XXXX-XXXX-XXXX-XXXX with each X an uppercase hexadecimal digit. Future versions of Command Centre may use other formats of API key, so treat it as an opaque string. Tempting as it may be, do not interpret is as a GUID.

There are two ways you can pass the API key to the server: following an authorisation method of GGL-API-KEY, or (in 9.0 and later) in the style of HTTP Basic authentication: prefixed with a colon, Base64-encoded, and following an authorisation method of Basic.

Examples:

Authorization: GGL-API-KEY C774-B01F-D695-AA4B-215F-A158-AC22-ADEB

Authorization: Basic OkM3NzQtQjAxRi1ENjk1LUFBNEItMjE1Ri1BMTU4LUFDMjItQURFQg==

Early versions of Command Centre allowed you to omit the 'GGL-API-KEY' from the first form. Future versions of Command Centre and all versions of the API gateway will reject you with a 401 if you do that. The API gateway is especially fussy about case and punctuation.

HTTP Basic authentication

The two example headers above are equivalent: prepending a colon to the API key beginning with C774 then encoding it into Base64 produces the 56 characters beginning with OkM3.

According to the HTTP Basic specification, the colon is a separator between a username and a password. In our case, the API key is the password and the username is unnecessary. If you place a username before the colon, before Base64-encoding it, Command Centre will ignore it and authenticate the connection based on the API key alone.

Pinning a client TLS certificate

Depending on Command Centre's site configuration, its REST API may also require a client certificate with each request. In versions up to and including 8.40 this was controlled by a flag labelled 'Do not require pinned client certficates' on the 'Web Services' tab of the server properties. In 8.50 that flag's label changed to 'Enable REST Clients with no client certificate', and its behaviour changed slightly when turned on.

If off, for all versions of CC, an incoming request's certificate has to match the thumbprint on its API key's REST Client item, and REST Client items with a blank thumbprint field do not work at all. This is how it ships, and it is the recommended way of running a production server.

If 'Do not require pinned client certificates' was turned on in versions up to and including 8.40, the server did not check any client certificates. If that flag is turned on in 8.50, now relabelled 'Enable REST Clients with no client certificate', it still does not check the client certificate if the thumbprint field of the matching REST Client item is blank, but if the Client item has a thumbprint, the server will reject connections with the wrong certificate.

See the Configuration Client help for instructions on where to enter REST Client thumbprints.

Source IP filtering

Also note that if IP filtering is enabled on the REST Client item in Command Centre, the API will only accept connections from the IP address ranges configurated into that client item.

Symptoms of authentication failures

If a connection attempt fails, the server will return a 401 and raise an event containing its reason for refusing the request. If that happens too often, the server will stop reporting each offence and will instead create a summary alarm at a much lower rate. The details of the alarm tell you how many failed attempts there have been since the start of the flood. The server will stay in this mode of reduced reporting until several minutes pass without a failed connection attempt.

The current failure limit is ten errors inside one minute. After that you will receive one "a large volume of requests has been denied" alarm every minute while the failures continue until five minutes passes without a failure.

The most common queries we receive from our integrators relate to their certificate handling. If your client's HTTP client library complains about certificates the first thing to check is Command Centre's alarm list. If there are 'invalid client certificate' alarms there, your client is not sending the certificate CC is expecting. If there are no alarms then the client is most likely rejecting the server's certificate.

Operator privileges

First, some background on operators, operator groups, and divisions.

To determine your REST client's privileges, the server starts by searching the list of REST Client items in its configuration for the one with the API key in the Authorization header of your request. Assuming it finds one, it takes the cardholder from that REST Client item.

To be any use at all that cardholder must be a member of at least one operator group. Being in an operator group makes a cardholder an operator.

After the server has your operator, it needs to check whether that operator has access to the items or events in the request. To explain that, it is necessary to cover divisions.

Aside from some special items such as day categories, every item in Command Centre is in a division. Divisions are hierarchical, with all divisions (but the root) being a child of another. Multi-server installations have one division tree per server.

Every event and alarm has a division. It is usually the division of the source item. Card events or 'forced door' alarms, for example, typically use a door as a source item; when an operator modifies an item, the event recording that change uses that operator's workstation as the source item; the alarm that the server generates when you send a bad API key uses the server item as the source.

An event's division is not always its source's division. 'Card activated' events have the server as a source item, but take on the cardholder's division so that operators who can see the cardholder can also see when the server activates their cards.

To link privileges to items and events, an operator group contains a list of privileges and a list of divisions. Its operators enjoy those privileges on all the items, events, and alarms that are in those divisions.

Having a privilege on a division also grants an operator that privilege on that division's descendants. Therefore an operator with a privilege on the root division has that privilege on all that server's items and events.

A common misconception is that the division an operator is in, or the division an operator group is in, have a bearing on the operator's privileges. They do not. It is all about the divisions in the operator group's 'Operator privileges' list.

If your privileges do not seem to be working

First, to protect Command Centre from accident and malice, you should strive to grant your REST clients the fewest and lowest-level privileges you can. Do not give them 'advanced user'. Reaching a point where you do not receive the results you want is a good thing: it means you have screwed things down a little too tightly.

If changing privileges in Command Centre does not seem to make any difference, remember to push the 'Refresh operator privileges' button in the properties window of your REST Client item.

Here are some general rules that may help if you are still not receiving the results you expect.

  • Receiving a 403 from a GET means the server may not have a license for the retrieval you are attempting or your operator does not have the privilege to view that object. If it is a licensing problem, the body of the response will describe it.

  • Receiving a 403 from a PATCH, POST, or DELETE means your operator does not have the necessary privilege to perform that operation. You need one of the privileges beginning with 'Edit', 'Modify', or 'Create'.

  • Receiving a 404 when trying to get one item or event means it either does not exist or your operator does not have the privilege to view it.

  • Receiving a 200 and an empty result set from a search means you are licensed for that search but your operator could not see any items or events that matched. One possible cause is that your operator is not licensed to see any items or events of that kind. Make sure that one of the operator groups that your operator is in has a 'View' privilege such as 'View events' or 'View cardholders' - whatever is appropriate. If it does, and you have hit the button mentioned above, then check that the divisions on the operator group contain the items you expect. If it is events you are searching for, check the source item on those events either by using a REST operator with 'View events' on the root division or by looking at them in one of the thick clients.

Text encoding

Command Centre's REST API encodes all payloads using UTF-8, and expects clients to do the same. It does not escape special characters in response bodies except where required to embed them in JSON.

Specifically, it does not sanitise HTML, XML, or SQL. Your clients should expect to receive strings exactly as they were sent, even if they were sent by a hostile client. Write your clients to resist injection attacks.

Dates and times

When you send dates and times to Command Centre you must use an ISO-8601 calendar date, time, and time zone designator, with hyphens separating the date fields and colons separating the time fields. This looks like YYYY-MM-DDTHH:MM:SSZ, where T is an actual T, and Z is a timezone designator such as 'Z' for UTC or '-0800' for Pacific Standard Time. Specify up to seven decimals on the seconds if you wish, but be aware that some Command Centre fields will not use them. You must supply the year and month but omit the other fields as you like. Command Centre will assume sensible defaults, such as the top of the minute when you omit seconds, midnight when you omit the time, or first of the month when you omit the day.

Do not omit the timezone designator. If you do, Command Centre will make an assumption.

Item status

Most items have a status. Access zones, for example, can be in one of a few different modes, and have a zone count that rises and falls with cardholders arriving and leaving. Inputs and outputs can be on or off. Any item can be in an unknown state when the REST server is out of touch with its hardware. Et cetera.

The REST API can send an item's status to you in a string ready for human consumption in a UI, or as a list of flags more suitable for an integration. Neither of those fields are on an item's summary or details pages by default; to obtain them reliably you need to subscribe to updates.

Subscribing to status updates

The server does not always have an item's status: to prevent unnecessary work on the controller, network, and server, it will stop requesting updates when nothing is subscribed to them. It is very important that items stay in touch with their controllers, and controllers with each other, but it is normal for controllers to limit what they send back to the server.

The server will be up to date when one of the following happened recently:

  • an operator had the item visible in the Configuration, Command Centre, or mobile clients,
  • an application monitored the item via another API,
  • a REST client used the item in a status subscription, or
  • a REST client followed the item's updates link from its details page.

If it is not up to date and you request the status on an item's summary or details page, the server will report that the status is unknown.

To retrieve the status of one item you should GET the item's updates link from its details page. To monitor the status of many items you should use the status subscription API on the items controller (added in 8.30).

Whichever API you use, if the server does not have an item's status when you ask it will request an update from the item itself. For hardware items that may involve a conversation with another server, a hardware controller, and another piece of hardware on the end of a serial line. That all takes time, but the server answers you immediately, so the first response you receive may be 'unknown'. The status request continues in the background.

No matter what you receive, you should follow the next link in a loop until it gives you a status you are looking for, or another status indicating why it cannot. Your original request started a subscription, which every subsequent request refreshes, so while you stay in that loop the server will have the item's current status for you and all other callers.

The first status you will receive after 'unknown' will probably be 'controller unknown', which means that the controller (or other hardware) has received the server's request but does not yet have an answer, because of that serial line. You need something better, so stay in the loop.

Staying current

When you use the updates link on the item's details page it will return immediately. When you follow the next link in the page it returns, it will send back the status straight away if it changed since your previous call, or block until it does change. If nothing happens within a minute or so, it will return with no updates.

Whether you received an update or not, the body will contain a next link for you to follow for the next update.

State changes are not queued: the API only keeps the last, so it only takes one call to get yourself up to date with the server. Remember that the server itself may not have been up to date, and your making the call will have started it on its own little journey of discovery, which will cause more updates.

The 'Site' tab of the sample application shows this in operation.

For a user interface

The statusText field describes the state of the item in a multi-line string taken from the server's language pack. The natural state of a door, for example, is

Closed, locked, secure access.

A fence zone's status text could be

On - HV.
Voltage: 8.2 kV.
Seven day High Voltage min to max: 0.1kV to 9.8kV.
Pre-arm check while Alarm Zone is arming.

For one-line display, the status field is the same thing with spaces instead of line endings.

Neither of these is intended for integrations. By all means display them in a user interface (as Gallagher software does) but do not attempt to parse information out of them.

For an integration

The statusFlags field contains an array of string enumerations (flags) that describe the item's condition in a reliable and machine-readable way.

Each item type has a different set of flags. Some overlap (doors, inputs, and outputs can all be closed, for example) but most flags apply to only one kind of item. The common exceptions are the flags which indicate why the server cannot return the item's actual status, covered next.

Abnormal status flags

These are the status flags that indicate the server does not have the current status of the item:

  • unsaved and deleted are transient conditions you should not encounter in normal use. Either way, the item is in no condition to query.

  • unconfigured is very common while a site is being set up. It means the item does not have all the configuration it needs for normal operation. For example, an access zone is not configured until it has at least one door.

  • remoteServerOffline is only possible in a multi-server setup. It means that the item is remote (on a different server) and the server answering your REST query cannot reach it.

  • processOffline means the Controller service that is meant to be running on the Command Centre server, and handling all the communications with hardware controllers, is not.

  • controllerOffline means the software on the server is as it should be but the hardware controller (such as a C6000) is offline. That could mean it needs its certificate revalidated, or just that its power or networking is out.

  • notPolled means the item is shunted: Command Centre is ignoring the item's communications at the request of an operator. You normally do it to stop spurious alarms.

  • deviceNotResponding means exactly that. It means the server is in contact with the hardware controller, but there is a problem between there and the item. Probably a cable fault, unless encryptionKeysTampered accompanies it.

Those are fault conditions. If you see one of those, there is a configuration or hardware fault or a shunt preventing the server communicating with the item.

They are in priority order: if you receive one near the bottom of the list you can take heart in the knowledge that your item is suffering none of the preceding abnormalities.

There are two more flags that are common to most item types.

  • unknown means everything else is in order but you caught the server in a period when it simply had no need to stay in touch with the item. You will get this on a summary or details page, because they do not subscribe to updates for the item. The 'updates' link will not send you this status flag.

  • controllerUnknown is a transient state, hopefully. The 'updates' call often returns it the first time if the server does not have the item's status already. It means a component (such as a hardware controller) between the server and your item is working on bringing in an update. This generally resolves quickly, so if you follow the 'next' link you will receive the latest status.

The server will not send any other flags with one of those eleven, apart from the possible pairing of encryptionKeysTampered and deviceNotResponding, and some unusual combinations noted later.

Do not go looking for all of the abnormal status flags above and assume the best if they are not there. Gallagher may add more fault conditions in future versions of the API.

Instead, read each item's section under Operations for what its flags will be when it is online. A paragraph called "flag rules" shows how you can tell if the item is in a correct state. For the impatient: doors, inputs, and outputs will be open or closed, fence zones will be on or off, and alarm and access zones will be in one of four zone states.

Access Groups

These methods give you access to the access groups in Command Centre. You can search for groups, see their lineage, and list their cardholder members. In 8.40 or later you can see how they affect those members. In 9.30 and later you can create, modify, and delete them.

Your REST operator will need the 'View' or 'Edit Access Groups' operator privileges for the GETs, and 'Edit Access Groups' for the POST and PATCH.

These methods also provide the links you need to manage memberships. Those links are hrefs to cardholders, to which you would send PATCH requests containing your updates. Your REST operator will need 'Edit Cardholders' privilege on the cardholder for that.

Use cases

Finding members of an access group, and managing memberships.

  1. GET /api.

  2. Follow the link at features.accessGroups.accessGroups.href (adding search terms, and setting top high to save pagination).

  3. Find your access group in the results.

  4. The link at cardholders returns the cardholders who have direct membership of your group. This is only a subset of the cardholders who are affected by that group, as the groups that list this group as their parent inherit its effects recursively. If you are after every cardholder who has effective membership of your group, follow the group's href to get its detail page, which includes its child groups in an array called children. In a depth-first traversal you would recurse down through the hrefs in that array before proceeding.

  5. Get the link at cardholders (which is the same on the search results and the details page), look in that cardholder's accessGroups array, and manage each membership as you require. Send a DELETE to a membership's href to remove it, or an HTTP PATCH to the cardholder href to update it.

Building the group hierarchy.

  1. GET /api.
  2. Follow the link at features.accessGroups.accessGroups.href . If you follow the efficiency tips in the cardholder section you will add top and sort parameters.
  3. Record each group's href, name (if you intend to display the results), and parent.href, if it is there. An access group may have no parents or one parent, never more.
  4. Follow the link at next.href, if there is one, and repeat.

You can now assemble the groups into a tree.

Search access groups

This returns access groups matching your search criteria.

The result will contain no more than 100 or 1000 groups depending on your version; you should follow the next link, if it is present, to collect the next batch.

When you have loaded all the access groups there will be no next link.

If your result set is empty it means your operator does not have the privilege to view any access groups. Perhaps there are none in the divisions in which your operator has 'View access groups' or 'Edit access groups', or your operator has no privileges at all.

This request does not return the group's cardholders. That would make the results unwieldy. Instead, it provides a separate link.

Adding, deleting, or modifying access groups between calls to this API will not affect the pagination of its results if you sort by ID.

You can find the URL for this call in the features.accessGroups.accessGroups.href field of /api. In the interest of forward compability, do not build it yourself.

Authorizations:
API_keybasic
query Parameters
sort
string
Enum: "id" "name" "-id" "-name"

Changes the sort field between database ID and name.

If you prefix id or name with a minus sign (ASCII 45), the sort order is reversed.

There are two very strong reasons to sort by ID:

  1. Sorting by name carries a risk of missing or duplicating objects if your result set spans multiple pages and another operator is editing the database while your REST client is enumerating them. This is known as "page drift." Sorting by ID does not carry that risk.
  2. Following a next link is dramatically quicker when sorting by ID.

We strongly recommend sorting by ID. In case you were still in doubt, we will do that by default in a future version of Command Centre.

The server silently ignores anything except the options listed here.

top
integer >= 1

Sets the maximum number of access groups to return per page. The default depends on your server version; you should set it appropriately for your application.

name
string

Limits the returned items to those with a name that matches this string. Without surrounding quotes or a percent sign or underscore, it is a substring match; surround the parameter with double quotes "..." for an exact match. Without quotes, a percent sign % will match any substring and an underscore will match any single character.

The search is always case-insensitive. Results are undefined if you do a substring search for the empty string (name=). You will receive no items if you search for those with no name (name=""), as all items must have a name.

Search parameters are ANDed together.

division
Array of strings

Limits the returned items to those that are in these divisions.

That includes all the items in those divisions' child divisions, because Command Centre treats items as though they are also in their division's parent, and its parent, and so on up to the root division.

Separate the IDs of the divisions you are interested with commas. Item IDs are short alphanumeric strings, not URLs.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

directDivision
Array of strings

Restricts items to those whose division is in this list.

Unlike division=, it does not follow ancestry. That means it will limit the search to items that are directly assigned to the divisions you list, whereas division (without the direct) will also include items that are assigned to their descendants.

List the IDs of the divisions you are interested in separated by commas. Item IDs are short alphanumeric strings, not URLs.

Because this is the first query parameter we added that contains a capital letter, this will be the first time you have had to think about case sensitivity. directDivision works, directdivision does not.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

Added in 9.20.

description
string

Limits the returned items to those with a description that matches this string. By default it is a substring match; surround it with double quotes "..." for an exact match. A _ will match any single character, and a % will match any substring. With or without quotes, having either of these wildcards in the string will anchor it at both ends as though you had surrounded it with ".

The search is always case-insensitive. Results are undefined if you search for the empty string (description= or description="").

Search parameters are ANDed together.

fields
Array of strings
Default: "defaults"
Items Enum: "href" "id" "name" "description" "parent" "division" "children" "notes" "personalDataDefinitions" "cardholders" "access" "saltoAccess" "alarmZones" "..." "defaults"

Sets the list of fields to return in the search results. The values you can list are the same as the field names in the details page. Using it you can return everything on the search page that you would find on the details page. Separate values with commas.

Use the special value defaults to return the fields you would have received had you not given the parameter at all. Add more after a comma.

Treat the string matches as case sensitive.

In v8.00 you will receive the href and internal ID even if you didn't ask for them. In 8.10 you will not. If you are going to send the fields parameter and need the href or ID, include them.

pos
integer

Reserved for internal use. You may see it in URLs you receive from the server, but you must never add it yourself.

skip
integer

Reserved for internal use. Do not add it to your queries.

Responses

Response samples

Content type
application/json
{}

BetaCreate an access group

Creates a new access group, setting its basic fields, parent, PDFs, and some membership defaults.

Do not code this URL into your application. Take it from the href field in the features.accessGroups.accessGroups.href field of GET /api.

The POST expects a document in the same format as the access group detail. All fields except division are optional.

You will achieve better performance if you combine all you want to achieve into one POST, rather than creating the access group bare with a POST then refining it with PATCHes later.

When successful it returns a location header containing the address of the new access group.

Note that you can only create one access group per POST.

This call requires the RESTConfiguration licence and a server running 9.30 or later.

Authorizations:
API_keybasic
Request Body schema: application/json
required

This is the POST body you would use to create an access group. A division is mandatory.

name
string

All items have a name. Command Centre makes one up for you if you omit it when creating an item.

description
string
division
required
object

Mandatory when creating any access group. In this example, we want the access group in division 352.

parent
object

A link to the group's parent.

This field is optional in a POST because unlike divisions, which must have a parent, an access group can stand alone. But should you wish it to be a member of another, link it here.

An access group may be a member of only one other: multiple inheritance is not possible.

Use the blank string "" to clear a group's parent in a PATCH.

notes
string
membershipAutoRemoveExpired
boolean

If true, memberships will be removed when their until time passes. If false, they will remain on the cardholder, inactive.

membershipFromDefault
string <date-time>

When a cardholder is granted membership of this access group without specifying a 'from' time, this default will apply. If left blank, such a membership will not have a 'from' time. It will be effective immediately, provided its 'until' time is blank or in the future.

To clear it, send the blank string "".

membershipUntilDefault
string <date-time>

When a cardholder is granted membership of this access group without specifying an 'until' time, this default will apply. If blank, such a membership will not have an 'until' time. It will be effective until removed.

To clear it, send the blank string "".

Array of objects

Responses

Request samples

Content type
application/json
{}

Get details of an access group

In addition to the group's vitals and a link to the membership document in the access group search results, this call lists the group's child groups.

Note that you can obtain the same results by adding a fields query parameter to a search.

You can find the URL for this call in the access group search results and in a cardholder's accessGroups array. In the interest of forward compability, do not build it yourself.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
fields
Array of strings
Default: "defaults"
Items Enum: "href" "id" "name" "description" "parent" "division" "children" "notes" "personalDataDefinitions" "access" "saltoAccess" "alarmZones" "..." "defaults"

Sets the list of fields to return. The values you can list are the same as the field names in the detail results. Use it to return less data than normal. Separate values with commas.

Treat the string matches as case sensitive.

In v8.00 you will receive the href and internal ID even if you didn't ask for them. In 8.10 you will not. If you are going to send the fields parameter and need the href or ID, include them.

Responses

Response samples

Content type
application/json
{}

Update an access group

This is the call you use to modify fields on an access group.

The PATCH expects a document in the same format as the the access group detail but with fewer fields. Note that you cannot change everything on an access group that the API shows you, such as its membership, access, and permissions. You can change its basic fields, PDFs, and membership defaults.

You can find the URL for this call in the access group search results and in a cardholder's accessGroups array. In the interest of forward compability, do not build it yourself.

This call requires the RESTConfiguration licence and a server running 9.30 or later.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

Request Body schema: application/json
required

The body you would send to an access group PATCH has the same schema as an access group POST apart from the personalDataDefinitions block.

name
string

All items have a name. Command Centre makes one up for you if you omit it when creating an item.

description
string
division
object

Mandatory when creating any access group. In this example, we want the access group in division 352.

parent
object

A link to the group's parent.

This field is optional in a POST because unlike divisions, which must have a parent, an access group can stand alone. But should you wish it to be a member of another, link it here.

An access group may be a member of only one other: multiple inheritance is not possible.

Use the blank string "" to clear a group's parent in a PATCH.

notes
string
membershipAutoRemoveExpired
boolean

If true, memberships will be removed when their until time passes. If false, they will remain on the cardholder, inactive.

membershipFromDefault
string <date-time>

When a cardholder is granted membership of this access group without specifying a 'from' time, this default will apply. If left blank, such a membership will not have a 'from' time. It will be effective immediately, provided its 'until' time is blank or in the future.

To clear it, send the blank string "".

membershipUntilDefault
string <date-time>

When a cardholder is granted membership of this access group without specifying an 'until' time, this default will apply. If blank, such a membership will not have an 'until' time. It will be effective until removed.

To clear it, send the blank string "".

object

This object can contain two arrays named add and remove. Every element you put in those arrays should contain a string called href giving the href of a PDF that you want to add to or remove from the access group.

In this example we are adding PDF 5516 and removing 9370.

Responses

Request samples

Content type
application/json
{}

Remove an access group

This call removes an access group from Command Centre.

You can find the URL for this call in the access group search results and in a cardholder's accessGroups array. In the interest of forward compability, do not build it yourself.

This call requires the RESTConfiguration licence and a server running 9.30 or later.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

Responses

Get membership of an access group

This lists all cardholders who are direct members of a particular group. It does not paginate the results, so there is no next link. That can make for a large document, so it omits the group's child groups and their cardholder members. It is not recursive, in other words.

There may be more than one entry per cardholder, because any one cardholder can have many memberships to a group, each with different from and until date-times.

If your operator does not have the privilege to view a cardholder item you will receive its name but not its href (since following it would 404).

You can find the URL in the cardholders block of an access group's search results or detail pages. In the interest of forward compability, do not build it yourself.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

Responses

Response samples

Content type
application/json
{}

Access Zones

These methods give you read access to Access Zones in the Command Centre database, and let you change their modes, lock them down, and send other overrides.

The first use case below introduces the main entry point. It is a paginated search interface that gives any number of access zones, each containing the fields you ask for in the query.

Overrides

Note:

  1. End-times on overrides are not accurate to the second. Internally, Command Centre converts the end time to a duration, so you may find that submitting end times in the very near future does not have the exact effect you expect.
  2. An override without an end time lasts until the next mode change or 'cancel untimed overrides' entry in the access zone's schedule.
  3. The end time you set for an override cannot be in the past or more than 24 hours into the future.

Access Zone status flags

If the access zone is online, its statusFlags field may contain one or more of these flags:

  • saltoOutputOnly means the the access zone would be considered unconfigured because it is missing doors, and therefore offline, except that it has a Salto output number assigned to it. That is a normal operational configuration.

  • mobileZone also means the access zone would be considered unconfigured (missing doors) and therefore offline, except that a mobile reader is able to badge cardholders into it, making it a perfectly useful access zone. It will also have a secure flag.

  • lockedDown means only cardholders with the privilege to enter locked-down zones shall pass. The zone will also be 'secure'. When the lockdown override ends it will return to its previous access mode.

  • usePin means when you use a card at a reader to unlock the door or at a terminal to control an alarm zone, you will also need your PIN.

  • zoneCountTooHigh means the zone count is above its maximum.

  • zoneCountTooLow means the zone count is below its minimum.

  • zoneCountInGrace means the zone count recently became too low or high.

The following four give the zone's access state. An online access zone will always return one of them.

  • secure means the doors are locked.
  • dualAuth means the doors are locked and - depending on configuration - cardholders will need a second credential to open them.
  • codeOrCard means you can unlock a door either with a card, the zone's access code, or (if suitably configured on the reader) a personal user code. You will not see this flag if the zone is locked down.
  • free means the zone's doors are unlocked. You will not see this when the zone is locked down.

Access Zone flag rules

  • If and only if the zone online and not locked down, there will be exactly one of 'secure', 'dualAuth', 'codeOrCard', or 'free'.

  • If and only if the zone online and locked down, there will be exactly one of 'secure' or 'dualAuth'.

  • Because 'saltoOutputOnly' and 'mobileZone' are variations of the unconfigured offline condition, 'saltoOutputOnly' will be alone and only 'secure' will accompany 'mobileZone'.

  • If a zone has both a Salto output number and mobile access, only 'saltoOutputOnly' will appear.

  • If there is 'zoneCountInGrace' there will always be exactly one of 'zoneCountTooHigh' or 'zoneCountTooLow' (never both).

Using the first three rules above, your test for an access zone being in error is 'secure', 'dualAuth', 'codeOrCard', 'free', 'saltoOutputOnly', and 'mobileZone' all missing.

Use cases

Searching for access zones by name

  1. GET /api.
  2. Follow the link at features.accessZones.accessZones.href , appending a search term such as name=substring to filter the access zones, and fields to tell the server what to return about each. The next section covers those query parameters.
  3. Process the results, following the next link until there isn't one.

Changing an access zone's access mode

  1. Find the href for the access zone using the process above.
  2. GET it.
  3. Find the API URL you require in the commands structure of the results, such as free or securePin, from the detail. Use the until variants if you are specifying an end time.
  4. POST to that URL. Some require a JSON object (resetting the zone count, and all those with until in their command block keys). The others expect an empty body.

Finding an access zone's status

  1. Find the href for the access zone using the process above, and GET it.
  2. Take the updates href from that page. For a version 8.00 server append the query parameter separator (? or &) then fields=defaults,zoneCount if you need the zone count as well as the default status fields. The zone count is included by default in 8.10 and later.
  3. GET it.
  4. Use the flag rules above to interpret the status flags you receive.
  5. Follow the next link to stay up to date.

Search access zones

This returns a summary of the access zones matching your search criteria.

The result will contain no more than 100 or 1000 access zones (depending on your version), or as many as you asked for more in your request; you should follow the next link, if it is present, to collect the next batch.

If your result set is empty it means your operator does not have the privilege to view any access zones, such as 'View Site', 'Edit Site', or 'Override'. Perhaps there are no access zones in the divisions in which your operator has privileges, or your operator has no privileges at all.

When you have loaded them all there will be no next link.

Do not code this URL into your application. Take it from the 'href' field in the features.accessZones.accessZones section of /api.

Authorizations:
API_keybasic
query Parameters
sort
string
Enum: "id" "name" "-id" "-name"

Changes the sort field between database ID and name.

If you prefix id or name with a minus sign (ASCII 45), the sort order is reversed.

There are two very strong reasons to sort by ID:

  1. Sorting by name carries a risk of missing or duplicating objects if your result set spans multiple pages and another operator is editing the database while your REST client is enumerating them. This is known as "page drift." Sorting by ID does not carry that risk.
  2. Following a next link is dramatically quicker when sorting by ID.

We strongly recommend sorting by ID. In case you were still in doubt, we will do that by default in a future version of Command Centre.

The server silently ignores anything except the options listed here.

top
integer >= 1

Limits the results to no more than this many items per page.

Older versions of Command Centre returned 100 items per page in the absence of this parameter. That is acceptable for GUI applications that will only display the first page, but for integrations that intend to proceed through the entire database it causes a lot of chatter.

8.70 and later versions will default to 1000 items per request. This is about where a graph of throughput versus page size begins to level out.

name
string

Limits the returned items to those with a name that matches this string. Without surrounding quotes or a percent sign or underscore, it is a substring match; surround the parameter with double quotes "..." for an exact match. Without quotes, a percent sign % will match any substring and an underscore will match any single character.

The search is always case-insensitive. Results are undefined if you do a substring search for the empty string (name=). You will receive no items if you search for those with no name (name=""), as all items must have a name.

Search parameters are ANDed together.

division
Array of strings

Limits the returned items to those that are in these divisions.

That includes all the items in those divisions' child divisions, because Command Centre treats items as though they are also in their division's parent, and its parent, and so on up to the root division.

Separate the IDs of the divisions you are interested with commas. Item IDs are short alphanumeric strings, not URLs.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

directDivision
Array of strings

Restricts items to those whose division is in this list.

Unlike division=, it does not follow ancestry. That means it will limit the search to items that are directly assigned to the divisions you list, whereas division (without the direct) will also include items that are assigned to their descendants.

List the IDs of the divisions you are interested in separated by commas. Item IDs are short alphanumeric strings, not URLs.

Because this is the first query parameter we added that contains a capital letter, this will be the first time you have had to think about case sensitivity. directDivision works, directdivision does not.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

Added in 9.20.

description
string

Limits the returned items to those with a description that matches this string. By default it is a substring match; surround it with double quotes "..." for an exact match. A _ will match any single character, and a % will match any substring. With or without quotes, having either of these wildcards in the string will anchor it at both ends as though you had surrounded it with ".

The search is always case-insensitive. Results are undefined if you search for the empty string (description= or description="").

Search parameters are ANDed together.

fields
Array of strings
Default: "defaults"
Items Enum: "href" "id" "name" "shortName" "description" "division" "commands" "connectedController" "doors" "zoneCount" "statusFlags" "statusText" "status" "notes" "updates" "defaults"

This instructs the server to return only these fields in the search results. The values you can list are the same as the field names in the details page. Using this you can return everything on the summary page that you would find on the details page. Separate values with commas.

Use the special value defaults to return the fields you would have received had you not given the parameter at all. Obviously only do that if you have more to add.

Treat the string matches as case-sensitive.

In v8.00 you will receive the href and internal ID even if you did not ask for them. In 8.10 and later you will only get what you asked for. If you are going to send the fields parameter and need the href or ID, be explicit.

pos
integer

Reserved for internal use. You may see it in URLs you receive from the server, but you must never add it yourself.

skip
integer

Reserved for internal use. Do not add it to your queries.

Responses

Response samples

Content type
application/json
{}

Search targetable access zones

This returns a list of the access zones to which your operator is allowed to move cardholders, and a special zone you can use as a target to remove a cardholder from all access zones.

Like all other paginated queries in this API, the result will contain no more than 100 or 1000 access zones (depending on your version), or as many as you asked for more in your request; you should follow the next link, if it is present, to collect the next batch.

When you have loaded them all there will be no next link.

If your result set is empty it means there are no access zones in the divisions in which your operator has the privilege to move cardholders ('Manage Cardholder Location'), or your operator does not have the privilege at all.

Do not code this URL into your application. Take it from the 'href' field in the features.cardholders.updateLocationAccessZones section of /api.

Added in 8.20.

Authorizations:
API_keybasic
query Parameters
sort
string
Enum: "id" "name" "-id" "-name"

Changes the sort field between database ID and name.

If you prefix id or name with a minus sign (ASCII 45), the sort order is reversed.

There are two very strong reasons to sort by ID:

  1. Sorting by name carries a risk of missing or duplicating objects if your result set spans multiple pages and another operator is editing the database while your REST client is enumerating them. This is known as "page drift." Sorting by ID does not carry that risk.
  2. Following a next link is dramatically quicker when sorting by ID.

We strongly recommend sorting by ID. In case you were still in doubt, we will do that by default in a future version of Command Centre.

The server silently ignores anything except the options listed here.

top
integer >= 1

Limits the results to no more than this many items per page.

Older versions of Command Centre returned 100 items per page in the absence of this parameter. That is acceptable for GUI applications that will only display the first page, but for integrations that intend to proceed through the entire database it causes a lot of chatter.

8.70 and later versions will default to 1000 items per request. This is about where a graph of throughput versus page size begins to level out.

name
string

Limits the returned items to those with a name that matches this string. Without surrounding quotes or a percent sign or underscore, it is a substring match; surround the parameter with double quotes "..." for an exact match. Without quotes, a percent sign % will match any substring and an underscore will match any single character.

The search is always case-insensitive. Results are undefined if you do a substring search for the empty string (name=). You will receive no items if you search for those with no name (name=""), as all items must have a name.

Search parameters are ANDed together.

division
Array of strings

Limits the returned items to those that are in these divisions.

That includes all the items in those divisions' child divisions, because Command Centre treats items as though they are also in their division's parent, and its parent, and so on up to the root division.

Separate the IDs of the divisions you are interested with commas. Item IDs are short alphanumeric strings, not URLs.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

directDivision
Array of strings

Restricts items to those whose division is in this list.

Unlike division=, it does not follow ancestry. That means it will limit the search to items that are directly assigned to the divisions you list, whereas division (without the direct) will also include items that are assigned to their descendants.

List the IDs of the divisions you are interested in separated by commas. Item IDs are short alphanumeric strings, not URLs.

Because this is the first query parameter we added that contains a capital letter, this will be the first time you have had to think about case sensitivity. directDivision works, directdivision does not.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

Added in 9.20.

description
string

Limits the returned items to those with a description that matches this string. By default it is a substring match; surround it with double quotes "..." for an exact match. A _ will match any single character, and a % will match any substring. With or without quotes, having either of these wildcards in the string will anchor it at both ends as though you had surrounded it with ".

The search is always case-insensitive. Results are undefined if you search for the empty string (description= or description="").

Search parameters are ANDed together.

fields
Array of strings
Default: "defaults"
Items Enum: "href" "id" "name" "shortName" "description" "division" "commands" "connectedController" "doors" "zoneCount" "statusFlags" "statusText" "status" "notes" "updates" "defaults"

This instructs the server to return only these fields in the search results. The values you can list are the same as the field names in the details page. Using this you can return everything on the summary page that you would find on the details page. Separate values with commas.

Use the special value defaults to return the fields you would have received had you not given the parameter at all. Obviously only do that if you have more to add.

Treat the string matches as case-sensitive.

In v8.00 you will receive the href and internal ID even if you did not ask for them. In 8.10 and later you will only get what you asked for. If you are going to send the fields parameter and need the href or ID, be explicit.

pos
integer

Reserved for internal use. You may see it in URLs you receive from the server, but you must never add it yourself.

skip
integer

Reserved for internal use. Do not add it to your queries.

Responses

Response samples

Content type
application/json
{}

Get details of an access zone

This returns the detail of one access zone.

Follow the 'href' field in an access zone summary to get here rather than building it yourself.

Authorizations:
API_keybasic
path Parameters
id
required
string
query Parameters
fields
string
Enum: "href" "id" "name" "shortName" "description" "division" "commands" "connectedController" "doors" "zoneCount" "statusFlags" "statusText" "status" "notes" "updates"

This instructs the server to return only these fields in the details page instead of the default set. The values you can list are the same as the field names you would see in the results. Use it to cut back on the size of the response. Separate values with commas.

Treat the string matches as case-sensitive.

In v8.00 you will receive the href and internal ID even if you did not ask for them. In 8.10 and later you will only get what you asked for. If you are going to send the fields parameter and need the href or ID, be explicit.

Responses

Response samples

Content type
application/json
{}

Set an access zone to free

Sends an override to an access zone to change its mode to 'free - no PIN', meaning the doors will be free and you will not need a PIN to perform an override on a terminal.

Take this URL from the commands block of an access zone. In there is a block called free, containing a field href. That is the URL of this method.

The URL from commands.freePin.href (as opposed to "free" without the "Pin") will send an override to an access zone to change its mode to 'free - PIN', meaning you will need a PIN on a terminal.

If you do not give the override an end time in the body it will remain in place until the next scheduled change.

Authorizations:
API_keybasic
path Parameters
id
required
string

The ID of the access zone.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Request Body schema: application/json
optional

Put this in the body of override POSTs to set the time at which the override should cease. The API will reject the override if the string is not empty and it cannot parse it into a date-time, but it will treat the override as having no end time if you mis-spell 'endTime' or if you send a blank string.

Command Centre computes an override's duration to a whole number of minutes with a minimum of one. That means that a timed override will always end at a multiple of sixty seconds from the time the hardware receives the override request, which means the override will end within thirty seconds of the time you supplied here. In versions older than 8.80, the discrepancy may be up to a minute.

Careful observation of overrides submitted from the Configuration client and from the API will reveal that they use different rounding methods. Be assured, both result in overrides ending within a minute of the requested time.

endTime
string <date-time>

Responses

Request samples

Content type
application/json
{
  • "endTime": "2018-07-31T00:00:00Z"
}

Set an access zone to secure

Sends an override to an access zone to change its mode to 'secure - no PIN', meaning you will need a card, but not a PIN, to open its doors or perform overrides on terminals.

Take this URL from the commands block of an access zone. In there is a block called secure, containing a field href. That is the URL of this method.

The URL from commands.securePin.href (as opposed to without the "Pin") will send an override to an access zone to change its mode to 'secure - PIN', meaning you will need a PIN on a terminal.

If you do not give the override an end time in the body, it will remain in place until the next scheduled change.

Authorizations:
API_keybasic
path Parameters
id
required
string

The ID of the access zone.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Request Body schema: application/json
optional

Put this in the body of override POSTs to set the time at which the override should cease. The API will reject the override if the string is not empty and it cannot parse it into a date-time, but it will treat the override as having no end time if you mis-spell 'endTime' or if you send a blank string.

Command Centre computes an override's duration to a whole number of minutes with a minimum of one. That means that a timed override will always end at a multiple of sixty seconds from the time the hardware receives the override request, which means the override will end within thirty seconds of the time you supplied here. In versions older than 8.80, the discrepancy may be up to a minute.

Careful observation of overrides submitted from the Configuration client and from the API will reveal that they use different rounding methods. Be assured, both result in overrides ending within a minute of the requested time.

endTime
string <date-time>

Responses

Request samples

Content type
application/json
{
  • "endTime": "2018-07-31T00:00:00Z"
}

Set an access zone to code or card

Sends an override to an access zone to change its mode to 'Code or Card - No PIN', meaning you can use your user code or the zone's 'code-only code' to open its doors, depending on the reader's configuration. You will not need a PIN on a terminal.

Take this URL from the commands block of an access zone. In there is a block called codeOnly, containing a field href. That is the URL of this method.

The URL from commands.codeOnlyPin.href (as opposed to without the "Pin") will send an override to an access zone to change its mode to 'Code or Card - PIN', meaning you will need a PIN on a terminal.

If you do not give the override an end time in the body it will remain in place until the next scheduled change.

Authorizations:
API_keybasic
path Parameters
id
required
string

The ID of the access zone.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Request Body schema: application/json
optional

Put this in the body of override POSTs to set the time at which the override should cease. The API will reject the override if the string is not empty and it cannot parse it into a date-time, but it will treat the override as having no end time if you mis-spell 'endTime' or if you send a blank string.

Command Centre computes an override's duration to a whole number of minutes with a minimum of one. That means that a timed override will always end at a multiple of sixty seconds from the time the hardware receives the override request, which means the override will end within thirty seconds of the time you supplied here. In versions older than 8.80, the discrepancy may be up to a minute.

Careful observation of overrides submitted from the Configuration client and from the API will reveal that they use different rounding methods. Be assured, both result in overrides ending within a minute of the requested time.

endTime
string <date-time>

Responses

Request samples

Content type
application/json
{
  • "endTime": "2018-07-31T00:00:00Z"
}

Set an access zone to dual auth

Sends an override to an access zone to change its mode to 'dual auth - no PIN', meaning you will need two badges to open its doors (either two different cardholders or two credentials for the same cardholder, depending on the access zone's configuration), and they will not need a PIN. Terminal functions will require a card but no PIN.

Take this URL from the commands block of an access zone. In there is a block called dualAuth, containing a field href. That is the URL of this method.

The URL from commands.dualAuthPin.href (as opposed to without the "Pin") will send an override to an access zone to change its mode to 'dual auth - PIN', meaning you will need a PIN on a terminal.

If you do not give the override an end time in the body it will remain in place until the next scheduled change.

Authorizations:
API_keybasic
path Parameters
id
required
string

The ID of the access zone.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Request Body schema: application/json
optional

Put this in the body of override POSTs to set the time at which the override should cease. The API will reject the override if the string is not empty and it cannot parse it into a date-time, but it will treat the override as having no end time if you mis-spell 'endTime' or if you send a blank string.

Command Centre computes an override's duration to a whole number of minutes with a minimum of one. That means that a timed override will always end at a multiple of sixty seconds from the time the hardware receives the override request, which means the override will end within thirty seconds of the time you supplied here. In versions older than 8.80, the discrepancy may be up to a minute.

Careful observation of overrides submitted from the Configuration client and from the API will reveal that they use different rounding methods. Be assured, both result in overrides ending within a minute of the requested time.

endTime
string <date-time>

Responses

Request samples

Content type
application/json
{
  • "endTime": "2018-07-31T00:00:00Z"
}

Forgive antipassback on a zone

Sends an override to an access zone to forgive anti-passback for all cardholders in the zone.

Authorizations:
API_keybasic
path Parameters
id
required
string

The ID of the access zone.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Responses

Lock a zone down

Locks down an access zone. In this mode, cardholders will need the 'Entry allowed during lockdown' privilege to enter the zone, in addition to normal access.

Take this URL from the commands block of an access zone. In there is a block called lockDown, containing a field href. That is the URL of this method.

It takes no parameters. The lockdown will remain in place until cancelled, or the access zone receives an override to another mode.

Authorizations:
API_keybasic
path Parameters
id
required
string

The ID of the access zone.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Responses

Cancel a zone lockdown

Cancels a lockdown, returning it to its scheduled state. It will not cancel any other kind of override.

Take this URL from the commands block of an access zone. In there is a block called cancelLockDown, containing a field href. That is the URL of this method.

Authorizations:
API_keybasic
path Parameters
id
required
string

The ID of the access zone.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Responses

Set a zone count

Sets the count of cardholders inside a zone.

Authorizations:
API_keybasic
path Parameters
id
required
string

The ID of the access zone.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Request Body schema: application/json
required

The new cardholder count for the zone.

zoneCount
required
integer

Put this in the body of access zone override POSTs to set the count of cardholders in the access zone.

Responses

Request samples

Content type
application/json
{
  • "zoneCount": 100
}

Cancel mode override

Cancels an override, returning the access zone to its scheduled state.

Take this URL from the commands block of an access zone. In there is a block called cancel, containing a field href. That is the URL of this method.

This command will achieve nothing if the alarm zone is not controlled by a schedule, because without a schedule the alarm zone does not have the concept of a 'normal' state.

It will not cancel a lockdown. For that you need cancel_lock_down.

Authorizations:
API_keybasic
path Parameters
id
required
string

The ID of the access zone.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Responses

Monitor an access zone

See the item status topic for how to use the updates APIs.

Note that this API call is good for watching one item only; if you want to monitor several, you are better off with a status subscription.

Follow the 'updates' field in an access zone summary or details pages to get here rather than building it yourself.

Authorizations:
API_keybasic
path Parameters
id
required
string

The ID of the access zone.

query Parameters
fields
string
Enum: "status" "statusText" "statusFlags" "zoneCount"

This instructs the server to return these fields in the update, instead of the default set. Note that removing fields also saves you from updates to those fields.

Responses

Response samples

Content type
application/json
{}

Alarms

Use these methods to download, monitor, and manage Command Centre alarms.

Alarm states

Each type of alarm can be stateless or stateful. Stateless alarm types are spikes, such as an operator getting their password wrong or a cardholder being denied at a door. Stateful alarms have a triggering event and a restoring event, such as a door being forced open then closed, or a service going offline then reappearing later.

An operator cannot process (dismiss) an active alarm without the 'Force process' privilege.

The API presents the difference in a field called active. It will always be false for stateless alarms, and it will be true for stateful alarms before their restoring event occurs.

Alarm use cases

Downloading and managing unprocessed alarms

  1. GET /api
  2. Follow the link at features.alarms.alarms . You will receive up to 100 alarms, each containing links to its management functions.
  3. If step 2 returned results and there is a link at next.href, follow it and repeat.

Staying up to date

After getting all the current alarms using the process above, which is following next.href in a loop until there are no more alarms to get, follow the link at updates.href. It will block until there is a new alarm or a change to an existing alarm. After handling that update, follow the link it contains at next.href and keep following it in a loop to stay up to date.

Licensing

  • The GETs that collect alarms and events require the RESTEvents licence.

Get current alarms

This returns the current list of unprocessed alarms. The result will contain no more than 100 alarms; you should follow the next link, if it is present, to collect more.

You can tell when you have loaded all the current alarms because there will not be a next link. Instead, there will be an updates link which takes you to a different endpoint that long-polls for live updates to alarms.

Unlike the corresponding method that retrieves events, this call does not take query parameters to filter its results. You can limit the fields it returns, but it will always return every alarm that your operator can view. If you wish to restrict it to alarms in certain divisions, give your operator permission to view alarms in only those divisions.

The alarm summary only contains unprocessed alarms. You can access a processed alarm by finding its corresponding event in the event summary and following its alarm.href link to the alarm details.

Do not code this URL into your application. Take it from alarms.alarms.href in the results of GET /api.

Authorizations:
API_keybasic
query Parameters
fields
string
Enum: "href" "id" "time" "message" "source" "type" "eventType" "priority" "state" "active" "division" "notePresets" "view" "comment" "acknowledgeWithComment" "acknowledge" "processWithComment" "process" "details" "history" "instruction" "cardholder" "event"

Sets the fields you want in your results. Separate fields with commas.

New to 8.40.

Responses

Response samples

Content type
application/json
{}

Get changes to alarms (or wait)

This is a long poll for live updates to alarms. If alarms occurred or changed since the previous call, no matter how long ago that was, it will return them immediately. If there are no updates pending, it will wait until one arrives. If none arrive before a timeout passes (about 30 seconds) it will return an empty updates array and a fresh next link.

Whether or not the response contained updates the client should follow the next link to wait for the next updates.

If your server receives a lot of alarm updates, wait some time between calls to reduce chatter. You will not miss any alarms: each response contains all the alarms that happened since the previous call, even if an operator processed the alarms in question.

You will receive each alarm only once in a result set, in its current state. For example if an alarm is raised, restored, acknowledged, then processed between two of your API calls you will receive it as 'processed' in your next call. If, however, you make API calls between each of the alarm's state changes you will receive it four times: active, inactive and unacknowledged, acknowledged, then finally processed.

Do not wait if you receive 100 updates or more. 100 is the maximum number of updates current versions of CC will return in one batch, so if that happens you have fallen behind: there are more updates waiting and you can catch up by asking for them immediately.

Command Centre does not tell you which alarms were added, removed, or modified. It is up to you to match the incoming alarms against your own internal alarm list and determine the differences.

Do not code this URL into your application. Take it from alarms.updates.href in the results of GET /api, or from updates in the results of GET /api/alarms, or from next in the results of this call. Do not attempt to interpret or set the id query parameter in the URL, as it tracks your progress through the alarm history.

Assuming you got the URL for this call from the response from another call, and your operator therefore has the privileges required to view alarms, this should always complete successfully.

Authorizations:
API_keybasic
query Parameters
fields
string
Enum: "href" "id" "time" "message" "source" "type" "eventType" "priority" "state" "active" "division" "notePresets" "view" "comment" "acknowledgeWithComment" "acknowledge" "processWithComment" "process" "details" "history" "instruction" "cardholder" "event"

Sets the fields you want in your results. Separate fields with commas.

New to 8.40.

Responses

Response samples

Content type
application/json
{}

Get details of an alarm

Full details for an alarm. Follow the href in the alarm summary to get here.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier. Do not insert this into your request yourself. Instead you should get the URL of this call from other results: the alarm summary or details, in this case.

query Parameters
fields
string
Enum: "href" "id" "time" "message" "source" "type" "eventType" "priority" "state" "active" "division" "notePresets" "view" "comment" "acknowledgeWithComment" "acknowledge" "processWithComment" "process" "details" "history" "instruction" "cardholder" "event"

Sets the fields you want in your results. Separate fields with commas.

New to 8.40.

Responses

Response samples

Content type
application/json
{}

Mark an alarm as viewed

Mark the alarm as viewed. Follow the view link in the alarm summary to get here.

You can do this for an alarm in any state, even processed, provided you have its URL and sufficient privilege.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier. Do not insert this into your request yourself. Instead you should get the URL of this call from other results: the alarm summary or details, in this case.

Request Body schema: application/json
optional

Optional comment.

comment
string

Optional for some methods that update alarms. Contains a comment placed by the operator.

Responses

Request samples

Content type
application/json
{
  • "comment": "Alarm was adequately explained."
}

Add a comment to an alarm

Follow the comment link in the alarm summary to get here.

You can comment on an alarm in any state, even processed, provided you have its URL and sufficient privilege.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier. Do not insert this into your request yourself. Instead you should get the URL of this call from other results: the alarm summary or details, in this case.

Request Body schema: application/json
optional

Optional comment.

comment
string

Optional for some methods that update alarms. Contains a comment placed by the operator.

Responses

Request samples

Content type
application/json
{
  • "comment": "Alarm was adequately explained."
}

Mark an alarm as acknowledged

Follow the acknowledgeWithComment or the acknowledge link in the alarm summary to get here.

You can acknowledge an alarm that is in any state provided you have its URL and sufficient privilege. Doing so will add an entry to the alarm's history, but will have no other effect if it is already acknowledged or processed.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier. Do not insert this into your request yourself. Instead you should get the URL of this call from other results: the alarm summary or details, in this case.

Request Body schema: application/json
optional

Optional comment.

comment
string

Optional for some methods that update alarms. Contains a comment placed by the operator.

Responses

Request samples

Content type
application/json
{
  • "comment": "Alarm was adequately explained."
}

Mark an alarm as processed

Follow the processWithComment, forceProcess, or process link in the alarm to get here.

You can process an alarm that is in any state provided you have its URL and sufficient privilege. Doing so will add an entry to the alarm's history, but will have no other effect if it is already acknowledged or processed. If the alarm is active -- waiting for another event to restore it (such as a 'door open too long' waiting for the door to close) -- it will perform a force process.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier. Do not insert this into your request yourself. Instead you should get the URL of this call from other results: the alarm summary or details, in this case.

Request Body schema: application/json
optional

Optional comment.

comment
string

Optional for some methods that update alarms. Contains a comment placed by the operator.

Responses

Request samples

Content type
application/json
{
  • "comment": "Alarm was adequately explained."
}

Alarm Zones

These methods give you read access to Alarm Zones in the Command Centre database, and let you change their states: armed, disarmed, two user-defined states, and (if at least one Fence Zone is directing its events to this Alarm Zone) 'Armed - High Voltage' or 'Armed - Low Feel'.

Alarm zones may run by a schedule, but it is optional. Alarm zones that do not have a schedule change state only through manual overrides, meaning they do not have a natural state. That in turn means that you cannot override them for a duration -- they have no state to return to.

The first use case below introduces the main entry point. It is a paginated search interface that gives you any number of alarm zones, each containing the fields you ask for in the query.

Overrides

Note:

  1. End-times on overrides are not accurate to the second. Internally, Command Centre converts the end time to a duration, so you may find that submitting end times in the very near future does not have the exact effect you expect.
  2. Submitting an override without an end time makes it take effect until the next state change or 'cancel untimed overrides' entry in the alarm zone's schedule.
  3. Overrides you submit via REST are not subject to the "manual unset" timeouts you can set in the Configuration Client. Those only affect readers, terminals, and pushbuttons.
  4. The end time you set for an override cannot be in the past or more than 24 hours into the future.

Alarm Zone status flags

If the alarm zone is online, its statusFlags field will contain one or more of these flags:

  • armed means the alarm zone is armed. It will be called that even if you have changed the terminology in the Server Properties.

  • disarmed as above.

  • user1 will be called that even if you have given it a different name in Server Properties.

  • user2 as above.

  • exitDelay means the zone is temporarily ignoring input triggers. One of the previous four flags shows you the state the zone is about to change away from.

  • entryDelay means an input has triggered the alarm zone but Command Centre is giving a cardholder the opportunity to disarm the zone.

  • lowFeel means the alarm zone has a fence zone attached, and that it is in 'low feel' mode (meaning it is delivering lower voltage than you would use for a strong deterrant).

  • highVoltage means that the alarm zone has a fence zone attached, and that it is 'high voltage' mode (meaning it is delivering a strong deterrant pulse).

Alarm Zone flag rules

  • If and only if the zone is online, there will exactly one of 'armed', 'disarmed', 'user1', or 'user2'. That is your test for whether an alarm zone is in error.
  • 'exitDelay' and 'entryDelay' cannot appear together.
  • If and only if the zone is online and has a fence zone, there will be exactly one of 'lowFeel' or 'highVoltage'.

Use cases

Searching for alarm zones by name

  1. GET /api.
  2. Follow the link at features.alarmZones.alarmZones.href , appending a search term such as name=substring to filter the access zones, and fields to tell the server what to return about each. The next section covers those query parameters.
  3. Process the results, following the next link until there isn't one.

Changing an alarm zone's state

  1. Find the href for the alarm zone using the process above.
  2. GET it.
  3. Find the API URL you require in the commands structure of the results, such as arm or disarm , using the detail. Use the calls with Until on the ends of their names if you are specifying an end time.
  4. POST to that URL. All those with Until in their names require a JSON object in the body giving the time at which the override should end; the others do not.

Finding an alarm zone's status

  1. Find the href for the alarm zone using the process above, and GET it.
  2. Follow the updates href from that page.
  3. Use the flag rules above to interpret the status flags you receive.
  4. Follow the next link to stay up to date.

Search alarm zones

This returns a summary of the alarm zones matching your search criteria.

The result will contain no more than 100 or 1000 alarm zones (depending on your version), or as many as you asked for more in your request; you should follow the next link, if it is present, to collect the next batch.

If your result set is empty it means your operator does not have the privilege to view any alarm zones, such as 'View Site', 'Edit Site', or 'Override'. Perhaps there are no alarm zones in the divisions in which your operator has privileges, or your operator has no privileges at all.

When you have loaded them all there will be no next link.

Do not code this URL into your application. Take it from the 'href' field in the features.alarmZones.alarmZones section of /api.

Authorizations:
API_keybasic
query Parameters
sort
string
Enum: "id" "name" "-id" "-name"

Changes the sort field between database ID and name.

If you prefix id or name with a minus sign (ASCII 45), the sort order is reversed.

There are two very strong reasons to sort by ID:

  1. Sorting by name carries a risk of missing or duplicating objects if your result set spans multiple pages and another operator is editing the database while your REST client is enumerating them. This is known as "page drift." Sorting by ID does not carry that risk.
  2. Following a next link is dramatically quicker when sorting by ID.

We strongly recommend sorting by ID. In case you were still in doubt, we will do that by default in a future version of Command Centre.

The server silently ignores anything except the options listed here.

top
integer >= 1

Limits the results to no more than this many items per page.

Older versions of Command Centre returned 100 items per page in the absence of this parameter. That is acceptable for GUI applications that will only display the first page, but for integrations that intend to proceed through the entire database it causes a lot of chatter.

8.70 and later versions will default to 1000 items per request. This is about where a graph of throughput versus page size begins to level out.

name
string

Limits the returned items to those with a name that matches this string. Without surrounding quotes or a percent sign or underscore, it is a substring match; surround the parameter with double quotes "..." for an exact match. Without quotes, a percent sign % will match any substring and an underscore will match any single character.

The search is always case-insensitive. Results are undefined if you do a substring search for the empty string (name=). You will receive no items if you search for those with no name (name=""), as all items must have a name.

Search parameters are ANDed together.

division
Array of strings

Limits the returned items to those that are in these divisions.

That includes all the items in those divisions' child divisions, because Command Centre treats items as though they are also in their division's parent, and its parent, and so on up to the root division.

Separate the IDs of the divisions you are interested with commas. Item IDs are short alphanumeric strings, not URLs.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

directDivision
Array of strings

Restricts items to those whose division is in this list.

Unlike division=, it does not follow ancestry. That means it will limit the search to items that are directly assigned to the divisions you list, whereas division (without the direct) will also include items that are assigned to their descendants.

List the IDs of the divisions you are interested in separated by commas. Item IDs are short alphanumeric strings, not URLs.

Because this is the first query parameter we added that contains a capital letter, this will be the first time you have had to think about case sensitivity. directDivision works, directdivision does not.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

Added in 9.20.

description
string

Limits the returned items to those with a description that matches this string. By default it is a substring match; surround it with double quotes "..." for an exact match. A _ will match any single character, and a % will match any substring. With or without quotes, having either of these wildcards in the string will anchor it at both ends as though you had surrounded it with ".

The search is always case-insensitive. Results are undefined if you search for the empty string (description= or description="").

Search parameters are ANDed together.

fields
Array of strings
Items Enum: "href" "id" "name" "shortName" "description" "division" "commands" "connectedController" "statusFlags" "status" "notes" "updates" "defaults"

This instructs the server to return only these fields in the search results. The values you can list are the same as the field names in the details page. Using this you can return everything on the summary page that you would find on the details page. Separate values with commas.

Use the special value defaults to return the fields you would have received had you not given the parameter at all. Obviously only do that if you have more to add.

Treat the string matches as case-sensitive.

In v8.00 you will receive the href and internal ID even if you did not ask for them. In 8.10 and later you will only get what you asked for. If you are going to send the fields parameter and need the href or ID, be explicit.

pos
integer

Reserved for internal use. You may see it in URLs you receive from the server, but you must never add it yourself.

skip
integer

Reserved for internal use. Do not add it to your queries.

Responses

Response samples

Content type
application/json
{}

Get details of an alarm zone

This returns the detail of one alarm zone.

Follow the 'href' field in an alarm zone summary to get here rather than building it yourself.

Authorizations:
API_keybasic
path Parameters
id
required
string

The ID of the alarm zone.

query Parameters
fields
string
Enum: "href" "id" "name" "shortName" "description" "division" "commands" "connectedController" "statusFlags" "status" "notes" "updates"

This instructs the server to return only these fields in the details page instead of the default set. The values you can list are the same as the field names you would see in the results. Use it to cut back on the size of the response. Separate values with commas.

Treat the string matches as case-sensitive.

In v8.00 you will receive the href and internal ID even if you did not ask for them. In 8.10 and later you will only get what you asked for. If you are going to send the fields parameter and need the href or ID, be explicit.

Responses

Response samples

Content type
application/json
{}

Arm an alarm zone

Sends an override to an alarm zone to arm it.

If you send an end time in the body, and the alarm zone has a schedule to consult to find the state that it should return to, the override will only stay in effect until then.

If you do not, the override will remain in place until the next scheduled or manual change.

Follow one of the 'commands.arm' or 'commands.armUntil' fields in an alarm zone to get here rather than building it yourself.

Authorizations:
API_keybasic
path Parameters
id
required
string

The ID of the alarm zone.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Request Body schema: application/json
optional

Put this in the body of override POSTs to set the time at which the override should cease. The API will reject the override if the string is not empty and it cannot parse it into a date-time, but it will treat the override as having no end time if you mis-spell 'endTime' or if you send a blank string.

Command Centre computes an override's duration to a whole number of minutes with a minimum of one. That means that a timed override will always end at a multiple of sixty seconds from the time the hardware receives the override request, which means the override will end within thirty seconds of the time you supplied here. In versions older than 8.80, the discrepancy may be up to a minute.

Careful observation of overrides submitted from the Configuration client and from the API will reveal that they use different rounding methods. Be assured, both result in overrides ending within a minute of the requested time.

endTime
string <date-time>

Responses

Request samples

Content type
application/json
{
  • "endTime": "2018-07-31T00:00:00Z"
}

Disarm an alarm zone

Sends an override to an alarm zone to disarm it.

If you send an end time in the body, and the alarm zone has a schedule to consult to find the state that it should return to, the override will only stay in effect until then.

If you do not, the override will remain in place until the next scheduled or manual change.

Follow one of the 'commands.disarm' or 'commands.disarmUntil' fields in an alarm zone to get here rather than building it yourself.

Authorizations:
API_keybasic
path Parameters
id
required
string

The ID of the alarm zone.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Request Body schema: application/json
optional

Put this in the body of override POSTs to set the time at which the override should cease. The API will reject the override if the string is not empty and it cannot parse it into a date-time, but it will treat the override as having no end time if you mis-spell 'endTime' or if you send a blank string.

Command Centre computes an override's duration to a whole number of minutes with a minimum of one. That means that a timed override will always end at a multiple of sixty seconds from the time the hardware receives the override request, which means the override will end within thirty seconds of the time you supplied here. In versions older than 8.80, the discrepancy may be up to a minute.

Careful observation of overrides submitted from the Configuration client and from the API will reveal that they use different rounding methods. Be assured, both result in overrides ending within a minute of the requested time.

endTime
string <date-time>

Responses

Request samples

Content type
application/json
{
  • "endTime": "2018-07-31T00:00:00Z"
}

Change an alarm zone to user1

Sends an override to an alarm zone to set its state to 'user1', one of the custom states.

If you send an end time in the body, and the alarm zone has a schedule to consult to find the state that it should return to, the override will only stay in effect until then.

If you do not, the override will remain in place until the next scheduled or manual change.

Follow one of the 'commands.user1' or 'commands.user1Until' fields in an alarm zone to get here rather than building it yourself.

Authorizations:
API_keybasic
path Parameters
id
required
string

The ID of the alarm zone.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Request Body schema: application/json
optional

Put this in the body of override POSTs to set the time at which the override should cease. The API will reject the override if the string is not empty and it cannot parse it into a date-time, but it will treat the override as having no end time if you mis-spell 'endTime' or if you send a blank string.

Command Centre computes an override's duration to a whole number of minutes with a minimum of one. That means that a timed override will always end at a multiple of sixty seconds from the time the hardware receives the override request, which means the override will end within thirty seconds of the time you supplied here. In versions older than 8.80, the discrepancy may be up to a minute.

Careful observation of overrides submitted from the Configuration client and from the API will reveal that they use different rounding methods. Be assured, both result in overrides ending within a minute of the requested time.

endTime
string <date-time>

Responses

Request samples

Content type
application/json
{
  • "endTime": "2018-07-31T00:00:00Z"
}

Change an alarm zone to user2

Sends an override to an alarm zone to set its state to 'user2', the other of of the custom states.

If you send an end time in the body, and the alarm zone has a schedule to consult to find the state that it should return to, the override will only stay in effect until then.

If you do not, the override will remain in place until the next scheduled or manual change.

Follow one of the 'commands.user2' or 'commands.user2Until' fields in an alarm zone to get here rather than building it yourself.

Authorizations:
API_keybasic
path Parameters
id
required
string

The ID of the alarm zone.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Request Body schema: application/json
optional

Put this in the body of override POSTs to set the time at which the override should cease. The API will reject the override if the string is not empty and it cannot parse it into a date-time, but it will treat the override as having no end time if you mis-spell 'endTime' or if you send a blank string.

Command Centre computes an override's duration to a whole number of minutes with a minimum of one. That means that a timed override will always end at a multiple of sixty seconds from the time the hardware receives the override request, which means the override will end within thirty seconds of the time you supplied here. In versions older than 8.80, the discrepancy may be up to a minute.

Careful observation of overrides submitted from the Configuration client and from the API will reveal that they use different rounding methods. Be assured, both result in overrides ending within a minute of the requested time.

endTime
string <date-time>

Responses

Request samples

Content type
application/json
{
  • "endTime": "2018-07-31T00:00:00Z"
}

Arm an alarm zone (high voltage)

Sends an override to an alarm zone to set its state to 'armed - high voltage'.

If you send an end time in the body, and the alarm zone has a schedule to consult to find the state that it should return to, the override will only stay in effect until then.

If you do not, the override will remain in place until the next scheduled or manual change.

Follow one of the 'commands.highVoltage or 'commands.highVoltageUntil' fields in an alarm zone to get here rather than building it yourself.

Authorizations:
API_keybasic
path Parameters
id
required
string

The ID of the alarm zone.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Request Body schema: application/json
optional

Put this in the body of override POSTs to set the time at which the override should cease. The API will reject the override if the string is not empty and it cannot parse it into a date-time, but it will treat the override as having no end time if you mis-spell 'endTime' or if you send a blank string.

Command Centre computes an override's duration to a whole number of minutes with a minimum of one. That means that a timed override will always end at a multiple of sixty seconds from the time the hardware receives the override request, which means the override will end within thirty seconds of the time you supplied here. In versions older than 8.80, the discrepancy may be up to a minute.

Careful observation of overrides submitted from the Configuration client and from the API will reveal that they use different rounding methods. Be assured, both result in overrides ending within a minute of the requested time.

endTime
string <date-time>

Responses

Request samples

Content type
application/json
{
  • "endTime": "2018-07-31T00:00:00Z"
}

Arm an alarm zone (low feel)

Sends an override to an alarm zone to set its state to 'armed - low feel'.

If you send an end time in the body, and the alarm zone has a schedule to consult to find the state that it should return to, the override will only stay in effect until then.

If you do not, the override will remain in place until the next scheduled or manual change.

Follow one of the 'commands.lowFeel or 'commands.lowFeelUntil' fields in an alarm zone to get here rather than building it yourself.

Authorizations:
API_keybasic
path Parameters
id
required
string

The ID of the alarm zone.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Request Body schema: application/json
optional

Put this in the body of override POSTs to set the time at which the override should cease. The API will reject the override if the string is not empty and it cannot parse it into a date-time, but it will treat the override as having no end time if you mis-spell 'endTime' or if you send a blank string.

Command Centre computes an override's duration to a whole number of minutes with a minimum of one. That means that a timed override will always end at a multiple of sixty seconds from the time the hardware receives the override request, which means the override will end within thirty seconds of the time you supplied here. In versions older than 8.80, the discrepancy may be up to a minute.

Careful observation of overrides submitted from the Configuration client and from the API will reveal that they use different rounding methods. Be assured, both result in overrides ending within a minute of the requested time.

endTime
string <date-time>

Responses

Request samples

Content type
application/json
{
  • "endTime": "2018-07-31T00:00:00Z"
}

Cancel mode override

Cancels an override, returning the alarm zone to its scheduled state.

Follow the 'commands.cancel' field in an alarm zone to get here rather than building it yourself.

Authorizations:
API_keybasic
path Parameters
id
required
string

The ID of the alarm zone.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Responses

Monitor an alarm zone

See the item status topic for how to use the updates APIs.

Note that this API call is good for watching one item only; if you want to monitor several, you are better off with a status subscription.

Follow the 'updates' field in an alarm zone summary or details pages to get here.

Authorizations:
API_keybasic
path Parameters
id
required
string

The ID of the alarm zone.

query Parameters
fields
string
Enum: "status" "statusText" "statusFlags"

This instructs the server to return these fields in the update, instead of the default set. Note that removing fields also saves you from updates to those fields.

Responses

Response samples

Content type
application/json
{}

Card encoding

These routes allow clients to get Gallagher card encoding data for MIFARE DESFire and MIFARE Classic cards.

  • Following features are required in the licence file:
    • RESTCardholders
    • RESTEncoding
    • Encoding
    • Photo-ID
  • The REST Client operator should have following privileges:
    • View Cardholders
    • Print/Preview & Encode Card
    • Allow Re-Printing and Re-Encoding (optional, depending on whether you want to allow re-encoding of already-encoded cards)
  • Bytes are encoded as hex strings in decrypted encoding data.
  • Sensitive data is encrypted in responses.
  • Using the client certificate for authentication is recommended.

Configuration End to End Encryption

  1. Using openssl to generate ECDH_P384 public/private key pair
openssl ecparam -name secp384r1 -genkey -noout -out private.pem

openssl ec -in private.pem -pubout -outform DER | tail -c 97 | head -c 97 | xxd -p -c 97

openssl req -new -x509 -key private.pem -out E2EEncryptionKey.crt -days 365 -subj "/CN=Command Center REST Client E2E Encryption Key"

openssl pkcs12 -export -out key.pfx -inkey private.pem -in E2EEncryptionKey.crt
  1. Store the private key securely on the encoding client side, e.g, storing it in Windows Certificate Store.
Import-PfxCertificate -FilePath "path\to\key.pfx" -CertStoreLocation Cert:\CurrentUser\My -Password (Read-Host "Enter PFX Password" -AsSecureString)
  1. Open the REST Client settings in Configuration Client, put the X9.63 hex format of public key to the Remote Public Key input in E2E Key tab.

Code Example for Client-Side Decryption

using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Text.Json;

var options = new JsonSerializerOptions
{
    PropertyNameCaseInsensitive = true
};

// Load private key from Windows Certificate Store
// Open the Current User store
using X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);

// Find the certificate by Subject Name
X509Certificate2? cert = store.Certificates
    .Find(X509FindType.FindBySubjectDistinguishedName, "CN=Command Center REST Client E2E Encryption Key", false)
    .FirstOrDefault();

if (cert == null)
{
    Console.WriteLine("Error: Certificate not found.");
    return;
}

// 3. Get The Private Key
ECDiffieHellman? privateKey = cert.GetECDiffieHellmanPrivateKey();

if (privateKey == null)
{
    throw new Exception("Certificate found, but private key is not accessible or not ECDH.");
}

Console.WriteLine($"Successfully retrieved key. Curve: {privateKey.ExportParameters(false).Curve.Oid.FriendlyName}");

// Simulated API response (replace with actual API call and response content)
var apiResponseJson = @"{
    ""encryptedEncodingData"": {
        ""cipherText"": ""<base64-encoded cipher text>"",
        ""iv"": ""<base64-encoded IV>"",
        ""ephemeralPublicKey"": ""<base64-encoded ephemeral public key>"",
        ""tag"": ""<base64-encoded authentication tag>""
    },
    ""callback"": {
    ""encodeCompleted"": {
        ""href"": ""https://<commandcentre host name>/api/cardholders/{id}/cards/{secondary_id}/encodeCompleted?token=abc"" },
        ""encodeFailed"": {
            ""href"": ""https://<commandcentre host name>/api/cardholders/{id}/cards/{secondary_id}/encodeFailed?token=abc"" }
        }
    }";

var response = JsonSerializer.Deserialize<EncryptedEncodingDataResponse>(apiResponseJson, options);
if (response == null)
{
    throw new Exception("Cannot deserialize response.");
}

// Derive the shared secret
var encryptedData = response.EncryptedEncodingData;
using var ephemeralKey = ECDiffieHellman.Create();
ephemeralKey.ImportSubjectPublicKeyInfo(encryptedData.EphemeralPublicKey, out _);
byte[] sharedSecret = privateKey.DeriveKeyFromHash(ephemeralKey.PublicKey, HashAlgorithmName.SHA512);

byte[] aesKey = sharedSecret.Take(32).ToArray();
byte[] hmacKey = sharedSecret.Skip(32).Take(32).ToArray();

// Verify HMAC tag to ensure data integrity and authenticity before decryption
using var hmac = new HMACSHA256(hmacKey);
var contentToSign = encryptedData.IV
    .Concat(encryptedData.CipherText)
    .Concat(encryptedData.EphemeralPublicKey) // Include ephemeral key to bind it to this session
    .ToArray();

byte[] computedHash = hmac.ComputeHash(contentToSign);
if (!computedHash.SequenceEqual(encryptedData.Tag))
{
    throw new Exception("Error: HMAC tag verification failed. Data may use a different signing order or has been tampered with.");
}

// Decrypt the cipher text using AES-CBC with the shared secret as the key and the provided IV
using var aes = Aes.Create();
aes.Key = aesKey;
aes.IV = encryptedData.IV;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;

using var decryptor = aes.CreateDecryptor();
byte[] decryptedData = decryptor.TransformFinalBlock(encryptedData.CipherText, 0, encryptedData.CipherText.Length);

// Convert decryptedData to string
string decryptedJson = Encoding.UTF8.GetString(decryptedData);
Console.WriteLine("Decryption successful. Decrypted data:\n" + decryptedJson);
// Deserialize decrypted JSON to get the actual encoding data structure (e.g., DESFireEncodingResponse or ClassicEncodingResponse)
...

public record EncryptedEncodingData(byte[] CipherText, byte[] IV, byte[] EphemeralPublicKey, byte[] Tag);
public record Link(string Href);
public record CallbackLinks(Link EncodeCompleted, Link EncodeFailed);
public record EncryptedEncodingDataResponse(EncryptedEncodingData EncryptedEncodingData, CallbackLinks Callback);

Get encoding payload for a DESFire card

This returns the data you need to encode a Gallagher credential to a MIFARE DESFire card.

POST the card's CSN (UID) and, if present on-card, the contents of the Gallagher Application Directory (CAD) files. The response contains the encrypted DESFire applications, keys, files, and updated CAD files to write, and callback links are in plain text for you to report the success of your encoding.

Encode applications in the order they are returned so that the card remains usable if encoding fails part-way through.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

secondary_id
required
string

An internal identifier.

Request Body schema: application/json
required
csn
required
string (HexString) ^0x([0-9A-Fa-f]{2})+$
object

Optional data read from CAD files, if present on the card.

reason
string <= 100 characters

Responses

Request samples

Content type
application/json
{
  • "csn": "0x04A23F9C123456",
  • "cadFiles": {
    },
  • "reason": "New card issuance"
}

Response samples

Content type
application/json
Example
{}

Get encoding payload for a Classic card

This returns the data you need to encode a Gallagher credential to a MIFARE Classic card.

POST the card's CSN (UID) and card directory data (CAD/MAD) if present, plus any unavailable sectors. The response contains the sectors and blocks to write, and callback links for you to report the success of your encoding.

Encode applications in the order they are returned so that the card remains usable if encoding fails part-way through.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

secondary_id
required
string

An internal identifier.

Request Body schema: application/json
required
csn
required
string (HexString) ^0x([0-9A-Fa-f]{2})+$
object (ClassicCad)
object (ClassicMad)
unavailableSectors
Array of integers
reason
string <= 100 characters

Responses

Request samples

Content type
application/json
{
  • "csn": "0x04A23F9C",
  • "cad": {
    },
  • "mad": {
    },
  • "unavailableSectors": [
    ],
  • "reason": "Lost Card Replacement"
}

Response samples

Content type
application/json
Example
{}

Notify Command Centre that encoding succeeded

Notify Command Centre that encoding succeeded for the given credential.

Do not code this URL into your application. Take it from the 'callback' block that accompanied the card's encoding data in the previous API call.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

secondary_id
required
string

An internal identifier.

query Parameters
token
required
string

Token provided by the encoding-data response callback link.

Responses

Notify Command Centre that encoding failed

Notify Command Centre that encoding failed for the given credential. Optionally include an error message.

Do not code this URL into your application. Take it from the 'callback' block that accompanied the card's encoding data in the previous API call.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

secondary_id
required
string

An internal identifier.

query Parameters
token
required
string

Token provided by the encoding-data response callback link.

Request Body schema: application/json
optional
message
string

Responses

Request samples

Content type
application/json
{
  • "message": "Insert any error message here."
}

Cardholders

A cardholder is a user account.

These methods give you read and write access to the cardholder data in the Command Centre database. You can download cardholders, create them, search them by name or Personal Data Field (PDF) value, and work on them as you would in the interactive clients.

The first use case below introduces the main entry point. It is a paginated search interface that gives you basic data for any number of cardholders. You won't receive many fields by default, but you can ask for more using the fields query parameter.

A field called 'href' serves both as a unique identifier for the cardholder and the location of what we call his or her details page. You can submit an HTTP GET to that href to retrieve the entire cardholder record, or an HTTP PATCH to update it, or an HTTP DELETE to remove it. Be careful: there is no coming back from deleting a cardholder.

Write-locked cardholders

If an operator has unsaved changes on a cardholder object when your integration attempts to update it, your PATCH will fail with a 409 error. The message will tell you the operator and workstation that is holding the lock; we suggest your application logs that and tries its update again later.

Licensing

All of the API calls described here are available with the RESTCardholders licence.

Cardholder use cases

Searching for cardholders by name

  1. GET /api.

  2. Follow the link at features.cardholders.cardholders.href , appending a search term to narrow the results and the 'fields' parameter to add the fields you need. 3. Process the results, following the next link until there isn't one.

Downloading all cardholders

  1. GET /api

  2. Follow the link at features.cardholders.cardholders.href . This is effectively a cardholder search with no filters. You should add sort and top query parameters to sort by ID and increase the number of cardholders per page: see the efficiency tips!

  3. Process the bundle of cardholders in the result.

  4. Follow the link at next.href if there is one, and repeat.

Synchronising a user directory

This is a common use case, described in the section on Cardholder changes. It shows how to:

  1. Get a bookmark at the head of the queue of cardholder changes.
  2. Do a one-off sync of all cardholders.
  3. Loop to stay up to date, starting with the bookmark.

That is how Gallagher's cardholder-synchronising integrations work.

Searching for cardholders by Personal Data Field value

Say you want to find a cardholder with a particular employee ID, and Command Centre is holding that in a personal data field called "employee_ID".

First, reconsider, and look at the 'Synchronising a user directory' use case above. If you are going to be doing this for many cardholders, GETting cardholders in bulk and filtering out the interesting ones client-side is more efficient than a large number of unique PDF searches. You don't have to get all cardholders; you could get all cardholders in one division, or all cardholders with a non-blank value for your PDF (shown below), or a combination. It will be quicker than a sequence of searches that return one cardholder each.

Before you can start a cardholder search, you must find the PDF's identifier.

  1. GET /api.

  2. v8.10 or later: follow the link at features.personalDataFields.personalDataFields.href , appending the query name="employee_id". This will return every PDF in the system with that name. There will be more than one, in rare cases.

  3. Earlier versions: follow the link at features.items.items.href , appending the query name="employee_id" (after a ? or &, of course). This will return every item in the system with that name. Pick the one with a type name of 'Personal Data Field'. Or you could append type=33 to the item search: you will only be shown PDFs.

  4. Note the ID of the item. It will be a short alphanumeric.

Case does not matter when searching by name but remember the quotes: Command Centre will perform a substring match if you omit them, which is vastly slower and (for the example above) return you the PDFs 'previous_employee_ID' and 'employee_ID_allocated_flag', if you have PDFs with those names.

Now you can use that PDF ID in a cardholder search.

  1. Recall the JSON object you received from GET /api.
  2. Follow the link at features.cardholders.cardholders.href , adding a query separator and pdf_<your_pdf_id>=<your_pdf_value>, without the angle brackets.

The results will only include cardholders who have <your_pdf_value> as a substring of the Personal Data Field with ID <your_pdf_id>. Again, the search is case-insensitive and you should bookend <your_pdf_value> with quotes if you want to anchor it at each end. In our example we would GET /api/cardholders?pdf_345="EID8888".

Use a percent sign % for <your_pdf_value> if you want to see all cardholders who have a non-blank value for that PDF.

The server will reply with a default set of fields for your cardholder. If they are not what you'd like, you can use the fields query parameter to change them.

See the cardholder GET for more.

Creating a cardholder

  1. GET /api.

  2. Use the link at features.accessGroups.accessGroups.href to find the hrefs of access groups you wish to add your new cardholder to.

  3. Do the same for the competencies, relationships (roles), lockers, PDF definitions, and cards/credentials (cardTypes) that your new cardholder needs, using other URLs in the 'features' section of /api. In v8.10, the card types that your operator has the privilege to assign are at a new URL given in the field features.cardTypes.assign.href .

  4. Compose a JSON body using this example and this detail, then send it in a POST to the href at features.cardholders.cardholders.href on the /api page.

Modifying a cardholder

  1. Find your cardholder using one of the processes above.

  2. If you need the current values before you update them, use the fields parameter to add fields (such as accessGroups, cards, or competencies) to the search results.

  3. PATCH the cardholder's href with a document describing the additions, deletions, and modifications you wish to make to the cardholder and his or her associations.

In its simplest form, your document could be a collection of key/value pairs much the same as you receive from a GET to the same href. More complex forms allow adding, modifying, and removing cards, competencies, group membership, PDFs, and relationships. Three examples follow.

Removing a cardholder from groups

  1. Find your cardholder using one of the processes above.

  2. Follow the link to their details page or add fields=accessGroups to the search. That will show all their access group memberships.

  3. PATCH the cardholder with the hrefs of the memberships you want to delete in an array called remove inside a block called accessGroups.

The access groups section describes what to do when you want to start with a group and remove several cardholders from it.

Removing all group memberships, competencies, relationships, cards, or lockers

This shows how you could remove a cardholder from all his or her access groups, but you could just as simply apply the process to other fields that come back as arrays, such as competencies, relationships, operator groups, cards, and lockers.

  1. GET your cardholder's details page, or search with accessGroups in the field list. Either way, you will receive all their access group memberships.

  2. Take the array at accessGroups, rename it to remove, and put it in object called accessGroups at the root level of a JSON object.

  3. PATCH the cardholder with that JSON object. That will remove the cardholder from all the groups that came back in the GET.

Assigning a new card to a cardholder

  1. GET /api.

  2. Follow the link at features.cardTypes.cardTypes.href to find the href for the new card's type.

  3. If you want to create a card in a state other than the default, get the state from the same page.

  4. Find the href for the cardholder using one of the search methods above.

  5. Optional: follow the link at edit.href on the cardholder page. If there is a link at update.href, your REST client has permission to modify the cardholder.

  6. PATCH the cardholder's href according to the cardholder patch schema.

Deleting a cardholder's PDF value

  1. Find the URL of your cardholder using one of the processes above.
  2. PATCH your cardholder with this in the body: { "@name_of_PDF": null }

Deleting a cardholder

  1. Find your cardholder using one of the processes above.
  2. Send an HTTP DELETE to the cardholder's href.

Updating a cardholder's location

  1. Find the href of your target access zone using the link at features.cardholders.updateLocationAccessZones in the results of GET /api.

  2. Find your cardholder using one of the processes above. If you are using search, add updateLocation to the fields parameter to save you having to GET their details page later.

  3. Send an HTTP POST to that cardholder's updateLocation.href link.

Finding which access zones and doors a cardholder can access

  1. GET your cardholder's details page, or search cardholders with accessGroups in the field list. Either way, you will receive all their access group memberships.
  2. Iterate through all the access groups looking into their access blocks for access zones and schedules. Recurse up the access group hierarchy by following each group's parent.href.

Now you have the cardholder's access zones. If you want doors:

  1. For each access zone, GET its href and look in its doors block.

Finding recently-created cardholders

Informing you when Command Centre creates cardholders is a function of the Cardholder changes call, described there.

However for that to work you need to make API calls before and after the cardholders are created. If they already exist, a workaround is to get a page of cardholders sorted by database ID descending using sort=-id&top=10. Change the ten to the number of cardholders you'd like, obviously. Because Command Centre allocates database IDs to new items in increasing order, the first page you get will be the most-recently created cardholders. This is not suitable for use in a production system! Use the cardholder changes call instead.

Field names in query parameters

The cardholder search and details operations' fields parameter and the change tracking operation's fields and filter parameters take a list of field names. Other sections of this document describe how those parameters affect the API calls, but their format is the same so this section will cover it once.

You can form the name of a field by joining the components of its JSON path with dots. Fields at the root level of the cardholder object, such as firstName and @emailAddress (a PDF), have just one component. Fields that are one level down, such as accessGroups.status, have two.

Treat the string matches as case sensitive: use lastName rather than lastname.

The string must not contain any spaces. Just alphanumerics, underscores, commas, and dots.

To serve as examples, this is the list you can choose from in 8.30:

href, id, firstName, lastName, shortName, description, authorised, lastSuccessfulAccessTime, lastSuccessfulAccessZone, division, personalDataFields, cards, accessGroups, competencies, notes, notifications, relationships, lockers, cards.href, cards.number, cards.from, cards.until, cards.cardSerialNumber, cards.type, cards.status, cards.invitation, cards.issueLevel, cards.pivData, cards.pivData.chuid, cards.pivData.pivStatus, cards.pivData.lastCheckTime, cards.pivData.chuid.hash, cards.pivData.chuid.fascn, cards.pivData.chuid.duns, cards.pivData.chuid.orgIdentifier, cards.invitation.href, cards.invitation.singleFactorOnly, cards.invitation.email, cards.invitation.mobile, notifications.enabled, notifications.from, notifications.until, accessGroups.href, accessGroups.accessGroup, accessGroups.from, accessGroups.until, accessGroups.status, relationships.href, relationships.cardholder, relationships.role, lockers.href, lockers.locker, lockers.from, lockers.until

Later versions of Command Centre added many more. See the details operation for the complete list of cardholder fields.

A special value default applies a default set of fields that varies with the call you're making.

personalDataFields is also special. It will give you the personalDataDefinitions block plus all the PDF values at the root level with their names preceded by '@'-signs.

Licensing

All of the API calls described here are available with the RESTCardholders licence, with the following exceptions and notes:

  • Visitor management calls need both RESTCardholders and VisitorManagement.

  • Creating, modifying, and deleting cardholders' connections to competencies requires the RESTConfiguration licence.

  • Creating, modifying, and deleting competency items requires the RESTConfiguration licence.

  • Managing access group memberships is enabled by the RESTCardholders licence but managing access group items, card types, personal data definitions, and roles will require the RESTConfiguration licence. These features are coming soon.

  • Lockers and locker banks are also available with the RESTStatus licence, and a subset of their fields (enough to allow overriding them) are available with the RESTOverrides licence.

The server will return a 403 if you attempt an operation for which the server is not licensed.

Versions

The body of this document clearly indicates when recent features arrived in the API so that readers with older versions of Command Centre know not to expect them.

Search cardholders

This call returns cardholders matching your search criteria.

The result will contain no more than 100 or 1000 cardholders depending on your version; you should follow the next link, if it is present, to collect the next batch.

When you have loaded all the cardholders there will be no next link.

If your result set is empty it means your operator does not have the privilege to view any cardholders. Perhaps there are none in the divisions in which your operator has privileges, or your operator has no privileges at all.

Adding or modifying cardholders between calls to this API will not affect the pagination of its results if you sort by ID.

Do not code this URL into your application. Take it from the 'href' field in the features.cardholders.cardholders section of /api.

Authorizations:
API_keybasic
query Parameters
sort
string
Enum: "id" "name" "-id" "-name"

Changes the sort field between database ID and name.

If you prefix id or name with a minus sign (ASCII 45), the sort order is reversed.

There are two very strong reasons to sort by ID:

  1. Sorting by name carries a risk of missing or duplicating objects if your result set spans multiple pages and another operator is editing the database while your REST client is enumerating them. This is known as "page drift." Sorting by ID does not carry that risk.
  2. Following a next link is dramatically quicker when sorting by ID.

We strongly recommend sorting by ID. In case you were still in doubt, we will do that by default in a future version of Command Centre.

The server silently ignores anything except the options listed here.

top
integer >= 1

Sets maximum number of cardholders to return per page.

Older versions of Command Centre returned 100. That is acceptable for a GUI application that will only display the first page of cardholders, but for integrations that intend to proceed through the entire database it causes a lot of chatter.

Version 8.70 will return 1000 items per request by default. 1000 is about where a graph of performance versus page size begins to level out. You may see some improvement by taking it even higher.

name
string

Limits the results to cardholders with a name that matches this string. By default, it is a substring search against the first name or the last name or the concatenation 'lastName, firstName'; surround the parameter with double quotes "..." for an exact search.

Without quotes, a percent sign % inside your search string will anchor the search at both ends (so it will no longer be a substring search) and the % will match any substring. For example, boothroyd,% will only match cardholders whose last name is Boothroyd.

The search is always case-insensitive. Results are undefined if you do a substring search for the empty string (name=). You will receive no cardholders if you search for those with no name (name=""), as all items must have a name.

Because a plus sign + represents a space in a query string, replace each plus sign in your search string with %2d.

The search parameters form a logical conjunction. They are ANDed together. Therefore if you search for name=Mary&pdf_1315=nanny you will only get back cardholders with 'Mary' in their name and 'nanny' in the PDF with ID 1315.

pdf_{id}
string

Limits the results to cardholders with a value for the Personal Data Field with this ID that matches the parameter.

It is a substring match by default; surround it with double quotes "..." for an exact match. Tests showed an exact match to be 100x quicker than a substring search on a large database.

Without quotes, _ will match any single character and % will match any substring. Having either in your term will anchor the string at both ends so it will not be a substring search. A lone % will return any cardholder who has this PDF set to a non-null value.

Searching for a blank value using pdf_xxx="" or pdf_xxx= currently matches no cardholders, which is not useful. Do not rely on that behaviour since we will change it in a future version of Command Centre to return cardholders with no value for that PDF.

Because a plus sign + represents a space in a query string, turn plus signs in your string into %2d.

The search is always case-insensitive.

Search parameters form a logical conjunction. They are ANDed together. Therefore the search pdf_1315=nanny&pdf_1315=paratrooper will only return cardholders whose PDF 1315 contains the strings 'nanny' and 'paratrooper'.

division
Array of strings

Limits the returned items to those that are in these divisions.

That includes all the items in those divisions' child divisions, because Command Centre treats items as though they are also in their division's parent, and its parent, and so on up to the root division.

Separate the IDs of the divisions you are interested with commas. Item IDs are short alphanumeric strings, not URLs.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

directDivision
Array of strings

Restricts items to those whose division is in this list.

Unlike division=, it does not follow ancestry. That means it will limit the search to items that are directly assigned to the divisions you list, whereas division (without the direct) will also include items that are assigned to their descendants.

List the IDs of the divisions you are interested in separated by commas. Item IDs are short alphanumeric strings, not URLs.

Because this is the first query parameter we added that contains a capital letter, this will be the first time you have had to think about case sensitivity. directDivision works, directdivision does not.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

Added in 9.20.

description
string

Limits the returned items to those with a description that matches this string. By default it is a substring match; surround it with double quotes "..." for an exact match. A _ will match any single character, and a % will match any substring. With or without quotes, having either of these wildcards in the string will anchor it at both ends as though you had surrounded it with ".

The search is always case-insensitive. Results are undefined if you search for the empty string (description= or description="").

Search parameters are ANDed together.

accessZone
Array of strings

Limits the results to cardholders who are in one of the access zones with the given IDs. Do not put quotes around the IDs, and separate them with commas.

To get everyone who is in any access zone use accessZone=*. It will return all cardholders who have badged at least once and who are not currently 'outside the system'. A cardholder is 'outside' if they badge through a door that has no access zone configured for that direction of travel, or if an operator manually moves them outside.

fields
Array of strings
Default: "defaults"

Specifies the fields you want in the search results. The values you can use here are the same as you can for the details page. Using it you can return everything on the search page that you would find on the details page with the exception of the edit and updates links. Separate values with commas.

Use the value cards.encodingData to receive links to the methods that return card-encoding data.

Use the special value defaults to return the fields you would have received had you not given the parameter at all. Obviously only do that if you have more to add.

Use the special value personalDataFields to return the 'personalDataDefinitions' block as well as the PDF values at the root level of the cardholder object.

Use the special value pdf_XXX (where XXX is the ID of a PDF definition) to include just that PDF. If you do not have the PDF's ID, and don't mind the performance hit of retrieving all the PDFs, using personalDataDefinitions may be simpler.

There is a special value defaults which adds everything you would have received had you not sent a fields parameter at all, but we advise against its use: specifying every field you want makes the response more predictable across different server versions.

Treat the string matches as case sensitive: use 'lastName' rather than 'lastname'.

In v8.00 you will receive the href and internal ID even if you do not ask for them. In 8.10 you will not. If you are going to send the fields parameter and need the href or ID, include them.

pos
integer

Reserved for internal use. You may see it in URLs you receive from the server, but you must never add it yourself.

skip
integer

Reserved for internal use. Do not add it to your queries.

Responses

Response samples

Content type
application/json
{}

Create a cardholder

This creates a new cardholder, including his or her cards, group memberships, personal data, competencies, and roles.

Do not code this URL into your application. Take it from the 'href' field in the features.cardholders.cardholders section of /api.

The POST expects a document in the same format as the the cardholder detail. Many fields are optional, of course, and some (like the last successful access time) do not make sense when creating a cardholder. See the cardholder POST example for details.

You will achieve better performance if you combine all you want to achieve into one POST, rather than creating the cardholder bare with a POST then adding cards, groups, PDFs, etc., with PATCHes later.

When successful it returns a location header containing the address of the new cardholder.

Note that you can only create one cardholder per POST.

Authorizations:
API_keybasic
Request Body schema: application/json
required

This can be a large object as shown in the body model, or a tiny one, because the only fields you must have in the POST are the division and either the first or last name.

firstName
string

You must supply either this or the last name when creating a cardholder.

The maximum length of a cardholder's first name in version 9.50 is 50 characters.

lastName
string

You must supply either this or the first name when creating a cardholder.

The maximum length of a cardholder's last name in version 9.50 is 50 characters.

shortName
string
description
string
authorised
boolean

Remember to set this true, as shown here in the POST, or later in a PATCH. Otherwise your new cardholder will never get through a door.

division
required
object

Mandatory when creating any cardholder. In this example, we want all students in division 5387.

@email
string

An example PDF value. In this example, access group 352 must include a PDF called 'email' otherwise this will appear to have no effect.

@headshot
string

An example image PDF encoded to Base64. Access group 352 must include this PDF as well. As a quick visual check on your encoding, JPEGs start with /9j/.

Array of objects (Cardholder PDF)

This is how you set and unset the notifications flags on PDFs. If you do not do it here when you first give a cardholder a PDF, it will come from the PDF's definition.

Array of objects (Cardholder card)

This example creates one physical card of type 600 with a PIN and a system-generated card number, and another of type 654 which--judging by the invitation block--must be a mobile credential. Command Centre will send an invitation to Nick at those coordinates.

Card PINs were added to the API in 8.90.

Array of objects (Cardholder access group membership)

Here you can add the access groups necessary to give your new cardholder the PDFs and access he or she needs. In this example we set the activation date of the access group membership to the first of January 2019.

Array of objects (Cardholder operator group membership)

Here you can add the operator groups necessary to give your new cardholder the software access he or she needs. Added in 8.50.

Array of objects (Cardholder competency)

In this example we are giving our new cardholder a disabled competency, set to enable in January 2019.

notes
string
object

You can set or update any of the three fields in this block.

Array of objects (Cardholder relationship)

Here you would set the cardholders who will perform roles for this cardholder.

The example shows that this cardholder will have cardholder 5398 performing role 5396.

Remember that you can supply an array of these objects if your cardholder is having more than one role filled.

Array of objects (Cardholder locker)

Here you set all the cardholder's locker assignments. Ensure you are only attempting to give your cardholder a locker according to site policy (one locker per locker bank, for example), otherwise the POST will fail.

The example shows our cardholder receiving two lockers.

Array of objects (Cardholder elevator group)

Here you set all the new cardholder's default elevator floors and passenger types. Passenger type properties are false by default.

The example shows our cardholder receiving a default floor for the first elevator group, with the Code Blue feature enabled in the second group.

Added in 8.50.

Responses

Request samples

Content type
application/json
Example

This is an example of a POST you could use to create a cardholder in a specific division and access group, with an access card, another cardholder as a supervisor, a competency, a student ID and a photo held in personal data fields, two lockers, and configuration for two elevator groups.

There are more fields on a cardholder than shown in this example. For a complete list please see the schema for the detailed cardholder object that you receive from a cardholder href.

In this example we are giving our new cardholder a disabled competency, set to enable in January 2019.

The example shows that this cardholder will have cardholder 5398 performing role 5396.

The example shows our cardholder receiving two lockers.

The example shows our cardholder receiving a default floor for the first elevator group, with the Code Blue feature enabled in the second group.

{}

Get details of a cardholder

This retrieves one cardholder from Command Centre. It does not return all the fields available (there are too many) so, much like the cardholder search, it accepts a fields parameter where you specify the fields you need.

Do not use a cardholder's ID to build the URL yourself: follow the href in the cardholder search to get here.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
fields
Array of strings
Default: "defaults"

Specifies the fields you want in the results. The values you can list are the same as the field names in the detail results. Use it to return fewer fields than normal. Separate values with commas.

Treat the string matches as case sensitive: use 'lastName' rather than 'lastname'.

Added to the cardholders controller in 8.00. In that version you will receive the href, internal ID, and updates link even if you do not ask for them. In 8.10 you will not. If you are going to send the fields parameter and need those fields, include them.

Responses

Response samples

Content type
application/json
{}

Update a cardholder

This is the call you use to update a cardholder, including:

  • changing general properties such as names, division, and description,

  • changing PDF values, and

  • adding or updating cards, access group membership, roles and relationships, lockers, and competencies.

When changing a cardholder's division at the same time as PDFs or competencies, the extra privilege checks required for PDFs and competency changes use the origin division, not the destination division. So if you are moving a cardholder from a division in which your operator has no access to PDFs and competencies into one in which it does, first PATCH the cardholder into the new division then PATCH it with the other changes.

You can find this URL in the href in the cardholder search or any of the other calls that return cardholder hrefs. Do not build it yourself.


Note that the REST API does not implement the full suite of Command Centre privileges. In particular, the following privileges do not have the same effect on an operator's ability to modify a cardholder that they do in the administrative clients:

  • Disable Card. This privilege has no effect on the 7.90 REST API. You need Edit Cardholders to disable cards.

  • Add or Edit Cardholder Notes. You also need Edit Cardholders to change notes on an existing cardholder via the API. In the administrative clients, you do not.

  • Manage Locker Assignments. You also need Edit Cardholders to assign and un-assign lockers on a cardholder via the API. In the administrative clients, you do not.

The 'De-authorise Cardholder' privilege is implemented. It allows an operator to set a cardholder's 'authorised' field to false (denying all their future access requests) without the Edit Cardholders privilege.

In short, if your application intends to do more to cardholders than de-authorise them, you will need an operator with Edit Cardholders.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

Request Body schema: application/json
required

As well as cardholder attributes such as 'authorised', the PATCH body contains instructions for creating, updating, and deleting personal data, group memberships, etc.

authorised
boolean
firstName
string
@employeeId
string

Replace PDF values as though they were flat fields on a cardholder. Prefix the name of the PDF with @, and Base64-encode images. Send 'null' if you want to delete a PDF value.

Remember that a cardholder's record will not return a PDF if they are not a member of an access group that grants that PDF. Current versions of Command Centre are tolerant of your attempts to change the PDF in that situation, but future versions may not be.

Array of objects (Cardholder PDF)

This is how you set and unset the notifications flags on PDFs.

cards
object

This object can contain three arrays, named 'add', 'update', and 'remove'. Every element you put in those arrays should be in the card schema. Each element of the 'add' array will need a 'type' member, at the very least. Every card field makes sense here except 'href'. Only existing cards have hrefs. This example adds two cards: one has nothing more than the type, so it will receive blank 'from' and 'until' dates and a computed number and issue level. The other is a mobile credential (it has an 'invitation' block) with a custom initial state.

Each element of the 'update' array should be a card to modify. It will need the href of that card, plus the fields you want to change. Remember you cannot change a card's type. The example changes the issue level and resets the 'until' date.

The only field that makes sense in an element of the 'remove' array is 'href' and 'status'.

You can remove and add cards in the same PATCH. In fact you should do that in preference to making multiple API calls. That is a good way of reissuing a mobile credentials, for example: put the href to the old one in the 'remove' array and a new invitation in the 'add' array. The new credential should have the same card number and the same 'type' and 'invitation' blocks as the credential you're re-issuing.

Do not put the same href in both the 'update' and 'remove' arrays.

In version 8.90 and later you can specify a card state in the value field inside the status block when removing a card or changing its issue level. It becomes the final state of the card if you remove it or the final state of the card with the previous issue level if you re-issue it, so it must be one of the valid states for the card type. The Gallagher clients and the resulting event call this state the 'reason' for the re-issue or removal. By default it will be the same as the card's current state.

accessGroups
object

Like the 'cards' object, this can contain three arrays named 'add', 'update', and 'remove'. Every element you send in those arrays should be in the access group schema.

This operation does not modify access groups in Command Centre; it works on a cardholder's memberships to those groups.

Each element of the 'add' array will need an 'accessGroup' member containing an href identifying the group to which you wish to add the cardholder. The other fields are optional. If you omit 'from', the membership will take effect immediately. If you omit 'until', it will be unending.

Each element of the 'update' array will need an href identifying the membership (not the group!) to update, and one or both of the 'from' and 'until' date-times with new values. You cannot change the group: just the activity period. The example removes the until date, effectively making the group membership unending.

In version 7.90.883 or earlier, 'from' and 'until' should be in UTC with a trailing 'Z'. Releases after 883 understand different timezones here.

Note that updating a cardholder's group membership will change its href, so do not cache it.

The only field that makes sense in an element of the 'remove' array is the href.

Do not put the same href in both the 'update' and 'remove' arrays.

competencies
object

Like the cards and accessGroups objects, this can contain three arrays named 'add', 'update', and 'remove'. Every element should be in the cardholder competency schema.

This operation does not modify Command Centre's competencies: it works on a cardholder's holdings of those competencies.

Each element of the 'add' array will need a 'competency' block containing an href member identifying the competency you wish to grant the cardholder. All other fields are optional. Note that attempting to give a cardholder a competency he or she already has will result in an error or an alarm depending on the server version.

Each element of the 'update' array will need an href identifying the cardholder/competency link to update, and one or more of the 'expiry', 'enabled', 'enablement', 'comment', 'limitedCredit', and 'credit' fields.

The only field that makes sense in an element of the 'remove' array is the href of the link between the cardholder and the competency.

Do not put the same href in both the 'update' and 'remove' arrays.

In this example we are giving the cardholder a disabled competency which will enable in 2021, and activating another competency.

relationships
object

It should be no surprise that this can contain three arrays named 'add', 'update', and 'remove', and that every element should be in the relationship schema.

This operation does not modify Command Centre's roles: it works on the relationships between two cardholders.

Each element of the 'add' array will need a 'role' member containing an href identifying the type of relationship you wish to establish, and a 'cardholder' member containing an href identifying the other party (the one who will perform the role for the cardholder at the URL you are PATCHing). There are no optional fields.

Each element of the 'update' array will need an href identifying the relationship to update, and one or both of the 'role' and 'cardholder' blocks containing the updated values. The example leaves the role but changes the cardholder - a new supervisor, presumably.

The only field that makes sense in an element of the 'remove' array is the href.

Do not put the same href in both the 'update' and 'remove' arrays.

lockers
object

With you well in the habit by now, each element of your three arrays should be in the cardholder locker schema. They will allocate lockers to cardholders, de-allocate them, and adjust validity periods.

Each member of the 'add' array will need a 'locker' member containing an href identifying the locker to allocate. The cardholder you will allocate it to is identified by the request URL, remember.

Each member of the 'update' array will need an href identifying the allocation to update, and one or both of the 'from' and 'until' date-times.

The validity period is all you can change about a locker allocation. If you want to change the locker, delete the old one and add a new. You can do that in the same PATCH, with one element in each of the 'add' and 'remove' arrays.

This example allocates one locker starting in January 2019, sets the end-date of an existing allocation to the end of February 2020, and removes another entirely.

operatorGroups
object

This can contain two arrays named 'add' and 'remove'. Every element you send in those arrays should be in the cardholder operator group schema.

Each element of the 'add' array will need an 'operatorGroup' member containing an href identifying the operator group to which you wish to add the cardholder. Supported in 8.50 and later.

The only field that makes sense in an element of the 'remove' array is the href. Make sure it is the href of the membership, not of the operator group. Supported in 8.90 and later.

There is nothing about an operator group membership that you can change so there is no point to an 'update' array. Operator group memberships are, or are not: there is no update.

elevatorGroups
object

This can contain three arrays named 'add', 'update', and 'remove', each containing an element in the cardholder elevator group schema.

The 'elevatorGroup' block only makes sense in the 'add' array. The 'update' array is for changing the cardholder's default floor and passenger types on an existing elevator group assignment.

The server will ignore all fields in the elevatorGroup and accessZone objects except 'href' if you place them in the body of your PATCH.

Remove the default floor in an update by supplying an accessZone block with the href set to null or "".

Change a passenger type in an update by supplying the new value. The passenger type will be unchanged otherwise.

As with cards and access group memberships etc., the server ignores root-level hrefs in the elements of an 'add' array, requires them in the 'update' array (since they indicate the entries to work on), and ignores everything but them in the 'remove' array.

The example shows our cardholder receiving a default floor for one elevator group and updating the Code Blue and VIP passenger types for another elevator group.

Added in 8.50.

Responses

Request samples

Content type
application/json
Example

This example:

  • sets 'authorised' true,

  • sets a PDF holding an employee ID,

  • changes the notification flags on two PDFs (presumably because this cardholder wants to receive notifications at the email address stored in the 'email' PDF rather than by SMS),

  • adds two new credentials, one card and one mobile,

  • changes the issue level with Stolen as the reissue reason and clears the until date on another credential,

  • deletes a third credential with Lost as the remove reason,

  • adds two access group memberships, one unending and one with an until date,

  • clears the until date on another access group membership,

  • removes a fourth access group membership,

  • adds a competency, inactive, with a future enablement date,

  • activates a competency that the cardholder already had,

  • adds one relationship,

  • changes the cardholder on another,

  • adds one locker assignment with a from date,

  • sets the until date on another locker assignment,

  • removes a third locker assignment,

  • adds two operator group memberships,

  • removes a third operator group membership,

  • adds an elevator group with a default floor,

  • modifies another elevator group, turning the 'code blue' feature on and the VIP feature off, and

  • removes a third elevator group.

{}

Remove a cardholder

This call removes a cardholder from Command Centre. You can find the URL in the href in the cardholder search or any of the other calls that return cardholder hrefs. Do not build it yourself.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

Responses

Remove an access group membership

This call removes a cardholder's membership in an access group. Note that a cardholder may have more than one membership in a group.

You can find this URL in the cardholder object. Do not build it yourself.

To modify a cardholder's membership of an access group your operator must have a privilege that allows editing that cardholder plus 'Modify access control' on the group.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

secondary_id
required
string

An internal identifier.

Responses

Remove a card from a cardholder

This call removes a card from a cardholder.

You can find this URL in the cardholder object. Do not build it yourself.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

secondary_id
required
string

An internal identifier.

Responses

Remove a competency from a cardholder

This call removes a competency from a cardholder.

You can find this URL in the cardholder object. Do not build it yourself.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

secondary_id
required
string

An internal identifier.

Responses

Change competency credit

This call increases or decreases a cardholder's competency credit. It is an indivisible operation.

It is reserved for the Pre-pay Car Parking feature.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

secondary_id
required
string

An internal identifier.

query Parameters
add
required
integer

The amount to adjust the competency credit. This can be positive or negative.

Responses

Remove an elevator group from a cardholder

This call removes a default floor assignment and passenger types from a cardholder for one elevator group.

You will find this URL in the elevatorGroups block of a cardholder object. Do not build it yourself.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

secondary_id
required
string

An internal identifier.

Responses

Remove a locker assignment

This call removes a locker assignment from a cardholder. If the cardholder has no other assignments for this locker after this operation he or she will not be able to open it.

You will find this URL in the lockers block of a cardholder object. In the interest of forward compability, do not build it yourself.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

secondary_id
required
string

An internal identifier.

Responses

Remove an operator group membership

This call removes a cardholder's membership in an operator group. Operator group memberships do not have start and end dates, so a cardholder can only have one membership in a given operator group.

You can find this URL in the cardholder object. In the interest of forward compability, do not build it yourself.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

secondary_id
required
string

An internal identifier.

Responses

Remove a relationship

This call severs a relationship between two cardholders.

You can find the URL in the relationships block in the cardholder object of the cardholder who has the relationship, not the cardholder who holds the role. For example if you have a 'supervisor' role you would find the URL to delete by looking up the supervised cardholder, not the supervisor.

In the interest of forward compability, do not build the URL yourself.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

secondary_id
required
string

An internal identifier.

Responses

Change a cardholder's location

This call updates a cardholder's location (moves them) to a target access zone. Added in 8.20.

Do not code this URL into your application. Take it from the 'updateLocation.href' field in a cardholder response.

The POST expects a document which contains an href to the target access zone. The recommended way of getting access zone hrefs is through an access zones call added in 8.20 that returns you the access zones to which you are allowed to move cardholders, according to your operator privileges.

You can also get access zone hrefs from the items controller.

Note that to change a cardholder's location your REST operator will need the "Manage Cardholder Location" privilege in the division of the target access zone and "View Cardholder" on the cardholder itself.

It is not possible to put a cardholder into "nowhere", also known as "outside the system". The only place you can move them is a new access zone.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

Request Body schema: application/json
required

The body of the request must contain the href of the target access zone.

object

Responses

Request samples

Content type
application/json
Example
{}

Find out which fields you can edit

This tells you which fields your REST operator can edit based on its privileges.

Gallagher uses this call for rapidly-evolving internal applications. As such, its results are tuned to those applications and are subject to change. Rather than relying on this call, we suggest that you simply give your REST operator the privileges it needs to access to everything it needs.

Note that this method returns 400 if there are two PDFs in the system with the same name. CC insists on unique names for items when you create them but you can end up with duplicates when you form a multiserver cluster out of standalone installations. You should move on that, because having two PDFs with the same name will bewilder your operational staff.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

Responses

Cardholder changes

This feature keeps you up to date with cardholders by telling you the changes that happened since the last time you called. It works for creations, modifications, and deletions coming from all sources, including Gallagher's clients, EDI, Active Directory, remote servers, and the other cardholder APIs.

It first appeared in version 8.30.

Because it also reports changes made through the REST API, it will tell you about your own changes. If you are using this API both for managing cardholders and as a source of truth, you should be careful not to get yourself into a loop.

This API was built to synchronise a second system with Command Centre's cardholder directory, not for auditing or reporting. You will find the events API quicker and more flexible for those tasks.

Recommended use

  1. First, get a bookmark at the end of Command Centre's list of changes as follows:

    1a. GET /api

    1b. Follow the link at features.cardholders.changes .

    1c. Take note of the href in the next block. This is your bookmark. Later on you will ask for all the changes that happen after this point.

  2. If you are filling a user directory from Command Centre, download all cardholders using this advice. Here is a reminder:

    2a. Using the results of GET /api again, follow the link at features.cardholders.cardholders , adding query parameters top=1000 and sort=id.

    2b. Process those cardholders (probably 1000) and follow the next.href link in a loop until you have extracted all of them.

  3. This is the start of your update loop. The first time through, to catch the changes that came in during the big download you did in step two, use the href that you got in step one. Simply GET it.

  4. If the results array you get back is empty you are up to date and you have nothing to do. Sleep for a time before your next poll, to avoid a tight loop and ease the load on your database. When it comes time to poll again, do not be tempted to resubmit the same request: the URL to use sometimes changes even when there are no results, so always get it from next.href.

  5. If the results array is not empty it will contain the first changes that happened after your previous call. The sections below will help you process them.

  6. Restart your polling loop using the link in next.href.

Use case: detecting when cardholders are created.

The first thing you need to do is get a link from the changes API call before the cardholders you are interested in are created in Command Centre. If you didn't do that, there is a workaround described in the cardholder use cases, but it is not suitable for production.

When you call this API the second time you will receive all changes made to cardholders since the previous call. To find the new cardholders, discard all the results that do not have type=add.

Since you are only interested in new data, you can optimise the call a little with fields=newValues, which will remove the fields you do not need.

Notes

  • The API will not notify changes to any fields that you cannot see in the cardholders API, such as user codes, passwords, card PINs, car park assignments, biometric credentials, and (in versions before 8.50) operator settings.

  • There is a known issue in 8.50 preventing operator group membership changes coming out of this API. It was fixed in 8.60. Changes to the other five operator settings work correctly in 8.50.

  • The API returns changes to configuration, not to changes in status. For example, when the time passes into or out of the activity period of a card or competency, the status of that card or competency changes but that does not prompt anything to come out of this API. To monitor for that, watch the configuration fields that define the card's or competency's validity period.

    Similarly, a cardholder moving between access zones changes two fields beginning with lastSuccessfulAccess but does not count as a cardholder change.

  • The API will return the pre-change values of some fields, but not those that require a lot of storage such as image PDFs and PIV certificates. Command Centre does not hang on to them after they change.

Get changes

This returns cardholder changes matching your search criteria and a link for the next batch.

The first time you call this it will return a link back to this call with a parameter marking the head of the change list. There will not be any changes in the result set for your first call. When you later GET the link the server sent you, it will return the changes that occurred since, if there were any, and a new link.

There will be no more than 1000 changes, or as many as you asked for using the top query parameter.

When you are up to date with all the cardholder changes, the results array will be empty. When it comes time to check again, don't just re-use the same URL: get a new one from the next block. It can change even when there are no results.

This is a polled interface: it will return immediately, whether or not there are results. Therefore you should wait for a time between calls if the results array was empty.

You can monitor changes to card data using this call, including serial numbers (MIFARE UIDs). However you cannot monitor changes in the lastSuccessfulAccessTime or lastSuccessfulAccessZone fields because they are not attributes of a cardholder object: they are derivatives of his or her activity. If you want to monitor a person's movements we advise subscribing to events.

This is a polled interface: it will return immediately, whether or not there are results. Therefore you should wait for a time between calls if the results array was empty.

Do not code this URL into your application. Take it from the href field in the features.cardholders.changes section of /api.

Efficiency tips when collecting cardholder changes

  • Filter for the kinds of changes you are after using the filter parameter. If you are only interested in people's access group memberships, for example, add filter=accessGroups to your GET, and you will not be troubled with all the other kinds of changes that cardholders go through.

  • The default set of fields is large and expensive to compute. Ease the load on the server, the network, and your client by asking for a smaller response. For example if you are only interested in the current state of a cardholder's group memberships and do not care who made the change, or when, or what state the cardholder was in before use fields=item,cardholder.accessGroups. You need item so you can tell which cardholder changed. If you store your own identifier in a PDF you could drop item and add cardholder.pdf_XXX, where 'XXX' is the ID of your PDF.

  • Sleep for as long as you can between calls.

  • If you are only interested in changes to cardholders in certain divisions, only give your REST operator access to those divisions. It will not see changes outside them.

Authorizations:
API_keybasic
query Parameters
top
integer >= 1

Limits the results to no more than this many items per page.

Older versions of Command Centre returned 100 items per page in the absence of this parameter. That is acceptable for GUI applications that will only display the first page, but for integrations that intend to proceed through the entire database it causes a lot of chatter.

8.70 and later versions will default to 1000 items per request. This is about where a graph of throughput versus page size begins to level out.

pos
integer

Reserved for internal use. You may see it in URLs you receive from the server, but you must never add it yourself.

filter
Array of strings
Default: "defaults"
Items Enum: "href" "id" "firstName" "lastName" "shortName" "description" "authorised" "lastSuccessfulAccessZone" "division" "notes" "personalDataFields" "operatorLoginEnabled" "operatorUsername" "operatorPassword" "operatorPasswordExpired" "windowsLoginEnabled" "windowsUsername" "cards" "accessGroups" "competencies" "notifications" "relationships" "lockers" "defaults"

Limits the search results to the changes that affected these fields, and limits the oldValues and newValues blocks to these fields. You can specify practically any of the fields in the cardholder detail. You can also go into more detail; for example you can monitor a cardholder's cards' validity dates using filter=cards.from,cards.until.

filter reduces the number of results; if you want to choose the blocks you receive in each result, use fields.

If you do not supply a filter parameter it will use the same fields you get in a cardholder details page. That is nearly everything the API has for a cardholder, but omits some seldom-used or expensive features such as card tracing and the large PIV fields. If you want to monitor them you must list them here. For example, filter=defaults,cards.trace will add the card trace flag to the usual filter.

personalDataFields will filter for PDF changes, and will give you the personalDataDefinitions block plus the PDF values that changed. You cannot filter for changes to a particular PDF: you will need to do that in your client.

Being able to monitor operator settings arrived in 8.50 and operator group memberships in 8.60.

Note that you cannot monitor changes in the lastSuccessfulAccessTime or lastSuccessfulAccessZone fields because they are not attributes of a cardholder object: they are derivatives of his or her activity. If you want to monitor a person's movements we advise subscribing to events.

If card changes are all you are interested in, and you do not want to hear about all the other changes that cardholders can experience, use filter=cards.

fields
Array of strings
Default: "defaults"
Items Enum: "href" "operator" "operator.href" "operator.name" "time" "type" "item" "oldValues" "newValues" "cardholder" "cardholder.*" "defaults"

Limits the blocks in the results.

fields affects the blocks in each result; if you want to reduce the number of results, use filter.

You can have finer-grained control of fields inside those blocks by listing their JSON paths. For example, to see what the operator and affected cardholder's names are now, you could use fields=operator.name,cardholder.firstName,cardholder.lastName.

The values you can list for the cardholder block are very similar to these field names. Prefix each with cardholder. (since in this API they are all inside a block called cardholder).

Separate values with commas and treat the strings as case sensitive.

If you do not send this parameter the API will return all cardholder changes to a default set of fields.

Use personalDataFields to monitor changes to PDF values on a cardholder.

deadline
integer >= 0
Default: 50

Sets the number of seconds after which the server will abort the query and return a 500. If that happens, you should try again later when the server (particularly the database server) is not so busy.

Using this can be dangerous. When the server aborts a query it discards all the work it did up to that point. If you send the same query again later, with the same deadline, you may end up stuck in a loop, never making progress, and effectively DoSing your server.

If your server is struggling, try reducing the size of each result set by using top.

Added in 8.80.

Responses

Response samples

Content type
application/json
{}

Card Types

The main purpose of the card type API is to find the card type you need when assigning a card to a cardholder.

A card connects a cardholder to a card type. A new card takes some defaults from its card type (such as its activity period, given by 'from' and 'until'), some limits (on the card number and PIN, for example), and other behaviours (such as how long a card can be inactive before Command Centre disables it).

The 'Site Installation' chapter of the Configuration Client online help has a section that describes card types.

As it does for the other item types, the REST API gives you read access to card types through search and details pages. However the privilege model for card types is more flexible than for other items: the 'View site' privilege determines whether you are allowed to view a card type, while the cardholder editing privileges ('Create', 'Edit', 'Create and edit') determine whether you can assign cards of that type to a cardholder, so version 8.10 of the API added a page that returns the card types that your operator is allowed to use in that way. Take its URL from features.cardTypes.assign in the results of GET /api.

This API uses the term 'card' but more broadly we prefer 'credential', because not all card types involve a physical card.

The API's coverage of PIV cards is in its own document.

API routes that allow creating, modifying, and deleting card types are in development.

Use cases

Finding the PIV card type

When you give a cardholder a card, PIV or otherwise, you need to provide the identifier of the card type. It will vary between Command Centre installations so you cannot use a value from another installation or from these examples. It will not change while Command Centre is running but it may change at upgrade, so your application should follow this process at startup.

It takes two queries and a loop:

  1. GET /api.
  2. If running 8.00 or earlier, follow the link at features.cardTypes.cardTypes.href (which will be to /api/card_types), or
  3. if running 8.10 or later, follow the link at features.cardTypes.assign.href (which will probably be to /api/card_types/assign. Both URLs will work in 8.10, but the advantage of this URL is that your operator can access it at a lower privilege level).
  4. Iterate through the array to find the element with credentialClass: piv, and
  5. note its href.

You can accomplish the last two steps with the JSONPath filter

$.results[?(@.credentialClass=='piv')].href.

Explanation: Command Centre ships with a handful of card types, and administrators can add more, but the one that Command Centre uses for PIV and PIV-I cards has its own credential class.

Search card types

This returns the card types your operator is privileged to view. They may be different card types from those you are allowed to assign to cardholders, and since that is the only thing that this API does with card types, you should probably be using that function instead.

Authorizations:
API_keybasic

Responses

BetaCreate a card type [coming]

Creates a new card type, setting practically everything except the PIV fields.

Do not code this URL into your application. Take it from the href field in the features.cardTypes.cardTypes.href field of GET /api.

The POST expects a document in the same format as the card type detail.

When successful it returns a location header containing the address of the new card type.

Note that you can only create one item per POST.

This call requires the RESTConfiguration licence.

Authorizations:
API_keybasic
Request Body schema: application/json
required

Note that not all the fields in this schema make sense to send when creating a new card type. id and href, for example.

name
string
division
object

The division that contains this card type. Required when creating a card type.

notes
string

Free text.

Because of its potential size, the server does not return the notes field by default. You need to ask for it with fields=notes.

facilityCode
string

A facility code is a letter (A-P) followed by up to five digits. It is encoded onto cards so that they only work at sites with the correct facility code.

PIV cards, PIV-I cards, and mobile credentials do not have a facility code.

Most credential classes require a facility code on creation. But it cannot be changed once set, so this field is ignored in a PATCH.

credentialClass
string
Enum: "piv" "pivi" "card" "mobile" "digitalId" "govPass" "trackingTag" "transact"

Required when creating a new card type but ignored when modifying one since a credential's type cannot be changed once set.

minimumNumber
string

For card types with integer card numbers, this is the minimum. Must be non-negative.

maximumNumber
string

For card types with integer card numbers, this is the maximum. Must be non-negative.

regex
string

This is the regular expression that a text card number must match before Command Centre will accept it.

regexDescription
string

Regular expressions often need explaining to your users.

cardStateSet
any

Documentation coming. TODO

POST only.

defaultIssueLevel
any

Documentation coming. TODO

cardIssueLevelMustMatchDefault
any

Documentation coming. TODO

enableExpiryNotifications
any

Documentation coming. TODO

warningPeriod
any

Documentation coming. TODO

pinLength
any

Documentation coming. TODO

inactivityTimeoutInDays
any

Documentation coming. TODO

allowReprint
any

Documentation coming. TODO

allowReEncode
any

Documentation coming. TODO

isEngage
any

Documentation coming. TODO

sendRegistrationEmail
any

Documentation coming. TODO

sendRegistrationSms
any

Documentation coming. TODO

warningPeriodType
any

Documentation coming. TODO

Days, Weeks, Months, or Years.

cardNumberFormat
any

Documentation coming. TODO

POST only.

defaultExpiryType
any

Documentation coming. TODO

ExplicitDateTime or Duration.

defaultExpiryDuration
any

Documentation coming. TODO

(if the type is duration)

defaultExpiryFrom
any

Documentation coming. TODO

defaultExpiryUntil
any

Documentation coming. TODO

(if defaultExpiryType is explicitDateTime)

engageCardFormat
any

Documentation coming. TODO

Only if isEngage is true. There are nine acceptable values.

appleTemplateId
any

Documentation coming. TODO

Required if credential class is Apple Pass.

appleLinkedCredentials |
any

Documentation coming. TODO

The POST format is different from the PATCH format's add and remove arrays.

Responses

Request samples

Content type
application/json
{
  • "name": "Red DESFire visitor badge",
  • "division": {},
  • "notes": "Disabled after 7d inactivity, 6-char PIN",
  • "facilityCode": "A12345",
  • "credentialClass": "card",
  • "minimumNumber": "1",
  • "maximumNumber": "16777215",
  • "regex": "^[A-Za-z0-9]+$",
  • "regexDescription": "Only alphanumeric characters",
  • "cardStateSet": null,
  • "defaultIssueLevel": null,
  • "cardIssueLevelMustMatchDefault": null,
  • "enableExpiryNotifications": null,
  • "warningPeriod": null,
  • "pinLength": null,
  • "inactivityTimeoutInDays": null,
  • "allowReprint": null,
  • "allowReEncode": null,
  • "isEngage": null,
  • "sendRegistrationEmail": null,
  • "sendRegistrationSms": null,
  • "warningPeriodType": null,
  • "cardNumberFormat": null,
  • "defaultExpiryType": null,
  • "defaultExpiryDuration": null,
  • "defaultExpiryFrom": null,
  • "defaultExpiryUntil": null,
  • "engageCardFormat": null,
  • "appleTemplateId": null,
  • "appleLinkedCredentials |": null
}

Search usable card types

This returns the card types you are privileged to assign to a cardholder.

Since a site usually has only a few card types, and each is small, the search, sorting, field selection, and pagination parameters are probably of little use to you. But they work.

If your result set is empty it means your operator does not have the privilege to view any card types. Your operator needs a privilege that allows assigning cards and credentials to cardholders such as 'Add / Edit Card or Credential' or 'Create / Edit / Create and Edit Cardholders'.

You can find this URL in features.cardTypes.assignin /api. It was new in 8.10. In the interest of forward compability, do not build it yourself.

Authorizations:
API_keybasic
query Parameters
sort
string
Enum: "id" "name" "-id" "-name"

Changes the sort field between database ID and name.

If you prefix id or name with a minus sign (ASCII 45), the sort order is reversed.

There are two very strong reasons to sort by ID:

  1. Sorting by name carries a risk of missing or duplicating objects if your result set spans multiple pages and another operator is editing the database while your REST client is enumerating them. This is known as "page drift." Sorting by ID does not carry that risk.
  2. Following a next link is dramatically quicker when sorting by ID.

We strongly recommend sorting by ID. In case you were still in doubt, we will do that by default in a future version of Command Centre.

The server silently ignores anything except the options listed here.

top
integer >= 1

Limits the results to no more than this many items per page.

Older versions of Command Centre returned 100 items per page in the absence of this parameter. That is acceptable for GUI applications that will only display the first page, but for integrations that intend to proceed through the entire database it causes a lot of chatter.

8.70 and later versions will default to 1000 items per request. This is about where a graph of throughput versus page size begins to level out.

name
string

Limits the returned items to those with a name that matches this string. Without surrounding quotes or a percent sign or underscore, it is a substring match; surround the parameter with double quotes "..." for an exact match. Without quotes, a percent sign % will match any substring and an underscore will match any single character.

The search is always case-insensitive. Results are undefined if you do a substring search for the empty string (name=). You will receive no items if you search for those with no name (name=""), as all items must have a name.

Search parameters are ANDed together.

division
Array of strings

Limits the returned items to those that are in these divisions.

That includes all the items in those divisions' child divisions, because Command Centre treats items as though they are also in their division's parent, and its parent, and so on up to the root division.

Separate the IDs of the divisions you are interested with commas. Item IDs are short alphanumeric strings, not URLs.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

directDivision
Array of strings

Restricts items to those whose division is in this list.

Unlike division=, it does not follow ancestry. That means it will limit the search to items that are directly assigned to the divisions you list, whereas division (without the direct) will also include items that are assigned to their descendants.

List the IDs of the divisions you are interested in separated by commas. Item IDs are short alphanumeric strings, not URLs.

Because this is the first query parameter we added that contains a capital letter, this will be the first time you have had to think about case sensitivity. directDivision works, directdivision does not.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

Added in 9.20.

description
string

Limits the returned items to those with a description that matches this string. By default it is a substring match; surround it with double quotes "..." for an exact match. A _ will match any single character, and a % will match any substring. With or without quotes, having either of these wildcards in the string will anchor it at both ends as though you had surrounded it with ".

The search is always case-insensitive. Results are undefined if you search for the empty string (description= or description="").

Search parameters are ANDed together.

fields
Array of strings
Items Enum: "href" "id" "name" "division" "facilityCode" "availableCardStates" "credentialClass" "minimumNumber" "maximumNumber" "notes" "regex" "regexDescription"

Specifies which fields to return instead of the default set (which contains nearly every field). Separate values with commas.

Treat the string matches as case sensitive: use 'facilityCode' rather than 'facilitycode'.

pos
integer

Reserved for internal use. You may see it in URLs you receive from the server, but you must never add it yourself.

skip
integer

Reserved for internal use. Do not add it to your queries.

Responses

Response samples

Content type
application/json
{
  • "results": [
    ],
}

Get one card type

This returns some basic data for a card type. It exists so that clients following card type hrefs from other controllers do not receive a 404. To find out about card types available for assigning to cardholders, use card_types/assign instead.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

Responses

BetaUpdate a card type [coming]

This is the call you use to update a card type. Take the URL from the results of a card type search. In the interest of forward compability, do not build it yourself.

The PATCH expects a document in the same format as the the card type detail but with fewer fields.

This call requires the RESTConfiguration licence.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

Request Body schema: application/json
required

Note that not all the fields in this schema make sense to send when creating a new card type. id and href, for example.

name
string
division
object

The division that contains this card type. Required when creating a card type.

notes
string

Free text.

Because of its potential size, the server does not return the notes field by default. You need to ask for it with fields=notes.

facilityCode
string

A facility code is a letter (A-P) followed by up to five digits. It is encoded onto cards so that they only work at sites with the correct facility code.

PIV cards, PIV-I cards, and mobile credentials do not have a facility code.

Most credential classes require a facility code on creation. But it cannot be changed once set, so this field is ignored in a PATCH.

credentialClass
string
Enum: "piv" "pivi" "card" "mobile" "digitalId" "govPass" "trackingTag" "transact"

Required when creating a new card type but ignored when modifying one since a credential's type cannot be changed once set.

minimumNumber
string

For card types with integer card numbers, this is the minimum. Must be non-negative.

maximumNumber
string

For card types with integer card numbers, this is the maximum. Must be non-negative.

regex
string

This is the regular expression that a text card number must match before Command Centre will accept it.

regexDescription
string

Regular expressions often need explaining to your users.

cardStateSet
any

Documentation coming. TODO

POST only.

defaultIssueLevel
any

Documentation coming. TODO

cardIssueLevelMustMatchDefault
any

Documentation coming. TODO

enableExpiryNotifications
any

Documentation coming. TODO

warningPeriod
any

Documentation coming. TODO

pinLength
any

Documentation coming. TODO

inactivityTimeoutInDays
any

Documentation coming. TODO

allowReprint
any

Documentation coming. TODO

allowReEncode
any

Documentation coming. TODO

isEngage
any

Documentation coming. TODO

sendRegistrationEmail
any

Documentation coming. TODO

sendRegistrationSms
any

Documentation coming. TODO

warningPeriodType
any

Documentation coming. TODO

Days, Weeks, Months, or Years.

cardNumberFormat
any

Documentation coming. TODO

POST only.

defaultExpiryType
any

Documentation coming. TODO

ExplicitDateTime or Duration.

defaultExpiryDuration
any

Documentation coming. TODO

(if the type is duration)

defaultExpiryFrom
any

Documentation coming. TODO

defaultExpiryUntil
any

Documentation coming. TODO

(if defaultExpiryType is explicitDateTime)

engageCardFormat
any

Documentation coming. TODO

Only if isEngage is true. There are nine acceptable values.

appleTemplateId
any

Documentation coming. TODO

Required if credential class is Apple Pass.

appleLinkedCredentials |
any

Documentation coming. TODO

The POST format is different from the PATCH format's add and remove arrays.

Responses

Request samples

Content type
application/json
{
  • "name": "Red DESFire visitor badge",
  • "division": {},
  • "notes": "Disabled after 7d inactivity, 6-char PIN",
  • "facilityCode": "A12345",
  • "credentialClass": "card",
  • "minimumNumber": "1",
  • "maximumNumber": "16777215",
  • "regex": "^[A-Za-z0-9]+$",
  • "regexDescription": "Only alphanumeric characters",
  • "cardStateSet": null,
  • "defaultIssueLevel": null,
  • "cardIssueLevelMustMatchDefault": null,
  • "enableExpiryNotifications": null,
  • "warningPeriod": null,
  • "pinLength": null,
  • "inactivityTimeoutInDays": null,
  • "allowReprint": null,
  • "allowReEncode": null,
  • "isEngage": null,
  • "sendRegistrationEmail": null,
  • "sendRegistrationSms": null,
  • "warningPeriodType": null,
  • "cardNumberFormat": null,
  • "defaultExpiryType": null,
  • "defaultExpiryDuration": null,
  • "defaultExpiryFrom": null,
  • "defaultExpiryUntil": null,
  • "engageCardFormat": null,
  • "appleTemplateId": null,
  • "appleLinkedCredentials |": null
}

BetaRemove a card type [coming]

This call removes a card type from Command Centre. In the interest of forward compability, take the URL from the results of a card type search rather than building it yourself.

This call requires the RESTConfiguration licence.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

Responses

Changelog

API changes on the roadmap

  • Alarms will have a block containing their event group, as events do.

  • You will be able to set the number of alarms you want coming back from a GET, as you can with events.

  • Potentially breaking change: the API routes that return the value of a cardholder's date PDF present it in either in RFC 3339 format with a time, or a format specific to the server's locale, depending on the route. A future version will change to date-only ISO 8601 (date PDFs only contain a date, not a time).

  • Potentially breaking change: the API route that returns the value of a string PDF will change to return a 404 if the cardholder does not have a value for it, as it does for image and date PDFs. Currently, missing string PDFs come out as a zero-length payload.

  • Events indicating that an operator modified an item may not have a cardholder at the end of the operator href. It may be a new kind of item, because we have new events coming that will indicate when an integration modifies an item rather than a human operator.

  • You will be able to create, delete, and change the the basic configuration of roles, PDFs, and card types.

  • POTENTIALLY BREAKING CHANGE: searching for cardholders using pdf_xxx="" or pdf_xxx= with no search value currently returns no cardholders. That is neither useful nor desired. Instead, a future version of Command Centre will return cardholders with a blank value for that PDF.

  • POTENTIALLY BREAKING CHANGE: the API route that lets you modify a cardholder by PATCH also works if you send it a POST. It should not, because POSTs create things, not modify them. The fix will break clients that rely on this. There should be no clients relying on it since the POST was not documented.

  • POTENTIALLY BREAKING CHANGE: in future, PATCH methods will return "200 Success" instead of "204 No Content" and may contain the object you modified plus a message from the API giving you feedback on your request. Please be aware that all 200-level response codes mean success, not just the ones old versions have been sending you.

  • A cardholder will show its visits and escort.

  • PDFs will have "Revealable" access levels.

  • Current versions of the API only show a PDF on a cardholder if he or she has a value for that PDF. That makes it difficult to find out which PDFs a cardholder could have, so a future version will allow you to ask for all of them with fields=allPdfs.

  • You will be able to request the competencies that your operator has the permission to assign. That is determined by privileges, a competency setting, and an operator group setting. Current versions let you request the competencies that your operator has the permission to view, which is a larger set determined by privileges alone, and not suitable for interactive REST clients.

  • You will be able to create and delete alarm zones, and modify some basic fields.

API changes in 9.50

  • OIDC login support for operators.

  • Creating an item status subscription and collecting the first batch of changes will no longer return the first set of results twice. If your application follows the algorithm at the second link above it will always be compatible with this API.

    The performance improvements were such that we felt it worthwhile to port it back to all supported versions, so it is also present in the latest maintenance releases of 9.10 through 9.40.

  • Potential breaking change: the maximum length of an item's name increased from 60 to 110 characters, and attempts to set a name longer than that will fail. Earlier versions silently truncated the name and let the update proceed. Cardholder first and last names remain capped at 50 characters each.

  • The Apple Employee Badge Type and State Set now have proper canonical type names, improved from type_279 and type_280.

  • Cardholders have accessibilities for skipping PIN entry and taking longer to get through a door, in addition to the existing accessibility to not use a scramble pad.

  • POTENTIALLY BREAKING CHANGE: GovPass cards and card states may have changed item type names between 9.20 and 9.30, depending on the card type and the site's licences.

API change in May 2026 maintenance releases

  • Potential breaking change in 9.20 MR7, 9.30 MR5, and 9.40 MR2: attempts to set the name of an item that is not a cardholder to a string that is longer than 60 characters will fail. Earlier versions silently truncated the name and let the update proceed. There is no change to the handling of cardholders' names.

API changes in 9.40

  • Support for half-cycle door locks. Common in correctional facilities, half-cycle locks remain unlocked until closed. Regular doors unlock for a few seconds before locking again.

  • POTENTIALLY BREAKING CHANGE: for efficiency, 9.30 orders search results differently from 9.20 when your query does not include a sort parameter. If you care about the order of your items, tell the server how you want them sorted.

  • POTENTIALLY BREAKING CHANGE: GovPass cards may have a new credentialClass and GovPass card states will have new names, depending on the card type and the site's licences.

  • You can create, modify, and delete access groups.

API changes in 9.30

  • You can create, modify, and delete divisions and access groups.

  • The server will accept TLS 1.3 connections when running on suitable versions of Windows. Prior versions would only accept TLS 1.2 connections.

  • An API client can switch its own status between normal and faulty, and can set arbitrary status text. Marking the item as faulty will raise an alarm in Command Centre.

  • Command Centre can, optionally, raise an alarm if an API client has not made an API call within a configurable period. This is an addition to Command Centre, not to the API, but deserves a mention here for developers considering adding status monitoring to their integrations. It may be done for you!

API changes in 9.20

  • You can filter events and items by their direct division. The older division search is recursive: it considers everything that has any of the filter's divisions anywhere in its ancestry. The new division search is shallow: it only returns events and items that are direct members of the division in the filter.

API changes in 9.10

  • You can request the name of an alarm's instruction, and the contents of the instruction itself.

  • You can create, modify, and delete competencies.

  • You can request a locker's status and send an override to quarantine it. The use cases section shows how.

API changes in 9.00

  • A new event type hasLocation greatly simplifies the monitoring of cardholder movements

  • A new (location block on events greatly simplifies interpreting them.

  • You can search for cardholders by the access zone they are in.

  • GovPass cards have two new fields, visitorContractor and ownedBySite.

Alarms and events API changes in 8.90

  • BREAKING CHANGE: the operator must have the 'Create Events and Alarms' privilege in the division of the source item, if your request specifies a source item. Current versions only require that the operator has that privilege on at least one division.

  • To improve the symmetry between events and alarms, they both now carry a field eventType containing the ID and name of their type. The type field, which has different contents for alarms and events, is now obsolete (but still returned in results).

  • Alarms contain a new field called event containing a link to the corresponding event, mirroring the existing alarm field coming the other way from an event.

  • You can request a division's description. This has been possible since 8.50 but was not certified until 2022, so it gets a mention now.

  • Write-only access to card PINs.

  • You can set a reason when re-issuing or removing a card which will appear on the resulting event. The default is the card's previous state.

  • You can now set a visitor's state (signing in, etc.). Visits will return that, if you ask.

  • Bug fix: removing an operator group from a cardholder by PATCH was not possible in the early versions of 8.70 and 8.80. It was fixed in 8.70.2113, 8.80.1116, and all versions of 8.90.

API changes in 8.80

  • BREAKING CHANGE: Date PDFs no longer come out of the API with a time component or time zone designator, because date PDFs don't hold a time or time zone. Previously they came out as midnight UTC, which implied more accuracy than date PDFs hold.

  • Redactions.

  • An optional PDF field operatorAccess contains the level of access your operator has to cardholders' values for the PDF.

  • Card type regex and regexDescription fields.

  • Email and mobile PDFs return their 'Default Notifications' flag on request. This actually happened in 8.50 but did not make it into the "changes" list.

  • Early-adopter support for Interlock groups.

API changes in 8.70

  • Each event in a page of search results will contain URLs to continue the search after that event. This is a significant benefit to integrations that extract large pages of events and may encounter a problem mid-page, and have to resume without loss or duplication later.

  • A new privilege 'View Cardholder Events' grants visibility of an event if the operator has the privilege in both the event's division and the event's cardholder's division. This allows a site to create a REST client that can monitor selected cardholders' movements through selected areas, but cannot see any other activity in those areas.

  • You may now use the relatedItem query parameter in an item search to find events that are associated with a particular item.

  • BREAKING CHANGE: Missing image PDFs will no longer have "not captured" as their value. Instead, they will have no value at all.

  • A cardholder's operator group memberships (added in 8.50) now contain an href that you can use in an HTTP DELETE as another way of removing a cardholder from an operator group.

  • The server returns 1000 items by default instead of 100.

  • Image PDFs tell you whether they are the cardholder's profile picture.

  • Image PDFs have a new optional field contentType that returns their MIME type. This deprecates the old imageFormat field, which is non-standard.

  • Asking for a particular PDF on a cardholder (by putting pdf_XXX into the fields query parameter) will cause it to appear even if the cardholder has no value for that PDF. Previous versions only showed if it had a non-blank value.

  • Attempting to give a cardholder a competency they already have will fail instead of allowing it and raising an alarm. Note that a cardholder having two links to the same competency leads to undefined behaviour.

  • A new query parameter requested_by lets you attribute overrides to another cardholder. Your operator must have the 'Delegate API Activity' privilege in the cardholder's division.

  • Item updates now include fields that changed to an empty value. Versions up to 8.60 returned an update but did not tell you which field changed or what it changed to, if it changed to a blank.

API changes in 8.60

  • Card numbers on Bluetooth (mobile) and PIV card events are now full-length. Mobile numbers are now the phone's ID string, changed from the number that 8.50 returned. Decimal numbers now come out unsigned. Note that neither 8.50's numbers nor 8.60's ID strings are guaranteed unique across phones.

  • Access events that do not have a card, such as someone entering their user code instead of badging their card, will no longer return a card block.

  • You can search for cardholders by division or description.

  • 8.60 rejects unsupported HTTP verbs instead of treating them like a GET. For example, if you send a POST to /api/competencies 8.50 will return a list of competencies but 8.60 will return a 400-level error.

  • In build 8.60.1684 or later, attempting to give a cardholder a competency they already have will fail instead of allowing it and raising an alarm. Note that a cardholder having two links to the same competency leads to undefined behaviour.

  • The RESTOverrides licence allows you to find items and their override URLs.

API changes in 8.50

  • The server property that turns off client certificate checking changed.

  • Divisions can return some of their Visitor Management configuration.

  • You can view any item's notes. You have been able to for a while now, but it was missing from this document.

  • You can request a division's description.

  • You can manage operators by setting their operator group memberships and logon credentials.

  • You can view operator groups.

  • Lockers and locker banks report the hardware controller where they reside.

  • Cardholders report their 'disable cipher pad' setting (vision impairment).

  • Card types will show their division on request.

  • Cardholders can have default floors and passenger type flags per elevator group. Thyssen-Krupp systems can prepare an elevator car when Command Centre grants a cardholder access through lobby turnstiles.

  • You can list receptions and see enough of a division's visitor management configuration to create and manage visits.

  • Image Personal Data Field definitions will show their width, height, and format (JPG, PNG, or BMP) on request.

  • Email and mobile PDFs return their 'Default Notifications' flag on request.

  • A schedules API provides CRUD of the six schedule item types.

  • A day categories API returns the day categories you need for those schedules.

  • A pulse overrides an output.

  • A 'connectedController' field grew on the item types that did not already have it.

  • An elevator groups API provides a view of elevator groups so that you can set a cardholder's default floor.

API changes in 8.40

  • You may now use the fields query parameter to tailor the fields that come back for events and alarms.

  • Operator add, modify, and delete events now contain a link to the affected item in a new modifiedItem block, deprecating the accessGroup block for those event types.

  • All operator events now contain the operator's name at the time.

  • All events now contain the name of the event's division.

  • The item search can now filter multiple item types.

  • Events now show their origin when they have arrived from a remote server (in a multiserver environment).

  • Access groups have 22 new fields showing the privileges and access they grant their members. These new fields are in the default set for the detail view.

  • Access groups now return the alarm zones over which they have privilege.

  • Items on remote servers now show their origin server in a new serverDisplayName field.

  • Cards contain the date and time of their last print or encode, and their issue level at the time.

API changes in 8.30

  • The items API has methods that let you monitor the status of large numbers of items.

  • Doors related to guard tour events now appear in an event's door block.

  • Cardholder change tracking lets you synchronise users into an external system by informing it of changes as they occur.

  • Cardholder group membership hrefs now contain a long string where they used to contain a small integer. Integrations that cache membership hrefs a) should not and b) will need to refresh.

  • A cardholder's card object now contains a Boolean field called trace indicating whether its trace flag is set. A card with tracing on generates an event every time it is used.

  • A 'connectedController' field in the door detail returns the ID and name of the door's hardware controller (a hardware controller, not an API controller).

API changes in 8.20

  • Alarms and events with a related cardholder now show the cardholder's current first and last name in separate fields.

  • The name field on an alarm or event with a related cardholder is now the cardholder's name at the time of the event, rather than at the time of the request.

  • You can use the 'fields' parameter to add the 'details' field to an event summary.

  • A new field update_location on a cardholder gives a link to a POST that changes his or her current location (access zone).

  • An update_cardholder_location call on the Access Zones API returns you the list of Access Zones into which your operator is allowed to move cardholders.

  • Lockers and locker banks are now visible with the RESTStatus licence, including whether a locker is available or allocated. You still need RESTCardholders to see which cardholder/s a locker is assigned to.

  • Lockers moved from the locker banks controller into their own. That changed their hrefs.

  • Bugfix: you can now change a cardholder's division.

  • A cardholder's relationships block now contains the role holder's two name fields. The name field, present since 7.90, is simply these two fields joined with a space, and is therefore ambiguous when a cardholder only has one name.

API changes in 8.10.1112

  • You can send an override to a locker to open it.

  • You can use the fields query parameter to select the fields you receive from locker bank summary and details GETs. The use cases section shows how.

API changes in 8.10

  • Incoming events

  • Events now show their related access groups and doors for external event types.

  • There is a card types API that returns the card types your operator is able to use when assigning cards to cardholders.

  • There is a PDF API that returns the personal data field definitions your operator is able to see.

  • You can change the notifications flag on a cardholder's PDF.

  • Certificates and biometric data are available on PIV cards.

  • An inputs API gives you the state of 'input' hardware items and lets you override them. It is very similar to the outputs API.

-

This path does not exist in the API. It is in the documentation to satisfy the HTML renderers that require every tag to contain a path.

Authorizations:
API_keybasic

Competencies

Competencies are items to which cardholders can be linked, and which access zones may require on a cardholder before allowing them in.

They have their own access privileges, so operators can see or edit a cardholder's competencies based on the competency's settings as well as the cardholder's division and the privileges the operator has in that division.

Notification settings on the competency cause advance warnings to go to the cardholder and his or her related cardholders (line managers, for example) before the competency expires.

Competencies differ from access groups in that a cardholder can have only one link to a given competency. Attempting to create another will either fail or raise a stateful alarm depending on your version of Command Centre.

The REST API gives you access to competencies through create, search, dereference, update, and delete functions described below.

The Configuration Client online help describes competencies fully.

Search competencies

This returns competencies matching your search criteria.

The result will contain no more than 100 or 1000 competencies depending on your version; you should follow the next link (if present) for the next batch.

If your result set is empty it means your operator does not have the privilege to view any competencies. Perhaps there are none in the divisions in which your operator has 'View site' or 'Edit site', or your operator has no privileges at all.

A bug in 7.90 meant that this call did not provide next links for sites that had more than 100 competencies. If this is you, set the 'top' parameter as high as you can (as recommended in the efficiency tips). Command Centre clamps that to a maximum of ten thousand. If that is not enough competencies for you, you are probably already in contact with Gallagher technical support.

Get this URL from features.competencies.competencies.href in /api. In the interest of forward compability, do not build it yourself.

Authorizations:
API_keybasic
query Parameters
sort
string
Enum: "id" "name" "-id" "-name"

Changes the sort field between database ID and name.

If you prefix id or name with a minus sign (ASCII 45), the sort order is reversed.

There are two very strong reasons to sort by ID:

  1. Sorting by name carries a risk of missing or duplicating objects if your result set spans multiple pages and another operator is editing the database while your REST client is enumerating them. This is known as "page drift." Sorting by ID does not carry that risk.
  2. Following a next link is dramatically quicker when sorting by ID.

We strongly recommend sorting by ID. In case you were still in doubt, we will do that by default in a future version of Command Centre.

The server silently ignores anything except the options listed here.

top
integer >= 1

Limits the results to no more than this many items per page.

Older versions of Command Centre returned 100 items per page in the absence of this parameter. That is acceptable for GUI applications that will only display the first page, but for integrations that intend to proceed through the entire database it causes a lot of chatter.

8.70 and later versions will default to 1000 items per request. This is about where a graph of throughput versus page size begins to level out.

name
string

Limits the returned items to those with a name that matches this string. Without surrounding quotes or a percent sign or underscore, it is a substring match; surround the parameter with double quotes "..." for an exact match. Without quotes, a percent sign % will match any substring and an underscore will match any single character.

The search is always case-insensitive. Results are undefined if you do a substring search for the empty string (name=). You will receive no items if you search for those with no name (name=""), as all items must have a name.

Search parameters are ANDed together.

division
Array of strings

Limits the returned items to those that are in these divisions.

That includes all the items in those divisions' child divisions, because Command Centre treats items as though they are also in their division's parent, and its parent, and so on up to the root division.

Separate the IDs of the divisions you are interested with commas. Item IDs are short alphanumeric strings, not URLs.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

directDivision
Array of strings

Restricts items to those whose division is in this list.

Unlike division=, it does not follow ancestry. That means it will limit the search to items that are directly assigned to the divisions you list, whereas division (without the direct) will also include items that are assigned to their descendants.

List the IDs of the divisions you are interested in separated by commas. Item IDs are short alphanumeric strings, not URLs.

Because this is the first query parameter we added that contains a capital letter, this will be the first time you have had to think about case sensitivity. directDivision works, directdivision does not.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

Added in 9.20.

description
string

Limits the returned items to those with a description that matches this string. By default it is a substring match; surround it with double quotes "..." for an exact match. A _ will match any single character, and a % will match any substring. With or without quotes, having either of these wildcards in the string will anchor it at both ends as though you had surrounded it with ".

The search is always case-insensitive. Results are undefined if you search for the empty string (description= or description="").

Search parameters are ANDed together.

fields
Array of strings
Default: "defaults"
Items Enum: "href" "id" "name" "shortName" "description" "division" "notes" "expiryNotify" "noticePeriod" "defaultExpiry" "defaultAccess" "defaults"

Specifies which fields to return in the search results. The values you can list are the same as the field names in the details page. Using it you can return everything on the search page that you would find on the details page. Separate values with commas.

Use the special value defaults to return the fields you would have received had you not given the parameter at all. Add more after a comma.

Treat the string matches as case sensitive.

In v8.00 you will receive the href and internal ID even if you did not ask for them. In 8.10 you will not. If you are going to send the fields parameter and need the href or ID, be explicit.

pos
integer

Reserved for internal use. You may see it in URLs you receive from the server, but you must never add it yourself.

skip
integer

Reserved for internal use. Do not add it to your queries.

Responses

Response samples

Content type
application/json
{}

Create a competency

Creates a new competency.

The POST expects a document in the same format as the the competency detail but with far fewer fields. An example is this POST example.

When successful it returns a location header containing the address of the new competency.

Note that you can only create one competency per POST.

Do not code this URL into your application. Take it from the results of GET /api.

New to Command Centre 9.10.

This requires the RESTConfiguration licence.

Authorizations:
API_keybasic
Request Body schema: application/json

This is an example of a PATCH you could use to update a competency, and a POST you could use to create one.

No fields are mandatory in a PATCH, but when using a POST to create a competency you must supply a division.

name
string

The new item's name. If you supply a name and another item of the same type already exists with that name, the call will fail. If you leave it blank in a POST, Command Centre will pick a name for you.

shortName
string <= 16 characters

If you supply a string that is too long, Command Centre will truncate it."

description
string

The new item's description.

division
object

The division to contain this competency.

Mandatory when creating a new competency.

notes
string

A string, able to me much longer than description, suitable for holding notes about the item.

Responses

Request samples

Content type
application/json
{}

Get details of a competency

You get this URL from a cardholder or from a competency search. In the interest of forward compability, do not build it yourself.

The results document gives everything Command Centre has on a competency except the warning messages that appear on a reader when a cardholder needs to take action.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
fields
Array of strings
Default: "defaults"
Items Enum: "href" "id" "name" "shortName" "description" "division" "notes" "expiryNotify" "noticePeriod" "defaultExpiry" "defaultAccess" "defaults"

Specifies which fields to return. The values you can list are the same as the field names in the details page. Use it to reduce the size of the result document. Separate values with commas.

Treat the string matches as case sensitive.

Responses

Response samples

Content type
application/json
{
  • "id": "2354",
  • "name": "Hazardous goods handling",
  • "description": "Required for access to chem sheds.",
  • "serverDisplayName": "ruatoria.satellite.net",
  • "notes": "",
  • "division": {},
  • "shortName": "",
  • "expiryNotify": false,
  • "noticePeriod": {
    },
  • "defaultExpiry": {
    },
  • "defaultAccess": "fullAccess"
}

Update a competency

This is the call you use to update a division's name, short name, description, notes, or division. In the interest of forward compability, take the URL from the results of a division search rather than building it yourself.

The PATCH expects a document in the same format as the the competency detail but with fewer fields. An example is this PATCH example.

New to Command Centre 9.10.

This call requires the RESTConfiguration licence.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

Request Body schema: application/json

This is an example of a PATCH you could use to update a competency, and a POST you could use to create one.

No fields are mandatory in a PATCH, but when using a POST to create a competency you must supply a division.

name
string

The new item's name. If you supply a name and another item of the same type already exists with that name, the call will fail. If you leave it blank in a POST, Command Centre will pick a name for you.

shortName
string <= 16 characters

If you supply a string that is too long, Command Centre will truncate it."

description
string

The new item's description.

division
object

The division to contain this competency.

Mandatory when creating a new competency.

notes
string

A string, able to me much longer than description, suitable for holding notes about the item.

Responses

Request samples

Content type
application/json
{}

Remove a competency

This call removes a competency from Command Centre. You get this URL from a cardholder or from a competency search. In the interest of forward compability, do not build it yourself.

New to Command Centre 9.10.

This call requires the RESTConfiguration licence.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

Responses

Day Categories

A day category links a calendar and a schedule. The calendar determines the days of the year that fall into a day category, and the schedule determines what happens at certain times on those days.

The method in this group gives you the day category hrefs you need when creating and modifying schedules. It is a GET: you cannot create or modify day categories using the API.

Day categories are new to the 8.50 API.

Use case: listing day categories

  1. GET /api.

  2. Follow the link at features.dayCategories.dayCategories.href, appending a search term such as name=substring or name="full name" to filter the selection, and fields to tell the server what to return about each day category.

  3. Search the results for the day category you are after. With other types of items you would follow the next link until there isn't one, but most sites only have a handful of day categories so they will most likely fit on the first page. Especially if you set top=1000, which is advised.

Search day categories

This returns the day categories that match your search criteria.

The result will contain no more than 100 or 1000 (depending on your version), or as many as you asked for more in your request; you should follow the next link, if it is present, to collect the next batch. Generally a site does not have too many day categories, so if you set top=1000 you are bound to collect them all.

If your result set is empty it means your operator does not have any of the privileges that allow viewing day categories, such as 'View Site', 'Configure Site', or 'Edit Schedules'. Because day categories do not have divisions, having one of those privileges in any division is enough.

When you have seen them all there will be no next link.

This does not take a division query parameter because day categories are not in divisions.

Do not code this URL into your application. Take it from the 'href' field in the features.dayCategories.dayCategories section of /api.

Added in 8.50.

Authorizations:
API_keybasic
query Parameters
sort
string
Enum: "id" "name" "-id" "-name"

Changes the sort field between database ID and name.

If you prefix id or name with a minus sign (ASCII 45), the sort order is reversed.

There are two very strong reasons to sort by ID:

  1. Sorting by name carries a risk of missing or duplicating objects if your result set spans multiple pages and another operator is editing the database while your REST client is enumerating them. This is known as "page drift." Sorting by ID does not carry that risk.
  2. Following a next link is dramatically quicker when sorting by ID.

We strongly recommend sorting by ID. In case you were still in doubt, we will do that by default in a future version of Command Centre.

The server silently ignores anything except the options listed here.

top
integer >= 1

Limits the results to no more than this many items per page.

Older versions of Command Centre returned 100 items per page in the absence of this parameter. That is acceptable for GUI applications that will only display the first page, but for integrations that intend to proceed through the entire database it causes a lot of chatter.

8.70 and later versions will default to 1000 items per request. This is about where a graph of throughput versus page size begins to level out.

name
string

Limits the returned items to those with a name that matches this string. Without surrounding quotes or a percent sign or underscore, it is a substring match; surround the parameter with double quotes "..." for an exact match. Without quotes, a percent sign % will match any substring and an underscore will match any single character.

The search is always case-insensitive. Results are undefined if you do a substring search for the empty string (name=). You will receive no items if you search for those with no name (name=""), as all items must have a name.

Search parameters are ANDed together.

fields
Array of strings
Default: "defaults"
Items Enum: "href" "name" "description" "notes" "defaults"

This instructs the server to return only these fields in the search results. The values you can list are the field names in the schema definitions in this document. Separate values with commas.

Use the special value defaults to return the fields you would have received had you not given the parameter at all. Obviously only do that if you have more to add.

Treat the string matches as case-sensitive.

pos
integer

Reserved for internal use. You may see it in URLs you receive from the server, but you must never add it yourself.

skip
integer

Reserved for internal use. Do not add it to your queries.

Responses

Response samples

Content type
application/json
{}

Divisions

These methods provide access to the Command Centre divisions that are available to the REST client. Call /api and use the link at features.{your_feature}.divisions.href to retrieve the divisions in which the REST operator has privileges for that feature. Pick out the ones of interest and use those IDs in event, alarm, or item searches if you don't want the search to scan everything.

Or, you may end up here by following a division's link from a reception item when you need to retrieve the visitor management configuration for that reception's division.

Licensing

Every REST licence enables the divisions controller: RESTEvents, RESTCreateEvents, RESTCardholders, RESTStatus, RESTOverrides, and RESTConfiguration.

Create a division

Creates a new division.

The POST expects a document in the same format as the the division detail but with far fewer fields. An example is this POST example. The only mandatory field is parent.

When successful it returns a location header containing the address of the new division.

Note that you can only create one division per POST.

Do not code this URL into your application. Take it from the results of GET /api. That shows the API features for which you have the necessary licence.

New to 9.30.

Authorizations:
API_keybasic
Request Body schema: application/json
required

The only required field here is the new division's parent. All divisions (except the root) must have a parent.

name
string

The division's name. If you supply a name and another division already exists with that name, the call will fail. If you leave it blank in a POST, Command Centre will pick value for you.

description
string

The division's description.

notes
string

A string, able to be much longer than description, suitable for holding notes about the division.

object

An object containing an href to the division entity representing the current division's parent.

Required when creating a new division, because only root divisions can be unparented and you cannot create a new one of those.

Responses

Request samples

Content type
application/json
{}

List divisions

The functions inside /api/divisions/ retrieve the divisions in which the operator can perform other functions. They all return the same data structure.

For example, /api/divisions/view_events retrieves the list of divisions in which the REST operator has privileges to view events, and /api/division/view_alarms does the same for alarms.

Do not code these URLs into your application. Take them from the results of GET /api. For the events and alarms examples, the links will be at events.divisions.href and alarms.division.href.

/api only shows API features for which you have the necessary licence.

Authorizations:
API_keybasic
query Parameters
top
integer >= 1

Sets the maximum number of divisions to return per page.

sort
string
Enum: "id" "name" "-id" "-name"

Changes the sort field between database ID and name.

If you prefix id or name with a minus sign (ASCII 45), the sort order is reversed.

There are two very strong reasons to sort by ID:

  1. Sorting by name carries a risk of missing or duplicating objects if your result set spans multiple pages and another operator is editing the database while your REST client is enumerating them. This is known as "page drift." Sorting by ID does not carry that risk.
  2. Following a next link is dramatically quicker when sorting by ID.

We strongly recommend sorting by ID. In case you were still in doubt, we will do that by default in a future version of Command Centre.

The server silently ignores anything except the options listed here.

fields
string
Enum: "href" "id" "name" "parent" "visitorManagement"

Return these fields instead of the default set. The values you can list are the same as the field names you would see in the results, plus visitorManagement, which does not come out by default. Use it to specify the fields you want in your results. Separate values with commas.

Treat the string matches as case-sensitive.

Responses

Response samples

Content type
application/json
{}

Get details of a division

Details of a division. Follow the href in a division summary to get here.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
fields
string
Enum: "href" "id" "name" "parent" "visitorManagement"

Return these fields instead of the default set. The values you can list are the same as the field names you would see in the results, plus visitorManagement, which does not come out by default. Use it to specify the fields you want in your results. Separate values with commas.

Treat the string matches as case-sensitive.

Responses

Response samples

Content type
application/json
{}

Remove a division

This call removes a division from Command Centre.

Deleting divisions will be possible in a future version of Command Centre.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

Responses

Update a division

This is the call you use to update a division's name, description, notes, or parent.

The PATCH expects a document in the same format as the the division detail but with fewer valid fields. An example is this PATCH example.

New to 9.30.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

Request Body schema: application/json
required

There are no mandatory fields, but it would not be much of an update without one.

name
string

The division's name. If you supply a name and another division already exists with that name, the call will fail. If you leave it blank in a POST, Command Centre will pick value for you.

description
string

The division's description.

notes
string

A string, able to be much longer than description, suitable for holding notes about the division.

object

An object containing an href to the division entity representing the current division's parent.

Required when creating a new division, because only root divisions can be unparented and you cannot create a new one of those.

Responses

Request samples

Content type
application/json
{}

Doors

These methods give you read access to basic data about Doors in the Command Centre database, and let you open them.

The first use case below introduces the main entry point. It is a paginated search interface that gives you any number of doors, each containing the fields you ask for in the query (including, for example, the URLs to open them).

Half-cycle doors and the lock override

Doors with half-cycle locks differ from regular doors in that once unlocked with an 'open' override or a card badge, they stay unlocked until physically opened then closed, or re-locked with a 'lock' override (added in 9.40). These doors normally require a physical key to open in addition to the electronic unlock. They are popular in correctional facilities.

Door status flags

If the door is online, its statusFlags field will contain one or more of these flags:

  • forced means the door was opened or unlocked while secure.
  • openTooLong means the door has been open for longer than its configured DOTL time.
  • tamper means one of the door's inputs is in a tampered state. The usual cause of that is a resistance moving outside nominal range, meaning the input has been cut or shorted.
  • open means the door has a sensor for detecting its openness and it is reporting as such.
  • closed is the inverse. The door is closed or has no open sensor.
  • locked means the door locked. It reflects the state of the door's unlock sensor, if it has one. Otherwise it reflects the state of the door's unlock output, if it has that. Without an unlock output, a door is not capable of access control.
  • unlocked means 'locked' is not set.
  • secure means the door's normal state is closed and locked.
  • free is the opposite of 'secure': nobody needs to badge to open it.

secure and free do not change when the door opens. They are about whether the door is enforcing access control, not about the current state of the door hardware.

When allowing passage, a door normally moves from closed and locked to closed and unlocked, to open and unlocked (extremely briefly), then to open and locked while someone is walking through it, then back to closed and locked. It will be secure throughout.

Door flag rules

  • If and only if the door is online, exactly one of 'closed' or 'open' will appear, and one of 'locked' or 'unlocked', and one of 'secure' or 'free'.

So, to establish if the door is in a normal state, look for 'closed' or 'open'. If neither is present, your door is in an error state.

Use cases

Listing Doors

  1. GET /api.
  2. Follow the link at features.doors.doors.href, appending a search term such as name=substring to filter the selection if you have a lot of doors, and fields to tell the server what to return about each. The next section covers those query parameters.
  3. Process the results, following the next link until there isn't one.

Opening a Door

  1. Find the href for the door using the process above.
  2. GET it.
  3. POST to the open URL in the commands structure of the results.

Finding a door's status

  1. Find the href for the door using the process above, and GET it.
  2. Follow the updates href from that page.
  3. Use the flag rules above to interpret the status flags you receive.
  4. Follow the next link to stay up to date.

Search doors

This returns a summary of the doors matching your search criteria.

The result will contain no more than 100 or 1000 doors (depending on your version), or as many as you asked for more in your request; you should follow the next link, if it is present, to collect the next batch.

If your result set is empty it means your operator does not have the privilege to view any doors, such as 'View Site', 'Edit Site', or 'Override - Open Door'. Perhaps there are no doors in the divisions in which your operator has privileges, or your operator has no privileges at all.

When you have loaded them all there will be no next link.

Do not code this URL into your application. Take it from the 'href' field in the features.doors.doors section of /api.

Authorizations:
API_keybasic
query Parameters
sort
string
Enum: "id" "name" "-id" "-name"

Changes the sort field between database ID and name.

If you prefix id or name with a minus sign (ASCII 45), the sort order is reversed.

There are two very strong reasons to sort by ID:

  1. Sorting by name carries a risk of missing or duplicating objects if your result set spans multiple pages and another operator is editing the database while your REST client is enumerating them. This is known as "page drift." Sorting by ID does not carry that risk.
  2. Following a next link is dramatically quicker when sorting by ID.

We strongly recommend sorting by ID. In case you were still in doubt, we will do that by default in a future version of Command Centre.

The server silently ignores anything except the options listed here.

top
integer >= 1

Limits the results to no more than this many items per page.

Older versions of Command Centre returned 100 items per page in the absence of this parameter. That is acceptable for GUI applications that will only display the first page, but for integrations that intend to proceed through the entire database it causes a lot of chatter.

8.70 and later versions will default to 1000 items per request. This is about where a graph of throughput versus page size begins to level out.

name
string

Limits the returned items to those with a name that matches this string. Without surrounding quotes or a percent sign or underscore, it is a substring match; surround the parameter with double quotes "..." for an exact match. Without quotes, a percent sign % will match any substring and an underscore will match any single character.

The search is always case-insensitive. Results are undefined if you do a substring search for the empty string (name=). You will receive no items if you search for those with no name (name=""), as all items must have a name.

Search parameters are ANDed together.

division
Array of strings

Limits the returned items to those that are in these divisions.

That includes all the items in those divisions' child divisions, because Command Centre treats items as though they are also in their division's parent, and its parent, and so on up to the root division.

Separate the IDs of the divisions you are interested with commas. Item IDs are short alphanumeric strings, not URLs.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

directDivision
Array of strings

Restricts items to those whose division is in this list.

Unlike division=, it does not follow ancestry. That means it will limit the search to items that are directly assigned to the divisions you list, whereas division (without the direct) will also include items that are assigned to their descendants.

List the IDs of the divisions you are interested in separated by commas. Item IDs are short alphanumeric strings, not URLs.

Because this is the first query parameter we added that contains a capital letter, this will be the first time you have had to think about case sensitivity. directDivision works, directdivision does not.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

Added in 9.20.

description
string

Limits the returned items to those with a description that matches this string. By default it is a substring match; surround it with double quotes "..." for an exact match. A _ will match any single character, and a % will match any substring. With or without quotes, having either of these wildcards in the string will anchor it at both ends as though you had surrounded it with ".

The search is always case-insensitive. Results are undefined if you search for the empty string (description= or description="").

Search parameters are ANDed together.

fields
string
Enum: "href" "id" "name" "shortName" "description" "division" "commands" "connectedController" "entryAccessZone" "exitAccessZone" "statusFlags" "statusText" "status" "notes" "updates" "defaults"

This instructs the server to return only these fields in the search results. The values you can list are the same as the field names in the details page. Using this you can return everything on the summary page that you would find on the details page. Separate values with commas.

Use the special value defaults to return the fields you would have received had you not given the parameter at all. Obviously only do that if you have more to add.

Treat the string matches as case-sensitive.

In v8.00 you will receive the href and internal ID even if you did not ask for them. In 8.10 and later you will only get what you asked for. If you are going to send the fields parameter and need the href or ID, be explicit.

pos
integer

Reserved for internal use. You may see it in URLs you receive from the server, but you must never add it yourself.

skip
integer

Reserved for internal use. Do not add it to your queries.

Responses

Response samples

Content type
application/json
{}

Get details of a door

This returns the detail of one door.

Follow the 'href' field in a door summary to get here.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
fields
string
Enum: "href" "id" "name" "shortName" "description" "division" "commands" "connectedController" "entryAccessZone" "exitAccessZone" "statusFlags" "statusText" "status" "notes" "updates" "defaults"

This instructs the server to return only these fields in the details page instead of the default set. The values you can list are the same as the field names you would see in the results. Use it to cut back on the size of the response. Separate values with commas.

Treat the string matches as case-sensitive.

In v8.00 you will receive the href and internal ID even if you did not ask for them. In 8.10 and later you will only get what you asked for. If you are going to send the fields parameter and need the href or ID, be explicit.

Responses

Response samples

Content type
application/json
{}

Lock a door

Sends an override to lock a half-cycle door that is in the unlocked state, rather than letting it wait to open and close.

Follow the commands.lock.href field in a door to get here.

Added in 9.40.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Responses

Open a door

Sends an override to unlock a door.

Follow the commands.open.href field in a door to get here.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Responses

Monitor a door

See the item status topic for how to use the updates APIs.

Note that this API call is good for watching one item only; if you want to monitor several, you are better off with a status subscription.

Follow the 'updates' field in a door summary or details pages to get here.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
fields
string
Enum: "status" "statusText" "statusFlags"

This instructs the server to return these fields in the update, instead of the default set. You will not hear about updates to fields you do not list.

Responses

Response samples

Content type
application/json
{}

Elevator Groups

These methods give you read access to Elevator Groups.

The reason you would want that is to allocate default floors to cardholders. Each cardholder can have one default floor per elevator group, so that when they badge into that group's lobby area the elevator system can arrange a car to take them to their favourite floor.

Each elevator group only goes to certain floors, so to give a cardholder a default floor you need to see which floors each elevator group services.

Command Centre represents floors with access zones. If an elevator car has two doors, front and rear, it may service two access zones on the same physical floor. A cardholder could pick either of those access zones as their default for that elevator group.

The main entry point is a paginated search that returns what you need to pick default floors for a cardholder, limited by the privilege that enables that operation on a cardholder. That is the call that you are most likely to need, but there is another that gives you all elevator groups that your operator can view, rather than the smaller set of groups your operator can use in a cardholder edit.

Use cases

Choosing and setting a cardholder's default floor

Your client will first need to list all elevator groups, and the floors and access zones on those elevator groups, so that it can pick from them (if knows them by name already) or present a list and allow a user to pick one if it is interactive.

Then it will need to send a PATCH back to the cardholder to set his or her default floor for an elevator group.

Listing elevator groups and their access zones

  1. GET /api.
  2. Follow the link at features.cardholders.modifyPassengerDetails.href, appending a search term such as name=substring to filter the selection if you have a lot of elevator groups.
  3. Find the elevator group you are after, following the next link if you have lots.
  4. Look in the floorAccess array for the floor names and access zone names you can use for picking the floor, and the access zone hrefs to use in the PATCH coming up.

Setting a cardholder's default floor

  1. Find the href for the cardholder.

  2. PATCH it with a request body containing the hrefs of the elevator groups and access zones you wish to set as that cardholder's defaults.

Search assignable elevator groups

This searches the elevator groups that your privileges allow you to use in cardholders' default floor and passenger type assignments, returning everything you need to make those assignments.

The result will contain no more than 100 or 1000 depending on your version, or as many as you asked for more in your request; you should follow the next link, if it is present, to collect the next batch.

If your result set is empty it means your operator does not have the privilege to assign elevator groups to cardholders ('Modify Passenger Details'). Perhaps there are no elevator groups in the divisions in which your operator has that privilege.

When you have loaded them all there will be no next link.

Do not code this URL into your application. Take it from the href field in the features.cardholders.modifyDefaultFloors section of /api.

It requires the RESTCardholders licence.

Authorizations:
API_keybasic
query Parameters
sort
string
Enum: "id" "name" "-id" "-name"

Changes the sort field between database ID and name.

If you prefix id or name with a minus sign (ASCII 45), the sort order is reversed.

There are two very strong reasons to sort by ID:

  1. Sorting by name carries a risk of missing or duplicating objects if your result set spans multiple pages and another operator is editing the database while your REST client is enumerating them. This is known as "page drift." Sorting by ID does not carry that risk.
  2. Following a next link is dramatically quicker when sorting by ID.

We strongly recommend sorting by ID. In case you were still in doubt, we will do that by default in a future version of Command Centre.

The server silently ignores anything except the options listed here.

top
integer >= 1

Limits the results to no more than this many items per page.

Older versions of Command Centre returned 100 items per page in the absence of this parameter. That is acceptable for GUI applications that will only display the first page, but for integrations that intend to proceed through the entire database it causes a lot of chatter.

8.70 and later versions will default to 1000 items per request. This is about where a graph of throughput versus page size begins to level out.

name
string

Limits the returned items to those with a name that matches this string. Without surrounding quotes or a percent sign or underscore, it is a substring match; surround the parameter with double quotes "..." for an exact match. Without quotes, a percent sign % will match any substring and an underscore will match any single character.

The search is always case-insensitive. Results are undefined if you do a substring search for the empty string (name=). You will receive no items if you search for those with no name (name=""), as all items must have a name.

Search parameters are ANDed together.

division
Array of strings

Limits the returned items to those that are in these divisions.

That includes all the items in those divisions' child divisions, because Command Centre treats items as though they are also in their division's parent, and its parent, and so on up to the root division.

Separate the IDs of the divisions you are interested with commas. Item IDs are short alphanumeric strings, not URLs.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

directDivision
Array of strings

Restricts items to those whose division is in this list.

Unlike division=, it does not follow ancestry. That means it will limit the search to items that are directly assigned to the divisions you list, whereas division (without the direct) will also include items that are assigned to their descendants.

List the IDs of the divisions you are interested in separated by commas. Item IDs are short alphanumeric strings, not URLs.

Because this is the first query parameter we added that contains a capital letter, this will be the first time you have had to think about case sensitivity. directDivision works, directdivision does not.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

Added in 9.20.

description
string

Limits the returned items to those with a description that matches this string. By default it is a substring match; surround it with double quotes "..." for an exact match. A _ will match any single character, and a % will match any substring. With or without quotes, having either of these wildcards in the string will anchor it at both ends as though you had surrounded it with ".

The search is always case-insensitive. Results are undefined if you search for the empty string (description= or description="").

Search parameters are ANDed together.

fields
string
Enum: "href" "name" "description" "division" "floorAccess" "defaults"

This instructs the server to return only these fields in the search results. The values you can list are the same as the field names in the details page. Using this you can return everything on the summary page that you would find on the details page. Separate values with commas.

Use the special value defaults to return the fields you would have received had you not given the parameter at all. Obviously only do that if you have more to add.

Treat the string matches as case-sensitive.

In v8.00 you will receive the href and internal ID even if you did not ask for them. In 8.10 and later you will only get what you asked for. If you are going to send the fields parameter and need the href or ID, be explicit.

pos
integer

Reserved for internal use. You may see it in URLs you receive from the server, but you must never add it yourself.

skip
integer

Reserved for internal use. Do not add it to your queries.

Responses

Response samples

Content type
application/json
{}

Search elevator groups

This returns the name and href of the elevator groups matching your search criteria. This uses a different privilege from the modify_default_floors call, so it may not return you the groups you need. If your goal is to set cardholders' default floors, you should that call instead.

The result will contain no more than 100 or 1000 (depending on your version), or as many as you asked for more in your request; you should follow the next link, if it is present, to collect the next batch.

If your result set is empty it means your operator does not have the privilege to view any elevator groups, such as 'View Site' or 'Edit Site'. Perhaps there are no elevator groups in the divisions in which your operator has privileges, or your operator has no privileges at all.

When you have loaded them all there will be no next link.

Do not code this URL into your application. Take it from the href field in the features.elevators.elevatorGroups section of /api.

Authorizations:
API_keybasic
query Parameters
sort
string
Enum: "id" "name" "-id" "-name"

Changes the sort field between database ID and name.

If you prefix id or name with a minus sign (ASCII 45), the sort order is reversed.

There are two very strong reasons to sort by ID:

  1. Sorting by name carries a risk of missing or duplicating objects if your result set spans multiple pages and another operator is editing the database while your REST client is enumerating them. This is known as "page drift." Sorting by ID does not carry that risk.
  2. Following a next link is dramatically quicker when sorting by ID.

We strongly recommend sorting by ID. In case you were still in doubt, we will do that by default in a future version of Command Centre.

The server silently ignores anything except the options listed here.

top
integer >= 1

Limits the results to no more than this many items per page.

Older versions of Command Centre returned 100 items per page in the absence of this parameter. That is acceptable for GUI applications that will only display the first page, but for integrations that intend to proceed through the entire database it causes a lot of chatter.

8.70 and later versions will default to 1000 items per request. This is about where a graph of throughput versus page size begins to level out.

name
string

Limits the returned items to those with a name that matches this string. Without surrounding quotes or a percent sign or underscore, it is a substring match; surround the parameter with double quotes "..." for an exact match. Without quotes, a percent sign % will match any substring and an underscore will match any single character.

The search is always case-insensitive. Results are undefined if you do a substring search for the empty string (name=). You will receive no items if you search for those with no name (name=""), as all items must have a name.

Search parameters are ANDed together.

division
Array of strings

Limits the returned items to those that are in these divisions.

That includes all the items in those divisions' child divisions, because Command Centre treats items as though they are also in their division's parent, and its parent, and so on up to the root division.

Separate the IDs of the divisions you are interested with commas. Item IDs are short alphanumeric strings, not URLs.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

directDivision
Array of strings

Restricts items to those whose division is in this list.

Unlike division=, it does not follow ancestry. That means it will limit the search to items that are directly assigned to the divisions you list, whereas division (without the direct) will also include items that are assigned to their descendants.

List the IDs of the divisions you are interested in separated by commas. Item IDs are short alphanumeric strings, not URLs.

Because this is the first query parameter we added that contains a capital letter, this will be the first time you have had to think about case sensitivity. directDivision works, directdivision does not.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

Added in 9.20.

description
string

Limits the returned items to those with a description that matches this string. By default it is a substring match; surround it with double quotes "..." for an exact match. A _ will match any single character, and a % will match any substring. With or without quotes, having either of these wildcards in the string will anchor it at both ends as though you had surrounded it with ".

The search is always case-insensitive. Results are undefined if you search for the empty string (description= or description="").

Search parameters are ANDed together.

fields
string
Enum: "href" "name" "shortName" "description" "division" "notes" "elevatorSystem" "elevatorGroupNumber" "floorAccess" "rearAccessEnabled" "groundFloorNumber" "defaults"

This instructs the server to return only these fields in the search results. The values you can list are the same as the field names in the details page. Using this you can return everything on the summary page that you would find on the details page. Separate values with commas.

Use the special value defaults to return the fields you would have received had you not given the parameter at all. Obviously only do that if you have more to add.

Treat the string matches as case-sensitive.

In v8.00 you will receive the href and internal ID even if you did not ask for them. In 8.10 and later you will only get what you asked for. If you are going to send the fields parameter and need the href or ID, be explicit.

pos
integer

Reserved for internal use. You may see it in URLs you receive from the server, but you must never add it yourself.

skip
integer

Reserved for internal use. Do not add it to your queries.

Responses

Response samples

Content type
application/json
{}

Get details of an elevator group

This returns the detail of one elevator group.

If you are setting cardholders' default floors, you should be using the modify_default_floors call rather than this one.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
fields
string
Enum: "href" "name" "shortName" "description" "division" "notes" "elevatorSystem" "elevatorGroupNumber" "floorAccess" "rearAccessEnabled" "groundFloorNumber" "defaults"

This instructs the server to return only these fields in the details page instead of the default set. The values you can list are the same as the field names you would see in the results. Use it to cut back on the size of the response. Separate values with commas.

Treat the string matches as case-sensitive.

In v8.00 you will receive the href and internal ID even if you did not ask for them. In 8.10 and later you will only get what you asked for. If you are going to send the fields parameter and need the href or ID, be explicit.

Responses

Response samples

Content type
application/json
{
  • "name": "Main building lower floors",
  • "description": "Main building lobby elevator group.",
  • "notes": "Multi-line text...",
  • "shortName": "Short text",
  • "elevatorGroupNumber": 1,
  • "elevatorSystem": {
    },
  • "rearAccessEnabled": true,
  • "groundFloorNumber": 1
}

Events

Use the GET methods in this API for historical searches or to stay up to date with new events as they occur. Use the POST method (added in version 8.10) to create events of your own.

There are no PATCH actions on events, because they are immutable. If an event is also an alarm it carries some changeable state and a log of activity and comments, but the underlying event never changes.

The API only returns events that are still in Command Centre's database. It will not return events that have been removed, even if they are in an archive file.

Location events in 9.00

Command Centre has about 80 event types that occur when somebody authenticates at a device, usually by badging a card. Some of those event types also contain the access zones that the person started and finished in. Version 9.00 introduced some improvements that presented the cardholder and the two zones to API clients in a consistent way:

  • A new event type hasLocation that lets you filter for only those events that reveal a cardholder's location. If your server is 9.00 or better, use it in the type query parameter as you would normally use an integer event type: type=hasLocation. Gallagher will update this as new versions add more event types. Do not use it on 8.90 or earlier: those servers will reject it.

  • A new location block on events of those types that contains fields containing the cardholder and their location.

For more on using these new features, see the relevant use case below (search for 'location').

Event use cases

Downloading the entire event database

  1. GET /api
  2. Follow the link at features.events.events.href . You can add query parameters to alter the search. If you are running 8.70 or later and there is a danger that you might encounter a problem while processing a batch of events you should also use fields to get the next link for each event. Note that this is different from the next link you receive at the end of each result set.
  3. Process the events you receive in that call. If you asked for the next field, write the link for each event you successfully process to disk before attempting the next one. Then, if the worst happens, your client can read that link from disk and pick up where it left off.
  4. If there were results, follow the link at next.href and repeat.

If you then wish to stay up to date, switch to following the link at updates.href in the results. That call will block until more events arrive, or a minute passes (approximately).

Downloading the most recent events

  1. Get /api
  2. Take the link at features.events.events.href and append previous=true&top=20. Add the appropriate query separator ? or & first, depending on whether there is a query parameter in the URL already, and change the 20 as appropriate. The default is 1000, which is probably more than you want.
  3. Process the events you receive in that call.
  4. Follow the link at previous.href to get earlier events, or next.href or updates.href for later events. The last is a long poll, which means that if no events are ready when you make the call it will block until new events arrive.

Reporting on events over a period.

  1. GET /api
  2. Follow the link at features.events.events.href appending after=2017-01-01Z&before=2017-02-01Z or whatever timestamps are appropriate (after the correct query separator, ? or &).

Remember that some remote systems take their time sending events to Command Centre, so do not be too hasty running your reports. If you fire them off at the stroke of midnight, you may miss events that occurred before midnight but have not yet arrived at Command Centre.

Receiving new events as they occur, starting from now

  1. GET /api
  2. Follow the link at features.events.updates.href adding query parameters containing your search terms. The call will block until at least one matching event arrives at the server.
  3. Process the events you receive in that call. Often there is only one: the first that arrived after you made the call.
  4. Sleep to reduce load on the server.
  5. Loop, following the link at updates.href after processing each batch of events. It will return immediately if there are new events waiting, or it will block until new events arrive. Follow the advice in downloading the entire event database about keeping track of your position if you might encounter a problem writing events mid-batch. Note that that advises using the next field, but you will be using the updates field, which is the same thing in long-poll form.

Receiving new events as they occur, starting from now, with no long polls

  1. GET /api
  2. Follow the link at features.events.events.href and append previous=true&top=1. Add the appropriate query separator ? or & first, depending on whether there is a query parameter in the URL already. The call will return one event (which you can ignore) and a next link you'll need later.
  3. Sleep and loop, following the link at next.href after processing each batch of events. It will return immediately whether or not there are new events waiting. Follow the advice in downloading the entire event database about keeping track of your position if you might encounter a problem writing events mid-batch.

Receiving new events as they occur, starting in the past

  1. GET /api
  2. Follow the link at features.events.events.href appending the query parameter after=2021-05-08Z (or whatever timestamp is appropriate).
  3. Process the events you receive in that call.
  4. Sleep to reduce load on the server.
  5. Loop, following the link at updates.href after processing each batch of events. It will return immediately if there are new events waiting, or it will block until new events arrive. Follow the advice in downloading the entire event database about keeping track of your position if you might encounter a problem writing events mid-batch. Note that that advises using the next field, but you will be using the updates field, which is the same thing in long-poll form.
  1. GET /api

  2. Follow the link at features.items.items.href , adding name="your_cardholder_name"&type=1 to the query after the appropriate separator (? or &).

    The 'items' controller necessary for that step is available with the RESTEvents licence. If you also have the RESTCardholders licence you could use the link at features.cardholders.cardholders.href instead, adding a separator and name="your_cardholder_name".

    In either case, remove the quotes if you want a substring search and can handle more than one cardholder in the results.

  3. Extract the item ID of your cardholder or cardholders from that page, repeating as necessary for additional cardholders.

  4. Follow the link on the /api page at features.events.events.href appending the separator and cardholder=XX or cardholder=XX,YY,ZZ with the cardholders' IDs.

To further improve the efficiency of your search, filter by event types and a time range.

Searching for events that indicate location or movement

If your server is running 8.60 or earlier, use the search filter type=20001,20002,20003,20047,20107,15582,15583,15800,15808,42415. That is not a complete list of movement event types but it includes the popular ones.

If your server is running 8.70-8.90 inclusive, give your operator the 'View cardholder events' privilege instead of 'View events'. Then you can request all events, and the server will only send you movements because that is all your operator is permitted to see.

If your server is running 9.00 or later, the 'View cardholder events' privilege is still an excellent idea to limit your operator's vision but you can also use the search filter type=hasLocation&fields=location (with a leading ? or & of course, and more fields if you need them). That will limit the results to location events.

When using a server at version 9.00 or better:

  1. GET /api

  2. Get the URL of the head of the event queue by following the link at features.events.updates.href appending type=hasLocation&fields=location with the appropriate query separator ? or & depending on whether there is a query parameter in the URL already. The call will block until a new location event arrives.

  3. If this is your first time here you will have an array containing one event. If you looped up from a later step, the array may contain many more. In any case, process all the events in the results using the advice immediately below about interpreting the location block. Also follow the advice in downloading the entire event database about keeping track of your position if you might have to abort mid-batch. Note that that advises using the next field, but if you want long polls you will be using the updates field.

  4. Sleep for a short time to reduce load on the server.

  5. Follow the link at updates.href for a long poll that waits for new events to arrive, or follow next.href for a call that will return immediately even if there are no new events for you.

  6. Loop up to process the events you received.

Interpreting the location block:

  • If you are simply after a person's location and do not care how they arrived there, use the afterLocation block inside location. The canonicalTypeName field in there will tell you what kind of location it is (reception or access zone). The schema definition describes afterLocation in more detail.

  • If you are after movements, which happen when a door grants a person access or an operator moves them on a tag board or via the API, and happen to some types of visitors when their host moves, ignore all events except those that have a location.type of moved. Look at the afterLocation to see where they landed. There will also be a beforeLocation if the door had two zones configured on it, in case you're interested in where they came from. The canonicalTypeName field in both blocks will tell you what kinds of item they are.

  • If you are after denials, which happen when a person authenticates but fails the access check, look at the events that have a location.type of denied. Like 'moved'-type events, location.afterLocation will show where they ended up. The difference is that with 'denied'-type events, they started there too.

Each of those fields is covered in the schema definition.

Be aware that the events you receive are limited to those with a source item that is in a division in which your operator has a privilege that allows viewing events. In 9.00 those privileges are 'View Events' and 'View Cardholder Events', and of course 'Advanced User'. That makes this API unsuitable for handling emergencies such as evacuations if your operator's view is limited: if your operator does not have the privilege to view events generated by a particular door, this API will not tell you about movements through that door.

Searching for events coming from other items

Events such as 'access granted' and 'zone count maximum' come from doors and access zones. To search for them, follow the same process as the previous use case (getting cardholder events) but use the source filter parameter instead of cardholder. It will limit the results to just those events that came from the items you gave in the query. If you have the RESTStatus licence you can search for access zones, alarm zones, fence zones, macros, outputs, doors, and (in 8.10) inputs. If you do not, or if your source is not one of those types, use the items API with a suitable type filter.

You can also use the type parameter to limit the events to particular event types. By doing this you can (for example) subscribe to 'access granted' events from a collection of doors.

New in v8.70, you can also filter by relatedItem. Use this to find events related to item or items regardless of the type.

Creating a new event

  1. GET /api
  2. POST to the link at features.events.events.href

There are some rules around creating events, so you should first have a careful read of the POST documentation.

Listing all event types

  1. GET /api
  2. GET the link at features.events.eventGroups

That will return all event types in their groups.

Event 'updates' versus 'next'

This expands on the difference between the API endpoints at the ends of the long poll updates and short poll next links that you receive in event searches. It will make more sense after reading the operations' own sections (long poll, short poll).

The two API calls use the same filters and return the same payloads, including the same pagination links. They differ at two times:

  • On your first call, the short-polling 'events' route will return you the first events in the historical record that meet your search criteria but the long-polling 'updates' route will wait until new events arrive.

  • On the last call, when there are no events that meet your criteria that the server has not sent you already, 'events' will immediately return an empty result set but 'updates' will wait for more to arrive.

The short poll is appropriate when you do not wish to stay up-to-date. When you are extracting events from the past, and want to move on to other things as soon as you have them all. Generating reports, basically.

The long poll is appropriate when you will be continuing to make the call, probably forever, because you wish to stay current and to not miss any events.

You should only be using one of the two. Using both in the same integration may indicate a design issue.

Efficiency tips

  • Use search parameters to reduce the filtering burden on the server.

  • When downloading a significant number of events, leave top at 1000 or more, provided your client can handle results over a megabyte (events are around 1 KB each). Performance tests have shown that throughput decreases dramatically if top is too low.

  • If using 8.40 or later, use its field query parameter to cut back on the fields the server sends to you. Not only will it save bandwidth, but it will save the server looking up all those values and serialising them for you.

  • If you are using the updates link to keep up to date with events, sleep between calls for as long as your requirements allow. Doing that will improve the likelihood of your collecting more than one event when it is busy.
    For example, if Command Centre is generating ten events per second and you do not sleep between REST calls, you will be calling updates ten times per second for one event each time. However if you sleep for two seconds after each call you will receive 20 events at a time, saving CPU and I/O.

Event field specifiers

What you can do with the fields query parameter on an events method has improved through the versions, so explaining it is a topic in itself.

In 8.40 and later the values you can list are the same as the field names in the details page, plus the special value for a personal data field described below. You can pick whichever fields you want, including defaults, though we urge you to only list the fields you need. Anything you wrote for 8.30 or earlier will work in 8.40 as it did before.

In versions up to 8.30 you can only add fields to the event summary and details pages, not remove them. If you send the parameter it must start with fields=defaults. That gives you the default set. What you can add after that depends on the version of Command Centre you're calling.

In 8.10 and earlier the only field you can add is cardholder.pdf_XXXX, where XXXX is the ID of a PDF. Find that ID with a query to the PDFs controller. Don't forget a separating comma between it and defaults.

That will add a cardholder's PDF to the events that are related to them.

You can only pick one PDF. It will only appear on events that have a related cardholder, such as access events, because without a cardholder there is no PDF. The security model applies too, so it will only appear if your REST operator has the appropriate privileges on that cardholder and PDF.

In 8.20 and later you can also add details. Make sure you have a separating comma after defaults or cardholder.pdf_XXXX.

An event detail string can be kilobytes long so we left it optional. It is the only field in the details page that is not in the search results, by the way, so if you are running 8.20 or later you can add it to your search results and you will not need the details page.

Server version Valid fields parameter values
Older than 8.20 defaults,cardholder.pdf_XXXX
8.20 to 8.30 defaults,cardholder.pdf_XXXX
or
defaults,details
or
defaults,cardholder.pdf_XXXX,details
8.40 and later any

Per-event bookmarks

If you are running 8.70 or later and you put previous, next, or updates in the field list of an event search, the server will add those fields to each event. All server versions include links with those names at the end of results, but they are not useful if you crash out half way through processing a batch. The per-event links, only available in 8.70 and later and only on request, give you a place to pick up from without being re-sent the events you already processed.

Licensing

  • The GETs that collect alarms and events require the RESTEvents licence.

  • The POST that creates events requires RESTCreateEvents.

  • The GET to collect event types requires RESTEvents or RESTCreateEvents.

Versions

The body of this document clearly indicates when recent features arrived in the API so that readers with older versions of Command Centre know not to expect them.

Add an event

Use this method to create an event in Command Centre v8.10 or later.

Do not code this URL into your application. Take it from events.events.href in the results of GET /api.

Each field has particular rules and has its own effects on the event and subsequent reports, and misconfiguration (such as inadvertently causing a macro to run itself) can land you in real trouble, so have a good look at the documentation below and the example POST body.

Events are immutable: you cannot PATCH or DELETE them after you create them.

Usable event types

You must supply an event type. At the time of writing (9.50), CC ships with 30 event types you can use, each in its own event type group. The POST body schema definition linked above shows which event types you can use: they have 'external' in their name.

You can create 970 of your own event types using the External Event Type Configuration Utility, a separate Windows application that lets you create external event types and make them appear on items' Event Response and Alarm Instructions tabs in the Configuration Client. You will find the release note for that utility in the Documentation folder on the installation media.

1000 event types sounds like a lot, but be aware that you cannot delete event types, and the only thing you can modify on an existing event type is its name. Their event type group and item types are permanent once you save them from the utility. Please plan carefully, and take backups!

A note on event type groups

There is much confusion between event types and groups.

You do not specify a type group when creating a new event. You specify a type. The parts of Command Centre that work with the event later will look up what group the event type is in, principally to select an action plan to run, but you do not need to consider groups when creating the event.

Usable source items

Every event needs a source item. You can let the server pick one for you (it will use the REST Client item identified by your API key) or you can use any item that has an 'Event Response' tab in its Configuration Client window (which is most of them). Our existing integrations use items like doors, external system items, and cameras.

If you allow the server to default to your REST client item as the source, or if specify it yourself, your operator must have 'Create events and alarms' in at least one division for the call to succeed. Any division will do. Otherwise you'll receive a 403.

If you specify a source item to a server running 8.90 or later and that item is not your REST Client item, your operator must have the 'Create events and alarms' privilege in that item's division. In older versions it was enough for your operator to have that privilege in any division.

Cardholders cannot be event sources because they do not have an 'Event Response' tab, but...

Along with a source, you can link other items to the events you create. If you link a cardholder, for example, your events will show on an activity report generated for that cardholder. To link an item your operator must have a privilege that allows viewing it ('View cardholders' for cardholders or 'View site' for most other item types).

Action plans

An event can fire an action plan, which will

  • set the priority if the REST client did not set one in the body of the POST, and
  • run a macro on the server.

Macros are extremely powerful, and a thorough treatment requires more room than we have, so it is sufficient to say that you should not aim for a dramatic first test. A good first result is to turn on a virtual output made for the purpose. Just make sure that it will not trigger another macro because it is possible to create loops, causing havoc.

You do not pick an action plan to run when you POST your event. Command Centre does that in three steps:

  1. The server looks at the configuration of the source item in the Event Response tab of its property page in the Configuration Client. If there is an entry for the event type that is not "use default", Command Centre will fire that action plan and skip the next steps. In versions older than 8.30 the control is per event group, not per event.
  2. Since the server did not find an action plan on the item, it tries its alarm zone. Specifically, the Event Defaults tab of the alarm zone's property page in the Configuration Client. Again the control is per event group not per event type in older versions. If the event's action plan is not 'use default', the server fires that action plan and goes no further.
  3. Since the server did not find an action plan on the item or its alarm zone, it looks at the configuration in the Event Defaults tab of the server properties. There is always an action plan there, even if it does nothing more than set the priority of the event.

Once it has found the action plan to run, the server will assign the event its priority (if you did not specify a priority yourself) and run the macro if there is one, both from the 'Command Centre' tab of the action plan's property page in the Configuration Client. The server will not use the configuration from the other tabs.

It is not possible to submit an event with priority zero, but it is possible to submit an event with no priority, and have the action plan assign it priority zero. This will run the macro on the action plan then drop the event before it reaches the database.

Alarm instructions

Alarm instructions are marked-up text fields that Command Centre presents to security personnel when events occur. Picking an alarm instruction to use follows the same decision path as picking an action plan: Command Centre looks at the configuration of the source item first, and finding nothing there will turn to the source item's alarm zone, and finally to the server properties. If all three are unset the operator will not receive any special instructions.

So, what an operator sees when your event arrives on their board depends on the priority and the event source.

When events become alarms

After the server has established an event's priority, either from the body you POSTed or the action plan, it looks at the Event Priorities tab of the server properties. There is a slider there that sets the level above which an event becomes an alarm. By default it is set to two, meaning that any event with a priority of two or higher will appear as an alarm.

Authorizations:
API_keybasic
Request Body schema: application/json
required

You can specify many things on an event but the only mandatory field is the type. When you are developing, start with just that.

object
Deprecated

A new event must contain either this or (if your server is running 8.90 or later) eventType. Without one of them, the POST will fail.

The event type is mandatory because the server cannot assume a reasonable default, as it does for the other fields.

If you send both a type block and an eventType block to a server running 8.90 or later it will use eventType. Versions before 8.90 do not know about eventType so they use type.

required
object

A new event must contain either this or type. Without one of them, the POST will fail.

The event type is mandatory because the server cannot assume a reasonable default, as it does for the other fields.

If you send both a type block and an eventType block to a server running 8.90 or later it will use eventType. Versions before 8.90 do not know about eventType so they use type.

object

This block should contain the href of the item you wish to use as the source of your event. It can be any site item to which your operator has view access including all hardware, access zones, fence zones, doors, lockers, car parks, servers, external systems, and many other item types. If you do not supply one Command Centre will use the REST Client item identified by the API key in the Authorization header.

Cardholders cannot be event sources. To relate a cardholder to your event, use the cardholder block.

Make sure that your operator has the 'Create Events and Alarms' privilege on this item's division. 8.90 and later insist on it.

The API will use the source's division as the event's division.

priority
integer [ 1 .. 9 ]

It is not possible to submit an event with priority zero in the body, but if you submit an event with no priority it will use the one on the event type's action plan, which can be zero.

time
string <date-time>

Like all other fields in this POST apart from the type, this field is optional. If you send it, it must be in the format described here.

If you do not send this, the server will use the time that it received your request (its "now").

message
string

This is the first thing an operator will see when they look at this event. Some interactive clients do not give it a lot of room on screen so put the important parts of your message first. It has a limit of 1024 characters.

details
string

Command Centre will attach this string to event, as it does the message, but operators will have to look more closely at the event to see it. On the upside, it can be longer than the message: 2048 characters in 8.10.

object

If you wish to attach a cardholder to your event, link it here. Reports can show or filter by the cardholder.

object

If you wish to attach an operator to your event, link it here. Like the cardholder, reports can show or filter by the operator.

object

If you wish to attach an access zone to your event, link it here. Reports can filter by and show the entry access zone on events.

object

If you wish to attach an access group to your event, link it here.

Unlike cardholders, operators, and entry access zones, access groups do not appear in Command Centre activity reports. You can add a filter to restrict an activity report by access groups, but the group that allowed an event into the report will not appear in a column.

Like all the other items you link to your event it will, of course, appear when you GET the event from the API later.

object

If you wish to attach a locker bank to your event, link it here.

Like an event's access group, you can filter a Command Centre activity report to events that involve a locker bank, but the bank will not appear in the report itself.

If you link both a locker and a locker bank to an event, Command Centre does not require that the locker is in the locker bank, but you may find that downstream reporting software misbehaves when it is not.

object

If you wish to link a locker to your event, do it here. Like an event's access group and locker bank, you can filter a Command Centre activity report to events that involve a locker, but the locker will not appear in the report itself.

object

If you wish to link a door to your event for later extraction or a report filter, do it here.

Responses

Request samples

Content type
application/json

This is an example showing how you could create a new event.

See the POST for where to get the address of the endpoint, the rules around event types and items, and what happens to your event after you create it, and see the schema definition for a description of each field.

Only eventType is required for the API to accept the POST, but an event is not much without a source item and a message string, and it never hurts to add some details.

To make this example work on a server running 8.80 or earlier change eventType to type.

{}

Search events

This returns the next batch of events matching the supplied filters starting at the beginning of the database, or at the time specified by the after parameter.

For its correct use in various scenarios, see the use cases.

By default the result will contain no more than 1000 events; for efficient transfer of large numbers of events you should increase this with the top parameter in the request URL.

Each response will contain a next and an updates link. Following the next link will return the next batch of events, or an empty list if there are no more available. Following the updates link will also return immediately if more events are available, but if there are none, it becomes a long poll. It will will block until an event is available that matches the specified filters, or a timeout passes.

Do not code this URL into your application. Take it from events.events.href in the results of GET /api.

Authorizations:
API_keybasic
query Parameters
top
integer [ 1 .. 10000 ]
Default: 1000

Sets the maximum number of events to return per page.

after
string <date-time>

Restricts events to those that occurred at or after this time.

The server accepts extended ISO-8601 time stamp formats. There must be hyphen separators in the date and colons in the time, and a T separating the two.

For predictable results you should also add a timezone specifier. A Z means UTC and is recommended, but +hh, +hhmm, and +hh:mm also work. Note that you need to encode plus-signs as %2b in a URL.

If you omit the time, the server will assume midnight. If you omit just the seconds, the server will take it to the top of the minute, :00.

before
string <date-time>

Restricts events to those that occurred before this time. Events that occurred at this exact time (to the second) will not appear in the results. For example, to collect all events that occurred on 1 January 2017, use after=2017-01-01Z,before=2017-01-02Z. You will not receive any events from 2 January.

The after parameter (above) describes the time stamp formats that the server accepts.

source
Array of strings

Restricts events to those whose source item has this ID. Separate multiple IDs with commas. Use the items API to search Command Centre's items.

type
Array of strings
Examples:
  • type=42613 - Events raised when an Engage door is held open for too long.
  • type=15808,20107 - Events raised when a cardholder is allowed access without a softly-enforced competency.

Restricts events to those whose type is in this list. Separate multiple IDs with commas.

The results may include other event types if you also use the group parameter because the type and group fields are combined as an 'OR', not an 'AND'.

Use the event groups call to see all event types. The IDs you need for this query parameter are strings but look like small integers. That call shows the event types along with the groups they are in, so do not confuse event types with event groups. They are separated in the results of the API call, but as a general rule you can tell them apart by their integer value: event group IDs are in the hundreds, while most event type IDs are in the thousands.

In version 9.00 and later use the special value hasLocation to include all event types that can reveal a cardholder's location or access zone. In 9.00 it is a set of about 80 event types; it may be more in future versions. If you use hasLocation you probably also want to ask for the location block using the fields query parameter.

Do not send type=hasLocation to a server running 8.90 or earlier: it will reject it.

group
Array of strings

Restricts events to those with this event group ID. Separate multiple IDs with commas.

group is ORed with type. In fact it is shorthand for type= followed by the IDs of all the event types in the event type groups you list, and the search uses the union of the two lists.

Use the event groups call to see all event types and groups.

cardholder
string
Example: cardholder=325

Restricts events to those associated with the cardholder that has this Command Centre ID. Separate multiple IDs with commas.

division
Array of strings
Examples:
  • division=201,330 - Two non-root divisions.

Restricts events to those in these divisions or their descendants. Separate IDs with commas.

A more secure option for limiting your client's visibility is to set the operator's privileges so that it only has access to those divisions.

directDivision
string

Restricts events to those whose division is in this list. Unlike division=, it does not follow ancestry. The name directDivision is case-sensitive. Separate IDs with commas.

Example: division=2,101.

relatedItem
string

Restrict events to those associated with the item that has this Command Centre ID. Separate multiple IDs with commas.

Example: relatedItem=3,102

fields
string
Enum: "defaults" "details" "cardholder.pdf_*" "href" "id" "serverDisplayName" "time" "message" "occurrences" "priority" "alarm" "operator" "source" "group" "type" "eventType" "division" "cardholder" "entryAccessZone" "exitAccessZone" "door" "accessGroup" "card" "modifiedItem" "lastOccurrenceTime" "previous" "next" "updates" "location"

In 8.40 and later the values you can list are the same as the field names in the details page, plus a special field name for a personal data field, described next. You can pick whichever fields you want, including defaults though we urge you to avoid that and only ask for the fields you need.

You can request cardholder.pdf_XXXX where XXXX is the ID of a PDF, which you can discover with a query to the PDFs controller. That will add a cardholder's PDF to the events that are related to them.

You can only pick one personal data field. It will only appear on events that have a related cardholder, such as access events, because without a cardholder there is no personal data. The security model applies too, so it will only appear if your REST operator has the appropriate privileges on that cardholder and PDF.

previous
boolean
Default: false

Returns the newest events rather than the oldest. Without this option the API will return events starting from the epoch, but if you set it to true the server will return the most recent events, the last of which will be the latest to arrive at the server.

In both cases you can move backward and forward in arrival time with the 'next' and 'previous' links.

pos
integer >= 0

INTERNAL USE ONLY. This is how Command Centre tracks the events you have seen already. Do not set it yourself. Retain the 'next' or 'updates' link in your application instead.

Responses

Response samples

Content type
application/json
{}

Get new events (or wait)

Poll this link to receive new events that match the specified filters. If there are none ready, the call will block until one arrives or a deadline passes.

For its correct use in various scenarios, see the use cases. In particular, sleep between calls to reduce load on the server.

The way this call picks its initial set of events is different from /api/events:

  • If you follow the link at events.updates.href in the results of GET /api, it will block until at least one event arrives that meet your search criteria, then return them.

  • If you follow the updates link from the results of GET /api/events or GET /api/events/updates, the link will contain a bookmark parameter that causes the server to return the first events that arrived after that bookmark (and that meet your search criteria, of course). If there are none, it will block until some arrive that do.

The response will contain an updates link back to the same API call with a new bookmark that will cause it to return the next page of results.

Each response will also contain a next link that will take you to the non-blocking version of the call at /api/events. However if you are using this call you should not also be using the next link: applications typically use one or the other, not both.

However long you wait between calls, following a next or updates link will always return the first events that arrived after your previous call.

Do not code this URL into your application. Take it from events.updates.href in the results of GET /api, or from updates in the results of GET /api/events.

Authorizations:
API_keybasic
query Parameters
top
integer [ 1 .. 10000 ]

Sets the maximum number of events to return per page.

deadline
integer [ 1 .. 86400 ]

Sets the number of seconds to wait for an event, if none are ready when you make the call. If none arrive before this number of seconds pass the result set will be empty. If not specified, a default will apply.

after
string <date-time>

Removes events that occurred before this time from the result set. It must be an ISO-8601 date or date-time with a timezone.

It is unlikely you will add this parameter to GET /api/events/updates. However it is a very useful parameter to /api/events, and it will pass from there into the updates URL that that call returns. In that case it has no effect; you can leave it there.

This will not push the start time of the search into the past. As described above, the search will start at the time of the call or after the last event in a previous result set depending on the pos parameter. The after parameter reduces the results to those events that arrived after the start time of the search and occurred after the after timestamp. Note that an event's arrival time can be different from its occurrence time.

before
string <date-time>

Removes events that occurred at or after this time from the result set. It must be an ISO-8601 date or date-time string with a timezone.

If no events arrive with an occurrence time earlier than this parameter, the call will eventually time out.

It is unlikely you will want this parameter in a call to GET /api/events/updates. It puts an end-date on the search, which is a very odd thing to do on a call intended to keep the caller up to date with events as they arrive. If you find yourself using it, you may wish to reconsider your approach.

If you only wish to receive events up to a point in history, use the before parameter on /api/events, following its next block in a loop until you get an empty result. If you only wish to receive events up to a point in the future, use /api/events again but loop until you receive an event with a date beyond your stopping point.

source
Array of strings

Restricts events to those whose source item has this ID. Separate multiple IDs with commas. Use /api/items to search Command Centre's items.

type
Array of strings

Restricts events to those with this event type ID. Separate multiple IDs with commas.

Use the API to see all of Command Centre's event types and groups. Event types names and IDs rarely change, but the ID is the more stable of the two. Therefore it is probably safer to use that API for reference then hard-code the event type IDs you find there into your application.

group
Array of strings

Restricts events to those with this event group ID. Separate multiple IDs with commas.

The documentation for /api/events/groups advises when to filter for event groups instead of event types.

Like event types, hard-coding the ID into your application is probably stabler (and definitely simpler) than searching for it at runtime.

cardholder
string

Restricts events to those associated with the cardholder with this Command Centre ID. Separate multiple IDs with commas.

Example: cardholder=325

division
string

Restricts events to those in the division with this ID and its descendant divisions. Separate multiple IDs with commas.

Example: division=2,101

fields
string
Enum: "defaults" "details" "cardholder.pdf_*" "href" "id" "serverDisplayName" "time" "message" "occurrences" "priority" "alarm" "operator" "source" "group" "type" "eventType" "division" "cardholder" "entryAccessZone" "exitAccessZone" "door" "accessGroup" "card" "modifiedItem" "lastOccurrenceTime" "previous" "next" "updates" "location"

In 8.40 and later the values you can list are the same as the field names in the details page, plus a special field name for a personal data field, described next. You can pick whichever fields you want, including defaults though we urge you to avoid that and only ask for the fields you need.

You can request cardholder.pdf_XXXX where XXXX is the ID of a PDF, which you can discover with a query to the PDFs controller. That will add a cardholder's PDF to the events that are related to them.

You can only pick one personal data field. It will only appear on events that have a related cardholder, such as access events, because without a cardholder there is no personal data. The security model applies too, so it will only appear if your REST operator has the appropriate privileges on that cardholder and PDF.

pos
integer >= 0

INTERNAL USE ONLY. Retain the 'next' or 'updates' link in your application instead. This is how Command Centre tracks the events you have seen already. Do not set it yourself.

Responses

Response samples

Content type
application/json
{}

Get details of an event

Full details for an event. You could follow the href in the event summary to get here, but if you are running 8.20 or later you could just use the fields parameter to add the details field to the summary results for the same result.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
fields
string
Enum: "defaults" "details" "cardholder.pdf_*" "href" "id" "serverDisplayName" "time" "message" "occurrences" "priority" "alarm" "operator" "source" "group" "type" "eventType" "division" "cardholder" "entryAccessZone" "exitAccessZone" "door" "accessGroup" "card" "modifiedItem" "lastOccurrenceTime" "previous" "next" "updates" "location"

In 8.40 and later the values you can list are the same as the field names in the details page, plus a special field name for a personal data field, described next. You can pick whichever fields you want, including defaults though we urge you to avoid that and only ask for the fields you need.

You can request cardholder.pdf_XXXX where XXXX is the ID of a PDF, which you can discover with a query to the PDFs controller. That will add a cardholder's PDF to the events that are related to them.

You can only pick one personal data field. It will only appear on events that have a related cardholder, such as access events, because without a cardholder there is no personal data. The security model applies too, so it will only appear if your REST operator has the appropriate privileges on that cardholder and PDF.

Responses

Response samples

Content type
application/json
{}

List event types

Retrieves the list of event type groups and the event types within those groups. Useful for obtaining IDs to use in event filters. Command Centre ships with about 1000 event types divided into about 150 groups. Each event type is in one group.

A site may rename the 30 groups dedicated to external event types—that is, event types for the site's own use—and may create another 970 event types for them.

The results of this query vary with:

  • the server version,
  • extra Gallagher software installed on the site, and
  • changes to external event groups and types made by the customer.

Event type identifiers do not often change between Command Centre versions, but the types in each group do. Therefore if you choose to use groups in filters rather than types you may find that your filter catches more or fewer event types after a Command Centre upgrade. That may be desirable if, for example, you are intested in a class of event and you want to grow with CC as it grows new features. If you want to catch all 'access denied's, for example. We frequently add new varieties of 'access denied'. If you do not want that, use types rather than groups.

Do not code this URL into your application. Take it from events.eventGroups.href in the results of GET /api.

Authorizations:
API_keybasic

Responses

Response samples

Content type
application/json
{}

Fence Zones

These methods give you read access to Fence Zones in the Command Centre database, letting you monitor their status, turn them on and off, change their modes, and shunt them.

The first use case below introduces the main entry point. It is a paginated search interface that gives you any number of fence zones, each containing the fields you ask for in the query.

Fence Zone status flags

If the fence zone is online, its statusFlags field may contain one or more of these flags:

  • notPolled means the fence zone is shunted, which means intentionally ignored, and is essentially offline.
  • overridden means just that.
  • deterrentUnknown means the controller cannot determine the state of the fence zone. This happens when there is a cabling problem between the C6000 and the fence controller (energiser).
  • on means the fence zone is live, energised. Take care.
  • off means the fence zone is off.
  • lowFeel means the fence energiser is delivering enough voltage to detect disturbances. Depending on the fence zone's configuration, it may also be a deterrant.
  • highVoltage means the pulse is delivering a deterrant pulse.
  • hVPlusMode means the fence voltage has increased in response to a disturbance. After some time or an override it will leave this mode. See the description of HVPlus mode in the Configuration Client's online help.
  • serviceMode means a technician has manually forced service mode at the fence controller. This safety measure prevents a Command Centre operator in an operations room inadvertently energising a hardware technician out in the field.
  • voltageKnown means Command Centre has the current voltage for the zone, provided there has been at least one pulse from the energiser recently. This can only happen when the zone is on, obviously. The 'voltage' field will contain the voltage at the last pulse.
  • alert means the fence voltage is outside the alert range. Typically this means an electical problem.
  • warning means the fence voltage is between the alert and warning ranges. Typically this means it has grounded somewhere.
  • preArm means the zone is performing its pre-arm check.
  • lockedOut means the zone has been locked out at a keypad.
  • parentAlert means there is a problem with the fence controller.

The item status section describes the flags an item returns when it is not online.

Fence Zone flag rules

  • If and only if the fence zone is online, there will be exactly one of 'deterrentUnknown', 'on', or 'off'. That is your test for whether a fence zone is in error.
  • If 'on', there will be exactly one of 'lowFeel', 'highVoltage', or 'hVPlusMode'.
  • If 'off', there will be exactly one of 'lowFeel' or 'highVoltage'.
  • 'hVPlusMode' will only appear if the fence zone is on.
  • If there is 'alert' there will never be 'warning'.
  • None of the flags above will appear if the fence zone is offline and only 'notPolled' will appear if it is not polled.
  • The 'voltage' field only contains a valid value if you receive 'voltageKnown' and the energiser has pulsed at least once since the zone turned on.

Use cases

Searching for fence zones by name

  1. GET /api.
  2. Follow the link at features.fenceZones.fenceZones.href , appending a search term such as name=substring to filter the fence zones, and fields to tell the server what to return about each. The next section covers those query parameters.
  3. Process the results, following the next link until there isn't one.

Overriding a fence zone

  1. Find the href for the fence zone using the process above.
  2. GET it.
  3. Find the API URL you require in the commands structure of the results, such as off, highVoltage, or shunt, from the detail.
  4. POST to that URL. You do not need to send anything in the body of the POST.

Finding a fence zone's status

  1. Find the href for the fence zone using the process above, and GET it.
  2. Take the updates href from that page. If you are after the fence's voltage and are using version 8.00, append fields=defaults,voltage (after a ? or &). You do not need that for later versions as voltage became a default field in 8.10.
  3. GET it.
  4. Use the flag rules above to interpret the status flags you receive.
  5. Follow the next link to stay up to date.

Search fence zones

This returns a summary of the fence zones matching your search criteria.

The result will contain no more than 100 or 1000 fence zones (depending on your version), or as many as you asked for more in your request; you should follow the next link, if it is present, to collect the next batch.

If your result set is empty it means your operator does not have a privilege that allows viewing fence zones, such as 'View Site', 'Edit Site', or 'Maintenance Override'. Perhaps there are no fence zones in the divisions in which your operator has privileges, or your operator has no privileges at all.

When you have loaded them all there will be no next link.

Do not code this URL into your application. Take it from the 'href' field in the features.fenceZones.fenceZones section of /api.

Authorizations:
API_keybasic
query Parameters
sort
string
Enum: "id" "name" "-id" "-name"

Changes the sort field between database ID and name.

If you prefix id or name with a minus sign (ASCII 45), the sort order is reversed.

There are two very strong reasons to sort by ID:

  1. Sorting by name carries a risk of missing or duplicating objects if your result set spans multiple pages and another operator is editing the database while your REST client is enumerating them. This is known as "page drift." Sorting by ID does not carry that risk.
  2. Following a next link is dramatically quicker when sorting by ID.

We strongly recommend sorting by ID. In case you were still in doubt, we will do that by default in a future version of Command Centre.

The server silently ignores anything except the options listed here.

top
integer >= 1

Limits the results to no more than this many items per page.

Older versions of Command Centre returned 100 items per page in the absence of this parameter. That is acceptable for GUI applications that will only display the first page, but for integrations that intend to proceed through the entire database it causes a lot of chatter.

8.70 and later versions will default to 1000 items per request. This is about where a graph of throughput versus page size begins to level out.

name
string

Limits the returned items to those with a name that matches this string. Without surrounding quotes or a percent sign or underscore, it is a substring match; surround the parameter with double quotes "..." for an exact match. Without quotes, a percent sign % will match any substring and an underscore will match any single character.

The search is always case-insensitive. Results are undefined if you do a substring search for the empty string (name=). You will receive no items if you search for those with no name (name=""), as all items must have a name.

Search parameters are ANDed together.

division
Array of strings

Limits the returned items to those that are in these divisions.

That includes all the items in those divisions' child divisions, because Command Centre treats items as though they are also in their division's parent, and its parent, and so on up to the root division.

Separate the IDs of the divisions you are interested with commas. Item IDs are short alphanumeric strings, not URLs.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

directDivision
Array of strings

Restricts items to those whose division is in this list.

Unlike division=, it does not follow ancestry. That means it will limit the search to items that are directly assigned to the divisions you list, whereas division (without the direct) will also include items that are assigned to their descendants.

List the IDs of the divisions you are interested in separated by commas. Item IDs are short alphanumeric strings, not URLs.

Because this is the first query parameter we added that contains a capital letter, this will be the first time you have had to think about case sensitivity. directDivision works, directdivision does not.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

Added in 9.20.

description
string

Limits the returned items to those with a description that matches this string. By default it is a substring match; surround it with double quotes "..." for an exact match. A _ will match any single character, and a % will match any substring. With or without quotes, having either of these wildcards in the string will anchor it at both ends as though you had surrounded it with ".

The search is always case-insensitive. Results are undefined if you search for the empty string (description= or description="").

Search parameters are ANDed together.

fields
string
Enum: "href" "id" "name" "shortName" "description" "division" "commands" "connectedController" "voltage" "statusFlags" "statusText" "status" "notes" "updates" "defaults"

This instructs the server to return only these fields in the search results. The values you can list are the same as the field names in the details page. Using this you can return everything on the summary page that you would find on the details page. Separate values with commas.

Use the special value defaults to return the fields you would have received had you not given the parameter at all. Obviously only do that if you have more to add.

Treat the string matches as case-sensitive.

In v8.00 you will receive the href and internal ID even if you did not ask for them. In 8.10 and later you will only get what you asked for. If you are going to send the fields parameter and need the href or ID, be explicit.

pos
integer

Reserved for internal use. You may see it in URLs you receive from the server, but you must never add it yourself.

skip
integer

Reserved for internal use. Do not add it to your queries.

Responses

Response samples

Content type
application/json
{}

Get details of a fence zone

This returns the detail of one fence zone.

Follow the 'href' field in a fence zone summary to get here.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
fields
string
Enum: "href" "id" "name" "shortName" "description" "division" "commands" "connectedController" "voltage" "statusFlags" "statusText" "status" "notes" "updates" "defaults"

This instructs the server to return only these fields in the details page instead of the default set. The values you can list are the same as the field names you would see in the results. Use it to cut back on the size of the response. Separate values with commas.

Treat the string matches as case-sensitive.

In v8.00 you will receive the href and internal ID even if you did not ask for them. In 8.10 and later you will only get what you asked for. If you are going to send the fields parameter and need the href or ID, be explicit.

Responses

Response samples

Content type
application/json
{}

Turn on a fence zone

Sends an override to an alarm zone to turn it on until the next scheduled or manual change.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Responses

Turn off a fence zone

Sends an override to an alarm zone to turn it off until the next scheduled or manual change.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Responses

Shunt a fence zone

Sends an override to an alarm zone to shunt it, effectively preventing all communication with it.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Responses

Unshunt a fence zone

Sends an override to an alarm zone to unshunt it, re-enabling its communication.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Responses

Change to high voltage

Sends an override to an alarm zone to change it to high voltage mode until the next scheduled or manual change.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Responses

Change to low feel

Sends an override to an alarm zone to change it to 'low feel' mode until the next scheduled or manual change.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Responses

Cancel an override

Cancels an active override.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Responses

Monitor a fence zone

See the item status topic for how to use the updates APIs.

Note that this API call is good for watching one item only; if you want to monitor several, you are better off with a status subscription.

Follow the 'updates' field in a door summary or details pages to get here.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
fields
any
Enum: "status" "statusText" "statusFlags" "voltage"

This instructs the server to return these fields in the update, instead of the default set. You will not hear about updates to fields you do not list.

Responses

Response samples

Content type
application/json
{}

Inputs

These methods, introduced in v8.10, give you read and override access to Input items.

The first use case below introduces the main entry point. It is a paginated search interface that gives you any number of inputs, each containing the fields you ask for in the query. You can, for instance, ask for the URLs you need to shunt or isolate an input.

Input status flags

Even though the Configuration client lets you set your own state names for open, closed, tampered open, and tampered short, status flags will always use 'closed' or 'open', and possibly 'tamper'.

Two-state inputs cannot report a tamper, because it is impossible to detect. They can only be open or closed. Hence the name.

Three-state inputs can report a tamper, but only one of tampered open or tampered closed, depending on their end-of-line resistance settings.

Four-state inputs can report tampered open (an open circuit) or tampered closed (a short).

If the input is online, its statusFlags field may contain one or more of these flags:

  • closed means the input circuit is closed.

  • open means the input circuit is open.

  • tamper means the input circuit is shorted or open.

  • notPolled means the input is shunted, which means intentionally ignored, and is essentially offline.

  • isolated means the input state will not prevent arming an alarm zone.

Input flag rules

  • If and only if the input is online and not shunted ('notPolled' status flag), exactly one of 'closed' or 'open' will appear.

  • 'closed' or 'open' may still appear if the input is tampered.

So, to establish if the input is in a completely normal state, look for 'closed' or 'open', and make sure 'tamper' is not there. However bear in mind that inputs are often shunted for ordinary reasons.

Use cases

Listing Inputs

  1. GET /api.
  2. Follow the link at features.inputs.inputs.href, appending a search term such as name=substring to select the inputs, top if you expect lots of them, and fields to tell the server what to return about each. The next section covers those query parameters.
  3. Process the results, following the next link if there is one.

Overriding an Input

  1. Find the href for the input using the process above.
  2. GET it.
  3. Find the API URL for the override you need in the commands structure of the results.
  4. POST to that URL with an empty body.

Finding an input's status

  1. Find the href for the input using the process above, and GET it.
  2. Take the updates href from that page.
  3. GET it.
  4. Use the flag rules above to interpret the status flags you receive.
  5. Follow the next link to stay up to date.

Search inputs

This returns a summary of the inputs matching your search criteria.

The result will contain no more than 100 or 1000 inputs (depending on your version), or as many as you asked for more in your request; you should follow the next link, if it is present, to collect the next batch.

If your result set is empty it means your operator does not have the privilege to view any inputs, such as 'View Site', 'Edit Site', or 'Maintenance Override'. Perhaps there are no inputs in the divisions in which your operator has privileges, or your operator has no privileges at all.

When you have loaded them all there will be no next link.

Do not code this URL into your application. Take it from the 'href' field in the features.inputs.inputs section of /api.

Authorizations:
API_keybasic
query Parameters
sort
string
Enum: "id" "name" "-id" "-name"

Changes the sort field between database ID and name.

If you prefix id or name with a minus sign (ASCII 45), the sort order is reversed.

There are two very strong reasons to sort by ID:

  1. Sorting by name carries a risk of missing or duplicating objects if your result set spans multiple pages and another operator is editing the database while your REST client is enumerating them. This is known as "page drift." Sorting by ID does not carry that risk.
  2. Following a next link is dramatically quicker when sorting by ID.

We strongly recommend sorting by ID. In case you were still in doubt, we will do that by default in a future version of Command Centre.

The server silently ignores anything except the options listed here.

top
integer >= 1

Limits the results to no more than this many items per page.

Older versions of Command Centre returned 100 items per page in the absence of this parameter. That is acceptable for GUI applications that will only display the first page, but for integrations that intend to proceed through the entire database it causes a lot of chatter.

8.70 and later versions will default to 1000 items per request. This is about where a graph of throughput versus page size begins to level out.

name
string

Limits the returned items to those with a name that matches this string. Without surrounding quotes or a percent sign or underscore, it is a substring match; surround the parameter with double quotes "..." for an exact match. Without quotes, a percent sign % will match any substring and an underscore will match any single character.

The search is always case-insensitive. Results are undefined if you do a substring search for the empty string (name=). You will receive no items if you search for those with no name (name=""), as all items must have a name.

Search parameters are ANDed together.

division
Array of strings

Limits the returned items to those that are in these divisions.

That includes all the items in those divisions' child divisions, because Command Centre treats items as though they are also in their division's parent, and its parent, and so on up to the root division.

Separate the IDs of the divisions you are interested with commas. Item IDs are short alphanumeric strings, not URLs.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

directDivision
Array of strings

Restricts items to those whose division is in this list.

Unlike division=, it does not follow ancestry. That means it will limit the search to items that are directly assigned to the divisions you list, whereas division (without the direct) will also include items that are assigned to their descendants.

List the IDs of the divisions you are interested in separated by commas. Item IDs are short alphanumeric strings, not URLs.

Because this is the first query parameter we added that contains a capital letter, this will be the first time you have had to think about case sensitivity. directDivision works, directdivision does not.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

Added in 9.20.

description
string

Limits the returned items to those with a description that matches this string. By default it is a substring match; surround it with double quotes "..." for an exact match. A _ will match any single character, and a % will match any substring. With or without quotes, having either of these wildcards in the string will anchor it at both ends as though you had surrounded it with ".

The search is always case-insensitive. Results are undefined if you search for the empty string (description= or description="").

Search parameters are ANDed together.

fields
string
Enum: "href" "id" "name" "shortName" "description" "division" "commands" "connectedController" "statusFlags" "statusText" "status" "notes" "updates" "defaults"

This instructs the server to return only these fields in the search results. The values you can list are the same as the field names in the details page. Using this you can return everything on the summary page that you would find on the details page. Separate values with commas.

Use the special value defaults to return the fields you would have received had you not given the parameter at all. Obviously only do that if you have more to add.

Treat the string matches as case-sensitive.

pos
integer

Reserved for internal use. You may see it in URLs you receive from the server, but you must never add it yourself.

skip
integer

Reserved for internal use. Do not add it to your queries.

Responses

Response samples

Content type
application/json
{}

Get details of an input

This returns the detail of one input.

Follow the 'href' field in an input summary to get here.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
fields
string
Enum: "href" "id" "name" "shortName" "description" "division" "commands" "connectedController" "statusFlags" "statusText" "status" "notes" "updates" "defaults"

This instructs the server to return only these fields in the details page instead of the default set. The values you can list are the same as the field names you would see in the results. Use it to cut back on the size of the response. Separate values with commas.

Treat the string matches as case-sensitive.

Responses

Response samples

Content type
application/json
{}

Shunt an input

Sends an override to shunt an input, preventing all communication.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Responses

Unshunt an input

Sends an override to unshunt an input, re-enabling communication.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Responses

Isolate an input

Sends an override to isolate an input. An isolated input will not prevent an alarm zone from arming.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Responses

De-isolate an input

Sends an override to end the isolation of an input.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Responses

Monitor an input

See the item status topic for how to use the updates APIs.

Note that this API call is good for watching one item only; if you want to monitor several, you are better off with a status subscription.

Follow the 'updates' field in an input summary or details pages to get here.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
fields
string
Enum: "status" "statusText" "statusFlags"

This instructs the server to return these fields in the update, instead of the default set. You will not hear about updates to fields you do not list.

Responses

Response samples

Content type
application/json
{}

Interlock Groups

These methods, yet to be released, will give you read access to Interlock Group items.

API support for interlocks is still in development and may change in future versions.

The first use case below introduces the main entry point. It is a paginated search interface that gives you any number of interlock groups, each containing the fields you ask for in the query. You can, for instance, ask for the IDs you need to monitor their status.

Interlock Group status flags

If an interlock is not in an error state it will return one flag out of the following set:

  • secure means the interlock items are closed and the door/s will open to a badge. This is probably where an interlock group spends most of its time.

  • open means the interlock's doors will not open because at least one of the other items in the group already is. This is a normal state after someone gains access at an interlock door. It will last until the door closes.

  • overridden means the interlock group has received a disable override. Doors will open as normal.

  • forced means that the interlock rules have been breached. This could be because someone forced a door, or used an emergency release while another door was already open.

If an interlock is completely normal it will report 'secure' or 'open'.

Use cases

Listing Interlock Groups

  1. GET /api.
  2. Follow the link at features.interlockGroups.interlockGroups.href, appending a search term such as name=substring to select the interlocks, top if you expect lots of them, and fields to tell the server what to return about each. The next section covers those query parameters.
  3. Process the results, following the next link if there is one.

Finding the status of many items including an interlock group

  1. Find the IDs of all the items you're interested in, including the interlock group, by searching for them with a query parameter appended such as fields=name,id.
  2. Create a status subscription for those items.

Finding the status of an interlock group

  1. Find the href for the interlock using the process above, and GET it.
  2. Take the updates href from that page.
  3. GET it.
  4. Use the flag rules above to interpret the status flags you receive.
  5. Follow the next link to stay up to date.

Overriding an Interlock Group

  1. Find the href for the interlock using the process above.
  2. GET it.
  3. Find the API URL for the override you need (disable or re-enable) in the commands structure of the results.
  4. POST to that URL with an empty body.

Search interlock groups

Not yet available. API support for interlocks is still in development and may change in future versions.

This returns a summary of the interlock groups matching your search criteria.

The result will contain no more than 100 or 1000 interlock groups (depending on your version), or as many as you asked for more in your request; you should follow the next link, if it is present, to collect the next batch.

If your result set is empty it means your operator does not have a privilege that allows viewing interlock groups, such as 'View Site', 'Edit Site', or 'Maintenance Override'. Perhaps there are no interlock groups in the divisions in which your operator has privileges, or your operator has no privileges at all.

When you have loaded them all there will be no next link.

Do not code this URL into your application. Take it from the 'href' field in the features.interlockGroups.interlockGroups section of /api.

Authorizations:
API_keybasic
query Parameters
sort
string
Enum: "id" "name" "-id" "-name"

Changes the sort field between database ID and name.

If you prefix id or name with a minus sign (ASCII 45), the sort order is reversed.

There are two very strong reasons to sort by ID:

  1. Sorting by name carries a risk of missing or duplicating objects if your result set spans multiple pages and another operator is editing the database while your REST client is enumerating them. This is known as "page drift." Sorting by ID does not carry that risk.
  2. Following a next link is dramatically quicker when sorting by ID.

We strongly recommend sorting by ID. In case you were still in doubt, we will do that by default in a future version of Command Centre.

The server silently ignores anything except the options listed here.

top
integer >= 1

Limits the results to no more than this many items per page.

Older versions of Command Centre returned 100 items per page in the absence of this parameter. That is acceptable for GUI applications that will only display the first page, but for integrations that intend to proceed through the entire database it causes a lot of chatter.

8.70 and later versions will default to 1000 items per request. This is about where a graph of throughput versus page size begins to level out.

name
string

Limits the returned items to those with a name that matches this string. Without surrounding quotes or a percent sign or underscore, it is a substring match; surround the parameter with double quotes "..." for an exact match. Without quotes, a percent sign % will match any substring and an underscore will match any single character.

The search is always case-insensitive. Results are undefined if you do a substring search for the empty string (name=). You will receive no items if you search for those with no name (name=""), as all items must have a name.

Search parameters are ANDed together.

division
Array of strings

Limits the returned items to those that are in these divisions.

That includes all the items in those divisions' child divisions, because Command Centre treats items as though they are also in their division's parent, and its parent, and so on up to the root division.

Separate the IDs of the divisions you are interested with commas. Item IDs are short alphanumeric strings, not URLs.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

directDivision
Array of strings

Restricts items to those whose division is in this list.

Unlike division=, it does not follow ancestry. That means it will limit the search to items that are directly assigned to the divisions you list, whereas division (without the direct) will also include items that are assigned to their descendants.

List the IDs of the divisions you are interested in separated by commas. Item IDs are short alphanumeric strings, not URLs.

Because this is the first query parameter we added that contains a capital letter, this will be the first time you have had to think about case sensitivity. directDivision works, directdivision does not.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

Added in 9.20.

description
string

Limits the returned items to those with a description that matches this string. By default it is a substring match; surround it with double quotes "..." for an exact match. A _ will match any single character, and a % will match any substring. With or without quotes, having either of these wildcards in the string will anchor it at both ends as though you had surrounded it with ".

The search is always case-insensitive. Results are undefined if you search for the empty string (description= or description="").

Search parameters are ANDed together.

fields
Array of strings
Items Enum: "href" "id" "name" "shortName" "description" "division" "commands" "connectedController" "statusFlags" "statusText" "status" "notes" "updates" "defaults"

This instructs the server to return only these fields in the search results. The values you can list are the same as the field names in the details page. Using this you can return everything on the summary page that you would find on the details page. Separate values with commas.

Use the special value defaults to return the fields you would have received had you not given the parameter at all. Obviously only do that if you have more to add.

Treat the string matches as case-sensitive.

pos
integer

Reserved for internal use. You may see it in URLs you receive from the server, but you must never add it yourself.

skip
integer

Reserved for internal use. Do not add it to your queries.

Responses

Response samples

Content type
application/json
{}

Get details of an interlock group

Not yet available. API support for interlocks is still in development and may change in future versions.

This returns the detail of one interlock group.

Follow the 'href' field in an interlock group summary to get here.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
fields
Array of strings
Items Enum: "href" "id" "name" "shortName" "description" "division" "commands" "connectedController" "statusFlags" "statusText" "status" "notes" "updates" "defaults"

This instructs the server to return only these fields in the details page instead of the default set. The values you can list are the same as the field names you would see in the results. Use it to cut back on the size of the response. Separate values with commas.

Treat the string matches as case-sensitive.

Responses

Response samples

Content type
application/json
{}

Disable an interlock group.

Not yet available. API support for interlocks is still in development and may change in future versions.

Sends an override to disable an interlock group, allowing all doors to act independently.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Responses

Re-enable an interlock group.

Not yet available. API support for interlocks is still in development and may change in future versions.

Cancels the disabling override on an interlock group, causing the doors to return to interlocking behaviour.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Responses

Monitor an interlock group.

Not yet available. API support for interlocks is still in development and may change in future versions.

See the item status topic for how to use the updates APIs.

Note that this API call is good for watching one item only; if you want to monitor several, you are better off with a status subscription.

Follow the 'updates' field in an interlock group summary or details pages to get here.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
fields
string
Enum: "status" "statusText" "statusFlags"

This instructs the server to return these fields in the update, instead of the default set. You will not hear about updates to fields you do not list.

Responses

Response samples

Content type
application/json
{}

Items

These methods let you find items for your search filters and events, and monitor their states. They return all items, including those that this API does not yet support in depth, and items added by customisations. However because they do not have deep knowledge of item types they can only give you the most basic fields.

Searching for items

Use the search methods when you are building a filter for an event search or a status subscription and need the ID of an item or an item type, or when you are creating an event and need an href to use as the event source.

To find an item, pass a substring of its name to the link at features.items.items.href in the results of a call to /api. If you are sure of its name, place the name inside " quotes, and it will use a full string match. Both types of search are case-insensitive.

To limit the search to items of a particular type, first get the ID of the type you are after using the link at features.items.itemTypes.href in the results of GET /api. Add that ID as the type parameter to the call above. You can specify multiple item types if, for example, you are interested in all the different kinds of doors.

For example, if you were after a list of divisions, following the instructions above on the current versions of Command Centre would produce the URL /api/items?type=15.

Status subscriptions

The item-specific APIs monitor only one item at a time, and are therefore not suitable for watching large collections. If you have CC version 8.30 or later, you should use the status subscription methods instead. We have tested subscriptions of 1000 items without noticing undue strain on the server. While the calls do not impose an upper bound on that we suggest keeping a watchful eye on the performance of the overall system if you go much higher.

The basic operations for monitoring item states is:

  1. Get all the IDs of the items you wish to monitor. You can do that using this API's own search with a name, division, or type parameter. If you're searching by division you'll need a division ID which (slightly recursively) is best found by using the same search function filtering for just divisions. If you're searching by type you'll need a type ID.

  2. POST to create a subscription. Your program should get the URL from items.updates.href in the results of GET /api.

  3. Take the current state of your items from the results of that call. If that's all you need, terrific. But if you want to monitor their state, continue.

  4. GET the next.href link that came in the results. The call will block until one of your monitored items changes state. When it returns, the results will be in the same format as the result of the POST, including the next link.

  5. Goto 4.

Licensing

Every REST licence enables the items controller: RESTEvents, RESTCreateEvents, RESTCardholders, RESTStatus, and RESTOverrides.

Search items

This returns a batch of items matching the applied filters. By default, each page will contain up to 1000 items although this can be changed by setting the top parameter in the request URL.

You will only receive items for which the REST operator has the necessary privilege. To view PDFs, for example, the operator must have the 'View Personal Data Definitions' privilege.

If more items are available, the response will contain a next link. Following that will return the next batch of items.

Items will be in ID order unless you change it with sort.

Do not code this URL into your application. Take it from items.items.href in the results of GET /api.

Authorizations:
API_keybasic
query Parameters
name
string

Limits the returned items to those with a name that matches this string. Without surrounding quotes or a percent sign or underscore, it is a substring match; surround the parameter with double quotes "..." for an exact match. Without quotes, a percent sign % will match any substring and an underscore will match any single character.

The search is always case-insensitive. Results are undefined if you do a substring search for the empty string (name=). You will receive no items if you search for those with no name (name=""), as all items must have a name.

Search parameters are ANDed together.

division
Array of strings

Limits the returned items to those that are in these divisions.

That includes all the items in those divisions' child divisions, because Command Centre treats items as though they are also in their division's parent, and its parent, and so on up to the root division.

Separate the IDs of the divisions you are interested with commas. Item IDs are short alphanumeric strings, not URLs.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

directDivision
Array of strings

Restricts items to those whose division is in this list.

Unlike division=, it does not follow ancestry. That means it will limit the search to items that are directly assigned to the divisions you list, whereas division (without the direct) will also include items that are assigned to their descendants.

List the IDs of the divisions you are interested in separated by commas. Item IDs are short alphanumeric strings, not URLs.

Because this is the first query parameter we added that contains a capital letter, this will be the first time you have had to think about case sensitivity. directDivision works, directdivision does not.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

Added in 9.20.

type
string

Only returns items that are of a type with this ID. In versions up to 8.30 you could only specify one, but in 8.40 and later this can be a comma-separated list.

top
integer >= 1
Default: 100

Sets the maximum number of items to return per page.

sort
string
Enum: "id" "name" "-id" "-name"

Changes the sort field between database ID and name.

If you prefix id or name with a minus sign (ASCII 45), the sort order is reversed.

There are two very strong reasons to sort by ID:

  1. Sorting by name carries a risk of missing or duplicating objects if your result set spans multiple pages and another operator is editing the database while your REST client is enumerating them. This is known as "page drift." Sorting by ID does not carry that risk.
  2. Following a next link is dramatically quicker when sorting by ID.

We strongly recommend sorting by ID. In case you were still in doubt, we will do that by default in a future version of Command Centre.

The server silently ignores anything except the options listed here.

fields
string
Enum: "href" "id" "name" "type" "division" "serverDisplayName" "notes"

Return these fields in the search results. The values you can list are the same as the field names in the details page. Using it you can return everything on the summary page that you would find on the details page. Separate values with commas.

Use the special value defaults to return the fields you would have received had you not given the parameter at all. Obviously only do that if you have more to add.

The string must not contain any spaces. Just alphanumerics, underscores, commas, and dots.

Treat the string matches as case-sensitive.

Responses

Response samples

Content type
application/json
{
  • "results": [
    ],
}

Get details of an item

This returns some basic fields for one item. It returns the same information as the item search plus the item's division.

Added in 8.40.

Authorizations:
API_keybasic
path Parameters
id
required
string

The ID of the item.

query Parameters
fields
string
Enum: "href" "id" "name" "type" "division" "serverDisplayName" "notes"

Return these fields in the search results. The values you can list are the same as the field names in the details page. Using it you can return everything on the summary page that you would find on the details page. Separate values with commas.

Use the special value defaults to return the fields you would have received had you not given the parameter at all. Obviously only do that if you have more to add.

The string must not contain any spaces. Just alphanumerics, underscores, commas, and dots.

Treat the string matches as case-sensitive.

Responses

Response samples

Content type
application/json
{
  • "id": "325",
  • "name": "Brick, Eva",
  • "type": {
    },
  • "serverDisplayName": "ruatoria.satellite.int",
  • "notes": "Multi-line text...",
  • "href": "string",
  • "division": {}
}

List item types

Retrieves the list of all item types in the Command Centre system. There are about 200. This is useful for obtaining type IDs to use in item search filters and (in 9.00) the canonical item type names.

Note that some item types have a blank name. These types are vestigial: disregard them.

Do not code this URL into your application. Take it from items.itemTypes.href in the results of GET /api.

Authorizations:
API_keybasic

Responses

Response samples

Content type
application/json
{
  • "itemTypes": [
    ]
}

Retrieve status updates

Collects status updates from a subscription created using the /api/items/updates POST.

This is a long poll, so if there are no updates waiting when you make the call it will block until some arrive or a timeout passes (about 50 seconds).

If you receive a 404 from this call it means that more than 30 seconds passed between the server sending you the link and you GETting it, or the server restarted. In either case it will have dropped your subscription: you will need to create a new one with a fresh POST.

Therefore your loop can be:

  1. Create a subscription with a POST.
  2. Process the statuses in the results, if there are any.
  3. Wait a second or two to avoid tight loops.
  4. GET the link from the results. It may take up to a minute to respond.
  5. If 404, go to 1.
  6. Go to 2.

...plus the necessary exception handling, of course.

Added in 8.30.

Note that the first time you make this GET request it will return all the activity that came back from the POST. There are other cases where the GET might return no updates or updates you have seen already (when some aspect of an item changes that your operator does not have the privilege to view, or an override is sent, for example). While these two behaviours are not harmful they are also not particularly helpful, so future versions may differ.

Authorizations:
API_keybasic
query Parameters
bookmark
required
string

Identifies your subscription and your position in the change list. You should not to set this parameter: it will be in the link that the server sends back to you.

Responses

Response samples

Content type
application/json
{
  • "updates": [
    ],
}

Subscribe to status updates

Creates a subscription to status changes. You POST a list of item IDs and the server returns the status flags of those items plus a link. When you GET that link some time later the server will return the items that changed state between the two calls.

If you do not GET the link within thirty seconds of the POST returning, the server will drop your subscription and free up the resources it had allocated to servicing it. If that happens you will need to send this POST again to create a new subscription.

Your operator must have view privileges on every item in the subscription otherwise you will receive a 4xx.

The subscription notices changes in state, not in configuration, so an operator modifying an item will not cause anything to come out of this API unless the change in configuration also causes a change in state.

Because this call returns the status of items, this call requires the RESTStatus licence.

Added in 8.30. 9.30 corrected the 401 response to a 403.

Authorizations:
API_keybasic
Request Body schema: application/json
optional

The body of the POST needs to contain a list of item IDs in an array called itemIds. Even though they look like small integers, these IDs are actually strings so don't forget the quotes.

itemIds
required
Array of strings

Responses

Request samples

Content type
application/json
{
  • "itemIds": [
    ]
}

Response samples

Content type
application/json
{
  • "updates": [
    ],
}

REST Clients

This lets you operate on the REST Client item that represents your application in Command Centre. You can send a description of the state of your application and raise an alarm if it is in strife.

This is still in development and may change behaviour before release.

REST Client status flags

  • offline means the item is configured with a keepalive time and it has not seen an API request in that time.

  • faulty means the item has used the endpoint in this section to declare itself in trouble.

Because this feature is intended for REST integrations needing to indicate their status, this API is the only way to change a REST Client item's status fields. Humans using Gallagher's operational and configuration clients can see it but not change it.

BetaSet status

This allows an integration to add a string to the status text of the REST Client item that represents your application. That text is visible on a suitably-configured site plan or a Monitor Site viewer in Gallagher's operational client, or any other client that is watching items.

Your integration can also set a flag indicating that it is in a fault condition and requires attention. Doing that will raise an alarm, hopefully provoking a response from an operator. The alarm is stateful, restored only by your integration clearing the flag later when it is back in working order.

A client can change its own status, but it can change no other's, and no other client can change its.

Your client's operator does not need any privileges for this call.

Do not code this URL into your application. Take it from me.client.href in the results of GET /api.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

Request Body schema: application/json
required

The status text and fault condition of your API client.

Both fields are optional.

hasFault
boolean

If true, the server will change the status of this REST Client to include an indication that is has a fault, and will raise an active alarm to draw the operators' attention. Being active, operators will not be able to process that alarm until you restore it by passing false here.

customStatusText
string <= 1024 characters

The server will include the text you supply here whenever it generates status text for this item.

This text field works independently of the item's other states and its fault flag: you can use it purely for information.

The integrator is responsibile for any personally identifiable information sent to Command Centre via the API.

Responses

Request samples

Content type
application/json
{
  • "hasFault": false,
  • "customStatusText": "Disk 87% full"
}

Lockers

The locker bank API exists for two purposes: finding a locker to assign a cardholder to, and integrating with operational locker management software that expects a bank-centric view rather than the cardholder-centric view available in the cardholder API. So a locker bank's detail page shows all its cardholder assignments.

You cannot use the API to create or configure lockers or banks, or to see the hardware features of a locker such as readers, inputs, and outputs, nor the door-like settings on the bank such as the lock type and unlock time. The locker configuration tool exists for this purpose.

To change the cardholder assignments you should PATCH the cardholder's href, since it is the cardholder you are updating, not the locker. The locker bank API supplies the URL to PATCH.

Locker status flags

Regardless of whether a locker is online or not, its status may contain these:

  • quarantined means the locked cannot be allocated to a cardholder. It needs a clean, in other words.

  • allocated means it is allocated to a cardholder, so another cardholder cannot self-allocate it.

  • free means it is not allocated to a cardholder.

If the locker is online, its statusFlags field may contain one or more of these flags:

  • forced, openTooLong, tamper, closed, open, locked, unlocked, the same as a door.

Locker status flag rules

  • A locker can only be one of quarantined, allocated, or free.

  • Like a door, if and only if the locker is online, exactly one of the closed or open flags will be there and one of locked or unlocked.

Use cases

Displaying all banks and lockers, and the cardholders assigned to them

  1. GET /api
  2. Follow the link at features.lockerBanks.lockerBanks.href , adding a search term to the query to thin out the results.
  3. Follow the href of the locker bank you are after.

The results of that query are the locker bank detail.

Assigning a locker to a cardholder

  1. Find the href of the locker, as above. Normally one that does not have someone already allocated.

  2. Find the href of the cardholder using the cardholders API.

  3. PATCH the cardholder with the locker's href in a property called locker in an element of an array called lockers.add. Add from and until properties as you like.

Opening or quarantining a locker

Command Centre version 8.10.1112 lets you use the 'fields' parameter on the locker bank search to request the 'open' override URLs for lockers, which in prior versions was only available on their details pages. Version 9.10 adds the ability to quarantine lockers, which prevents anyone from allocating them to a cardholder.

  1. GET /api
  2. Follow the link at features.lockerBanks.lockerBanks.href , adding ? or & as appropriate then fields=name,lockers.name,lockers.shortName,lockers.commands. Also add a search term to thin out the results, if you have a lot of locker banks.
  3. Dig through the results for your locker bank, then through the lockers array of that locker bank for your locker, then into the commands block of that locker for another block called open or quarantine depending on your need. If your operator is able to override that locker, that block will contain a field called href which gives the URL you need to POST to override the locker (open, for example).

Search locker banks

This returns locker banks matching your search criteria.

The result will contain no more than 100 or 100 objects depending on your version; you should follow the next link, if it is present, to collect more.

If the result set is empty it means there are no locker banks in the divisions in which the operator has a privilege that allows listing them, such as 'View lockers and assignments'.

When you have loaded all the locker banks there will no next link.

Do not code this URL into your application. Take it from the 'href' field in the features.lockerBanks.lockerBanks section of /api.

Authorizations:
API_keybasic
query Parameters
sort
string
Enum: "id" "name" "-id" "-name"

Changes the sort field between database ID and name.

If you prefix id or name with a minus sign (ASCII 45), the sort order is reversed.

There are two very strong reasons to sort by ID:

  1. Sorting by name carries a risk of missing or duplicating objects if your result set spans multiple pages and another operator is editing the database while your REST client is enumerating them. This is known as "page drift." Sorting by ID does not carry that risk.
  2. Following a next link is dramatically quicker when sorting by ID.

We strongly recommend sorting by ID. In case you were still in doubt, we will do that by default in a future version of Command Centre.

The server silently ignores anything except the options listed here.

top
integer >= 1

Limits the results to no more than this many items per page.

Older versions of Command Centre returned 100 items per page in the absence of this parameter. That is acceptable for GUI applications that will only display the first page, but for integrations that intend to proceed through the entire database it causes a lot of chatter.

8.70 and later versions will default to 1000 items per request. This is about where a graph of throughput versus page size begins to level out.

name
string

Limits the returned items to those with a name that matches this string. Without surrounding quotes or a percent sign or underscore, it is a substring match; surround the parameter with double quotes "..." for an exact match. Without quotes, a percent sign % will match any substring and an underscore will match any single character.

The search is always case-insensitive. Results are undefined if you do a substring search for the empty string (name=). You will receive no items if you search for those with no name (name=""), as all items must have a name.

Search parameters are ANDed together.

division
Array of strings

Limits the returned items to those that are in these divisions.

That includes all the items in those divisions' child divisions, because Command Centre treats items as though they are also in their division's parent, and its parent, and so on up to the root division.

Separate the IDs of the divisions you are interested with commas. Item IDs are short alphanumeric strings, not URLs.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

directDivision
Array of strings

Restricts items to those whose division is in this list.

Unlike division=, it does not follow ancestry. That means it will limit the search to items that are directly assigned to the divisions you list, whereas division (without the direct) will also include items that are assigned to their descendants.

List the IDs of the divisions you are interested in separated by commas. Item IDs are short alphanumeric strings, not URLs.

Because this is the first query parameter we added that contains a capital letter, this will be the first time you have had to think about case sensitivity. directDivision works, directdivision does not.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

Added in 9.20.

description
string

Limits the returned items to those with a description that matches this string. By default it is a substring match; surround it with double quotes "..." for an exact match. A _ will match any single character, and a % will match any substring. With or without quotes, having either of these wildcards in the string will anchor it at both ends as though you had surrounded it with ".

The search is always case-insensitive. Results are undefined if you search for the empty string (description= or description="").

Search parameters are ANDed together.

fields
Array of strings
Default: "defaults"
Items Enum: "href" "id" "name" "shortName" "description" "division" "lockers" "notes" "lockers.defaults" "lockers.id" "lockers.href" "lockers.name" "lockers.shortName" "lockers.description" "lockers.division" "lockers.notes" "lockers.commands" "lockers.assignments" "defaults"

Sets which fields to return. The values you can list are the same as the field names in the details page. Using it you can return everything on the search page that you would find on the details page. Separate values with commas.

If you specify any value for this parameter, the default no longer applies and you will only receive the fields you asked for.

Use the special value defaults to return the locker bank fields you would have received had you not given the parameter at all. Then you can add a comma and more fields.

In v8.00 you will receive the href and internal ID even if you did not ask for them. In 8.10 you will not. If you are going to send the fields parameter and need the href or ID, be explicit.

All the field names beginning with lockers. arrived in v8.10.1112. They affect the fields that appear inside the 'lockers' block. The guideline for using defaults is: if you want to receive less data, specify only the fields you want. If you want to receive more, either list every field you want or simply use lockers.defaults plus your extras.

Treat the string matches as case sensitive.

pos
integer

Reserved for internal use. You may see it in URLs you receive from the server, but you must never add it yourself.

skip
integer

Reserved for internal use. Do not add it to your queries.

Responses

Response samples

Content type
application/json
{}

Get details of a locker bank

This returns details for a locker bank. In the interest of forward compatibility follow the href in the locker bank summary to get here rather than building the URL yourself.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
fields
Array of strings
Default: "defaults"
Items Enum: "href" "id" "name" "shortName" "description" "division" "notes" "connectedController" "lockers" "lockers.defaults" "lockers.connectedController" "..." "defaults"

Sets which fields to return. The values you can list are the same as the field names you would get in the details page. Use it to cut back on the size of the response for large locker banks. Separate values with commas.

Treat the string matches as case sensitive.

In v8.00 you will receive the href and internal ID even if you did not ask for them. In 8.10 you will not. If you are going to send the fields parameter and need the href or ID, be explicit.

Responses

Response samples

Content type
application/json
{}

Get details of a locker

This returns details for a locker. Follow the href in the locker bank summary or locker bank detail to get here rather than building the URL yourself.

Prior to v8.20 this endpoint was at /api/locker_banks/{locker_bank_id}/lockers/{id} .

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
fields
Array of strings
Default: "defaults"
Items Enum: "href" "id" "name" "shortName" "description" "division" "assignments" "notes" "commands" "connectedController" "defaults"

Sets which fields to return. Use it to cut back on the size of the response for a locker with many assignments. Separate values with commas.

Treat the string matches as case sensitive.

Responses

Response samples

Content type
application/json
{}

Open a locker

Sends an override to open a locker.

You should get this URL from a locker detail or locker bank detail rather than building it yourself.

New in 8.10.1112.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

Responses

Quarantine a locker

Sends an override to quarantine a locker. If the override succeeds, the locker will not be allocatable until its quarantine ends.

The call will fail if the locker is allocated to a cardholder.

You should get this URL from a locker detail or locker bank detail rather than building it yourself.

New in 9.10.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

Responses

Un-quarantine a locker

Sends an override to remove the quarantine from a locker, making it available for allocation.

You should get this URL from a locker detail or locker bank detail rather than building it yourself.

New in 9.10.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

Responses

Macros

These methods give you read access to basic data about the Macros in the Command Centre database, and let you run them.

Reading the section 'Understanding Macros' in the Configuration client help is an excellent way to do exactly that.

The first use case below introduces the main entry point. It is a paginated search interface that gives you any number of macros, each containing the fields you ask for in the query, including (for example) the URL you need to run the macro.

You cannot use the REST API to change a macro's schedule. You must use the Command Centre or Configuration client for that.

Overrides

You can use this API to run a macro. That is the only override they accept.

Macro status flags

Being very simple creatures macros normally bear no flags of status, but an experimental addition to version 9.30 adds the flag closed while a macro is running. If you have subscribed to status updates you will see this flag flash past, but if you simply ask for a macro's status on your own schedule you are very unlikely to strike it during the extremely brief time it is active.

This is a feature meant for Gallagher clients only. A future version may change the flag's name so we suggest avoiding it for now.

Macro flag rules

  • Do not rely on closed meaning that the macro is running.

Use cases

Listing Macros

  1. GET /api.
  2. Follow the link at features.macros.macros.href , appending a search term (described below) to narrow the results if your installation has a lot of macros.
  3. Process the results, following the next link until there isn't one.

Running a Macro

  1. Find the href for the macro using the process above.
  2. GET it.
  3. If your operator is able to run the macro, the results will contain a URL at commands.run.href. POST to that to run the macro. No body required.

Search macros

This returns a summary of the macros matching your search criteria.

The result will contain no more than 100 or 1000 macros (depending on your version), or as many as you asked for more in your request; you should follow the next link, if it is present, to collect the next batch.

If your result set is empty it means your operator does not have the privilege to view any macros, such as 'View Site', 'Run Macros', or 'Schedule and Run Macros'. Perhaps there are no macros in the divisions in which your operator has privileges, or your operator has no privileges at all.

When you have loaded them all there will be no next link.

Do not code this URL into your application. Take it from the 'href' field in the features.macros.macros section of /api.

Authorizations:
API_keybasic
query Parameters
sort
string
Enum: "id" "name" "-id" "-name"

Changes the sort field between database ID and name.

If you prefix id or name with a minus sign (ASCII 45), the sort order is reversed.

There are two very strong reasons to sort by ID:

  1. Sorting by name carries a risk of missing or duplicating objects if your result set spans multiple pages and another operator is editing the database while your REST client is enumerating them. This is known as "page drift." Sorting by ID does not carry that risk.
  2. Following a next link is dramatically quicker when sorting by ID.

We strongly recommend sorting by ID. In case you were still in doubt, we will do that by default in a future version of Command Centre.

The server silently ignores anything except the options listed here.

top
integer >= 1

Limits the results to no more than this many items per page.

Older versions of Command Centre returned 100 items per page in the absence of this parameter. That is acceptable for GUI applications that will only display the first page, but for integrations that intend to proceed through the entire database it causes a lot of chatter.

8.70 and later versions will default to 1000 items per request. This is about where a graph of throughput versus page size begins to level out.

name
string

Limits the returned items to those with a name that matches this string. Without surrounding quotes or a percent sign or underscore, it is a substring match; surround the parameter with double quotes "..." for an exact match. Without quotes, a percent sign % will match any substring and an underscore will match any single character.

The search is always case-insensitive. Results are undefined if you do a substring search for the empty string (name=). You will receive no items if you search for those with no name (name=""), as all items must have a name.

Search parameters are ANDed together.

division
Array of strings

Limits the returned items to those that are in these divisions.

That includes all the items in those divisions' child divisions, because Command Centre treats items as though they are also in their division's parent, and its parent, and so on up to the root division.

Separate the IDs of the divisions you are interested with commas. Item IDs are short alphanumeric strings, not URLs.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

directDivision
Array of strings

Restricts items to those whose division is in this list.

Unlike division=, it does not follow ancestry. That means it will limit the search to items that are directly assigned to the divisions you list, whereas division (without the direct) will also include items that are assigned to their descendants.

List the IDs of the divisions you are interested in separated by commas. Item IDs are short alphanumeric strings, not URLs.

Because this is the first query parameter we added that contains a capital letter, this will be the first time you have had to think about case sensitivity. directDivision works, directdivision does not.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

Added in 9.20.

description
string

Limits the returned items to those with a description that matches this string. By default it is a substring match; surround it with double quotes "..." for an exact match. A _ will match any single character, and a % will match any substring. With or without quotes, having either of these wildcards in the string will anchor it at both ends as though you had surrounded it with ".

The search is always case-insensitive. Results are undefined if you search for the empty string (description= or description="").

Search parameters are ANDed together.

fields
string
Enum: "href" "id" "name" "description" "division" "commands" "notes" "updates" "defaults"

This instructs the server to return only these fields in the search results. The values you can list are the same as the field names in the details page. Using this you can return everything on the summary page that you would find on the details page. Separate values with commas.

Use the special value defaults to return the fields you would have received had you not given the parameter at all. Obviously only do that if you have more to add.

Treat the string matches as case-sensitive.

In v8.00 you will receive the href and internal ID even if you did not ask for them. In 8.10 and later you will only get what you asked for. If you are going to send the fields parameter and need the href or ID, be explicit.

pos
integer

Reserved for internal use. You may see it in URLs you receive from the server, but you must never add it yourself.

skip
integer

Reserved for internal use. Do not add it to your queries.

Responses

Response samples

Content type
application/json
{}

Get details of a macro

This returns the detail of one macro.

Follow the 'href' field in an macro summary to get here.

Authorizations:
API_keybasic
path Parameters
id
required
string

The ID of the macro.

query Parameters
fields
string
Enum: "href" "id" "name" "description" "division" "commands" "notes" "updates" "defaults"

This instructs the server to return only these fields in the details page instead of the default set. The values you can list are the same as the field names you would see in the results. Use it to cut back on the size of the response. Separate values with commas.

Treat the string matches as case-sensitive.

In v8.00 you will receive the href and internal ID even if you did not ask for them. In 8.10 and later you will only get what you asked for. If you are going to send the fields parameter and need the href or ID, be explicit.

Responses

Response samples

Content type
application/json
{}

Run a macro

Sends a run request to a macro.

Authorizations:
API_keybasic
path Parameters
id
required
string

The ID of the macro.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Responses

Operator Groups

An operator group is like an access group in that:

  • one may contain any number of cardholders, and
  • a cardholder can be a member of any number of operator groups.

However:

  • there is no lineage: an operator group has no parent,

  • memberships have no begin or end dates,

  • a cardholder can have only one membership per group (and, because of the previous point, needs only one),

  • operator group updates do not go to controllers, so editing them is a much cheaper operation.

The biggest difference is in their purpose, of course. They grant cardholders the use of software instead of doors.

These API methods give you read access to the system's operator groups. You can search them, list their cardholder members, and see the divisions into which they grant their privileges. The API will not tell you the privileges that they grant.

Your REST operator will need either the 'View' or 'Edit Operators' operator privilege for those GETs.

Operator groups first appeared in the API in version 8.50.

Use cases

These are practically identical to the operations you'd perform on an access group, simplified because of the lack of lineage.

Finding members of an operator group, and managing memberships.

  1. GET /api.

  2. Follow the link at features.operatorGroups.operatorGroups.href (adding search terms, and setting top high to save pagination). 3. Find your operator group.

  3. The link at cardholders returns the cardholders who have membership of your group.

  4. Get the link at cardholders (which is the same on the search results and the details page), look in that cardholder's operatorGroups array, and manage each membership as you require. Send a DELETE to a membership's href to remove it, or an HTTP PATCH to the cardholder href to update it.

Search operator groups

This returns operator groups matching your search criteria.

The result will contain a batch of groups; you should follow the next link, if it is present, to collect the next batch.

When you have loaded all the operator groups there will be no next link.

If your result set is empty it means either your search terms were too tight or your operator does not have the privilege to view any operator groups. Perhaps there are none in the divisions in which your operator has 'View operators' or 'Edit operators', or your operator does not have those privileges at all.

This request does not return the group's cardholders. That would make the results unwieldy. Instead, it provides a separate link.

Adding, deleting, or modifying operator groups between calls to this API will not affect the pagination of its results if you sort by ID.

You can find the URL for this call in the features.operatorGroups.operatorGroups.href field of /api. In the interest of forward compability, do not build it yourself.

Added in 8.50.

Authorizations:
API_keybasic
query Parameters
sort
string
Enum: "id" "name" "-id" "-name"

Changes the sort field between database ID and name.

If you prefix id or name with a minus sign (ASCII 45), the sort order is reversed.

There are two very strong reasons to sort by ID:

  1. Sorting by name carries a risk of missing or duplicating objects if your result set spans multiple pages and another operator is editing the database while your REST client is enumerating them. This is known as "page drift." Sorting by ID does not carry that risk.
  2. Following a next link is dramatically quicker when sorting by ID.

We strongly recommend sorting by ID. In case you were still in doubt, we will do that by default in a future version of Command Centre.

The server silently ignores anything except the options listed here.

top
integer >= 1

Limits the results to no more than this many items per page.

Older versions of Command Centre returned 100 items per page in the absence of this parameter. That is acceptable for GUI applications that will only display the first page, but for integrations that intend to proceed through the entire database it causes a lot of chatter.

8.70 and later versions will default to 1000 items per request. This is about where a graph of throughput versus page size begins to level out.

name
string

Limits the returned items to those with a name that matches this string. Without surrounding quotes or a percent sign or underscore, it is a substring match; surround the parameter with double quotes "..." for an exact match. Without quotes, a percent sign % will match any substring and an underscore will match any single character.

The search is always case-insensitive. Results are undefined if you do a substring search for the empty string (name=). You will receive no items if you search for those with no name (name=""), as all items must have a name.

Search parameters are ANDed together.

division
Array of strings

Limits the returned items to those that are in these divisions.

That includes all the items in those divisions' child divisions, because Command Centre treats items as though they are also in their division's parent, and its parent, and so on up to the root division.

Separate the IDs of the divisions you are interested with commas. Item IDs are short alphanumeric strings, not URLs.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

directDivision
Array of strings

Restricts items to those whose division is in this list.

Unlike division=, it does not follow ancestry. That means it will limit the search to items that are directly assigned to the divisions you list, whereas division (without the direct) will also include items that are assigned to their descendants.

List the IDs of the divisions you are interested in separated by commas. Item IDs are short alphanumeric strings, not URLs.

Because this is the first query parameter we added that contains a capital letter, this will be the first time you have had to think about case sensitivity. directDivision works, directdivision does not.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

Added in 9.20.

description
string

Limits the returned items to those with a description that matches this string. By default it is a substring match; surround it with double quotes "..." for an exact match. A _ will match any single character, and a % will match any substring. With or without quotes, having either of these wildcards in the string will anchor it at both ends as though you had surrounded it with ".

The search is always case-insensitive. Results are undefined if you search for the empty string (description= or description="").

Search parameters are ANDed together.

fields
Array of strings
Default: "defaults"
Items Enum: "href" "id" "name" "description" "division" "notes" "cardholders" "divisions" "defaults"
pos
integer

Reserved for internal use. You may see it in URLs you receive from the server, but you must never add it yourself.

skip
integer

Reserved for internal use. Do not add it to your queries.

Responses

Response samples

Content type
application/json
{}

Get details of an operator group

In addition to the group's vitals and a link to the membership document, this call returns the divisions in which the operator groups grants its privileges.

Note that you can obtain the same results by adding fields=defaults,description,division,divisions,cardholders to a search.

You can find the URL for this call in the operator group search results and in a cardholder's operatorGroups array. In the interest of forward compability, do not build it yourself.

Added in 8.50.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
fields
Array of strings
Default: "defaults"
Items Enum: "href" "id" "name" "description" "division" "notes" "cardholders" "divisions" "defaults"

Sets which fields to return. The values you can list are the same as the field names in the detail results. Use it to return the notes, which don't appear by default. Separate values with commas.

Treat the string matches as case sensitive.

Responses

Response samples

Content type
application/json
{}

Get membership of an operator group

This lists all cardholders who are members of the group identified by the request URL. It does not paginate the results, so there is no next link.

Operator groups cannot contain other operator groups, so every cardholder benefiting from this operator group comes out of this call.

If your operator does not have the privilege to view a cardholder item you will receive its name but not its href (since following the href would 404).

You can find this call's URL in the cardholders block of an operator group. In the interest of forward compability, do not build it yourself.

Added in 8.50.

There are two hrefs per cardholder. The lower-level href is the identifier for the cardholder, found throughout this API. The higher-level href field only appears if you ask for it using the fields query parameter, and only if the server is 8.70 or later. It refers to the cardholder's membership in the operator group. If you DELETE it, you will remove the cardholder from this operator group (which will demote them from an operator to a regular cardholder if this was their last remaining operator group).

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
fields
Array of strings
Default: "defaults"
Items Enum: "defaults" "cardholder" "href"

Specifies the fields you want in the search results. The only two candidates are cardholder and href. The default is fields=defaults, which is the same as fields=cardholder. Separate values with commas.

Responses

Response samples

Content type
application/json
{}

Outputs

These methods give you read access to Outputs in the Command Centre database, and let you override them.

The first use case below introduces the main entry point. It is a paginated search interface that gives you any number of outputs, each containing the fields you ask for in the query, including (for example) the URLs you need to switch the outputs on and off.

Override times

  1. End-times on overrides are not accurate to the second. Internally, Command Centre converts the end time to a duration, so you may find that submitting end times in the very near future does not have the exact effect you expect.
  2. The end time you set for an override cannot be in the past or more than 24 hours into the future.

Overrides always use 'on' and 'off'

The Configuration client allows you to assign different display strings to the two normal output states, on and off. On could be 'green', for example, and off could be 'red'. Regardless, the overrides you apply to an output are called 'on' and 'off'.

Output status flags

Status flags, on the other hand, use the language of the relays on the hardware modules. They will report 'closed' for an output that is on, and 'open' for one that is off.

If the output is online, its statusFlags field may contain one or more of these flags:

  • relayStateUnknown means the controller does not know what the output should be doing.

  • closed means the output relay is closed.

  • open means the output relay is open.

  • pulsed means the relay's change in state is momentary.

  • switchingDisabled means switching this output is disabled.

  • overridden can appear whether the output is online or offline. It means the output has an override in effect.

Output flag rules

  • If and only if the output is online, one of 'relayStateUnknown', 'closed', or 'open' will appear. That is your test for whether an output is in error.
  • Of the above, only 'overridden' can appear when the output is offline.

Use cases

Listing Outputs

  1. GET /api.
  2. Follow the link at features.outputs.outputs.href , appending a search term such as name=substring to select the outputs, and fields to tell the server what to return about each. The next section covers those query parameters.
  3. Process the results, following the next link until there isn't one.

Switching an Output

  1. Find the href for the output using the process above.
  2. GET it.
  3. Look in the commands structure of the results to find the API URLs that turn the output on, off, or cancel a previous override. Use the until variants if you want to specify an end time.
  4. POST to that URL. Those with until in their command block keys require a JSON object in the body; the others expect it empty.

Finding an output's status

  1. Find the href for the output using the process above, and GET it.
  2. Take the updates href from that page.
  3. GET it.
  4. Use the flag rules above to interpret the status flags you receive.
  5. Follow the next link to stay up to date.

Search outputs

This returns a summary of the outputs matching your search criteria.

The result will contain no more than 100 or 1000 outputs (depending on your version), or as many as you asked for more in your request; you should follow the next link, if it is present, to collect the next batch.

If your result set is empty it means your operator does not have the privilege to view any outputs, such as 'View Site', 'Edit Site', or 'Override'. Perhaps there are no outputs in the divisions in which your operator has privileges, or your operator has no privileges at all.

When you have loaded them all there will be no next link.

Do not code this URL into your application. Take it from the 'href' field in the features.outputs.outputs section of /api.

Authorizations:
API_keybasic
query Parameters
sort
string
Enum: "id" "name" "-id" "-name"

Changes the sort field between database ID and name.

If you prefix id or name with a minus sign (ASCII 45), the sort order is reversed.

There are two very strong reasons to sort by ID:

  1. Sorting by name carries a risk of missing or duplicating objects if your result set spans multiple pages and another operator is editing the database while your REST client is enumerating them. This is known as "page drift." Sorting by ID does not carry that risk.
  2. Following a next link is dramatically quicker when sorting by ID.

We strongly recommend sorting by ID. In case you were still in doubt, we will do that by default in a future version of Command Centre.

The server silently ignores anything except the options listed here.

top
integer >= 1

Limits the results to no more than this many items per page.

Older versions of Command Centre returned 100 items per page in the absence of this parameter. That is acceptable for GUI applications that will only display the first page, but for integrations that intend to proceed through the entire database it causes a lot of chatter.

8.70 and later versions will default to 1000 items per request. This is about where a graph of throughput versus page size begins to level out.

name
string

Limits the returned items to those with a name that matches this string. Without surrounding quotes or a percent sign or underscore, it is a substring match; surround the parameter with double quotes "..." for an exact match. Without quotes, a percent sign % will match any substring and an underscore will match any single character.

The search is always case-insensitive. Results are undefined if you do a substring search for the empty string (name=). You will receive no items if you search for those with no name (name=""), as all items must have a name.

Search parameters are ANDed together.

division
Array of strings

Limits the returned items to those that are in these divisions.

That includes all the items in those divisions' child divisions, because Command Centre treats items as though they are also in their division's parent, and its parent, and so on up to the root division.

Separate the IDs of the divisions you are interested with commas. Item IDs are short alphanumeric strings, not URLs.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

directDivision
Array of strings

Restricts items to those whose division is in this list.

Unlike division=, it does not follow ancestry. That means it will limit the search to items that are directly assigned to the divisions you list, whereas division (without the direct) will also include items that are assigned to their descendants.

List the IDs of the divisions you are interested in separated by commas. Item IDs are short alphanumeric strings, not URLs.

Because this is the first query parameter we added that contains a capital letter, this will be the first time you have had to think about case sensitivity. directDivision works, directdivision does not.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

Added in 9.20.

description
string

Limits the returned items to those with a description that matches this string. By default it is a substring match; surround it with double quotes "..." for an exact match. A _ will match any single character, and a % will match any substring. With or without quotes, having either of these wildcards in the string will anchor it at both ends as though you had surrounded it with ".

The search is always case-insensitive. Results are undefined if you search for the empty string (description= or description="").

Search parameters are ANDed together.

fields
string
Enum: "href" "id" "name" "shortName" "description" "division" "commands" "connectedController" "statusFlags" "statusText" "status" "notes" "updates" "defaults"

This instructs the server to return only these fields in the search results. The values you can list are the same as the field names in the details page. Using this you can return everything on the summary page that you would find on the details page. Separate values with commas.

Use the special value defaults to return the fields you would have received had you not given the parameter at all. Obviously only do that if you have more to add.

Treat the string matches as case-sensitive.

In v8.00 you will receive the href and internal ID even if you did not ask for them. In 8.10 and later you will only get what you asked for. If you are going to send the fields parameter and need the href or ID, be explicit.

pos
integer

Reserved for internal use. You may see it in URLs you receive from the server, but you must never add it yourself.

skip
integer

Reserved for internal use. Do not add it to your queries.

Responses

Response samples

Content type
application/json
{}

Get details of an output

This returns the detail of one output.

Follow the 'href' field in an output summary to get here.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
fields
string
Enum: "href" "id" "name" "shortName" "description" "division" "commands" "connectedController" "statusFlags" "statusText" "status" "notes" "updates" "defaults"

This instructs the server to return only these fields in the details page instead of the default set. The values you can list are the same as the field names you would see in the results. Use it to cut back on the size of the response. Separate values with commas.

Treat the string matches as case-sensitive.

In v8.00 you will receive the href and internal ID even if you did not ask for them. In 8.10 and later you will only get what you asked for. If you are going to send the fields parameter and need the href or ID, be explicit.

Responses

Response samples

Content type
application/json
{}

Turn on an output

Sends an override to close an output.

If you send an end time in the body, the override will only stay in effect until then.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Request Body schema: application/json
optional

Put this in the body of override POSTs to set the time at which the override should cease. The API will reject the override if the string is not empty and it cannot parse it into a date-time, but it will treat the override as having no end time if you mis-spell 'endTime' or if you send a blank string.

Command Centre computes an override's duration to a whole number of minutes with a minimum of one. That means that a timed override will always end at a multiple of sixty seconds from the time the hardware receives the override request, which means the override will end within thirty seconds of the time you supplied here. In versions older than 8.80, the discrepancy may be up to a minute.

Careful observation of overrides submitted from the Configuration client and from the API will reveal that they use different rounding methods. Be assured, both result in overrides ending within a minute of the requested time.

endTime
string <date-time>

Responses

Request samples

Content type
application/json
{
  • "endTime": "2018-07-31T00:00:00Z"
}

Pulse an output

Sends an override to pulse an output.

Pulsing an output differs from turning it on in two ways:

  • You cannot specify a duration for it to stay activated, because that comes from the output's configuration.

  • A pulsed output will stay on for its pulse time even if another event seeks to deactivate it (an 'off' override will still deactivate the output).

Added in 8.50.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Responses

Turn off an output

Sends an override to open an output.

If you send an end time in the body, the override will only stay in effect until then.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Request Body schema: application/json
optional

Put this in the body of override POSTs to set the time at which the override should cease. The API will reject the override if the string is not empty and it cannot parse it into a date-time, but it will treat the override as having no end time if you mis-spell 'endTime' or if you send a blank string.

Command Centre computes an override's duration to a whole number of minutes with a minimum of one. That means that a timed override will always end at a multiple of sixty seconds from the time the hardware receives the override request, which means the override will end within thirty seconds of the time you supplied here. In versions older than 8.80, the discrepancy may be up to a minute.

Careful observation of overrides submitted from the Configuration client and from the API will reveal that they use different rounding methods. Be assured, both result in overrides ending within a minute of the requested time.

endTime
string <date-time>

Responses

Request samples

Content type
application/json
{
  • "endTime": "2018-07-31T00:00:00Z"
}

Cancel an override

Cancels an override, returning the output to its previous state.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
requested_by
string

Attributes this override to the cardholder with this ID rather than the REST operator. Privilege checks will use the operator as normal, but event monitors and reports will state that the person responsible for the override was the attributed cardholder, not the REST operator. The REST operator will appear in a special mention in the event's details.

First available in 8.70. Versions older than 8.70 will ignore the parameter, leaving the override attributed to the REST operator.

Responses

Monitor an output

See the item status topic for how to use the updates APIs.

Note that this API call is good for watching one item only; if you want to monitor several, you are better off with a status subscription.

Follow the 'updates' field in an output summary or details pages to get here.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
fields
string
Enum: "status" "statusText" "statusFlags"

This instructs the server to return these fields in the update, instead of the default set. You will not hear about updates to fields you do not list.

Responses

Response samples

Content type
application/json
{}

PDF definitions

A Personal Data Field is an item that adds a custom value to a cardholder. Each PDF has a type (text, image, numeric, ...) and optional constraints on the values that it can hold. For example, text, email, and telephone number types can have a regular expression with which new values must match. A date can have a maximum and a minimum. Text PDFs can have a list of valid values, like an enumeration. Mobile numbers and email addresses have a flag indicating whether they are suitable to receive SMS and email notifications.

There is more configuration: image PDFs have a type and size, to which Command Centre will transcode incoming images. All PDFs have their own access level (hidden, read-only, or full access) that applies to operators in operator groups that do not expressly override it.

Importantly, PDFs are attached to access groups. A cardholder can have a value for a PDF only if he or she is a member of one of the PDF's access groups.

This API lets you see the definitions and configuration of all the personal data fields in the system.

API routes that allow creating, modifying, and deleting PDF definitions are in development.

Use cases

Finding all a cardholder's PDF definitions

You can see all a cardholder's PDF values by looking in the personalDataDefinitions block of a cardholder. But that will only show you the PDFs that the cardholder currently has values for -- it will not show you the blanks. If you are writing an application that needs to find all the PDFs that a cardholder could carry, you will need this process.

Recall that a PDF is attached to an access group and appears on all direct and indirect members of that access group. To find a cardholder's PDFs, including those for which the cardholder has no value, you must find all the cardholder's groups, then find all the PDFs on those groups.

  1. GET the cardholder's access groups from the cardholder's detail page, or the search page with accessGroups added to the query's fields parameter.
  2. Iterate through the hrefs of those access groups, GETting each. That will return their detail pages.
  3. For each access group detail page, record the names and hrefs from the personalDataDefinitions block and add the parent.href link to the list of groups to check (unless you have already seen it, of course).

Now you have the names and hrefs of all the PDFs that cardholder can hold.

Finding a PDF's regular expression

  1. GET /api
  2. Follow the link at features.personalDataFields.personalDataFields.href , adding a search term to the query to thin out the results. For example, add name="PDF name" to only return the PDF definitions with that name.

Setting a cardholder's PDF value

You do that by PATCHing a cardholder with a field named after the PDF following an '@'.

Search PDF definitions

This returns the PDF definitions you are privileged to view. You will need the 'View Personal Data Definitions' privilege, or its 'Edit' equivalent, on a PDF's division in order to see it.

The result will contain no more than 100 or 1000 objects, depending on your version; you should follow the next link, if it is present, to collect more. When you have loaded all the PDF definitions there will no next link.

Do not code this URL into your application. Take it from the href in the features.personalDataFields.personalDataFields section of /api.

Authorizations:
API_keybasic
query Parameters
sort
string
Enum: "id" "name" "-id" "-name"

Changes the sort field between database ID and name.

If you prefix id or name with a minus sign (ASCII 45), the sort order is reversed.

There are two very strong reasons to sort by ID:

  1. Sorting by name carries a risk of missing or duplicating objects if your result set spans multiple pages and another operator is editing the database while your REST client is enumerating them. This is known as "page drift." Sorting by ID does not carry that risk.
  2. Following a next link is dramatically quicker when sorting by ID.

We strongly recommend sorting by ID. In case you were still in doubt, we will do that by default in a future version of Command Centre.

The server silently ignores anything except the options listed here.

top
integer >= 1

Limits the results to no more than this many items per page.

Older versions of Command Centre returned 100 items per page in the absence of this parameter. That is acceptable for GUI applications that will only display the first page, but for integrations that intend to proceed through the entire database it causes a lot of chatter.

8.70 and later versions will default to 1000 items per request. This is about where a graph of throughput versus page size begins to level out.

name
string

Limits the returned items to those with a name that matches this string. Without surrounding quotes or a percent sign or underscore, it is a substring match; surround the parameter with double quotes "..." for an exact match. Without quotes, a percent sign % will match any substring and an underscore will match any single character.

The search is always case-insensitive. Results are undefined if you do a substring search for the empty string (name=). You will receive no items if you search for those with no name (name=""), as all items must have a name.

Search parameters are ANDed together.

division
Array of strings

Limits the returned items to those that are in these divisions.

That includes all the items in those divisions' child divisions, because Command Centre treats items as though they are also in their division's parent, and its parent, and so on up to the root division.

Separate the IDs of the divisions you are interested with commas. Item IDs are short alphanumeric strings, not URLs.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

directDivision
Array of strings

Restricts items to those whose division is in this list.

Unlike division=, it does not follow ancestry. That means it will limit the search to items that are directly assigned to the divisions you list, whereas division (without the direct) will also include items that are assigned to their descendants.

List the IDs of the divisions you are interested in separated by commas. Item IDs are short alphanumeric strings, not URLs.

Because this is the first query parameter we added that contains a capital letter, this will be the first time you have had to think about case sensitivity. directDivision works, directdivision does not.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

Added in 9.20.

description
string

Limits the returned items to those with a description that matches this string. By default it is a substring match; surround it with double quotes "..." for an exact match. A _ will match any single character, and a % will match any substring. With or without quotes, having either of these wildcards in the string will anchor it at both ends as though you had surrounded it with ".

The search is always case-insensitive. Results are undefined if you search for the empty string (description= or description="").

Search parameters are ANDed together.

fields
Array of strings
Default: "defaults"
Items Enum: "href" "id" "name" "description" "division" "serverDisplayName" "type" "default" "required" "unique" "sortPriority" "accessGroups" "regex" "regexDescription" "defaultAccess" "operatorAccess" "notificationDefault" "defaults"

Specifies the fields in the search results. The values you can list are the same in the search and details pages. Using it you can return everything on the search page that you would find on the details page. Separate values with commas.

Use the special value defaults to return the fields you would have received had you not given the parameter at all. Add more after a comma.

Treat the string matches as case sensitive.

pos
integer

Reserved for internal use. You may see it in URLs you receive from the server, but you must never add it yourself.

skip
integer

Reserved for internal use. Do not add it to your queries.

Responses

Response samples

Content type
application/json
{}

BetaCreate [coming]

Creates a new personal data definition.

Do not code this URL into your application. Take it from the href field in the features.personalDataFields.personalDataFields.href field of GET /api.

When successful it returns a location header containing the address of the new PDF.

Note that you can only create one per POST.

This call requires the RESTConfiguration licence.

Authorizations:
API_keybasic
Request Body schema: application/json
required

This example shows the fields that you can set when creating a PDF.

name
string
description
string
division
object

The division containing this PDF definition. Required when creating one.

type
string
Enum: "string" "image" "strEnum" "numeric" "date" "address" "phone" "email" "mobile"

The type of PDF: string, image, email address, etc.

Required when creating a new PDF definition, but ignored when PATCHing one since a PDF's type is fixed once set.

default
string

This is the value that new cardholders will receive, if not supplied by the creating client. Required for 'required' PDFs.

This field will be missing if there is no default value.

To clear the default, send the blank string "".

required
boolean
Default: false

If true, every cardholder with this PDF must have a value for it. No blanks allowed.

unique
boolean
Default: false

If true, every cardholder with a value for this PDF must have a different value.

After 8.70 this will not show for date and image PDFs, because it can never be true for them.

defaultAccess
string
Default: "fullAccess"
Enum: "noAccess" "readOnly" "fullAccess"

This is the access that operators will have to cardholders' values of this PDF if the operator is not a member of an operator group that overrides it. Check the operator group's 'Personal data' tab in the Configuration Client.

sortPriority
integer

This is called 'sort order' in the Configuration Client. Interactive clients use this number to order the list of PDFs on a cardholder. It has no effect on access control or this API.

notificationDefault
boolean

This value is copied to the 'notification' flag on a cardholder's value for this PDF when they first gain membership of one of this PDF's access groups. It will only appear for PDF types that can receive notifications (email addresses and mobile numbers), and only if you ask for it with the fields parameter. The server will ignore it if you send it in a POST or PATCH to a PDF that is not email or mobile.

New in 8.50.

regex
string

This is the regular expression that a string-valued PDF value must match before Command Centre will accept it on a cardholder.

To remove the requirement that PDF values match a regular expression, send the empty string "".

regexDescription
string

Regular expressions often need explaining.

imageWidth
integer

The maximum width of an image stored in this PDF, in pixels, for image PDF types. You will only get this field if you ask for it with the fields parameter.

You can set this on a new PDF definition but not change it on an existing definition.

New in 8.50.

imageHeight
integer

The maximum height of an image stored in this PDF, in pixels, for image PDF types. You will only get this field if you ask for it with the fields parameter.

You can set this on a new PDF definition but not change it on an existing definition.

New in 8.50.

imageFormat
string
Deprecated
Enum: "bmp" "jpg" "png"

Whether this image PDF stores BMPs, JPEGs, or PNGs. You will only get this field if you ask for it with the fields parameter.

New in 8.50. Deprecated in 8.70 by contentType, which is more standard.

contentType
string
Enum: "image/bmp" "image/jpeg" "image/png"

Whether this image PDF stores BMPs, JPEGs, or PNGs. You will only get this field if you ask for it with the fields parameter.

You can set this on a new PDF definition but not change it on an existing definition.

New in 8.70.

isProfileImage
boolean

True if and only if this PDF holds images and it is set as a profile image.

Unlike many other properties of an image PDF, this can be changed at will.

New in 8.70.

Responses

Request samples

Content type
application/json
{
  • "name": "email",
  • "description": "Corporate mailbox",
  • "division": {},
  • "type": "email",
  • "default": "contact@example.com",
  • "required": false,
  • "unique": false,
  • "defaultAccess": "fullAccess",
  • "sortPriority": 50,
  • "notificationDefault": false,
  • "regex": ".*@.*",
  • "regexDescription": "@ least",
  • "imageWidth": 600,
  • "imageHeight": 800,
  • "imageFormat": "jpg",
  • "contentType": "image/jpeg",
  • "isProfileImage": false
}

Get details of a PDF definition

This returns details for a PDF definition. Follow the href in the summary to get here, rather than building it yourself.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
fields
Array of strings
Default: "defaults"
Items Enum: "href" "id" "name" "description" "division" "serverDisplayName" "type" "default" "required" "unique" "sortPriority" "accessGroups" "regex" "regexDescription" "defaultAccess" "operatorAccess" "notificationDefault" "defaults"

Specifies the fields in the search results. The values you can list are the same in the search and details pages. Using it you can return everything on the search page that you would find on the details page. Separate values with commas.

Use the special value defaults to return the fields you would have received had you not given the parameter at all. Add more after a comma.

Treat the string matches as case sensitive.

Responses

Response samples

Content type
application/json
{
  • "id": "string",
  • "name": "email",
  • "serverDisplayName": "ruatoria.satellite.int",
  • "description": "Corporate mailbox",
  • "division": {},
  • "type": "email",
  • "default": "contact@example.com",
  • "required": false,
  • "unique": false,
  • "defaultAccess": "fullAccess",
  • "operatorAccess": "fullAccess",
  • "sortPriority": 50,
  • "accessGroups": [],
  • "notificationDefault": false,
  • "regex": ".*@.*",
  • "regexDescription": "@ least",
  • "imageWidth": 600,
  • "imageHeight": 800,
  • "imageFormat": "jpg",
  • "contentType": "image/jpeg",
  • "isProfileImage": false
}

BetaUpdate [coming]

This is the call you use to update a PDF. Follow the href in the summary to get here, rather than building it yourself.

The PATCH expects a document in the same format as the the PDF detail.

It requires the RESTConfiguration licence.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

Request Body schema: application/json
required

There are no mandatory fields when PATCHing. There are, however, some fields you cannot change.

name
string
description
string
division
object

The division containing this PDF definition. Required when creating one.

type
string
Enum: "string" "image" "strEnum" "numeric" "date" "address" "phone" "email" "mobile"

The type of PDF: string, image, email address, etc.

Required when creating a new PDF definition, but ignored when PATCHing one since a PDF's type is fixed once set.

default
string

This is the value that new cardholders will receive, if not supplied by the creating client. Required for 'required' PDFs.

This field will be missing if there is no default value.

To clear the default, send the blank string "".

required
boolean
Default: false

If true, every cardholder with this PDF must have a value for it. No blanks allowed.

unique
boolean
Default: false

If true, every cardholder with a value for this PDF must have a different value.

After 8.70 this will not show for date and image PDFs, because it can never be true for them.

defaultAccess
string
Default: "fullAccess"
Enum: "noAccess" "readOnly" "fullAccess"

This is the access that operators will have to cardholders' values of this PDF if the operator is not a member of an operator group that overrides it. Check the operator group's 'Personal data' tab in the Configuration Client.

sortPriority
integer

This is called 'sort order' in the Configuration Client. Interactive clients use this number to order the list of PDFs on a cardholder. It has no effect on access control or this API.

notificationDefault
boolean

This value is copied to the 'notification' flag on a cardholder's value for this PDF when they first gain membership of one of this PDF's access groups. It will only appear for PDF types that can receive notifications (email addresses and mobile numbers), and only if you ask for it with the fields parameter. The server will ignore it if you send it in a POST or PATCH to a PDF that is not email or mobile.

New in 8.50.

regex
string

This is the regular expression that a string-valued PDF value must match before Command Centre will accept it on a cardholder.

To remove the requirement that PDF values match a regular expression, send the empty string "".

regexDescription
string

Regular expressions often need explaining.

imageWidth
integer

The maximum width of an image stored in this PDF, in pixels, for image PDF types. You will only get this field if you ask for it with the fields parameter.

You can set this on a new PDF definition but not change it on an existing definition.

New in 8.50.

imageHeight
integer

The maximum height of an image stored in this PDF, in pixels, for image PDF types. You will only get this field if you ask for it with the fields parameter.

You can set this on a new PDF definition but not change it on an existing definition.

New in 8.50.

imageFormat
string
Deprecated
Enum: "bmp" "jpg" "png"

Whether this image PDF stores BMPs, JPEGs, or PNGs. You will only get this field if you ask for it with the fields parameter.

New in 8.50. Deprecated in 8.70 by contentType, which is more standard.

contentType
string
Enum: "image/bmp" "image/jpeg" "image/png"

Whether this image PDF stores BMPs, JPEGs, or PNGs. You will only get this field if you ask for it with the fields parameter.

You can set this on a new PDF definition but not change it on an existing definition.

New in 8.70.

isProfileImage
boolean

True if and only if this PDF holds images and it is set as a profile image.

Unlike many other properties of an image PDF, this can be changed at will.

New in 8.70.

Responses

Request samples

Content type
application/json
{
  • "name": "email",
  • "description": "Corporate mailbox",
  • "division": {},
  • "type": "email",
  • "default": "contact@example.com",
  • "required": false,
  • "unique": false,
  • "defaultAccess": "fullAccess",
  • "sortPriority": 50,
  • "notificationDefault": false,
  • "regex": ".*@.*",
  • "regexDescription": "@ least",
  • "imageWidth": 600,
  • "imageHeight": 800,
  • "imageFormat": "jpg",
  • "contentType": "image/jpeg",
  • "isProfileImage": false
}

BetaRemove [coming]

This call removes a PDF item from Command Centre. Follow the href in the summary to get here, rather than building it yourself.

It requires the RESTConfiguration licence.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

Responses

PIV cards

This tag is a supplement to the main cardholder API documentation ('cardholder' is the Command Centre term for a user). That section describes how to add a card to an existing cardholder in a PATCH, and how to create a cardholder with cards in a POST, but in the interests of brevity its examples do not cover PIV.

The schema / models section gives you the details of the PIV part of a Command Centre card, with examples of what you would submit to create or update one, and what Command Centre will send you when you view one.

The Paths section takes those schema examples and wraps them into a PATCH and a POST. The two differ only in how they wrap the card into the submission body.

If your application will be assigning PIV cards to cardholders, however, the first thing it needs to do is learn the value of some constants for your particular installation of Command Centre.

Finding the PIV card type

When you assign any card to a cardholder, PIV or otherwise, you need to provide the identifier of the card type. It will vary between Command Centre installations, so you cannot use a value from another installation or these examples. It will not change while Command Centre is running but it may change at upgrade, so your application should follow this process at startup.

It takes two queries and a loop:

  1. GET /api.
  2. If running 8.00 or earlier, follow the link at features.cardTypes.cardTypes.href (which will be to /api/card_types), or
  3. if running 8.10 or later, follow the link at features.cardTypes.assign.href (which will probably be to /api/card_types/assign. Both URLs will work in 8.10, but the advantage of this URL is that your operator can access it at a lower privilege level).
  4. Iterate through the array to find the element with credentialClass: piv, and
  5. note its href.

You can accomplish the last two steps with the JSONPath filter

$.results[?(@.credentialClass=='piv')].href.

Explanation: Command Centre ships with a handful of card types, and administrators can add more, but the one that Command Centre uses for PIV and PIV-I cards has its own credential class. It will look like the example in the GET.

Finding the URL to create cardholders

GET /api. The link is at features.cardholders.cardholders.href.

Finding the URL of a cardholder

See the main cardholder documentation, particularly the section on searching cardholders.

Licensing

All of the API calls described here require the RESTCardholders licence. If your site is also licensed to use PIV cards, you can access those cards via REST.

Cardholder API changes in 8.10

  • Certificates and biometric data are now available without a customisation. They are too large to send to all REST clients so you must ask for them using the fields parameter.

Create a cardholder with a PIV card

This shows how to create a cardholder with a PIV card.

Authorizations:
API_keybasic
Request Body schema: application/json
required

When creating a cardholder there are many fields you can send that are not shown here, but since this is the PIV section of the documentation it only shows how to give the new person a PIV card.

firstName
string

You must set either a first or last name when creating a cardholder.

required
object

You must set a division when creating a cardholder.

Array of objects (New PIV Card)

An array of cards to give to the new cardholder.

Responses

Request samples

Content type
application/json

When sent in a POST this body would create a PIV credential and assign it to the cardholder being created by the POST.

A PIV-I example would have a different style of FASC-N, and a card number to match.

{
  • "firstName": "Nick",
  • "division": {},
  • "cards": [
    ]
}

Update a cardholder's PIV cards

This shows how to update a cardholder's PIV cards.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

Request Body schema: application/json
required

To update a cardholder's cards or give them a new one, send an object called cards containing up to three arrays named 'add', 'update', and 'remove'. Every element you put in those arrays should be in the card schema shown here.

object

Responses

Request samples

Content type
application/json

This example would update an existing PIV card on an existing cardholder. The two fields it changes are the status, which is a field common to credentials of all types, and the PIV status.

The PIV status is the only PIV-specific data you can change on a PIV card. Everything else--the CHUID, certificates, and biometrics--are all fixed, once set.

See the PIV data schema for when you should set the PIV status and what you can set it to.

{}

Get details of a cardholder

You will receive this URL from other calls to the API, in a search result or an access group membership list, for example. The URL is the unique identifier of a cardholder, and calling it returns much of what Command Centre holds for that person, including assigned cards.

The result includes an array called cards. Each element of that array is a credential of some type. If it is a PIV card, it will look like the example here.

Note that this example is an array of one.

Only the PIV card schema is shown below. The main documentation covers all the other fields Command Centre holds for a cardholder.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

Responses

Response samples

Content type
application/json
{
  • "cards": [
    ]
}

Receptions

A reception is an item that represents a location at which site visitors identify themselves, meet their hosts, and fulfil induction requirements. Every visit item has a reception. This controller gives you the list of receptions you can pick from when creating a visit.

This controller is read-only. It lets you pick a reception by name so that you can use its href on the visits controller.

Receptions are new to 8.50.

Use case: finding a reception by name

  1. GET /api
  2. Follow the link at features.receptions.receptions.href after adding search terms such as name="Front lobby". A site typically has very few receptions, so if you add top=1000 you're very unlikely to need to follow a next link.
  3. Find the reception you're after and use its href in a visit.

Search receptions

This returns the receptions you are privileged to view.

The result will contain no more than 100 or 1000 objects depending on your version; you should follow the next link, if it is present, to collect more, or use the top parameter to get more per page. Receptions are small, so setting a limit of 1000 is sensible.

When you have loaded all the receptions there will no next link.

Do not code this URL into your application. Take it from the href in the features.receptions.receptions section of /api.

Authorizations:
API_keybasic
query Parameters
sort
string
Enum: "id" "name" "-id" "-name"

Changes the sort field between database ID and name.

If you prefix id or name with a minus sign (ASCII 45), the sort order is reversed.

There are two very strong reasons to sort by ID:

  1. Sorting by name carries a risk of missing or duplicating objects if your result set spans multiple pages and another operator is editing the database while your REST client is enumerating them. This is known as "page drift." Sorting by ID does not carry that risk.
  2. Following a next link is dramatically quicker when sorting by ID.

We strongly recommend sorting by ID. In case you were still in doubt, we will do that by default in a future version of Command Centre.

The server silently ignores anything except the options listed here.

top
integer >= 1

Limits the results to no more than this many items per page.

Older versions of Command Centre returned 100 items per page in the absence of this parameter. That is acceptable for GUI applications that will only display the first page, but for integrations that intend to proceed through the entire database it causes a lot of chatter.

8.70 and later versions will default to 1000 items per request. This is about where a graph of throughput versus page size begins to level out.

name
string

Limits the returned items to those with a name that matches this string. Without surrounding quotes or a percent sign or underscore, it is a substring match; surround the parameter with double quotes "..." for an exact match. Without quotes, a percent sign % will match any substring and an underscore will match any single character.

The search is always case-insensitive. Results are undefined if you do a substring search for the empty string (name=). You will receive no items if you search for those with no name (name=""), as all items must have a name.

Search parameters are ANDed together.

division
Array of strings

Limits the returned items to those that are in these divisions.

That includes all the items in those divisions' child divisions, because Command Centre treats items as though they are also in their division's parent, and its parent, and so on up to the root division.

Separate the IDs of the divisions you are interested with commas. Item IDs are short alphanumeric strings, not URLs.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

directDivision
Array of strings

Restricts items to those whose division is in this list.

Unlike division=, it does not follow ancestry. That means it will limit the search to items that are directly assigned to the divisions you list, whereas division (without the direct) will also include items that are assigned to their descendants.

List the IDs of the divisions you are interested in separated by commas. Item IDs are short alphanumeric strings, not URLs.

Because this is the first query parameter we added that contains a capital letter, this will be the first time you have had to think about case sensitivity. directDivision works, directdivision does not.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

Added in 9.20.

description
string

Limits the returned items to those with a description that matches this string. By default it is a substring match; surround it with double quotes "..." for an exact match. A _ will match any single character, and a % will match any substring. With or without quotes, having either of these wildcards in the string will anchor it at both ends as though you had surrounded it with ".

The search is always case-insensitive. Results are undefined if you search for the empty string (description= or description="").

Search parameters are ANDed together.

fields
Array of strings
Default: "defaults"
Items Enum: "href" "name" "description" "division" "serverDisplayName" "defaultVisitorType" "notes" "defaults"

Specifies the fields in the response. The values you can list are the same in the search and details pages. Using it you can return everything on the search page that you would find on the details page, plus the reception's notes. Separate values with commas.

Use the special value defaults to return the fields you would have received had you not given the parameter at all. Add more after a comma.

Treat the string matches as case sensitive.

pos
integer

Reserved for internal use. You may see it in URLs you receive from the server, but you must never add it yourself.

skip
integer

Reserved for internal use. Do not add it to your queries.

Responses

Response samples

Content type
application/json
{}

Get details of a reception

This returns details for a reception. Follow the href in the summary to get here, rather than building it yourself.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
fields
Array of strings
Default: "defaults"
Items Enum: "href" "name" "description" "division" "serverDisplayName" "defaultVisitorType" "notes" "defaults"

Specifies the fields in the response. The values you can list are the same in the search and details pages. Using it you can return everything on the search page that you would find on the details page, plus the reception's notes. Separate values with commas.

Use the special value defaults to return the fields you would have received had you not given the parameter at all. Add more after a comma.

Treat the string matches as case sensitive.

Responses

Response samples

Content type
application/json
{}

Redactions

A redaction is a process that removes one cardholder's personal information from Command Centre. There are two kinds of redaction:

An event redaction disconnects a cardholder from events that record an operation that affected that cardholder. Examples:

  • an operator created the cardholder,

  • an operator changed the value of one of the cardholder's PDFs,

  • an operator changed the cardholder's access group memberships, or

  • the cardholder moved through a door.

An event recation does not affect a cardholder's history (visible in the enterprise clients).

A cardholder information redaction is absolute. It clears all the data held against the item. After being redacted a cardholder has nothing that can identify it: no names and no PDFs.

The only way back from a redaction is a database restore.

Because redactions can take some time, and should not be allowed to run immediately for security reasons, API clients can only schedule a redaction to occur at a future date. After doing that you can check the progress of redactions, and cancel them.

Exactly how far in the future a redaction needs to be depends on the site configuration.

There are two ways to list redactions: via their own paginated interface, which returns all the redactions in the system that your operator has the permission to view, or in the cardholder record.

Performance

In early tests with SQL Server and Command Centre on a Core i5, event redactions took roughly one second per 1000 affected events. Logs and events generated when a redaction completes contain statistics you could use to calculate your own redaction rate, but expect them to vary with the other demands on the database at the time.

Search redactions

This returns all cardholders' redactions. Paginated.

Authorizations:
API_keybasic
query Parameters
cardholder
string

Limits the results to redactions to cardholders with these IDs. Separate with commas.

status
string
Enum: "pending" "inProgress" "cancelled" "done" "failed"

Limits the results to redactions with this status. Separate with commas.

type
string
Enum: "normalEvents" "cardholder"

Limits the results to redactions of this type. Separate with commas.

after
string <date-time>

Limits the results to redactions that were scheduled to occur after this time.

before
string <date-time>

Limits the results to redactions that were scheduled to occur before this time.

fields
Array of strings
Items Value: "before cardholder finishTime href redactionOperator status type when"

Specifies the fields you want in the results.

Treat the string matches as case sensitive: use lastName rather than lastname.

pos
integer

Reserved for internal use. You may see it in URLs you receive from the server, but you must never add it yourself.

Responses

Response samples

Content type
application/json
{}

Schedule a redaction

Schedules a cardholder redaction.

Authorizations:
API_keybasic
Request Body schema: application/json

POST one of these to schedule a redaction.

cardholder
required
object

The href of the cardholder whose events or item this redaction should affect.

Required.

type
required
string
Enum: "normalEvents" "cardholder"

Whether this redaction is for events or cardholder information.

Required.

before
string <date-time>

For event redactions, do not redact any events after this time. No effect on cardholder information redactions.

Optional.

when
string <date-time>

When redaction is meant to happen. This should be in the future. If it is in the past, the service returns a 400.

Optional. If it is absent, it means to do it asap.

Responses

Request samples

Content type
application/json
{}

Cancel a redaction

This deletes a redaction record. It must be pending. Take the URL from the results of a redaction search.

Note that the only way to modify a redaction is to delete it and create a new one for the same cardholder. This is due to concerns about a redaction's effect on auditing.

Authorizations:
API_keybasic

Responses

Roles

The roles API gives you basic information about Command Centre's role items so that you can use them to form relationships between cardholders.

A role defines a relationship between two cardholders. One cardholder can perform a role for many others but can have it performed for them by only one other. For example, a person can be a supervisor for many people but has only one of his or her own.

When you use REST to look up or update a cardholder, you will work on the 'has a' relationships, not the 'is a' relationships. In other words, when a role represents a connection between a person and their supervisor, the API lets you change a cardholder's supervisor but not who the cardholder supervises.

API routes that allow creating, modifying, and deleting roles are in development.

Use case: searching for a role by name and assigning a relationship

  1. GET /api
  2. Follow the link at features.roles.roles.href after adding search terms such as name="supervisor".
  3. Find the href of the role with which you want to link your two cardholders.
  4. Find the href of the cardholder who will perform this role (the supervisor).
  5. Find the href of the cardholder for whom he or she will perform this role (the supervised).
  6. PATCH the second cardholder (the supervised) with the href of the first cardholder (the supervisor) and the href of the role.

Search

This returns the roles you are privileged to view.

The result will contain no more than 100 or 1000 objects depending on your version; you should follow the next link, if it is present, to collect more, or use the top parameter to get more per page. Roles are small, so a limit of 1000 is sensible.

When you have loaded all the roles there will no next link.

Do not code this URL into your application. Take it from the href in the features.roles.roles section of /api.

Authorizations:
API_keybasic
query Parameters
sort
string
Enum: "id" "name" "-id" "-name"

Changes the sort field between database ID and name.

If you prefix id or name with a minus sign (ASCII 45), the sort order is reversed.

There are two very strong reasons to sort by ID:

  1. Sorting by name carries a risk of missing or duplicating objects if your result set spans multiple pages and another operator is editing the database while your REST client is enumerating them. This is known as "page drift." Sorting by ID does not carry that risk.
  2. Following a next link is dramatically quicker when sorting by ID.

We strongly recommend sorting by ID. In case you were still in doubt, we will do that by default in a future version of Command Centre.

The server silently ignores anything except the options listed here.

top
integer >= 1

Limits the results to no more than this many items per page.

Older versions of Command Centre returned 100 items per page in the absence of this parameter. That is acceptable for GUI applications that will only display the first page, but for integrations that intend to proceed through the entire database it causes a lot of chatter.

8.70 and later versions will default to 1000 items per request. This is about where a graph of throughput versus page size begins to level out.

name
string

Limits the returned items to those with a name that matches this string. Without surrounding quotes or a percent sign or underscore, it is a substring match; surround the parameter with double quotes "..." for an exact match. Without quotes, a percent sign % will match any substring and an underscore will match any single character.

The search is always case-insensitive. Results are undefined if you do a substring search for the empty string (name=). You will receive no items if you search for those with no name (name=""), as all items must have a name.

Search parameters are ANDed together.

division
Array of strings

Limits the returned items to those that are in these divisions.

That includes all the items in those divisions' child divisions, because Command Centre treats items as though they are also in their division's parent, and its parent, and so on up to the root division.

Separate the IDs of the divisions you are interested with commas. Item IDs are short alphanumeric strings, not URLs.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

directDivision
Array of strings

Restricts items to those whose division is in this list.

Unlike division=, it does not follow ancestry. That means it will limit the search to items that are directly assigned to the divisions you list, whereas division (without the direct) will also include items that are assigned to their descendants.

List the IDs of the divisions you are interested in separated by commas. Item IDs are short alphanumeric strings, not URLs.

Because this is the first query parameter we added that contains a capital letter, this will be the first time you have had to think about case sensitivity. directDivision works, directdivision does not.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

Added in 9.20.

description
string

Limits the returned items to those with a description that matches this string. By default it is a substring match; surround it with double quotes "..." for an exact match. A _ will match any single character, and a % will match any substring. With or without quotes, having either of these wildcards in the string will anchor it at both ends as though you had surrounded it with ".

The search is always case-insensitive. Results are undefined if you search for the empty string (description= or description="").

Search parameters are ANDed together.

pos
integer

Reserved for internal use. You may see it in URLs you receive from the server, but you must never add it yourself.

skip
integer

Reserved for internal use. Do not add it to your queries.

Responses

Response samples

Content type
application/json
{}

Create [coming]

Creates a new role.

Do not code this URL into your application. Take it from the href field in the features.roles.roles.href field of GET /api.

When successful it returns a location header containing the address of the new role.

Note that you can only create one per POST.

This call requires the RESTConfiguration licence.

Authorizations:
API_keybasic
Request Body schema: application/json
required

This example shows the fields that you can set when creating a role. There are no mandatory fields when PATCHing a role, but you must specify a division when creating one.

name
string
description
string
division
object

The division containing this role. Required in a POST, optional in a PATCH.

enableCompetencyExpiryWarnings
boolean

Controls whether CC sends notifications to a person holding this role when their staff's competencies are about to expire.

enableCardExpiryWarnings
boolean

Controls whether CC sends notifications to a person holding this role when their staff's cards are about to expire.

Responses

Request samples

Content type
application/json
{
  • "name": "Supervisor",
  • "description": "aka floor manager",
  • "enableCompetencyExpiryWarnings": false,
  • "enableCardExpiryWarnings": true
}

Update [coming]

This is the call you use to update a role. Take its URL from a cardholder or a role search rather than building it yourself.

The PATCH expects a document in the same format as the the role detail.

This call requires the RESTConfiguration licence.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

Request Body schema: application/json
required

There are no mandatory fields when PATCHing a role, but you must specify a division when creating one.

name
string
description
string
division
object

The division containing this role. Required in a POST, optional in a PATCH.

enableCompetencyExpiryWarnings
boolean

Controls whether CC sends notifications to a person holding this role when their staff's competencies are about to expire.

enableCardExpiryWarnings
boolean

Controls whether CC sends notifications to a person holding this role when their staff's cards are about to expire.

Responses

Request samples

Content type
application/json
{
  • "name": "Supervisor",
  • "description": "aka floor manager",
  • "enableCompetencyExpiryWarnings": false,
  • "enableCardExpiryWarnings": true
}

Remove [coming]

This call removes a role item from Command Centre. Take its URL from a cardholder or a role search rather than building it yourself.

It requires the RESTConfiguration licence.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

Responses

Schedules

These methods give you read/write access to seven types of schedules. Avigilon Engage schedules are not included.

The main entry point is a paginated search that gives you any number of schedules. The most useful field on a schedule is a list of state changes and the days and times that those changes should occur.

There is also a method that allows creating new schedules.

Schedules are new to 8.50.

Licensing

The schedules APIs are licensed a little differently from most others. RESTCardholders gives you Cardholder Access Schedules, while RESTStatus and RESTOverrides give you all schedule types.

Search schedules

This returns a summary of the schedules matching your search criteria.

The result will contain no more than 100 or 1000, depending on your version, or as many as you asked for more in your request; you should follow the next link, if it is present, to collect the next batch.

If your result set is empty it means your operator does not have the privilege to view schedules, such as 'View Schedules', 'Edit Schedules', or 'Schedule Access Zone'. Perhaps there are no schedules in the divisions in which your operator has privileges, or your operator has no privileges at all.

Note that the privilege 'Schedule Access Zone' only lets you see Access Zone schedules, not the other five types.

When you have loaded them all there will be no next link.

Do not code this URL into your application. Take it from the 'href' field in the features.schedules.schedules section of /api.

Added in 8.50.

Authorizations:
API_keybasic
query Parameters
sort
string
Enum: "id" "name" "-id" "-name"

Changes the sort field between database ID and name.

If you prefix id or name with a minus sign (ASCII 45), the sort order is reversed.

There are two very strong reasons to sort by ID:

  1. Sorting by name carries a risk of missing or duplicating objects if your result set spans multiple pages and another operator is editing the database while your REST client is enumerating them. This is known as "page drift." Sorting by ID does not carry that risk.
  2. Following a next link is dramatically quicker when sorting by ID.

We strongly recommend sorting by ID. In case you were still in doubt, we will do that by default in a future version of Command Centre.

The server silently ignores anything except the options listed here.

top
integer >= 1

Limits the results to no more than this many items per page.

Older versions of Command Centre returned 100 items per page in the absence of this parameter. That is acceptable for GUI applications that will only display the first page, but for integrations that intend to proceed through the entire database it causes a lot of chatter.

8.70 and later versions will default to 1000 items per request. This is about where a graph of throughput versus page size begins to level out.

name
string

Limits the returned items to those with a name that matches this string. Without surrounding quotes or a percent sign or underscore, it is a substring match; surround the parameter with double quotes "..." for an exact match. Without quotes, a percent sign % will match any substring and an underscore will match any single character.

The search is always case-insensitive. Results are undefined if you do a substring search for the empty string (name=). You will receive no items if you search for those with no name (name=""), as all items must have a name.

Search parameters are ANDed together.

division
Array of strings

Limits the returned items to those that are in these divisions.

That includes all the items in those divisions' child divisions, because Command Centre treats items as though they are also in their division's parent, and its parent, and so on up to the root division.

Separate the IDs of the divisions you are interested with commas. Item IDs are short alphanumeric strings, not URLs.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

directDivision
Array of strings

Restricts items to those whose division is in this list.

Unlike division=, it does not follow ancestry. That means it will limit the search to items that are directly assigned to the divisions you list, whereas division (without the direct) will also include items that are assigned to their descendants.

List the IDs of the divisions you are interested in separated by commas. Item IDs are short alphanumeric strings, not URLs.

Because this is the first query parameter we added that contains a capital letter, this will be the first time you have had to think about case sensitivity. directDivision works, directdivision does not.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

Added in 9.20.

description
string

Limits the returned items to those with a description that matches this string. By default it is a substring match; surround it with double quotes "..." for an exact match. A _ will match any single character, and a % will match any substring. With or without quotes, having either of these wildcards in the string will anchor it at both ends as though you had surrounded it with ".

The search is always case-insensitive. Results are undefined if you search for the empty string (description= or description="").

Search parameters are ANDed together.

fields
Array of strings
Items Enum: "href" "name" "description" "division" "notes" "type" "dayCategories" "defaults"

This instructs the server to return only these fields in the search results. The values you can list are the same as the field names in the details page. Using this you can return everything on the summary page that you would find on the details page. Separate values with commas.

Use the special value defaults to return the fields you would have received had you not given the parameter at all. Obviously only do that if you have more to add.

Treat the string matches as case-sensitive.

pos
integer

Reserved for internal use. You may see it in URLs you receive from the server, but you must never add it yourself.

skip
integer

Reserved for internal use. Do not add it to your queries.

Responses

Response samples

Content type
application/json
{}

Create a schedule

This is how you create a new schedule.

Your POST needs a body containing JSON in the same from received from a GET, containing a division and type, and (if you want it to be useful) dayCategories.

Do not code this URL into your application. Take it from the 'href' field in the features.schedules.schedules section of /api.

Added in 8.50.

Authorizations:
API_keybasic
Request Body schema: application/json
required

The only fields you must supply in a POST are division and type. The server can make up a name for you, and is happy to leave the timetable empty.

href
string <uri-reference>

A link to a schedule detail.

name
string
description
string
object

The division containing this schedule. It is possible to change a schedule's division after creating it.

notes
string

Because of their potential size, notes are only available by request. Use the 'fields' parameter:

?fields=defaults,notes,...

object

This block contains a string field type which will (in the server's response to a GET) or must (in the body of your POST) be one of the seven schedule types. It is not a valid field in a PATCH, because you cannot change the type of an existing schedule.

Elevator kiosk control schedules arrived in 8.60.

Array of objects

This is the part of the schedule that controls when changes occur on its scheduled items.

It is an array of objects, each containing a day category and an array of times. The day category picks days of the year, and the times array sets what will happen and at what times on those days.

In the body of your POST:

  • The time field of each object inside times must be a string of the form HH:MM between 00:00 and 23:59. If you find another format that works (four zeroes, for example), it may not work in future versions.

  • Each day category must have an entry at 00:00. This means an item does not need to search back in time to find what state it should be in when it first comes online.

  • Each day category cannot have more than one entry at the same time.

If you receive a 400 response to your POST or PATCH and one of those rules is the cause, the body of the response should contain a reminder.

The state field is an array describing what should happen at that time. It is comparable to the statusFlags arrays on access zones, alarm zones, outputs, and fence zones. For most schedule types it will contain only one word, but the extra flag usePin may accompany access zone state changes.

When building your JSON, treat these string comparisons as case-sensitive.

All schedule types can have a state change called 'cancelUntimedOverrides'. That sets an item back to its scheduled state if it was under the effect of an override with no end time.

Other than that, each schedule type has its own set of state changes:

  • An Access Schedule, also known as a Cardholder Access Schedule, controls the ability of the members of an access group to pass into an access zone. The valid states are grant and deny. Note that 'deny' is a misnomer: a cardholder will gain access through a door if they are a member of a different access group that still has access.

  • An Access Zone Schedule controls the mode of an access zone. The valid states are the same as the zone's status flags: secure, dualAuth, codeOrCard, or free. The extra flag usePin means the same here as it does in the status flags: people will need their PINs at readers and alarms terminals.

  • An Alarm Zone Schedule switches an alarm zone between its four modes: set, unset, user, and user2. Use the words user1 and user2 here even if you have renamed them in the server properties.

  • An Output Schedule can be on or off, plain and simple.

  • A Notification Schedule controls when notifications go out. They can make sure that notifications go to the people who are on shift, and they can prevent bothering people at night. Like the access and output schedules it is binary, but the valid states are called notificationEnabled and notificationDisabled.

  • A HV/LF Schedule controls the voltage on an electric fence. 'lowFeel' mode allows detection without the deterrant of highVoltate.

This example sets an access zone to secure mode between 7.30am and 6:00pm on work days, and secure plus PIN mode at all other times.

Responses

Request samples

Content type
application/json
{}

Get details of a schedule

This returns the detail of one schedule.

Follow the 'href' field in an schedule summary to get here.

Authorizations:
API_keybasic
path Parameters
id
required
string

The ID of the schedule.

query Parameters
fields
string
Enum: "href" "name" "description" "division" "notes" "type" "dayCategories"

This instructs the server to return only these fields in the details page instead of the default set. The values you can list are the same as the field names you would see in the results. Use it to cut back on the size of the response. Separate values with commas.

Treat the string matches as case-sensitive.

Responses

Response samples

Content type
application/json
{}

Delete a schedule

Deletes the schedule identified by the request's URL.

Added in 8.50.

Authorizations:
API_keybasic
path Parameters
id
required
string

The ID of the schedule. Do not add it yourself: you will receive this URL from other API calls.

Responses

Modify a schedule

Modifies a schedule according to the body of the PATCH.

Added in 8.50.

Authorizations:
API_keybasic
path Parameters
id
required
string

The ID of the schedule. Do not add it yourself: you will receive this URL from other API calls.

Request Body schema: application/json
required

You do not need to supply any fields in the body of this PATCH, but if you want it to achieve something you should add at least one. Probably dayCategories.

href
string <uri-reference>

A link to a schedule detail.

name
string
description
string
object

The division containing this schedule. It is possible to change a schedule's division after creating it.

notes
string

Because of their potential size, notes are only available by request. Use the 'fields' parameter:

?fields=defaults,notes,...

object

This block contains a string field type which will (in the server's response to a GET) or must (in the body of your POST) be one of the seven schedule types. It is not a valid field in a PATCH, because you cannot change the type of an existing schedule.

Elevator kiosk control schedules arrived in 8.60.

Array of objects

This is the part of the schedule that controls when changes occur on its scheduled items.

It is an array of objects, each containing a day category and an array of times. The day category picks days of the year, and the times array sets what will happen and at what times on those days.

In the body of your POST:

  • The time field of each object inside times must be a string of the form HH:MM between 00:00 and 23:59. If you find another format that works (four zeroes, for example), it may not work in future versions.

  • Each day category must have an entry at 00:00. This means an item does not need to search back in time to find what state it should be in when it first comes online.

  • Each day category cannot have more than one entry at the same time.

If you receive a 400 response to your POST or PATCH and one of those rules is the cause, the body of the response should contain a reminder.

The state field is an array describing what should happen at that time. It is comparable to the statusFlags arrays on access zones, alarm zones, outputs, and fence zones. For most schedule types it will contain only one word, but the extra flag usePin may accompany access zone state changes.

When building your JSON, treat these string comparisons as case-sensitive.

All schedule types can have a state change called 'cancelUntimedOverrides'. That sets an item back to its scheduled state if it was under the effect of an override with no end time.

Other than that, each schedule type has its own set of state changes:

  • An Access Schedule, also known as a Cardholder Access Schedule, controls the ability of the members of an access group to pass into an access zone. The valid states are grant and deny. Note that 'deny' is a misnomer: a cardholder will gain access through a door if they are a member of a different access group that still has access.

  • An Access Zone Schedule controls the mode of an access zone. The valid states are the same as the zone's status flags: secure, dualAuth, codeOrCard, or free. The extra flag usePin means the same here as it does in the status flags: people will need their PINs at readers and alarms terminals.

  • An Alarm Zone Schedule switches an alarm zone between its four modes: set, unset, user, and user2. Use the words user1 and user2 here even if you have renamed them in the server properties.

  • An Output Schedule can be on or off, plain and simple.

  • A Notification Schedule controls when notifications go out. They can make sure that notifications go to the people who are on shift, and they can prevent bothering people at night. Like the access and output schedules it is binary, but the valid states are called notificationEnabled and notificationDisabled.

  • A HV/LF Schedule controls the voltage on an electric fence. 'lowFeel' mode allows detection without the deterrant of highVoltate.

This example sets an access zone to secure mode between 7.30am and 6:00pm on work days, and secure plus PIN mode at all other times.

Responses

Request samples

Content type
application/json
{}

Visits

Visits are new to 8.50.

Use case: finding a visit by name

  1. GET /api
  2. Follow the link at features.visits.visits.href after adding search terms such as name=Ginger Greeter. A site typically has many visits, so add top=1000 for efficiency's sake.
  3. Find the visit you're after. You can then modify it by PATCHing its href.

Use case: creating a visit

  1. Find the href of the reception at which your visitors will arrive.
  2. Look at the visitor management configuration for your reception's division.
  3. Pick a visitor type from that configuration, and a host from that visitor type's host access groups, and (optionally) some visitor access groups from that visitor type's visitor access groups.
  4. Pick (or create) at least one cardholder for your visitor or visitors.
  5. Build a JSON payload containing all that.
  6. POST to the link at features.visits.visits.href (in the payload of the GET /api you did for the first step).

Search visits

This returns the visits you are privileged to view.

The result will contain no more than 100 or 1000 objects depending on your version; you should follow the next link, if it is present, to collect more, or use the top parameter to get more per page.

When you have loaded all the visits there will no next link.

Do not code this URL into your application. Take it from the href in the features.visits.visits section of /api.

Visits are new to 8.50.

Authorizations:
API_keybasic
query Parameters
sort
string
Enum: "id" "name" "-id" "-name"

Changes the sort field between database ID and name.

If you prefix id or name with a minus sign (ASCII 45), the sort order is reversed.

There are two very strong reasons to sort by ID:

  1. Sorting by name carries a risk of missing or duplicating objects if your result set spans multiple pages and another operator is editing the database while your REST client is enumerating them. This is known as "page drift." Sorting by ID does not carry that risk.
  2. Following a next link is dramatically quicker when sorting by ID.

We strongly recommend sorting by ID. In case you were still in doubt, we will do that by default in a future version of Command Centre.

The server silently ignores anything except the options listed here.

top
integer >= 1

Limits the results to no more than this many items per page.

Older versions of Command Centre returned 100 items per page in the absence of this parameter. That is acceptable for GUI applications that will only display the first page, but for integrations that intend to proceed through the entire database it causes a lot of chatter.

8.70 and later versions will default to 1000 items per request. This is about where a graph of throughput versus page size begins to level out.

name
string

Limits the returned items to those with a name that matches this string. Without surrounding quotes or a percent sign or underscore, it is a substring match; surround the parameter with double quotes "..." for an exact match. Without quotes, a percent sign % will match any substring and an underscore will match any single character.

The search is always case-insensitive. Results are undefined if you do a substring search for the empty string (name=). You will receive no items if you search for those with no name (name=""), as all items must have a name.

Search parameters are ANDed together.

division
Array of strings

Limits the returned items to those that are in these divisions.

That includes all the items in those divisions' child divisions, because Command Centre treats items as though they are also in their division's parent, and its parent, and so on up to the root division.

Separate the IDs of the divisions you are interested with commas. Item IDs are short alphanumeric strings, not URLs.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

directDivision
Array of strings

Restricts items to those whose division is in this list.

Unlike division=, it does not follow ancestry. That means it will limit the search to items that are directly assigned to the divisions you list, whereas division (without the direct) will also include items that are assigned to their descendants.

List the IDs of the divisions you are interested in separated by commas. Item IDs are short alphanumeric strings, not URLs.

Because this is the first query parameter we added that contains a capital letter, this will be the first time you have had to think about case sensitivity. directDivision works, directdivision does not.

Results are undefined if you provide an ID that is not in the form of a division ID.

Search parameters are ANDed together.

Added in 9.20.

description
string

Limits the returned items to those with a description that matches this string. By default it is a substring match; surround it with double quotes "..." for an exact match. A _ will match any single character, and a % will match any substring. With or without quotes, having either of these wildcards in the string will anchor it at both ends as though you had surrounded it with ".

The search is always case-insensitive. Results are undefined if you search for the empty string (description= or description="").

Search parameters are ANDed together.

fields
Array of strings
Default: "defaults"
Items Enum: "href" "name" "description" "division" "serverDisplayName" "notes" "reception" "visitorType" "host" "from" "until" "location" "badgeText" "visitorAccessGroups" "visitors" "visitors.cardholder" "visitors.href" "visitors.invitation" "visitors.status" "..." "defaults"

Specifies the fields in the response. The values you can list are the same in the search and details pages. Using it you can return everything on the search page that you would find on the details page, plus the visit's notes. Separate values with commas.

Use the special value defaults to return the fields you would have received had you not given the parameter at all. Add more after a comma.

Treat the string matches as case sensitive.

pos
integer

Reserved for internal use. You may see it in URLs you receive from the server, but you must never add it yourself.

skip
integer

Reserved for internal use. Do not add it to your queries.

Responses

Response samples

Content type
application/json
{}

Create a visit

This creates a new visit.

In the interest of forward compatibility, do not code its URL into your application. Take it from the href in the features.visits.visits section of /api.

This POST expects a JSON body in the same format as a visit detail.

These fields are required:

  • name
  • reception
  • visitor type (access group)
  • host cardholder
  • start time (from)
  • end time (until)

Do not code this URL into your application. Take it from the href in the features.visits.visits section of /api.

Like all the visit endpoints, this one is new to 8.50.

Authorizations:
API_keybasic
Request Body schema: application/json

Pay particular attention to the field descriptions in the visit schema because some of the fields that the server sends you in response to a GET will not make sense in a POST, and some are optional.

name
required
string

You can name a visit however you like. Gallagher's in-house applications name them after their hosts.

This field is mandatory when creating a visit. No blank names allowed!

description
string

A visit's description is free text. Gallagher's visitor management clients use it to store the visit's purpose. You can change it at any time.

required
object

Every visit must have a reception. It represents the location at which your visitors will first arrive. Having one attached to a visit allows a kiosk at that location to hide visits for other receptions, revealing only those meant to start there.

Your choice of reception also determines the rules with which the visit must comply, because those rules come from the visitor management configuration on the reception's division.

Since every visit must have a reception, every POST that creates a visit must have one. Once you have a visit in the system you can change its reception, but be aware that changing receptions might change the visit's division, which also might change the rules to which the visit must conform, and if any validation fails--and there is a lot of it--the PATCH will fail.

The reception's name comes from the server in a GET, but you need not send it when creating or modifying a visit. Command Centre only needs an href from you.

Note that you must send the reception like it appears in the example, as an href inside a block called reception. This will not work:

"reception": "https://localhost:8904/api/receptions/123"

required
object

Every visit must also have a visitor type. It provides an access group for your visitors so that they can have personal data (remember that a cardholder must be in an access group before he or she can have a PDF), and it is an index into the visitor management configuration that governs things like the host (the cardholder who is responsible for your visitors) and the access groups that the server will give your visitors when they sign in.

Use the href from the division's visitor management configuration, or the access group's href. Both will work.

You will receive the accessGroup object inside the visitorType block in a GET, but you needn't send it in a POST or PATCH. The server can find the visitor type using only its href.

Like the reception, when you send this to the server you must use the same form as the example, as an href inside a block called visitorType. The href can be to an access group that you got from an access group or the visitorTypes in the visitor management configuration on a division. For example, both of these will work as visitor type hrefs:

https://localhost:8904/api/access_groups/925 (taken from another visit, or a search of access groups)

https://localhost:8904/api/divisions/2/visitor_types/925 (taken from a division config)

Your operator must have the privilege to view the access group, otherwise you will be told 'Access denied when writing to one or more fields'. Having the 'Modify Access Control' privilege on the group's division is a good choice because it not only gives you a view of access groups but the ability to change cardholders' membership of them, which you need to add visitors and visitor groups.

required
object

A host is a cardholder, and every visit has one. A visit's host is the person who (optionally) receives an email or SMS notification when visitors start signing in, and is responsible for them until they sign out again.

A host must be a member of at least one of the visit's visitor type's host access groups at the time that you create or modify the visit. To find out what those are, get the visitor management configuration for your reception's division (remembering that your visit's division is its reception's division). That visitor type contains an array of access groups called hostAccessGroups. Your host cardholder must be a member of one of those groups or their descendants.

When you GET a visit the server will send you the host cardholder's name, but when you create a visit with a POST or modify one with a PATCH, you needn't send the name back. Do so if you must, but it will not have an effect.

from
required
string <date-time>

Every visit has a validity period, defined by start and end times called from and until.

Not only are they both required when you create a visit, but the server will insist that until is later than from and that you followed the date-time rules.

You can use short forms such as 2021-04-01+12 and the server will fill in zeroes for the parts you missed. But because the end time must always be later than the start time you cannot use the same date for both start and end. The server will treat them both like midnight, see that they are equal, and reject your API call. So if you have a one-day visit, bump until by a day or pad it out until the evening. 2021-04-01T23:59:59+12, for example.

until
required
string <date-time>

Every visit has a validity period, defined by start and end times called from and until.

Not only are they both required when you create a visit, but the server will insist that until is later than from and that you followed the date-time rules.

You can use short forms such as 2021-04-01+12 and the server will fill in zeroes for the parts you missed. But because the end time must always be later than the start time you cannot use the same date for both start and end. The server will treat them both like midnight, see that they are equal, and reject your API call. So if you have a one-day visit, bump until by a day or pad it out until the evening. 2021-04-01T23:59:59+12, for example.

location
string

Free text. Entirely optional in the POST and PATCH.

Array of objects

These are the access groups that the server will add your visitors to after they complete induction and sign in. They define the access that your visitors have to the site, as they do for all cardholders.

It is perfectly valid to have no visitor access groups on a visit - it just means that someone will be opening all your guests' doors for them. That might be the kind of thing they are used to anyway.

The visitor access groups on a visit must be a subset of the visitor access groups on the division's visitor type (in the list of visitor access groups in the visit's reception's division's visitor management configuration, in other words).

When you send a visitor access group block to the server in a POST, just send an array of blocks each containing an href to an access group. This is one reason why you cannot copy a visit by POSTing back the JSON from a GET.

When you send a visitor access group block in a PATCH to edit an existing visit, the server expects it to contain one or two arrays called add and remove. The add array should contain access group hrefs, exactly as you would send when creating a visit. The remove array can contain access group hrefs or the hrefs you received in the GET. The PATCH example shows two hrefs trying to remove the same access group.

Your operator must have a privilege on the groups' divisions that allows viewing the access groups and adding and removing cardholders to and from them, otherwise you will be told 'Access denied when writing to one or more fields'. 'Modify Access Control' is a good choice.

Array of objects

When the server sends this array to you, it contains two hrefs for each cardholder due to arrive in this visit. The first, outside the cardholder block, is the URL you PATCH to change the state of their visit (new in 8.90). The one inside the cardholder block is simply an href to the cardholder item. You can use either href when removing visitors from a visit with a PATCH.

The status block contains two fields. value is a human-readable description of their state in the server's language. type comes from a fixed enumeration.

The invitation string is opaque: please do not interpret it.

Note that a visit with no visitors on it will come out of the API but will not appear in Gallagher's visitor management application. Why clutter the screen if you're not expecting anybody, after all.

When you send a visitor block to the server in a POST to create a visit, just send an array of blocks each containing an href to a cardholder. You do not need to put the hrefs inside cardholder blocks, as the server sends to you, so this is the other reason you cannot copy a visit by POSTing back the JSON from a GET.

Also do not bother sending a status block: the server will ignore it and set all visitors to 'expected'.

When you send a visitor block in a PATCH to edit an existing visit, the server expects it to contain an array called add, an array called remove, or both. The add array should contain cardholder hrefs, exactly as you would send when creating a visit. The remove array should contain either of the hrefs you received for the cardholder in the GET. The PATCH example shows two hrefs removing the same cardholder.

Your operator must have a privilege on the groups' divisions that allows viewing the access groups and adding and removing cardholders to and from them, otherwise you will be told 'Access denied when writing to one or more fields'. 'Modify Access Control' is a good choice.

Responses

Request samples

Content type
application/json
{}

Get details of a visit

This returns details for a visit. Follow the href in the visit item to get here rather than building the URL yourself.

All visit endpoints are new to 8.50.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

query Parameters
fields
Array of strings
Default: "defaults"
Items Enum: "href" "name" "description" "division" "serverDisplayName" "notes" "reception" "visitorType" "host" "from" "until" "location" "badgeText" "visitorAccessGroups" "visitors" "visitors.cardholder" "visitors.href" "visitors.invitation" "visitors.status" "..." "defaults"

Specifies the fields in the response. The values you can list are the same in the search and details pages. Using it you can return everything on the search page that you would find on the details page, plus the visit's notes. Separate values with commas.

Use the special value defaults to return the fields you would have received had you not given the parameter at all. Add more after a comma.

Treat the string matches as case sensitive.

Responses

Response samples

Content type
application/json
{}

Modify a visit

Changes an existing visit.

Follow the href in a visit item to get here rather than building the URL yourself.

New to 8.50.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

Request Body schema: application/json

As well as simple attributes such as from and until, the PATCH body you send can contain instructions for updating the lists of visitors and access groups.

name
string

You can name a visit however you like. Gallagher's in-house applications name them after their hosts.

This field is mandatory when creating a visit. No blank names allowed!

description
string

A visit's description is free text. Gallagher's visitor management clients use it to store the visit's purpose. You can change it at any time.

object

Every visit must have a reception. It represents the location at which your visitors will first arrive. Having one attached to a visit allows a kiosk at that location to hide visits for other receptions, revealing only those meant to start there.

Your choice of reception also determines the rules with which the visit must comply, because those rules come from the visitor management configuration on the reception's division.

Since every visit must have a reception, every POST that creates a visit must have one. Once you have a visit in the system you can change its reception, but be aware that changing receptions might change the visit's division, which also might change the rules to which the visit must conform, and if any validation fails--and there is a lot of it--the PATCH will fail.

The reception's name comes from the server in a GET, but you need not send it when creating or modifying a visit. Command Centre only needs an href from you.

Note that you must send the reception like it appears in the example, as an href inside a block called reception. This will not work:

"reception": "https://localhost:8904/api/receptions/123"

object

Every visit must also have a visitor type. It provides an access group for your visitors so that they can have personal data (remember that a cardholder must be in an access group before he or she can have a PDF), and it is an index into the visitor management configuration that governs things like the host (the cardholder who is responsible for your visitors) and the access groups that the server will give your visitors when they sign in.

Use the href from the division's visitor management configuration, or the access group's href. Both will work.

You will receive the accessGroup object inside the visitorType block in a GET, but you needn't send it in a POST or PATCH. The server can find the visitor type using only its href.

Like the reception, when you send this to the server you must use the same form as the example, as an href inside a block called visitorType. The href can be to an access group that you got from an access group or the visitorTypes in the visitor management configuration on a division. For example, both of these will work as visitor type hrefs:

https://localhost:8904/api/access_groups/925 (taken from another visit, or a search of access groups)

https://localhost:8904/api/divisions/2/visitor_types/925 (taken from a division config)

Your operator must have the privilege to view the access group, otherwise you will be told 'Access denied when writing to one or more fields'. Having the 'Modify Access Control' privilege on the group's division is a good choice because it not only gives you a view of access groups but the ability to change cardholders' membership of them, which you need to add visitors and visitor groups.

object

A host is a cardholder, and every visit has one. A visit's host is the person who (optionally) receives an email or SMS notification when visitors start signing in, and is responsible for them until they sign out again.

A host must be a member of at least one of the visit's visitor type's host access groups at the time that you create or modify the visit. To find out what those are, get the visitor management configuration for your reception's division (remembering that your visit's division is its reception's division). That visitor type contains an array of access groups called hostAccessGroups. Your host cardholder must be a member of one of those groups or their descendants.

When you GET a visit the server will send you the host cardholder's name, but when you create a visit with a POST or modify one with a PATCH, you needn't send the name back. Do so if you must, but it will not have an effect.

from
string <date-time>

Every visit has a validity period, defined by start and end times called from and until.

Not only are they both required when you create a visit, but the server will insist that until is later than from and that you followed the date-time rules.

You can use short forms such as 2021-04-01+12 and the server will fill in zeroes for the parts you missed. But because the end time must always be later than the start time you cannot use the same date for both start and end. The server will treat them both like midnight, see that they are equal, and reject your API call. So if you have a one-day visit, bump until by a day or pad it out until the evening. 2021-04-01T23:59:59+12, for example.

until
string <date-time>

Every visit has a validity period, defined by start and end times called from and until.

Not only are they both required when you create a visit, but the server will insist that until is later than from and that you followed the date-time rules.

You can use short forms such as 2021-04-01+12 and the server will fill in zeroes for the parts you missed. But because the end time must always be later than the start time you cannot use the same date for both start and end. The server will treat them both like midnight, see that they are equal, and reject your API call. So if you have a one-day visit, bump until by a day or pad it out until the evening. 2021-04-01T23:59:59+12, for example.

location
string

Free text. Entirely optional in the POST and PATCH.

object

These are the access groups that the server will add your visitors to after they complete induction and sign in. They define the access that your visitors have to the site, as they do for all cardholders.

It is perfectly valid to have no visitor access groups on a visit - it just means that someone will be opening all your guests' doors for them. That might be the kind of thing they are used to anyway.

The visitor access groups on a visit must be a subset of the visitor access groups on the division's visitor type (in the list of visitor access groups in the visit's reception's division's visitor management configuration, in other words).

When you send a visitor access group block to the server in a POST, just send an array of blocks each containing an href to an access group. This is one reason why you cannot copy a visit by POSTing back the JSON from a GET.

When you send a visitor access group block in a PATCH to edit an existing visit, the server expects it to contain one or two arrays called add and remove. The add array should contain access group hrefs, exactly as you would send when creating a visit. The remove array can contain access group hrefs or the hrefs you received in the GET. The PATCH example shows two hrefs trying to remove the same access group.

Your operator must have a privilege on the groups' divisions that allows viewing the access groups and adding and removing cardholders to and from them, otherwise you will be told 'Access denied when writing to one or more fields'. 'Modify Access Control' is a good choice.

object

When the server sends this array to you, it contains two hrefs for each cardholder due to arrive in this visit. The first, outside the cardholder block, is the URL you PATCH to change the state of their visit (new in 8.90). The one inside the cardholder block is simply an href to the cardholder item. You can use either href when removing visitors from a visit with a PATCH.

The status block contains two fields. value is a human-readable description of their state in the server's language. type comes from a fixed enumeration.

The invitation string is opaque: please do not interpret it.

Note that a visit with no visitors on it will come out of the API but will not appear in Gallagher's visitor management application. Why clutter the screen if you're not expecting anybody, after all.

When you send a visitor block to the server in a POST to create a visit, just send an array of blocks each containing an href to a cardholder. You do not need to put the hrefs inside cardholder blocks, as the server sends to you, so this is the other reason you cannot copy a visit by POSTing back the JSON from a GET.

Also do not bother sending a status block: the server will ignore it and set all visitors to 'expected'.

When you send a visitor block in a PATCH to edit an existing visit, the server expects it to contain an array called add, an array called remove, or both. The add array should contain cardholder hrefs, exactly as you would send when creating a visit. The remove array should contain either of the hrefs you received for the cardholder in the GET. The PATCH example shows two hrefs removing the same cardholder.

Your operator must have a privilege on the groups' divisions that allows viewing the access groups and adding and removing cardholders to and from them, otherwise you will be told 'Access denied when writing to one or more fields'. 'Modify Access Control' is a good choice.

Responses

Request samples

Content type
application/json
{}

Modify a visitor's status

Changes a visitor's state for a visit. This is how you mark a visitor as signing in, signed in, on site, off site again, etc.

Doing so will create an event if your visitor was not already in the state you attempted to move them to.

It will not send a notification to the visitor's host or escort. There are other API calls for notifying that a visitor is signing in or on-site.

Note that this URL is different from a normal cardholder href because a cardholder can be a visitor on more than one visit at a time.

Do not code this URL into your application. Take it from the results of a visit search.

New to 8.90.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

secondary_id
required
string

An internal identifier.

Request Body schema: application/json

This must contain a block called status containing a string called value, giving your desired state of the visitor.

object

This is the same status that you see in a visit GET for each visitor except that you only need to send the value field.

Responses

Request samples

Content type
application/json
{
  • "status": {
    }
}

Notify that a visitor is signing in

Sends an email and / or SMS notification to a visit's host.

The difference between this and notify_onsite is the type of event that Command Centre puts in the audit trail. In all other ways they are identical.

New to 8.90.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

secondary_id
required
string

An internal identifier.

Request Body schema: application/json

The contents of the notification email or SMS, or both.

emailSubject
string

If you wish to send an email notification, put its subject here. Email will go out if you leave it blank but provide a body, but it is generally easier on the recipient the other way around.

emailMessage
string

If you want your email notification to contain body text, put it here.

smsMessage
string

If you wish to send an SMS notification (a TXT), put it here. Leave it blank if you only wish to send email.

Responses

Request samples

Content type
application/json
{
  • "emailSubject": "Visitor arriving",
  • "emailMessage": "",
  • "smsMessage": "Visitor arriving"
}

Notify that a visitor is on-site

Sends an email and / or SMS notification to a visit's host.

The difference between this and notify_signing_in is the type of event that Command Centre puts in the audit trail. In all other ways they are identical.

New to 8.90.

Authorizations:
API_keybasic
path Parameters
id
required
string

An internal identifier.

secondary_id
required
string

An internal identifier.

Request Body schema: application/json

The contents of the notification email or SMS, or both.

emailSubject
string

If you wish to send an email notification, put its subject here. Email will go out if you leave it blank but provide a body, but it is generally easier on the recipient the other way around.

emailMessage
string

If you want your email notification to contain body text, put it here.

smsMessage
string

If you wish to send an SMS notification (a TXT), put it here. Leave it blank if you only wish to send email.

Responses

Request samples

Content type
application/json
{
  • "emailSubject": "Visitor arriving",
  • "emailMessage": "",
  • "smsMessage": "Visitor arriving"
}