Remove owner's access to a completed inspection

Prevent users from viewing and editing inspections once they have been completed.

Removing an owner's access to their completed inspections is useful in scenarios where you want to increase data security and integrity.

For example, you may want to:

  • Safeguard the integrity of inspection records by preventing unauthorized alterations post-completion.
  • Ensure confidentiality by restricting access to sensitive results after the inspection is finalized.
  • Establish a clear audit trail, attribute responsibility, and prevent unauthorized changes to the inspection data.

📘

It's important to note that this will only remove direct user access to an inspection. If the user has access via group or site membership, their access will be maintained.

You can learn more about inspection access in this article: Give inspection access to users and groups.

Removing access can be achieved in 3 steps:

  1. Register a webhook and receive inspection completion events.
  2. Fetch the inspection document and retrieve the owner.
  3. Remove inspection user access.

Register a webhook and receive inspection completion events

SafetyCulture provides a number of webhooks for being notified when something happens on the platform. You can read more about our different webhooks and how to register them here.

In this specific scenario, only the TRIGGER_EVENT_INSPECTION_COMPLETED_STATUS event is relevant. Subscribing to it gives you all events where inspection completion is set, or unset.

curl --request POST \
     --url https://api.safetyculture.io/webhooks/v1/webhooks \
     --header 'accept: application/json' \
     --header 'authorization: Bearer {access_token}' \
     --header 'content-type: application/json' \
     --data '
{
  "trigger_events": [
    "TRIGGER_EVENT_INSPECTION_COMPLETED_STATUS"
  ],
  "url": "https://example.com"
}
'

Upon any inspection completion, your server will receive an HTTP POST request with a payload similar to the following:

{
  "webhook_id": "ed50b5c9-47a7-41e9-a06c-9e1260f16738",
  "version": "3.0.0",
  "event": {
    "date_triggered": "2023-12-07T17:13:01Z",
    "event_types": [
      "TRIGGER_EVENT_INSPECTION",
      "TRIGGER_EVENT_INSPECTION_METADATA",
      "TRIGGER_EVENT_INSPECTION_COMPLETED_STATUS"
    ],
    "triggered_by": {
      "user": "user_f2dad30f787b4b5da890655ab8ac8ddf",
      "organization": "1deba7cb-6354-4377-9c35-7ccb56180d4e"
    }
  },
  "resource": {
    "id": "audit_a5efbea09b0b4585a7f28d1a5c630519",
    "type": "INSPECTION"
  },
  "data": {
    "inspection_completed_set": {
      "complete_by": {
        "user_id": "user_f2dad30f787b4b5da890655ab8ac8ddf"
      },
      "complete_time": "2023-12-07T17:13:01.373Z",
      "site": {
        "folder_id": "c1293ede-04ca-4be5-bd90-bc6ea01360b6"
      },
      "status": {
        "is_completed": true
      }
    },
    "details": {
      "inspection_id": "audit_a5efbea09b0b4585a7f28d1a5c630519",
      "template_id": "template_6d12911d002949a7af409565cbe1653e",
      "org_id": "1deba7cb-6354-4377-9c35-7ccb56180d4e",
      "modify_time": "2023-12-07T17:13:01.559Z",
      "canonical_start_time": "2023-12-07T17:12:47.603Z",
      "score": {
        "score": 1,
        "maximum_possible_score": 2,
        "score_percentage": 50
      }
    }
  }
}

In your application, you should filter for events that contain data.inspection_completed_set. Otherwise, you will process events for inspections that have moved from "Completed" to "Incomplete".

Fetch the inspection document and retrieve the owner

Using the inspection ID provided in the event, you can retrieve the inspection owner using Get an inspection (legacy).

curl --request GET \
     --url https://api.safetyculture.io/audits/{inspection_id} \
     --header 'accept: application/json' \
     --header 'authorization: Bearer {access_token}'

This will return a payload similar to the following:

{
  "template_id": "template_6d12911d002949a7af409565cbe1653e",
  "audit_id": "audit_a5efbea09b0b4585a7f28d1a5c630519",
  "archived": false,
  "created_at": "2023-12-07T17:12:47.603Z",
  "modified_at": "2023-12-07T17:23:02.934Z",
  "audit_data": {
    "score": 1,
    "total_score": 2,
    "score_percentage": 50,
    "name": "7 Dec 2023 / Joe Bloggs",
    "duration": 612,
    "authorship": {
      "device_id": "user_f2dad30f787b4b5da890655ab8ac8ddf",
      "owner": "Joe Bloggs",
      "owner_id": "user_f2dad30f787b4b5da890655ab8ac8ddf",
      "author": "Joe Bloggs",
      "author_id": "user_f2dad30f787b4b5da890655ab8ac8ddf"
    },
    "date_completed": "2023-12-07T17:13:01.373Z",
    "date_modified": "2023-12-07T17:23:02.934Z",
    "date_started": "2023-12-07T17:12:47.000Z",
    ...
  },
  ...
}

In this payload, the value of audit_data.authorship.owner_id contains the ID of the user who created this inspection and owns it.

Remove inspection user access

With the combined information from the previous steps, you can use Remove user access to an inspection.

It's important you also provide a new owner ID who will now become the owner of this document.

curl --request DELETE \
     --url 'https://api.safetyculture.io/inspections/v1/inspections/{audit_id}/user/{owner_id}/access?new_owner_id={new_owner_id}' \
     --header 'accept: application/json' \
     --header 'authorization: Bearer {access_token}'

A complete example of this might look like this:

// https://developer.safetyculture.com/reference/authentication
const ACCESS_TOKEN = 'my-access-token';
// The template that we want to apply access revocation to
const TEMPLATE_ID = 'template_456';
// The user we want to reassign ownership to when it is removed from another user.
const NEW_OWNER_ID = 'user_abc123'

// The payload received from https://developer.safetyculture.com/reference/webhooks
async function receiveSafetyCultureWebhook(payload) {
  // Only listen to events where an inspection has been completed.
  if (!payload.data.inspection_completed_set) {
    return;
  }

  // Only listen to events for a specific template in SafetyCulture.
  if (!payload.details.template_id !== TEMPLATE_ID) {
    return;
  }
  
  const inspection_id = payload.details.inspection_id;

  // Retrieve the current owner of the inspection.
  const response = await fetch(`https://api.safetyculture.io/audits/${inspection_id}`, {
    method: 'GET',
    headers: {
      accept: 'application/json',
      authorization: `Bearer ${ACCESS_TOKEN}`
    }
  });
  const inspection = await response.json();
  const owner_id = inspection.audit_details.authorship.owner_id;

  // Reassign the ownership.
  await fetch(`https://api.safetyculture.io/inspections/v1/inspections/${inspection_id}/user/${owner_id}/access?new_owner_id=${NEW_OWNER_ID}`, {
    method: 'DELETE',
    headers: {
      accept: 'application/json',
      authorization: `Bearer ${ACCESS_TOKEN}`
    }
  });
}