Skip to main content
Skip table of contents

Using the REST API with ScriptRunner

The Compliance for Confluence REST API allows you to integrate with external tools such as ScriptRunner. This allows for the implementation of more complicated automations such as applying a classification level based on a page template or label.

Prerequisites

To start using the Compliance API with ScriptRunner, you will need both a valid Compliance API key (with the appropriate scopes for the endpoints you are using) and the UUIDs for any Compliance elements you wish to interact with such as classification levels.

Compliance API Key

Requests made to the API using ScriptRunner must be authorised using an API key generated within the API Keys page of the Compliance administration area.

The key scopes will depend on the specific actions to be taken, for example classification::write is needed to set the level of a page.

Required scopes are listed in the documentation for each API endpoint.

It is recommended that the Compliance API key is stored as a Script Variable and not included directly in the script body, both to minimise risk of exposure and to allow this key to be used across multiple scripts.

CleanShot 2025-09-23 at 10.54.21-20250923-095426.png

Compliance API stored as a Script Variable

Classification Level UUIDs

While the Compliance UI shows classification names to users, the setting of a page level via the REST API requires a UUID that is not visible in UI. There are two ways to obtain these UUIDs:

  1. Use the GET /level endpoint in the Compliance API
    The easiest way to do this is directly within the API Reference page of your Compliance admin area, but could also be performed with a tool such as Postman. It will require the use of an API token with the classification::manage scope. This could also be done dynamically as part of the Script in some cases.

  2. Use the browser’s network tools in the Compliance admin area
    Inspecting the response to the graphql request that is made when opening the Classification Levels page in the Compliance admin area will allow the user to see all classification levels and their UUIDs

These UUIDs are what must be passed into the POST /page-level endpoint to set a page’s level and can be included in the script.

Using the Compliance (and Confluence) API with ScriptRunner

ScriptRunner comes with Unirest imported by default as well as the Confluence Cloud API auto-completed, and this makes it straightforward to create API requests for interacting with native Confluence endpoints. This can also be easily extended to Compliance.

Confluence API

The Confluence API can be called without a root, for example:

JAVA
get("/wiki/api/v2/pages/12345")
    .queryString("include-labels", true)
    .asJson()

This will make the request GET https://appfox.atlassian.net/wiki.api.v2/pages/12345?include-label=true.

Note that authorisation does not need to be passed into the request as it is included within ScriptRunner’s functionality.

Compliance API

Requests to the Compliance API must be more explicit in passing both authorisation and root, but can be made in much the same way, for example:

JAVA
post("https://ac-cloud.com/compliance/api/v1/page-level")
    .header("Content-Type", "application/json")
    .header("x-api-key", "${CC_API_KEY}")
    .body([pageId: pageId, levelId: classificationId])
    .asJson()

 Note the above request is referencing the CC_API_KEY Script Variable as noted earlier in the document.

Script Listeners

ScriptRunner supports automated running of scripts in two ways:

  • Script Jobs - scripts that run at set intervals

  • Script Listeners - scripts that are triggered by some action happening in Confluence

Script listeners are useful for ‘if X then Y’ automations such as classifying a page if some condition is met and appear more relevant for Compliance use cases.

Example trigger events include:

  • Page created/updated/moved/trashed

  • Attachment created/removed

  • Label added/removed

  • User created/deactivated

Depending on the resource the triggered the event, different resource information will be automatically available, but additional information can be fetched using API calls.

For example, on a page update, the page ID will be available to reference in the script, but the page content would need to be fetched separately.

CleanShot 2025-09-23 at 11.33.46-20250923-103352.png

A label-based classification script set up as a Script Listener

Example Script Listener

The below example script is designed to be created as a script listener that is triggered by page created, updated, and restored events.

This script will apply a classification level based on the page labels, with the specific label mapping listed in the script itself.

In order to use this script, the user would need to update the mapping of labels to classification levels in the classificationLabels dictionary as well as updating the names and IDs of classification levels for their instance.

This script:

  1. Gets the page ID from the trigger event

  2. Fetches the page’s labels using a separate call to the Confluence Cloud API

  3. Checks the labels listed in the script to see if any are present on the page

  4. Selects the highest classification level from the list of matched labels

  5. Applies this classification level to the page using a call to the Compliance Cloud API

To use this Script in your own instance, update the UUIDs listed in the classificationIDs dictionary to match the UUIDs for these levels in your own instance, and map your own labels in the classificationLabels array.

JAVA
import groovy.json.JsonSlurper

/*
PREREQUISITES:
- Create a Compliance for Conlfuence API key with classification write perms
    - Create this variable in ScriptRunner: in this file it is assumed to be called CC_API_KEY
- Determine all classification UUIDs using either the GET levels endpoint or browser tools
    - These should be added to the classificationIDs dictionary
- Determine labels the should be mapped to relevant classification levels
    - These should be added to the classificationLabels dictionary
*/


def pageId = page.id

// Classification label mapping
// IMPORTANT: levels must be ordered by precedence, i.e. if labels match multiple levels, the first in the list will be applied
def classificationLabels = [
    "highlyRestricted": ["confidential"]
    as Set<String>,
    "restricted": ["financial"]
    as Set<String>,
    "internal": ["product_requirements", "technical_design", "documentation", "policies"]
    as Set<String>,
    "public": ["public", "external_docs"]
    as Set<String>
]

// Classification level IDs matching the above keys
// IMPORTANT: all levels present in the classificationLabels dict MUST be present in this dict
def classificationIds = [
    "highlyRestricted": '8620aaab-35e0-47ce-b983-8434b2b849bd',
    "restricted": 'a21fbc98-9bf1-4ab4-8ffa-f9f663a9ef8f',
    "internal": 'a6563559-8772-4383-aed2-bbf1cfaae052',
    "public": 'b129b47b-b172-4678-b635-f30a8f605f87'
]

// Fetch labels for created/updated page
def response = get("/wiki/api/v2/pages/${pageId}")
        .queryString("include-labels", true)
        .asJson()

println "Status: ${response.getStatus()}"

// Apply classification based on labels
if (response.status == 200) {
    def parsedJson = new JsonSlurper().parseText("${response.body}")
    def labelMap = [:]
    def labels = parsedJson['labels']['results']

    // Create a dictionary of labels on the given page
    labels.each { label ->
        def id = label['id'] ?: ""
        def name = label['name'] ?: ""
        labelMap[id] = name
    }

    println "Labels: ${labelMap}"

    // Determine a classification to apply based on label matching
    def classificationId = checkLabelClassifications(labelMap, classificationLabels, classificationIds)
    
    if (classificationId) {
        // Classify the page if labels matched list defined in script
        sendClassificationRequest(pageId, classificationId)
    } else {
        println "No classification applied."
    }
} else {
    println "Unexpected response: ${response.body}"
}

// Determine classification for all labels combined
def checkLabelClassifications(Map labelMap, Map<String, Set<String>> classificationLabels, Map<String, String> classificationIds) {
    def labelNames = labelMap.values() as Set<String>
    for (entry in classificationLabels) {
        def key = entry.key
        def labels = entry.value
        if (labelNames.any { it in labels }) {
            return classificationIds[key]
        }
    }
    return null
}

// Send classification API request
def sendClassificationRequest(pageId, classificationId) {
    def response = post("https://ac-cloud.com/compliance/api/v1/page-level")
            .header("Content-Type", "application/json")
            .header("x-api-key", "${CC_API_KEY}")
            .body([pageId: pageId, levelId: classificationId])
            .asJson()

    println "POST Status: ${response.getStatus()}"
    if (response.status == 201) {
        println "Classification applied successfully."
    } else {
        println "Failed to apply classification: ${response.body}"
    }
}


Need support? We’re here to help 🧡

If you have any questions or would like to speak with us, please don’t hesitate to reach out to our Customer Support team.

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.