This section describes the Keep by Feenicsâ„¢ Application Program Interface from the vantage point of the HTTP protocol. This section will be of particular interest to non .NET developers, for example those using PHP, Python, Node or JavaScript.
All calls to the API must be authenticated. The exception to this rule is a POST to the authentication endpoint https://api.us.acresecurity.cloud/token. A successful call to this endpoint will provide an access_token that can used for all other API calls.
The sample python script illustrates making such a call. This script imports the requests library and the built-in python package called json
to make working with JSON data easier.
A successful response (HTTP Status 200) will yield the illustrated JSON object. Take note that the access token is set to expire, in this example in 86399 seconds (1 day minus 1 second). You must claim a new access token within that time period using the supplied refresh token.
Example in PYTHON
import requests
import json
r = requests.post('https://api.us.acresecurity.cloud/token',
data = {
'grant_type':'password',
'client_id':'consoleApp',
'client_secret':'consoleSecret',
'username':'INSTANCENAME\\USERNAME',
'password':'PASSWORD',
'instance':'INSTANCENAME'}
)
result = json.loads(r.content)
access_token = result[u'access_token']
print(json.dumps(result,indent=4))
{
"access_token": "PBSWlquRR4nXpDvxLqXyCFXDdPAiRib5xasIFAHf14d6wMwVtCvJzo7Mmu14jxR3oH5M8tvMbo0W8MDQL0iRAwtpGhLJ7msqCeTFsbrOgtLkcEu8of_bzOl1ccfE-zsPNv_fcCe9izedtZWe5mztk_hRMDDXPW50QYNgbDEqpURxEHYRtjcYiBgGiLRmiYbQpwmWK2SwuZFtrQnbvOl-o9Hs2qk9hVB1eMZ3wl1ohOsOlDa6knEy0S1RJV_BVlD28hD-zF_lrYa-jXilZsCHCv2nRaADwqZ0g3OhmZT-WHSIfhEEICzh1kZj4ohy_rOQswxi1R_yORyJf2Rkjw7ItQ",
"token_type": "bearer",
"expires_in": 86399,
"refresh_token": "5bd30016a3ac160cf88835f3",
"as:client_id": "consoleApp",
"userName": "rgsc\\ralph",
"instance": "5bcde6c5a3ac1600485092a0",
".issued": "Fri, 26 Oct 2018 11:52:53 GMT",
".expires": "Sat, 27 Oct 2018 11:52:53 GMT"
}
To claim a new access token POST
to the authentication endpoint a refresh request object similar to:
Example in PYTHON
{
'refresh_token':'5bd30016a3ac160cf88835f3',
'grant_type':'refresh_token',
'client_id':'consoleApp',
'client_secret':'consoleSecret'
}
If the POST is successful (HTTP Status 200) you will receive a new access token value and new refresh token. Repeat this process within the timespan of the expire value to avoid having to prompt the user for login credentials again.
Please note the expire period may chance from 24 hours to a shorter time span. Use the supplied value in the authentication response to determine an appropriate refresh interval.
Example in PYTHON
headers = {'Authorization': 'bearer %s' % access_token}
currentInstance = requests.get('https://api.us.acresecurity.cloud/api', headers=headers)
print(json.dumps(json.loads(currentInstance.content), indent=4))
{
"$type": "Feenics.Keep.WebApi.Model.InstanceInfo, Feenics.Keep.WebApi.Model",
"FullyQualifiedDomainName": "rgsc",
"PasswordPolicy": null,
"Key": "5bcde6c5a3ac1600485092a0",
"CommonName": "Really Good Software Company",
"InFolderHref": "/api/f/5af2edd1a3ac160cb0c20901",
"InFolderKey": "5af2edd1a3ac160cb0c20901",
"Links": [
{
"$type": "Feenics.Keep.WebApi.Model.Link, Feenics.Keep.WebApi.Model",
"Relation": "Settings",
"Anchor": {
"$type": "Feenics.Keep.WebApi.Model.Anchor, Feenics.Keep.WebApi.Model",
"Href": "settings",
"Text": "Settings"
}
},
... etc ...
{
"$type": "Feenics.Keep.WebApi.Model.Link, Feenics.Keep.WebApi.Model",
"Relation": "People",
"Anchor": {
"$type": "Feenics.Keep.WebApi.Model.Anchor, Feenics.Keep.WebApi.Model",
"Href": "people",
"Text": "People"
}
},
... etc ...
"Notes": [],
"Tags": [],
"Monikers": [],
"Href": "/api/f/5bcde6c5a3ac1600485092a0"
}
Following the Restful pattern the API is designed to be navigated by code, much the same as a web site is navigated by human readers. Just as a web site has a starting point default document, so to does the Keep By Feenicsâ„¢ API. https://api.us.acresecurity.cloud/api
You must supply the access_token from the authentication request for this and all other API calls. This is supplied as an Authentication header with the bearer scheme. Notice that the you are supplying any parameters to this base end point. The InstanceInfo object that is returned was identified from the content of the access_token.
What must be observed by the non .NET developer is that the Keep by Feenicsâ„¢ object model is strongly typed. Since Javascript Object Notation (JSON) does not support a type declarations we follow the convention of naming the .NET datatype using the $type
key and suppling the two part type identifier: Feenics.Keep.WebApi.Model.{typename} Feenics.Keep.WebApi.Model
It it critical that all JSON objects supplied to the server supply the appropriate type declaration of the request will be rejected.
As descried in the BaseInfo specification all objects carry a common set of properties. For the purpose of API navigation the most important of these is the Href property and Links array.
the API consumer can construct new Resource URI values from the Href of the object in question and one of the href property of one of the Links.
For example, after getting the current instance by calling the base API endpoint we see that the relative path Href for the root instance is: /api/f/5bcde6c5a3ac1600485092a0
and that there is a People resource available.
We can construct the URL for accessing People resources from this information.
Link
object with the Relation
of People
.Anchor.Href
value to the Href
of the InstanceInfo for
/api/f/5bcde6c5a3ac1600485092a0/people
We can now issue GET and POST requests on this resource URL. A GET request will return a set of PersonInfo objects.
We can also issue a POST request to this resource URL. A POST request expects a new PersonInfo object in valid JSON format as the request body.
Every object that is returned from the API will have an HREF property. You can issue a PUT request to this relative path HRef to update an existing object. You can issue a DELETE request to this HRef to delete the object.
Verb | Outcome |
---|---|
GET | Returns an object of a specific object type to the caller |
POST | Expects a specific object type in the message body to be added to the system |
PUT | Updates a specific instance of an object in the system with new values |
DELETE | Deletes a specific instance of an object from the system |
Keep by Feenicsâ„¢ is a strongly typed API. This means that every object sent to the system or retrieved from the system will carry type information. For example a PersonInfo object retrieved from the system will have the following properties. All objects are in the Feenics.Keep.WebApi.Model
namespace, and from the .NET assembly of the same name. Therefore the 3 part name of any given object type can be constructed as: Feenics.Keep.WebApi.Model
+ .
+ TypeName + ,
+ Feenics.Keep.WebApi.Model
.
For example the $type value for an InstanceInfo object is Feenics.Keep.WebApi.Model.InstanceInfo, Feenics.Keep.WebApi.Model
More complex object types, such as the PersonInfo will have imbedded types. Consider the example. Notice that the CardAssignments
property is an array of CardAssignmentInfo objects, and that those object instances are also identified by the $type
property.
Also notice that the Addresses
property is an array of AddressInfo objects, but that each specific address is further sub-classed into MailingAddressInfo, EmailAddressInfo and PhoneInfo types.
With this strong typing in place it’s possible to POST
or PUT
any derived type of the AddressInfo to the addressing endpoint of the person.
Example in PYTHON
// Sample PersonInfo Object
{
"$type": "Feenics.Keep.WebApi.Model.PersonInfo, Feenics.Keep.WebApi.Model",
"CommonName": "Shillington, Ralph",
"InFolderKey": "5bcde6c5a3ac1600485092a0",
"CardAssignments": [
{
"PinExempt": false,
"ExpiresOn": "2019-10-22T15:03:58.825Z",
"RecordId": 1,
"$type": "Feenics.Keep.WebApi.Model.CardAssignmentInfo, Feenics.Keep.WebApi.Model",
"IsDisabled": false,
"OriginalUseCount": null,
"CurrentUseCount": 0,
"PinCode": "55566",
"HexValue": null,
"Note": null,
"AntiPassbackExempt": false,
"Href": "/api/f/5bcde6c5a3ac1600485092a0/people/5bcde6d2a3ac1600485092ed/cards/5bcde6dba3ac160048509333",
"Key": "5bcde6dba3ac160048509333",
"ManagerLevel": 1,
"ActiveOn": "2018-10-22T15:03:58.825Z",
"EncodedCardNumber": 2362,
"ExtendedAccess": false,
"DisplayCardNumber": "2362"
}
],
"Surname": "Shillington",
"GivenName": "Ralph",
"Addresses": [
{
"Province": "Ontario",
"City": "Ottawa",
"$type": "Feenics.Keep.WebApi.Model.MailingAddressInfo, Feenics.Keep.WebApi.Model",
"IsPrivate": false,
"Street": "302 - 2310 St. Laurent Blvd",
"Key": "5bcde6d2a3ac1600485092e7",
"Country": "Canada",
"PostalCode": "K1G 5H9",
"Href": "/api/f/5bcde6c5a3ac1600485092a0/people/5bcde6d2a3ac1600485092ed/addresses/5bcde6d2a3ac1600485092e7",
"Type": "Work"
},
{
"MailTo": "ralph.shillington@feenics.com",
"$type": "Feenics.Keep.WebApi.Model.EmailAddressInfo, Feenics.Keep.WebApi.Model",
"Href": "/api/f/5bcde6c5a3ac1600485092a0/people/5bcde6d2a3ac1600485092ed/addresses/5bcde6d2a3ac1600485092e9",
"Key": "5bcde6d2a3ac1600485092e9",
"IsPrivate": false,
"Type": "Work"
},
{
"$type": "Feenics.Keep.WebApi.Model.PhoneInfo, Feenics.Keep.WebApi.Model",
"Number": "16135202455",
"Href": "/api/f/5bcde6c5a3ac1600485092a0/people/5bcde6d2a3ac1600485092ed/addresses/5bcde6d2a3ac1600485092eb",
"Key": "5bcde6d2a3ac1600485092eb",
"IsPrivate": false,
"Type": "Work"
}
],
"ObjectLinks": [
{
"$type": "Feenics.Keep.WebApi.Model.ObjectLinkItem, Feenics.Keep.WebApi.Model",
"CommonName": "Really Good Software Company",
"Href": null,
"Relation": "InstanceScope",
"MetaDataBson": {
"$type": "System.Byte[], mscorlib",
"$value": ""
},
"LinkedObjectKey": "5bcde6c5a3ac1600485092a0"
},
{
"$type": "Feenics.Keep.WebApi.Model.ObjectLinkItem, Feenics.Keep.WebApi.Model",
"CommonName": "Staff Badge",
"Href": null,
"Relation": "BadgeType",
"MetaDataBson": {
"$type": "System.Byte[], mscorlib",
"$value": ""
},
"LinkedObjectKey": "5bcde6d9a3ac16004850931d"
},
{
"$type": "Feenics.Keep.WebApi.Model.ObjectLinkItem, Feenics.Keep.WebApi.Model",
"CommonName": "Management Access",
"Href": null,
"Relation": "AccessLevel",
"MetaDataBson": {
"$type": "System.Byte[], mscorlib",
"$value": ""
},
"LinkedObjectKey": "5bcde6dba3ac16004850932f"
}
]
}
The BaseInfo type has an ObjectLinks property which is an array of type ObjectLink. This is the uniform mechanism for relating objects together.
For example when a person is assigned a badge type, what is happening a new ObjectLink is being added to the person with the key of the AccessLevel being assigned. The resource URL for this relationship is constructed as follows:
Segment | Description |
---|---|
https://api.us.acresecurity.cloud | The Base address for API service |
/api/f/ | The identifier for instances in the system |
{folderKey} | the key value for the instance that contains the person |
/people/ | the identifier for the collection of people in the identified instance |
{key} | the key of value of the person that is being assigned a new access level |
/connections/ | the identifier for object connections for this person |
{relation} | the name of the relationship. For Access Levels the name must be “AccessLevel” |
? | the following segments are added to the URL as query parameters |
relatedKey={foreignKey} | the key of the foreign object - in this case the AccessLevelInfo object |
isOneToOne=false | a boolean value to identify if this relationship is one to one. In the case of access levels, it is not. A person may be assigned many access levels |
Thus to assign an access level to a person, where the key of instance is 5bd5d96af0794c509032b7f8
and person is 5bd5d98ef0794c509032b7f9
the access level is 5bd5d98ff0794c509032b7fb
then POST
to the resource URL:
https://api.us.acresecurity.cloud/api/f/5bd5d96af0794c509032b7f8/people/5bd5d98ef0794c509032b7f9/connections/AccessLevel?relatedKey=5bd5d98ff0794c509032b7fb&isOneToOne=false
To remove the same AccessLevel issue a DELETE
to
https://api.us.acresecurity.cloud/api/f/5bd5d96af0794c509032b7f8/people/5bd5d98ef0794c509032b7f9/connections/AccessLevel/5bd5d98ff0794c509032b7fb
Notice that in the case of a DELETE
the key of the AccessLevel is a part of the URL, versus the POST where the key passed as a parameter of the Connections resource URL.
While the relationship between objects is flexible for the purpose of Card Assignments the AccessLevel
relationship is mandatory.
The BadgeType
relationship will associate a specific badge type to a person. However this relationship is not observed by the service. It is used by the various Client Applications to provide default values for AccessLevels and Card Expiries. In other words changing the default expiry or access levels on a badge type will not change anything for people that are assigned that badge type. The expectation is that customer that wish to force a badge type change on existing card holders will implement a script to affect that change.