Developer
News and Updates
Get Support
Sign in
Get Support
Sign in
DOCUMENTATION
Cloud
Data Center
Resources
Sign in
Sign in
DOCUMENTATION
Cloud
Data Center
Resources
Sign in
Last updated Feb 26, 2026

Data security policy cookbook

Overview

Data security policies allow you to govern how users, apps, and people outside your organization interact with content such as Confluence pages and Jira issues. You can create policies in the Atlassian Administration or via the API. It's important to note that not all rules are available for all policy coverage types.

This guide will help you create a policy and apply it to your organization.

Explore Admin Control APIs

Before using this guide, understand how data security policy APIs work

Create a new Data Security Policy

POST /v2/orgs/{orgId}/policies This endpoint is designed to create a draft data security policy. To publish policies, see Publish data security policies.

Recommended flow:

  1. Create an ORG draft for the rule if none exists.
  2. Create a WORKSPACE, CONTAINER, or CLASSIFICATION draft.
  3. Add resources.
  4. Get policy and resources to validate.
  5. Publish via publishDraftPolicies.
  • Each policy can only have one coverage type: WORKSPACE, CLASSIFICATION, CONTAINER or ORG.
  • Each policy must contain exactly one rule, covering one of: publicLinks, page export, attachmentDownload, anonymousAccess, or appAccess, with effect set to block or allow
  • For any policy, an ORG-level policy for the rule must exist first.
    • If missing, create the org-wide draft before proceeding with other coverage levels, or you will receive a 400 error: "The draft org-wide policy does not contain the rule being overridden"
    • Only one draft override per rule, per coverage, is allowed per org. A second draft returns "Redundant draft override rule found."
    • To retry, delete existing data security drafts (e.g., DELETE /v1/orgs/{orgId}/policies/{policyId})
  • For appAccess policies:
    • The subject field must be defined.
      • Set subjectId: all_apps for overrides to the default policy, OR the app's ARI for specific apps.
      • Only CONTAINER and ORG coverage levels are supported for appAccess rules
      • A CONTAINER-level app access policy requires an existing ORG-level policy for the same subject.

Sample Request: create org-wide draft first (Required when no org-wide policy exists for the rule). Multiple rules can be added to an org-wide policy.

1
2
# Create an org-wide draft so workspace/container/classification drafts can override this rule
curl --request POST \
  --url 'https://api.atlassian.com/admin/control/v2/orgs/{orgId}/policies' \
  --header 'Authorization: Bearer <access_token>' \
  --header 'Content-Type: application/json' \
  --header 'Accept: application/json' \
  --data '{
    "data": {
      "type": "policy",
      "attributes": {
        "type": "data-security",
        "name": "Org-wide default export",
        "status": "draft",
        "metadata": { "policyCoverageLevel": "ORG" },
        "rule": { "export": { "effect": "allow" } }
      }
    }
  }'
  
# Create an org-wide draft with all rules so workspace/container/classification drafts can override this rule
curl --request POST \
  --url https://api.atlassian.com/admin/control/v2/orgs/{orgId}/policies \
  --header 'Authorization: Bearer <access_token>' \
  --header 'Content-Type: application/json' \
  --data '{
    "data": {
      "type": "policy",
      "attributes": {
        "type": "data-security",
        "name": "Org Wide policy with all rules",
        "subject": {
          "subjectType": "marketplaceApp",
          "subjectId": "all_apps"
        },
        "rule": {
          "export": {
            "effect": "allow"
          },
          "publicLinks": {
            "effect": "allow"
          },
          "anonymousAccess": {
            "effect": "allow"
          },
          "appAccess": {
            "effect": "allow"
          }
        },
        "status": "draft",
        "metadata": {
          "policyCoverageLevel": "ORG",
          "description": "Org wide with all rules allow"
        }
      }
    }
  }'

Sample Requests: create workspace/container/classification draft

1
2
# This will create a draft data security policy without any resources
curl --request POST \ 
  --url 'https://api.atlassian.com/admin/control/v2/orgs/{orgId}/policies' \
  --header 'Authorization: Bearer <access_token>' \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data '{ "data": {
        "type": "policy",
        "attributes": {
            "type": "data-security",
            "name": "test policy",
            "status": "draft",
            "metadata": {
                "policyCoverageLevel": "CLASSIFICATION",
                "description": "Some description"
            }, 
            "rule": {
                "export": {
                    "effect": "block"
                }
            }
        }
    }
}'

# App access policy with a subject
curl --request POST \ 
  --url 'https://api.atlassian.com/admin/control/v2/orgs/{orgId}/policies' \
  --header 'Authorization: Bearer <access_token>' \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data '{ "data": {
        "type": "policy",
        "attributes": {
            "type": "data-security",
            "name": "test policy",
            "status": "draft",
            "metadata": {
                "policyCoverageLevel": "CONTAINER",
                "description": "Some description"
            }, 
            "rule": {
                "appAccess": {
                    "effect": "block"
                }
            },
            "subject": {
              "subjectId": "all_apps",
              "subjectType": "marketplaceApp"
            }
        }
    }
}'

Sample Requests: create draft appAccess container coverage policy flow

1
2
# Create org-wide coverage level draft appAccess policy with subject all_apps if it doesn't already exist
# App ARI is in format ari:cloud:ecosystem::connect-app/marketplace/{appKey}. 
# To grab the appKey, go to https://{site}.atlassian.net/wiki/marketplace/discover, choose the app, and get the appKey from the URL: https://{site}.atlassian.net/wiki/marketplace/discover/app/{appKey} 
curl --request POST \
  --url 'https://api.atlassian.com/admin/control/v2/orgs/{orgId}/policies' \
  --header 'Authorization: Bearer <access_token>' \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data '{
    "data": {
      "type": "policy",
      "attributes": {
        "type": "data-security",
        "name": "test policy",
        "status": "draft",
        "metadata": {
          "policyCoverageLevel": "ORG",
          "description": "Some description"
        },
        "rule": {
          "appAccess": {
            "effect": "allow"
          }
        },
        "subject": {
          "subjectId": "all_apps",
          "subjectType": "marketplaceApp"
        }
      }
    }
  }'
  
# Create org-wide coverage level draft appAccess policy with specified app in the subject
curl --request POST \
  --url 'https://api.atlassian.com/admin/control/v2/orgs/{orgId}/policies' \
  --header 'Authorization: Bearer <access_token>' \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data '{
    "data": {
      "type": "policy",
      "attributes": {
        "type": "data-security",
        "name": "test policy",
        "status": "draft",
        "metadata": {
          "policyCoverageLevel": "ORG",
          "description": "Some description"
        },
        "rule": {
          "appAccess": {
            "effect": "allow"
          }
        },
        "subject": {
          "subjectId": "ari:cloud:ecosystem::connect-app/specific-app",
          "subjectType": "marketplaceApp"
        }
      }
    }
  }'

# Create container coverage level draft appAccess policy with specified app in the subject
curl --request POST \
  --url 'https://api.atlassian.com/admin/control/v2/orgs/{orgId}/policies' \
  --header 'Authorization: Bearer <access_token>' \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data '{
    "data": {
      "type": "policy",
      "attributes": {
        "type": "data-security",
        "name": "test policy",
        "status": "draft",
        "metadata": {
          "policyCoverageLevel": "CONTAINER",
          "description": "Some description"
        },
        "rule": {
          "appAccess": {
            "effect": "block"
          }
        },
        "subject": {
          "subjectId": "ari:cloud:ecosystem::connect-app/specific-app",
          "subjectType": "marketplaceApp"
        }
      }
    }
  }'

Sample Response

The response to this call will include a policyId; save it for the subsequent steps.

Common errors when creating policies

HTTPCode / messageCauseWhat to do
400ADMIN-400-24 — The draft org-wide policy does not contain the rule being overriddenNo org-wide policy (draft or published) exists for that ruleCreate an ORG-level draft with that rule first (e.g. export with effect: allow)
400ADMIN-400-24 — Redundant draft override rule foundA draft already exists for the same rule and coverage level (e.g. workspace + export)Delete the existing draft via DELETE /v1/orgs/{orgId}/policies/{policyId} or use a different rule/coverage
400ADMIN-400-24 — Invalid policyCoverageLevelWrong value for metadata.policyCoverageLevelUse one of: UNASSIGNED, ORG, WORKSPACE, CONTAINER, CLASSIFICATION, DC_WORKSPACE (use ORG for org-wide, not ORG_WIDE)
1
2
{
    "data": {
        "type": "policy",
        "id": "358d916a-aed3-474a-9ae0-17def3bad866",
        "attributes": {
            "id": "358d916a-aed3-474a-9ae0-17def3bad866",
            "ownerId": "706c6425-3967-42b3-a070-53ffba3102b3",
            "type": "data-security",
            "name": "test policy",
            "rule": {
                "export": {
                    "effect": "block"
                }
            },
            "status": "draft",
            "metadata": {
                "lastUpdatedBy": "ari:cloud:identity::user/8044ac9ff568615bdc7ea094",
                "createdBy": "ari:cloud:identity::user/8044ac9ff568615bdc7ea094",
                "hasHadCoverage": true,
                "systemTag": null,
                "policyCoverageLevel": "CLASSIFICATION",
                "description": "Some description"
            },
            "createdAt": "2024-04-06T02:46:56.707Z", 
            "updatedAt": "2024-04-06T02:46:56.707Z", 
            "queryData": null
        }, 
        "links": null,
        "relations": null,
        "message": null
    }
}

Add resources to the policy

POST /v2/orgs/{orgId}/policies/{policyId}/resources

Show me how to create classification levels within an org

After you create a policy, add resources to it via /resources endpoint.

Anything marked with the classification level you choose will immediately follow the policy's rules.

This API can ADD or REMOVE one or more resources to/from policies. If you need to remove all associated resources, deleting the policy with the DELETE data security policy API and starting again might be faster.

Sample Request for adding workspace

To grab the workspace resourceAri,

1
2
# Add workspaces (sites) as resources to a policy. ResourceAri is a string. Use site ARIs: ari:cloud:confluence::site/{cloudId}, ari:cloud:jira::site/{cloudId}, etc.
# To grab the cloudId, go to https://{site}.atlassian.net/_edge/tenant_info
curl --request POST \
  --url 'https://api.atlassian.com/admin/control/v2/orgs/{orgId}/policies/{policyId}/resources' \
  --header 'Authorization: Bearer <access_token>' \
  --header 'Content-Type: application/json' \
  --header 'Accept: application/json' \
  --data '[
    { 
      "operation": "ADD", 
      "resourceAri": "ari:cloud:confluence::site/4518289c-2159-48b9-a4f6-ae8f629aa2a2" 
    }, 
    { 
      "operation": "ADD", 
      "resourceAri": "ari:cloud:jira::site/1988289c-2159-48b9-a4f6-ae8f629aa2a2" 
    }
]'

Sample Response

1
2
204
No content

Sample Request for adding container

1
2
# Add containers (Confluence spaces or Jira projects) as resources. The resourceAri has format confluence:{cloudId}:space/{spaceId} or jira:{cloudId}:project/{projectId}
# To grab cloudId, go to https://{site}.atlassian.net/_edge/tenant_info
# To grab spaceId in Confluence, go to https://{site}.atlassian.net/wiki/api/v2/spaces and select the id of the space you want to attach
# To grab projectId in Jira, go to https://{site}.atlassian.net/rest/api/3/project and select the id of the project you want to attach  
curl --request POST \
  --url 'https://api.atlassian.com/admin/control/v2/orgs/{orgId}/policies/{policyId}/resources' \
  --header 'Authorization: Bearer <access_token>' \
  --header 'Content-Type: application/json' \
  --header 'Accept: application/json' \
  --data '[
    {
      "operation": "ADD",
      "resourceAri": "ari:cloud:confluence:ee3c3183-3d6e-4077-8053-676d62c40929:space/10005"
    },
    {
      "operation": "ADD",
      "resourceAri": "ari:cloud:jira:ee3c3183-3d6e-4077-8053-676d62c40929:project/10004"
    }
]'

Sample Response

1
2
204
No content

Sample Request for adding classification

1
2
# Add classification level as a resource. resourceAri is a string (platform classification-tag). The resourceAri has format: ari:cloud:platform::classification-tag/{tagId}
# To grab the tagId in Confluence: https://{site}.atlassian.net/wiki/api/v2/classification-levels
# To grab the tagId in Jira:  https://{site}.atlassian.net/rest/api/3/classification-levels
curl --request POST \
  --url 'https://api.atlassian.com/admin/control/v2/orgs/{orgId}/policies/{policyId}/resources' \
  --header 'Authorization: Bearer <access_token>' \
  --header 'Content-Type: application/json' \
  --header 'Accept: application/json' \
  --data '[
    {
      "operation": "ADD",
      "resourceAri": "ari:cloud:platform::classification-tag/28a6d272-0d95-4a81-baea-a0660f490afc"
    }
  ]'

Sample Response

1
2
204
No content

Validate the attached resources

GET /v2/orgs/{orgId}/policies/{policyId} and GET /v2/orgs/{orgId}/policies/{policyId}/resources

Before publishing, fetch the policy and its resources to confirm configuration. The resource applicationStatus should transition to applied when ready.

Sample Request

1
2
# Retrieve policy details
curl --request GET \
  --url 'https://api.atlassian.com/admin/control/v2/orgs/{orgId}/policies/{policyId}' \
  --header 'Authorization: Bearer <access_token>' \
  --header 'Accept: application/json'

Sample Response - workspace

1
2
{
  "data": [
    {
      "type": "resource",
      "id": "d653c974-8d83-4ea9-b6b7-b49e18c69391",
      "attributes": {
        "parentResourceId": "ari:cloud:platform::org/c74e07d8-ddc2-4583-a8bc-5d5405a3907a",
        "resourceId": "ari:cloud:confluence::confluence::site/4518289c-2159-48b9-a4f6-ae8f629aa2a2",
        "applicationStatus": "applied",
        "createdAt": "2024-06-23T03:55:39.128Z",
        "updatedAt": "2024-06-23T03:55:38.900Z"
      }
    },
    {
      "type": "resource",
      "id": "d653c974-8d83-4ea9-b6b7-b49e18c69391",
      "attributes": {
        "parentResourceId": "ari:cloud:platform::org/c74e07d8-ddc2-4583-a8bc-5d5405a3907a",
        "resourceId": "ari:cloud:jira::confluence::site/1988289c-2159-48b9-a4f6-ae8f629aa2a2",
        "applicationStatus": "applied",
        "createdAt": "2024-06-23T03:55:39.128Z",
        "updatedAt": "2024-06-23T03:55:38.900Z"
      }
    }
  ],
  "meta": {
    "page_size": 2,
    "next": null,
    "prev": null

  },
  "links": {
    "self": "string",
    "prev": "loremipsum-prev",
    "next": "loremipsum-next"
  }
}

Sample Response - Container

1
2
{
  "data": [
    {
      "type": "resource",
      "id": "d653c974-8d83-4ea9-b6b7-b49e18c69391",
      "attributes": {
        "parentResourceId": "ari:cloud:confluence::site/ee3c3183-3d6e-4077-8053-676d62c40929",
        "resourceId": "ari:cloud:confluence::site/ee3c3183-3d6e-4077-8053-676d62c40929/space/10005",
        "resourceName": "Test project",
        "resourceKey": "~62cf0218ec233f24684a01a1",
        "resourceStatus": "active",
        "resourceLogoUrls": {
          "default": "/images/logo/default-space-logo-256.png"
        }
        "links": null,
        "message": null
      }
    },
    {
      "type": "resource",
      "id": "d653c974-8d83-4ea9-b6b7-b49e18c69391",
      "attributes": {
        "parentResourceId": "ari:cloud:jira::site/ee3c3183-3d6e-4077-8053-676d62c40929",
        "resourceId": "ari:cloud:jira::site/ee3c3183-3d6e-4077-8053-676d62c40929/project/10003",
        "resourceName": "Test project",
        "resourceKey": "~62cf0218ec233f24684a01a1",
        "self": "https://beacon-staging.jira-dev.com/admin/private/rest/api/2/project/10000",
        "projectType": "service_desk",
        "resourceStatus": "archived",
        "resourceLogoUrls": {
          "16x16": "https://beacon-staging.jira-dev.com/admin/private/rest/api/2/universal_avatar/view/type/project/avatar/10404?size=xsmall",
          "24x24": "https://beacon-staging.jira-dev.com/admin/private/rest/api/2/universal_avatar/view/type/project/avatar/10404?size=small",
          "32x32": "https://beacon-staging.jira-dev.com/admin/private/rest/api/2/universal_avatar/view/type/project/avatar/10404?size=medium",
          "48x48": "https://beacon-staging.jira-dev.com/admin/private/rest/api/2/universal_avatar/view/type/project/avatar/10404"
        },
        "links": null,
        "message": null
      }
    }
  ],
  "meta": {
    "page_size": 2,
    "next": null,
    "prev": null
  },
  "links": {
    "self": "string",
    "prev": "loremipsum-prev",
    "next": "loremipsum-next"
  }
}

Sample Response - Classification

1
2
{
  "data": [
    {
      "type": "resource",
      "id": "d653c974-8d83-4ea9-b6b7-b49e18c69391",
      "attributes": {
        "parentResourceId": "ari:cloud:platform::org/c74e07d8-ddc2-4583-a8bc-5d5405a3907a",
        "resourceId": "ari:cloud:platform::classification-tag/28a6d272-0d95-4a81-baea-a0660f490afc",
        "applicationStatus": "applied",
        "createdAt": "2024-06-23T03:55:39.128Z",
        "updatedAt": "2024-06-23T03:55:38.900Z"
      },
      "links": null,
      "message": null
    }
  ],
  "meta": {
    "page_size": 2,
    "next": null,
    "prev": null
  },
  "links": {
    "self": "string",
    "prev": "loremipsum-prev",
    "next": "loremipsum-next"
  }
}

Modify a policy

PUT /v2/orgs/{orgId}/policies/{policyId}

Before modifying the policy, fetch the details of the policy and review its configuration. It is crucial to modify the policy object only after retrieving its details.

Remove the auto-generated data listed below from the response:

  • From the metadata object, eliminate the lastUpdatedBy, createdBy, hasHadCoverage, and systemTag properties.
  • From each resource entry, retain only the id property and remove all others.
  • From the attributes object, exclude the id, ownerId, createdAt, updatedAt, and queryData.
  • From the data object, remove the id, links, relations, and message.

You can update name, description, and/or effect. You can only modify policies in a draft status. To modify published policies, see Publish data security policies.

Example: Update description property to a new value and resubmit a JSON object via PUT call.

Sample Request

1
2
# Update policy description
curl --request PUT \
  --url 'https://api.atlassian.com/admin/control/v2/orgs/{orgId}/policies/{policyId}' \
  --header 'Authorization: Bearer <access_token>' \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data '{"data": {
        "type": "policy",
        "attributes": {
            "type": "data-security",
            "name": "test policy",
            "rule": {
                "export": {
                    "effect": "block"
                }
            },
            "status": "draft",
            "metadata": {
                "policyCoverageLevel": "CLASSIFICATION",
                "description": "A new description"
            }
        }
    }
}'

Publish data security policies

POST /v2/orgs/{orgId}/policies/publishDraftPolicies

Publishing policies is done by a bulk request for a specific ruleName. This is the only way to create or modify published policies.

The policyOperations array should include operations that define the following:

  • policyId: id of the policy to be acted on
  • action: UPDATE or DELETE
  • policyCoverageLevel: WORKSPACE, CLASSIFICATION, CONTAINER, or ORG

Updating a draft policy via publishDraft will replace any equivalent published policy with the now-published draft policy.

For appAccess rules: include a policy operation for the default (all_apps) ORG policy, and if updating an app-specific policy, include that app's ORG level policy in policyOperations. For export, publicLinks, anonymousAccess, you typically only include the workspace/container/classification policy operations (no ORG required unless you are publishing an org-wide draft).

Sample Request

1
2
curl --request POST \
  --url 'https://api.atlassian.com/admin/control/v2/orgs/{orgId}/policies/publishDraftPolicies' \
  --header 'Authorization: Bearer <access_token>' \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data '{
	"type": "data-security",
	"ruleName": "appAccess",
	"policyOperations": [
		{
			"policyId": "6d338cb1-501a-4017-bafd-d1ddcbb9f0aa",
			"action": "UPDATE",
			"policyCoverageLevel": "ORG"
		},
		{
			"policyId": "0cb2bcd5-fcb7-4b09-b27d-0b901d5ece10",
			"action": "UPDATE",
			"policyCoverageLevel": "CONTAINER"
		},
		{
			"policyId": "e5012592-a520-4093-9351-76ac8a769a75",
			"action": "DELETE",
			"policyCoverageLevel": "CONTAINER"
		}
	]
}'

Sample Response

1
2
{
    "messages": [
        {
            "messageId": "b9045023-9f4a-4448-9f3f-04a987186de1",
            "ticket": {
                "id": "b9045023-9f4a-4448-9f3f-04a987186de1",
                "containerAri": "ari:cloud:platform::org/185b5ad5-3c85-45f2-abe4-91e7b4ecd5c8",
                "scope": "USER"
            }
        }
    ]
}

The messageId in the response can be used by support engineers in the event of an error.

Delete a data security policy

There are two ways to delete a data security policy. Note that the published default (all_apps) ORG level policy cannot be deleted.

Recommended: Use the publishDraft endpoint to delete the policy. On a policyOperation, set the action to DELETE and the policyId to the id of the published or draft policy that you want to delete.

1
2
curl --request POST \
  --url 'https://api.atlassian.com/admin/control/v2/orgs/{orgId}/policies/publishDraftPolicies' \
  --header 'Authorization: Bearer <access_token>' \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data '{
	"type": "data-security",
	"ruleName": "appAccess",
	"policyOperations": [
		{
			"policyId": "6d338cb1-501a-4017-bafd-d1ddcbb9f0aa",
			"action": "UPDATE",
			"policyCoverageLevel": "ORG"
		},
		{
			"policyId": "e5012592-a520-4093-9351-76ac8a769a75",
			"action": "DELETE",
			"policyCoverageLevel": "CONTAINER"
		}
	]
}'

Alternatively, you can use the delete endpoint to delete a specific policy.

DELETE /v1/orgs/{orgId}/policies/{policyId}

Sample Request

1
2
curl --request DELETE \
  --url 'https://api.atlassian.com/admin/control/v1/orgs/{orgId}/policies/{policyId}' \
  --header 'Authorization: Bearer <access_token>' \
  --header 'Accept: application/json'

Sample Response

1
2
202
Accepted

Rate this page: