API

Authentication

Authentication to the API is provided using mutual TLS. Your Culture Shift contact will sign a CSR with our private CA to be used as a client certificate.

For webhook APIs, all requests are sent over HTTPS. We will sign this request using a client TLS certificate issued by our intermediate CA, which we recommend that you verify.

Please contact your Culture Shift contact to receive our CA chain.

Data Structures

Report

The report body is structured as follows:

{
  "id": "812ef473-b4ef-4307-b54d-5718293ef2d2",
  "key": 1,
  "timestamp": "2022-09-13T15:18:30.063Z",
  "site": "reportandsupport.example.com",
  "form": "anonymous",
  "answers": [
    {
      "id": "1234",
      "question": "Role",
      "selectedOption": "Staff",
      "freeText": null,
      "attachmentUrl": null
    },
    {
      "id": "1235",
      "question": "Incident type",
      "selectedOption": "Bullying",
      "freeText": null,
      "attachmentUrl": null
    },
    {
      "id": "1236",
      "question": "Incident type",
      "selectedOption": "Other",
      "freeText": "Drink spiking",
      "attachmentUrl": null
    }
  ]
}

A report object is structured as follows:

  • id: the machine ID of the report, in the form of a UUID string (only when reading)
  • key: the human-readable ID ("key") of the report, which is an incrementing integer (only when reading)
  • timestamp: the time the report was submitted, as an ISO-8601 string
  • site: the hostname of the site that was used to submit this report
  • form: the slug identifier of the report form that was used to submit the report, for example "anonymous" or "named". The values here will vary based on your specific configuration. This ID is the same as the one that appears as part of the URL on the reporting site.
  • answers: an array of objects corresponding to the answers left on this form. If a question allows multiple answer selections to be made then the same "question" will appear multiple times once for each answer. If a question was asked, but not answered, then all the value fields will be null. The following are fields on the answer:
    • id: the unique ID for this answer as an opaque string
    • question: the short descriptive title of the question that was answered as a string
    • selectedOption: the name (string) of the option that was selected, or null if this was not a multiple choice question (or the question was not answered)
    • freeText: the contents of any free text that was entered into this field. If this is a multiple choice question which prompts user for text when selected (ie., "please specify" style questions) this is the follow-up text entered in that box.
    • attachmentUrl / attachmentBody / attachmentMimeType: if being read, the attachmentUrl is a URL to download the file. Please note that the URL will only be valid for 60 minutes once the initial API request is made. If writing, then attachmentBody should be a base-64 encoding of the file, and attachmentMimeType the MIME type of the file.

Audit Log Events

An audit log event object is structured as follows:

  • id: an opaque identifier identifying this event
  • timestamp: an ISO-8601 encoded timestamp of this event
  • eventType: a code indicating the type of event that occurred
  • eventMessage: a human-readable message for this event, which may contain additional context
  • user: an object describing the user (actor) which performed this action. It contains the following sub-fields:
    • id: the ID of the user who performed this action. If your instance is using username/password based logins, this will be a UUID corresponding to Culture Shift's internal user database. If your instance is using single sign on, then this will be in the form of InternalIdentifier_username, where the element before the _ corresponds to an internal identifier we use for your SSO integration, and after the underscore the username provided to us by the SSO system.
    • email: if known, the email address of this user. For deleted users, this will be null.
    • displayName: if known, the display name of this user. For deleted users, this will be null.

Endpoints

Submit report (PUT /reports/:id)

The PUT body should be a JSON object following the structure defined above. The ID can be any valid UUID generated by your system.

Please note that the report object must not specify the key on the report as this will be generated on submission. In addition, on the report object, attachmentUrl must not be specified and a base-64 encoded string in the attachmentBody field is expected with an attachmentMimeType also specified when attaching a file.

Upon success, a 200 OK response is returned which contains a JSON object with the following body:

{
  "key": 2
}

The key of the response correspond to the submitted report.

The following error conditions may also occur:

  • if the form or hostname fields do not correspond to a hostname that belongs to your instance of the system, or there is no form with the corresponding slug.
  • if the question field on an answer does not correspond to a known question in the system
  • if the selectedOption does not correspond to a valid option on that question (or this is specified, and this is a non-choice question)

In such event, a 400 HTTP response is made including an error message describing the validation failure.

If you submit a report with an ID that already exists in the system, then you will receive an HTTP 409 Conflict error response unless it matches identically to the report that already exists.

Please note that submitted answers do not need to match the current structure of the form. For example, you could submit a report which contains answers to a question not asked on the form (for example, if importing historical data which contains question data no longer asked). Similarly, you can submit an answer which contains an option that was deleted from your form, but the option must have existed at one point.

Read audit log (GET /audit-log)

This endpoint allows you to export the audit log from the product to be loaded into a SIEM or similar.

The following query parameters must be specified:

  • since: an ISO-8601 datetime string indicating when events should be started from
  • n: an integer indicating the number of events to return (must be no more than 500)

A JSON object is returned of the following format:

{
  "next": "https://api.reportandsupport.co.uk/audit-log?since=2022-09-13T17:20:00.000Z&n=100",
  "events": [
    {
      "id": "update-1234",
      "user": {
        "id": "300ae936-d9e8-4672-87cd-1ace092d407b",
        "displayName": "John Campbell",
        "email": "john@example.com"
      },
      "timestamp": "2022-09-13T17:18:12.521Z",
      "eventType": "ReportAssignment",
      "eventMessage": "report #586 was assigned to user Joe Bloggs"
    }
  ]
}

The next field contains a URL to the next page of data if you wish to paginate forwards. Please see the documentation for the type of audit log events for more detail on the objects in events.

Webhooks

To set up webhooks, please contact the support desk.

Webhooks are delivered with "at-least-once" semantics, within a retry window. Please note that this means you may receive more the one submission, and your receiving endpoint will be expected to handle this case. The ID field can be used as an idempotent identifier. Successful delivery is noted once a successful HTTP code is received from the server (in the 2xx range).

In the event of an unsuccessful delivery (either due to error code, or other connection issue), delivery will be reattempted up to 3 times. If delivery still fails, an email will be sent to the nominated content and the message stored on a DLQ. Please contact the Culture Shift support desk in order to request redelivery of any messages on the DLQ.

Report Submission

This webhook will make a POST request to your nominated endpoint when a new report is submitted in the system.

The report body is structured as follows:

{
  "report": {
    "id": "812ef473-b4ef-4307-b54d-5718293ef2d2",
    "key": 1,
    "timestamp": "2022-09-13T15:18:30.063Z",
    "site": "reportandsupport.example.com",
    "form": "anonymous",
    "answers": [
      {
        "id": "1234",
        "question": "Role",
        "selectedOption": "Staff",
        "freeText": null,
        "attachmentUrl": null
      },
      {
        "id": "1235",
        "question": "Incident type",
        "selectedOption": "Bullying",
        "freeText": null,
        "attachmentUrl": null
      },
      {
        "id": "1236",
        "question": "Incident type",
        "selectedOption": "Other",
        "freeText": "Drink spiking",
        "attachmentUrl": null
      }
    ]
  }
}

This is a JSON object consisting of a report object (please see the definition of a report object above).

Please note that this will be triggered in the event of the report submission endpoint being used to create a report, not just reports from end users. Please take care not to introduce loops!