This section provides a technical overview on how to interact with the API and interactive testing can be performed via our swagger documentation.
Overview
Endpoint & Versioning
All APIs are reached on the https://client-api.culture.ai endpoint with the version prefixing the API name, for example version 1 of the test API would be /v1/test.
Changes to APIs will be made iteratively unless breaking, in which case you will be notified ahead of time and in our release notes of the upcoming changes. We will always make an effort to keep our APIs backwards compatible with changes being made to new major versions only.
Authentication
Generate an API key in your administration dashboard valid for the scopes that the APIs you want to call require, then pass it in the Authorization header of your request as Basic <API KEY>. You may also restrict the IP ranges each API key can be called from, for additional security.
You can find permissions listed along with the API endpoints below.
Requests & Responses
GET request parameters can be passed via JSON or query string, but we recommend passing them as JSON with the Content-Type of application/json to work around query string length limitations. All other requests should pass their parameters in a JSON string via the request/post body.
Responses will always be made with the Content-Type set to application/json and a JSON object being returned.
Errors
Whenever an error is encountered you will receive a < 400 status code JSON response with the key error in it, describing what exactly was wrong about the request. Here are all the status codes you can expect and some example error messages:
Status code | Error message | Reason |
---|---|---|
401 |
No authentication provided Invalid authentication Authentication out of bounds |
The Authorization header has not been set. The provided API key is invalid. The provided API key is valid, but not for the given IP range. |
403 | Invalid authentication level | The API being called requires a scope that the API key is not valid for. |
400/422 | Invalid <X> | Part of the request body is invalid or malformed. |
404 | N/A | The requested API does not exist. |
405 | N/A | Incorrect HTTP verb supplied for the given API. |
500 | Service communication error | Something has gone wrong on CultureAI's side, the error will have been flagged to us but any additional context you can provide to success@culture.ai would be useful. |
Pagination & Ordering
CultureAI supports a cursor-offset hybrid pagination system, which allows you to determine the total amount of records and paginate through real time data feeds without receiving duplicates or skipping records. Ordering is not currently supported on any APIs at this early stage, but we plan to in the future.
APIs which support pagination will note the request supporting a pagination cursor, return their items inside the data key as opposed to the root of the JSON response, include a total key representing the total amount of items there is to retrieve, and (assuming there is more items to retrieve) include a nextPageCursor key which you pass as the paginationCursor on your request for the next page. You can control how many items are returned in each page with the pageSize parameter, the default is 50 and the maximum is 500.
Here is an example of a paginated request using the employee list API, we start by fetching a page of 5 employees:
GET https://client-api.culture.ai/v1/employees?pageSize=5
Accept: application/json
Authorization: Basic <API_KEY>
Which gives us a response indicating there are 11 employees total and another page from our current position:
{
"data": [
{
"id": 11123,
"name": "Test Account 1",
"email": "test1@culture.ai"
},
{
"id": 11124,
"name": "Test Account 2",
"email": "test2@culture.ai"
},
....
],
"total": 11,
"nextPageCursor": "eyJzdGFydCI6MSwibWF4SWQiOjE4MTQ3MX0="
}
To fetch the next page we make another request, identical to the first but with the parameter paginationCursor set to the value of nextPageCursor from our previous response:
GET https://client-api.culture.ai/v1/employees?pageSize=5&paginationCursor=eyJzdGFydCI6MSwibWF4SWQiOjE4MTQ3MX0
Accept: application/json
Authorization: Basic <API_KEY>
API Endpoints
Connection Testing
Tests your connection and authentication with the CultureAI API, requires no scopes. Returns minimal data about who you are authenticated as and what the read API key was for your verification.
Request
This API does not support any parameters.
GET https://client-api.culture.ai/v1/me
Accept: application/json
Authorization: Basic <API_KEY>
Response
{
"apiKey": "API_KEY",
"client": "Culture AI"
}
Get Employees
Fetches the employees you have synced, imported or manually created in access management settings.
Requires the employee.read scope.
Request
This API only supports the standard pagination parameters.
GET https://client-api.culture.ai/v1/employees
Accept: application/json
Authorization: Basic <API KEY>
Response
This API follows the standard pagination response structure, with each employee in the data array containing the following values:
Key | Type | Description |
---|---|---|
id | Integer | The unique id of the employee, used in related APIs such as fetching risk scores. |
name | String | The full name of the employee, space concatenated. |
String | The email address of the employee, used for non-SSO login, email notifications and relating things such as Slack logins, mailbox reports, etc. to the employee. |
Here is an example response:
{
"data": [
{
"id": 523163,
"name": "Test Account",
"email": "test@culture.ai"
}
....
],
"total": 52,
"nextPageCursor": "eyJzdGFydCI6NSwibWF4SWQiOjE4MTQ3MX0="
}
Employee's Risks
List employee's associated security decision, livelihood, impact and organisation risk scores from the People & Teams Dashboard.
Requires the risk.read scope.
Request
This API supports the standard pagination parameters, in addition to:
Parameter | Type | Purpose |
---|---|---|
ids | Array of employee id integers | Only fetch associated scores & risks for the given employee IDs. |
Get all users/risks:
GET https://client-api.culture.ai/v1/risks
Accept: application/json
Authorization: Basic <API_KEY>
Get risks for a subset of employees:
GET https://client-api.culture.ai/v1/risks?ids[]=12345&ids[]=678910
Accept: application/json
Authorization: Basic <API_KEY>
Response
This API follows the standard pagination response structure, with each object in the data array representing a single employee's score & risk data following the below structure:
Key | Type | Description |
---|---|---|
employeeId | Integer | The unique ID of the employee this is for. |
securityDecisionScore | Integer | An integer from 0-100 aggregating an employee's positive & negative security decisions, higher is better. |
securityDecisionScoreThreshold | String Enum (LOW/MED/HIGH) |
A string value representing what band CultureAI consider the employee's security decision score to be in. Low is good. |
overallRiskScore | Integer | An integer from 0-100 representing how much risk CultureAI estimates an employee poses to your organisation, considering security decisions, likelihood of being attacked and impact if breached. Lower is better. |
overallRiskScoreThreshold | String Enum (LOW/MED/HIGH) |
A string value representing what band of risk CultureAI consider the employee to be in. Low is good. |
likelihoodRiskScore | Integer | An integer from 0-100 representing how likely CultureAI think it is that a given employee will be attacked. Lower is better. |
likelihoodRiskScoreThreshold | String Enum (LOW/MED/HIGH) |
A string value representing what band of likelihood of attack CultureAI consider the employee to be in. Low is good. |
impactRiskScore | Integer | An integer from 0-100 representing the impact CultureAI think compromising a given employee would have on your organisation. Lower is better. |
impactRiskScoreThreshold | String Enum (LOW/MED/HIGH) |
A string value representing what band of impact on you organisation CultureAI consider the employee to be in. Low is good. |
Here is an example response:
{
"data": [
{
"employeeId": 523163,
"securityDecisionScore": 100,
"securityDecisionScoreThreshold": "LOW",
"overallRiskScore": 50,
"overallRiskScoreThreshold": "MED",
"liklihoodRiskScore": 77,
"liklihoodRiskScoreThreshold": "HIGH",
"impactRiskScore": 0,
"impactRiskScoreThreshold": "LOW"
}
...
],
"total": 52,
"nextPageCursor": "eyJzdGFydCI6NSwibWF4SWQiOjE4MTQ3MX0="
}
Behavioural Event Creation
Creates an event for a new or existing behaviour (Security decision) against a given employee, if you're creating an event for a new behaviour it must be set-up by an admin within Custom Behaviour settings before the CultureAI Platform will process the event.
Requires the behaviour.event.create scope.
Please note that behavioural event creation is a paid upgrade to your CultureAI account. If you'd be interested in trailing this, please get in touch with your account manager.
A dot implies the following key is in a sub object of the previous. So foo.bar
would have bar
in the object foo
Parameter | Type | Purpose |
---|---|---|
behaviour | Array | Provides details about the behaviour the event will be linked to |
behaviour.reference | String | Unique reference for the behaviour, used to link multiple created events to the same behaviour |
event | Array | Provides details about the event being created |
event.employee | Array | Provides linking data for the employee the event happened to, either id ot email must be provided |
event.employee.id | Optional Integer | ID of the employee the event happened to, if fetched from another API |
event.employee.email | Optional String | Case insensitive string of the employee's email address as configured in Users & Access |
event.description | Nullable String | Text giving further detail on the event, displayed under the event title within supporting event logs |
event.reference | Integer | Unique reference for the event happening within the behaviour, used to ensure event uniqueness |
event.date | String | Y-m-d formatted date string (EG: 2024-07-28 ) for the date the event happened |
event.time | Nullable String | H:i:s formatted time string (EG: 17:32:16 ) for the time on the date the event happened. The event will be displayed as date-only if this is not specified. Events with & without times can be used within the same behaviour |
event.metadata | Optional Array | Provides additional data for displaying within "Details" on supporting event logs, and for use as "Personalisation Tokens" within messages |
event.metadata.* | Array | Array of a single metadata value relating to the event |
event.metadata.*.key | String | Short name for the metadata being recorded, will be automatically converted to Title Case when displayed |
event.metadata.*.value | String | Value of the metadata being recorded, will be stored securely so PII containing values may be provided |
event.metadata.*.important | Boolean | Whether the metadata is important to describing the event, true will display the metadata key & value in the "Details" column of supporting event logs |
POST https://client-api.culture.ai/v1/risks
Accept: application/json
Authorization: Basic <API_KEY>
{
"behaviour": {
"reference": "LEAVING_DESKTOP_UNLOCKED"
},
"event": {
"employee": {
"email": "robby.rogers@culture.ai"
},
"reference": 5000,
"date": "2024-02-22",
"time": "09:58:32",
"description": "Laptop was left unlocked on longue table",
"metadata": [
{
"key": "area",
"value": "Social Lounge 1",
"important": true
},
{
"key": "spottedBy",
"value": "IT Support",
"important": false
},
{
"key": "operatingSystem",
"value": "Windows",
"important": false
}
]
}
}
Key | Type | Description |
---|---|---|
id | Nullable Integer | The unique id of the processed behaviroual event, null when the event has not been processed |
ingestionId | Integer | The unique id of the ingestion log, identifies this ingestion of an event even when the event has not been processed yet |
status | Enum | The processing status of the ingested eventPENDING_BEHAVIOUR_SETUP if the ingested event has not been processedINGESTED if the ingested event has been processed into a behavioural event |
Here is an example response when ingesting an event for a new behaviour, note how the id
is null because the event has not been processed and the status
is PENDING_BEHAVIOUR_SETUP
to indicate the event was ingested to a behaviour which has not been set-up within Custom Behaviour settings:
{
"id": null,
"ingestionId": 16,
"status": "PENDING_BEHAVIOUR_SETUP"
}
Here is an example response when ingesting an event for a behaviour which has already been set-up, the event will appear immediately in the UI with triggered processes such as Interventions & Just-in-time-education processing within a few minutes of ingestion, usually within a minute.
{
"id": 5313640,
"ingestionId": 17,
"status": "INGESTED"
}
List Email Reports
Fetches email reports from users submitted by the CultureAI reporting plugin or synchronized via integration.
Requires the triage.reports.emails.read scope.
This API supports the standard pagination parameters, in addition to:
Parameter | Type | Purpose |
---|---|---|
fromDate | Date time string (Y-m-d H:i:s) | Restrict the returned results based on the reportedAt |
GET https://client-api.culture.ai/v1/triage/reports/emails
Accept: application/json
Authorization: Basic <API_KEY>
Response
Key | Type | Description |
---|---|---|
caseId | Integer | The caseID associated with the reported email, this is a logical aggregation and shared between reports where they appear to be the same |
reportType | String | The source of the report event, this will be CULTUREAI for reports submitted via the CultureAI Outlook or Gmail plugin, or the integration such as 'MICROSOFT' |
reportTypeId | Integer | A unique reference linked to the reportType and used for retrieving further information such as the original email |
externalReference | String | Used for integration synced reports, represents the id/reference of the report in the integration (EG Microsoft Defender) |
reportedAt | String | The timestamp from when the email was reported (YYYY-mm-dd hh:mm:ss) |
isSimulated | Integer | Specifies whether the email was sent by CultureAI as part of a simulated phishing assessment. 1 if simulated, 0 if not. |
isSharedMailbox | Integer | Specifies whether the email was reported by a user from a shared mailbox (currently supported only for Microsoft 365 using the CultureAI plugin) |
recipients | Array | An array containing 'name' (string) and 'email' (string) keys for each recipient, may contain the reporter's details where no recipients are visible (e.g. if all users BCC'd) |
sender | Array | An array containing 'name' (string) and 'email' (string) keys for the sender |
subject | String | Subject of the email |
riskScore | Integer | Indicative score on risk out of 100 (higher number suggests higher risk) based on high level automated analysis |
attachments | Integer | Number of attachments in the email |
reportedBy | Array | An array containing 'id' (integer), 'name' (string), 'email' (string) for the reporting user. Id is a unique employee reference used within the CultureAI platform. |
reportReason | String | Has the reason the user reported the email (where provided), current options are 'PHISHING', 'SPAM', 'OTHER' |
interactions | Array | Array containing any interactions specified by the user, currently supports 'CLICKED'. |
Note, some fields may be returned as 'null' where the source does not provide sufficient metadata (e.g. 3rd party integration).
Here is an example response:
[
{
"caseId": 10,
"reportType": "CULTUREAI",
"reportTypeId": 406,
"externalReference": null,
"reportedAt": "2021-11-30 22:11:19",
"isSimulated": 0,
"isSharedMailbox": 0,
"recipients": [
{
"name": "Bob Smith",
"email": "bob.smith@culture.ai"
},
{
"name": "Another User",
"email": "another.user@culture.ai"
}
],
"sender": {
"name": "payroll",
"email": "urgent@thirdparty.culture.ai"
},
"subject": "Urgent: Payroll details need updating",
"riskScore": 97,
"attachments": 1,
"reportedBy": {
"id": 46,
"name": "Targeted User",
"email": "targeted.user@culture.ai"
},
"reportReason": "PHISHING",
"interactions": ['CLICKED']
}
]
Fetch Reported Email Contents
Fetches a reported email and associated metadata, only supported for the 'CULTUREAI' report source.
Requires the triage.reports.emails.detail scope.
Request
GET https://client-api.culture.ai/v1/triage/reports/emails/detail
Accept: application/json
Authorization: Basic <API_KEY>
Content-Type: application/json
{
"reportType": "CULTUREAI",
"reportTypeId": 406
}
Response
Key | Type | Description |
---|---|---|
headers | String | The headers extracted from the email |
links | Array | Returns an array of links found in the body of the main email |
body | String | The body of the email |
attachments | Array | Returns an array of attachment details 'filename' (string), 'contentType' (string), 'sha512' (string) |
raw | String | Base64 encoded version of the raw email content |
Here is an example response:
{
"headers": "Received: from ...",
"links": [
"https:\/\/app.domain.eu\/account\/profile\/u-tQ0u6I-g11j9",
"https:\/\/app.domain.eu\/monitors\/686069?to_ts=1638299909000",
"https:\/\/app.domain.eu\/monitors#686069\/edit",
"https:\/\/app.domain.eu\/event\/event?id=6275296781375450081",
"https:\/\/app.domain.eu\/account\/login\/mobile?dd_referrer=subscription_email&dd_m=1&",
"https:\/\/app.domain.eu\/account\/preferences"
],
"body": "<html><head>\r\n<meta http-equiv=\"Co...",
"attachments": [],
"raw": "UmVjZWl2ZWQ6IGZyb20gQ1dMUDEyM01CMzc3OS5HQlJ..."
}
Bug Reports & Feature Requests
If you spot anything wrong with our APIs (We're only human!) or have new features you'd like to see, or data you'd like to pull out, don't hesitate to contact us on success@culture.ai.