Last updatedSep 20, 2019

Entity properties

Entity properties allow apps to add key/value stores to Jira entities such as issues or projects, or to your Connect app itself. This page provides an overview and examples of how entity properties work.

Jira entity properties

Entity properties let you store data on the following entities:

Jira Cloud platform

Jira Software

Limitations of entity properties

Entity properties have the following limitations:

  • Entity properties can be modified by all users that have permission to edit the entity; they are not sandboxed on a per-user basis. This means that the same entity property can be edited by two different users.
  • Entity properties can be modified by all apps in the system and exist in a global namespace. We recommend that you namespace the entity property keys for the properties that you wish to be specific to your app. This also means that you should avoid storing unencrypted sensitive data in entity properties.
  • There is no mechanism to handle concurrent edits by two users to the one app property. Whomever saves data last will win.
  • The scopes that your app requires to modify entity properties are different depending on the type of entity property that you wish to modify. For example, to delete an issue entity property you only need DELETE scope. However, to delete a project entity property you require PROJECT_ADMIN scope.
  • The value stored in each property must be in valid JSON format. (Valid JSON format is defined as anything that JSON.parse can read).
  • The maximum length of an entity property key is 255 bytes.
  • The maximum length of an entity property value is 32768 bytes.

Keep these limitations in mind when you use entity properties.

Storing data against an entity with REST

The curl examples below show you how to store data against and retrieve data from an issue using REST. For information how to manipulate properties of other Jira entities, e.g. projects, please see the Jira REST API documentation.

Show me the code!

In order to modify, add or remove the properties, the user executing the request must have permission to edit the entity. For example, to add new property to issue ENPR-4, you need permission to edit the issue. To retrieve a property, the user must have read permissions for the issue.

Example 1: Storing data

The simple example below will store the JSON object {"content":"Test if works on Jira Cloud", "completed" : 1} against issue ENPR-4 with the key tasks.

1
curl -X PUT -H "Content-type: application/json" https://jira-instance1.net/rest/api/2/issue/`ENPR-4`/properties/tasks -d '{"content":"Test if works on Jira Cloud", "completed" : 1}'

The key has a maximum length of 255 characters.

The value must be a valid JSON Object and has a maximum size of 32 KB.

Example 2: Retrieving data

The example below shows how to get all of the properties stored against an issue.

1
curl -X GET https://jira-instance1.net/rest/api/2/issue/ENPR-4/properties/

The response from server will contain keys and URLs of all properties of the issue ENPR-4.

1
{"keys":[{"self":"https://jira-instance1.net/rest/api/2/issue/ENPR-4/properties/tasks","key":"tasks"}]}

Example 3: Removing a property

The example below shows how to remove a property from an issue.

1
curl -X DELETE https://jira-instance1.net/rest/api/2/issue/ENPR-4/properties/tasks

Making searchable entity properties

Atlassian Connect can provide a module descriptor, making the issue properties searchable using JQL. For example, to index the data from the first example, apps provide the following module descriptors:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
"jiraEntityProperties": [{
    "key": "jira-issue-tasklist-indexing",
    "name": {
        "value" :"Tasks index",
        "i18n": "tasks.index"
    },
    "entityType": "issue",
    "keyConfigurations": [{
        "propertyKey" : "tasks",
        "extractions" : [{
            "objectName" : "content",
            "type" : "text"
        }]
    }]
}]

The descriptor above will make Jira index the object "content" of the issue property "tasks" as a text. The available index data types are:

  • number: indexed as a number and allows for range ordering and searching on this field.
  • text: tokenized before indexing and allows for searching for particular words.
  • string: indexed as-is and allows for searching for the exact phrase only.
  • date: indexed as a date and allows for date range searching and ordering. The expected date format is [YYYY]-[MM]-[DD]. The expected date time format is [YYYY]-[MM]-[DD]T[hh]:[mm]:[ss] with optional offset from UTC: +/-[hh]:[mm] or Z for no offset. For reference, please see ISO_8601 standard.

The indexed data is available for a JQL search. The JQL query...

1
2
issue.property[tasks].completed = 1 AND 
issue.property[tasks].content ~ "works" 

...result is shown in this screenshot.

Alt text

Conditions on entity properties

Entity properties can be referenced in the following conditions to decide whether or not to show a web fragment:

  • entity_property_exists
  • entity_property_equal_to
  • entity_property_equal_to_context
  • entity_property_contains_any
  • entity_property_contains_all
  • entity_property_contains_context
  • entity_property_contains_any_user_group
  • entity_property_contains_any_user_role

You can use the entity_property_equal_to condition to decide whether or not to show a web fragment based on the data in an entity property. For example, if we had an issue entity property with the key myExtraProperties and a JSON value that has the field isSpecial set to true (JSON boolean) then we could write the following condition:

1
2
3
4
5
6
7
8
9
{
  "condition": "entity_property_equal_to",
  "params": {
      "entity": "issue",
      "propertyKey": "myExtraProperties",
      "objectName": "isSpecial",
      "value": "true"
  }
}

It is important to note that the params.value field currently expects a string. Therefore you will need to convert your JSON into a string before you can compare it for equality. For example, to check that the JSON string "special" was stored in myExtraProperties then the condition must be written like so:

1
2
3
4
5
6
7
8
9
{
  "condition": "entity_property_equal_to",
  "params": {
      "entity": "issue",
      "propertyKey": "myExtraProperties",
      "objectName": "isSpecial",
      "value": "\"special\""
  }
}

There is currently no way to get a nested value out of a JSON object stored in an entity property for the purposes of comparison in a condition.

App properties

App properties are entity properties stored against your app itself. In this case the app is considered to be the storage container. However, app properties are still unique to each host application: the same app installed on two different host applications will not share the same app properties.

Limitations of app properties

App properties have the following limitations:

  • The properties for each app are sandboxed to the app. Only the app that writes the app properties can read those properties. They cannot be shared or read by other apps.
  • Each app can create a maximum of 100 properties, each property value cannot be more than 32KB in size.
  • The value stored in each property must be in valid JSON format. (Valid JSON format is defined as anything that JSON.parse can read).
  • Requests via AP.request to store and receive app properties can only be made via a logged-in user.
  • There is no mechanism to handle concurrent edits by two users to the one app property. Whomever saves data last will win.

Warning

App properties can be manipulated by a malicious authenticated user (for example, by making REST calls through the developer console). For this reason:

  • Don't store user-specific data in app properties (particularly sensitive data).
  • Be defensive when retrieving app properties, and don't assume data consistency (arbitrary keys may be modified or deleted by users).

Supported operations

The following operations may be performed to manipulate app properties:

Examples

App properties can be set using Create or update app property:

1
2
3
4
5
6
curl --request PUT \ 
--user 'email@example.com:<api_token>' \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--data '{"string":"string-value","number":5}' \
 'https://your-domain.atlassian.net/rest/atlassian-connect/1/addons/{addonKey}/properties/{propertyKey}'

Use Get app property to get the value of the property we just set:

1
2
3
4
curl --request GET \ 
--user 'email@example.com:<api_token>' \
--header "Accept: application/json" \
 'https://your-domain.atlassian.net/rest/atlassian-connect/1/addons/{addonKey}/properties/{propertyKey}'

Here is an example that will show a pop-up with a JSON property named my-property-key for an app with the key my-app-key.

1
2
3
4
5
6
7
8
9
10
11
12
13
AP.request({
    url: '/rest/atlassian-connect/1/addons/my-app-key/properties/my-property-key?jsonValue=true',
    success: function(response) {
        // Convert the string response to JSON
        response = JSON.parse(response);
        alert(response);
    },
    error: function(response) {
        console.log("Error loading API (" + uri + ")");
        console.log(arguments);
    },
    contentType: "application/json"
});

Apart from using AP.request, the same resources are accessible via a request signed with JWT.

Conditions based on app properties

App properties can be referenced in the entity_property_equal_to, entity_property_contains_any, and entity_property_contains_all conditions to decide whether or not to show a web fragment. For example, the following is a valid condition on the app property activated:

1
2
3
4
5
6
7
8
9
{
  "condition": "entity_property_equal_to",
  "params": {
      "entity": "addon",
      "propertyKey": "activated",
      "objectName": "for-users"  
      "value": "true"
  }
}

The structure of the JSON value of the activated app property might look like this:

1
2
3
4
5
{
  "for-anonymous": false,
  "for-users": true,
  "for-admins": true,
}

Only if the for-users sub-property is set to true against the app will the condition allow the web fragment to show. Thus you can use this to decide whether or not to show web fragments based on data that you have stored in app properties. This is very useful when you have host application-wide configuration that you wish to rely upon.

Here is an example of a condition that requires the browser user to be in at least one specified group:

1
2
3
4
5
6
{
  "condition": "addon_property_contains_any_user_group",
  "params": {
      "propertyKey": "myListOfGroups"
  }
}

addon_property_contains_any_user_role is very similar to addon_property_contains_any_user_group, but references project roles in Jira.

Reference

See Entity Property reference