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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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:
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.
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.
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.
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.
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.
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.
GET /api.
Follow the link at features.accessGroups.accessGroups.href
↪ (adding search terms, and setting top high to save
pagination).
Find your access group in the results.
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.
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.
GET /api.features.accessGroups.accessGroups.href
↪. If you follow the efficiency tips in the cardholder
section you will add top and sort parameters.parent.href,
if it is there. An access group may have no parents or one parent, never more.next.href, if there is one, and repeat.You can now assemble the groups into a tree.
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.
| sort | string Enum: "id" "name" "-id" "-name" Changes the sort field between database ID and name. If you prefix There are two very strong reasons to sort 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 The search is always case-insensitive. Results are undefined if you do a substring search for
the empty string ( 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 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. 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 The search is always case-insensitive. Results are undefined if you search for the empty
string ( 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 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. |
{- "results": [
- {
- "name": "R&D special projects group.",
- "description": "Deep underground.",
- "id": "352",
- "notes": "",
- "serverDisplayName": "ruatoria.satellite.int"
}
],
}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.
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 |
| notes | string |
| membershipAutoRemoveExpired | boolean If true, memberships will be removed when their |
| 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 |
{- "name": "R&D special projects group.",
- "description": "Deep underground.",
- "notes": "",
- "membershipAutoRemoveExpired": true,
- "membershipFromDefault": "2025-01-01T00:00:00Z",
- "membershipUntilDefault": "2025-01-01T00:00:00Z",
- "personalDataDefinitions": [
]
}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.
| id required | string An internal identifier. |
| 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. |
{- "name": "R&D special projects group.",
- "description": "Deep underground.",
- "id": "352",
- "notes": "",
- "serverDisplayName": "ruatoria.satellite.int",
- "personalDataDefinitions": [
], - "children": [
], - "visitor": false,
- "escortVisitors": false,
- "lockUnlockAccessZones": false,
- "enterDuringLockdown": false,
- "firstCardUnlock": false,
- "overrideAperioPrivacy": false,
- "aperioOfflineAccess": false,
- "disarmAlarmZones": false,
- "armAlarmZones": false,
- "hvLfFenceZones": false,
- "viewAlarms": false,
- "shunt": false,
- "lockOutFenceZones": false,
- "cancelFenceZoneLockout": false,
- "ackAll": false,
- "ackBelowHigh": false,
- "selectAlarmZone": false,
- "armWhileAlarm": false,
- "armWhileActiveAlarm": false,
- "isolateAlarmZones": false,
- "access": [
- {
- "schedule": {
- "name": "Default Cardholder Access Granted"
}
}, - {
}
], - "saltoAccess": [
- {
- "saltoItemType": {
- "value": "saltoAccessZone"
}, - "schedule": {
- "name": "Default Cardholder Access Granted"
}
}, - {
- "saltoItemType": {
- "value": "saltoDoor"
},
}
], - "alarmZones": [
- {
- "alarmZone": {
- "name": "Roswell building 2 lobby alarms"
}
}, - {
- "alarmZone": {
- "name": "Roswell building 3 lobby alarms"
}
}
]
}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.
| id required | string An internal identifier. |
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 |
| notes | string |
| membershipAutoRemoveExpired | boolean If true, memberships will be removed when their |
| 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 In this example we are adding PDF 5516 and removing 9370. |
{- "name": "R&D special projects group.",
- "description": "Deep underground.",
- "notes": "",
- "membershipAutoRemoveExpired": true,
- "membershipFromDefault": "2025-01-01T00:00:00Z",
- "membershipUntilDefault": "2025-01-01T00:00:00Z",
- "personalDataDefinitions": {
}
}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.
| id required | string An internal identifier. |
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.
| id required | string An internal identifier. |
{- "cardholders": [
- {
- "from": "2017-01-01T00:00:00Z",
- "until": "2017-12-31T11:59:59Z"
}, - {
- "cardholder": {
- "name": "Miles Messervy"
}, - "from": "2016-11-18T00:00:00Z"
}
]
}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.
Note:
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.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.
GET /api.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.next link until there isn't one.commands structure of the results, such as free or
securePin, from the detail. Use the until variants if
you are specifying an end time.until in their command block keys). The others expect an empty body.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.next link to stay up to date.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.
| sort | string Enum: "id" "name" "-id" "-name" Changes the sort field between database ID and name. If you prefix There are two very strong reasons to sort 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 The search is always case-insensitive. Results are undefined if you do a substring search for
the empty string ( 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 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. 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 The search is always case-insensitive. Results are undefined if you search for the empty
string ( 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 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 |
| 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. |
{- "results": [
- {
- "id": "3280",
- "name": "Roswell building 2 lobby"
}
],
}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.
| sort | string Enum: "id" "name" "-id" "-name" Changes the sort field between database ID and name. If you prefix There are two very strong reasons to sort 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 The search is always case-insensitive. Results are undefined if you do a substring search for
the empty string ( 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 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. 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 The search is always case-insensitive. Results are undefined if you search for the empty
string ( 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 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 |
| 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. |
{- "results": [
- {
- "id": "3280",
- "name": "Roswell building 2 lobby"
}
],
}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.
| id required | string |
| 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 |
{- "id": "3280",
- "name": "Roswell building 2 lobby",
- "description": "Receives all visitors.",
- "doors": [
], - "zoneCount": 365,
- "notes": "Multi-line text...",
- "shortName": "Short text",
- "statusFlags": [
- "secure"
], - "connectedController": {
- "name": "Fourth floor C7000",
- "id": "634"
}, - "commands": {
- "forgiveAntiPassback": {
},
}
}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.
| id required | string The ID of the access zone. |
| 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. |
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> |
{- "endTime": "2018-07-31T00:00:00Z"
}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.
| id required | string The ID of the access zone. |
| 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. |
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> |
{- "endTime": "2018-07-31T00:00:00Z"
}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.
| id required | string The ID of the access zone. |
| 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. |
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> |
{- "endTime": "2018-07-31T00:00:00Z"
}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.
| id required | string The ID of the access zone. |
| 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. |
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> |
{- "endTime": "2018-07-31T00:00:00Z"
}Sends an override to an access zone to forgive anti-passback for all cardholders in the zone.
| id required | string The ID of the access zone. |
| 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. |
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.
| id required | string The ID of the access zone. |
| 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. |
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.
| id required | string The ID of the access zone. |
| 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. |
Sets the count of cardholders inside a zone.
| id required | string The ID of the access zone. |
| 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. |
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. |
{- "zoneCount": 100
}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.
| id required | string The ID of the access zone. |
| 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. |
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.
| id required | string The ID of the access zone. |
| 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. |
{- "updates": {
- "status": "Secure.",
- "statusText": "Secure.",
- "statusFlags": [
- "secure"
], - "zoneCount": 100
},
}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.
GET /apifeatures.alarms.alarms ↪. You will
receive up to 100 alarms, each containing links to its management functions.next.href, follow it and
repeat.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.
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.
| 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. |
{- "alarms": [
- {
- "id": "10135",
- "time": "2016-02-18T19:21:52Z",
- "message": "External bulk loading bay door has been forced",
- "source": {
- "id": "1321",
- "name": "External bulk loading bay door",
}, - "type": "Forced door",
- "eventType": { },
- "priority": 8,
- "state": "unacknowledged",
- "active": false,
- "notePresets": [
- "False alarm confirmed by surveillance",
- "Security staff dispatched"
],
}
],
}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.
| 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. |
{- "updates": [
- {
- "id": "10135",
- "time": "2016-02-18T19:21:52Z",
- "message": "External bulk loading bay door has been forced",
- "source": {
- "id": "1321",
- "name": "External bulk loading bay door",
}, - "type": "Forced door",
- "eventType": { },
- "priority": 8,
- "state": "unacknowledged",
- "active": false,
- "notePresets": [
- "False alarm confirmed by surveillance",
- "Security staff dispatched"
],
}
],
}Full details for an alarm. Follow the href in the alarm summary to get here.
| 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. |
| 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. |
{- "details": "Forced door",
- "history": [
- {
- "time": "2016-02-18T19:21:52Z",
- "action": "viewed",
- "comment": "Operator viewed alarm properties",
- "operator": {
- "name": "System Operator"
}
}
], - "instruction": {
- "name": "Forced door instruction"
}, - "cardholder": {
- "name": "Smith, Jane",
- "firstName": "Jane",
- "lastName": "Smith-Jones"
}, - "id": "10135",
- "time": "2016-02-18T19:21:52Z",
- "message": "External bulk loading bay door has been forced",
- "source": {
- "id": "1321",
- "name": "External bulk loading bay door",
}, - "type": "Forced door",
- "eventType": { },
- "priority": 8,
- "state": "unacknowledged",
- "active": false,
- "notePresets": [
- "False alarm confirmed by surveillance",
- "Security staff dispatched"
],
}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.
| 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. |
Optional comment.
| comment | string Optional for some methods that update alarms. Contains a comment placed by the operator. |
{- "comment": "Alarm was adequately explained."
}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.
| 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. |
Optional comment.
| comment | string Optional for some methods that update alarms. Contains a comment placed by the operator. |
{- "comment": "Alarm was adequately explained."
}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.
| 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. |
Optional comment.
| comment | string Optional for some methods that update alarms. Contains a comment placed by the operator. |
{- "comment": "Alarm was adequately explained."
}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.
| 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. |
Optional comment.
| comment | string Optional for some methods that update alarms. Contains a comment placed by the operator. |
{- "comment": "Alarm was adequately explained."
}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.
Note:
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).
GET /api.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.next link until there isn't one.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.Until in their names require a JSON object in
the body giving the time at which the override should end; the others do not.updates ↪ href from that page.next link to stay up to date.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.
| sort | string Enum: "id" "name" "-id" "-name" Changes the sort field between database ID and name. If you prefix There are two very strong reasons to sort 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 The search is always case-insensitive. Results are undefined if you do a substring search for
the empty string ( 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 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. 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 The search is always case-insensitive. Results are undefined if you search for the empty
string ( 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 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 |
| 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. |
{- "results": [
- {
- "id": "328",
- "name": "Roswell building 2 lobby alarms"
}
],
}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.
| id required | string The ID of the alarm zone. |
| 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 |
{- "id": "328",
- "name": "Roswell building 2 lobby alarms",
- "description": "Lobby, cafeteria, inbound artefacts.",
- "shortName": "R2 lobby",
- "notes": "Multi-line text...",
- "statusFlags": [
- "armed"
], - "connectedController": {
- "name": "Third floor C6000",
- "id": "634"
}, - "commands": {
}
}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.
| id required | string The ID of the alarm zone. |
| 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. |
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> |
{- "endTime": "2018-07-31T00:00:00Z"
}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.
| id required | string The ID of the alarm zone. |
| 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. |
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> |
{- "endTime": "2018-07-31T00:00:00Z"
}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.
| id required | string The ID of the alarm zone. |
| 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. |
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> |
{- "endTime": "2018-07-31T00:00:00Z"
}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.
| id required | string The ID of the alarm zone. |
| 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. |
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> |
{- "endTime": "2018-07-31T00:00:00Z"
}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.
| id required | string The ID of the alarm zone. |
| 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. |
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> |
{- "endTime": "2018-07-31T00:00:00Z"
}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.
| id required | string The ID of the alarm zone. |
| 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. |
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> |
{- "endTime": "2018-07-31T00:00:00Z"
}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.
| id required | string The ID of the alarm zone. |
| 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. |
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.
| id required | string The ID of the alarm zone. |
| 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. |
{- "updates": {
- "status": "Disarmed.",
- "statusText": "Disarmed.",
- "statusFlags": [
- "disarmed"
]
},
}These routes allow clients to get Gallagher card encoding data for MIFARE DESFire and MIFARE Classic cards.
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
Import-PfxCertificate -FilePath "path\to\key.pfx" -CertStoreLocation Cert:\CurrentUser\My -Password (Read-Host "Enter PFX Password" -AsSecureString)
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);
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.
| id required | string An internal identifier. |
| secondary_id required | string An internal identifier. |
| 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 |
{- "csn": "0x04A23F9C123456",
- "cadFiles": {
- "0": "0x00C34F2081F4000000000000000000000000000000000000000000000000000000000000"
}, - "reason": "New card issuance"
}{- "encryptedEncodingData": {
- "cipherText": "a8G79CeiZPIgm3nZaAdE6ACIjivuHdOVWHB/nxO+xWOMXLXbVnObOSPVwCDvUwIk97OVZi7gahBgjZPcy4D0TeQJ6YUMzNuwB50EsGkeu+UWD640Hmwq7WGGuchXAZP4bSw6DrrSvwSh",
- "iv": "2XpAcIq4nfKzamPMlCo36g==",
- "ephemeralPublicKey": "BEK2nvjPU3+fZ9DjU2xmy1+zWI0wCGOzX1bCi4mnpaKbmsI9fEMgitljCA+aJRSZWvCBhzIn9vQswwni5F9dOg30tjrW",
- "tag": "N/NNXOvJlvUm+UgPQVufM7w/t0dfvcdluc6qOUgRFio="
}, - "callback": {
- "encodeCompleted": {
}, - "encodeFailed": {
}
}
}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.
| id required | string An internal identifier. |
| secondary_id required | string An internal identifier. |
| csn required | string (HexString) ^0x([0-9A-Fa-f]{2})+$ |
object (ClassicCad) | |
object (ClassicMad) | |
| unavailableSectors | Array of integers |
| reason | string <= 100 characters |
{- "csn": "0x04A23F9C",
- "cad": {
- "sector": 14,
- "blocks": {
- "0": "0xadad",
- "1": "0xafad"
}
}, - "mad": {
- "blocks": {
- "1": "0x0ebd",
- "2": "0x0816"
}
}, - "unavailableSectors": [
- 2,
- 3,
- 4
], - "reason": "Lost Card Replacement"
}{- "encryptedEncodingData": {
- "cipherText": "a8G79CeiZPIgm3nZaAdE6ACIjivuHdOVWHB/nxO+xWOMXLXbVnObOSPVwCDvUwIk97OVZi7gahBgjZPcy4D0TeQJ6YUMzNuwB50EsGkeu+UWD640Hmwq7WGGuchXAZP4bSw6DrrSvwSh",
- "iv": "2XpAcIq4nfKzamPMlCo36g==",
- "ephemeralPublicKey": "BEK2nvjPU3+fZ9DjU2xmy1+zWI0wCGOzX1bCi4mnpaKbmsI9fEMgitljCA+aJRSZWvCBhzIn9vQswwni5F9dOg30tjrW",
- "tag": "N/NNXOvJlvUm+UgPQVufM7w/t0dfvcdluc6qOUgRFio="
}, - "callback": {
- "encodeCompleted": {
}, - "encodeFailed": {
}
}
}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.
| id required | string An internal identifier. |
| secondary_id required | string An internal identifier. |
| token required | string Token provided by the encoding-data response callback link. |
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.
| id required | string An internal identifier. |
| secondary_id required | string An internal identifier. |
| token required | string Token provided by the encoding-data response callback link. |
| message | string |
{- "message": "Insert any error message here."
}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.
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.
GET /api.
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.
GET /api
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!
Process the bundle of cardholders in the result.
Follow the link at next.href if there is one, and repeat.
This is a common use case, described in the section on Cardholder changes. It shows how to:
That is how Gallagher's cardholder-synchronising integrations work.
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.
GET /api.
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.
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.
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.
GET /api.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.
GET /api.
Use the link at features.accessGroups.accessGroups.href to find the hrefs of access groups
you wish to add your new cardholder to.
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
↪.
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.
Find your cardholder using one of the processes above.
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.
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.
Find your cardholder using one of the processes above.
Follow the link to their details page or add fields=accessGroups to the search. That will
show all their access group memberships.
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.
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.
GET your cardholder's details page, or search with accessGroups in the field list. Either
way, you will receive all their access group memberships.
Take the array at accessGroups, rename it to remove, and put it in object called
accessGroups at the root level of a JSON object.
PATCH the cardholder with that JSON object. That will remove the cardholder from all the groups that came back in the GET.
GET /api.
Follow the link at
features.cardTypes.cardTypes.href↪ to find the href
for the new card's type.
If you want to create a card in a state other than the default, get the state from the same page.
Find the href for the cardholder using one of the search methods above.
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.
PATCH the cardholder's href according to the cardholder patch schema.
{ "@name_of_PDF": null }Find the href of your target access zone using the link at
features.cardholders.updateLocationAccessZones
↪ in the results of
GET /api.
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.
Send an HTTP POST to that
cardholder's updateLocation.href link.
accessGroups in the field
list. Either way, you will receive all their access group memberships.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:
doors block.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.
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.
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.
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.
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.
| sort | string Enum: "id" "name" "-id" "-name" Changes the sort field between database ID and name. If you prefix There are two very strong reasons to sort 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 Without quotes, a percent sign The search is always case-insensitive. Results are undefined if you do a substring search
for the empty string ( Because a plus sign The search parameters form a logical conjunction. They are ANDed
together. Therefore if you search for |
| 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 Without quotes, Searching for a blank value using Because a plus sign The search is always case-insensitive. Search parameters form a logical conjunction. They are ANDed
together. Therefore the search |
| 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 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. 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 The search is always case-insensitive. Results are undefined if you search for the empty
string ( 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 |
| 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 Use the value Use the special value Use the special value Use the special value There is a special value 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. |
{- "results": [
- {
- "id": "325",
- "firstName": "Algernon",
- "lastName": "Boothroyd",
- "shortName": "Q",
- "description": "Quartermaster",
- "authorised": true
}
],
}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.
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. |
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 |
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. |
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.
{- "firstName": "Algernon",
- "lastName": "Boothroyd",
- "shortName": "Quartermaster",
- "authorised": true,
- "@email": "user@sample.com",
- "@headshot": "/9j/4A...==",
- "personalDataDefinitions": [
- {
- "@email": {
- "notifications": true
}
}
], - "cards": [
- {
- "number": "Nick's mobile",
- "invitation": {
- "email": "nick@example.com",
- "mobile": "02123456789"
}
}
], - "accessGroups": [
- {
- "from": "2019-01-01T00:00:00Z"
}
], - "competencies": [
- {
- "enablement": "2019-01-01T00:00:00Z"
}
], - "notes": "",
- "notifications": {
- "enabled": true,
- "from": "2017-10-10T14:59:00Z",
- "until": "2017-10-17T14:59:00Z"
}, - "relationships": [
- {
}
], - "lockers": [
], - "elevatorGroups": [
- {
}, - {
- "enableCodeBlueFeatures": true
}
]
}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.
| id required | string An internal identifier. |
| 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. |
{- "id": "325",
- "firstName": "Algernon",
- "lastName": "Boothroyd",
- "shortName": "Q",
- "description": "Quartermaster",
- "authorised": true,
- "disableCipherPad": false,
- "notes": "",
- "notifications": {
- "enabled": true,
- "from": "2017-10-10T14:59:00Z",
- "until": "2017-10-17T14:59:00Z"
}, - "oidcLoginEnabled": true,
- "oidcUserId": "admin_qmaster@misix.gov.uk",
- "operatorLoginEnabled": true,
- "operatorUsername": "qmaster",
- "operatorPasswordExpired": false,
- "personalDataDefinitions": [
- {
- "@Student ID": {
- "definition": {
- "name": "Student ID",
- "id": "2356",
- "type": "string"
}, - "value": "8904640"
}
}, - {
- "@Photo": {
- "definition": {
- "name": "Photo",
- "id": "2369",
- "type": "image"
},
}
}
], - "windowsLoginEnabled": true,
- "windowsUsername": "misix.local\\qmaster",
- "lastSuccessfulAccessTime": "2004-11-18T19:21:52Z",
- "lastSuccessfulAccessZone": {
- "name": "Twilight zone"
}, - "serverDisplayName": "ruatoria.satellite.int",
- "usercode": "numeric, and write-only",
- "operatorPassword": "write-only",
- "cards": [
- {
- "number": "1",
- "cardSerialNumber": "045A5769713E80",
- "issueLevel": 1,
- "status": {
- "value": "Disabled (manually)",
- "type": "inactive"
}, - "invitation": {
- "email": "nick@example.com",
- "mobile": "02123456789",
- "singleFactorOnly": false,
- "status": "sent",
}, - "from": "2017-01-01T00:00:00Z",
- "until": "2017-12-31T11:59:59Z",
- "credentialClass": "mobile",
- "trace": false,
- "lastPrintedOrEncodedTime": "2020-08-10T09:20:50Z",
- "lastPrintedOrEncodedIssueLevel": 1,
- "lastUsedTime": "2025-09-24T14:00:00Z",
- "pin": "153624",
- "visitorContractor": false,
- "ownedBySite": false,
- "credentialId": "reserved",
- "bleFacilityId": "reserved",
- "encodingData": {
- "mifareClassic": {
- "href": "../dictionary"
}, - "mifareDesfire": {
- "href": "../dictionary"
}
}
}
], - "accessGroups": [
- {
- "accessGroup": {
- "name": "R&D special projects group",
}, - "status": {
- "value": "Pending",
- "type": "pending"
}, - "from": "2017-01-01T00:00:00Z",
- "until": "2017-12-31T11:59:59Z"
}
], - "operatorGroups": [
- {
}
], - "competencies": [
- {
- "competency": {
- "name": "Hazardous goods handling"
}, - "status": {
- "value": "Pending",
- "type": "pending"
}, - "disabled": true,
- "enabled": true,
- "expiryWarning": "2017-03-06T15:45:00Z",
- "expiry": "2017-03-09T15:45:00Z",
- "enablement": "2018-03-09T15:45:00Z",
- "comment": "CPR refresher due March.",
- "limitedCredit": true,
- "credit": 37
}
], - "relationships": [
- {
- "cardholder": {
- "name": "Miles Messervy",
- "firstName": "Miles",
- "lastName": "Messervy"
}
}
], - "lockers": [
- {
- "locker": {
- "name": "Bank A locker 1",
- "shortName": "A1",
}, - "from": "2017-01-01T00:00:00Z",
- "until": "2018-12-31T00:00:00Z"
}
], - "elevatorGroups": [
- {
- "elevatorGroup": {
- "name": "Main building lower floors"
}, - "enableCaptureFeatures": true,
- "enableCodeBlueFeatures": false,
- "enableExpressFeatures": true,
- "enableServiceFeatures": false,
- "enableService2Features": true,
- "enableService3Features": true,
- "enableVipFeatures": false
}
], - "updates": { },
- "redactions": [
- {
- "type": "normalEvents",
- "when": "2023-01-01T00:00:00Z",
- "before": "2022-01-01T00:00:00Z",
- "status": "pending",
}
], - "accessibilities": [
- {
- "type": "useExtendedAccessTime",
- "enabled": true,
- "from": "2026-08-15T21:00:00Z"
}, - {
- "type": "disableCipherPad",
- "enabled": false
}, - {
- "type": "pinExemption",
- "enabled": false
}
]
}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.
| id required | string An internal identifier. |
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 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 |
| 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. |
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.
{- "authorised": true,
- "firstName": "Erica",
- "@employeeId": "THX1139",
- "personalDataDefinitions": [
- {
- "@email": {
- "notifications": true
}
}, - {
- "@cellphone": {
- "notifications": false
}
}
], - "cards": {
- "add": [
- {
- "number": "Jock's iPhone 8",
- "status": {
- "value": "Pending sign-off"
}, - "invitation": {
- "email": "jock@example.com"
}
}
], - "update": [
- {
- "issueLevel": 2,
- "until": "",
- "status": {
- "value": "Stolen"
}, - "pin": "153624"
}
], - "remove": [
- {
- "status": {
- "value": "Lost"
}
}
]
}, - "accessGroups": {
- "add": [
],
}, - "competencies": {
- "add": [
- {
- "enabled": false,
- "enablement": "2021-01-01T08:00+13"
}
],
}, - "relationships": {
- "add": [
- {
}
], - "update": [
- {
}
]
}, - "lockers": {
- "update": [
],
}, - "operatorGroups": {
- "add": [
],
}, - "elevatorGroups": {
- "add": [
- {
}
], - "update": [
- {
- "enableCodeBlueFeatures": true,
- "enableVipFeatures": false
}
],
}
}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.
| id required | string An internal identifier. |
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.
| id required | string An internal identifier. |
| secondary_id required | string An internal identifier. |
This call removes a card from a cardholder.
You can find this URL in the cardholder object. Do not build it yourself.
| id required | string An internal identifier. |
| secondary_id required | string An internal identifier. |
This call removes a competency from a cardholder.
You can find this URL in the cardholder object. Do not build it yourself.
| id required | string An internal identifier. |
| secondary_id required | string An internal identifier. |
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.
| id required | string An internal identifier. |
| secondary_id required | string An internal identifier. |
| add required | integer The amount to adjust the competency credit. This can be positive or negative. |
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.
| id required | string An internal identifier. |
| secondary_id required | string An internal identifier. |
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.
| id required | string An internal identifier. |
| secondary_id required | string An internal identifier. |
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.
| id required | string An internal identifier. |
| secondary_id required | string An internal identifier. |
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.
| id required | string An internal identifier. |
| secondary_id required | string An internal identifier. |
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.
| id required | string An internal identifier. |
The body of the request must contain the href of the target access zone.
object |
{
}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.
| id required | string An internal identifier. |
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.
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.
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.
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.
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.
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.
Restart your polling loop using the link in next.href.
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.
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.
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.
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.
| 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
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,
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 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 |
| 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.
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 The values you can list for the cardholder block are very similar to these field
names. Prefix each with 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 |
| 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 Added in 8.80. |
{- "results": [
- {
- "time": "2020-01-14T03:14:33Z",
- "type": "update",
- "oldValues": {
- "firstName": "Craig",
- "competencies": [
]
}, - "newValues": {
- "firstName": "Gavin",
- "competencies": [
- {
- "enablement": "2020-02-29T00:00:00Z",
}
], - "cards": [
- {
- "number": "2",
- "cardSerialNumber": "",
- "issueLevel": 1,
- "from": "",
- "until": "",
}
], - "accessGroups": [
- {
- "from": "",
- "until": "2020-01-15T04:39:00Z",
}
]
}, - "cardholder": {
- "firstName": "Gavin",
- "cards": [
- {
- "number": "2",
- "cardSerialNumber": "",
- "issueLevel": 1,
- "from": "",
- "until": "",
}
]
}
}
],
}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.
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:
GET /api.features.cardTypes.cardTypes.href (which
will be to /api/card_types), orfeatures.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).credentialClass: piv, andhref.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.
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.
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.
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 |
| 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 |
| defaultExpiryFrom | any Documentation coming. TODO |
| defaultExpiryUntil | any Documentation coming. TODO (if |
| 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 |
{- "name": "Red DESFire visitor badge",
- "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
}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.
| sort | string Enum: "id" "name" "-id" "-name" Changes the sort field between database ID and name. If you prefix There are two very strong reasons to sort 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 The search is always case-insensitive. Results are undefined if you do a substring search for
the empty string ( 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 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. 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 The search is always case-insensitive. Results are undefined if you search for the empty
string ( 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. |
{- "results": [
- {
- "id": "600",
- "name": "Red DESFire visitor badge",
- "notes": "Disabled after 7d inactivity, 6-char PIN",
- "facilityCode": "A12345",
- "availableCardStates": [
- "Active",
- "Disabled (manually)",
- "Lost",
- "Stolen",
- "Damaged"
], - "credentialClass": "card",
- "minimumNumber": "1",
- "maximumNumber": "16777215",
- "serverDisplayName": "ruatoria.satellite.int",
- "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
}
],
}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.
| id required | string An internal identifier. |
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.
| id required | string An internal identifier. |
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 |
| 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 |
| defaultExpiryFrom | any Documentation coming. TODO |
| defaultExpiryUntil | any Documentation coming. TODO (if |
| 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 |
{- "name": "Red DESFire visitor badge",
- "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
}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.
| id required | string An internal identifier. |
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.
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.
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.
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!
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.
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.
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.
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.
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.
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.
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.
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.
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.
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).
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.
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.
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.
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.
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.
| sort | string Enum: "id" "name" "-id" "-name" Changes the sort field between database ID and name. If you prefix There are two very strong reasons to sort 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 The search is always case-insensitive. Results are undefined if you do a substring search for
the empty string ( 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 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. 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 The search is always case-insensitive. Results are undefined if you search for the empty
string ( 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 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. |
{- "results": [
- {
- "id": "2354",
- "name": "Hazardous goods handling",
- "description": "Required for access to chem sheds.",
- "serverDisplayName": "ruatoria.satellite.net",
- "notes": ""
}
],
}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.
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 |
{- "name": "New competency",
- "shortName": "C4",
- "description": "Translated automatically.",
- "notes": "A very long string."
}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.
| id required | string An internal identifier. |
| 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. |
{- "id": "2354",
- "name": "Hazardous goods handling",
- "description": "Required for access to chem sheds.",
- "serverDisplayName": "ruatoria.satellite.net",
- "notes": "",
- "shortName": "",
- "expiryNotify": false,
- "noticePeriod": {
- "units": "weeks",
- "number": 2
}, - "defaultExpiry": {
- "expiryType": "durationmonths",
- "expiryValue": 6
}, - "defaultAccess": "fullAccess"
}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.
| id required | string An internal identifier. |
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 |
{- "name": "New competency",
- "shortName": "C4",
- "description": "Translated automatically.",
- "notes": "A very long string."
}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.
| id required | string An internal identifier. |
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.
GET /api.
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.
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.
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.
| sort | string Enum: "id" "name" "-id" "-name" Changes the sort field between database ID and name. If you prefix There are two very strong reasons to sort 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 The search is always case-insensitive. Results are undefined if you do a substring search for
the empty string ( 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 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. |
{- "results": [
- {
- "name": "Default Day Category",
- "description": "Factory default",
- "notes": "The default calendar puts every day in this day category."
}
],
}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.
Every REST licence enables the divisions controller: RESTEvents, RESTCreateEvents, RESTCardholders, RESTStatus, RESTOverrides, and RESTConfiguration.
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.
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 |
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. |
{- "name": "Long division",
- "description": "Quatermasters",
- "notes": "A very long string.",
}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.
| 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 There are two very strong reasons to sort 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 Treat the string matches as case-sensitive. |
{- "results": [
- {
- "id": "2",
- "name": "Root division",
- "description": "Contains all other divisions",
- "serverDisplayName": "ruatoria.satellite.int",
- "visitorManagement": {
- "active": true,
- "visitorTypes": [
- {
- "accessGroup": {
- "name": "Visitor access group 1",
}, - "hostAccessGroups": [
- {
- "accessGroup": {
- "name": "Host access group 1",
}
}
], - "visitorAccessGroups": [
- {
},
]
}
]
}
}
],
}Details of a division. Follow the href in a division summary to get here.
| id required | string An internal identifier. |
| 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 Treat the string matches as case-sensitive. |
{- "id": "2",
- "name": "Root division",
- "description": "Contains all other divisions",
- "serverDisplayName": "ruatoria.satellite.int",
- "visitorManagement": {
- "active": true,
- "visitorTypes": [
- {
- "accessGroup": {
- "name": "Visitor access group 1",
}, - "hostAccessGroups": [
- {
- "accessGroup": {
- "name": "Host access group 1",
}
}
], - "visitorAccessGroups": [
- {
},
]
}
]
}
}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.
| id required | string An internal identifier. |
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 |
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. |
{- "name": "Long division",
- "description": "Quatermasters",
- "notes": "A very long string.",
}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).
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.
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.
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.
GET /api.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.next link until there isn't one.open ↪ URL in the commands structure
of the results.updates href from that page.next link to stay up to date.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.
| sort | string Enum: "id" "name" "-id" "-name" Changes the sort field between database ID and name. If you prefix There are two very strong reasons to sort 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 The search is always case-insensitive. Results are undefined if you do a substring search for
the empty string ( 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 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. 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 The search is always case-insensitive. Results are undefined if you search for the empty
string ( 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 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 |
| 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. |
{
}This returns the detail of one door.
Follow the 'href' field in a door summary to get here.
| id required | string An internal identifier. |
| 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 |
{- "id": "332",
- "name": "Front door",
- "description": "Main lobby doors.",
- "entryAccessZone": {
- "name": "Roswell building 2 lobby",
}, - "exitAccessZone": {
- "name": "Roswell building 2 cafeteria",
}, - "notes": "Multi-line text...",
- "shortName": "Short text",
- "statusFlags": [
- "secure",
- "closed",
- "locked"
], - "commands": {
}, - "connectedController": {
- "name": "Third floor C6000",
- "id": "634"
}
}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.
| id required | string An internal identifier. |
| 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. |
Sends an override to unlock a door.
Follow the commands.open.href field in a door to get here.
| id required | string An internal identifier. |
| 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. |
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.
| id required | string An internal identifier. |
| 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. |
{- "updates": {
- "status": "Closed, Locked, Secure access.",
- "statusText": "Closed, Locked, Secure access.",
- "statusFlags": [
- "closed",
- "locked",
- "secure"
]
},
}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.
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.
GET /api.features.cardholders.modifyPassengerDetails.href, appending a search term
such as name=substring to filter the selection if you have a lot of elevator groups.next link if you have lots.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.Find the href for the cardholder.
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.
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.
| sort | string Enum: "id" "name" "-id" "-name" Changes the sort field between database ID and name. If you prefix There are two very strong reasons to sort 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 The search is always case-insensitive. Results are undefined if you do a substring search for
the empty string ( 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 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. 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 The search is always case-insensitive. Results are undefined if you search for the empty
string ( 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 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 |
| 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. |
{- "results": [
- {
- "name": "Main building lower floors",
- "floorAccess": [
- {
- "floorNumber": 1,
- "frontService": true,
- "rearService": true,
- "floorName": "Level 1",
- "frontAccessZone": {
- "id": "637",
- "name": "Lvl 1 lift lobby",
}, - "rearAccessZone": {
- "id": "638",
- "name": "Lvl 1 lift lobby rear",
}
}
]
}
],
}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.
| sort | string Enum: "id" "name" "-id" "-name" Changes the sort field between database ID and name. If you prefix There are two very strong reasons to sort 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 The search is always case-insensitive. Results are undefined if you do a substring search for
the empty string ( 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 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. 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 The search is always case-insensitive. Results are undefined if you search for the empty
string ( 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 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 |
| 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. |
{- "results": [
],
}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.
| id required | string An internal identifier. |
| 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 |
{- "name": "Main building lower floors",
- "description": "Main building lobby elevator group.",
- "notes": "Multi-line text...",
- "shortName": "Short text",
- "elevatorGroupNumber": 1,
- "elevatorSystem": {
- "id": "632"
}, - "rearAccessEnabled": true,
- "groundFloorNumber": 1
}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.
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').
GET /apifeatures.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.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.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).
Get /apifeatures.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.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.GET /apifeatures.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.
GET /apifeatures.events.updates.href
↪ adding query parameters containing your search
terms. The call will block until at least one matching event arrives at the server.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.GET /apifeatures.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.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.GET /apifeatures.events.events.href ↪ appending
the query parameter after=2021-05-08Z (or whatever timestamp is appropriate).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.GET /api
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.
Extract the item ID of your cardholder or cardholders from that page, repeating as necessary for additional cardholders.
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.
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:
GET /api
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.
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.
Sleep for a short time to reduce load on the server.
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.
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.
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.
GET /apifeatures.events.events.href ↪There are some rules around creating events, so you should first have a careful read of the POST documentation.
GET /apifeatures.events.eventGroups ↪That will return all event types in their groups.
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.
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.
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 |
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.
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.
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.
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.
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!
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.
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).
An event can fire an action plan, which will
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:
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 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.
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.
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) 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 | |
required | object A new event must contain either this or 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 |
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 Cardholders cannot be event sources. To relate a cardholder to your event, use the
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. |
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.
{- "message": "Glass break detected in southwest sauna",
- "details": "Temperature dropping"
}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.
| 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 For predictable results you should also add a timezone specifier. A 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, |
| 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 The |
| 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:
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 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 Do not send |
| group | Array of strings Restricts events to those with this event group ID. Separate multiple IDs with commas.
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:
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 Example: |
| relatedItem | string Restrict events to those associated with the item that has this Command Centre ID. Separate multiple IDs with commas. Example: |
| 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 You can request 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 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. |
{- "events": [
- {
- "id": "61320",
- "serverDisplayName": "ruatoria.satellite.int",
- "time": "2016-02-18T19:21:52Z",
- "message": "Operator logon failed for FT Workstation on GNZ-PC1439",
- "occurrences": 2,
- "priority": 3,
- "source": {
- "id": "321",
- "name": "FT Workstation on GNZ-PC1439",
}, - "group": {
- "id": "35",
- "name": "Invalid Logon"
}, - "type": {
- "id": "601",
- "name": "Operator logon failed"
}, - "eventType": {
- "id": "601",
- "name": "Operator logon failed"
}, - "cardholder": {
- "id": "325",
- "name": "Bruce, Jennifer",
- "firstName": "Jennifer",
- "lastName": "Caitlin"
}, - "entryAccessZone": {
- "name": "Brookwood showroom",
- "id": "333"
}, - "exitAccessZone": {
- "name": "Compressor room",
- "id": "913"
}, - "card": {
- "facilityCode": "A12345",
- "number": "78745",
- "issueLevel": 1
}, - "modifiedItem": {
- "type": {
- "id": "1",
- "name": "Cardholder"
}
},
}
],
}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.
| 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 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 |
| 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 If you only wish to receive events up to a point in history, use the |
| source | Array of strings Restricts events to those whose source item has this ID. Separate multiple IDs with
commas. Use |
| 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 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: |
| division | string Restricts events to those in the division with this ID and its descendant divisions. Separate multiple IDs with commas. Example: |
| 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 You can request 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. |
{- "events": [
- {
- "id": "61320",
- "serverDisplayName": "ruatoria.satellite.int",
- "time": "2016-02-18T19:21:52Z",
- "message": "Operator logon failed for FT Workstation on GNZ-PC1439",
- "occurrences": 2,
- "priority": 3,
- "source": {
- "id": "321",
- "name": "FT Workstation on GNZ-PC1439",
}, - "group": {
- "id": "35",
- "name": "Invalid Logon"
}, - "type": {
- "id": "601",
- "name": "Operator logon failed"
}, - "eventType": {
- "id": "601",
- "name": "Operator logon failed"
}, - "cardholder": {
- "id": "325",
- "name": "Bruce, Jennifer",
- "firstName": "Jennifer",
- "lastName": "Caitlin"
}, - "entryAccessZone": {
- "name": "Brookwood showroom",
- "id": "333"
}, - "exitAccessZone": {
- "name": "Compressor room",
- "id": "913"
}, - "card": {
- "facilityCode": "A12345",
- "number": "78745",
- "issueLevel": 1
}, - "modifiedItem": {
- "type": {
- "id": "1",
- "name": "Cardholder"
}
},
}
],
}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.
| id required | string An internal identifier. |
| 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 You can request 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. |
{- "id": "61320",
- "serverDisplayName": "ruatoria.satellite.int",
- "time": "2016-02-18T19:21:52Z",
- "message": "Operator logon failed for FT Workstation on GNZ-PC1439",
- "occurrences": 2,
- "priority": 3,
- "source": {
- "id": "321",
- "name": "FT Workstation on GNZ-PC1439",
}, - "group": {
- "id": "35",
- "name": "Invalid Logon"
}, - "type": {
- "id": "601",
- "name": "Operator logon failed"
}, - "eventType": {
- "id": "601",
- "name": "Operator logon failed"
}, - "cardholder": {
- "id": "325",
- "name": "Bruce, Jennifer",
- "firstName": "Jennifer",
- "lastName": "Caitlin"
}, - "entryAccessZone": {
- "name": "Brookwood showroom",
- "id": "333"
}, - "exitAccessZone": {
- "name": "Compressor room",
- "id": "913"
}, - "card": {
- "facilityCode": "A12345",
- "number": "78745",
- "issueLevel": 1
}, - "modifiedItem": {
- "type": {
- "id": "1",
- "name": "Cardholder"
}
}, - "lastOccurrenceTime": "2016-02-18T19:21:59Z",
- "details": "Originating IP address: 192.168.2.3",
- "location": {
- "type": "moved",
- "beforeLocation": {
- "name": "Lvl 1 lift lobby",
- "canonicalTypeName": "accesszone"
}, - "afterLocation": {
- "outside": true
}
}
}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:
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.
{- "eventGroups": [
- {
- "id": "35",
- "name": "Invalid Logon",
- "eventTypes": [
- {
- "id": "601",
- "name": "Operator logon failed"
}, - {
- "id": "20065",
- "name": "Terminal: Invalid User Code"
}, - {
- "id": "23052",
- "name": "Wrong Code only Code"
}
]
}
]
}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.
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.
GET /api.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.next link until there isn't one.commands structure of the results, such as
off, highVoltage, or shunt, from the detail.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.next link to stay up to date.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.
| sort | string Enum: "id" "name" "-id" "-name" Changes the sort field between database ID and name. If you prefix There are two very strong reasons to sort 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 The search is always case-insensitive. Results are undefined if you do a substring search for
the empty string ( 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 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. 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 The search is always case-insensitive. Results are undefined if you search for the empty
string ( 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 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 |
| 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. |
{- "results": [
],
}This returns the detail of one fence zone.
Follow the 'href' field in a fence zone summary to get here.
| id required | string An internal identifier. |
| 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 |
{- "id": "8487",
- "name": "Storage yard",
- "description": "Trailers and pallets.",
- "voltage": 7300,
- "notes": "Multi-line text...",
- "shortName": "Short text",
- "statusFlags": [
- "on",
- "highVoltage",
- "voltageKnown"
], - "connectedController": {
- "name": "Fourth floor C7000",
- "id": "634"
}, - "commands": {
}
}Sends an override to an alarm zone to turn it on until the next scheduled or manual change.
| id required | string An internal identifier. |
| 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. |
Sends an override to an alarm zone to turn it off until the next scheduled or manual change.
| id required | string An internal identifier. |
| 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. |
Sends an override to an alarm zone to shunt it, effectively preventing all communication with it.
| id required | string An internal identifier. |
| 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. |
Sends an override to an alarm zone to unshunt it, re-enabling its communication.
| id required | string An internal identifier. |
| 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. |
Sends an override to an alarm zone to change it to high voltage mode until the next scheduled or manual change.
| id required | string An internal identifier. |
| 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. |
Sends an override to an alarm zone to change it to 'low feel' mode until the next scheduled or manual change.
| id required | string An internal identifier. |
| 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. |
Cancels an active override.
| id required | string An internal identifier. |
| 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. |
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.
| id required | string An internal identifier. |
| 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. |
{- "updates": {
- "status": "On - HV.",
- "statusText": "On - HV.",
- "statusFlags": [
- true,
- "highVoltage"
], - "voltage": 7300
},
}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.
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.
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.
GET /api.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.next link if there is one.commands structure of the
results.updates ↪ href from that page.next link to stay up to date.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.
| sort | string Enum: "id" "name" "-id" "-name" Changes the sort field between database ID and name. If you prefix There are two very strong reasons to sort 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 The search is always case-insensitive. Results are undefined if you do a substring search for
the empty string ( 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 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. 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 The search is always case-insensitive. Results are undefined if you search for the empty
string ( 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 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. |
{- "results": [
],
}This returns the detail of one input.
Follow the 'href' field in an input summary to get here.
| id required | string An internal identifier. |
| 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. |
{- "id": "9701",
- "name": "Studio door open sensor",
- "description": "Reed switch.",
- "shortName": "Short text",
- "notes": "Multi-line text...",
- "statusFlags": [
- "open"
], - "connectedController": {
- "name": "Fourth floor C7000",
- "id": "634"
}, - "commands": {
}
}Sends an override to shunt an input, preventing all communication.
| id required | string An internal identifier. |
| 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. |
Sends an override to unshunt an input, re-enabling communication.
| id required | string An internal identifier. |
| 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. |
Sends an override to isolate an input. An isolated input will not prevent an alarm zone from arming.
| id required | string An internal identifier. |
| 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. |
Sends an override to end the isolation of an input.
| id required | string An internal identifier. |
| 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. |
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.
| id required | string An internal identifier. |
| 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. |
{- "updates": {
- "status": "This Input is Open-Circuit Tampered.",
- "statusText": "This Input is Open-Circuit Tampered.",
- "statusFlags": [
- "open",
- "tamper"
]
},
}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.
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'.
GET /api.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.next link if there is one.fields=name,id.updates href from that page.next link to stay up to date.commands structure
of the results.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.
| sort | string Enum: "id" "name" "-id" "-name" Changes the sort field between database ID and name. If you prefix There are two very strong reasons to sort 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 The search is always case-insensitive. Results are undefined if you do a substring search for
the empty string ( 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 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. 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 The search is always case-insensitive. Results are undefined if you search for the empty
string ( 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 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. |
{- "results": [
],
}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.
| id required | string An internal identifier. |
| 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. |
{- "name": "Excercise yard egress",
- "id": "122322",
- "description": "Exercise yard egress.",
- "shortName": "Short text",
- "notes": "Multi-line text...",
- "statusFlags": [
- "secure"
], - "statusText": "All doors in the group are in a Secure state.",
- "status": "All doors in the group are in a Secure state.",
- "connectedController": {
- "name": "Fourth floor C7000",
- "id": "634"
}, - "commands": {
}
}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.
| id required | string An internal identifier. |
| 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. |
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.
| id required | string An internal identifier. |
| 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. |
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.
| id required | string An internal identifier. |
| 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. |
{- "updates": {
- "statusFlags": [
- "open"
]
},
}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.
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.
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:
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.
POST to create a subscription. Your program should
get the URL from items.updates.href in the results of GET /api.
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.
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.
Goto 4.
Every REST licence enables the items controller: RESTEvents, RESTCreateEvents, RESTCardholders, RESTStatus, and RESTOverrides.
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.
| 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 The search is always case-insensitive. Results are undefined if you do a substring search for
the empty string ( 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 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. 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 There are two very strong reasons to sort 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 The string must not contain any spaces. Just alphanumerics, underscores, commas, and dots. Treat the string matches as case-sensitive. |
{- "results": [
- {
- "id": "325",
- "name": "Brick, Eva",
- "type": {
- "id": "1",
- "name": "Cardholder",
- "canonicalTypeName": "cardholder"
}
}, - {
- "id": "2707",
- "name": "Brewer, Amy",
- "type": {
- "id": "1",
- "name": "Cardholder",
- "canonicalTypeName": "cardholder"
}
}
],
}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.
| id required | string The ID of the item. |
| 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 The string must not contain any spaces. Just alphanumerics, underscores, commas, and dots. Treat the string matches as case-sensitive. |
{- "id": "325",
- "name": "Brick, Eva",
- "type": {
- "id": "1",
- "name": "Cardholder",
- "canonicalTypeName": "cardholder"
}, - "serverDisplayName": "ruatoria.satellite.int",
- "notes": "Multi-line text...",
- "href": "string",
}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.
{- "itemTypes": [
- {
- "id": "1",
- "name": "Cardholder",
- "canonicalTypeName": "cardholder"
}, - {
- "id": "2",
- "name": "Access Group",
- "canonicalTypeName": "accessgroup"
}
]
}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:
...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.
| 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. |
{- "updates": [
- {
- "id": "508",
- "status": "Controller offline. 62 message(s) pending.",
- "statusText": "Controller offline.\n62 message(s) pending.",
- "statusFlags": [
- "controllerOffline"
]
}, - {
- "id": "526",
- "status": "Disarmed.",
- "statusText": "Disarmed.",
- "statusFlags": [
- "disarmed"
]
}
],
}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.
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 |
{- "itemIds": [
- "508",
- "526"
]
}{- "updates": [
- {
- "id": "508",
- "status": "Controller offline. 62 message(s) pending.",
- "statusText": "Controller offline.\n62 message(s) pending.",
- "statusFlags": [
- "controllerOffline"
]
}, - {
- "id": "526",
- "status": "Disarmed.",
- "statusText": "Disarmed.",
- "statusFlags": [
- "disarmed"
]
}
],
}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.
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.
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.
| id required | string An internal identifier. |
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. |
{- "hasFault": false,
- "customStatusText": "Disk 87% full"
}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.
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.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.
GET /apifeatures.lockerBanks.lockerBanks.href
↪, adding a search term to the query to thin out the
results.The results of that query are the locker bank detail.
Find the href of the locker, as above. Normally one that does not have someone already allocated.
Find the href of the cardholder using the cardholders API.
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.
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.
GET /apifeatures.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.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).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.
| sort | string Enum: "id" "name" "-id" "-name" Changes the sort field between database ID and name. If you prefix There are two very strong reasons to sort 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 The search is always case-insensitive. Results are undefined if you do a substring search for
the empty string ( 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 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. 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 The search is always case-insensitive. Results are undefined if you search for the empty
string ( 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 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 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. |
{- "results": [
- {
- "name": "Lobby",
- "description": "Behind reception",
}, - {
- "name": "Bank A",
- "description": "Level 4 east A",
}
],
}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.
| id required | string An internal identifier. |
| 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. |
{- "name": "Lobby",
- "description": "Behind reception",
- "lockers": [
- {
- "name": "Lobby locker 1",
- "shortName": "L1",
- "description": "Wheelchair-suitable",
- "assignments": [
- {
- "from": "2018-01-01T00:00:00Z",
- "until": "2020-01-01T00:00:00Z"
}, - {
- "from": "2018-04-01T05:00:00Z",
- "until": "2018-04-07T00:00:00Z"
}
], - "commands": {
}
}, - {
- "name": "Lobby locker 2",
- "shortName": "L2",
- "description": "Faulty USB charging port",
- "assignments": [
- {
- "from": "1999-11-08T00:00:00Z",
- "until": "2002-11-20T00:00:00Z"
}
], - "commands": {
}
}
]
}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} .
| id required | string An internal identifier. |
| 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. |
{- "name": "Lobby locker 1",
- "shortName": "L1",
- "description": "Wheelchair-suitable",
- "notes": "string",
- "connectedController": {
- "name": "Fourth floor C7000",
- "id": "634"
}, - "assignments": [
- {
- "from": "2018-01-01T00:00:00Z",
- "until": "2020-01-01T00:00:00Z"
}, - {
- "from": "2018-04-01T05:00:00Z",
- "until": "2018-04-07T00:00:00Z"
}
], - "commands": {
},
}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.
| id required | string An internal identifier. |
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.
| id required | string An internal identifier. |
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.
| id required | string An internal identifier. |
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.
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.
closed meaning that the macro is running.GET /api.features.macros.macros.href
↪, appending a search term (described below) to
narrow the results if your installation has a lot of macros.next link until there isn't one.commands.run.href. POST to that to run the macro.
No body required.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.
| sort | string Enum: "id" "name" "-id" "-name" Changes the sort field between database ID and name. If you prefix There are two very strong reasons to sort 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 The search is always case-insensitive. Results are undefined if you do a substring search for
the empty string ( 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 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. 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 The search is always case-insensitive. Results are undefined if you search for the empty
string ( 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 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 |
| 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. |
{
}This returns the detail of one macro.
Follow the 'href' field in an macro summary to get here.
| id required | string The ID of the macro. |
| 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 |
{- "id": "8492",
- "name": "Arm lobby",
- "description": "Arms and secures all lobby zones.",
- "shortName": "Short text",
}Sends a run request to a macro.
| id required | string The ID of the macro. |
| 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. |
An operator group is like an access group in that:
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.
These are practically identical to the operations you'd perform on an access group, simplified because of the lack of lineage.
GET /api.
Follow the link at features.operatorGroups.operatorGroups.href
↪ (adding search terms, and setting top
high to save pagination). 3. Find your operator group.
The link at cardholders returns the cardholders who have membership of your group.
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.
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.
| sort | string Enum: "id" "name" "-id" "-name" Changes the sort field between database ID and name. If you prefix There are two very strong reasons to sort 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 The search is always case-insensitive. Results are undefined if you do a substring search for
the empty string ( 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 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. 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 The search is always case-insensitive. Results are undefined if you search for the empty
string ( 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. |
{- "results": [
- {
- "name": "Locker admins.",
- "serverDisplayName": "ruatoria.satellite.int"
}
],
}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.
| id required | string An internal identifier. |
| 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. |
{- "name": "Locker admins.",
- "serverDisplayName": "ruatoria.satellite.int",
- "description": "For managing locker assignments.",
- "divisions": [
]
}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).
| id required | string An internal identifier. |
| 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
|
{- "cardholders": [
- {
}, - {
- "cardholder": {
- "name": "Miles Messervy"
}
}
]
}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.
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'.
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.
GET /api.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.next link until there isn't one.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.until in their command block keys require a JSON
object in the body; the others expect it empty.updates ↪ href from that page.next link to stay up to date.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.
| sort | string Enum: "id" "name" "-id" "-name" Changes the sort field between database ID and name. If you prefix There are two very strong reasons to sort 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 The search is always case-insensitive. Results are undefined if you do a substring search for
the empty string ( 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 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. 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 The search is always case-insensitive. Results are undefined if you search for the empty
string ( 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 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 |
| 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. |
{- "results": [
],
}This returns the detail of one output.
Follow the 'href' field in an output summary to get here.
| id required | string An internal identifier. |
| 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 |
{- "id": "2365",
- "name": "Studio door red/green",
- "description": "Red or green, controlled from sound desk.",
- "shortName": "Short text",
- "notes": "Multi-line text...",
- "statusFlags": [
- "open",
- "overridden"
], - "connectedController": {
- "name": "Fourth floor C7000",
- "id": "634"
}, - "commands": {
}
}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.
| id required | string An internal identifier. |
| 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. |
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> |
{- "endTime": "2018-07-31T00:00:00Z"
}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.
| id required | string An internal identifier. |
| 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. |
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.
| id required | string An internal identifier. |
| 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. |
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> |
{- "endTime": "2018-07-31T00:00:00Z"
}Cancels an override, returning the output to its previous state.
| id required | string An internal identifier. |
| 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. |
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.
| id required | string An internal identifier. |
| 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. |
{- "updates": {
- "status": "This Output is Off.",
- "statusText": "This Output is Off.",
- "statusFlags": [
- "open"
]
},
}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.
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.
accessGroups added to the query's fields parameter.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.
GET /apifeatures.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.You do that by PATCHing a cardholder with a field named after the PDF following an '@'.
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.
| sort | string Enum: "id" "name" "-id" "-name" Changes the sort field between database ID and name. If you prefix There are two very strong reasons to sort 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 The search is always case-insensitive. Results are undefined if you do a substring search for
the empty string ( 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 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. 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 The search is always case-insensitive. Results are undefined if you search for the empty
string ( 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 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. |
{- "results": [
- {
- "name": "email",
- "id": "5516"
}, - {
- "name": "cellphone",
- "id": "9998",
- "serverDisplayName": "ruatoria.satellite.int"
}
],
}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.
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 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 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 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 New in 8.50. Deprecated in 8.70 by |
| 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 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. |
{- "name": "email",
- "description": "Corporate mailbox",
- "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
}This returns details for a PDF definition. Follow the href in the summary to get here, rather than building it yourself.
| id required | string An internal identifier. |
| 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 Treat the string matches as case sensitive. |
{- "id": "string",
- "name": "email",
- "serverDisplayName": "ruatoria.satellite.int",
- "description": "Corporate mailbox",
- "type": "email",
- "default": "contact@example.com",
- "required": false,
- "unique": false,
- "defaultAccess": "fullAccess",
- "operatorAccess": "fullAccess",
- "sortPriority": 50,
- "accessGroups": [
- {
- "name": "All Staff"
},
], - "notificationDefault": false,
- "regex": ".*@.*",
- "regexDescription": "@ least",
- "imageWidth": 600,
- "imageHeight": 800,
- "imageFormat": "jpg",
- "contentType": "image/jpeg",
- "isProfileImage": false
}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.
| id required | string An internal identifier. |
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 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 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 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 New in 8.50. Deprecated in 8.70 by |
| 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 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. |
{- "name": "email",
- "description": "Corporate mailbox",
- "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
}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.
| id required | string An internal identifier. |
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.
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:
GET /api.features.cardTypes.cardTypes.href (which
will be to /api/card_types), orfeatures.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).credentialClass: piv, andhref.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.
GET /api. The link is at features.cardholders.cardholders.href.
See the main cardholder documentation, particularly the section on searching cardholders.
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.
fields parameter.This shows how to create a cardholder with a PIV card.
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. |
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",
- "cards": [
- {
- "number": "47000256001337111234567890199991",
- "status": {
- "value": "active"
}, - "pivData": {
- "chuid": {
- "hash": "NSBvmBxA8zXz+dScJoYNLb96YMHEZXGghGirRJxWVhE=",
- "fascn": "47000256001337111234567890199991",
- "orgIdentifier": "",
- "duns": ""
}, - "pivStatus": {
- "type": "Normal"
}, - "contentSigningCert": "MIIE[...]Kltk=",
- "cardAuthenticationCert": "MIIE[...]e5mE=",
- "pivAuthenticationCert": "MIIE[...]wkrp",
- "fingerprints": "N7[...]Shpd="
}
}
]
}This shows how to update a cardholder's PIV cards.
| id required | string An internal identifier. |
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 |
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.
{- "cards": {
- "update": [
- {
- "status": {
- "value": "disabled (manually)"
}, - "pivData": {
- "pivStatus": {
- "type": "notChecked"
}
}
}
]
}
}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.
| id required | string An internal identifier. |
{- "cards": [
- {
- "number": "3165-4313-245789-098765432113456799",
- "issueLevel": 1,
- "status": {
- "value": "Not Trusted",
- "type": "inactive"
}, - "pivData": {
- "chuid": {
- "hash": "NSBvmBxA8zXz+dScJoYNLb96YMHEZXGghGirRJxWVhE=",
- "fascn": "47000256001337111234567890199991",
- "orgIdentifier": "",
- "duns": ""
}, - "lastCheckTime": "2018-04-26T00:22:05Z",
- "pivStatus": {
- "type": "Normal"
}, - "contentSigningCert": "MIIE[...]Kltk=",
- "cardAuthenticationCert": "MIIE[...]e5mE=",
- "pivAuthenticationCert": "MIIE[...]wkrp",
- "fingerprints": "N7[...]Shpd="
}
}
]
}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.
GET /apifeatures.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.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.
| sort | string Enum: "id" "name" "-id" "-name" Changes the sort field between database ID and name. If you prefix There are two very strong reasons to sort 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 The search is always case-insensitive. Results are undefined if you do a substring search for
the empty string ( 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 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. 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 The search is always case-insensitive. Results are undefined if you search for the empty
string ( 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 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. |
{- "results": [
],
}This returns details for a reception. Follow the href in the summary to get here, rather than building it yourself.
| id required | string An internal identifier. |
| 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 Treat the string matches as case sensitive. |
{- "name": "Main lobby",
- "serverDisplayName": "ruatoria.satellite.int",
- "description": "Security foyer in B1",
- "defaultVisitorType": {
}, - "notes": "string"
}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.
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.
This returns all cardholders' redactions. Paginated.
| 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 |
| pos | integer Reserved for internal use. You may see it in URLs you receive from the server, but you must never add it yourself. |
{- "results": [
- {
- "type": "normalEvents",
- "when": "2023-01-01T00:00:00Z",
- "before": "2022-01-01T00:00:00Z",
- "status": "pending",
- "finished": "2022-01-01T00:00:00Z",
- "message": "Invalid cardholder",
- "details": ""
}
],
}Schedules a cardholder redaction.
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. |
{- "type": "normalEvents",
- "before": "2022-01-01T00:00:00Z",
- "when": "2023-01-01T00:00:00Z"
}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.
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.
GET /apifeatures.roles.roles.href ↪ after adding
search terms such as name="supervisor".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.
| sort | string Enum: "id" "name" "-id" "-name" Changes the sort field between database ID and name. If you prefix There are two very strong reasons to sort 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 The search is always case-insensitive. Results are undefined if you do a substring search for
the empty string ( 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 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. 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 The search is always case-insensitive. Results are undefined if you search for the empty
string ( 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. |
{- "results": [
- {
- "name": "Contract manager",
- "serverDisplayName": "ruatoria.satellite.int"
}
],
}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.
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. |
{- "name": "Supervisor",
- "description": "aka floor manager",
- "enableCompetencyExpiryWarnings": false,
- "enableCardExpiryWarnings": true
}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.
| id required | string An internal identifier. |
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. |
{- "name": "Supervisor",
- "description": "aka floor manager",
- "enableCompetencyExpiryWarnings": false,
- "enableCardExpiryWarnings": true
}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.
| id required | string An internal identifier. |
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.
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.
| sort | string Enum: "id" "name" "-id" "-name" Changes the sort field between database ID and name. If you prefix There are two very strong reasons to sort 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 The search is always case-insensitive. Results are undefined if you do a substring search for
the empty string ( 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 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. 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 The search is always case-insensitive. Results are undefined if you search for the empty
string ( 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 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. |
{- "results": [
],
}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.
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:
|
object This block contains a string field 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 In the body of your POST:
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 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:
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. |
{- "name": "Default Access Zone Secure",
- "description": "Secure 24/7",
- "notes": "Multi-line text...",
- "type": {
- "type": "accessZoneSchedule"
}, - "dayCategories": [
- {
- "dayCategory": {
- "name": "Default Day Category"
}, - "times": [
- {
- "time": "00:00",
- "state": [
- "secure",
- "usePin"
]
}, - {
- "time": "07:30",
- "state": [
- "secure"
]
}, - {
- "time": "18:00",
- "state": [
- "secure",
- "usePin"
]
}
]
}, - {
- "dayCategory": {
- "name": "Weekends and holidays"
}, - "times": [
- {
- "time": "00:00",
- "state": [
- "secure",
- "usePin"
]
}
]
}
]
}This returns the detail of one schedule.
Follow the 'href' field in an schedule summary to get here.
| id required | string The ID of the schedule. |
| 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. |
{- "name": "Default Access Zone Secure",
- "description": "Secure 24/7",
- "notes": "Multi-line text...",
- "type": {
- "type": "accessZoneSchedule"
}, - "dayCategories": [
- {
- "dayCategory": {
- "name": "Default Day Category"
}, - "times": [
- {
- "time": "00:00",
- "state": [
- "secure",
- "usePin"
]
}, - {
- "time": "07:30",
- "state": [
- "secure"
]
}, - {
- "time": "18:00",
- "state": [
- "secure",
- "usePin"
]
}
]
}, - {
- "dayCategory": {
- "name": "Weekends and holidays"
}, - "times": [
- {
- "time": "00:00",
- "state": [
- "secure",
- "usePin"
]
}
]
}
], - "scheduledItems": [
]
}Modifies a schedule according to the body of the PATCH.
Added in 8.50.
| id required | string The ID of the schedule. Do not add it yourself: you will receive this URL from other API calls. |
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:
|
object This block contains a string field 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 In the body of your POST:
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 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:
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. |
{- "name": "Default Access Zone Secure",
- "description": "Secure 24/7",
- "notes": "Multi-line text...",
- "type": {
- "type": "accessZoneSchedule"
}, - "dayCategories": [
- {
- "dayCategory": {
- "name": "Default Day Category"
}, - "times": [
- {
- "time": "00:00",
- "state": [
- "secure",
- "usePin"
]
}, - {
- "time": "07:30",
- "state": [
- "secure"
]
}, - {
- "time": "18:00",
- "state": [
- "secure",
- "usePin"
]
}
]
}, - {
- "dayCategory": {
- "name": "Weekends and holidays"
}, - "times": [
- {
- "time": "00:00",
- "state": [
- "secure",
- "usePin"
]
}
]
}
]
}GET /apifeatures.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.features.visits.visits.href ↪ (in the
payload of the GET /api you did for the first step).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.
| sort | string Enum: "id" "name" "-id" "-name" Changes the sort field between database ID and name. If you prefix There are two very strong reasons to sort 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 The search is always case-insensitive. Results are undefined if you do a substring search for
the empty string ( 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 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. 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 The search is always case-insensitive. Results are undefined if you search for the empty
string ( 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 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. |
{- "results": [
- {
- "name": "Visit hosted by Greta Ginger",
- "serverDisplayName": "ruatoria.satellite.int",
- "description": "Initial scoping",
- "visitorType": {
}, - "from": "1971-03-08T14:35:00Z",
- "until": "2021-03-08T14:35:00Z",
- "location": "Gather in Ginger's office",
- "visitorAccessGroups": [
], - "visitors": [
- {
- "status": {
- "value": "Expected Back",
- "type": "expectedBack"
}, - "invitation": "text to be encoded into a QR code for 940"
}, - {
- "status": {
- "value": "On-Site",
- "type": "onSite"
}, - "invitation": "text to be encoded into a QR code for 9040"
}
]
}
],
}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:
from)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.
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
|
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 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
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 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 Not only are they both required when you create a visit, but the server will insist that
You can use short forms such as |
| until required | string <date-time> Every visit has a validity period, defined by start and end times called Not only are they both required when you create a visit, but the server will insist that
You can use short forms such as |
| 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 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 The The 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
Also do not bother sending a When you send a visitor block in a PATCH to edit an existing visit, the server expects it to
contain an array called 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. |
{- "name": "Visit hosted by Greta Ginger",
- "description": "Initial scoping",
- "from": "1962-12-06T14:35:00Z",
- "until": "2025-08-15T23:00:00Z",
- "location": "Gather in Ginger's office",
- "visitorAccessGroups": [
], - "visitors": [
]
}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.
| id required | string An internal identifier. |
| 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 Treat the string matches as case sensitive. |
{- "name": "Visit hosted by Greta Ginger",
- "serverDisplayName": "ruatoria.satellite.int",
- "description": "Initial scoping",
- "visitorType": {
}, - "from": "1971-03-08T14:35:00Z",
- "until": "2021-03-08T14:35:00Z",
- "location": "Gather in Ginger's office",
- "visitorAccessGroups": [
], - "visitors": [
- {
- "status": {
- "value": "Expected Back",
- "type": "expectedBack"
}, - "invitation": "text to be encoded into a QR code for 940"
}, - {
- "status": {
- "value": "On-Site",
- "type": "onSite"
}, - "invitation": "text to be encoded into a QR code for 9040"
}
]
}Changes an existing visit.
Follow the href in a visit item to get here rather than building the URL yourself.
New to 8.50.
| id required | string An internal identifier. |
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
| |
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 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
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 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 Not only are they both required when you create a visit, but the server will insist that
You can use short forms such as |
| until | string <date-time> Every visit has a validity period, defined by start and end times called Not only are they both required when you create a visit, but the server will insist that
You can use short forms such as |
| 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 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 The The 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
Also do not bother sending a When you send a visitor block in a PATCH to edit an existing visit, the server expects it to
contain an array called 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. |
{- "name": "Visit hosted by Greta Ginger",
- "description": "Initial scoping",
- "from": "1971-03-08T14:35:00Z",
- "until": "2023-03-08T14:35:00Z",
- "location": "Gather in Ginger's office",
- "visitorAccessGroups": {
- "add": [
], - "remove": [
]
}, - "visitors": {
- "add": [
], - "remove": [
]
}
}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.
| id required | string An internal identifier. |
| secondary_id required | string An internal identifier. |
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 |
{- "status": {
- "value": "signingIn"
}
}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.
| id required | string An internal identifier. |
| secondary_id required | string An internal identifier. |
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. |
{- "emailSubject": "Visitor arriving",
- "emailMessage": "",
- "smsMessage": "Visitor arriving"
}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.
| id required | string An internal identifier. |
| secondary_id required | string An internal identifier. |
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. |
{- "emailSubject": "Visitor arriving",
- "emailMessage": "",
- "smsMessage": "Visitor arriving"
}